Skip to content

Content API

The content API serves published content to your frontend. All endpoints are public (no authentication) and return JSON with Cache-Control and ETag headers.

Base URL: http://localhost:4321/api/content

Returns published pages with filtering, sorting, and pagination.

ParameterTypeDefaultDescription
typestring-Filter by content type slug
taxonomystring-Filter by taxonomy (category:news or category)
sortstringpublished_at:descSort field and direction
limitnumber20Results per page (max 50)
offsetnumber0Pagination offset

Sort fields: published_at, created_at, updated_at, title, slug

Terminal window
curl "http://localhost:4321/api/content/pages?type=blog_post&limit=5"

Response: { "data": [...], "meta": { "total": 12, "limit": 5, "offset": 0 } }

Each page in data includes: id, type, title, slug, status, fields, terms, meta (created_at, updated_at, published_at).

Returns a single published page with resolved blocks organized by region, SEO metadata, and taxonomy terms.

Terminal window
curl "http://localhost:4321/api/content/pages/about"

Response shape:

{
"data": {
"id": 1, "type": "marketing_page", "title": "About Us", "slug": "about",
"status": "published", "fields": {}, "terms": [],
"seo": { "meta_title": "...", "meta_description": "...", "og_image": null, "canonical_url": null, "robots": null },
"regions": {
"hero": [{ "id": "pb_1", "block_type": "hero", "fields": { "heading": "About Us" } }],
"content": [{ "id": "pb_2", "block_type": "rich_text", "fields": { "body": {} } }]
},
"meta": { "created_at": "...", "updated_at": "...", "published_at": "..." }
}
}

Returns 404 with { "errors": [{ "code": "NOT_FOUND", "message": "Page not found" }] } if not found.

Returns a menu with its full nested item tree. Pass ?depth=N to limit nesting.

Terminal window
curl "http://localhost:4321/api/content/menus/main-nav"

Each item has: id, title, url, page_slug, target, attributes, children.

Searches published pages by title and slug. Min 2 characters.

ParameterTypeDefaultDescription
qstringrequiredSearch query
typestring-Filter by content type
limitnumber20Max results (max 50)

Returns { "data": [...], "meta": { "total": N, "query": "..." } } where each result has id, type, title, slug, description, meta.

Taxonomies — GET /taxonomies/:slug/terms

Section titled “Taxonomies — GET /taxonomies/:slug/terms”

Returns all terms for a taxonomy. Hierarchical taxonomies return a nested tree with children; flat taxonomies return a list.

Serves a media file. For local storage, returns the binary. For S3/R2, redirects to the public URL.

Variants: original, thumbnail, medium, large, info

The info variant returns JSON metadata (dimensions, alt text, variant URLs) instead of the file.

Fetch multiple pages and menus in one request. Body: { "pages": ["home", "about"], "menus": ["main-nav"] }. Max 50 pages and 10 menus per batch.

XML sitemap of all published pages (also at /sitemap.xml). Pages with robots: "noindex" are excluded. Uses SITE_URL env var for absolute URLs.

EndpointDescription
GET /configSite configuration (name, tagline, social links)
GET /schemasAll content type and block type schemas
GET /redirectsActive URL redirects
GET /og/:slug.pngAuto-generated Open Graph image
GET /tracking-scriptsActive tracking scripts (optionally filtered by ?page=slug)

All responses include Cache-Control (with max-age, s-maxage, stale-while-revalidate) and ETag headers. Send If-None-Match to get 304 Not Modified when content has not changed.