Errors
Every error comes back in the same envelope, with an HTTP status that says what kind of problem it is:
{
"success": false,
"message": "Request failed",
"errors": [
{
"message": "The API key does not have the quotes:write scope this endpoint requires.",
"code": "insufficient_scope",
"required_scope": "quotes:write"
}
]
}
errors[].messageis for a person to read. It may change, so don't match on it.errors[].codeis stable. Branch on it in your code.errors[].fieldnames the input to fix, when the problem is one input.
Key and access errors
| Status | Code | What it means | What to do |
|---|---|---|---|
| 401 | invalid_api_key | The key is wrong or incomplete. | Check the header is Authorization: Bearer <key> and the key was copied in full. |
| 401 | api_key_wrong_environment | A test key was sent to production, or a live key to the sandbox. | Use the key that matches the address. See Environments. |
| 401 | api_key_expired | The key's expiry date has passed. | Ask an admin for a new key. Roll keys before they expire next time. |
| 401 | api_key_revoked | An admin revoked the key. | Ask an admin for a new key. |
| 401 | organization_inactive | The organization that owns the key is inactive. | Contact HighQube. |
| 403 | insufficient_scope | The key lacks the permission this endpoint needs. required_scope names it. | Ask an admin for a key with that permission. |
| 403 | ip_not_allowed | The key is restricted to other addresses. | Call from an allowed address, or ask an admin to add yours. |
| 403 | api_access_disabled | API access is turned off for your organization. | Contact HighQube. |
| 429 | rate_limited | Too many requests. | Wait for the number of seconds in Retry-After, then send it again. See Rate limits. |
| 503 | api_keys_unavailable | Keys can't be checked right now. | Retry after a short wait. |
Input errors
A request with a missing or invalid input gets 400 or 422, with field naming the input:
{
"success": false,
"message": "Validation failed",
"errors": [{ "message": "routes must be a valid JSON array", "field": "routes" }]
}
Fix the request before sending it again: the same request gets the same answer.
Handling errors in code
response = requests.get(url, headers=headers, params=params, timeout=30)
if not response.ok:
error = response.json()["errors"][0]
code = error.get("code")
if code == "rate_limited":
... # wait Retry-After seconds, then send it again
elif code in {"api_key_expired", "api_key_revoked", "invalid_api_key"}:
... # alert someone: the key needs replacing
else:
raise RuntimeError(f"{response.status_code} {code}: {error['message']}")
Each endpoint's page in the API reference lists the errors it can return, with examples.

