Domma CMS User Manual

Navigation API

Updated by Darryl Waterhouse on 29 September 2026 2 min read

The site's navigation is made of menus: each is a file in config/menus/<slug>.json, edited at Content > Menus, and shown by mapping it to a slot (the navbar, the footer) or placing it on a page with [menu slug="..." /]. The endpoints need the menus permission for the action named. The old single navigation file (config/navigation.json) was retired when menus arrived - see Legacy navigation at the end.

GET /api/menus

Requires Bearer token + menus read permission.

Every menu you may see (a user confined to some projects sees their projects' menus), without items.

GET /api/menus/:slug

Requires Bearer token + menus read permission.

One menu, with its items. Sub-items go under items.

// Response 200
{ "slug": "main", "name": "Main navigation", "variant": "dark", "position": "sticky",
  "items": [
    { "text": "Home", "url": "/", "icon": "home" },
    { "text": "Services", "items": [ { "text": "Design", "url": "/design" } ] }
  ],
  "meta": { "createdAt": "...", "updatedAt": "..." } }

POST /api/menus

Requires Bearer token + menus create permission.

Create a menu. slug is required; name, description, items and the display options (variant, position, orientation, align, side, float, highlight, binding) are optional. An item may carry visibility to show it only to some roles.

// Response 201 - the created menu
// Error 409
{ "error": "Menu \"main\" already exists" }

PUT /api/menus/:slug

Requires Bearer token + menus update permission.

Save a menu. The public pages that show it are refreshed.

DELETE /api/menus/:slug

Requires Bearer token + menus delete permission.

Delete a menu. Refused while it is mapped to a slot.

// Error 409
{ "error": "Cannot delete - menu is mapped to slot \"navbar\". Unmap it first." }

POST /api/menus/:slug/duplicate (create permission) makes a copy.

GET /api/menu-locations

Requires Bearer token + menus read permission.

Which menu fills each slot. GET /api/menu-locations/registry lists the slots there are (navbar, footer-primary, footer-legal, overlay, admin-sidebar, and any a plugin adds).

// Response 200
{ "navbar": "main", "footer-primary": "footer", "admin-sidebar": "admin-sidebar" }

PUT /api/menu-locations

Requires Bearer token + menus update permission.

Save the slot map (same shape as above).

// Response 200
{ "success": true }

GET /api/context-menus

Requires Bearer token + context-menus read permission.

Right-click menus for the public site (Content > Context Menus) are a separate kind of menu, with the same shape of routes: GET, POST /api/context-menus, GET, PUT, DELETE /api/context-menus/:slug, POST /api/context-menus/:slug/duplicate, and GET /api/context-menus/action-types for what an item can do.

Legacy navigation

GET and PUT /api/navigation (the navigation permission) still read and write config/navigation.json, but the public site no longer reads that file: on first start after menus arrived it was moved into the main menu and renamed navigation.json.bak. Use the menus endpoints above.