Errors

Every error response follows the same envelope shape — type, message, and a request id you can include in support tickets. No upstream branding leaks through; messages are sanitized.

Envelope shape

response · 400
{
"error": {
  "type": "invalid_request",
  "message": "Field 'prompt' is required.",
  "request_id": "01JX..."
}
}
request_id is also returned as the X-Request-ID response header. Quote it when filing a support ticket — we use it to look up the upstream call in our logs.
  • parameter
    error.type
    type
    string
    required
    required
    Machine-readable error code. See the table below.
  • parameter
    error.message
    type
    string
    required
    required
    Human-readable message. Safe to surface to end-users.
  • parameter
    error.request_id
    type
    string
    required
    optional
    ULID. Quote in support tickets and bug reports.

Common error types

  • parameter
    invalid_request
    type
    400
    required
    optional
    The request body or query is malformed (missing required field, bad enum value, etc).
  • parameter
    unsupported_media_type
    type
    415
    required
    optional
    The multipart upload used a MIME type we don't accept. See per-endpoint docs for allowed types.
  • parameter
    payload_too_large
    type
    413
    required
    optional
    The uploaded file exceeded the cap. 10MB for images, 25MB for transcription audio.
  • parameter
    insufficient_balance
    type
    402
    required
    optional
    Your wallet doesn't have enough credit for the request. Top up at /billing/topup.
  • parameter
    rate_limit_exceeded
    type
    429
    required
    optional
    Either your API key hit its usage limit (set in /keys), or the upstream rate-limited us. Back off and retry.
  • parameter
    asset_expired
    type
    410
    required
    optional
    A signed asset URL (/v1/assets/<token>) older than 24h was fetched. Re-request the asset from the original endpoint.
  • parameter
    asset_invalid
    type
    401
    required
    optional
    A signed asset URL was malformed or had a bad signature.
  • parameter
    upstream_error
    type
    502
    required
    optional
    The upstream model provider returned an error we couldn't recover from. Safe to retry once; if it persists, file a ticket with the request_id.

Handling errors in code

import requests

resp = requests.post(
  "https://api.echotokens.me/v1/images/generations",
  headers={"Authorization": "Bearer sk-echo-..."},
  json={"model": "nano-banana-2", "prompt": "..."},
)

if not resp.ok:
  err = resp.json().get("error", {})
  print(f"{err.get('type')}: {err.get('message')}")
  print(f"request_id: {err.get('request_id')}")
  raise SystemExit(1)
when in doubt, include the request_id

Support requests with a request_id are resolved roughly 10× faster than ones without. The id lets us find the exact request in our logs without playing detective.

What our errors hide

When the upstream rejects a request, we deliberately drop:

  • The exact upstream provider's identity (you only see upstream_error, not e.g. kling internal error 42).
  • Stack traces and internal paths.
  • Headers from the upstream that could leak vendor info.

This keeps your error UX consistent regardless of which provider you're routed through. If you need the upstream's raw failure context for debugging, file a ticket with the request_id — we have it in our logs.