Skip to content

Errors and status codes

All Xref API responses use a consistent JSON envelope for both successful and error responses.

Response envelope

{
  "data": <object | array | null>,
  "status_message": "ok",
  "message": ""
}
Field Type Description
data object | array | null The successful payload. null on error responses.
status_message string Coarse-grained status: informational, ok, redirect, client_error, or server_error.
message string Human-readable detail. Empty on success; populated for errors.

The HTTP status code and the status_message are always consistent — for example, an HTTP 404 always carries status_message: "client_error". Use the HTTP status code as your primary signal and the message for diagnostics or surfacing to humans.

Cache headers (Cache-Control: no-store, Pragma: no-cache, Expires: 0) are set on every response.

Status code matrix

Status status_message Meaning Retry?
200 ok Successful read. —
201 ok Successful create (POST /v1/requests). —
202 ok Reserved. Not currently emitted. —
400 client_error Validation failure — missing/invalid field, bad JSON, unsupported query value, package not ACTIVE, schema mismatch. Fix the body, then retry.
401 client_error Missing or invalid X-Xref-API-Key / X-Xref-User-Email headers, or invalid / expired ?t= report token. Fix the headers or re-query for a fresh token, then retry.
403 client_error User email is not a permitted member of the API key's organisation, or the organisation has no credits remaining, trial has expired, or subscription is inactive. Check user membership and organisation plan/credits, then retry.
404 client_error Package or request not found, or not visible to the caller's organisation / tier. Don't retry — the resource doesn't exist for this caller.
422 client_error Reserved. v1 emits 400 for all validation failures. Future versions may use 422 to distinguish semantic from syntactic validation. Fix the body, then retry.
429 client_error Per-API-key throttle exceeded. Retry-After header included. Wait Retry-After seconds, then retry.
5xx server_error Internal error; the request log carries a trace id. Retry with backoff. Treat the outcome as unknown for POST /v1/requests.

Examples

200 OK — success

{
  "data": { "packages": [/* ... */] },
  "status_message": "ok",
  "message": ""
}

201 Created — request accepted

{
  "data": {
    "request_id": "9b2a14ee-9d0e-4d3a-aff2-7f68c19f3f3a",
    "status": "RECEIVED"
  },
  "status_message": "ok",
  "message": ""
}

400 Bad Request — validation failure

{
  "data": null,
  "status_message": "client_error",
  "message": "recipient.email: enter a valid email address"
}

401 Unauthorized — missing or invalid API key

{
  "data": null,
  "status_message": "client_error",
  "message": "Missing X-Xref-Api-Key or X-Xref-User-Email"
}
{
  "data": null,
  "status_message": "client_error",
  "message": "Invalid API key"
}

403 Forbidden — user not permitted or plan exhausted

{
  "data": null,
  "status_message": "client_error",
  "message": "User is not a member of the organisation"
}
{
  "data": null,
  "status_message": "client_error",
  "message": "Organisation has no credits remaining"
}
{
  "data": null,
  "status_message": "client_error",
  "message": "Organisation subscription is not active"
}

404 Not Found — package or request not visible

{
  "data": null,
  "status_message": "client_error",
  "message": "Resource not found"
}

429 Too Many Requests — throttled

Headers:

HTTP/1.1 429 Too Many Requests
Retry-After: 27
Content-Type: application/json

Body:

{
  "data": null,
  "status_message": "client_error",
  "message": "Rate limit exceeded"
}

The Retry-After value is the number of seconds remaining in the breached window (per-minute or per-hour, whichever was hit first).

5xx Server Error — internal error

{
  "data": null,
  "status_message": "server_error",
  "message": "Internal server error"
}

A 5xx response indicates that the server was unable to process the request.

GET requests can be retried. For POST /v1/requests, see Idempotency and retries before retrying.