Errors
The TOVR REST API error catalog — the error envelope, the six error types, every error code with its HTTP status and what to do about it, and retry guidance. Every error's doc_url links to an entry on this page.
Every /api/v1 error answers with a non-2xx status and the same JSON envelope. Each error's
doc_url links to its entry on this page. The conventions shared by all three TOVR APIs are in
API conventions; this page is the catalog for the TOVR REST API.
Response format
{
"error": {
"type": "invalid_request_error",
"code": "validation_failed",
"message": "The request did not match the expected shape.",
"param": "contacts",
"details": [{ "path": "contacts.0.email", "code": "invalid_string", "message": "Invalid email" }],
"request_id": "req_…",
"doc_url": "https://tovr.eu/docs/tovr/reference/errors#validation_failed"
}
}| Field | Always present | Description |
|---|---|---|
type | yes | The coarse bucket. It never gains a member without an API version bump. |
code | yes | The specific cause, from the closed list below. Branch on this. |
message | yes | A human-readable explanation, in English. Do not parse it. |
param | sometimes | The field or header at fault, when one can be named. |
details | sometimes | Machine-shaped specifics, such as validation issues. |
request_id | yes | Also sent as the X-Request-Id header. Quote it in a support request. |
doc_url | yes | A link to this page, at the entry for code. |
type tells you what kind of action fixes the error. code tells you which one. A client that
switches only on code should still have a fallback per type, because new codes can be added.
message is always English, in every locale, as it is with most public APIs. code is the
contract and does not change. This page is translated.
Types
type | Meaning |
|---|---|
authentication_error | The credentials are missing or not valid. |
permission_error | The caller is authenticated but not allowed to do this. |
invalid_request_error | The request cannot be served as sent. |
conflict_error | The request conflicts with data that already exists. |
rate_limit_error | Reserved. Today the per-minute rate limit answers with rate_limited and the type invalid_request_error. |
api_error | A fault on TOVR's side or in a service TOVR depends on. |
Authentication errors
A 401 is answered before the request reaches the error envelope, so today its body is a plain
{"error": "Unauthorized: …"}. Branch on the 401 status and the
WWW-Authenticate: Bearer error="invalid_token" header, then get a new token as described in
Authentication.
missing_credentials
401. The request has no Authorization: Bearer header. Send the access token with every
request.
invalid_token
401. The token is not one TOVR issued, or it was revoked. Get a new token. Do not retry the same one.
expired_token
401. The token was valid but has expired. Tokens last one hour. Get a new token and retry.
Permission errors
insufficient_scope
403. The token does not have the scope this endpoint needs. The REST API overview lists the scope for each endpoint. Give the client application that scope, then get a new token. Retrying with the same token does not help.
forbidden
403. The token has the right scope, but this organization may not act on this object. Do not retry.
quota_exceeded
402, type permission_error. The organization has used its monthly API request quota. Waiting
does not help until the month resets. Upgrade the plan to continue. See
Rate limiting and quota.
Invalid request errors
validation_failed
422. The body, query or path parameters do not match the expected shape. details lists each
issue with its path. A malformed Idempotency-Key header answers 400 with
param: "Idempotency-Key". Fix the request. Do not retry it unchanged.
unknown_parameter
422. Reserved for a parameter the endpoint does not accept. No endpoint returns it today.
invalid_id
422. An id in the path is not a valid identifier. Check that you sent the id that TOVR returned.
invalid_cursor
422. The cursor value could not be decoded. Send the next_cursor from the previous page
unchanged, or start again without a cursor.
contact_required
422, param: "contacts". A shipment must name at least one contact with a name and an
email or phone, so that a carrier can reach someone. Add the contact to the request body.
org_not_reachable
422, param: "visibility". The organization cannot publish freight until its profile says how
a carrier can reach it. The message lists what is missing. Complete the organization profile in
Settings → General, or create the shipment with visibility: "private". Retrying the same
request does not help.
insufficient_market_data
422. The request was valid, but there is not enough market data to price that lane.
details.estimate contains the full estimate, with zero prices and quality_status: "INSUFFICIENT_DATA". Changing the request does not help. Try a different lane, or try again
later when more data is available.
cursor_expired
410. The cursor points at events older than the 30-day retention window, so your copy of the
data may have gaps. Read the current state again from the list endpoints, then resume from the
next_cursor of a new GET /v1/events. See Events.
not_found
404. The object does not exist, or it is not visible to this organization. The two cases look the same on purpose.
rate_limited
429, type invalid_request_error. The client application sent more requests per minute than
its limit allows. Wait for the number of seconds in the Retry-After header, then retry. See
Rate limiting and quota.
Conflict errors
duplicate_external_id
409. Your organization already has an object with this external_id. Read the existing object
instead of creating it again, or send a different external_id.
external_id_owned_by_another_org
409. Another organization already uses this external_id. Send a different external_id.
idempotency_key_reuse
409, param: "Idempotency-Key". This Idempotency-Key was already used for a different
request. Use a new key for each operation. Use the same key only when you retry the same request.
See Idempotency.
API errors
internal_error
500. A fault on TOVR's side. Retrying the same request does not help. Contact support and quote
the request_id.
service_unavailable
503. A service that TOVR depends on is unavailable. Your request was valid. Retry with exponential backoff.
Retry strategy
429 rate_limited: wait for theRetry-Afterseconds, then retry.503 service_unavailable: retry with exponential backoff (1 s, 2 s, 4 s), then stop after three attempts.500 internal_error: do not retry. Contact support and quote therequest_id.402 quota_exceeded: do not retry until the month resets or the plan is upgraded.401: get a new token, then retry once.- Other
4xx: do not retry. Fix the request first.
Mutations that you retry should send an Idempotency-Key, so that a retry never creates the same
object twice.
Authentication
The TOVR REST API uses the OAuth 2.0 client-credentials flow. Exchange a client_id and client_secret at the token endpoint for a one-hour bearer token, then send it as an Authorization header on every request.
Shipments
Create a shipment (a nested tree of stops, contents, costs, and identifiers), list your shipments, get one by its master ID, and change its status or visibility.