Error Handling
The Adapto CMS Public API uses standard HTTP status codes and returns structured error responses. This page covers all error scenarios and how to handle them in your applications.
HTTP Status Codes
| Code | Meaning | When It Occurs |
|---|---|---|
200 | OK | Request succeeded. Response body contains the requested data. |
401 | Unauthorized | API key is missing from the request headers. |
403 | Forbidden | API key is invalid or does not have access to the tenant. |
404 | Not Found | The requested resource (article, page, category, collection, or item) does not exist. |
422 | Validation Error | Request parameters failed validation (wrong type, missing required param, etc.). |
429 | Too Many Requests | Rate limit exceeded. Back off and retry. |
500 | Internal Server Error | Unexpected server error. Contact support if persistent. |
Validation Errors (422)
When query parameters or path parameters fail validation, the API returns a 422 Unprocessable Entity response with detailed error information:
{
"detail": [
{
"loc": ["query", "limit"],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
}Error Fields
| Field | Type | Description |
|---|---|---|
loc | array | Location path indicating where the error occurred (e.g. ["query", "limit"], ["path", "article_id"]) |
msg | string | Human-readable error message |
type | string | Machine-readable error type identifier |
Multiple Validation Errors
Multiple errors can be returned at once:
{
"detail": [
{
"loc": ["query", "page"],
"msg": "value is not a valid integer",
"type": "type_error.integer"
},
{
"loc": ["query", "limit"],
"msg": "ensure this value is greater than 0",
"type": "value_error.number.not_gt"
}
]
}Not Found Errors (404)
When a resource is not found by ID or slug:
{
"detail": "Article not found"
}Error Handling Best Practices
JavaScript / TypeScript
async function fetchArticle(slug) {
const response = await fetch(
`${BASE_URL}/public/articles/by-slug/${slug}`,
{ headers: { 'x-api-key': API_KEY } }
);
if (!response.ok) {
switch (response.status) {
case 401:
case 403:
throw new Error('Authentication failed. Check your API key.');
case 404:
return null; // Article not found
case 422:
const errors = await response.json();
throw new Error(`Validation error: ${errors.detail.map(e => e.msg).join(', ')}`);
case 429:
// Implement retry with exponential backoff
await sleep(1000);
return fetchArticle(slug);
default:
throw new Error(`API error: ${response.status}`);
}
}
return response.json();
}Python
import requests
from time import sleep
def fetch_article(slug, retries=3):
response = requests.get(
f'{BASE_URL}/public/articles/by-slug/{slug}',
headers={'x-api-key': API_KEY}
)
if response.status_code == 200:
return response.json()
elif response.status_code == 404:
return None
elif response.status_code == 422:
errors = response.json()
raise ValueError(f"Validation error: {errors['detail']}")
elif response.status_code == 429 and retries > 0:
sleep(1)
return fetch_article(slug, retries - 1)
else:
response.raise_for_status()Rate Limiting
The Public API enforces rate limits based on your subscription plan. When you exceed the limit, requests return 429 Too Many Requests. Implement exponential backoff in your client:
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) return response;
const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
await new Promise(resolve => setTimeout(resolve, delay));
}
throw new Error('Rate limit exceeded after retries');
}