AI92 is live - onze wereldwijde zachte lancering is begonnen: het volledige platform is wereldwijd geopend voor de eerste 30 dagen.
Documentatiemenu

Deze ontwikkelaarsdocumentatie is momenteel alleen in het Engels. Code en API-gedrag zijn identiek in elke regio.

Errors

Every AI92 API error — across all eight services — uses one envelope. Parse it once and you can handle errors everywhere.

The error envelope

json
{
  "error": {
    "code": "INSUFFICIENT_CREDITS",
    "message": "Your credit balance (2) is below the cost of this operation (3). Top up at https://api.ai92.ai/account/credits.",
    "status": 402,
    "documentation_url": "https://ai92.ai/docs/errors"
  }
}
FieldMeaning
codeStable, machine-readable identifier. Branch on this, never on the message.
messageHuman-readable explanation, safe to log and (carefully) surface.
statusThe HTTP status code, mirrored in the body for convenience.
documentation_urlDeep link to the docs for this error (not present on every error).

The HTTP status line always matches error.status.

HTTP status families

StatusMeaning
400Malformed request
401Authentication problem (missing / invalid / expired / revoked credential)
402Payment required — out of credits or over a spending cap
403Authenticated but not allowed (IP, scope, suspended, read-only)
404Not found (or not owned by you — existence is never leaked across accounts)
409Conflict (idempotency key reused with a different body)
422Semantically invalid (bad enum, bad window, brand not onboarded)
429Rate limited
503An upstream service was unavailable (retryable, not charged)

Error code reference

Authentication & authorization

CodeStatusCauseSolution
AUTHENTICATION_REQUIRED401No Authorization header, or not in Bearer <token> form.Send Authorization: Bearer ai92_live_....
INVALID_API_KEY401Key not found, revoked, unrecognized token format, or a revoked OAuth token.Check the key value; rotate if lost; re-issue OAuth tokens if revoked.
EXPIRED_API_KEY401The key's expires_at has passed.Create a new key and update your deployment.
FORBIDDEN_SCOPE403An OAuth token is missing a scope the endpoint requires.Re-authorize the user requesting the needed scope(s).
IP_NOT_ALLOWED403Request IP is outside the key's ip_whitelist.Call from an allowed CIDR, or update the allowlist via PATCH /v1/account/keys/{id}.
TENANT_INACTIVE403The account is suspended.Contact support / resolve billing.
ACCOUNT_READ_ONLY403Account placed in read-only mode after long inactivity.Reactivate the account (a paid action re-activates it).

Credits & billing

CodeStatusCauseSolution
INSUFFICIENT_CREDITS402Balance is below the operation's cost (checked before the call runs).Top up via POST /v1/billing/checkout; check balance with GET /v1/account.
KEY_SPENDING_LIMIT402The key hit its per-key daily_credit_limit or monthly_credit_limit.Raise the cap via PATCH /v1/account/keys/{id}, wait for the period to reset, or use another key.

Request validation

CodeStatusCauseSolution
INVALID_REQUEST400The request is malformed (bad JSON, missing required field, wrong type).Fix the payload to match the endpoint schema.
UNPROCESSABLE_ENTITY422Well-formed but semantically invalid input.Correct the value (see the message for which field).
INVALID_REVEAL_MODE422mode on /v1/contacts/reveal was not email or email_phone.Use a valid mode.
INVALID_PLANNING_WINDOW422Creative campaign window is reversed or longer than 31 days.Send planning_window_end ≥ start, window ≤ 31 days.
BRAND_NOT_ONBOARDED422A brand-scoped endpoint was called with a brand_id that hasn't completed onboarding.Register/onboard the brand via POST /v1/brands first.
IDEMPOTENCY_KEY_REUSE409Same X-AI92-Idempotency-Key used with a different request body.Use a new key for a new request. See Idempotency.

Upstream / backend

CodeStatusCauseSolution
BACKEND_UNAVAILABLE503The upstream service powering this endpoint returned a 5xx or was unreachable. You are not charged.Retry with exponential backoff; it's transient.
BACKEND_ERROR4xx / 502The upstream rejected the request (4xx is passed through; an unclassified failure becomes 502).For 4xx, fix the input; for 502, retry, then contact support if it persists.

Migrating from older clients: earlier drafts referenced FEATURE_UNAVAILABLE and BACKEND_DISPATCH_FAILED. These map to the codes above — a disabled service surfaces as a 503-class backend failure, and dispatch failures surface as BACKEND_UNAVAILABLE (503, not charged). Branch on the HTTP status family for forward compatibility.

Not found

CodeStatusCauseSolution
NOT_FOUND404The resource doesn't exist — or exists but belongs to another account.Verify the id; ids are scoped to your account.

Handling errors well

  • Switch on error.code, not the message string (messages can change).
  • Retry 503 and 429 with backoff; do not auto-retry 4xx (fix the request instead).
  • Pair write retries with an idempotency key so a retried POST can't double-charge.
  • Log X-AI92-Trace-Id from the response — quote it to support to pinpoint the exact request.
python
r = httpx.post(url, headers=headers, json=payload)
if r.is_error:
    err = r.json()["error"]
    code, status = err["code"], err["status"]
    if status in (429, 503):
        ...  # retry with backoff
    elif code == "INSUFFICIENT_CREDITS":
        ...  # top up, then replay with the same idempotency key
    else:
        raise RuntimeError(f"{code}: {err['message']} (trace {r.headers.get('X-AI92-Trace-Id')})")