REST Delivery
REST endpoints under /api/delivery/projects/{slug}/sites/{siteSlug}/. All are GET. Bodies follow the { data, meta } envelope.
Endpoints
/api/delivery/projects/{slug}/sites/{siteSlug}/
entries/{id} single entry by id
routes?path=/about path → entry / redirect / 404
content/{contentTypeApiName} paginated list
media/{assetId}?locale=en-US asset with locale overlay
sitemap?format=xml|json sitemap.xml or JSON inventory
Auth
Same as GraphQL. Bearer key (delivery / preview / management) or no auth for public read.
Include / expand model
Reference + blocks fields can be expanded inline:
?include= | Behavior |
|---|---|
0 (default) | { _ref, _type } link objects. |
1 | Direct references inlined as full entries. |
2 | Two hops deep (refs of refs). |
3 | Max — three hops. Cycles collapse to links. |
Cycle detection is per-request: if expansion would revisit an id already on the path, the recursion bails to { _ref, _type }. Hard cap matches GraphQL's MAX_REFERENCE_DEPTH = 3.
Pagination
REST list endpoints use page + limit:
?page=1&limit=25
Response meta:
{ "total": 142, "page": 1, "limit": 25, "pages": 6 }
Limit is capped at 100. Order via ?orderBy=updatedAt:desc. V1 allows createdAt and updatedAt as sort keys; arbitrary field sorts come via the search lib at /api/v1/projects/{slug}/search.
Examples
Single entry, expanded refs
curl -H "Authorization: Bearer $KEY" \
"https://cms.example.com/api/delivery/projects/demo/sites/main/entries/$ID?include=1"
Route resolution
curl -H "Authorization: Bearer $KEY" \
"https://cms.example.com/api/delivery/projects/demo/sites/main/routes?path=/blog/hello-world"
List articles, page 2
curl -H "Authorization: Bearer $KEY" \
"https://cms.example.com/api/delivery/projects/demo/sites/main/content/articlePage?page=2&limit=10&orderBy=updatedAt:desc"
Response shapes
Entry
Delivery entries use underscore-prefixed system keys (_id, _type, _slug, _siteId, _locale, _publishedAt) plus fields. There is no version, createdAt, or updatedAt on the delivery shape.
{
"data": {
"_id": "ckl_…",
"_type": "articlePage",
"_slug": "hello-world",
"_siteId": "ckl_site_main",
"_locale": "en-US",
"_publishedAt": "...",
"fields": {
"title": "Hello World",
"body": {
"raw": { "type": "doc", "content": [...] },
"html": "<p>...</p>",
"text": "..."
},
"category": { "_ref": "ckl_…", "_type": "category" }
}
}
}
Route resolution
The routes endpoint returns a { data } envelope discriminated on kind — entry or redirect:
{ "data": { "kind": "entry", "entry": { "_id": "ckl_…", "_type": "articlePage", ... } } }
{ "data": { "kind": "redirect", "target": "/new-path", "status": 301 } }
A path with no match returns HTTP 404 with the standard error envelope (not a kind: "notFound" body):
{ "error": "route_not_found", "message": "No route for that path." }