API Overview
A versioned REST API at /api/v1/*. JSON in, JSON out. Most endpoints are gated by an API key; a small set is public.
Base URL
https://<your-host>/api/v1
Response envelope
Every endpoint returns the same shape — either data is populated and error is null, or vice versa.
// Success
{
"data": <payload>,
"meta": { "page": 1, "per_page": 20, "total": 137 },
"error": null
}
// Failure
{
"data": null,
"error": {
"code": "VALIDATION_FAILED",
"message": "The given data was invalid.",
"details": { "title": ["The title field is required."] }
}
}
Endpoint surface
| Resource | Public? | Notes |
|---|---|---|
GET /v1/i18n/locales | Public | Active locales for frontend switchers |
GET /v1/settings | Public | Safe site config — name, logo, social, SEO defaults |
POST /v1/forms/{slug}/submit | Public (throttled) | 5 req/min/IP |
GET /v1/forms/{slug} | Public | Returns the form schema |
GET /v1/ping | Auth | Health + echoes key name + scopes |
GET /v1/upload/files | Auth | List media |
POST /v1/upload | Auth + write | Upload file |
DELETE /v1/upload/files/{id} | Auth + delete | Delete file |
GET /v1/search | Auth | Cross-model full-text |
GET /v1/{model} | Auth | List entries for a content model |
GET /v1/{model}/{idOrSlug} | Auth | Single entry by UUID or slug |
POST /v1/{model} | Auth + write | Create entry |
PUT /v1/{model}/{id} | Auth + write | Update entry |
DELETE /v1/{model}/{id} | Auth + delete | Soft-delete entry |
Route order mattersThe dynamic content routes are catch-alls and registered last. The specific routes (
upload, search, i18n, forms, settings, ping) must be defined before them.Middleware chain
Authenticated endpoints go through:
api.cors— validatesOriginagainst the key's allowlist; handles preflight.api.auth— validates the public key + secret pair, attachesrequest()->apiKey.api.rate— enforces the per-key requests/min limit.api.log— writes anapi_request_logsrow at the end.api.scope:<scope>— for write/delete-only routes.
HTTP status codes
| Code | Meaning |
|---|---|
| 200 | OK |
| 201 | Created |
| 204 | No content (delete) |
| 400 | Malformed request |
| 401 | Missing / invalid API key |
| 403 | Missing required scope |
| 404 | Resource or model slug not found |
| 410 | Form deactivated |
| 422 | Validation failed |
| 429 | Rate limit exceeded — see Retry-After |
| 500 | Server error |
Pagination, sorting, filtering
List endpoints (entries, media, search) accept these query params:
?page=2
&per_page=20
&sort=-published_at // dash prefix → descending
&filter[status]=published
&filter[locale]=en
&filter[data.tags]=launch
&include=author,hero_image
&fields=title,slug,excerpt,published_at
Quickstart
curl -s https://your-host/api/v1/ping \
-H "X-API-Key: pk_live_abc123…" \
-H "X-API-Secret: sk_live_xyz789…" | jq
# {
# "data": { "message": "pong", "key_name": "Website Production", "scopes": ["read"] },
# "error": null
# }