Server API
The type-safe server-side API on cms.api, method by method.
createCMS returns an api object namespaced by collection: cms.api.<collection>.<method>. Methods follow the better-call convention: read methods take a query object, write methods take a body object. Inputs and outputs are typed from your collection definitions.
const { roots } = await cms.api.pages.listRoots({ query: { limit: 20 } });The same methods are available on the client, with identical types.
Collection methods
listRoots
Lists the entries (roots) of a collection. GET, input via query (all fields optional).
| Query field | Type | Default | Description |
|---|---|---|---|
limit | number | 20 | Page size (1 to 100). |
offset | number | 0 | Rows to skip. |
search | string | Search term. | |
searchField | column or property | Field to search. | |
sortBy | column or property | createdAt | Sort field. |
sortDirection | 'asc' | 'desc' | desc | Sort order. |
filterField | column or property | Field to filter. | |
filterValue | string | Filter value. | |
hasPublications | boolean | Only entries with or without publications. | |
createdAfter | Date | Entries created after this time. | |
createdBefore | Date | Entries created before this time. | |
parentRootId | string | Filter by parent entry. |
Returns { roots, total, hasMore }. Each root has rootId, createdAt, createdBy, parentRootId, sortOrder, slug, properties (typed), hasPublications, publicationCount, branchCount, and openMergeRequestCount. path (the full ancestor-resolved URL) is present only for slug-enabled collections, and createdByUser only when called with query.withUser.
createRoot
Creates a new entry. POST, input via body.
| Body field | Type | Required | Default | Description |
|---|---|---|---|---|
properties | typed root properties | yes if the root has required props | The root's properties. | |
slug | string | no | Slug for the entry. | |
parentRootId | string | no | Parent entry for nesting. | |
message | string | no | 'Initial commit' | Commit message. |
Returns { rootId, branchId, commitId }.
const { rootId } = await cms.api.pages.createRoot({
body: { slug: 'welcome', properties: { title: 'Welcome' } },
});getBlockTree
Returns the editing view of an entry's block tree. GET, input via query.
| Query field | Type | Required | Description |
|---|---|---|---|
rootId | string | yes | The entry. |
branchId | string | yes | The branch to read. |
commitId | string | no | A specific commit (defaults to branch head). |
raw | boolean | no | Keep stored values for editing: skip variable, link, and image resolution. |
includeReferencePreviews | boolean | no | Also return a references sidecar (see below). |
Returns { tree, reconstructed }. The tree is a discriminated union over type, and the top node is type: 'root'.
With includeReferencePreviews: true, the result also carries references: a Record<storedReferenceValue, tree> holding the published render tree of every reference embedded anywhere in the entry — its own nested references resolved and {{variables}} substituted, resolved through the active scope (tenant / language fallback). This lets an editor render the raw editable tree and all embedded reusable-block previews in one call instead of one getPublishedContent per reference. References that are not published (or out of scope) are omitted from the map. The flag is opt-in because resolving is more expensive; combine it with raw: true to keep the main tree editable while still getting rendered previews.
createBlock
Adds a block under a parent. POST, input via body.
| Body field | Type | Required | Description |
|---|---|---|---|
rootId | string | yes | The entry. |
branchId | string | yes | The branch. |
parentBlockId | string | yes | Parent block to attach under. |
type | block type name | yes | One of the collection's block types. |
properties | typed block properties | yes | The block's properties. |
position | number | no | Insert position (defaults to append). |
message | string | no | Commit message. |
Returns { commitId, blockId }.
updateBlock
Updates a block with patch semantics: supplied fields overwrite, omitted fields stay, null deletes. POST, input via body.
| Body field | Type | Required | Description |
|---|---|---|---|
rootId | string | yes | The entry. |
branchId | string | yes | The branch. |
blockId | string | yes | The block to update. |
type | block type name | yes | The block's type. |
properties | partial block properties | yes | Fields to change. |
message | string | no | Commit message. |
Returns { commitId }.
getPublishedContent
Returns the published view of an entry, with references resolved. GET, input via query. Provide at least one of rootId, slug, or path.
| Query field | Type | Description |
|---|---|---|
rootId | string | Look up by entry id. |
slug | string | Look up by slug (slug-enabled collections). |
path | string | Look up by full path. |
raw | boolean | Keep stored values: skip variable and link resolution. |
Returns { rootId, collection, variants }, where each variant has branchId, branchName, commitId, publishedAt, publishedBy, and a resolved tree. Additional fields appear when relevant: a page-level A/B test descriptor when one is running, and ancestors when the collection uses nested slugs.
In the resolved tree, reference properties are inlined and link properties become a ResolvedLink (an href). An image property is returned verbatim as the stored asset-id string (nothing is resolved); build the gate URL /media/asset/{id} from that id to serve it. A raw read keeps the stored link / reference target instead, for re-picking in an editor.
const { variants } = await cms.api.pages.getPublishedContent({
query: { path: '/welcome' },
});listBranches
Lists the branches of an entry. GET, input via query.
| Query field | Type | Default | Description |
|---|---|---|---|
rootId | string | The entry (required). | |
limit | number | 20 | Page size (1 to 100). |
offset | number | 0 | Rows to skip. |
search | string | Search term. | |
isDeletable | boolean | Filter protected vs deletable branches. | |
hasPublications | boolean | Filter by publication state. | |
hasOpenMergeRequests | boolean | Filter by open merge requests. |
Returns { branches, total, hasMore }. Each branch has id, rootId, name, headCommitId, createdBy, createdAt, updatedAt, isDeletable, and hasPublications (whether the branch is currently published) — plus createdByUser when called with query.withUser.
createBranch
Creates a branch from an existing one, copying its head commit. POST, input via body.
| Body field | Type | Required | Description |
|---|---|---|---|
rootId | string | yes | The entry. |
name | string | yes | Branch name (unique per entry). |
sourceBranchId | string | yes | Branch to copy the head commit from. |
createdBy | string | no | Actor (defaults to the request user). |
Returns { branchId, headCommitId }.
getBranch
Returns one branch. GET, query: { branchId }.
renameBranch
Renames a branch (main cannot be renamed). POST, body: { branchId, newName }.
deleteBranch
Deletes a branch. main, published branches, and branches with open merge requests cannot be deleted. POST, body: { branchId }.
publishBranch
Publishes a branch as the live content of an entry. POST, input via body.
| Body field | Type | Required | Description |
|---|---|---|---|
rootId | string | yes | The entry. |
branchId | string | yes | The branch to publish. |
publishedBy | string | no | Fallback actor, used only when the request has no user. The request user takes precedence. |
Returns { rootId, branchId, commitId, publishedBy, publishedAt }.
Admin methods
System-wide methods live under cms.api.admin.
admin.runPruning
Runs one bounded, resumable pruning pass to reclaim storage (old commits, hard-deleted archived roots, unreferenced assets). Requires dataRetention to be configured. POST, input via body.
| Body field | Type | Default | Description |
|---|---|---|---|
dryRun | boolean | false | Plan deletions without persisting. |
maxRoots | number | 50 | Roots processed per pass (1 to 1000). |
maxDurationMs | number | 8000 | Soft time budget in milliseconds. |
liveRescanMs | number | 86400000 | Interval before a live root is rescanned. |
maxAssets | number | 100 | Archived assets reclaimed per pass (1 to 1000). |
Returns deletion counts (deletedCommits, deletedBlockVersions, deletedSnapshots, deletedMergeRequests, deletedApprovals), deletedRoots and deletedAssets (id arrays), prunedRoots, processedLiveRoots, plugins, stoppedReason, and done (true when all due work has drained within budget).
admin.reindexSearch
Rebuilds the full-text search index across all entities. POST, empty body. Returns { indexed } with per-entity counts.
More collection methods
Each collection also exposes the rest of the versioning and review surface. The remaining methods, all under cms.api.<collection>:
- Blocks:
moveBlock,deleteBlock,duplicateBlock,updateBlocks,updateRoot. - Branches:
revertBranch,checkDivergence(plus the branch methods above). - Merges:
createMergeRequest,getDiff,checkConflicts,resolveConflicts,createMergeBlockVersion,executeMerge,listMergeRequests,updateMergeRequest,closeMergeRequest,reopenMergeRequest. - Approvals:
requestApproval,approve,reject,cancelApproval,getApproval,listApprovals. - Comments:
createCommentThread,createCommentMessage,listCommentThreads,getCommentThread,resolveCommentThread,reopenCommentThread,updateCommentMessage,deleteCommentMessage,listMentions. - Publications:
unpublishBranch,listPublications(pluspublishBranchandgetPublishedContent). - Redirects:
createRedirect,updateRedirect,archiveRedirect,listRedirects, andresolveRedirect(call this in routing to follow a redirect).
Other namespaces
Beyond collections and admin, cms.api exposes system namespaces, each on its own page:
Media
Variables
{{key}} values.Templates
Search
Notifications
These methods are also available on the client as client.<collection>.<method> and client.admin.<method>.