Errors use HTTP status codes and a stable body. The message is safe to show to your staff; build logic on code, retryable and details, never on the message text.
{
"error": {
"code": "DEVICE_NOT_ELIGIBLE",
"message": "This device cannot be activated for the selected fleet.",
"retryable": false,
"request_id": "req_7Hs2…",
"details": { "field": "device_id" }
}
}Every response carries X-Request-Id. Quote it when you contact support — it lets us find the request without you sending any data.
Error codes
| Code | HTTP | Meaning | Retry? |
|---|---|---|---|
INVALID_REQUEST | 400 / 413 / 415 / 422 | The request is malformed or a field is invalid (details.field). 413: body over 1 MB; 415: not application/json. | No — fix the request. |
UNAUTHENTICATED | 401 | Missing, unknown, expired, rotated-out or revoked key, or an address outside the key's IP allowlist. | No — check the key. Repeated failures from one address are rate limited. |
INSUFFICIENT_SCOPE | 403 | The key lacks a scope (details.required) or is the wrong class for this API. | No — use a key with the right scope. |
RESOURCE_NOT_FOUND | 404 | The id does not exist for this partner, mode and key (including other tenants' ids). | No. |
PARTNER_ACCESS_REQUIRED | 403 | The Partner account is not active, or a feature is not enabled (details.feature). | No — see the portal. |
DEVICE_NOT_ELIGIBLE | 422 | The device cannot be used for this action (ownership, model, state). | No. |
PLAN_NOT_AVAILABLE | 422 | The plan or capability is not on your rate card or not included for this device. | No. |
IDEMPOTENCY_CONFLICT | 409 | The Idempotency-Key was used before with a different request. | No — use a new key. |
OPERATION_IN_PROGRESS | 409 | The same key is being processed, or the resource already has a change running. | Yes, after a short wait. |
BILLING_RESTRICTED | 402 | New charge-creating actions are paused until the outstanding balance is paid. Reads, invoices, payment recovery and deactivations still work. | After the balance is paid. |
PAYMENT_ACTION_REQUIRED | 402 | A payment needs authentication or a new payment method. | After completing the payment in the portal. |
RATE_LIMITED | 429 | Too many requests for this key and request class, or too many replays/test events. | Yes — after Retry-After seconds. |
SERVICE_TEMPORARILY_UNAVAILABLE | 503 | A temporary problem on our side or with the tracking platform. | Yes — honour Retry-After, back off. |
CONFLICT | 409 | The request conflicts with the current state (duplicate reference, already rotated, toggle limit reached — see details.reason). | No — re-read the resource. |
CREDIT_LIMIT_REACHED | 402 | The action would exceed your credit limit. | After paying or asking for a higher limit. |
QUOTE_EXPIRED | 410 | The hardware quote is no longer valid. | No — request a new quote. |
METHOD_NOT_ALLOWED | 405 | The path exists but not with this method (Allow header). | No. |
TEST_MODE_MISMATCH | 400 | The request mixes live and test (for example a test key minting a live key). | No. |
INTERNAL_ERROR | 500 | Something failed on our side. Nothing secret is exposed; the request id identifies it. | Yes, with backoff and the same Idempotency-Key. |
SERVICE_INACTIVE | 409 | The vehicle's tracking service is not active, so live data is not available (details.service_status). Journeys from active periods remain available. | No — activate the service first. |
Retrying well
- Retry only when
retryableis true (or the status is 429/503), with exponential backoff and jitter, and honourRetry-Afterwhen present. - Retry writes with the same
Idempotency-Key. - A timeout on your side is an unknown outcome: retry with the same key, or look the result up by
external_request_id, before doing anything else. - Another partner's id, an id from the other mode and an id outside your key's fleets all answer
404— by design.