Entries and publishing
All paths on this page are relative to https://api.avvyr.com/v1/cms/sites/{siteId} and take an Avvyr API key in x-api-key.
Entries
POST /entries
{ "typeKey": "page", "title": "Sofas", "folderId": null,
"slug": { "sv": "soffor", "en": "sofas" }, "locales": ["sv", "en"], "fields": {} }
The answer is 201 with the entry and status: "draft". title is required and is the entry's name in the app. A second entry of a singleton type returns 409 CMS_SINGLETON_EXISTS.
| Status | Meaning |
|---|---|
draft | Never published, or unpublished |
published | The draft and the published version are the same |
modified | Published, with unpublished changes in the draft |
Writing fields
PATCH /entries/{entryId} takes title, slug, folderId, order, locales and fields.
fields replaces the whole draft. Read the entry, change what you mean to change and send every field back. A body with one block deletes the others.- Write only the fields the type defines. Other keys are kept in the draft but never published.
- Block ids are strings you choose, unique within the entry. Keep the id of an existing block: the editor and live preview follow blocks by id.
GET /entries?folderId=&type=&q=&status=&scheduled=&limit=&offset=lists entries.folderId=rootgives the top level.
Folders and paths
A routable entry's path is / + its folders' segments + its slug, per language:
folder "blog" (segment sv: "blogg", en: "blog")
entry "Our new sofa" (slug sv: "var-nya-soffa", en: "our-new-sofa")
sv: /blogg/var-nya-soffa
en: /blog/our-new-sofa
- A folder with
inPath: falsegroups entries in the app without adding a segment. - A folder's index entry (
indexEntryId) gets the folder's own path,/blogg. - The site's home entry (
homeEntryIdon the site) gets/. - A missing slug or segment in a language falls back to the default language.
- Slugs and segments start with a letter or digit and may contain letters, digits and
. _ ~ -. - Paths never include a language prefix. How the language appears in your URLs (
/en/..., a domain per language) is up to your site.
Publishing an entry whose path another published entry already has returns 409 CMS_PATH_CONFLICT.
Folders have no draft. Renaming or moving a folder (PATCH /folders/{folderId}) changes the published paths right away and creates a new version.
| Method | Path | Body |
|---|---|---|
| GET | /folders | All folders, flat |
| POST | /folders | { name, parentId?, segment: { [locale]: string }, inPath? } |
| PATCH | /folders/{folderId} | { name?, parentId?, segment?, inPath?, indexEntryId?, order? } |
| DELETE | /folders/{folderId} | 409 CMS_FOLDER_NOT_EMPTY if it has content |
Publishing
POST /entries/{entryId}/publish # → { entry, version }
POST /entries/{entryId}/unpublish # → { entry, version }
POST /entries/{entryId}/discard # reset the draft to the published version
Publishing validates the draft: required fields, choices, min and max, references and the path. Errors come back as 400 CMS_VALIDATION with details: [{ path, message }].
Every publish, unpublish or folder change raises the site's version by one. The delivery API serves content per version, so the new content is live as soon as your site asks for the new version.
To publish several entries as one change, use the batch endpoints. They produce a single version:
POST /publish { "entryIds": ["…", "…"] } # → { published, failed: [{ id, errorCode, details }], version }
POST /unpublish { "entryIds": ["…"] } # → { version }
Checking a draft before publishing
POST /entries/{entryId}/preview with { locale, title?, slug?, folderId?, fields } returns the unsaved draft as the delivery API would, with draft: true. Nothing is saved. Invalid values come back as null rather than as errors; publishing is the real validation.
Scheduling
PUT /entries/{entryId}/schedule
{ "publishAt": "2026-11-28T07:00:00Z", "unpublishAt": "2026-12-02T23:00:00Z" }
A field you leave out is unchanged, and null removes it. Times in the past, or unpublishAt before publishAt, return 400. POST /schedule with { entryIds, publishAt?, unpublishAt? } schedules several entries.
Scheduled entries are published within 30 seconds of the time, as the draft looks at that moment. If publishing fails, the error is saved in schedule.error on the entry and publishAt is cleared. GET /entries?scheduled=1 lists everything scheduled.
Version history
| Method | Path | |
|---|---|---|
| GET | /entries/{entryId}/revisions | Newest first, at most 200 |
| GET | /entries/{entryId}/revisions/{revisionId} | One revision with its fields |
| POST | /entries/{entryId}/revisions/{revisionId}/restore | Puts the revision in the draft |
Every publish writes a publish revision. A save that changes content writes a save revision; saves by the same person within 10 minutes are merged. Each entry keeps its last 10 publish revisions and its last 10 save and restore revisions; older ones are pruned. The published revision is always kept. Restoring saves the current draft first, so a restore can be undone.