> ## 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.
> 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. /api/company/v1 and /api/v1/... paths are documented in no spec here and must never be used (/api/v1.1/... is distinct and documented in company-v0). Use page/per_page offset pagination only where a spec documents it — in practice the unversioned company-v0 admin surface; every versioned surface uses cursor pagination.
> Navigation menu management is documented in themes/navigation-menus. These unversioned admin endpoints (/api/menus and nested menu_items) are verified against the implementation but are not yet in the synced OpenAPI specs. Use that reference for menu payloads and its flat page/per_page pagination; missing spec coverage does not make these endpoints unavailable.
> 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/auth-v0.yaml covers the unversioned auth surface (/api/... paths — authentication, MFA, social auth, and token exchange); 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 — 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.

# Member Liquid variables

> Read the signed-in member, lazy media, content pages, playlists, navigation, and authentication URLs in your theme.

<Warning>
  Member storefront is in a limited pilot. Confirm that it is enabled for your company before using these variables. The sign-in and sign-out links described here require the updated storefront authentication release.
</Warning>

Use `member` for profile fields and `member_content` for media, content pages, and playlists. Use `member_routes` for navigation and authentication links, and `settings.menu` for the current member site's navigation.

## Where variables are available

| Variable         | Live, authorized member page               | Cached storefront page            |
| ---------------- | ------------------------------------------ | --------------------------------- |
| `member`         | Signed-in member's approved profile fields | Not available                     |
| `member_content` | Content visible to the signed-in member    | Not available                     |
| `member_routes`  | Root, sign-in, and sign-out links          | Root, sign-in, and sign-out links |
| `settings.menu`  | Resolved member site menu                  | Normal theme settings             |

Guests are redirected to hosted authentication before a protected member page renders. There is no themed sign-in landing.

Signing in on a storefront does not put private member data into its cached Liquid render. Use [Member-aware sections](/themes/member-storefront/member-aware-sections) for browser-side personalization there. Builder previews do not expose a real member's private data, even when you select a preview audience.

Member page access rules still apply. Reading a variable does not grant access to another member's content or another site's pages.

## Member profile

| Field                     | Value                                                                    |
| ------------------------- | ------------------------------------------------------------------------ |
| `member.first_name`       | Given name                                                               |
| `member.last_name`        | Family name                                                              |
| `member.full_name`        | Nonempty first and last names joined with a space                        |
| `member.email`            | Email address for the membership in this company                         |
| `member.status`           | Activity status in this company                                          |
| `member.avatar_url`       | Profile image URL, when available                                        |
| `member.bio`              | Profile biography, when available                                        |
| `member.language_iso`     | Saved member language code, when available; no company-language fallback |
| `member.member_type.slug` | Member type slug, when a type is assigned                                |
| `member.member_type.name` | Member type display name, when a type is assigned                        |

Read these fields for display. They do not expose permissions, passwords, authentication tokens, or payment-card details. Fields without a value render empty.

```liquid theme={null}
{% if member %}
  <header class="member-profile">
    {% if member.avatar_url != blank %}
      <img src="{{ member.avatar_url | escape }}" alt="" />
    {% endif %}
    <h1>Hello, {{ member.first_name | default: member.full_name | escape }}</h1>
    <p>{{ member.member_type.name | escape }}</p>
  </header>
{% endif %}
```

## Lazy content collections

| Collection                 | Content                                                             |
| -------------------------- | ------------------------------------------------------------------- |
| `member_content.media`     | Published media visible to the member in the current country        |
| `member_content.pages`     | Published company content pages available in the current country    |
| `member_content.playlists` | Active company-wide playlists and playlists belonging to the member |
| `playlist.entries`         | Visible media and content-page entries in a playlist                |

`member_content.pages` is the company's content library. It is **not** the list of custom member pages created in the builder. Use `settings.menu` to navigate the member site.

Collections load independently. Assigning a collection to a Liquid variable does not load it. Reading its items, size, empty state, first or last item, navigation links, or error loads one bounded batch. Repeated reads reuse that result during the same render. A playlist's entries load only when you consume that entries collection. Profile fields also load when you read them.

Render individual fields or loop through `items`. Printing a collection directly does not display its records. Serializing a whole profile reads all its exposed fields, so prefer the fields your section actually needs.

### Collection fields

| Field                      | Value                                                              |
| -------------------------- | ------------------------------------------------------------------ |
| `items`                    | Items in the current batch                                         |
| `size`                     | Number of items in this batch, not a total count                   |
| `empty`                    | Whether this batch has no items                                    |
| `first`, `last`            | First or last item in this batch, or empty                         |
| `next_url`, `previous_url` | Relative navigation link, or empty when unavailable                |
| `error`                    | Empty on success; `invalid_pagination` or `unavailable` on failure |

A failed collection returns no items. Check `error` separately so you do not present a loading failure as an empty library.

### Media fields

| Field            | Value                                                         |
| ---------------- | ------------------------------------------------------------- |
| `id`             | Media identifier                                              |
| `title`          | Localized title                                               |
| `content_format` | Media kind, such as `video`, `image`, `pdf`, `ppt`, or `link` |
| `url`            | Source file or destination URL, when supported                |
| `thumbnail_url`  | Thumbnail URL, when available                                 |

Reading `url` does not create a tracked share link. Not every media item has a URL or thumbnail; check before rendering them.

```liquid theme={null}
{% if member_content %}
  {% assign library = member_content.media %}
  <section class="member-media">
    <h2>Media library</h2>
    {% if library.error %}
      <p>Media could not be loaded. Please try again.</p>
    {% elsif library.empty %}
      <p>No media is available yet.</p>
    {% else %}
      <ul class="member-media__grid">
        {% for media in library.items %}
          <li>
            {% if media.thumbnail_url != blank %}
              <img src="{{ media.thumbnail_url | escape }}" alt="" loading="lazy" />
            {% endif %}
            {% if media.url != blank %}
              <a href="{{ media.url | escape }}">{{ media.title | escape }}</a>
            {% else %}
              <span>{{ media.title | escape }}</span>
            {% endif %}
          </li>
        {% endfor %}
      </ul>
      <nav aria-label="Media navigation">
        {% if library.previous_url %}
          <a href="{{ library.previous_url | escape }}">Previous</a>
        {% endif %}
        {% if library.next_url %}
          <a href="{{ library.next_url | escape }}">Next</a>
        {% endif %}
      </nav>
    {% endif %}
  </section>
{% endif %}
```

Place this markup inside your theme's section and use its existing settings and CSS. The variables do not impose a layout, component, or style.

### Content page fields

| Field         | Value                                 |
| ------------- | ------------------------------------- |
| `id`          | Content page identifier               |
| `title`       | Localized title                       |
| `slug`        | Content page slug                     |
| `description` | Localized description, when available |
| `image_url`   | Image URL, when available             |

This projection exposes metadata. It does not expose the page body or a `url` field. Do not turn its slug into a member-site `/pages/` link: those are different resources.

### Playlist fields

| Field         | Value                                             |
| ------------- | ------------------------------------------------- |
| `id`          | Playlist identifier                               |
| `title`       | Playlist title                                    |
| `description` | Description, when available                       |
| `image_url`   | Stored cover image, when available                |
| `entries`     | Lazy collection of the playlist's visible entries |

The cover does not fall back to a child item's image. A playlist does not expose a direct `url` field.

### Playlist entry fields

| Field          | Value                                                       |
| -------------- | ----------------------------------------------------------- |
| `id`           | Entry identifier                                            |
| `content_type` | `media` or `page`                                           |
| `position`     | Stored position, when assigned                              |
| `content`      | The corresponding media or content-page fields listed above |

Entries retain their stored order and exclude content the member cannot view. Other entry types are not exposed.

```liquid theme={null}
{% if member_content %}
  {% assign playlists = member_content.playlists %}
  {% if playlists.error %}
    <p>Playlists could not be loaded.</p>
  {% else %}
    {% for playlist in playlists.items %}
      <section>
        <h2>{{ playlist.title | escape }}</h2>
        {% assign entries = playlist.entries %}
        {% if entries.error %}
          <p>This playlist could not be loaded.</p>
        {% else %}
          <ul>
            {% for entry in entries.items %}
              <li>
                {% if entry.content_type == 'media' and entry.content.url != blank %}
                  <a href="{{ entry.content.url | escape }}">{{ entry.content.title | escape }}</a>
                {% else %}
                  {{ entry.content.title | escape }}
                {% endif %}
              </li>
            {% endfor %}
          </ul>
          {% if entries.next_url %}
            <a href="{{ entries.next_url | escape }}">More entries</a>
          {% endif %}
        {% endif %}
      </section>
    {% endfor %}
    {% if playlists.next_url %}
      <a href="{{ playlists.next_url | escape }}">More playlists</a>
    {% endif %}
  {% endif %}
{% endif %}
```

### Navigate collections

Use each collection's generated `next_url` and `previous_url`. The default batch size is 25 and the maximum is 100. Navigation uses simple numeric query values for these Liquid collections; this is separate from REST API pagination.

| Collection       | Batch number                   | Batch size                      |
| ---------------- | ------------------------------ | ------------------------------- |
| Media            | `member_media_page`            | `member_media_limit`            |
| Content pages    | `member_content_pages_page`    | `member_content_pages_limit`    |
| Playlists        | `member_playlists_page`        | `member_playlists_limit`        |
| Playlist entries | `member_playlist_entries_page` | `member_playlist_entries_limit` |

For example, `?member_media_page=2&member_media_limit=12` requests the second batch of 12 media items. Batch numbers and sizes must be integers from 1 through 100. Invalid values produce `invalid_pagination` and an empty result.

Media, content pages, and playlists appear newest first. Playlist entries follow their stored order. Entry navigation parameters apply to all playlist entry collections in the same request. Generated links preserve validated collection navigation parameters, but do not preserve unrelated query parameters. You do not need a Liquid `paginate` block around these collections.

## Member routes

These are navigation values, not a login-state signal. They remain available regardless of whether the visitor is signed in, so you can safely include both links in shared cached HTML.

| Field                    | Value                                                                                       |
| ------------------------ | ------------------------------------------------------------------------------------------- |
| `member_routes.root`     | `/` on the current host: storefront home on the storefront, member home on the account host |
| `member_routes.sign_in`  | Sign-in URL for the current surface, with a return destination                              |
| `member_routes.sign_out` | `/auth/sign_out` on the current host; use a normal link                                     |

Use `member_routes.sign_in` for sign-in links. Both hosts use `/auth/sign_in`; no theme login template or `sign_in_url` field is needed.

There is no `member_routes.csrf_token` variable. See [Sign in and sign out](/themes/member-storefront/authentication) for complete examples and session behavior.

## Member site navigation

`settings.menu` contains the current site's navigation while preserving the theme's other settings.

| Field                      | Value                                                   |
| -------------------------- | ------------------------------------------------------- |
| `settings.menu.title`      | Menu title                                              |
| `settings.menu.handle`     | Menu slug, or empty for a derived menu                  |
| `settings.menu.menu_items` | Ordered items with `title`, `url`, and `sub_menu_items` |

Render item URLs as provided. See the complete layout example in [Member page templates](/themes/member-storefront/member-page-templates#create-the-member-layout).
