Errors
Errors use the same envelope as successes, with a machine-readable code, a human-readable message, and a matching HTTP status:
{
"success": false,
"error": {
"code": "rate_limited",
"message": "Per-minute rate limit exceeded. Retry after 23s.",
"status": 429
}
}All error codes
| Code | HTTP | Meaning & handling |
|---|---|---|
| invalid_key | 401 | Missing, malformed, or revoked API key. Check the Authorization header. |
| rate_limited | 429 | Per-minute limit exceeded. Honor the Retry-After header and back off. |
| quota_exceeded | 429 | Monthly quota exhausted. /quota still works so you can monitor; resets on the 1st. |
| plan_required | 403 | The endpoint isn't included in your plan (e.g. /convert on Free). Upgrade to use it. |
| invalid_params | 400 | A parameter is missing or malformed — the message says exactly which. |
| unsupported_currency | 400 | A currency code isn't supported. GET /api/v1/currencies lists what is. |
| date_out_of_plan_range | 403 | The requested date is older than your plan's history window. |
| no_data | 404 | No rates stored for the requested date or range. |
| internal_error | 500 | Something went wrong on our side. Safe to retry with backoff. |
Retry guidance
- •
429 rate_limited: wait forRetry-Afterseconds, then retry. - •
429 quota_exceeded: don't retry — the quota resets monthly. Upgrade or reduce volume. - •
500 internal_error: retry with exponential backoff (e.g. 1s, 2s, 4s). - • 4xx errors other than 429: fix the request; retrying the same request returns the same error.