Using the API
Requests and errors
What a request must look like, how a refusal is reported as a problem document, rate limits, and which failures are worth retrying.
A client is easiest to write when every failure looks the same. Snaga answers
every refusal under /api/v1/ with one shape — an RFC 9457 problem document —
so your code can branch on a stable code and show people a readable detail.
Making a request
- Base URL:
https://api.snaga.ai. The platform API lives under/api/v1/. - Send JSON with
Content-Type: application/json. Field names are snake_case. - A JSON body needs a
Content-Length. A POST, PUT or PATCH without one is refused with 411 — this catches chunked uploads and some HTTP/2 clients that leave the header out. - A JSON body may be up to 10 MiB, an upload up to 50 MiB; above that the answer is 413.
- You may send your own
X-Request-Id(8–128 characters of letters, digits and._:-, starting with a letter or digit). The server uses it as the request's id; otherwise it makes one. Either way it comes back in theX-Request-Idresponse header.
The problem document
A refusal arrives as application/problem+json:
{
"type": "about:blank",
"title": "Unauthorized",
"status": 401,
"detail": "Missing Authorization header, token query parameter, or uarp_session cookie",
"code": "AUTH_ERROR",
"correlation_id": "<request_id>"
}
That is a real answer from GET /api/v1/agents without a key. The fields:
| Field | Meaning |
|---|---|
status | The HTTP status, repeated. |
title | The status's reason phrase (Not Found, Too Many Requests …). A 422 says Validation Error. |
detail | A sentence for a person, specific to this case. Never empty. |
code | A stable machine-readable code, such as NOT_FOUND, MISSING_SCOPE or IDEMPOTENCY_KEY_REUSED. Branch on this. |
correlation_id | The request id — the same value as the X-Request-Id header. Quote it when you contact support. |
errors | On a 422 for a body that failed validation: a list of {field, message} naming each field that failed. Other 422s, such as INVALID_CURSOR, have none. |
You may also see correlationId: the same value in an older spelling, kept
for now and marked deprecated. Read correlation_id.
Statuses you will meet
| Status | Usually means |
|---|---|
| 400 | The request is malformed: bad JSON, a missing header. |
| 401 | No key, or a key that does not authenticate. |
| 403 | The key lacks the scope or role, the company is suspended, or a limit or safety control blocks the call. |
| 404 | No such thing in this company. Things in other companies are invisible, not forbidden. |
| 409 | A state conflict: it already exists, or it changed under you. |
| 422 | The body failed validation; see errors. |
| 429 | Too many requests. |
| 5xx | Something failed on our side or upstream. |
The OpenAI- and Anthropic-compatible endpoints answer in the error shapes those SDKs expect instead; see Compatible endpoints.
Rate limits
Responses carry three headers:
X-RateLimit-Limit— the limit that applies to you;X-RateLimit-Remaining— how much of it is left;X-RateLimit-Reset— when it resets (a Unix timestamp, in seconds).
Past the limit the answer is 429 with Retry-After (seconds) and
X-RateLimit-Bucket, which says whether the company's, the key's or the
endpoint's allowance ran out.
Some refusals are about your plan's allowance rather than speed. Where an
operation documents it, the body's code tells them apart:
rate_limit_exceeded clears in seconds; quota_exceeded clears at
quota.resets_at; limit_reached does not clear by waiting and needs a plan
change. See Usage and limits.
limit_reached does not come with one status: it is 403 on POST /api/v1/runs,
POST /api/v1/llm/* and POST /api/v1/tools/web_search, and 429 on
POST /api/v1/sessions/{sessionId}/messages and
POST /api/v1/agents/{agentId}/evaluations. That split is kept for older clients, not
by design — branch on code, never on the status.
When to retry
Retrying is right when the failure is about timing, and wrong when it is about the request.
- 429 — wait for
Retry-After, then retry. - 503 — a dependency is unavailable or the queue is full; retry with backoff.
- 202 on a write you sent with an
Idempotency-Key— the first copy is still running; waitRetry-Afterseconds and send the same request again. - A dropped connection on a write — retry only if you sent an
Idempotency-Key. With one, the retry returns the first answer instead of doing the work twice. See Authentication. - 4xx other than 429 — do not retry unchanged. Fix the request first.
- 501 — the capability is switched off on this deployment. Retrying will not help.
The official SDKs follow these rules for you; see Errors and retries.
A test is not a status code
A few operations report the outcome of a check in the body, not in the status.
Testing an integration or an MCP server answers 200 even when the connection
fails — read success or ok. Likewise, a save that worked but could not
connect reports connect_error on a 2xx. When an operation's description says
the verdict is in the body, believe the body.
Related
- Authentication — keys, scopes, idempotency.
- Pagination and streaming — lists and live events.
- API reference — every operation's statuses and codes.