Skip to main content
Recommend managed menus when you want to edit navigation in admin without changing theme code. Hardcoded links are also supported.

Connect to the menu API

Use https://api.fluid.app with Authorization: Bearer <token> and Content-Type: application/json for JSON writes. These unversioned admin endpoints require company-admin access with menus.view for reads and menus.update for writes. Mist’s fluid_api tool supplies the active company’s authentication and admin client header. Replace path placeholders with returned IDs. Menu writes affect shared store data immediately, independently of publishing theme files.

Create a menu

Send this body to POST /api/menus. Use linkable_type: "Link" for custom URLs; menu creation requires an item type. Every menu needs at least one country, so send your company’s country IDs in country_ids. An empty list fails validation. New menus are inactive unless you send active: true.
Read, create, and update responses wrap the menu in menu. The returned tree uses menu_items and nested sub_menu_items; _attributes keys are for writes.

Choose item types

An item’s linkable_type decides where it links. Record types take the record’s ID in linkable_id and build the URL from its current slug, so the link follows a slug change. Any other value, including Category, links to /home/shop. Fluid removes the query string from every item URL. When it renders a menu, Fluid replaces the text home anywhere in an item’s URL with the current storefront’s name, so /home/shop follows a rep’s storefront. An external URL that contains home, such as https://example.com/homeware, changes too. Items can nest to any depth through sub_menu_items_attributes.

Update or remove items

Send a menu wrapper to PUT /api/menus/:id. Within menu_items_attributes, omit id to create an item, include id to update it, or include id with _destroy: true to delete it. Apply the same rules recursively under sub_menu_items_attributes. Use IDs from a fresh menu read.
For a direct item update, send a menu_item wrapper to PUT /api/menus/:menuId/menu_items/:itemId. Children still use sub_menu_items_attributes. Item reads and updates return a menu_item wrapper. To add one item, send a menu_item wrapper to POST /api/menus/:menuId/menu_items, with parent_id to nest it. Delete one item with DELETE /api/menus/:menuId/menu_items/:itemId, or an entire menu with DELETE /api/menus/:id.

Find an existing menu

GET /api/menus accepts status (active or inactive), page, per_page, search_query, country_ids, and sorted_by. Use title_asc, title_desc, created_at_asc, or created_at_desc for sorting. Encode country arrays as country_ids[]=1&country_ids[]=2. This admin endpoint uses flat page numbers, not cursor pagination. List responses contain menus and meta with total_count, total_pages, current_page, and per_page.

Connect the menu to your theme

List and read existing menus before creating another. After a write, read the menu again to verify its labels, destinations, ordering, and children. Use the returned menu slug as the value of a section’s link_list setting. Do not derive it from the title: older menus can return a null slug.
Replace the example default with the returned slug. Render items from section.settings.menu.menu_items, using each item’s title and url. Check desktop and mobile navigation in preview before finishing. A link_list value can be a menu’s slug or its ID. In Liquid, the menu has title, handle, and menu_items, and each item has only title, url, and sub_menu_items. A blank value, or one that matches no menu, renders an empty menu. The menu’s active flag and countries don’t change what a link_list renders. The setting’s value is saved in the template’s schema, and the visual editor saves it there too. The schema default applies only while no value is saved, so changing the default doesn’t move a header that already has one. The live storefront renders each template’s published version, and a theme push saves templates without publishing them. The Base theme’s navbar reads its menu from the menu setting of its nav block, which defaults to main-menu.

Import a menu from another site

When you move a store to Fluid, rebuild its header menu after the pages, products, collections, and categories it links to exist.
  1. Record the source header: each item’s title, URL, order, and children, including dropdown items that are hidden until hover and items that appear only in the mobile menu. Leave out header controls such as the logo, search, account, cart, and country or language selector. They aren’t menu items.
  2. Map each internal link to the canonical_url of the Fluid record that replaced it, or use that record’s type and linkable_id. Don’t build a URL from the source handle. Keep external links as they are, and note any internal link you can’t map instead of pointing it at the home page.
  3. Find the menu the header already names. Read the header’s link_list value and match it against GET /api/menus.
  4. Replace that menu’s items with PUT /api/menus/:id, adding the source items and sending _destroy: true for the ones the source doesn’t have. Menu writes are live immediately, so the header changes without a theme publish.
  5. If the value matches no menu, create one and use the returned slug. Set it as the header’s value, then publish the theme so the live storefront picks it up.
  6. Read the menu back and compare it with the source. Then load the live storefront and check the header and mobile menu.
Keep the country and language selector next to the menu, not inside it. See Build a navbar country and language selector.