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

# FairShare Cart API: JavaScript Methods and HTML Controls

> Full reference for the FairShare cart JavaScript API — add items, update quantities, subscribe, checkout, and control the cart widget programmatically.

The FairShare cart API gives you complete programmatic control over the shopper's cart. You can read cart state, add or remove items, manage subscription plans, trigger checkout, and control the cart widget UI — either through JavaScript or by adding `data-*` attributes directly to your HTML elements. Both approaches work together, so you can mix declarative HTML for simple cases and the JavaScript API for anything more complex.

## Declarative HTML Controls

For common actions you don't need to write any JavaScript. Add the following `data-*` attributes to any HTML element and FairShare handles the rest.

**Opening and closing the cart panel:**

```html theme={null}
<button data-fluid-cart="open">Open Cart</button>
<button data-fluid-cart="close">Close Cart</button>
<button data-fluid-cart="toggle">Toggle Cart</button>
```

**Adding a product to the cart** — set `data-fluid-add-to-cart` to the variant ID:

```html theme={null}
<!-- Add one unit -->
<button data-fluid-add-to-cart="123456">Add to Cart</button>

<!-- Add a specific quantity -->
<button data-fluid-add-to-cart="123456" data-fluid-quantity="2">Add 2 to Cart</button>

<!-- Add and immediately open the cart panel -->
<button
  data-fluid-add-to-cart="123456"
  data-fluid-open-cart-after-add="true"
>
  Add &amp; View Cart
</button>

<!-- Add as a subscription -->
<button data-fluid-add-to-cart="123456" data-fluid-subscribe="true">
  Subscribe &amp; Add
</button>

<!-- Add an enrollment pack by pack ID -->
<button data-fluid-add-enrollment-pack="42">Add Enrollment Pack</button>
```

## Cart Display

Place a `<span>` with `id="fluid-cart-count"` anywhere in your markup and FairShare will keep its text content in sync with the current cart item count. The count updates automatically when items are added, removed, updated, or when the cart is cleared, created, or refreshed — no JavaScript needed.

```html theme={null}
<span id="fluid-cart-count">0</span>
```

## JavaScript Cart Methods

All cart methods live on `window.FairShareSDK`. Async methods return Promises — use `await` or `.then()` depending on your environment.

The REST-backed cart methods here call the **Fluid Public SDK API**
(`public-v2025-06`) — the surface the SDK is generated against. They do not call
the direct Checkout API that the [headless checkout
guide](/api/guides/headless-commerce) teaches. Both surfaces read and write the
same cart records, but their request shapes differ, so drive any one cart
through one surface only. See [Choosing a cart
surface](/api/choosing-a-cart-surface) if you also call REST directly.

### The operation behind each method

Each REST-backed method maps to the Public SDK API operation or operations it
calls. Follow a link for the full request and response contract.

| Method                                         | Public SDK API operation                                                                                                                                                           |
| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `createCart()`                                 | [Creates a cart](/api-reference/carts/creates-a-cart)                                                                                                                              |
| `getCart()`, `refreshCart()`, `setCartToken()` | [Retrieves a cart](/api-reference/carts/retrieves-a-cart)                                                                                                                          |
| `addCartItems()`, `updateCartItems()`          | [Adds items to cart](/api-reference/carts/adds-items-to-cart)                                                                                                                      |
| `decrementCartItem()`                          | [Adds items to cart](/api-reference/carts/adds-items-to-cart) while a unit remains, then [Removes item from cart](/api-reference/carts/removes-item-from-cart) on the last one     |
| `removeCartItemById()`                         | [Removes item from cart](/api-reference/carts/removes-item-from-cart)                                                                                                              |
| `updateCartItemVariant()`                      | [Updates a cart item's variant](/api-reference/carts/updates-a-cart-items-variant)                                                                                                 |
| `subscribeCartItem()`                          | [Subscribes a cart item](/api-reference/carts/subscribes-a-cart-item)                                                                                                              |
| `unsubscribeCartItem()`                        | [Removes the subscription from a cart item](/api-reference/carts/updates-subscribe:false-to-cart-item)                                                                             |
| `addEnrollmentPack()`                          | [Add enrollment to existing cart](/api-reference/carts/add-enrollment-to-existing-cart), preceded by [Creates a cart](/api-reference/carts/creates-a-cart) when no cart exists yet |
| `clearCart()`                                  | None — it only resets local state                                                                                                                                                  |

### Reading Cart State

```javascript theme={null}
// Fetch the current cart from the server
const cart = await window.FairShareSDK.getCart();

// Read the cart from local state without a network request
const localCart = window.FairShareSDK.getLocalCart();

// Get the total number of items in the cart
const itemCount = window.FairShareSDK.getCartItemCount();

// Fetch fresh state and notify every cart widget
const refreshedCart = await window.FairShareSDK.refreshCart();
```

`getCart()` fetches the cart. `refreshCart()` also dispatches the cart-update
event that tells mounted widgets to render the fresh state.

To adopt a cart created outside the SDK, validate and store its token:

```javascript theme={null}
const adoptedCart =
  await window.FairShareSDK.setCartToken("7Hq2Kd9Rm4bV1nX");
```

`setCartToken()` updates local state, mounted widgets, and any configured
real-time cart subscription after validation succeeds. It rejects an empty,
unavailable, or completed token. Validation and fetch failures that happen
before adoption leave the existing local cart intact. Some later failures can
reject after local state has changed, so inspect the current cart in your error
handler. Only one adoption can run at a time.

The CDN loader also recognizes a `cart_token` query parameter. After a
successful adoption, it removes that parameter with `history.replaceState`.

### Modifying the Cart

```javascript theme={null}
// Shorthand: add one variant with optional quantity and subscription options
await window.FairShareSDK.addCartItems(123, {
  quantity: 2,
  subscribe: true,
  subscription_plan_id: 642,
});

// Array form: add a configured bundle
await window.FairShareSDK.addCartItems([
  {
    variant_id: 278318,
    quantity: 1,
    bundled_items: [
      {
        variant_id: 39325,
        quantity: 1,
        product_bundle_group_id: 3301,
        subscription: true,
        subscription_plan_id: 642,
      },
    ],
  },
]);

// Decrement an item's quantity; pass options.quantity to control the decrement amount
await window.FairShareSDK.decrementCartItem(123, { quantity: 1 });

// Remove an item by its cart item ID
await window.FairShareSDK.removeCartItemById(456);

// Replace quantities for one or more items
await window.FairShareSDK.updateCartItems([
  { variant_id: 123, quantity: 3 },
]);

// Replace the variant on one cart line
await window.FairShareSDK.updateCartItemVariant({
  itemId: 456,
  variantId: 789,
});

// Clear the SDK's local cart state
await window.FairShareSDK.clearCart();

// Create a new cart session
await window.FairShareSDK.createCart();
```

The numeric shorthand defaults `quantity` to `1`. In the array form, each parent
item includes `variant_id` and `quantity`. Use `subscribe` and
`subscription_plan_id` for a parent subscription.

For a bundle, put the selected children in `bundled_items`. Each child includes
`variant_id` and `quantity`, and can include `product_bundle_group_id`,
`subscription`, and `subscription_plan_id`. The direct checkout Add Items
contract models all five child fields.

The SDK forwards nested child fields at runtime, but its current public
TypeScript declaration may omit `product_bundle_group_id`. JavaScript callers
can send it. TypeScript callers may need a local type extension until the SDK
declaration catches up. This SDK method uses the FairShare cart lifecycle — it
posts to [Adds items to cart](/api-reference/carts/adds-items-to-cart) on the
Public SDK API, not to the Add Items operation in the generated Checkout
endpoints reference.

`clearCart()` resets the local client state. It does not call a dedicated
server-side clear-cart operation.

### Subscriptions

```javascript theme={null}
// Convert an existing cart item to a subscription
await window.FairShareSDK.subscribeCartItem(itemId, subscriptionPlanId);

// Remove the subscription from a cart item (keeps the item as a one-time purchase)
await window.FairShareSDK.unsubscribeCartItem(itemId);
```

### Enrollment Packs

Enrollment packs bundle products for new rep onboarding. Add a pack by its numeric ID:

```javascript theme={null}
await window.FairShareSDK.addEnrollmentPack(42);
```

For an enrollment pack with dynamic bundles, pass the selected parent variants
and their nested items as `bundleSelections`:

```javascript theme={null}
await window.FairShareSDK.addEnrollmentPack(42, {
  bundleSelections: [
    {
      variant_id: 321,
      bundled_items: [
        {
          variant_id: 654,
          quantity: 1,
          display_to_customer: true,
          subscription: false,
        },
      ],
    },
  ],
});
```

`bundleSelections` is the SDK option name. The nested `bundled_items` array
describes the selected items within each parent variant.

### Checkout

```javascript theme={null}
// Redirect the shopper to the Fluid checkout page
await window.FairShareSDK.checkout();

// Get the checkout URL without redirecting (useful for building custom checkout buttons)
const checkoutUrl = window.FairShareSDK.getCheckoutUrl();
```

`getCheckoutUrl()` returns `undefined` until a cart token exists.

To replace the default checkout behavior, register a handler:

```javascript theme={null}
window.FairShareSDK.setOnCheckout(() => {
  window.location.assign("/custom-checkout");
});

const checkoutHandler = window.FairShareSDK.getOnCheckout();
```

### Cart Control

You can open, close, and toggle the cart panel from JavaScript in addition to the declarative HTML attributes described above:

```javascript theme={null}
window.FairShareSDK.cart.control.open();
window.FairShareSDK.cart.control.close();
window.FairShareSDK.cart.control.toggle();
```

<Note>
  The legacy `window.fluidCart` namespace is also supported for backwards compatibility:

  ```javascript theme={null}
  window.fluidCart.open();
  window.fluidCart.close();
  window.fluidCart.toggle();
  ```

  Prefer `window.FairShareSDK.cart.control` for new integrations.
</Note>

## Cart Settings

Cart settings let you override the default widget appearance and position on a per-page basis. Settings are **page-scoped** — they apply to the current URL path and are stored separately for each path, excluding query parameters and URL fragments. This means you can display the cart widget in the bottom-right corner on your homepage while hiding it entirely on a custom checkout page.

**Setting cart options:**

```javascript theme={null}
window.FairShareSDK.cart.settings.set({
  hideWidget: true,        // Hide the floating cart button
  position: "top_left",   // bottom_right | bottom_left | top_right | top_left
  size: 80,               // Button diameter in pixels
  placement: "left",      // Sidebar placement: left or right
  primaryColor: "#ff6b35",
  secondaryColor: "#2d3748",
  xMargin: 20,            // Horizontal margin from screen edge (px)
  yMargin: 50,            // Vertical margin from screen edge (px)
});
```

**Reading the current settings:**

```javascript theme={null}
const cartSettings = window.FairShareSDK.cart.settings.get();
```

**Clearing overrides** (reverts to the defaults set on the `<fluid-cart-widget>` element):

```javascript theme={null}
window.FairShareSDK.cart.settings.clear();
```

## Shop Settings

Read and update shop-level configuration, including locale and language preferences.

```javascript theme={null}
// Fetch settings from the server and cache them
await window.FairShareSDK.fetchSettings();

// Return cached settings without a network request
const settings = window.FairShareSDK.getSettings();

// Return cached settings if available, otherwise fetch from the server
const settings = await window.FairShareSDK.getOrFetchSettings();

// Update locale settings for the current session
await window.FairShareSDK.updateLocaleSettings({ language: "en", country: "US" });

// Get the active country code
const country = window.FairShareSDK.getCountryCode();

// Get the active language code
const language = window.FairShareSDK.getLanguage();
```

## Cart operation events

These six methods emit a consistent success or error event on `window`:

* `addCartItems()`
* `addEnrollmentPack()`
* `updateCartItems()`
* `decrementCartItem()`
* `removeCartItemById()`
* `updateCartItemVariant()`

Listen once to react to these operations across custom controls and FairShare
widgets:

```javascript theme={null}
window.addEventListener("CART_OPERATION_SUCCESS", (event) => {
  console.log(event.detail.operation, "succeeded");
});

window.addEventListener("CART_OPERATION_ERROR", (event) => {
  console.error(event.detail.operation, event.detail.message);
});
```

Every detail includes `operation`, the `add` / `update` / `remove` category,
the per-call toast preference, identifying IDs when available, and an ISO
timestamp. A success can include the updated `cart`. An error includes the raw
thrown `error` and a human-readable `message`.

When an error reaches the public operation wrapper, all six methods emit
`CART_OPERATION_ERROR`. `addCartItems()` and `decrementCartItem()` then resolve
`undefined` to preserve their historical contract. The other four methods
rethrow the error. A no-op result from `addCartItems()`, `addEnrollmentPack()`,
`decrementCartItem()`, or `updateCartItemVariant()` emits no success event.
`updateCartItems()` emits success when its void operation completes.

## Analytics

Fire events and inspect attribution state directly from your JavaScript code.

```javascript theme={null}
// Fire an event into the Fluid attribution pipeline. `eventName` accepts exactly
// one value, "CHECKOUT_STARTED"; any other name never reaches Fluid and raises
// no error. Returns nothing — do not await it.
window.FairShareSDK.trackFairshareEvent({
  eventName: "CHECKOUT_STARTED",
  data: { cart_token: "7Hq2Kd9Rm4bV1nX" },
});

// Track that a checkout flow has started
window.FairShareSDK.trackCheckoutStarted({ cart_token: "7Hq2Kd9Rm4bV1nX" });

// Get the resolved attribution record for the current session
const attribution = window.FairShareSDK.getAttribution();

// Get the current session token for cross-system correlation
const sessionToken = window.FairShareSDK.getSessionToken();

// Force all queued events to be sent immediately (e.g., before page unload)
await window.FairShareSDK.flushEvents();

// Flush buffered events using the Beacon API (safe to call during page unload)
window.FairShareSDK.flushEventsWithBeacon();
```

## Lead Capture

Capture a prospect's contact information and send it to Fluid without requiring the lead capture widget. This is useful when you're building a custom form or capturing leads as part of another flow.

```javascript theme={null}
await window.FairShareSDK.captureLead({
  message: "I'm interested in the starter kit",
  contact: {
    name: "Dana Whitfield",
    email: "dana.whitfield@example.com",
  },
});
```

The prospect's details go inside `contact` — `name`, `email`, and `phone`. Keys outside that shape are dropped silently, so a flat payload submits an empty lead and still resolves successfully. Every field is optional, but send at least one of `email` or `phone` so the lead is reachable. The lead is attributed to the same rep resolved at SDK initialization.
