Atlas

API Reference

HTTP API endpoints for chat, queries, conversations, actions, and health checks.

Atlas exposes a Hono-based HTTP API. All endpoints are mounted under /api/. Use the SDK for a typed client, or call the API directly.

Base URL

SetupBase URL
Same-origin (Next.js rewrites)http://localhost:3000/api
Standalone APIhttp://localhost:3001/api
Cross-originSet NEXT_PUBLIC_ATLAS_API_URL to the API host

Authentication

Authentication headers depend on the configured auth mode:

Auth ModeHeader
NoneNo header required
Simple KeyAuthorization: Bearer <api-key> or X-API-Key: <key>
ManagedCookie: better-auth.session_token=<token> (browser) or Authorization: Bearer <session-token>
BYOTAuthorization: Bearer <jwt>

POST /api/chat

Streaming chat endpoint. Returns an event stream using the AI SDK Data Stream Protocol.

Request

curl -X POST http://localhost:3001/api/chat \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <key>" \
  -d '{
    "messages": [
      {
        "id": "msg-1",
        "role": "user",
        "parts": [{ "type": "text", "text": "How many users signed up last week?" }]
      }
    ],
    "conversationId": "optional-uuid"
  }'
FieldTypeRequiredDescription
messagesarrayYesChat messages with id, role, and parts
conversationIdstring (UUID)NoResume an existing conversation

Response

Server-sent event stream. The x-conversation-id header contains the conversation ID.


POST /api/v1/query

Synchronous JSON query endpoint. Runs the agent and returns structured results.

Request

curl -X POST http://localhost:3001/api/v1/query \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <key>" \
  -d '{"question": "What was last month revenue?"}'
FieldTypeRequiredDescription
questionstringYesNatural language question
conversationIdstring (UUID)NoResume an existing conversation

Response

{
  "answer": "Last month's revenue was $1.2M, a 15% increase...",
  "sql": ["SELECT SUM(total_amount) FROM orders WHERE ..."],
  "data": [
    {
      "columns": ["total_revenue"],
      "rows": [{ "total_revenue": 1200000 }]
    }
  ],
  "steps": 3,
  "usage": { "totalTokens": 1523 },
  "conversationId": "uuid",
  "pendingActions": []
}
FieldTypeDescription
answerstringAgent's natural language response
sqlstring[]SQL queries executed
dataarrayQuery results with columns and rows
stepsnumberAgent steps taken
usage.totalTokensnumberTokens consumed
conversationIdstringConversation ID (if persisted)
pendingActionsarrayActions awaiting approval (if action framework enabled)

GET /api/v1/conversations

List conversations for the authenticated user.

Query Parameters

ParameterTypeDefaultDescription
limitnumber20Max results (1--100)
offsetnumber0Pagination offset
starredbooleanFilter by starred status

Response

{
  "conversations": [
    {
      "id": "uuid",
      "userId": "user-id",
      "title": "Revenue analysis",
      "surface": "web",
      "connectionId": null,
      "starred": false,
      "createdAt": "2026-01-15T10:30:00Z",
      "updatedAt": "2026-01-15T10:35:00Z"
    }
  ],
  "total": 42
}

GET /api/v1/conversations/:id

Get a conversation with all messages.

Response

{
  "id": "uuid",
  "userId": "user-id",
  "title": "Revenue analysis",
  "surface": "web",
  "starred": false,
  "createdAt": "2026-01-15T10:30:00Z",
  "updatedAt": "2026-01-15T10:35:00Z",
  "messages": [
    {
      "id": "msg-uuid",
      "conversationId": "uuid",
      "role": "user",
      "content": { "parts": [{ "type": "text", "text": "..." }] },
      "createdAt": "2026-01-15T10:30:00Z"
    }
  ]
}

PATCH /api/v1/conversations/:id/star

Star or unstar a conversation.

curl -X PATCH http://localhost:3001/api/v1/conversations/<id>/star \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <key>" \
  -d '{"starred": true}'

DELETE /api/v1/conversations/:id

Delete a conversation and its messages. Returns 204 No Content.


GET /api/health

Health check endpoint. No authentication required.

Response

{
  "status": "ok",
  "checks": {
    "datasource": { "status": "ok", "latencyMs": 12 },
    "provider": { "status": "ok", "provider": "anthropic", "model": "(default)" },
    "semanticLayer": { "status": "ok", "entityCount": 5 },
    "internalDb": { "status": "not_configured" },
    "explore": { "backend": "nsjail", "isolated": true },
    "auth": { "mode": "managed", "enabled": true },
    "slack": { "enabled": false, "mode": "disabled" }
  },
  "sources": {
    "default": { "status": "healthy", "latencyMs": 12, "dbType": "postgres" }
  }
}

Actions

Manage approval-gated write operations. Requires ATLAS_ACTIONS_ENABLED=true and an internal database.

GET /api/v1/actions

List actions, filtered by status.

ParameterTypeDefaultDescription
statusstringpendingFilter by status: pending, approved, denied, executed, failed
limitnumber50Max results (1--100)

Response

{
  "actions": [
    {
      "id": "uuid",
      "action_type": "export_csv",
      "target": "orders",
      "summary": "Export orders table to CSV",
      "status": "pending",
      "requested_by": "user-id",
      "created_at": "2026-01-15T10:30:00Z"
    }
  ]
}

GET /api/v1/actions/:id

Get a single action by ID. Returns 404 if the action was not requested by the authenticated user.

POST /api/v1/actions/:id/approve

Approve a pending action. The action is executed immediately upon approval.

curl -X POST http://localhost:3001/api/v1/actions/<id>/approve \
  -H "Authorization: Bearer <key>"

Returns the updated action with execution results. Returns 409 Conflict if the action has already been resolved.

For admin-only approval mode, the requester cannot approve their own action (separation of duties).

POST /api/v1/actions/:id/deny

Deny a pending action. Optionally provide a reason.

curl -X POST http://localhost:3001/api/v1/actions/<id>/deny \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <key>" \
  -d '{"reason": "Not approved for production"}'

Scheduled Tasks

CRUD endpoints for recurring queries. Requires ATLAS_SCHEDULER_ENABLED=true and an internal database.

GET /api/v1/scheduled-tasks

List scheduled tasks owned by the authenticated user.

ParameterTypeDefaultDescription
limitnumber20Max results (1--100)
offsetnumber0Pagination offset
enabledbooleanFilter by enabled status

POST /api/v1/scheduled-tasks

Create a scheduled task.

curl -X POST http://localhost:3001/api/v1/scheduled-tasks \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <key>" \
  -d '{
    "name": "Daily revenue",
    "question": "What was yesterday total revenue?",
    "cronExpression": "0 9 * * *",
    "deliveryChannel": "email",
    "recipients": [{"type": "email", "address": "team@example.com"}]
  }'
FieldTypeRequiredDescription
namestringYesTask name (1--200 chars)
questionstringYesNatural language question (1--2000 chars)
cronExpressionstringYesCron schedule (e.g. 0 9 * * *)
deliveryChannelstringNoemail, slack, or webhook (default: webhook)
recipientsarrayNoDelivery targets (see below)
connectionIdstringNoTarget datasource connection
approvalModestringNoauto, manual, or admin-only (default: auto)

Recipient types:

  • { "type": "email", "address": "user@example.com" }
  • { "type": "slack", "channel": "#channel", "teamId": "T0..." }
  • { "type": "webhook", "url": "https://...", "headers": {} }

GET /api/v1/scheduled-tasks/:id

Get a task with its 10 most recent runs.

PUT /api/v1/scheduled-tasks/:id

Update a scheduled task. All fields are optional.

DELETE /api/v1/scheduled-tasks/:id

Delete (disable) a scheduled task. Returns 204 No Content.

POST /api/v1/scheduled-tasks/:id/run

Trigger immediate execution of a task.

GET /api/v1/scheduled-tasks/:id/runs

List past runs for a task.

ParameterTypeDefaultDescription
limitnumber20Max results (1--100)

Admin API

All admin endpoints are mounted at /api/v1/admin and require the admin role. When auth mode is none (local dev), requests are treated as implicit admin.

Overview

GET /api/v1/admin/overview

Dashboard summary with counts of connections, entities, metrics, glossary terms, and plugins.

{
  "connections": 2,
  "entities": 15,
  "metrics": 8,
  "glossaryTerms": 12,
  "plugins": 1,
  "pluginHealth": [
    { "id": "clickhouse", "name": "ClickHouse", "type": "datasource", "status": "healthy" }
  ]
}

Semantic Layer

GET /api/v1/admin/semantic/entities

List all entity YAML files with summary info (table name, description, column/join/measure counts, source).

GET /api/v1/admin/semantic/entities/:name

Get the full parsed YAML for a specific entity. Path-traversal protected.

GET /api/v1/admin/semantic/metrics

List all metric YAML files grouped by source.

GET /api/v1/admin/semantic/glossary

Get all glossary files (default + per-source).

GET /api/v1/admin/semantic/catalog

Get the parsed catalog.yml file. Returns { "catalog": null } if no catalog exists.

GET /api/v1/admin/semantic/stats

Aggregate statistics across the semantic layer.

{
  "totalEntities": 15,
  "totalColumns": 120,
  "totalJoins": 18,
  "totalMeasures": 25,
  "coverageGaps": {
    "noDescription": 2,
    "noColumns": 0,
    "noJoins": 5
  }
}

GET /api/v1/admin/semantic/raw/:file

Serve raw YAML content for top-level files (catalog.yml, glossary.yml).

GET /api/v1/admin/semantic/raw/:dir/:file

Serve raw YAML content for subdirectory files (e.g., entities/orders.yml, metrics/revenue.yml).

Connections

GET /api/v1/admin/connections

List all registered database connections with their type and cached health status.

{
  "connections": [
    { "id": "default", "dbType": "postgres", "health": { "status": "healthy", "latencyMs": 12 } }
  ]
}

POST /api/v1/admin/connections/:id/test

Trigger a live health check for a specific connection. Returns latency and status.

{
  "status": "healthy",
  "latencyMs": 15,
  "checkedAt": "2026-01-15T10:30:00Z"
}

Users

User management endpoints require managed auth mode (Better Auth).

GET /api/v1/admin/users

List users with pagination, search, and role filtering.

ParameterTypeDefaultDescription
limitnumber50Max results (1--200)
offsetnumber0Pagination offset
searchstringSearch by email (contains match)
rolestringFilter by role: viewer, analyst, admin

GET /api/v1/admin/users/stats

Aggregate user statistics: total count, banned count, and breakdown by role.

{
  "total": 42,
  "banned": 1,
  "byRole": { "admin": 2, "analyst": 15, "viewer": 25 }
}

PATCH /api/v1/admin/users/:id/role

Change a user's role. Cannot change your own role or demote the last admin.

curl -X PATCH http://localhost:3001/api/v1/admin/users/<id>/role \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <key>" \
  -d '{"role": "analyst"}'

POST /api/v1/admin/users/:id/ban

Ban a user. Optionally provide a reason and expiration.

curl -X POST http://localhost:3001/api/v1/admin/users/<id>/ban \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <key>" \
  -d '{"reason": "Policy violation", "expiresIn": 86400}'

POST /api/v1/admin/users/:id/unban

Remove a ban from a user.

DELETE /api/v1/admin/users/:id

Permanently delete a user. Cannot delete yourself or the last admin.

POST /api/v1/admin/users/:id/revoke

Revoke all sessions for a user (force logout).

Audit

Audit log endpoints require an internal database (DATABASE_URL).

GET /api/v1/admin/audit

Query the audit log with pagination and filters.

ParameterTypeDefaultDescription
limitnumber50Max results (1--200)
offsetnumber0Pagination offset
userstringFilter by user ID
successbooleanFilter by success/failure
fromstringISO 8601 start date
tostringISO 8601 end date

GET /api/v1/admin/audit/stats

Aggregate audit statistics: total queries, error count, error rate, and queries per day (last 7 days).

Plugins

GET /api/v1/admin/plugins

List all installed plugins with their type, version, and status.

POST /api/v1/admin/plugins/:id/health

Trigger a health check for a specific plugin.

Password Management

These endpoints are available to any authenticated managed-auth user (not admin-only).

GET /api/v1/admin/me/password-status

Check if the current user must change their password.

POST /api/v1/admin/me/password

Change the current user's password.

curl -X POST http://localhost:3001/api/v1/admin/me/password \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <key>" \
  -d '{"currentPassword": "old-pass", "newPassword": "new-pass-min-8-chars"}'

Error Responses

All error responses follow a consistent format:

{
  "error": "error_code",
  "message": "Human-readable error description",
  "retryAfterSeconds": 12
}

Error Codes

CodeStatusDescription
auth_error401Authentication failed or missing
rate_limited429Too many requests. Retry-After header included
configuration_error400Atlas is not fully configured (missing provider, etc.)
no_datasource400No datasource URL configured
invalid_request400Invalid request body or parameters
validation_error422Request validation failed (Zod errors in details)
not_found404Resource not found
not_available404Feature not available (e.g., no internal DB)
provider_model_not_found400Configured AI model does not exist
provider_auth_error502AI provider authentication failed
provider_rate_limit429AI provider rate limited
provider_timeout504AI provider timed out
provider_unreachable502Could not reach the AI provider
provider_error502AI provider returned an error
internal_error500Unexpected server error

Rate Limiting

When ATLAS_RATE_LIMIT_RPM is set, the API enforces per-user rate limits (sliding 60-second window). Rate-limited responses include:

  • HTTP status 429
  • Retry-After header (seconds until the limit resets)
  • retryAfterSeconds in the response body

See Environment Variables for configuration.


CORS

CORS is configured via ATLAS_CORS_ORIGIN (defaults to *). When an explicit origin is set, credentials (cookies) are allowed. The Retry-After and x-conversation-id headers are exposed to the client.

For cross-origin managed auth deployments, see the cross-origin section in the authentication guide.

On this page

Base URLAuthenticationPOST /api/chatRequestResponsePOST /api/v1/queryRequestResponseGET /api/v1/conversationsQuery ParametersResponseGET /api/v1/conversations/:idResponsePATCH /api/v1/conversations/:id/starDELETE /api/v1/conversations/:idGET /api/healthResponseActionsGET /api/v1/actionsResponseGET /api/v1/actions/:idPOST /api/v1/actions/:id/approvePOST /api/v1/actions/:id/denyScheduled TasksGET /api/v1/scheduled-tasksPOST /api/v1/scheduled-tasksGET /api/v1/scheduled-tasks/:idPUT /api/v1/scheduled-tasks/:idDELETE /api/v1/scheduled-tasks/:idPOST /api/v1/scheduled-tasks/:id/runGET /api/v1/scheduled-tasks/:id/runsAdmin APIOverviewGET /api/v1/admin/overviewSemantic LayerGET /api/v1/admin/semantic/entitiesGET /api/v1/admin/semantic/entities/:nameGET /api/v1/admin/semantic/metricsGET /api/v1/admin/semantic/glossaryGET /api/v1/admin/semantic/catalogGET /api/v1/admin/semantic/statsGET /api/v1/admin/semantic/raw/:fileGET /api/v1/admin/semantic/raw/:dir/:fileConnectionsGET /api/v1/admin/connectionsPOST /api/v1/admin/connections/:id/testUsersGET /api/v1/admin/usersGET /api/v1/admin/users/statsPATCH /api/v1/admin/users/:id/rolePOST /api/v1/admin/users/:id/banPOST /api/v1/admin/users/:id/unbanDELETE /api/v1/admin/users/:idPOST /api/v1/admin/users/:id/revokeAuditGET /api/v1/admin/auditGET /api/v1/admin/audit/statsPluginsGET /api/v1/admin/pluginsPOST /api/v1/admin/plugins/:id/healthPassword ManagementGET /api/v1/admin/me/password-statusPOST /api/v1/admin/me/passwordError ResponsesError CodesRate LimitingCORS