Errors & status codes

AllAPI speaks one response shape everywhere: a JSON envelope with an ok boolean. When a public source is reachable you get ok:true and real data. When it is walled, empty, or failing, you get ok:false and a documented, honest error — never a fabricated success.

The envelopeThe one ruleStatus codes Error codesRate limitsComposite responsesHandling errors

The response envelope

Every response — success or failure — is the same object. Read data when ok is true; read error when it is false.

// success
{ "ok": true, "data": { /* the real payload */ }, "error": null, "meta": { } }

// error
{ "ok": false, "data": null,
  "error": { "code": "unauthorized", "message": "...",
    "detail": { "status_code": 404, "retriable": false } },
  "meta": { } }

error.detail.status_code carries the upstream source's own status when the failure came from a public source; error.detail.retriable tells you whether trying again may succeed.

The one rule: branch on ok, not on HTTP status

Most source-level problems — a walled page, a rate-limited upstream, an empty result — come back as 200 OK with ok:false. The HTTP status reflects our gateway; the field ok reflects your data. Always check ok first. HTTP 4xx/5xx are reserved for gateway-level conditions (auth, rate limits, unknown platform) described below.

HTTP status codes

What the gateway itself returns. Anything not in this list means the request reached a service and the outcome is in the envelope.

StatusMeaningBody
200Request handled. Real data (ok:true) or an honest source error (ok:false).envelope
401Missing, unknown, or deactivated API key.envelope · unauthorized
404Unknown platform, or a route that does not exist on a known platform.envelope / {"detail":"Not Found"}
405Wrong HTTP method — most data routes are POST.{"detail":"Method Not Allowed"}
422Request body failed validation (missing/invalid field).{"detail":[…]}
429Rate limit or monthly quota exceeded. See Rate limits.envelope · rate_limited
503Temporary — the service is briefly unavailable. Retry after a short pause.envelope

Validation (422) and method (405) errors use FastAPI's native {"detail":…} shape rather than the ok envelope. If ok is absent from a response, you hit one of these — check the HTTP status.

Error codes

When ok:false, error.code is a stable, machine-readable string you can switch on.

Gateway codes

CodeWhen
unauthorizedAPI key missing, unknown, or deactivated.
rate_limitedPer-minute rate limit or monthly quota exceeded.
not_foundThe requested platform or resource does not exist.
validation_errorInput failed a semantic check.
bad_inputThe request was malformed.
upstream_walledThe public source blocked or challenged the request (login wall, anti-bot).
upstream_unreachableThe public source timed out or could not be reached.

Source codes

Errors that originate at a specific platform use a namespaced code, <platform>.<reason> — for example nasa.not_found, spotify.rate_limited, or github.unavailable. The reason mirrors the source's own status; error.detail.status_code gives the exact upstream code.

Rate limits & headers

Limits are per API key. Every response carries your live budget; a 429 includes Retry-After.

PlanRequests / minute
Free60
Standard120
Pro300
Business600
Enterprise1,200
MaxUnmetered

Response headers on every call: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. On a 429: Retry-After (seconds). Monthly credits are separate from the per-minute rate and are set by your plan — see Pricing.

Composite & MCP responses

Composite endpoints fan out to several sources and merge the results. They are partial-tolerant: ok:true as soon as at least one source returns real data. Sources that failed are still listed honestly inside data, each with its own status, so nothing is silently dropped.

CodeWhen
composite.all_upstream_failedEvery source was tried and all failed.
composite.no_subservice_applicableNo source matched the input, so nothing was attempted.

Per-source badges inside data carry a status of real, empty, timeout, transport_error, skipped_input, or unsupported.

Handling errors well

const r = await fetch(url, { method: "POST", headers, body }).then(x => x.json());
if (!r.ok) {
  switch (r.error.code) {
    case "rate_limited": /* wait Retry-After, retry */ break;
    case "upstream_unreachable": /* backoff + retry */ break;
    default: /* unauthorized, walled, validation → surface it */
  }
} else {
  use(r.data);
}

See also API Reference · Getting Started · All platforms · Status.