Domma CMS User Manual

Pages API

Updated by Darryl Waterhouse on 29 September 2026 3 min read

Pages are Markdown files in content/pages/, addressed by their URL path. All endpoints need the pages permission for the action named (read, create, update, delete). In the paths below, * is the page's URL path without the leading slash, e.g. /api/pages/about.

GET /api/pages

Requires Bearer token + pages read permission.

List every page with its metadata (no body).

// Response 200
[ { "urlPath": "/about", "title": "About Us", "slug": "about", "status": "published", "layout": "default",
    "visibility": "public", "tags": [], "sortOrder": 0, "category": null, "project": null, "resolvedProject": "core",
    "plugin": null, "bundled": false, "updatedAt": "2026-09-27T10:30:00.000Z", "createdAt": "...", "versionCount": 3 } ]

A page may still carry a legacy showInNav value; nothing reads it - the site's navigation is edited in Menus.

GET /api/pages/*

Requires Bearer token + pages read permission.

One page, with its frontmatter fields and full Markdown body.

// Response 200
{ "urlPath": "/about", "title": "About Us", "body": "## Our Story\n\nWe started...", ... }
// Error 404
{ "error": "Page not found" }

POST /api/pages

Requires Bearer token + pages create permission.

Create a page.

FieldTypeDescription
urlPathstringRequired. Public URL path, e.g. /about
frontmatterobjectFrontmatter fields (title, status, visibility, layout, ...)
bodystringMarkdown content
// Response 201 - the created page
// Error 409 - names the project the existing page belongs to
{ "error": "A page already exists at /about (project: core)", "urlPath": "/about", "project": "core" }

PUT /api/pages/*

Requires Bearer token + pages update permission.

Update a page, and optionally move it to a new URL path. A move re-aims menu links that pointed at the old path and drops the page's share links. Each save keeps a version (see Versions below).

FieldTypeDescription
frontmatterobjectFrontmatter fields
bodystringMarkdown content
newUrlPathstringOptional. Move the page to this path
// Response 200 - the updated page
// Error 404
{ "error": "Page not found" }
// Error 409
{ "error": "A page already exists at that path" }

DELETE /api/pages/*

Requires Bearer token + pages delete permission.

Delete a page and its share links.

// Response 200
{ "success": true }

GET /api/pages/tags

Requires Bearer token + pages read permission.

Every tag used on any page, sorted.

// Response 200
{ "tags": ["guide", "news", "tutorial"] }

POST /api/pages/preview

Requires Bearer token + pages read permission.

Render Markdown to HTML (shortcodes processed, no frontmatter), as the signed-in user sees it.

// Request body
{ "markdown": "Hello **world**" }
// Response 200
{ "html": "<p>Hello <strong>world</strong></p>" }

POST /api/pages/preview/full

Requires Bearer token + pages read permission.

Render unsaved editor content as the complete public page - layout, navbar, footer, theme and custom CSS - the editor's Live Preview.

// Request body
{ "urlPath": "/about", "frontmatter": { "title": "About" }, "body": "..." }
// Response 200
{ "html": "<!doctype html>..." }

POST /api/pages/preview-links

Requires Bearer token + pages update permission.

Make a share link that lets anyone with it see one page, draft or not, until it expires. expiresIn is 1h, 24h, 7d (default) or 30d, or a number of seconds up to 30 days. GET /api/pages/preview-links?urlPath=/about lists them and DELETE /api/pages/preview-links/:id withdraws one.

// Request body
{ "urlPath": "/about", "expiresIn": "7d", "label": "For the client" }
// Response 201
{ "id": "...", "urlPath": "/about", "expiresAt": "...", "token": "...", "url": "https://example.com/_preview?token=..." }

Versions

GET /api/versions/list/*

Requires Bearer token + pages read permission.

A page's saved versions (its History), newest first. The other version routes take a version's filename from this list:

RoutePermissionDoes
GET /api/versions/get/:filename/*readOne version's content
POST /api/versions/create/*updateSave a named version now ({"label": "..."})
POST /api/versions/restore/:filename/*updatePut a version back as the page
DELETE /api/versions/delete/:filename/*deleteDelete one version
POST /api/versions/bulk-delete/*deleteDelete several ({"filenames": [...]})
POST /api/versions/prune/*deleteKeep only the most recent ({"keep": 10})