Reference
Errors
HTTP status codes, error types and codes returned by the API, with guidance on which errors to retry and which to fix.
The API uses standard HTTP status codes. Codes in the 2xx range mean success, 4xx means something in the request needs fixing, and 5xx means something went wrong on our side.
This is preview documentation for a prototype. Endpoints, fields and keys are illustrative.
The error object
Every error returns the same JSON shape:
{
"error": {
"type": "invalid_request_error",
"code": "parameter_missing",
"message": "Missing required field: currency.",
"param": "currency",
"request_id": "req_4Tx9bL2mQ7vH",
"doc_url": "https://international-orders.com/docs-preview/errors#parameter_missing"
}
}
Include request_id when you contact support. It lets us find the exact request.
HTTP status codes
| Status | Meaning |
|---|---|
200 OK | The request succeeded |
201 Created | A new object was created |
400 Bad Request | The request is invalid, often a missing or malformed field |
401 Unauthorized | No valid API key was sent |
402 Payment Required | The request was valid but the payment failed |
403 Forbidden | The key doesn't have permission for this request |
404 Not Found | The object doesn't exist, or belongs to the other mode |
409 Conflict | The request conflicts with the object's state, or reused an idempotency key |
429 Too Many Requests | You've hit a rate limit |
500, 502, 503 | Something went wrong on our side |
Error types
| Type | What to do |
|---|---|
authentication_error | Check the key and mode. See Authentication |
invalid_request_error | Fix the request. param names the field |
payment_error | Show the shopper message and let them try again |
rate_limit_error | Back off and retry |
api_error | Retry with the same idempotency key |
Common codes
| Code | Status | Meaning |
|---|---|---|
parameter_missing | 400 | A required field is missing |
parameter_invalid | 400 | A field has the wrong type or format |
amount_too_small | 400 | Below the minimum for the currency |
currency_not_supported | 400 | The currency isn't available for this destination |
invalid_bank_account | 400 | Payout bank details failed validation |
quote_expired | 400 | The landed-cost quote is more than 24 hours old |
card_declined | 402 | The issuer declined the card |
insufficient_funds | 402 | The shopper's account can't cover the amount |
permission_denied | 403 | A restricted key lacks access |
resource_missing | 404 | No object with that ID |
order_not_capturable | 409 | The order isn't in authorized status |
refund_exceeds_payment | 409 | The refund is larger than what's left to refund |
idempotency_key_reused | 409 | Same key, different request body |
balance_insufficient | 409 | Your balance can't cover the payout |
Retrying safely
Retry these, with exponential backoff and the same Idempotency-Key:
429responses. Honour theRetry-Afterheader.5xxresponses.- Network timeouts where you got no response.
Don't retry other 4xx errors unchanged. They will fail the same way.
try {
await io.refunds.create({ order: "ord_7Hc2kQ9xL4mP", amount: 4500 });
} catch (err) {
if (err instanceof InternationalOrders.errors.InvalidRequestError) {
console.error(err.code, err.param);
} else {
throw err;
}
}
The server SDKs retry 429 and 5xx responses twice by default.
Rate limits
Test mode allows 25 requests per second. Live mode allows 100 per second per account, with short bursts above that. Each response includes IO-RateLimit-Remaining so you can slow down before you hit the limit.