Server API

Complete REST API reference for OpenAnalyst. Covers authentication, all resource endpoints, request and response formats, pagination, rate limiting, and error handling.

Base URL and Versioning

All API requests are made over HTTPS to the following base URL:

https://api.openanalyst.com/v1

The version segment /v1 is part of every endpoint URL. When a new incompatible API version is released, it will be accessible at /v2 while/v1 remains available for a minimum deprecation period of 12 months. Version sunset dates are announced in the changelog at least 90 days in advance.

Note: The API does not support content negotiation via the Accept-Version header. Always include the explicit version in the URL path.

Authentication

Every request must include a valid API key as a Bearer token in theAuthorization header. API keys are generated from the Settings page inside the web app at app.openanalyst.com.

Authorization: Bearer oa_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx

API keys are prefixed with oa_live_ for production keys andoa_test_ for test-mode keys. Test-mode keys return synthetic data and do not consume credits or trigger real webhooks.

curl https://api.openanalyst.com/v1/datasets \
  -H "Authorization: Bearer oa_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json"

Warning: Never expose API keys in client-side JavaScript, mobile app bundles, or public repositories. If a key is compromised, revoke it immediately from the Settings page and issue a replacement.

Request and Response Format

All request bodies must be JSON with the header Content-Type: application/json. All successful responses return JSON with an HTTP 2xx status code. Collections are wrapped in a top-level object with data and pagination keys. Single resources are returned directly as a JSON object.

Success Response — Single Resource

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "rpt_abc123",
  "name": "Weekly Executive Summary",
  "format": "pdf",
  "created_at": "2025-11-01T09:00:00Z",
  "updated_at": "2025-11-15T14:22:00Z"
}

Success Response — Collection

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": [
    { "id": "rpt_abc123", "name": "Weekly Executive Summary" },
    { "id": "rpt_def456", "name": "Monthly Churn Analysis" }
  ],
  "pagination": {
    "cursor": "cur_xyz789",
    "has_more": true,
    "total": 47
  }
}

Pagination

All list endpoints use cursor-based pagination. Pass the cursor value from a previous response as the after query parameter to retrieve the next page. Use the limit parameter to control page size (default: 20, maximum: 100).

# First page
curl "https://api.openanalyst.com/v1/reports?limit=25" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY"

# Next page
curl "https://api.openanalyst.com/v1/reports?limit=25&after=cur_xyz789" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY"

When pagination.has_more is false, you have reached the last page. The total field reflects the total number of matching records and does not change between pages.

Rate Limiting

API rate limits are applied per API key. The default limits are:

PlanRequests / minuteRequests / day
Starter6010,000
Pro300100,000
EnterpriseCustomCustom

Every response includes the following rate limit headers:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 247
X-RateLimit-Reset: 1732016460

When the limit is exceeded, the API returns HTTP 429 with a Retry-Afterheader indicating the number of seconds to wait before retrying.

Error Response Format

All errors return a consistent JSON body regardless of the error type:

{
  "error": {
    "code": "not_found",
    "message": "Dataset ds_nonexistent does not exist or you do not have access to it.",
    "status": 404,
    "request_id": "req_8f3kd92ls"
  }
}
HTTP StatusError CodeDescription
400invalid_requestMissing or malformed request parameters
401authentication_requiredMissing or invalid API key
403forbiddenKey does not have permission for this action
404not_foundThe requested resource does not exist
409conflictResource already exists or state conflict
422unprocessableSemantically invalid request body
429rate_limit_exceededToo many requests
500internal_errorUnexpected server error

Datasets

Datasets represent connected data sources or uploaded data files.

GET /datasets

List all datasets accessible to the authenticated key.

curl "https://api.openanalyst.com/v1/datasets" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY"

# Response
{
  "data": [
    {
      "id": "ds_abc123",
      "name": "Production Postgres",
      "type": "postgresql",
      "status": "connected",
      "created_at": "2025-09-01T12:00:00Z"
    }
  ],
  "pagination": { "cursor": null, "has_more": false, "total": 1 }
}

POST /datasets

Create (connect) a new dataset.

curl -X POST "https://api.openanalyst.com/v1/datasets" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Analytics Warehouse",
    "type": "bigquery",
    "credentials": {
      "project_id": "my-gcp-project",
      "dataset": "analytics",
      "service_account_key": "{ ... }"
    }
  }'

GET /datasets/:id

Retrieve a single dataset by ID.

curl "https://api.openanalyst.com/v1/datasets/ds_abc123" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY"

DELETE /datasets/:id

Disconnect and remove a dataset. This does not delete the underlying data source.

curl -X DELETE "https://api.openanalyst.com/v1/datasets/ds_abc123" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY"

# Response: HTTP 204 No Content

Queries

Queries execute SQL or natural-language requests against a connected dataset.

POST /queries/run

curl -X POST "https://api.openanalyst.com/v1/queries/run" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "dataset_id": "ds_abc123",
    "sql": "SELECT country, COUNT(*) AS users FROM customers GROUP BY country ORDER BY 2 DESC LIMIT 10",
    "timeout": 60
  }'

# Response
{
  "id": "qry_xyz789",
  "status": "running",
  "created_at": "2025-11-20T10:00:00Z"
}

GET /queries/:id/results

Retrieve the results of a completed query. Poll this endpoint until status is completed or failed.

curl "https://api.openanalyst.com/v1/queries/qry_xyz789/results" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY"

# Response
{
  "id": "qry_xyz789",
  "status": "completed",
  "columns": ["country", "users"],
  "rows": [
    { "country": "United States", "users": 48291 },
    { "country": "United Kingdom", "users": 12047 }
  ],
  "row_count": 10,
  "execution_time_ms": 342
}

Reports

GET /reports

curl "https://api.openanalyst.com/v1/reports?limit=10" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY"

POST /reports

curl -X POST "https://api.openanalyst.com/v1/reports" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Monthly Revenue Report",
    "dataset_id": "ds_abc123",
    "format": "pdf",
    "schedule": {
      "frequency": "monthly",
      "day_of_month": 1,
      "hour": 7,
      "timezone": "UTC"
    },
    "recipients": ["finance@example.com"]
  }'

GET /reports/:id

curl "https://api.openanalyst.com/v1/reports/rpt_abc123" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY"

PUT /reports/:id

Full replacement update of a report. All writable fields must be included.

curl -X PUT "https://api.openanalyst.com/v1/reports/rpt_abc123" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Monthly Revenue Report (Updated)",
    "dataset_id": "ds_abc123",
    "format": "xlsx",
    "schedule": { "frequency": "monthly", "day_of_month": 2, "hour": 8, "timezone": "UTC" },
    "recipients": ["finance@example.com", "cfo@example.com"]
  }'

Agents

POST /agents/run

Start a new AI agent session. The agent will autonomously query data, reason over results, and produce a final answer.

curl -X POST "https://api.openanalyst.com/v1/agents/run" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "What were the top 5 product categories by revenue last quarter, and how do they compare to the same quarter last year?",
    "dataset_ids": ["ds_abc123"],
    "model": "claude-3-5-sonnet",
    "max_steps": 15
  }'

# Response
{
  "id": "ses_kj2h8d",
  "status": "running",
  "created_at": "2025-11-20T10:05:00Z"
}

GET /agents/sessions

curl "https://api.openanalyst.com/v1/agents/sessions" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY"

GET /agents/sessions/:id

curl "https://api.openanalyst.com/v1/agents/sessions/ses_kj2h8d" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY"

# Response (completed session)
{
  "id": "ses_kj2h8d",
  "status": "completed",
  "prompt": "What were the top 5 product categories ...",
  "model": "claude-3-5-sonnet",
  "steps": 8,
  "final_answer": "The top 5 product categories by revenue last quarter were ...",
  "created_at": "2025-11-20T10:05:00Z",
  "completed_at": "2025-11-20T10:05:42Z"
}

Exports and Webhooks

POST /exports

curl -X POST "https://api.openanalyst.com/v1/exports" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "dataset_id": "ds_abc123",
    "format": "parquet",
    "filter": {
      "date_range": { "start": "2025-01-01", "end": "2025-12-31" }
    }
  }'

GET /exports/:id/download

Returns a temporary pre-signed download URL valid for 15 minutes. The export must have status: "ready".

curl "https://api.openanalyst.com/v1/exports/exp_mn4op9/download" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY"

# Response
{
  "download_url": "https://storage.openanalyst.com/exports/exp_mn4op9.parquet?token=...",
  "expires_at": "2025-11-20T10:20:00Z",
  "size_bytes": 4820194,
  "format": "parquet"
}

POST /webhooks

curl -X POST "https://api.openanalyst.com/v1/webhooks" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourdomain.com/hooks/openanalyst",
    "events": ["report.completed", "agent.session.completed", "export.ready"],
    "secret": "whsec_your_signing_secret"
  }'

GET /webhooks and DELETE /webhooks/:id

# List webhooks
curl "https://api.openanalyst.com/v1/webhooks" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY"

# Delete a webhook
curl -X DELETE "https://api.openanalyst.com/v1/webhooks/wh_pq5rs1" \
  -H "Authorization: Bearer $OPENANALYST_API_KEY"

Tip: Webhook payloads include an X-OpenAnalyst-Signature header containing an HMAC-SHA256 signature of the raw request body using your webhook secret. Always verify this signature before processing the event.