Errors
Every planEvery plan.
Docs pages
Every error has the same JSON body: an error object with a machine-readable code and a human-readable message. Branch on code, not on the message, which may change.
401, 403 and 429 errors also carry upgrade_url (where to get a key or a bigger plan) and docs_url (the page that explains the error). A 429 adds plan, limit (daily or monthly: the window that blocked the call) and limit_value.
Error body
HTTP/1.1 403 Forbidden
{
"error": {
"code": "forbidden",
"message": "Transfer partners requires a Pro plan or above",
"upgrade_url": "https://cardapi.dev/pricing?utm_source=api&utm_medium=error&utm_campaign=forbidden",
"docs_url": "https://cardapi.dev/pricing#plan-fields"
}
}Rate-limited body
HTTP/1.1 429 Too Many Requests
Retry-After: 3600
{
"error": {
"code": "rate_limited",
"message": "Daily limit of 100 calls reached on the Free plan. Starter gives 500 calls/day and 15,000/month, with a 7-day free trial for new customers: https://cardapi.dev/pricing",
"plan": "free",
"limit": "daily",
"limit_value": 100,
"upgrade_url": "https://cardapi.dev/pricing?utm_source=api&utm_medium=error&utm_campaign=rate_limited",
"docs_url": "https://cardapi.dev/docs/rate-limits"
}
}Error codes
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_request | A parameter or the request body is invalid. The message names the parameter, e.g. a malformed slug or a limit that isn't a number. |
| 401 | unauthorized | The Authorization header is missing, the key is malformed or unknown, or the key was deactivated. |
| 403 | forbidden | Your plan doesn't include this endpoint. The message names the plan it needs, e.g. "Transfer partners requires a Pro plan or above". |
| 403 | account_suspended | The account is suspended. Contact support@cardapi.dev. |
| 404 | not_found | No such card, issuer, webhook or route. /v1/cards/compare names the slugs it couldn't find. |
| 409 | use_portal | POST /v1/auth/upgrade on an account that already has a paid plan. Change the plan in the developer portal. |
| 413 | payload_too_large | The request body is too large. |
| 429 | rate_limited | Your account's daily or monthly quota is used up. Retry-After gives the seconds until the blocking window resets; the X-RateLimit-* headers carry the numbers. |
| 500 | internal_error | Something failed on CardAPI's side. Retry later; if it persists, tell support@cardapi.dev. |
| 503 | service_unavailable | CardAPI briefly couldn't check your key or usage. Retry-After is 30. This is not your quota. |
| 504 | timeout | The request took longer than 30 seconds to process. |
Retrying
Retry 429, 503 and 504 after the Retry-After header (429 and 503 send one). Don't retry 400, 401, 403 or 404 unchanged: the same request gets the same answer.