Help Center

Errors

The atoship API uses conventional HTTP response codes to indicate the success or failure of an API request. Codes in the 2xx range indicate success, 4xx indicate client errors, and 5xx indicate server errors.

HTTP Status Codes

Success Codes

200
OK

Request succeeded

201
Created

Resource created successfully

Client Errors

400
Bad Request

Invalid request parameters

401
Unauthorized

Invalid or missing API key

402
Payment Required

Insufficient balance or payment failed

403
Forbidden

API key lacks required permissions

404
Not Found

Resource does not exist

422
Unprocessable Entity

Validation error on request data

429
Too Many Requests

Rate limit exceeded

Server Errors

500
Internal Server Error

Something went wrong on our end

503
Service Unavailable

API is temporarily unavailable

Error Object

Every error returns a JSON body with an error object. Branch on the HTTP status code and error.code — those two are on every error response.

error.codestring

Machine-readable code in UPPER_SNAKE_CASE (e.g. "RATE_LIMIT_EXCEEDED"). This is the field to branch on.

error.messagestring

Human-readable description. Safe to show a user; do not parse it — the wording changes.

error.detailsarray (optional)

Validator output on a 400. Each entry carries path and message; the shape follows the field that failed.

error.paramstring (optional)

The offending field, when a single one can be named (e.g. "to_address.phone").

error.retryAfternumber (optional)

Seconds to wait, on a 429 only. The same value is in the Retry-After header.

Responses also carry object, and some carry mode. Neither is guaranteed on every endpoint, so do not branch on them. There is no type or request_id field.

Handling Errors

Check the HTTP status code

Use the status code to determine the error category

Branch on error.code

The UPPER_SNAKE_CASE code is the stable handle — match on it, not on the message text

Display the message

Show the message to users for actionable feedback

Back off on 429

Wait error.retryAfter seconds (or read the Retry-After header) before retrying

ERROR
Response Examples
1{
2 "object": "Error",
3 "error": {
4 "code": "VALIDATION_ERROR",
5 "message": "Invalid request data",
6 "details": [
7 {
8 "code": "custom",
9 "path": ["parcel"],
10 "message": "Send `parcel` for a single box, or `parcels` for a multi-piece shipment."
11 }
12 ]
13 }
14}
Common Error Codes
VALIDATION_ERRORRequest failed validation
UNAUTHORIZEDMissing or invalid API key
FORBIDDENKey lacks access to this resource
NOT_FOUNDNo such resource
INSUFFICIENT_FUNDSWallet balance too low
RATE_LIMIT_EXCEEDEDToo many requests
INTERNAL_SERVER_ERRORSomething broke on our side

Endpoints add their own codes — a label purchase can return DESTINATION_PHONE_REQUIRED or CUSTOMS_REQUIRED. Treat an unrecognised code as its HTTP status class.

Rate Limits
Per minute5 requests
Per day300 requests

The budget belongs to your organization, not to a key — every API key and user on the account draws from the same one.

Counted in fixed windows. The daily budget resets at 00:00 UTC, and a 429 carries a Retry-After header.

Need a higher limit? Contact [email protected] — limits are raised per account.