Errors
A refused request answers with an HTTP status and an RFC 9457 problem (Content-Type: application/problem+json).
Branch on the status first, then on code. Never parse title or detail: they are for people.
From a service
Most errors come from the service behind the operation:
{
"type": "https://errors.zaitrack.app/ZTK74001",
"title": "Not Found",
"status": 404,
"code": "ZTK74001",
"detail": "not found"
}
codeisZTKand digits. Each service has its own range, and a code keeps its meaning once published.detailsays what was wrong, for examplevehicleId (required) and driverId must be UUIDs. A few services put the message intitleand send nodetail.
| Status | Means |
|---|---|
400 | The body or a parameter is invalid: fix the request. |
401 | The gateway gave the service no organisation (a gateway or configuration fault: report it). |
404 | No such resource in your organisation. Another organisation's resource is also 404. |
409 | The resource's state forbids the action (a device already bound, a job already dispatched). |
412 | If-Match names a version that is no longer current: read again. |
422 | The body names something that does not exist or is not yours (a device or driver id). |
500 | A fault on our side: retry later and report the X-Zaitrack-Request-Id. |
From the gateway
The gateway answers before the service when a credential, scope, idempotency key or region is wrong. Its
problems have a type under https://api.zaitrack.app/errors/, a dotted code and the request_id:
{
"type": "https://api.zaitrack.app/errors/scope-missing",
"title": "Required scope missing",
"status": 403,
"code": "auth.token.scope_missing",
"detail": "Missing scopes: vehicles:write",
"request_id": "…"
}
| Status | code | Means |
|---|---|---|
401 | auth.api_key.invalid | The key is malformed, unknown, revoked or expired. |
403 | auth.api_key.ip_not_allowed | The key has an IP allowlist and your address is not on it. |
403 | auth.tenant_missing | The credential is not bound to an organisation. |
403 | auth.token.scope_missing | The credential lacks the operation's scope; detail names it. |
403 | step_up_required | The operation needs a recent MFA step-up (device commands). |
400 | idempotency.required | The operation needs an Idempotency-Key. |
409 | idempotency.body_mismatch | The key was used before with a different body. |
409 | idempotency.in_flight | A request with this key is still running. |
421 | misdirected_request | Your organisation is in another region: follow Location. See Regions. |
503 | auth.api_key.unavailable, idempotency.unavailable | A dependency of the gateway is down: retry with backoff. |
Two answers are not problems:
- An invalid or expired OAuth access token gets
401with aWWW-Authenticate: Bearerheader. - A request over a rate limit gets
429with{"error_msg": "rate limit exceeded"}. See Rate limits.