API reference

Errors

A single error shape, stable machine-readable codes, and what to retry.


Every error returns the same JSON shape, so you can parse one structure everywhere:

{
  "error": {
    "code": "UPSTREAM_TIMEOUT",
    "type": "upstream_timeout",
    "message": "The model backend exceeded the allowed processing deadline.",
    "request_id": "req_0b903419521e4e2c",
    "retryable": true
  }
}

Branch on code — it is stable and will not change meaning within /v1. Treat message as human-readable only; its wording may change.

retryable tells you whether an identical retry could succeed. Use it instead of guessing from the status code.

Codes

Code HTTP Retryable Meaning
AUTHENTICATION_ERROR 401 / 403 No Missing, invalid, or unauthorised key.
INVALID_REQUEST 400 / 422 No Malformed or semantically invalid request.
NOT_FOUND 404 No Unknown endpoint. Only the documented /v1 endpoints exist.
MODEL_NOT_FOUND 404 No The model does not exist or is not available to your key.
PAYLOAD_TOO_LARGE 413 No Request body exceeds the maximum size.
RATE_LIMITED 429 Yes Rate limit exceeded. Honour Retry-After.
CONCURRENCY_LIMIT 429 Yes Capacity momentarily saturated. Not a quota violation — retry shortly.
UPSTREAM_TIMEOUT 504 Yes The model exceeded the processing deadline.
UPSTREAM_ERROR 502 Yes The model backend returned an error.
UPSTREAM_UNAVAILABLE 502 Yes The model backend could not be reached.
INTERNAL_ERROR 500 Yes Unexpected server-side failure.

Request IDs

Every response — success or failure — carries an x-request-id header, and every error body repeats it in error.request_id. Quote this value in any support request; it is how we find your exact call in our logs.

You can supply your own instead, and it will be used and echoed back:

curl https://api.civix.com.vn/v1/chat/completions \
  -H "Authorization: Bearer $CIVIX_API_KEY" \
  -H "X-Request-Id: my-trace-id-123" \
  ...

Retrying safely

Retry only when retryable is true, use exponential backoff with jitter, and honour Retry-After when present.

Be careful retrying 504 UPSTREAM_TIMEOUT on a non-streaming request: the generation that timed out may have consumed real compute. Rather than retrying the same slow request, prefer switching to "stream": true, which is not bound by the deadline in the first place.

import time
from openai import OpenAI, APIStatusError

def with_retry(fn, attempts=3):
    for i in range(attempts):
        try:
            return fn()
        except APIStatusError as e:
            body = e.response.json().get("error", {})
            if not body.get("retryable") or i == attempts - 1:
                raise
            time.sleep((2 ** i) * 0.5)

What errors never contain

Error messages never include stack traces, internal hostnames, ports, or any other detail about our infrastructure. If you need to understand a failure beyond what code tells you, send us the request_id.