Atlas API

A high-performance timeseries data platform for storing, querying, and streaming arbitrary timeseries data. Built with Go and TimescaleDB.

Base URL

Quick Start

Reading Data

# First-time API users: acquire the "public" tag (Atlas UI does this automatically)
curl -X POST https://your-domain.com/api/tags/acquire/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tag_name": "public"}'

# List available datasets
curl -H "X-API-Key: YOUR_API_KEY" https://your-domain.com/api/datasets/

# Search by name or description
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://your-domain.com/api/datasets/?search=bitcoin"

# Get data from a dataset
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://your-domain.com/api/rows/?dataset=1&limit=100"

Creating Data

# 1. Create a dataset
curl -X POST https://your-domain.com/api/datasets/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "my_btc_prices", "description": "Bitcoin hourly prices"}'

# 2. Insert data (use the returned dataset ID)
curl -X POST https://your-domain.com/api/rows/bulk_insert/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dataset": 1, "rows": [
    {"timestamp": "2025-12-16T10:00:00Z", "values": {"price": 104500}},
    {"timestamp": "2025-12-16T11:00:00Z", "values": {"price": 104600}}
  ]}'

# 3. Share it by adding the "public" tag
curl -X POST https://your-domain.com/api/datasets/1/tags/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tag_name": "public"}'

Authentication

All API requests require authentication using an API key passed in the X-API-Key header.

curl -H "X-API-Key: YOUR_API_KEY" https://your-domain.com/api/datasets/
Keep Your Key Secret

Never expose your API key in client-side code or public repositories.

Health Check (No Auth Required)

GET /health

Check if the service is running and connected to the database.

Response
{
  "status": "healthy",
  "time": "2025-12-16T10:30:00Z",
  "database": "connected"
}

Access Control & Roles

Atlas uses a tag-based authorization system combined with dataset ownership. Understanding this system is essential for sharing and accessing data.

Summary

Creators: You own what you create. Assign tags to share datasets.
Consumers: Acquire tags to access datasets. The public tag is free.
Rule: Matching tags = read access. Ownership = full control.

Ownership

When you create a dataset, you become its owner with full control: read, write, delete, and manage access tags. New datasets are private by default—only visible to the owner until tags are assigned.

Tag-Based Access

Users can read a dataset if they have at least one tag that matches a tag on the dataset. No matching tags means no access (unless you're the owner).

Tag Types

Tag Type How to Acquire Use Case
Public Tags Any user can acquire freely public, test - Open datasets for everyone
Private Tags Require a secret key to acquire premium, tiingo - Restricted data access

Permissions Matrix

Action Owner Matching Tag No Match
Read dataset / rows
Write / Update / Delete
Manage tags

List & Search Datasets

Text Search

GET /api/datasets/

List datasets with optional text search. The search parameter performs case-insensitive substring matching against the dataset name and description.

Parameter Type Description
search string Substring to match against name or description (case-insensitive)
limit integer Max results to return (default: 250)
offset integer Number of results to skip (for pagination)

Examples

# Search for datasets containing "bitcoin" in name or description
curl -H "X-API-Key: YOUR_KEY" \
  "https://your-domain.com/api/datasets/?search=bitcoin"

# Search for datasets with "price" anywhere in the text
curl -H "X-API-Key: YOUR_KEY" \
  "https://your-domain.com/api/datasets/?search=price"

# Get first 10 results
curl -H "X-API-Key: YOUR_KEY" \
  "https://your-domain.com/api/datasets/?search=market&limit=10"
Same as Atlas UI

The web interface search bar uses this endpoint—substring matching against name and description.

Metadata Search

GET /api/datasets/search/

Search datasets by metadata field values. Each query parameter (except limit and offset) is treated as a metadata filter with exact matching.

Parameter Type Description
{key} any Metadata field name and value (exact match)
limit integer Max results to return (default: 250)
offset integer Number of results to skip

Examples

# Find all datasets from Tiingo
curl -H "X-API-Key: YOUR_KEY" \
  "https://your-domain.com/api/datasets/search/?source=tiingo"

# Find BTC/USD data with 1-minute frequency
curl -H "X-API-Key: YOUR_KEY" \
  "https://your-domain.com/api/datasets/search/?ticker=btcusd&frequency=1min"

# Find premium-tier datasets
curl -H "X-API-Key: YOUR_KEY" \
  "https://your-domain.com/api/datasets/search/?tier=premium"
Filter Required

At least one metadata filter is required. Use /api/datasets/ to list all datasets.

Create / Read / Update / Delete

POST /api/datasets/

Create a new dataset. You automatically become the owner.

Request Body
{
  "name": "btc_hourly_ohlcv",
  "description": "Bitcoin hourly OHLCV candles from Tiingo",
  "metadata": {
    "source": "tiingo",
    "ticker": "btcusd",
    "frequency": "1h"
  }
}
Response (201 Created)
{
  "id": 1,
  "name": "btc_hourly_ohlcv",
  "description": "Bitcoin hourly OHLCV candles from Tiingo",
  "metadata": {"source": "tiingo", "ticker": "btcusd", "frequency": "1h"},
  "columns": [],
  "created_at": "2025-12-16T10:30:00Z",
  "updated_at": "2025-12-16T10:30:00Z"
}
GET /api/datasets/{id}/ Read Access

Get a single dataset by ID. Requires read access (owner or matching tag).

PUT /api/datasets/{id}/ Owner Only

Update dataset name, description, and metadata. Replaces all fields.

DELETE /api/datasets/{id}/ Owner Only

Permanently delete a dataset and all its data. This cannot be undone.

Metadata Operations

Update metadata without affecting other dataset fields.

PATCH /api/datasets/{id}/metadata/ Owner Only

Merge new fields into existing metadata (partial update).

curl -X PATCH https://your-domain.com/api/datasets/1/metadata/ \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"version": "2.0"}'
# Merges with existing: {"source": "tiingo"} → {"source": "tiingo", "version": "2.0"}
PUT /api/datasets/{id}/metadata/ Owner Only

Replace all metadata (full overwrite).

How Tags Work

Tags connect users to datasets. A user can read any dataset that shares at least one tag with them.

Common Tags

Tag Type Purpose
public Public General sharing—most datasets use this
test Public Development and demo datasets
premium Private Requires secret to acquire

For Creators

After creating a dataset, assign tags to control access. Use public for open sharing, or private tags for restricted access. Multiple tags can be assigned to a single dataset.

For Consumers

Acquire the public tag (free) to access public datasets. For private datasets, obtain the secret from the data provider.

Tags API

GET /api/tags/

List all available tags in the system.

Response
[
  {
    "id": 1,
    "name": "public",
    "description": "Publicly accessible datasets",
    "is_public": true,
    "metadata": {},
    "created_at": "2025-12-01T00:00:00Z",
    "updated_at": "2025-12-01T00:00:00Z"
  },
  {
    "id": 2,
    "name": "premium",
    "description": "Premium tier datasets",
    "is_public": false,
    "metadata": {},
    "created_at": "2025-12-01T00:00:00Z",
    "updated_at": "2025-12-01T00:00:00Z"
  }
]
POST /api/tags/acquire/

Acquire a tag for yourself to gain access to datasets with that tag.

Acquire a Public Tag

curl -X POST https://your-domain.com/api/tags/acquire/ \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tag_name": "public"}'

Acquire a Private Tag (with secret)

curl -X POST https://your-domain.com/api/tags/acquire/ \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tag_name": "premium", "secret": "your-secret-key"}'
POST /api/access/check/

Check if you have access to a specific dataset.

Request
{
  "dataset_id": 1,
  "require_write": false
}
Response
{
  "has_access": true,
  "is_owner": false,
  "matching_tags": ["public"]
}

Dataset Tags

Manage which tags are assigned to a dataset to control access.

GET /api/datasets/{id}/tags/ Read Access

Get all tags assigned to a dataset.

POST /api/datasets/{id}/tags/ Owner Only

Assign a tag to your dataset to grant read access to users with that tag.

curl -X POST https://your-domain.com/api/datasets/1/tags/ \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tag_name": "public"}'

# Or by tag ID:
curl -X POST https://your-domain.com/api/datasets/1/tags/ \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tag_id": 1}'
DELETE /api/datasets/{id}/tags/{tag_id}/ Owner Only

Remove a tag from your dataset. Users with only that tag will lose access.

Columns

Columns define the schema of your timeseries data. Each column has a name and data type.

Columns Are Optional

You can insert data without pre-defining columns. The values field accepts any JSON object. Columns are primarily for schema documentation and Atlas UI display.

GET /api/columns/?dataset={id}

List columns for a specific dataset.

POST /api/columns/

Create a new column definition. Use this to document your schema for the Atlas UI.

Request
{
  "dataset": 1,
  "name": "close_price",
  "dtype": "float"
}
Field Type Description
dataset integer Dataset ID this column belongs to
name string Column name (should match keys in row values)
dtype string float or int

Rows (Timeseries Data)

Rows contain the actual timeseries data. Each row has a timestamp and values for the dataset's columns.

GET /api/rows/ Read Access

Query timeseries data with optional filters.

Parameter Type Description
dataset integer Filter by dataset ID (required for access check)
start datetime Start timestamp (ISO 8601 format)
end datetime End timestamp (ISO 8601 format)
ordering string timestamp (ascending) or -timestamp (descending)
limit integer Max rows to return (default: 250)
offset integer Number of rows to skip

Example

curl -H "X-API-Key: YOUR_KEY" \
  "https://your-domain.com/api/rows/?dataset=1&start=2025-12-01T00:00:00Z&end=2025-12-16T00:00:00Z&ordering=-timestamp&limit=100"
POST /api/rows/ Owner Only

Insert a single row of data.

{
  "dataset": 1,
  "timestamp": "2025-12-16T10:00:00Z",
  "values": {
    "open": 104500.00,
    "high": 104800.00,
    "low": 104200.00,
    "close": 104600.00,
    "volume": 1234567
  }
}
POST /api/rows/bulk_insert/ Owner Only

Bulk insert using PostgreSQL COPY protocol. Optimized for ~100K rows/sec throughput.

{
  "dataset": 1,
  "rows": [
    {
      "timestamp": "2025-12-16T10:00:00Z",
      "values": {"open": 104500, "close": 104600}
    },
    {
      "timestamp": "2025-12-16T11:00:00Z",
      "values": {"open": 104600, "close": 104700}
    }
  ]
}
Response
{
  "inserted": 2,
  "total": 2
}

Streaming & Downloads

Efficient endpoints for bulk data access and real-time streaming.

GET /api/rows/bulk_download/ Read Access

Download all data from a dataset in CSV or JSON format.

Parameter Type Description
dataset integer Dataset ID (required)
output string json (default) or csv
start datetime Optional start timestamp
end datetime Optional end timestamp
# Download as CSV
curl -H "X-API-Key: YOUR_KEY" \
  "https://your-domain.com/api/rows/bulk_download/?dataset=1&output=csv" \
  > data.csv

# Download as JSON
curl -H "X-API-Key: YOUR_KEY" \
  "https://your-domain.com/api/rows/bulk_download/?dataset=1&output=json" \
  > data.json
GET /api/rows/live/ Read Access

Bulk download recent data as NDJSON (newline-delimited JSON). Memory-efficient for large datasets.

# Download most recent 1000 rows
curl -H "X-API-Key: YOUR_KEY" \
  "https://your-domain.com/api/rows/live/?dataset=1&limit=1000"

# Output: one JSON object per line
# {"timestamp":"2025-12-16T10:00:00Z","close":104600}
# {"timestamp":"2025-12-16T11:00:00Z","close":104700}
GET /api/rows/stream/ Read Access

Real-time Server-Sent Events (SSE) stream. Connection stays open and pushes new data as it arrives.

Parameter Type Description
dataset integer Dataset ID (required)
poll_interval integer Seconds between checks for new data (default: 2)

Event Types

  • connected - Initial connection established
  • data - New data point received
  • heartbeat - Keepalive (no new data)
  • error - Query error occurred
# Connect to real-time stream
curl -H "X-API-Key: YOUR_KEY" \
  -H "Accept: text/event-stream" \
  "https://your-domain.com/api/rows/stream/?dataset=1&poll_interval=2"

# Output (connection stays open):
# event: connected
# data: {"dataset_id":1,"message":"Connected to real-time stream"}
#
# event: data
# data: {"timestamp":"2025-12-16T10:00:00Z","close":104600}
#
# event: heartbeat
# data: {"timestamp":"2025-12-16T10:00:02Z"}

Error Responses

All errors return a JSON object with an error field and optional details.

{
  "error": "Dataset not found",
  "details": "No dataset with ID 999"
}
Status Code Meaning
400 Bad Request - Invalid parameters or request body
401 Unauthorized - Missing or invalid API key
403 Forbidden - You don't have permission for this action
404 Not Found - Resource doesn't exist
429 Too Many Requests - Rate limit exceeded
500 Internal Server Error - Something went wrong

Common 403 Forbidden Scenarios

Pagination

List endpoints return paginated results with metadata for navigation.

{
  "count": 150,
  "next": "https://your-domain.com/api/datasets/?limit=50&offset=50",
  "previous": null,
  "results": [...]
}
Field Description
count Total number of results matching the query
next URL for the next page (null if no more results)
previous URL for the previous page (null if on first page)
results Array of items for the current page

Pagination Parameters

# Get page 2 with 50 items per page
curl -H "X-API-Key: YOUR_KEY" \
  "https://your-domain.com/api/datasets/?limit=50&offset=50"

Troubleshooting

Empty dataset list

You need the public tag to see public datasets. The Atlas UI acquires this automatically on login. API-only users should run:

curl -X POST https://your-domain.com/api/tags/acquire/ \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tag_name": "public"}'

Others can't see my dataset

New datasets are private. Assign a tag to share:

curl -X POST https://your-domain.com/api/datasets/YOUR_DATASET_ID/tags/ \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tag_name": "public"}'

403 Forbidden on read

You lack matching tags. Check what tags the dataset requires (ask the owner), list available tags with GET /api/tags/, then acquire the matching tag.

403 Forbidden on write

Only the owner can write. Tags grant read access only. Create your own dataset if you need write access.

Check your access

curl -X POST https://your-domain.com/api/access/check/ \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dataset_id": 1}'
# Returns: {"has_access": true, "is_owner": false, "matching_tags": ["public"]}

Allora Atlas Team