Skip to main content

What it is

This page explains how the Symphony API reports failures, what each error code means, when it’s worth retrying, and which usage limits exist. Use it to build your integration’s error handling.

1. How to read an error

Every error response has an HTTP 4xx or 5xx status and a JSON body. The stable error code can come in two different places, depending on the endpoint.
Special cases, with no code:

Reading the code safely

Rules for coding against errors

  • Use the code, never the text. The code is stable. message and action can be rewritten at any time.
  • Messages are always in English. The API doesn’t translate. If you show the error to your user, translate it from the code.
  • retryable tells you whether retrying has a chance of working.
  • Store the request_id in your logs. That’s how the Symphony team finds what happened.

2. HTTP status codes

For security, a resource that exists but that you can’t see responds 404, not 403. That way the API doesn’t reveal the existence of other people’s data.

3. Error code catalog

Model and agent

Availability and network

Usage and quota

Access

Files and documents

Other

4. When to retry

Retry when retryable is true, or when the status is 429 or 5xx:
  • Wait a time that grows with each attempt (1 s, 2 s, 4 s, 8 s…) and add a small random variation.
  • If the response includes the Retry-After header, wait at least that many seconds.
  • Limit the number of attempts (for example, 5) and log the final failure with the request_id.
Never retry on 400, 401, 402, 403, 404, 409, and 422. None of them resolves on its own, and retrying only uses up your request limit.

5. Usage limits

These limits are independent. Knowing which one you hit avoids pointless retries. Values may be adjusted per environment.

Request limit per IP

Every response includes headers so you can track the limit:
The limit is per IP, not per key. Several integrations leaving from the same network (same server, same NAT, same CI runner) share the same quota.
GET /health and GET /api/version don’t count toward this limit, and neither does GET /api/models.

User usage limit

This is the monthly spending cap for the account that owns the key. It’s checked before any call to the model, so a blocked request doesn’t cost anything. Track it with GET /api/v1/consumption/me (see the API reference).

Response time and size

  • Set generous timeouts. Responses from large models, with lots of context or files, can take a few minutes. We recommend at least 300 seconds for the complete response. If you need fast responses, use streaming.
  • Files: the maximum upload size is set by your company’s configuration. Ask the administrator if you need to upload large files.
  • Audio: files over 25 MB are compressed automatically before transcription.

6. Errors during streaming

With "stream": true, the 200 OK status is sent before the model starts responding. If something goes wrong midway, the failure arrives inside the stream, as a JSON event with an error object, not as an HTTP error status. The error event has the same content as format B:
When reading the stream:
  1. For each data: {...} line, check whether the JSON has an error key before reading choices.
  2. A data: [DONE] after an error does not mean success. Treat the response as a failure.
  3. If the connection closes without data: [DONE], treat it as STREAM_INTERRUPTED.
  4. Ignore blank lines.

7. How to get help with an error

When you open a ticket, send:
  • The request_id from the error response.
  • The endpoint and the approximate time (with time zone).
  • The HTTP status and the code.
  • The request body, without the API key.
The support channels are in Environments and support.