Errors
All errors use the same JSON envelope. Match on code rather than message — messages may change.
Error format
{
"error": {
"code": "rate_limited", // machine-readable, stable
"message": "Rate limit exceeded. Limit: 5 req/s (burst: 10).",
"request_id": "req_4f2a9b" // include this when contacting support
}
}Error codes
| HTTP | Code | When it fires | How to handle |
|---|---|---|---|
| 400 | invalid_request | Request body is malformed JSON, or a required field is missing or wrong type. | Fix the request body. Check field names and types. |
| 400 | invalid_address | The address format does not match the specified chain (e.g., not a valid EVM or Tron address). | Validate address format before sending. See chain-specific format rules. |
| 401 | unauthorized | Authorization header is missing, malformed, or the key is invalid/revoked. | Check that the header is "Authorization: Bearer <key>". Verify the key is active in the dashboard. |
| 402 | quota_exceeded | Monthly request quota is exhausted. | Upgrade your plan or wait for the quota to reset on the 1st of next month. |
| 403 | forbidden | The API key is valid but belongs to a Free-tier org, which does not include API access. | Upgrade to Starter or higher. |
| 429 | rate_limited | Requests per second exceeded the plan limit. | Retry with exponential backoff. See Rate Limits. |
| 500 | internal_error | Unexpected server-side error. | Retry once after a short delay. If persistent, contact support. |
Error handling pattern
response = requests.post(url, headers=headers, json=body, timeout=10)
if response.status_code == 200:
result = response.json()
# handle result
elif response.status_code in (400, 401, 402, 403):
# Don't retry — fix the request or auth
error = response.json()["error"]
raise ValueError(f"{error['code']}: {error['message']}")
elif response.status_code == 429:
# Retry with backoff
time.sleep(backoff_delay)
elif response.status_code == 500:
# Retry once, then alert
time.sleep(2)
# retry...