Navigation API
https://api.airogelcms.com/v1/accounts/:account_id/navigations
A navigation is a named menu, such as a main menu or a footer menu. It holds a tree of items. Each item is either a plain link (url) or a link to an entry, which follows the entry's URL when that changes. Items nest through parent_id.
Navigation operations
- GET
/v1/accounts/:account_id/navigations- List navigations - GET
/v1/accounts/:account_id/navigations/:id- Get one navigation with its item tree - POST
/v1/accounts/:account_id/navigations- Create a navigation - PUT / PATCH
/v1/accounts/:account_id/navigations/:id- Update a navigation - DELETE
/v1/accounts/:account_id/navigations/:id- Delete a navigation (returns204)
:id is the navigation's nav_ ID or handle.
Item operations
- GET
/v1/accounts/:account_id/navigations/:navigation_id/items- List items (top-level items with nestedchildren) - GET
/v1/accounts/:account_id/navigations/:navigation_id/items/:id- Get one item - POST
/v1/accounts/:account_id/navigations/:navigation_id/items- Create an item - PUT / PATCH
/v1/accounts/:account_id/navigations/:navigation_id/items/:id- Update an item - DELETE
/v1/accounts/:account_id/navigations/:navigation_id/items/:id- Delete an item (returns204)
:navigation_id is the navigation's ID or handle. An item's :id must be its ni_ prefix ID, because items have no handle.
Navigation fields
| Field | Type | Required | Description |
|---|---|---|---|
title | string | yes | Display name |
handle | string | yes | Identifier used in Liquid. POST with an existing handle updates that navigation. |
Item fields
| Field | Type | Required | Description |
|---|---|---|---|
title | string | yes | Link text |
url | string | no | Explicit URL or path, for links that do not point to an entry |
collection_handle | string | no | With entry_handle: link to that entry |
entry_handle | string | no | With collection_handle: the entry to link to |
priority | integer | no | Sort order among siblings, ascending. If you leave it out, the item goes after its existing siblings. |
parent_id | string | no | ni_ ID of the parent item. It must be in the same navigation. |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
account_id
|
string | Required |
Path. Your account prefix ID (acct_...).
|
id
|
string | Optional |
Path. Navigation nav_ ID or handle (navigation endpoints). On item endpoints, the item's ni_ ID.
|
navigation_id
|
string | Optional |
Path, item endpoints. Navigation nav_ ID or handle.
|
handle
|
string | Optional | Query, list only. Return only the record with exactly this handle. |
all
|
string | Optional |
Query, item list only. true returns every item in a flat list (still paginated). By default only top-level items are listed, each with nested children.
|
page
|
integer | Optional | Query, list only. Page number, starting at 1. The page size is fixed at 20. |
title
|
string | Required | Body. Navigation name, or item link text. |
handle
|
string | Required | Body, navigations only. Identifier. POST with an existing handle updates it. |
url
|
string | Optional | Body, items. Explicit link URL. |
collection_handle
|
string | Optional | Body, items. Collection of the linked entry. |
entry_handle
|
string | Optional | Body, items. Handle of the linked entry. |
priority
|
integer | Optional | Body, items. Sort order among siblings. Defaults to after the last sibling. |
parent_id
|
string | Optional |
Body, items. ni_ ID of the parent item.
|
Request Example
# Create a navigation
curl -X POST "https://api.airogelcms.com/v1/accounts/$ACCOUNT_ID/navigations" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title": "Main Menu", "handle": "main_menu"}'
# Add a plain link
curl -X POST "https://api.airogelcms.com/v1/accounts/$ACCOUNT_ID/navigations/main_menu/items" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title": "Home", "url": "/", "priority": 1}'
# Add a link to an entry
curl -X POST "https://api.airogelcms.com/v1/accounts/$ACCOUNT_ID/navigations/main_menu/items" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title": "About Us", "priority": 2, "collection_handle": "pages", "entry_handle": "about"}'
# Nest an item under another one
curl -X POST "https://api.airogelcms.com/v1/accounts/$ACCOUNT_ID/navigations/main_menu/items" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title": "Our Team", "url": "/about/team", "parent_id": "ni_Hk2m8Pq"}'
# Get the navigation with its item tree
curl "https://api.airogelcms.com/v1/accounts/$ACCOUNT_ID/navigations/main_menu" \
-H "Authorization: Bearer $API_TOKEN"
# List every item flat
curl "https://api.airogelcms.com/v1/accounts/$ACCOUNT_ID/navigations/main_menu/items?all=true" \
-H "Authorization: Bearer $API_TOKEN"
# Move an item
curl -X PATCH "https://api.airogelcms.com/v1/accounts/$ACCOUNT_ID/navigations/main_menu/items/ni_Rt5v1Wz" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"priority": 5}'
Response Example
// GET /navigations/main_menu - items here show only id, title, url, priority, timestamps and children
{
"id": "nav_6pWq3Lm",
"handle": "main_menu",
"title": "Main Menu",
"items_count": 3,
"created_at": "2026-09-10T12:00:00Z",
"updated_at": "2026-09-10T12:05:00Z",
"items": [
{
"id": "ni_Rt5v1Wz",
"title": "Home",
"url": "/",
"priority": 1,
"created_at": "2026-09-10T12:01:00Z",
"updated_at": "2026-09-10T12:01:00Z"
},
{
"id": "ni_Hk2m8Pq",
"title": "About Us",
"url": null,
"priority": 2,
"created_at": "2026-09-10T12:02:00Z",
"updated_at": "2026-09-10T12:02:00Z",
"children": [
{ "id": "ni_Zb7c4Xn", "title": "Our Team", "url": "/about/team", "priority": 1,
"created_at": "2026-09-10T12:03:00Z", "updated_at": "2026-09-10T12:03:00Z" }
]
}
]
}
// POST/PUT /navigations and GET /navigations (list items) return the navigation without "items"
// Item endpoints (GET/POST/PUT .../items/:id) add parent_id and, for linked items, entity
{
"id": "ni_Hk2m8Pq",
"title": "About Us",
"url": null,
"priority": 2,
"created_at": "2026-09-10T12:02:00Z",
"updated_at": "2026-09-10T12:02:00Z",
"parent_id": null,
"entity": {
"type": "CollectionEntry",
"id": "cnety_3sDf9Gh",
"handle": "about",
"title": "About",
"url": "/about"
},
"children": [
{ "id": "ni_Zb7c4Xn", "title": "Our Team", "url": "/about/team", "priority": 1,
"created_at": "2026-09-10T12:03:00Z", "updated_at": "2026-09-10T12:03:00Z", "parent_id": "ni_Hk2m8Pq" }
]
}
// GET .../items
{
"data": [ { "id": "ni_Rt5v1Wz", "title": "Home", "url": "/", "priority": 1, "parent_id": null, "...": "..." } ],
"pagination": {
"page": 1,
"per_page": 20,
"total": 1,
"total_pages": 1,
"next_page": null,
"prev_page": null
}
}
Additional Notes
Two item shapes. GET /navigations/:id embeds the item tree, but those items carry only id, title, url, priority, timestamps and children. The /items endpoints also return parent_id and, for items linked to an entry, an entity object. children is present only when an item has children. Create and update on a navigation return it without items.
Linked items. For items linked with collection_handle + entry_handle, url is null and the page URL is entity.url. That URL follows the entry if its path changes, and it is what templates render.
Create is idempotent. POSTing an item with the same title and url (or the same title and linked entry) as an existing item in the navigation updates that item instead of adding a duplicate.
Unresolved references. On update, an unknown collection_handle/entry_handle pair or parent_id returns 422 (path: "entry_handle" or "parent_id"). On create, they are currently ignored, and the item is created without the link or parent. Check the response.
Sorting. Items are ordered by priority ascending within their parent.
Deleting a navigation deletes all of its items. See Liquid Templates for rendering menus.