Skip to main content
Browse the documentation

Using the API

Authentication

API keys and their scopes, the Bearer header, safe retries with Idempotency-Key, and how the API is versioned.

Every call to the Snaga API is made on behalf of one company, with one API key. The key says who is calling and what they may do; everything else on this page — idempotency, versioning — is about making those calls safe to repeat and safe to depend on.

API keys

A key looks like uarp_<prefix>_<secret> and is sent as a Bearer token:

curl https://api.snaga.ai/api/v1/agents \
  -H "Authorization: Bearer $SNAGA_API_KEY"

Without a valid key the API answers 401 with WWW-Authenticate: Bearer realm="uarp".

Creating a key

Creating a key through the API needs a key with api_keys:write held by a company admin or owner:

curl -X POST https://api.snaga.ai/api/v1/tenants/me/keys \
  -H "Authorization: Bearer $SNAGA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "CI pipeline", "scopes": ["agents:read", "runs:create", "runs:read"]}'

The answer contains raw_key exactly once. Store it straight away; it can never be read again. name is required. A key created this way does not expire: its expires_at is null.

A key belongs to the person who created it and shows only in their own list (GET /api/v1/tenants/me/keys). DELETE /api/v1/tenants/me/keys/{keyId} revokes it: it stops working immediately, the record stays for the audit trail, and revoking cannot be undone — create a new key instead.

Scopes

Scopes limit what a key can do. They are named resource:action: agents:read, agents:write, runs:create, runs:read, sessions:read, files:write, webhooks:write and so on. The API reference lists every scope with its description, and each operation names the scope it needs.

  • Leave scopes out and the key gets the default set, narrowed to what you yourself hold: agents, runs (create and read), sessions, notifications, memory and files (read and write), plus analytics:read. billing:read is not in it.
  • A key can never carry more than its creator: you cannot grant a scope you do not hold (422), and only an owner may grant the wildcard *.
  • Some operations also need a member role. Roles run viewer < developer < admin < owner; the API reference names the minimum for each operation.

Give each integration its own key with only the scopes it needs. A key that can only read cannot start runs, whatever it is pointed at.

When a header is not possible

Browsers cannot set headers on an EventSource or a WebSocket. For those, the same key is accepted as the uarp_auth_token cookie, or as a ?token= query parameter — but ?token= is read only on an event stream (a request with Accept: text/event-stream), a WebSocket upgrade or a file download; on any other request it is ignored and the answer is 401. For event streams, prefer a short-lived token, which lasts 60 seconds — see Pagination and streaming. The Anthropic-compatible routes also accept the key in x-api-key; see Compatible endpoints.

A signed-in browser session is not a key: it stays valid on a 90-day sliding window, renewed as it is used.

Idempotency

Networks fail half-way. A request can reach the server and its answer be lost, and retrying blindly could start the same run twice. The Idempotency-Key header prevents that.

curl -X POST https://api.snaga.ai/api/v1/runs \
  -H "Authorization: Bearer $SNAGA_API_KEY" \
  -H "Idempotency-Key: 7f9c2b1e-run-weekly-report" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "<agent_id>", "input": {"message": "Write the weekly report."}}'
  • Every authenticated write under /api/v1/ accepts it.
  • The key is bound to the request it first came with: method, path with query, and body. Repeat the same request within 24 hours and you get the cached answer, marked X-Idempotency-Replayed: true.
  • Send the key with a different request and it is refused with 422, code: IDEMPOTENCY_KEY_REUSED. Use a new key for each new request.
  • If the first request is still being processed, the repeat gets 202 with Retry-After; wait and send it again.
  • Keys are 1–128 characters of letters, digits, _, . and -.

Anonymous calls — inbound webhooks, sign-in exchanges, public chat sessions — do not take the header.

Versioning

Every response carries X-API-Version, the date of the contract the server runs (currently 2026-09-10). It changes only on a breaking change.

There is no version negotiation: a request header of the same name is not read, so you cannot pin an older behaviour by sending an older date. Watch the response header instead.

When something is on its way out, the response can say so with Deprecation: true, naming what in X-API-Deprecation-Info — for example camelcase-fields, where a field is still sent in camelCase beside its snake_case twin. Not every such response is marked yet: most problem documents carry the camelCase correlationId while the header says none. Read the snake_case field; the camelCase twins go in the next breaking release. Where there is a replacement, a Link header with rel="successor-version" points to it. No removal date has been named yet.