Errors and rate limits
Last updated July 30, 2026
Response envelope
Every response, success or failure, uses the same JSON envelope.
Success:
json
{
"success": true,
"sandbox": true,
"data": { ... },
"meta": { "page": 1, "limit": 20, "total": 42, "totalPages": 3 }
}
sandbox tells you which environment served the request (redundant with your key, but convenient for logging). meta is only present on paginated list endpoints.
Error:
json
{
"success": false,
"error": {
"code": "insufficient_funds",
"message": "Insufficient wallet balance",
"details": []
}
}
Always branch on success, never on HTTP status code alone, though the status code and error.code are kept consistent per the table below.
Error codes
error.code | HTTP status | Meaning |
|---|---|---|
authentication_error | 401 | Missing, invalid, or revoked API key |
environment_mismatch | 401 | The key's prefix doesn't match its stored environment (should never happen in normal use, indicates a tampered or corrupted key) |
permission_error | 403 | Your account can't perform this action right now (e.g. a PROD_ key used before go-live approval, or a suspended account) |
invalid_request | 400 | Missing or malformed fields, see error.message for specifics |
not_found | 404 | The requested resource doesn't exist or doesn't belong to you |
insufficient_funds | 402 | Your wallet balance is too low to create this shipment |
rate_limited | 429 | Too many requests, see below |
api_error | 500 | An unexpected server error, safe to retry |
Rate limits
The API allows 300 requests per minute per API key. If you exceed this, you'll receive a rate_limited error. Limits are scoped to the key itself, not your IP address, so requests from different servers using the same key share the same limit.