Content Management
Day-to-day authoring surfaces. Entries live in a tree. Every new entry takes a place under a parent node — there are no orphan rows.
Lifecycle
- Create —
POST /api/v1/projects/{slug}/entrieswith content type, locale, tree parent, fields. Always lands as draft. - Update —
PUT /api/v1/projects/{slug}/entries/{id}with the currentversionfor optimistic concurrency. Mismatched versions return 409. - Publish —
POST /api/v1/projects/{slug}/entries/{id}/publishwith locale. Required references must already be published, or the publish returns422 required_references_unpublishedwith the blockers indetails.unpublished[]. - Unpublish —
POST .../unpublish. The entry stays as a draft; route index drops the locale's path. - Delete —
DELETE .../entries/{id}. Soft-delete: the row stays for audit, references resolve to null at delivery.
Sub-pages
- Content tree — sites, folders, materialized paths
- Entries — create, update, version, restore
- Publishing — workflow, scheduling, publish gates
- Media — assets, transforms, locale overlays
- Localization — per-locale field values, fallback chains
- Search — Postgres FTS by default, Meilisearch optional
Quick example
POST /api/v1/projects/demo/entries
Content-Type: application/json
Authorization: Bearer krios_mk_…
{
"contentTypeApiName": "blogPost",
"locale": "en-US",
"treeParentId": "node_blogIndex",
"treeNodeName": "Hello World",
"slug": "hello-world",
// siteId is derived from the parent when treeParentId is set;
// only pass siteId for root placement (treeParentId: null).
// A mismatching siteId here returns 422 tree_site_mismatch.
"fields": {
"title": "Hello World",
"body": {
"type": "doc",
"content": [
{ "type": "paragraph", "content": [{ "type": "text", "text": "First post." }] }
]
}
}
}
Common pitfalls
- Forgetting
versionon update. The PUT body must include the current version.versionis required — omitting it fails Zod validation with422 validation(the server never defaults to 1). - Publishing an entry whose required reference is still draft. Returns
422 required_references_unpublishedwith the blockers indetails.unpublished[]. Publish each blocker first or remove the reference. - Two
update_entrycalls in parallel. Both pass version=N; the second 409s. Catch and re-fetch.