> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fluid.app/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> For new direct REST integrations, use the v2026-04 surfaces. The @fluid-app FairShare SDK continues to use its own published public-v2025-06 contract.
> Authenticate with the header Authorization: Bearer <token>; public storefront read endpoints require no auth.
> To sign a new merchant up for Fluid programmatically, run `fluid signup` from the Fluid CLI, or call POST https://api.fluid.app/api/company with no credentials, as described in /api/agent-signup. Do not automate the signup form or book a demo. Before authenticated calls are possible, the merchant must sign the agent in to the Fluid CLI with the emailed code and --shop set to the company's fluid_shop (which also confirms the signup), or open the emailed confirmation link and give the agent an API token.
> After signup, to launch a merchant's store (back-office sync, payments onboarding, store setup, a theme copied from their current site, and a preview link before billing), follow /api/agent-launch.
> Lists use cursor pagination via the page[cursor] and page[limit] query params; follow meta.pagination.next_cursor until it is null.
> When the same operation exists on more than one surface, use the newest: dated API versions are newer than unversioned ones, and later dates win (v2026-04 > v2025-06 > unversioned v0/v1.1). Fall back to a legacy or unversioned operation only when no newer versioned equivalent exists — the company-v0 notes below list the known superseded operations. The same applies to /api/company/v1 and /api/v1/... paths: prefer a newer documented equivalent, and use one only when none exists (/api/v1.1/... is distinct and documented in company-v0). Use page/per_page offset pagination only on an operation whose spec documents those params — mostly the unversioned company-v0 admin surface, plus some lists on other surfaces, versioned ones included; page every other list with cursors.
> Fluid has three navigation APIs; don't mix them up. Storefront website menus (navigation bars, footers) are /api/menus and nested menu_items, in api-reference/content-v0.yaml (API Reference: Website > Navigation menus), with a how-to in themes/navigation-menus; their list uses flat page/per_page pagination. The Fluid mobile app's navigation is /api/v2/mobile_navigations, in api-reference/mobile-v2.yaml (API Reference: Mobile app > Navigation); its list also uses page/per_page. Portal navigations belong to a portal definition (Fluid OS), in api-reference/fluid-os-v0.yaml (API Reference: Portal > Portal navigation), and each has a platform of web or mobile.
> The OpenAPI specs under api-reference/ are the authoritative contracts; prefer them over prose when in doubt. api-reference/storefront-v2026-04.yaml covers the v2026-04 storefront surface (/api/v202604/... paths); api-reference/checkout-v2026-04.yaml covers the v2026-04 checkout surface (/api/checkout/v2026-04/... paths — carts, cart auth, discounts, items, subscriptions, orders, enrollments, and store config); api-reference/public-v2025-06.yaml covers the Public SDK surface used by the @fluid-app FairShare SDK, including its parallel cart lifecycle, browser integrations, versioned payment callbacks, unversioned public utilities, and the cart price-override operation; api-reference/payment-v2026-04.yaml covers the v2026-04 payment gateway admin surface (/api/payment/v2026-04/... paths, bearer-authenticated — gateway CRUD, gateway purchase/authorize/$0-verify, transaction list/show and capture/void/credit, and merchant payment configuration); api-reference/payments-v2026-04.yaml covers the v2026-04 cart payment surface (/api/payments/v2026-04/carts/{cart_token}/... paths, authenticated by the cart token in the path with no bearer — payment-method selection, VGS card tokenization, 3D Secure verification, and PayPal/Braintree/Klarna/Apple Pay flows); api-reference/commerce-v2026-04.yaml covers the v2026-04 commerce order-editing surface (/api/v202604/orders/{order_id}/edits paths, bearer-authenticated — post-checkout order edits that atomically insert items and add adjustments/discounts, with an optional dry-run preview); api-reference/webhooks-v0.yaml covers the unversioned webhooks surface (/api/... paths — webhook registration, delivery payloads, callback registrations, company events, and webhook/callback schemas); api-reference/company-v0.yaml covers the legacy unversioned company admin surface (/api/... paths, bearer-authenticated except two operations that take no credential, POST /api/company (create a company) and GET /api/agreements/{id} — company settings and management, customers, users, roles, subscription plans, subscription bundles, subscriptions, media, pages, catch-ups, inventory levels, domains, agreements, and admin order actions). company-v0 caveats: it is the legacy v0 admin contract and its lists use flat page/per_page offset pagination, which is expected there despite the general cursor-pagination rule; where an operation exists in both company-v0 and a versioned spec, prefer the versioned spec — the subscriptions lifecycle (list/create/show/update, cancel, pause, reactivate, resume, retry, skip, failed-cycle-waiver, discounts) and subscription bundles are superseded by checkout-v2026-04, and company pages/media CRUD plus the public pages, categories, products, and media list endpoints are superseded by storefront-v2026-04. Subscription plan management (/api/subscription_plans, resource-wrapped {"subscription_plan": {...}} bodies) exists only in company-v0. api-reference/members-v2025-06.yaml covers the v2025-06 unified Member identity surface (/api/v2025-06/members/... paths, bearer-authenticated — member list/create/show/update, lookup by email/username/external_id/legacy_customer_id, member-type assignment, and the sponsor genealogy read). Prefer it over the customers and reps surfaces when the member type matters: /customers does not serialize member_type. api-reference/analytics-v2026-04.yaml covers the v2026-04 Home dashboard analytics surface (/api/v202604/analytics/dashboard/... paths, bearer-authenticated — read-only endpoints for the Home > Overview, Home > Live, and Home > Field tabs, each accepting an optional country ISO alpha-2 query param that scopes aggregations to a single country).
> api-reference/analytics-v0.yaml covers the unversioned analytics surface that backs the fluid-admin Traffic tab (/api/analytics/... and /api/analytics/traffic/... paths, bearer-authenticated — the legacy shares/views/visitors summary plus traffic overview, ranked campaigns, sources, geographies, flows, and per-rep breakdown, all sharing one reporting-period contract).
> Successful responses wrap the resource payload alongside a top-level integer status and a meta object.
> Portal Definition authoring edits and synchronizes the portal JSON resource graph. Widget Package authoring builds either a company-owned or Droplet-owned Remote DOM package. These are separate contracts; do not imply that one defines the other.
> For Widget Package worker code, use only @fluid-app/portal-sdk/widgets/worker. Use only the Portal Definition and Widget Package workflows and public entry points documented here; do not infer support for undocumented surfaces.
> Every portal function and declarative capability used by a widget must appear in that widget's uses array. Use the same typed function value in uses; do not invent capability-name strings.
> Widget styling must use the portal's semantic theme variables for colors, typography, spacing, radii, borders, focus, and charts whenever a token represents the visual decision. Do not create a separate light or dark palette or duplicate theme controls as widget properties.
> Prefer worker-safe Fluid UI components exported by @fluid-app/portal-sdk/widgets/worker when they fit the interaction. When no exported component fits, use semantic HTML, accessible behavior, and the portal theme variables.
> A Portal Definition push updates the remote working definition. A portal version is an immutable snapshot, and activation is a separate live release operation.
> The Help Center (/help/...) is for merchants, admins and reps using Fluid. Its admin pages mirror the admin's routes: the screen at admin.fluid.app/settings/taxes is documented at /help/admin/settings/taxes. Use the Help Center for how-to questions about the admin, and the Developer Platform and API Reference for building integrations.
> Help Center pages describe what a company admin sees. A reader's role can hide screens and actions; admins manage roles on Settings > Roles (/help/admin/settings/roles). If someone can't find a screen or button, their role's permissions are the first thing to check.
> Send people who need Fluid support to /help/getting-help. Don't invent support email addresses, phone numbers or response times.

# Build member site pages with Liquid

> Write a member site's layouts, sections, snippets, pages and assets, use the Liquid objects, tags and filters a site gets, and work within the sandboxed frame's rules.

A member site is its own small theme. Its pages are Liquid templates that read only the site's own files. This page covers what a site holds, the Liquid objects its templates can read, and the rules of the frame it renders in. To read a member's data, use a script instead: see [Read viewer data in site scripts](https://docs.fluid.app/member-sites/site-scripts.md).

> [!NOTE]
>
> Member sites are not storefront themes. A site can't use a theme's files, settings or stylesheets, and `fluid theme` commands don't touch it. See the [overview](https://docs.fluid.app/member-sites/overview.md).

## Know the folder

A site holds six kinds of file. In the [CLI](https://docs.fluid.app/member-sites/cli.md), each lives in a folder of the same name, and a path in the folder is the path the file API uses.

| Folder | What it holds |
| - | - |
| `layouts/` | The templates that frame a page, such as `layouts/site.liquid` |
| `sections/` | Reusable blocks of a page, such as `sections/hero.liquid` |
| `snippets/` | Small shared fragments, such as `snippets/card.liquid` |
| `pages/` | One template for each page. `pages/about.liquid` is a page's content, and `pages/index.liquid` is the home page |
| `assets/` | Text assets: CSS, JavaScript, JSON, text and HTML files |
| `config/` | `settings.json`, `menus.json`, `pages.json` and `access.json` |

* **No subfolders.** A name uses lowercase letters, digits, hyphens and underscores. Names that start with a dot are ignored.
* **A page is a file and a row.** `pages/<slug>.liquid` holds the content, and a row in `config/pages.json` holds the slug, title, position, published flag, layout and menu. A new page needs both. A site holds at most 50 pages.
* **The home page's slug is `/`** in `config/pages.json`, and its file is `pages/index.liquid`. A slug is never `index`.

The [CLI page](https://docs.fluid.app/member-sites/cli.md#know-the-folder) shows the folder, and [Pages and menus](https://docs.fluid.app/member-sites/pages-and-menus.md) explains the config files.

## Pick a layout

A page uses its row's `layout`, else the site's default `layout`, else `layouts/site.liquid`. The layout name `none` renders the page with no layout. A missing layout falls back to `site`: see [Pages and menus](https://docs.fluid.app/member-sites/pages-and-menus.md#pick-a-layout).

A layout prints the page where it writes `content_for_layout`, and Fluid's head content where it writes `content_for_header`:

```liquid layouts/site.liquid theme={null}
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>{{ page.title }} | {{ site.name }}</title>
    {{ content_for_header }}
  </head>
  <body>
    {% render 'nav' %}
    {{ content_for_layout }}
    {{ 'site.js' | asset_url | script_tag }}
  </body>
</html>
```

`content_for_header` carries what the page needs in its `<head>`: the site SDK that installs `window.fluid`, and a link to `assets/site.css` when the site has that file. A page with no layout can print `content_for_header` too.

## Read the Liquid objects

A page and its layout render with the same objects.

| Object | What it holds |
| - | - |
| `site` | `name`, `handle`, `url` (`/accounts/<handle>`), `pages`, `pages_menu` and `menus` |
| `site.pages` | The published pages in position order. Each has `title`, `slug`, `url`, `home` and `current` |
| `site.pages_menu` | The same pages as a menu: `title`, `handle` and `menu_items`. Each item has `title`, `url` and `sub_menu_items` |
| `site.menus.<slug>` | A menu from `config/menus.json`, in the same shape, such as `site.menus.footer` |
| `settings` | The published `config/settings.json`, plus `settings.menu`, which is the page's menu, else the menu with the slug `main`, else `site.pages_menu` |
| `page` | The page being rendered, shaped like an entry of `site.pages` |
| `company` | `id` and `name` |

* **Every `url` is a path on your company's domain**, such as `/accounts/rileys-shop/about`. Use it as written in links.
* **An unpublished page isn't listed.** A page with `published: false` isn't in `site.pages`, `site.pages_menu` or any menu.
* **Don't read member data in Liquid.** Don't read `member` or `member.<field>` in a layout, section, snippet or page. Member data is leaving member site Liquid, and `fluid member-site lint` warns on every `member.<field>` it finds. Read the viewer's data in a script.
* **Keep members' data out of settings.** `config/settings.json` is the same for every viewer.

A navigation snippet reads `settings.menu`:

```liquid snippets/nav.liquid theme={null}
<nav>
  {% for item in settings.menu.menu_items %}
    <a href="{{ item.url }}">{{ item.title }}</a>
  {% endfor %}
</nav>
```

## Use tags and filters

A site's Liquid reaches its own files only.

| You write | It resolves to |
| - | - |
| `{% render 'card' %}` | `snippets/card.liquid` |
| `{% section 'hero' %}` | `sections/hero.liquid` |
| `{{ 'site.css' \| asset_url }}` | The address of the site's `assets/site.css` |
| `{{ 'site.js' \| asset_url \| script_tag }}` | A `<script>` element for `assets/site.js` |
| `{{ 'page.css' \| asset_url \| stylesheet_tag }}` | A `<link>` element for `assets/page.css` |
| `{{ content_for_layout }}` | The rendered page, inside a layout |
| `{{ content_for_header }}` | The site's head content, inside a layout or a page |

A page template can use a section, a snippet and a settings value together:

```liquid pages/index.liquid theme={null}
{% section 'hero' %}
<main style="color: {{ settings.primary_color }}">
  <h1>{{ site.name }}</h1>
  {% render 'card' %}
</main>
```

Sections can carry a `{% schema %}` block. Lint checks it, and the pairing of block tags such as `{% if %}` and `{% endif %}`.

> [!WARNING]
>
> Load a site's JavaScript with `script_tag`, or add `crossorigin="anonymous"` to a hand-written `<script src>`. Fluid serves a site's script only to a request from the site's own frame, which sends `Origin: null`. A plain `<script src>` sends no origin, and Fluid answers it with `404`. A `<script>` element with the code inline works either way.

## Know the frame's rules

Every page renders in an iframe on your company's domain with this policy:

```text theme={null}
Content-Security-Policy: frame-ancestors 'self'; sandbox allow-scripts allow-forms
```

The sandbox never allows the same origin, so the page has an opaque origin. Your code runs freely inside it. These rules follow:

* **No cookies and no storage.** A site's JavaScript has no cookie, and reading `document.cookie` throws. It has no `localStorage` or `sessionStorage`. Don't build sign-in, "remember me" or any state that relies on them, and never put a token or other credential in Liquid, settings or an asset.
* **Scripts and forms only.** The sandbox grants scripts and forms. The browser also blocks popups, `alert` and `confirm` dialogs, and navigation of the top page.
* **Fluid draws the account menu.** It appears outside the frame on every page, even a page with the layout `none`. No template can hide or replace it, so don't build a second account menu or a sign-out link.
* **Link inside the site.** Use `site.pages` and menu `url` values. A click navigates inside the frame.
* **Reach Fluid with `fluid.fetch`.** The frame has no cookie, so the page's own `fetch` to a Fluid API carries no session and fails. Call `window.fluid.fetch(path, init)` instead, which behaves like `fetch`. See [Read viewer data in site scripts](https://docs.fluid.app/member-sites/site-scripts.md).

## Use text assets only

A site holds text assets only: `css`, `js`, `json`, `txt` and `html` files in `assets/`, valid UTF-8 and not empty. A push refuses any other file.

Don't put an image, a font, a PDF or a video in the folder, and don't inline one as a large base64 string. Upload images and fonts to your company's media library and use the URL it gives you, in an `<img src>`, in `background-image: url(...)` and in an `@font-face` `src`.

```css assets/site.css theme={null}
@font-face {
  font-family: "Riley Serif";
  src: url("https://media.example.com/fonts/riley-serif.woff2") format("woff2");
}

.hero {
  background-image: url("https://media.example.com/images/hero.jpg");
}
```

An asset has no draft. A new, changed or removed asset is live on a published site as soon as a push writes it, so write assets that still work with the published pages. See [Know what is live at once](https://docs.fluid.app/member-sites/cli.md#know-what-is-live-at-once).

## Preview and publish

Page content, layouts, sections, snippets and settings are drafts until you publish the site, and members see only the published copies. See [Publish a site](https://docs.fluid.app/member-sites/publishing.md). To see a draft, run `fluid member-site dev`, or use the draft preview operations of the [member API](https://docs.fluid.app/api-reference/site-preview/preview-the-home-page-of-a-sites-draft.md) or the [company API](https://docs.fluid.app/api-reference/member-site-preview/preview-the-home-page-of-a-company-sites-draft.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.