> ## 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, 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. The merchant must open the emailed sign-in link and create an API token before authenticated calls are possible.
> 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 where a spec documents it — in practice the unversioned company-v0 admin surface; every versioned surface uses cursor pagination.
> 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 — 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.

# Collect Enrollment Details After Payment: Checkout Forms Guide

> How Fluid's post-purchase forms tie into enrollment checkout: which carts get a form, when it appears, what happens if it isn't finished, and how to read and answer enrollment fields through the Checkout API.

A checkout form collects extra information from a shopper who is enrolling, such as a date of birth, a tax ID or a signed document. Fluid shows it **after** the payment is taken and the order is placed, so it never adds a step between the shopper and paying. This guide explains the model end to end, then shows how a custom checkout reads and answers the form through the Checkout API.

<Info>
  Merchants build forms in the admin. For the screen-by-screen steps, see
  [Forms](/help/admin/forms) in the Help Center. This guide covers the model
  and the API.
</Info>

## The model

| Piece | What it is |
| - | - |
| **Form** | A set of fields you build in the admin, with a title, a form type, a list of countries and an **Active** switch |
| **Form type** | **Post Purchase** forms appear at enrollment checkout. **General** forms are standalone forms shared by link or embed. **Pre Purchase** is retired and can't be chosen for new forms |
| **Field** | One question, such as **Date of Birth** or **File Upload**, with a label and a **Required** switch |
| **Countries** | The cart countries a form applies to |
| **Enrollment** | Created for each enrollment cart. It carries the token that addresses its fields, and its state is complete or incomplete |
| **Answer** | A shopper's saved response to one field, stored as text. A file answer is stored as a link to the uploaded file |

### Which carts get a form

Forms apply only to **enrollment carts**. A cart becomes one when the shopper adds an enrollment pack, or when it's flagged with [Flag a cart as enrollment eligible](/api-reference/carts/flag-a-cart-as-enrollment-eligible). A regular cart never gets a form.

An enrollment cart gets every form that is **Post Purchase**, **Active**, and set to the cart's country. Forms aren't attached to enrollment packs, member types or products, so every enrollment in a country gets the same fields. When more than one form matches, checkout shows their fields together as one form.

### When the form appears

<Steps>
  <Step title="Checkout places the order">
    The shopper pays. Checkout captures the payment and places the order. Outstanding form fields never block this step.
  </Step>

  <Step title="The order confirmation page shows the form">
    Fluid-hosted checkout renders the form at the top of the order confirmation page, above the order-details drop zones. It appears only when the order has an enrollment and the enrollment has outstanding Post Purchase fields.
  </Step>

  <Step title="The shopper submits">
    Checkout saves each answer. File fields upload as soon as a file is dropped in.
  </Step>

  <Step title="The enrollment completes">
    When every required field has an answer, the enrollment is complete. Fluid saves a copy of the answers with the new member's record and sends the enrollment completed webhook.
  </Step>
</Steps>

### What the order and the form each decide

The **order** decides the purchase and the membership. The shopper is charged, the order exists, and the shopper is enrolled as a member of the enrollment's member type as soon as checkout places the order, whether or not they ever open the form.

The **form** decides only whether the enrollment is complete. An incomplete enrollment means:

* The form keeps appearing on the order confirmation page, with saved answers filled in.
* Fluid emails up to five reminders over about 25 days, each linking back to that page, while the company's enrollment completion reminder email is active.
* The enrollment completed webhook hasn't fired yet.

Only fields marked **Required** keep an enrollment open. A form whose fields are all optional doesn't.

## Read and answer the form through the API

Fluid-hosted checkout does all of this for you. Use these steps when you build your own order confirmation experience on the Checkout API, or when an agent or back-office tool collects the answers instead.

<Steps>
  <Step title="Get the enrollment token">
    [Complete checkout](/api-reference/carts/complete-checkout) returns the new order. On an enrollment order, its `enrollment_token` addresses the enrollment. You can read it again later from [Show order](/api-reference/orders/show-order). On a regular order, it's null.
  </Step>

  <Step title="Read the fields">
    Call [Show enrollment](/api-reference/enrollments/show-enrollment) with the token. It needs no Bearer token: the enrollment token is the credential, so treat it like a password. The response lists `enrollment_fields`, each with its type, order, placement, any saved answer, and its builder settings, plus the enrollment's `state`.

    Render only fields whose `placement` is `post_purchase`. That's what Fluid-hosted checkout shows. The list can also carry fields from other active forms for the country.
  </Step>

  <Step title="Save each answer">
    Send each answer with [Submit enrollment field answer](/api-reference/enrollments/submit-enrollment-field-answer). The answer is a string, so send a date as `1985-04-12` and a yes-or-no answer as text.

    For a file field, send the file with [Upload file for enrollment field](/api-reference/enrollments/upload-file-for-enrollment-field). Fluid accepts JPEG, PNG, WebP, TIFF or PDF files up to 5 MB.
  </Step>

  <Step title="Change a saved answer">
    Use [Update enrollment field answer](/api-reference/enrollments/update-enrollment-field-answer). The path segment that the reference names as the field ID takes the saved answer's `field_answer_id` from Show enrollment, not the field's `id`. Submitting a second answer for the same field creates another answer instead of replacing the first.
  </Step>

  <Step title="Check completion">
    Read Show enrollment again. When `state` is `complete`, the enrollment is finished. After that, every write to the enrollment is refused with `422`.
  </Step>
</Steps>

<Warning>
  Checkout checks only that required fields are filled in. Fluid saves any
  string as an answer, so validate formats, such as a tax ID's length, in your
  own front end before you submit.
</Warning>

### Webhooks

Subscribe to these with the [Webhooks guide](/api/guides/webhooks). Call [List webhook resources](/api-reference/webhooks-resources/list-webhook-resources) for the exact resource and event pairs your company can use.

| Event | When it fires |
| - | - |
| `enrollment_started` | When Fluid creates the enrollment for an enrollment cart |
| `form_submitted` | When an enrollment saves its first answer to a form. It doesn't mean the form is finished |
| `enrollment_completed` | When every required field has an answer |

To act on finished enrollments, such as sending a welcome kit or syncing to a compensation system, use `enrollment_completed`. Don't use `form_submitted` for that.

### Managing forms

Build and edit forms, and read or export all of a form's responses, in the admin. See [Forms](/help/admin/forms). You can also manage forms through the API: [List forms](/api-reference/forms/list-forms), [Create a form](/api-reference/forms/create-a-form), [List form elements](/api-reference/form-elements/list-form-elements), [List form respondents](/api-reference/forms/list-form-respondents), [Export form responses as CSV](/api-reference/forms/export-form-responses-as-csv), [List incomplete enrollees](/api-reference/forms/list-incomplete-enrollees), and [Send manual enrollment reminders](/api-reference/forms/send-manual-enrollment-reminders). Through the Checkout API you can read and answer one enrollment's fields at a time, by its token.

## Example: a rep enrollment form for the United States

Dunder Mifflin enrolls paper sales reps in the United States. It needs each new rep's legal name, date of birth and a signed W-9 to pay commissions.

| Field | Component | Required | Sensitive Info |
| - | - | - | - |
| Legal name | **Legal Name** | Yes | Off |
| Date of birth | **Date of Birth** | Yes | On |
| Blank W-9 | **File Download** | No | Off |
| Signed W-9 | **File Upload** | Yes | On |
| How did you hear about Dunder Mifflin? | **Multiple Choice** | No | Off |

The form is `Enrollment - United States`, with **Form type** set to **Post Purchase**, **Countries** set to United States, and **Active** on.

When Pam Beesly buys the Paper Sales Starter Kit from Dwight Schrute's link:

1. She pays on one page with no extra fields. Her order is placed, Dwight gets credit for it, and Pam becomes a member of the enrollment pack's member type.
2. The order confirmation page asks for her legal name, date of birth and signed W-9, and the optional survey question.
3. She uploads her W-9 the next day from the reminder email's link. The enrollment completes, and the enrollment completed webhook tells the company's compensation system to start paying her commissions.

For Canada, Dunder Mifflin adds a second Post Purchase form, `Enrollment - Canada`, set to Canada only. It asks for a SIN in a **Short Text Entry** field, with **Sensitive Info** on, instead of the W-9.

## Example: "How did you hear about us?"

To learn where new members come from, add one optional **Multiple Choice** field to each country's Post Purchase form:

* **Label**: How did you hear about us?
* **Options**: Social media, A friend or family member, A rep, Search, An event, Other
* **Required**: off, so the question never holds an enrollment open

Read the answers in the form's responses in the admin, or export them as CSV.

A Post Purchase form reaches new members only, because regular checkouts never show forms. To survey every customer, use a **General** form and share its link, for example in a post-purchase email.

## Recommended field sets

### Enrollment

| Need | Component | Required | Notes |
| - | - | - | - |
| Legal name | **Legal Name** | Yes | Match tax and payout records |
| Date of birth | **Date of Birth** | Where you have an age minimum | Nothing checks the age for you |
| Tax ID | **Short Text Entry**, or **Social Security Number** in the US | Where you pay commissions | Turn on **Sensitive Info** |
| Tax or compliance document | **File Download** and **File Upload** | Where required | One field offers the blank document, the other collects the signed copy |
| Business details | **Short Text Entry** | No | For members who enroll as a business |
| Consent statement | **Checkbox** | Yes | Checkout shows only the label, so put the full statement in it |

For terms and policies the shopper must accept before buying, use [Agreements](/help/admin/settings/agreements), not a form field. Agreements linked to an enrollment appear in checkout before the order is placed, and each acceptance is recorded.

### Attribution and preferences

| Need | Component | Required |
| - | - | - |
| How did you hear about us? | **Multiple Choice** | No |
| Product interests | **Multiple Choice** | No |
| Contact preference | **Multiple Choice** | No |
| Anything else? | **Long Text Entry** | No |

## Gotchas

* **Forms are country-scoped, not pack-scoped.** You can't show a different form for each enrollment pack or member type. Use one form per country when countries need different fields.
* **A form must be Active and Post Purchase.** A draft, or a General form, never appears at checkout.
* **General forms can hold enrollments open.** Completion counts the fields of every active form for the cart's country, but checkout shows only Post Purchase fields. Keep General forms out of the countries where you enroll members, or turn them off when you don't need them.
* **Pre Purchase forms are retired.** An older form with that type still asks before payment. Change it to Post Purchase.
* **A sponsor field doesn't set a sponsor.** Answers are stored as text. They don't change who gets credit for the order or the new member's sponsor.
* **No conditional logic and no pattern checks.** Every field shows to every shopper who gets the form.

## Related pages

<CardGroup cols={2}>
  <Card title="Forms in the admin" icon="clipboard-list" href="/help/admin/forms">
    Build forms, set their countries, and view, export and follow up on responses.
  </Card>

  <Card title="Checkout" icon="cart-shopping" href="/concepts/checkout">
    How Fluid Checkout works and how to extend it.
  </Card>

  <Card title="Headless commerce" icon="code" href="/api/guides/headless-commerce">
    Run the cart-to-order flow on the Checkout API.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/api/guides/webhooks">
    Subscribe to enrollment and form events.
  </Card>
</CardGroup>


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