> ## 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.
> Never use /api/company/v1 or /api/v1 paths, page/per_page params, or offset pagination — they are legacy.
> 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).
> Successful responses wrap the resource payload alongside a top-level integer status and a meta object.

# Developer Guide: Building and Customizing Fluid Themes

> Learn how to build and customize Fluid themes using Liquid templating, JSON section schemas, components, assets, and locale files for translations.

Fluid themes are built on the Liquid templating language — a proven, widely adopted templating engine — combined with a JSON schema system that powers the visual Page Editor. As a developer, you have full control over markup, styles, logic, and content structure. This guide walks you through the key building blocks of a Fluid theme.

## Theme File Structure

A Fluid theme is organized into directories by function. Each directory holds a specific type of file, and Fluid's template resolver knows where to look for each one.

```
theme/
├── layouts/
│   └── theme.liquid
├── product/
│   └── default/
│       ├── index.liquid
│       └── styles.css
├── shop_page/
├── navbar/
├── footer/
├── sections/
├── components/
├── assets/
├── locales/
└── config/
```

## Layout File

The `layouts/theme.liquid` file is the outermost shell rendered for every page on your storefront. It contains the `<html>`, `<head>`, and `<body>` tags that wrap all page-specific content.

Two special Liquid tags connect the layout to the rest of the theme:

* `{{ content_for_header }}` — Outputs platform-injected metadata, scripts, and stylesheets into the `<head>`. Always include this tag.
* `{{ content_for_layout }}` — Outputs the rendered content of the current page template between the `<body>` tags.

Here is a minimal layout example:

```liquid theme={null}
<!DOCTYPE html>
<html lang="{{ localization.language.iso_code }}">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>{{ page_title }} — {{ company.name }}</title>
    {{ content_for_header }}
  </head>
  <body>
    {% section 'navbar' %}

    <main>
      {{ content_for_layout }}
    </main>

    {% section 'footer' %}
  </body>
</html>
```

## Choose a layout for a template

Templates use `layouts/theme.liquid` by default. To use another layout, add the `layout` tag to the template and pass the layout name without the `.liquid` extension:

```liquid theme={null}
{% layout "custom" %}

<h1>{{ page_title }}</h1>
```

Fluid renders this template inside `layouts/custom.liquid`. To render the template without a layout, use `none`:

```liquid theme={null}
{% layout none %}

<!DOCTYPE html>
<html>
  <head>
    {{ content_for_header }}
  </head>
  <body>
    <h1>{{ page_title }}</h1>
  </body>
</html>
```

When you disable the layout, the template must provide any document structure and global markup it needs.

## Template Files

Template files contain the page-specific Liquid markup rendered inside `{{ content_for_layout }}`. Each template type maps to a page category in Fluid:

| Type              | Description                           |
| ----------------- | ------------------------------------- |
| `product`         | Individual product detail pages       |
| `medium`          | Media detail pages (videos, articles) |
| `shop_page`       | Main shop listing page                |
| `home_page`       | Storefront home page                  |
| `collection_page` | Product collection pages              |
| `category_page`   | Category browsing pages               |
| `enrollment_pack` | Enrollment pack detail pages          |
| `cart_page`       | Shopping cart                         |
| `join_page`       | Affiliate or member sign-up pages     |
| `navbar`          | Global navigation                     |
| `footer`          | Global footer                         |
| `sections`        | Reusable page sections                |
| `components`      | Shared UI components                  |

Each template type can have **multiple named templates** stored as subdirectories — for example, `product/default/` and `product/featured/`. Only one template per type is published and active at a time, but you can create and preview others before switching.

## Sections

Sections are the primary building blocks of Fluid pages. Each section is a self-contained Liquid file that pairs markup with a `{% schema %}` block defining its configurable settings. The schema powers the right panel of the visual Page Editor.

Here is an example product header section:

```liquid theme={null}
<section class="product-header">
  <h1>{{ section.settings.heading | default: product.name }}</h1>

  {% if section.settings.show_price %}
    <p class="price">{{ product.price | money }}</p>
  {% endif %}

  {% if section.settings.image %}
    <img
      src="{{ section.settings.image | img_url: '800x600' }}"
      alt="{{ section.settings.heading | default: product.name }}"
    />
  {% endif %}
</section>

{% schema %}
{
  "name": "Product Header",
  "settings": [
    {
      "type": "text",
      "id": "heading",
      "label": "Custom Heading",
      "placeholder": "Leave blank to use product name"
    },
    {
      "type": "checkbox",
      "id": "show_price",
      "label": "Show Price",
      "default": true
    },
    {
      "type": "image_picker",
      "id": "image",
      "label": "Override Image"
    }
  ],
  "presets": [
    {
      "name": "Product Header",
      "settings": {
        "show_price": true
      }
    }
  ]
}
{% endschema %}
```

## Blocks

Blocks are repeatable content items defined within a section's schema. They allow editors to add, remove, and reorder dynamic items — like testimonial cards, feature bullets, or image slides — without touching code.

Define blocks in the schema and render them in Liquid using `section.blocks`:

```json theme={null}
{
  "name": "Testimonials",
  "blocks": [
    {
      "type": "testimonial",
      "name": "Testimonial",
      "limit": 6,
      "settings": [
        {
          "type": "textarea",
          "id": "quote",
          "label": "Quote"
        },
        {
          "type": "text",
          "id": "author",
          "label": "Author Name"
        }
      ]
    }
  ]
}
```

```liquid theme={null}
<div class="testimonials">
  {% for block in section.blocks %}
    {% if block.type == 'testimonial' %}
      <blockquote>
        <p>{{ block.settings.quote }}</p>
        <cite>{{ block.settings.author }}</cite>
      </blockquote>
    {% endif %}
  {% endfor %}
</div>
```

## Assets

Store images, fonts, stylesheets, and scripts in the `assets/` directory. Reference any asset in Liquid using the `asset_url` filter:

```liquid theme={null}
<link rel="stylesheet" href="{{ 'main.css' | asset_url }}" />
<img src="{{ 'logo.png' | asset_url }}" alt="{{ company.name }}" />
<script src="{{ 'storefront.js' | asset_url }}"></script>
```

Fluid distinguishes between two types of assets:

* **Binary assets** — Images, fonts, and other files served as-is (e.g. `.png`, `.jpg`, `.woff2`)
* **Non-binary assets** — CSS and JavaScript files that can be edited directly in the CLI or Code Mode

All assets are served via Fluid's CDN, so the `asset_url` filter always resolves to the correct CDN URL regardless of environment.

## Localization

Fluid's translation system uses JSON locale files stored in `locales/`. Each file corresponds to a language (e.g. `locales/en.json`, `locales/es.json`) and contains a nested key-value structure.

```json theme={null}
{
  "products": {
    "add_to_cart": "Add to Cart",
    "sold_out": "Sold Out",
    "from_price": "From {{ price }}"
  },
  "general": {
    "learn_more": "Learn More"
  }
}
```

Reference any locale key in Liquid using the `| t` filter:

```liquid theme={null}
<button>{{ 'products.add_to_cart' | t }}</button>
<a href="{{ product.url }}">{{ 'general.learn_more' | t }}</a>
```

When a visitor's language is set, Fluid automatically resolves `| t` to the correct locale file. If a key is missing in a non-English locale, Fluid falls back to the English value.

## Available Liquid Filters

Fluid extends Liquid with a set of commerce-focused filters for formatting and transforming data:

| Filter               | Purpose                                                       |
| -------------------- | ------------------------------------------------------------- |
| `img_url: '300x200'` | Resize and serve an image via CDN at the specified dimensions |
| `money`              | Format a numeric price value as a currency string             |
| `t`                  | Look up a translation key in the active locale file           |
| `truncate: 150`      | Limit a string to the specified number of characters          |
| `asset_url`          | Resolve a filename in `assets/` to its full CDN URL           |
| `date: '%B %d, %Y'`  | Format a date value using `strftime`-style format strings     |
| `join: ', '`         | Join an array of values into a single string with a separator |

For pushing your finished theme to Fluid or setting up a local development workflow, see the [Fluid CLI guide](/themes/cli).

For theme-wide settings, see [root theme configuration](/themes/root-theme-configuration). When you add navigation, use the canonical patterns in [supported storefront paths](/themes/supported-paths).
