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
scopesout and the key gets the default set, narrowed to what you yourself hold:agents,runs(create and read),sessions,notifications,memoryandfiles(read and write), plusanalytics:read.billing:readis 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.
Related
- Your first API call — a walk-through from key to result.
- Requests and errors — what a refusal looks like.
- API reference — every operation, its scope and its role.