> ## 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.

# Open the bank account (ACH) session

> Resolves the bank account (ACH) payment account for the cart and returns
the ACH session: the provider the account runs on, the amount the debit
will ask for, and what that provider's collector mounts with. The
checkout calls it when the shopper looks at bank account and mounts the
provider's collector from the answer. No request body. It does not set
the cart's payment method, create a payment method row, register a
webhook or void an open charge, so calling it again is safe and a
shopper who looks at bank account and goes back to another method is
unaffected. It stores a reserved routing pin in the cart's metadata that
names the account the session opened on; clients cannot write it and no
response shows it. The pin is sticky: later calls reopen the session on
the pinned account while the cart's payment methods still offer it.
`PUT payment_method` with type `ach` records the pinned account when the
shopper pays. A cart that cannot pay by bank account is refused with
`422` and `meta.code` = `ach_points` or `ach_unavailable`, the same codes
as that write. Cart-token authenticated. Returns `404` when the cart is not
found and `410` when the cart has already been processed or holds an
authorized enrollment.




## OpenAPI

````yaml /api-reference/payments-v2026-04.yaml post /api/payments/v2026-04/carts/{cart_token}/ach-session
openapi: 3.1.0
info:
  title: Fluid Cart Payments API
  version: v2026-04
  description: >
    Consumer-agnostic, cart-scoped payment endpoints under
    /api/payments/v2026-04/carts/{cart_token}. The same endpoints serve
    checkout, admin, and portal identically. Authentication is cart-token based
    (the token in the path); no JWT or API key is required. The one exception is
    paying with a saved payment method on the set-payment-method endpoint, which
    requires a customer/user JWT (in the body, an Authorization header, or the
    session) and fails with 422 without one. Unknown request keys are stripped
    server-side rather than rejected, so the server accepts payloads that the
    strict request schemas in this document would flag. This spec is the source
    of truth for generated payment API clients and is intentionally separate
    from payment-v2026-04.yaml, which documents the bearer-authenticated
    gateway/transaction admin surface at /api/payment/v2026-04.


    **Sandbox test companies.** A sandbox test company is linked to a live

    company. While the test company cannot be reached, because sandbox access

    is turned off for its live company or the live company was deleted:


    - a cart token for one of its carts answers exactly as a token no cart
      holds, with the operation's documented `404` (cart not found), so the
      response does not reveal that the cart exists;
    - an operation that resolves the company from a bearer credential refuses
      that credential with `403` and the body `{"error": "<message>"}`,
      before the operation runs.

    These refusals are documented here once rather than on each operation.
  contact:
    email: support@fluid.app
  license:
    name: Proprietary
    identifier: LicenseRef-Proprietary
servers:
  - url: https://api.fluid.app
security: []
tags:
  - name: payments
    description: >-
      Cart-scoped payment method selection, VGS card tokenization, and 3D Secure
      verification.
    x-fluid-section: Payments
  - name: paypal
    description: >-
      PayPal checkout — client SDK token, order creation and authorization, and
      shipping-change callbacks.
  - name: braintree
    description: Braintree checkout — client token issuance and transaction authorization.
  - name: klarna
    description: Klarna checkout — payment session creation and updates.
  - name: apple-pay
    description: Apple Pay checkout — merchant session validation.
paths:
  /api/payments/v2026-04/carts/{cart_token}/ach-session:
    post:
      tags:
        - payments
      summary: Open the bank account (ACH) session
      description: >
        Resolves the bank account (ACH) payment account for the cart and returns

        the ACH session: the provider the account runs on, the amount the debit

        will ask for, and what that provider's collector mounts with. The

        checkout calls it when the shopper looks at bank account and mounts the

        provider's collector from the answer. No request body. It does not set

        the cart's payment method, create a payment method row, register a

        webhook or void an open charge, so calling it again is safe and a

        shopper who looks at bank account and goes back to another method is

        unaffected. It stores a reserved routing pin in the cart's metadata that

        names the account the session opened on; clients cannot write it and no

        response shows it. The pin is sticky: later calls reopen the session on

        the pinned account while the cart's payment methods still offer it.

        `PUT payment_method` with type `ach` records the pinned account when the

        shopper pays. A cart that cannot pay by bank account is refused with

        `422` and `meta.code` = `ach_points` or `ach_unavailable`, the same
        codes

        as that write. Cart-token authenticated. Returns `404` when the cart is
        not

        found and `410` when the cart has already been processed or holds an

        authorized enrollment.
      operationId: payments_v2026_04_ach_session
      parameters:
        - $ref: '#/components/parameters/CheckoutJourneyId'
        - $ref: '#/components/parameters/CheckoutAttemptId'
        - name: cart_token
          in: path
          required: true
          description: >
            Opaque cart token returned by the create-cart response. It scopes
            the

            request to a single cart and is the credential for these endpoints —

            cart-token authentication carried in the path, with no bearer token
            or API

            key.
          schema:
            type: string
      responses:
        '200':
          description: The ACH session
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AchSessionResponse'
              examples:
                stripe:
                  summary: A Stripe-backed session
                  value:
                    ach:
                      provider: stripe
                      amount_cents: 3999
                      currency: usd
                      mandate_text: null
                      client:
                        publishable_key: pk_test_51Abc
                    meta:
                      request_id: 018f2c1a-8b3a-7e6d-9f10-2a3b4c5d6e7f
                      timestamp: '2026-04-01T12:00:00Z'
        '404':
          description: Cart not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '410':
          description: Cart already processed or holds an authorized enrollment
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProcessedCartResponse'
        '422':
          description: >-
            The cart cannot pay by bank account (`meta.code` = `ach_points` or
            `ach_unavailable`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AchRefusedResponse'
      security: []
components:
  parameters:
    CheckoutJourneyId:
      name: X-Checkout-Journey-Id
      in: header
      required: false
      description: |
        Optional non-authorizing checkout journey UUID. Use with
        X-Checkout-Attempt-Id. Capture is disabled by default; malformed or
        incomplete pairs are ignored without changing checkout behavior.
        Cart scope comes from the authenticated cart token, never these headers.
      schema:
        type: string
      example: 00000000-0000-4000-8000-000000000001
    CheckoutAttemptId:
      name: X-Checkout-Attempt-Id
      in: header
      required: false
      description: >
        Optional customer-submission UUID paired with X-Checkout-Journey-Id.

        Retain it for transport retries and originating continuations; use a new

        UUID for a new customer submission. It does not replace payment or order

        idempotency keys. Invalid pairs are ignored rather than rejecting
        payment.
      schema:
        type: string
      example: 00000000-0000-4000-8000-000000000011
  schemas:
    AchSessionResponse:
      description: Success body for the ACH session.
      type: object
      additionalProperties: false
      required:
        - ach
        - meta
      properties:
        ach:
          $ref: '#/components/schemas/AchSession'
        meta:
          $ref: '#/components/schemas/Meta'
    ErrorResponse:
      description: >-
        Standard error envelope — a human-readable error_message, a structured
        errors object, and response meta.
      type: object
      additionalProperties: false
      required:
        - error_message
        - errors
        - meta
      properties:
        error_message:
          type: string
          description: Human-readable summary of the failure, safe to surface to the buyer.
        errors:
          $ref: '#/components/schemas/ErrorBag'
        meta:
          $ref: '#/components/schemas/Meta'
    ProcessedCartResponse:
      description: >-
        Returned with 410 Gone by every cart payment endpoint when the cart is
        locked against payment changes, either because it has already been
        processed (converted to an order) or because it holds an authorized
        enrollment.
      type: object
      additionalProperties: false
      required:
        - error_message
        - errors
        - meta
      properties:
        error_message:
          type: string
          description: >-
            Human-readable message stating why the cart is locked (already
            processed into an order, or in authorized state holding an
            enrollment).
        errors:
          $ref: '#/components/schemas/ErrorBag'
        meta:
          $ref: '#/components/schemas/ProcessedCartMeta'
    AchRefusedResponse:
      description: >
        The cart cannot pay by bank account (ACH), so no ACH session was opened

        and no payment method was created. `meta.code` is the stable reason
        clients translate:

        `ach_points` (points are applied; bank payments cannot be

        combined with points) or `ach_unavailable` (the method is not

        offered for this cart: the flag is off, the account is not set up, the

        cart was created in the admin or holds a subscription, is not in USD,

        or the total is under the minimum; or, on `PUT payment_method`, the

        account the ACH session pinned is no longer offered, so the client

        opens a new session). The English

        `error_message` is for logs and for clients that do not know the code.
      type: object
      additionalProperties: false
      required:
        - error_message
        - errors
        - meta
      properties:
        error_message:
          type: string
        errors:
          type: object
          additionalProperties: false
          required:
            - payment_method
          properties:
            payment_method:
              type: array
              items:
                type: string
        meta:
          type: object
          additionalProperties: false
          required:
            - request_id
            - timestamp
            - code
          properties:
            request_id:
              type:
                - string
                - 'null'
            timestamp:
              type: string
              format: date-time
            code:
              type: string
              enum:
                - ach_points
                - ach_unavailable
    AchSession:
      description: >-
        The ACH session. Routing has chosen the account behind it, and the
        checkout mounts that provider's collector from this object alone. The
        payment-method list carries no provider credentials.
      type: object
      additionalProperties: false
      required:
        - provider
        - amount_cents
        - currency
        - mandate_text
        - client
      properties:
        provider:
          type: string
          description: >-
            The key of the provider the routed account runs on (`stripe`). The
            checkout picks its collector by this key and treats a key it does
            not know as unavailable.
        amount_cents:
          type: integer
          description: What the debit will ask for, in cents (the cart total after points).
        currency:
          type: string
          enum:
            - usd
        mandate_text:
          type:
            - string
            - 'null'
          description: >-
            The debit authorization text Fluid shows the shopper. Null when the
            provider renders its own, as Stripe's Payment Element does.
        client:
          type: object
          additionalProperties: true
          description: >-
            What the provider's collector mounts with. The keys are
            provider-defined and opaque to every other client. For `stripe` it
            holds `publishable_key`, the account's Stripe publishable key, which
            is public by design; the secret key never leaves Fluid.
    Meta:
      description: Standard response metadata included on every response.
      type: object
      additionalProperties: false
      required:
        - request_id
        - timestamp
      properties:
        request_id:
          type:
            - string
            - 'null'
          description: >-
            Server-assigned id for this request, echoed so responses can be
            correlated with server logs and support tickets; `null` when none
            was assigned.
        timestamp:
          type: string
          format: date-time
          description: ISO 8601 timestamp (UTC) marking when the response was generated.
    ErrorBag:
      description: >-
        Validation errors keyed by field, a list of errors, a single error
        message, or null when no structured error details are available.
      anyOf:
        - type: string
        - type: array
          items:
            $ref: '#/components/schemas/ErrorValue'
        - type: object
          additionalProperties:
            $ref: '#/components/schemas/ErrorValue'
        - type: 'null'
    ProcessedCartMeta:
      description: >-
        Meta for the cart-lock guards (processed cart, authorized enrollment).
        Carries the shop URL and the full locked cart. The cart is returned as
        an open object here; its fully-typed shape is documented in the checkout
        API.
      type: object
      additionalProperties: false
      required:
        - request_id
        - timestamp
        - shop_url
        - cart
      properties:
        request_id:
          type:
            - string
            - 'null'
          description: >-
            Server-assigned id for this request, echoed for log correlation;
            `null` when none was assigned.
        timestamp:
          type: string
          format: date-time
          description: ISO 8601 timestamp (UTC) marking when the response was generated.
        shop_url:
          type:
            - string
            - 'null'
          description: >-
            Storefront URL of the shop that owns the processed cart; `null` when
            it cannot be resolved.
        cart:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/JsonValue'
          description: >-
            The full processed cart as an open object. Its fully-typed shape is
            documented on the Cart checkout surface (Checkout endpoints
            reference).
    ErrorValue:
      description: A validation or API error value.
      anyOf:
        - type: string
        - type: array
          items:
            type: string
        - type: object
          additionalProperties:
            $ref: '#/components/schemas/JsonValue'
    JsonValue:
      description: >-
        Any valid JSON value for provider-specific payloads (card payloads,
        payment method payloads, Apple Pay token envelopes) whose keys are not
        fixed by the API contract.
      anyOf:
        - type: string
        - type: number
        - type: boolean
        - type: 'null'
        - type: array
          items:
            $ref: '#/components/schemas/JsonValue'
        - type: object
          additionalProperties:
            $ref: '#/components/schemas/JsonValue'

````

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