---
title: "REST API · Ataris docs"
description: "Authentication, rate limits, errors, and every /v1 endpoint."
canonical: "https://ataris.dev/docs/reference/api"
last-updated: 2026-10-12
---
# REST API

Authentication, rate limits, errors, and every /v1 endpoint.

The Ataris REST API is served at `https://api.ataris.dev/v1`. Requests and responses are JSON unless noted.

## Authentication

Every request needs a workspace API key as a bearer token. Create keys in the dashboard under **Settings → API keys**.

```bash
curl https://api.ataris.dev/v1/sessions \
  -H "Authorization: Bearer $ATARIS_API_KEY"
```

A missing, invalid, or revoked key returns `401 unauthorized`.

## Rate limits

Limits are per API key:

- **All requests:** 10 per second, with bursts up to 30.

Past a limit the API returns `429 rate_limited` with a `Retry-After` header. The CLI waits out a `429` and retries, so events aren't dropped.

## Errors

Errors share one shape:

```json
{
  "error": {
    "type": "invalid_request",
    "message": "Invalid session.",
    "issues": [{ "path": "command", "message": "..." }]
  }
}
```

| Status | `type` | When |
| --- | --- | --- |
| `400` | `invalid_request` | The body or query failed validation. `issues` lists each problem. |
| `401` | `unauthorized` | Missing or invalid API key. |
| `403` | `plan_limit` | The workspace has used its plan's credit for the cycle, on Starter. |
| `404` | `not_found` | No such session, or it belongs to another workspace. |
| `409` | `conflict` | The session has already ended. |
| `413` | `invalid_request` | The body is too large. |
| `429` | `rate_limited` | See rate limits above. |
| `500` | `internal` | Something failed on our side. |

## Sessions

### List sessions

`GET /v1/sessions?tag=&state=&limit=&cursor=`

`tag` is `key:value`, repeatable; a session matches when it carries every tag. `state` is a session state or `active`. `limit` is 1 to 100, 20 by default. Returns `{ "sessions": [...], "nextCursor": "..." }`, newest first.

### Get a session

`GET /v1/sessions/{id}` returns `{ "session": SessionSummary }`.

## Events

### List events

`GET /v1/sessions/{id}/events?after=&limit=`

`after` is an event id (0 by default) and `limit` is 1 to 1,000, 500 by default. Returns `{ "events": [...], "nextAfter": 1234, "hasMore": true }`. See [Trace events](/docs/concepts/trace-events) for the event shape.

### Stream events

`GET /v1/sessions/{id}/stream`

Server-Sent Events:

| SSE event | Data |
| --- | --- |
| `trace` | One trace event. The SSE `id` is the event id. |
| `session` | The session summary, on each state change. |
| `end` | Sent once the session is over and every event has been delivered. |

Resume with the `Last-Event-ID` header or `?after=`.

## Trace ingest

Record a run. The [`ataris` CLI](/docs/guides/cli) uses these endpoints; you only need them to build your own integration. They work on every plan.

### Start a session

`POST /v1/trace/sessions`

| Field | Type | Description |
| --- | --- | --- |
| `command` | string | Required. The command the agent runs, up to 4,096 characters. |
| `tags` | string[] | `key:value` tags, up to 32. |
| `harness` | string | The agent's harness, such as `claude-code`, `codex`, or `grok`. |
| `mission` | string | Up to 4,096 characters. |
| `models` | string[] | Models the agent uses, up to 32. |
| `env` | object | The machine's `home` and `cwd`, so `~` and relative [policy](/docs/concepts/policies) patterns resolve. |

Returns `201` with `{ "session": SessionSummary, "policy": { "rules": [...] } }`. The session starts in `running`. `policy.rules` are the rules that govern it, from every enabled policy whose tags it carries (none on Starter); check each tool call against them before it runs. On Starter, a workspace that has used its credit for the cycle gets `403 plan_limit`.

### Append events

`POST /v1/trace/sessions/{id}/events` with `{ "events": [{ "seq": 1, "event": TraceEvent }, ...] }`, 1 to 1,000 events per call, each with a positive `seq`. Events use the [trace event](/docs/concepts/trace-events) shape. Ataris checks each event against the session's policy as it arrives. A `seq` already stored is skipped, so retries are safe. Returns `{ "inserted": n, "dropped": n }`.

### Finish a session

`POST /v1/trace/sessions/{id}/finish` with `{ "outcome": "succeeded" }` (or `failed`, `stopped`), an optional `reason`, and optional `models`. Returns `{ "session": SessionSummary }`, or `409 conflict` if the session has already ended.

