Skip to main content

Entries

An entry is one row of a content type. Field values are stored per locale in ContentFieldValue; non-localizable fields use the synthetic __shared locale.

Create

POST /api/v1/projects/{slug}/entries
Authorization: Bearer krios_mk_…

{
"contentTypeApiName": "blogPost",
"siteId": "site_main",
"locale": "en-US",
"treeParentId": "node_blogIndex",
"treeNodeName": "Hello World",
"slug": "hello-world",
"fields": {
"title": "Hello World",
"body": { "type": "doc", "content": [...] }
},
"publishAt": "2026-06-01T09:00:00Z" // optional — schedules a future publish
}

treeParentId must reference an existing node whose allowedChildTypes permits the new type. The server enforces both the per-node override and the parent CT's allowedChildTypes. Always lands as draft.

Update

Optimistic concurrency via version. Pass the version you observed; the server bumps it on success.

PUT /api/v1/projects/{slug}/entries/{id}
{
"version": 3,
"locale": "fr-CA",
"fields": { "title": "Bonjour", "body": { "type": "doc", … } }
}

If version doesn't match, you get 409 with the current version in the body. Catch and re-fetch.

Version history

Every save creates an immutable ContentVersion snapshot containing the full field data for the locale, the author, and an optional message. The admin UI's Versions tab lists them with diff + restore actions.

GET /api/v1/projects/{slug}/entries/{id}/versions
GET /api/v1/projects/{slug}/entries/{id}/versions/{versionNum}
POST /api/v1/projects/{slug}/entries/{id}/versions/{versionNum}/restore
{ "locale": "en-US" }

The version number is the path segment ({versionNum}), and the body carries the locale to restore. Restore creates a new version (it doesn't rewrite history) so the audit trail stays linear.

Soft delete

DELETE /api/v1/projects/{slug}/entries/{id}

The row stays in the database with isDeleted=true. References to deleted entries resolve to null at delivery (the GraphQL field returns null; REST ?include= skips them).

Recover a soft-deleted entry via the REST endpoint (also surfaced as the admin UI's restore action):

POST /api/v1/projects/{slug}/entries/{id}/restore

No body. Returns 409 entry_not_deleted if the entry isn't currently soft-deleted. (This is distinct from version restore above, which lives at …/versions/{versionNum}/restore.)

Hard delete is a separate management API call that bypasses referential integrity (caller must explicitly confirm).

Where used

GET /api/v1/projects/{slug}/entries/{id}/references

Returns every entry that references the requested one (via reference, blocks, or rich-text embeddedEntry). The same data drives the safety gate on delete: deleting a referenced entry returns 409 with the referencer list.

Duplicate

POST /api/v1/projects/{slug}/entries/{id}/duplicate
{
"title": "Hello World (Copy)",
"treeParentId": "node_blogIndex",
"locales": ["en-US", "fr-CA"], // optional — only copy these locales
"deepCopyBlocks": true // optional — recursively duplicate referenced block entries
}

The clone is always created as draft, slug auto-suffixed (hello-world-copy).

Copy from another locale

When seeding a translation:

POST /api/v1/projects/{slug}/entries/{id}/copy-locale
{ "sourceLocale": "en-US", "targetLocale": "fr-CA" }

Copies localizable field values from source to target on the same entry. Sets the target's translation status to in-progress so stale detection works.

CLI shortcuts

krios entries list --type blogPost --site main --status published
krios entries get <id> --locale en-US
krios entries create --type blogPost --locale en-US --site main --file home.json
krios entries update <id> --locale en-US --file changes.json --version 4
krios entries publish <id> --locale en-US