Skip to main content
Browse the documentation

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 the X-Request-Id response 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:

FieldMeaning
statusThe HTTP status, repeated.
titleThe status's reason phrase (Not Found, Too Many Requests …). A 422 says Validation Error.
detailA sentence for a person, specific to this case. Never empty.
codeA stable machine-readable code, such as NOT_FOUND, MISSING_SCOPE or IDEMPOTENCY_KEY_REUSED. Branch on this.
correlation_idThe request id — the same value as the X-Request-Id header. Quote it when you contact support.
errorsOn 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

StatusUsually means
400The request is malformed: bad JSON, a missing header.
401No key, or a key that does not authenticate.
403The key lacks the scope or role, the company is suspended, or a limit or safety control blocks the call.
404No such thing in this company. Things in other companies are invisible, not forbidden.
409A state conflict: it already exists, or it changed under you.
422The body failed validation; see errors.
429Too many requests.
5xxSomething 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; wait Retry-After seconds 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.