Error Handling
HTTP status codes, error response format, and retry strategies for the Aurion API.
Error Handling
The Aurion API uses standard HTTP status codes and returns structured JSON error responses.
HTTP Status Codes
| Code | Meaning | When |
|---|---|---|
200 | OK | Request succeeded |
201 | Created | Resource created successfully |
204 | No Content | Resource deleted successfully |
400 | Bad Request | Invalid request body or parameters |
401 | Unauthorized | Missing or invalid API key |
403 | Forbidden | Valid key but insufficient scope |
404 | Not Found | Resource does not exist |
409 | Conflict | Resource already exists (duplicate) |
422 | Unprocessable Entity | Validation error on request body |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Unexpected server error |
503 | Service Unavailable | Temporary outage or maintenance |
Error Response Format
All error responses follow the same structure:
{
"error": "validation_error",
"message": "Human-readable description of what went wrong",
"details": [
{
"field": "priority",
"message": "Must be one of: low, medium, high, urgent"
}
]
}| Field | Type | Description |
|---|---|---|
error | string | Machine-readable error code |
message | string | Human-readable error description |
details | array | Field-level validation errors (only for 422) |
Common Error Codes
| Error Code | HTTP Status | Description |
|---|---|---|
unauthorized | 401 | Missing or invalid API key |
forbidden | 403 | Insufficient scope |
not_found | 404 | Resource not found |
validation_error | 422 | Request body validation failed |
rate_limit_exceeded | 429 | Too many requests |
idempotency_conflict | 409 | Different request body with same idempotency key |
internal_error | 500 | Unexpected server error |
Rate Limiting
The API returns a 429 response when you exceed your rate limit. The response includes a Retry-After header:
HTTP/1.1 429 Too Many Requests
Retry-After: 12{
"error": "rate_limit_exceeded",
"message": "Rate limit exceeded. Retry after 12 seconds.",
"retry_after": 12
}Retry Strategy
For transient errors (429, 500, 503), use exponential backoff with jitter:
import time
import random
import requests
def request_with_retry(method, url, max_retries=3, **kwargs):
for attempt in range(max_retries + 1):
response = requests.request(method, url, **kwargs)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 5))
time.sleep(retry_after)
continue
if response.status_code in (500, 503) and attempt < max_retries:
delay = (2 ** attempt) + random.uniform(0, 1)
time.sleep(delay)
continue
return response
return responseasync function requestWithRetry(
url: string,
options: RequestInit,
maxRetries = 3
): Promise<Response> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = parseInt(
response.headers.get("Retry-After") ?? "5"
);
await new Promise((r) => setTimeout(r, retryAfter * 1000));
continue;
}
if ([500, 503].includes(response.status) && attempt < maxRetries) {
const delay = 2 ** attempt + Math.random();
await new Promise((r) => setTimeout(r, delay * 1000));
continue;
}
return response;
}
throw new Error("Max retries exceeded");
}Best Practices
- Check the
errorfield — Use the machine-readable code for programmatic handling - Log the full response — Include the
messagefor debugging - Respect
Retry-After— Don't retry faster than the header suggests - Don't retry
4xx— Client errors (except429) indicate a problem with your request