Skip to main content

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

CodeMeaningWhen It Occurs
200OKRequest succeeded. Response body contains the requested data.
401UnauthorizedAPI key is missing from the request headers.
403ForbiddenAPI key is invalid or does not have access to the tenant.
404Not FoundThe requested resource (article, page, category, collection, or item) does not exist.
422Validation ErrorRequest parameters failed validation (wrong type, missing required param, etc.).
429Too Many RequestsRate limit exceeded. Back off and retry.
500Internal Server ErrorUnexpected 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

FieldTypeDescription
locarrayLocation path indicating where the error occurred (e.g. ["query", "limit"], ["path", "article_id"])
msgstringHuman-readable error message
typestringMachine-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');
}