Error codes
The API returns a standard HTTP status code plus a flat JSON body describing the error.
Format
Every error response has the same shape: a human-readable error string, the HTTP status
repeated as an integer code, and a message (an alias of error, kept stable for older
clients).
{
"error": "API key missing or invalid.",
"code": 401,
"message": "API key missing or invalid."
}Validation failures may add a fieldErrors object mapping each offending field to its message:
{
"error": "Validation failed.",
"code": 422,
"message": "Validation failed.",
"fieldErrors": {
"data": "destination must be a valid URL"
}
}There is no nested error.code / error.details envelope, and error identifiers are never
returned as string codes in the body. Machine-readable identifiers are delivered in the
X-ExaRoutes-Error-Code response header (see below).
HTTP status codes
| HTTP | Meaning |
|---|---|
| 400 | Malformed JSON, missing required field, or an upload rejected by server limits. |
| 401 | API key missing or invalid. |
| 403 | Not permitted: the feature is not on your plan, or your email is unverified. See the X-ExaRoutes-Error-Code header. |
| 404 | Resource does not exist. |
| 409 | Conflict (e.g. a duplicate resource). |
| 410 | Resource expired or was deleted. |
| 413 | Upload too large (max 10 MB per file). |
| 422 | Field-level validation failed. See fieldErrors. |
| 429 | Rate limit or plan quota hit. See the rate-limit headers and the X-ExaRoutes-Error-Code header. |
| 500 | Server-side error. A short refId is logged; retry with exponential backoff. |
| 503 | Service temporarily unavailable. |
The X-ExaRoutes-Error-Code header
Plan, quota, and feature-gate failures carry a stable identifier in the
X-ExaRoutes-Error-Code response header (not a body field). Branch on the header, not on
the error text.
| Header value | Typical HTTP | Meaning |
|---|---|---|
PLAN_LIMIT_REACHED | 429 | A per-plan quota was hit (e.g. daily/monthly QR generation, dynamic-code count, bulk orders). |
FEATURE_NOT_ON_PLAN | 403 | The requested capability is not included on your current plan (upgrade required). |
EMAIL_VERIFICATION_REQUIRED | 403 | The account’s email is not yet verified. |
Example: hitting a plan quota returns a plain body plus the header.
HTTP/1.1 429 Too Many Requests
X-ExaRoutes-Error-Code: PLAN_LIMIT_REACHED
Retry-After: 30
{
"error": "Daily QR generation limit reached for the qr.starter plan.",
"code": 429,
"message": "Daily QR generation limit reached for the qr.starter plan."
}Billing and workspace-administration routes (session-authenticated, used by the dashboard)
can emit additional identifiers such as ADDON_IN_USE, DOWNGRADE_OVER_CAP, and
WORKSPACE_REQUIRES_MFA. Bearer-authenticated QR integrations only see the three above.
Rate-limit headers
Per-IP and per-plan throttles emit the draft-7
combined RateLimit header (plus RateLimit-Policy), and Retry-After on 429 responses.
Rate-limit state lives in these headers, never in the response body. See
Rate limits for the full table.