Error Handling
The DayZero API uses standard HTTP status codes and returns one consistent JSON envelope for every non-2xx response (schema ErrorResponse in the OpenAPI spec).
Error Response Format
{
"error": "not_found",
"message": "Invoice '01912345-abcd-7000-8000-000000000042' not found",
"code": "NOT_FOUND_006",
"request_id": "3f0e7c2a-4b1d-4a8e-9c2f-1d2e3f4a5b6c"
}| Field | Description |
|---|---|
error |
Machine-readable category: validation_error, unauthorized, forbidden, not_found, conflict, rate_limited, server_error, service_unavailable |
message |
Human-readable explanation. May change between releases — don't branch on it |
code |
Stable, specific code in the form CATEGORY_NNN (e.g. AUTH_010, NOT_FOUND_006). Branch on this |
request_id |
Correlation ID for this request; also returned in the X-Request-ID response header. Quote it when contacting support |
errors |
Only on 400/422 validation failures: a map of field name → message |
Validation errors name the offending fields:
{
"error": "validation_error",
"message": "Validation failed: due_date: Input should be a valid date",
"errors": {
"due_date": "Input should be a valid date"
},
"code": "GEN_002",
"request_id": "3f0e7c2a-4b1d-4a8e-9c2f-1d2e3f4a5b6c"
}Send Accept: application/json on every request. Errors are only rendered as HTML pages for browser-style text/html requests, but stating JSON removes the ambiguity.
Status Codes
| Status | error |
Typical code |
When |
|---|---|---|---|
200 |
— | — | Request completed |
201 |
— | — | Resource created |
400 |
validation_error |
GEN_002, VALIDATION_* |
Invalid parameters or a business-rule violation; errors names the fields |
401 |
unauthorized |
AUTH_001, AUTH_008 (missing x-business-id), AUTH_010 (no access to that business) |
Missing, invalid, expired or revoked token, or wrong business |
403 |
forbidden |
AUTH_002 |
Token valid but its scope or role doesn't permit the operation (e.g. a read_only token calling POST) |
404 |
not_found |
NOT_FOUND_* |
Resource doesn't exist — or belongs to a different business than x-business-id |
409 |
conflict |
CONFLICT_* |
Duplicate or state conflict (e.g. voiding an invoice that has payments) |
422 |
validation_error |
GEN_002 |
Request body or parameters failed schema validation; errors names the fields |
429 |
rate_limited |
GEN_005 |
Too many requests — back off exponentially and retry the same request |
500 |
server_error |
GEN_003 |
Unexpected error — retry idempotent requests with backoff; quote request_id to support |
503 |
service_unavailable |
GEN_004 |
Temporary maintenance or dependency outage — retry with backoff |
Retry guidance
- Retry
429,500,503with exponential backoff (start at 1–2 s, cap at ~30 s). - Don't retry
400,401,403,404,409,422unchanged — the request itself is the problem. POSTrequests that create records have no idempotency key yet. Before re-sending one after a timeout or5xx, check whether the record already exists (list with the filter you would have used) to avoid duplicates.
Common Mistakes
Wrong business context: Getting 404 on a resource you know exists? Check that x-business-id matches the business that owns it.
Missing business header: 401 with code: "AUTH_008" means x-business-id was required and absent. Only GET /api/v1/businesses (and a handful of user-level endpoints) work without it.
Amounts in dollars instead of cents: All monetary values are integers in cents. $150.00 should be sent as 15000; 150.00 fails validation.
Expired token: Tokens with an expiration return 401 once expired. Generate a new one from Settings → Developers.
Read-only token on a write: A token created with the read_only scope gets 403 on every non-GET request.