HTTP semantics & error payloads
This document describes the HTTP status codes and error payloads returned by the Routic API. Business API errors and gateway (LLM) errors may differ in HTTP status and JSON shape — follow live responses and handle them appropriately.
Error response format
All errors return a consistent JSON format:
{
"error": {
"message": "Invalid API key provided.",
"type": "authentication_error",
"code": "invalid_api_key",
"param": null,
"request_id": "req_abc123def456"
}
}
Error fields
| Field | Type | Description |
|---|---|---|
message | string | Human-readable error description. |
type | string | Error category (e.g., authentication_error, invalid_request_error, rate_limit_error). |
code | string | Machine-readable error code for programmatic handling. |
param | string / null | The request parameter that caused the error, if applicable. |
request_id | string | Unique request identifier for debugging and support. Always log this value. |
HTTP status codes
200 OK
The request was successful. The response body contains the requested data.
400 Bad Request
The request was malformed or missing required parameters.
| Code | Type | Message example | Cause & solution |
|---|---|---|---|
invalid_request_error | invalid_request_error | "Invalid request body: 'messages' is required." | The request body is missing a required field or has an invalid format. Check the request parameters and retry. |
invalid_model | invalid_request_error | "Model 'gpt-999' is not available." | The specified model is not in your catalog or does not exist. Check the Model catalog. |
invalid_message_format | invalid_request_error | "Each message must have 'role' and 'content' fields." | The messages array has an invalid structure. Each message must have role and content. |
Retry: Do not retry without fixing the request.
401 Unauthorized
Authentication failed.
| Code | Type | Message example | Cause & solution |
|---|---|---|---|
invalid_api_key | authentication_error | "Invalid API key provided." | The API key is malformed or does not exist. Check your key format (sk-*). |
expired_api_key | authentication_error | "Your API key has expired." | The key has reached its budget deadline or was revoked. Generate a new key in your dashboard. |
missing_api_key | authentication_error | "No API key provided. Include an Authorization header." | The Authorization: Bearer header is missing. Add it to your request. |
Retry: Do not retry. Fix the authentication issue first.
402 Payment Required
Insufficient balance.
| Code | Type | Message example | Cause & solution |
|---|---|---|---|
insufficient_balance | insufficient_quota | "Your account balance is insufficient. Please top up." | The account balance is zero or negative. Top up your account or wait for the billing cycle to reset. |
budget_exceeded | insufficient_quota | "Monthly budget exceeded for this key." | The key has exceeded its configured budget. Increase the budget in your dashboard or create a new key. |
Retry: Do not retry. Top up or adjust the budget first.
422 Unprocessable Entity
The request was syntactically valid but semantically invalid.
| Code | Type | Message example | Cause & solution |
|---|---|---|---|
unsupported_feature | invalid_request_error | "Tool calls are not supported by this model." | The specified feature (e.g., tools, response_format) is not supported by the selected model. Check the Capability matrix. |
parameter_conflict | invalid_request_error | "'thinking' parameter requires a reasoning model." | The parameter combination is invalid (e.g., using thinking with a non-reasoning model). |
Retry: Do not retry. Fix the parameter issue first.
429 Too Many Requests
Rate limit exceeded.
| Code | Type | Message example | Cause & solution |
|---|---|---|---|
rate_limit_exceeded | rate_limit_error | "RPM limit exceeded. Try again in 5 seconds." | The key has exceeded its requests-per-minute limit. Wait and retry with exponential backoff. |
token_rate_limit_exceeded | rate_limit_error | "TPM limit exceeded. Try again in 10 seconds." | The key has exceeded its tokens-per-minute limit. Wait and retry with exponential backoff. |
Retry: Yes, with exponential backoff. See Retry strategy below.
500 Internal Server Error
An unexpected error occurred on the server side.
| Code | Type | Message example | Cause & solution |
|---|---|---|---|
internal_error | api_error | "An unexpected error occurred. Please try again." | A server-side issue. Log the request_id and retry. If persistent, contact support. |
Retry: Yes, with exponential backoff.
503 Service Unavailable
Model provider is unavailable.
| Code | Type | Message example | Cause & solution |
|---|---|---|---|
upstream_unavailable | api_error | "Upstream provider is temporarily unavailable. Please try again." | The model provider is experiencing issues. Routic may automatically route to a backup. Retry after a delay. |
Retry: Yes, after a delay (e.g., 30 seconds). The gateway may also automatically retry with fallback models.
Retry strategy
When to retry
| Status code | Retry? | Strategy |
|---|---|---|
| 400 | No | Fix the request and resend. |
| 401 | No | Fix the API key and resend. |
| 402 | No | Top up or adjust budget. |
| 422 | No | Fix the parameter issue and resend. |
| 429 | Yes | Exponential backoff with jitter. |
| 500 | Yes | Exponential backoff with jitter. |
| 503 | Yes | Backoff with longer delay (e.g., 30s). |
Exponential backoff with jitter
delay = min(base_delay * 2^attempt + random_jitter, max_delay)
Recommended values:
| Parameter | Value |
|---|---|
| Base delay | 1 second |
| Max retries | 3 |
| Max delay | 60 seconds |
| Jitter range | 0–500 ms |
Python example
import time
import random
def retry_with_backoff(func, max_retries=3, base_delay=1, max_delay=60):
for attempt in range(max_retries):
try:
return func()
except Exception as e:
if attempt == max_retries - 1:
raise
delay = min(base_delay * (2 ** attempt) + random.uniform(0, 0.5), max_delay)
print(f"Attempt {attempt + 1} failed. Retrying in {delay:.1f}s...")
time.sleep(delay)
Gateway vs provider errors
Routic acts as a gateway proxy. Errors may originate from:
| Source | Description | HTTP status |
|---|---|---|
| Routic | Authentication, billing, rate limiting, request validation | 400, 401, 402, 429 |
| Gateway | Routing, fallback, format normalization | 422, 500 |
| Model provider | Model-specific errors, content policy violations | 400, 422, 500, 503 |
In all cases, the error response format is normalized to the structure described above. The request_id can be used to trace the issue across layers.
Rate limit behavior
- Rate limits are applied per API Key, not per account.
- When a rate limit is hit, the gateway does not queue requests — they are rejected immediately with 429.
- The
Retry-Afterheader may be included in 429 responses indicating the number of seconds to wait. - Rate limits are configurable per key. Defaults: 100 RPM, 10,000 TPM.