Skip to main content

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.
1Direct references inlined as full entries.
2Two hops deep (refs of refs).
3Max — 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 kindentry 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." }