Error codes
Every error is application/problem+json (RFC 9457). The
code is the contract: it does not change, even when the wording of title or detail does.
Branch on code, never on title.
{ "type": "https://cargofollow.com/errors/validation_failed", "title": "Validation failed", "status": 422, "detail": "The body does not match the schema.", "code": "validation_failed", "request_id": "req_01M2FP3S65WEANPZF49VGJRATH", "errors": [{ "path": "goods.0.gross_weight_kg", "message": "Expected number, received string" }], "warnings": []}code— the stable error code from the table below.request_id— quote this to support; it is how we find your exact request.errors— what is wrong per field, onvalidation_failedand rule findings.warnings— findings that did not block the request.title— English by default, translated when you sendAccept-Language: nl.
Every code
Section titled “Every code”The table comes from the register in @freightapi/core/errors; what the API can return is here, and
nothing else.
| Code | Status | Meaning |
|---|---|---|
bad_request | 400 | Bad request The request is malformed: a wrong parameter, a missing header or a combination that does not exist. |
invalid_cursor | 400 | Invalid cursor The `cursor` did not come from an earlier list response, or it expired. Start the list again without a cursor. |
invalid_id | 400 | Invalid identifier An identifier in the path or the body does not have the expected shape. |
malformed_json | 400 | Malformed JSON body The body is not valid JSON. Check the content type and the encoding. |
invalid_api_key | 401 | Invalid API key The API key does not exist, was revoked, or belongs to another environment. |
unauthorized | 401 | Authentication required No API key was sent. Put it in the `Authorization: Bearer` header. |
forbidden | 403 | Forbidden The key is valid but is not allowed to see or change this resource. |
insufficient_scope | 403 | Insufficient scope The key lacks the scope this route requires. Create a key with the right scopes. |
live_not_enabled | 403 | Live mode is not enabled for this organisation The organisation is not cleared for live yet. Work with an `sk_test_` key in the sandbox. |
test_mode_only | 403 | Only available in test mode This route only exists in the sandbox, for example the simulation endpoints. |
turnstile_failed | 403 | Turnstile verification failed The Turnstile check of the public validator did not pass: the token is missing, expired or already used. Fetch a new token and try again. |
two_factor_required | 403 | Two-factor authentication is required The console session has not shown a second factor yet, or the account has none while the organisation requires one. Only the console sees this code; an API key has no second factor. |
invoice_not_available | 404 | The invoice is not available yet The shipment has not been delivered yet, so there is no invoice: an invoice follows the proof of delivery. |
not_found | 404 | Not found The resource does not exist, or not within this organisation and this mode. |
pod_not_available | 404 | The proof of delivery is not available yet The shipment has not been delivered yet, so there is no proof of delivery to fetch. |
already_signed | 409 | Already signed A signature was already recorded for this role. |
conflict | 409 | Conflict The request conflicts with the current state of the resource. |
field_frozen | 409 | Field is frozen in the current status The field is frozen in the current status; after issuing, the consignment note fields are fixed. |
idempotency_in_progress | 409 | A request with this idempotency key is still running An earlier request with this `Idempotency-Key` is still running. Wait and retry. |
idempotency_key_reused | 409 | Idempotency key reused with a different request The same `Idempotency-Key` was used for a different body. Use a fresh key per request. |
invalid_state | 409 | The shipment is in the wrong state for this operation The shipment is in a status in which this operation has no meaning. |
invalid_transition | 409 | Invalid state transition The state machine forbids this transition, for example `delivered` after `cancelled`. |
shipment_immutable | 409 | The shipment can no longer be changed The shipment is finished or cancelled and no longer changes. |
link_expired | 410 | Signed link expired The signed link expired. Request a new one. |
token_expired | 410 | The link has expired The inspection or signing link expired. |
token_revoked | 410 | The link was withdrawn The sign link was withdrawn by the party that sent it. Ask for a new link. |
token_rotated | 410 | The link was replaced by a newer one The link was replaced by a newer one; the old one no longer works. |
payload_too_large | 413 | Payload too large The body or the file exceeds the limit of the route. |
unsupported_media_type | 415 | Unsupported media type The `Content-Type` is not supported on this route. |
identification_invalid | 422 | The identification is unknown, already used or expired The `identification_token` is unknown, already used, older than fifteen minutes or belongs to another sign link. One identification signs once. Ask for a new one. |
identification_required | 422 | This signature needs an identification at the trust service provider This sign link asks for `ades` or `qes`. Identify the signer first with `POST /v1/sign/:token/identification` and send the `identification_token` along. Not a failure but a step: the sign PWA renders it as a screen, not as an error. |
invoice_incomplete | 422 | The invoice misses something EN 16931 requires The shipment or the query lacks a fact EN 16931 requires — `charges.carriage`, the VAT rate of a domestic run, or the payee account of a Dutch seller. `detail` names which one. |
otp_invalid | 422 | The one-time password is wrong or expired The one-time password is wrong, expired or already used. Ask for a new one with `POST /v1/sign/:token/otp`. The same answer covers an `otp_verified_token` that was already spent. |
subset_unknown | 422 | Unknown eFTI subset The requested `subset` is not an eFTI subset this platform projects. `GET /v1/shipments/:id/efti` without `subset` returns the common data set. |
two_factor_invalid | 422 | The two-factor code is wrong, expired or already used The six digits or the recovery code are wrong, expired or already used. One answer for all three: which of the three it was is exactly what an attacker wants to learn. |
validation_failed | 422 | Validation failed The body parses but does not validate. The `errors` array names the problem per field. |
otp_locked | 429 | Too many wrong one-time passwords Five wrong codes in a row: this recipient is locked until the ten-minute window passes. `Retry-After` says how long. |
rate_limited | 429 | Too many requests Too many requests. Respect `Retry-After` and the `RateLimit-*` headers. |
internal_error | 500 | Internal error An unexpected error on our side. Report the `request_id` to support. |
pdf_render_failed | 500 | The consignment note PDF could not be rendered The consignment note PDF could not be built. Retry, and report the `request_id` if it keeps failing. |
not_implemented | 501 | Not implemented The route is declared but not filled in yet. |
provider_unavailable | 502 | The eCMR provider is unavailable The eCMR provider behind this route is not answering. Try again later. |
billing_not_configured | 503 | Billing is not configured for this organisation This deployment has no billing provider, so there is no customer portal and nothing is charged. Usage is still visible through `GET /v1/usage`. |
qtsp_unavailable | 503 | The trust service provider is unavailable The trust service that signs `ades` and `qes` is absent or refused. Without the binding `QTSP_PROVIDER` this deployment has none — the default in production, because a test certificate is not a qualified signature. Signing at `platform_auth` is unaffected. |
service_unavailable | 503 | Service unavailable The API is temporarily unavailable. Try again later. |