Error body
Every error is the mirror image of the success envelope —success: false
with a stable machine-readable code and a human-readable message:
401
{ "success": false, "code": "missing_token", "message": "Missing bearer token" }
403
{ "success": false, "code": "missing_scope", "message": "Missing scope: classify:read" }
404
{ "success": false, "code": "consignment_not_found", "message": "Consignment not found" }
code (stable, never renamed), not on message (free text,
may change or carry request-specific detail). Schema validation failures
respond 400 with code: "validation_error" and the failing messages
joined into message:
400
{
"success": false,
"code": "validation_error",
"message": "country must be a 2-letter code"
}
HTTP statuses
| Status | Meaning | What to do |
|---|---|---|
200 OK | Request succeeded | — |
201 Created | Resource created | — |
400 Bad Request | Validation failed | Fix the fields named in message |
401 Unauthorized | Missing, invalid, or expired token | Mint a new token |
403 Forbidden | Token lacks the required scope, its organization doesn’t match the partner subdomain, or the feature isn’t enabled for the requested country | Check scopes; call the workspace the token belongs to |
404 Not Found | Resource doesn’t exist in this workspace | Check the ID — IDs from another partner always 404 |
409 Conflict | The request conflicts with existing state (duplicate code, resource in the wrong state) | Read code / message |
422 Unprocessable | The request was valid but couldn’t be fulfilled (unclassifiable input, a validation-rule rejection on create) | Read message / errors |
429 Too Many Requests | Rate limited — see Rate limits | Back off and retry with the Retry-After header |
5xx | Something went wrong on our side | Retry with exponential backoff |
Error codes
| Code | Status | Description |
|---|---|---|
bad_request | 400 | The request was malformed or invalid. |
validation_error | 400 | Schema validation failed; the message lists the failing fields. |
invalid_id | 400 | An id in the path or body is not a valid identifier. |
invalid_json | 400 | The request body is not valid JSON. |
related_not_found | 400 | A referenced record does not exist. |
unauthorized | 401 | Authentication failed. |
missing_token | 401 | No Authorization header was sent. |
invalid_token | 401 | The bearer token failed verification. |
forbidden | 403 | The credentials do not permit this action. |
account_key_mismatch | 403 | A customer-pinned credential supplied an account key (CDS accountKey / IPC eretailerIdentifier) that the workspace mapped to another customer. Account keys are sub-accounts under the credential’s customer — use one mapped to it, or an unmapped key. |
missing_scope | 403 | The token lacks a required scope; the message names it. |
insufficient_role | 403 | The user’s role does not permit this action. |
admin_only | 403 | The endpoint is restricted to platform administrators. |
tenant_mismatch | 403 | The token belongs to a different workspace than the request targets. |
feature_not_enabled | 403 | The feature or country is not enabled for this workspace. |
not_found | 404 | The requested resource does not exist in this workspace. |
consignment_not_found | 404 | No consignment with that id in this workspace. |
parcel_not_found | 404 | No parcel with that id (or barcode) on this consignment. |
item_not_found | 404 | No item with that id. |
customer_not_found | 404 | No customer with that id. |
import_not_found | 404 | No import with that id. |
manifest_not_found | 404 | No manifest with that id. |
shipment_not_found | 404 | No shipment with that id. |
catalogue_not_found | 404 | No catalogue (or catalogue entry) with that id. |
product_not_found | 404 | No product with that id or code. |
group_not_found | 404 | No group with that id or code. |
account_not_found | 404 | No account with that id. |
template_not_found | 404 | No template with that id. |
rule_not_found | 404 | No rule with that id. |
run_not_found | 404 | No run with that id. |
invoice_not_found | 404 | No invoice with that id. |
fee_not_found | 404 | No fee (or fee rule) with that id. |
partnership_not_found | 404 | No partnership with that id. |
transfer_not_found | 404 | No partner transfer with that id. |
thread_not_found | 404 | No email thread with that id. |
message_not_found | 404 | No message with that id. |
organization_not_found | 404 | No organization with that id. |
location_not_found | 404 | No location with that id. |
carrier_not_found | 404 | No carrier with that code in the catalogue. |
carrier_account_not_found | 404 | No connected carrier account matches. |
filer_account_not_found | 404 | No customs filer account with that id. |
case_not_found | 404 | No case with that id. |
entry_not_found | 404 | No customs entry with that id. |
document_not_found | 404 | No document with that id. |
webhook_not_found | 404 | No webhook with that id. |
job_not_found | 404 | No job with that id. |
flow_not_found | 404 | No flow with that id. |
agent_not_found | 404 | No agent with that id. |
agent_run_not_found | 404 | No run with that id for this agent. |
agent_learning_not_found | 404 | No learning with that id for this agent. |
release_not_found | 404 | No data release with that id. |
data_source_not_found | 404 | No data source with that id. |
charge_type_not_found | 404 | No charge type with that id or code. |
api_client_not_found | 404 | No API client with that id. |
member_not_found | 404 | No workspace member with that id. |
invitation_not_found | 404 | No invitation with that id, or the invite code is invalid/expired. |
domain_not_found | 404 | No custom domain with that id. |
label_not_found | 404 | No label with that id. |
service_not_found | 404 | No carrier service with that code. |
file_not_found | 404 | The referenced file is missing or has expired. |
reconciliation_not_found | 404 | No reconciliation with that id. |
rate_not_found | 404 | No rate with that id. |
app_not_connected | 404 | The app is not connected for this workspace. |
pod_not_available | 404 | The carrier has no proof-of-delivery document for the shipment — not delivered yet, signature unavailable, or outside the carrier’s retention window. |
conflict | 409 | The request conflicts with the current state of the resource. |
already_exists | 409 | A unique value (code, barcode, external id) is already in use. |
agent_paused | 409 | Resume the agent before running it. |
code_in_use | 409 | The chosen code/identifier is already taken by another record. |
barcode_exists | 409 | The barcode already belongs to another parcel in this workspace. |
already_connected | 409 | The partnership, domain, or app connection already exists. |
import_in_progress | 409 | The import is locked by an active run. |
transfer_not_pending | 409 | The partner transfer was already accepted or declined. |
invalid_state | 409 | The action is not allowed in the resource’s current state; the message explains why. |
portal_delete_blocked | 409 | Portal deletes are refused when the shipment has an active hold or a booked carrier label; an operator must action it. |
payload_too_large | 413 | The request body exceeds the size limit. |
unsupported_media_type | 415 | The uploaded file’s type is not accepted for this endpoint. |
unprocessable | 422 | The request was valid but could not be fulfilled. |
empty_file | 422 | The uploaded file is empty or has no usable rows. |
label_generation_failed | 422 | The carrier could not produce a label for this shipment. |
rate_limited | 429 | Rate limit exceeded — back off and retry (see Retry-After). |
internal_error | 500 | Something went wrong on our side. Retry with backoff. |
not_implemented | 501 | The operation is not supported for this resource. |
oauth_not_configured | 501 | The platform has no OAuth credentials configured for this app. |
not_supported | 501 | The integration (e.g. the carrier behind the label) does not support the requested operation. |
upstream_error | 502 | An external service (carrier, provider) failed to respond correctly. |
carrier_error | 502 | The carrier’s API rejected or failed the request; the message carries the carrier’s reason. |
Exceptions to the envelope
When a calculate request is rejected by your workspace’s country validation rules, the400 body is an errors array naming each failed
rule:
400
{
"errors": [
{ "code": "US_MAX_VALUE", "description": "Line value exceeds the configured limit" }
]
}
/v1/cds) speaks the UPU spec’s own
{ "errors": [{ "code", "description" }] } envelope with spec-fixed numeric
codes.
404 is also the answer for resources that exist but belong to another
partner — the API never reveals whether an ID exists outside your
organization.