Errors, rate limits & retries
Errors
Errors are RFC 9457 problem details with a stable
machine code. Branch on code, not on the message:
JSON
{
"type": "https://api.antivio.app/problems/request.validation_failed",
"title": "Unprocessable Entity",
"status": 422,
"code": "request.validation_failed",
"detail": "One or more fields are invalid.",
"errors": [
{ "field": "recipient_phone", "code": "shipment.recipient_phone_invalid", "message": "…" }
]
}| Status | Common codes | What to do |
|---|---|---|
| 400 | request.malformed_body, idempotency.key_required | fix the request |
| 401 | auth.invalid_token, auth.missing_token | the token is wrong, revoked or expired: get a new one |
| 403 | authz.forbidden | the token lacks a scope, or the role behind it does |
| 403 | auth.api_token_not_allowed | this route is not part of the public API |
| 403 | auth.token_owner_inactive | the person who made the token can no longer act: make a new token |
| 404 | shipment.not_found, … | the resource does not exist or is not yours |
| 409 | idempotency.key_reused, shipment.transition_not_allowed, … | a conflict with the current state |
| 412 / 428 | request.precondition_failed / request.precondition_required | send the current ETag in If-Match |
| 422 | request.validation_failed | see errors[] |
| 429 | rate_limited | wait Retry-After seconds |
| 5xx | internal | retry with backoff, with the same Idempotency-Key |
Idempotency
Requests that create something or change a state (POST to create, confirm, cancel, replay, …)
need an Idempotency-Key header: 1 to 255 visible ASCII characters, unique per operation (your
order number works well).
- The same key with the same request within 24 h returns the stored answer, with
Idempotent-Replayed: true; nothing happens twice. - The same key with a different request answers
409 idempotency.key_reused. - While the first request is still running, a retry answers
409 idempotency.in_progress. - Keys belong to the token: two tokens may use the same key without seeing each other's answers. An app's access tokens share their installation's keys, so a retry after a refresh still gets the first answer.
Rate limits
Each token may make 1000 requests per minute (live) or 100 (test). Every answer says where you are:
HTTP
RateLimit-Limit: 1000
RateLimit-Remaining: 997
RateLimit-Reset: 42Over the limit you get 429 rate_limited with Retry-After (seconds until the minute ends).
Changing a resource safely
Reads of a single shipment return an ETag. PATCH needs it in If-Match, so you never
overwrite a change you have not seen: on 412 read it again and redo your change.