Errors

Every response uses a consistent envelope. On failure you get a machine-readable code and an HTTP status — never a stack trace or an internal service name.

Response envelope

Success and failure are both wrapped, distinguished by the success flag:

json
// success
{ "success": true, "data": { "the": "payload" } }

// error
{ "success": false,
  "error": { "code": "NOT_FOUND", "message": "Content not found.", "statusCode": 404 } }

Status codes

ParamTypeDescription
401 UNAUTHORIZEDerrorMissing, invalid, expired, or revoked API key. Check your token.
403 FORBIDDENerrorThe project in the path does not match the key’s project, or the scope is wrong.
404 NOT_FOUNDerrorUnknown content type apiId, unknown slug, or no published entry matches.
422 VALIDATION_ERRORerrorMalformed query parameters (bad sort key, limit over 100, unknown select field, etc.).
429 RATE_LIMITEDerrorMonthly Delivery request quota exceeded, when usage enforcement is enabled. See Rate Limits.
500 INTERNAL_ERRORerrorServer-side failure. Safe to retry; transient.

Handling errors

Check the HTTP status (or the success flag) before reading the payload:

ts
const res = await fetch(url, { headers: { Authorization: 'Bearer ' + token } });
const body = await res.json();
if (!res.ok || body.success === false) {
  const err = body.error ?? { code: 'REQUEST_FAILED', message: 'Request failed.' };
  throw new Error('[' + err.code + '] ' + err.message);
}
const data = body.data;
// SAFE BY DESIGNError messages are generic and never leak internals — database errors, service names, and stack traces are all stripped before the response leaves the gateway.
Rate Limits & Usage