Errors, rate limits & retries
Errors
Errors are RFC 9457 problem details with a stable
machine code. Branch on code, not on the message:
{
"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.
Rate limits
Each token may make 1000 requests per minute (live) or 100 (test). Every answer says where you are:
RateLimit-Limit: 1000
RateLimit-Remaining: 997
RateLimit-Reset: 42
Over 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.