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