Skip to main content
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:
Adding a product to the cart — set data-fluid-add-to-cart to the variant ID:
Adding several items, subscriptions, and bundles:
data-fluid-subscription-plan-id takes a single plan ID. data-fluid-bundled-items and data-fluid-bundle-selections take JSON; the SDK logs invalid JSON to the console and adds the item without it. Attribute names are case-sensitive kebab-case: data-fluid-addToCart does nothing.

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.

Real-time cart sync

Real-time cart updates arrive over Action Cable, Fluid’s WebSocket transport. The SDK applies each update to local cart state and notifies mounted cart widgets. Your existing cart methods stay the same. The loader on every Fluid storefront always sets data-realtime-enabled="true", so you don’t turn it on in a theme. If you install the SDK by hand outside a Fluid theme, add the attribute yourself. See Enable real-time cart updates.

Carts that fill in the background

Every Fluid storefront creates carts in the background. The first add on a new cart creates the cart, and the server fills it in. The cart’s population_status moves from pending to complete, or to failed if the items cannot be added. The fill usually takes a few hundred milliseconds to about 2 seconds. The cart methods wait for the fill, so you rarely handle pending yourself: CART_OPERATION_SUCCESS carries the filled cart too. When a fill fails, the add resolves undefined, no success event fires, and the SDK emits CART_POPULATION_FAILED with the reason. Use whenCartSettled() when your code needs the items and does not hold the value an add resolved with. It takes an optional timeoutMs, which defaults to 10 seconds. It resolves with the filled cart, a failed cart (population_status: "failed"), or a cart that is still pending when the wait ends. It resolves null when there is no cart, and it never rejects.
Never call createCart() to read data such as the shopper’s country. It creates a new empty cart and replaces the stored cart token, so the shopper loses the cart they had. Read the country and language with getCountryCode() and getLanguage(), and read the current cart with getLocalCart().
The cart drawer does not wait for the fill. It opens at the click and draws the new line at once. A theme with its own cart sidebar, or its own add button, has more to do. See Build a custom cart drawer.

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

Reading Cart State

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:
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

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

Enrollment Packs

Enrollment packs bundle products for new rep onboarding. Add a pack by its numeric ID:
For an enrollment pack with dynamic bundles, pass the selected parent variants and their nested items as bundleSelections:
bundleSelections is the SDK option name. The nested bundled_items array describes the selected items within each parent variant.

Checkout

getCheckoutUrl() returns undefined until a cart token exists. To replace the default checkout behavior, register a handler:

Cart Control

You can open, close, and toggle the cart panel from JavaScript in addition to the declarative HTML attributes described above:
The legacy window.fluidCart namespace is also supported for backwards compatibility:
Prefer window.FairShareSDK.cart.control for new integrations.

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:
Reading the current settings:
Clearing overrides (reverts to the defaults set on the <fluid-cart-widget> element):

Shop Settings

Read and update shop-level configuration, including locale and language preferences.
For a complete Liquid and JavaScript implementation, see navbar locale selector.

Cart state events

The SDK listens for cart_update messages over Action Cable when real-time sync is on. It is always on in a Fluid storefront, and you set it only on a hand-installed tag. After applying a received cart, it emits a CustomEvent named UPDATE_CART_ITEM on window. Built-in cart widgets already listen for this event; add a listener when you build your own cart display. The WebSocket message name cart_update is not a browser event name. Listen for UPDATE_CART_ITEM on window to react to the applied update. Other WebSocket message types are ignored by the SDK’s cart-sync subscription. These browser events also help you keep custom cart displays in sync with local SDK actions: CART_ITEMS_ADDING and CART_ITEMS_SETTLED bracket every add of items, bundles and enrollment packs, and each pair shares an operationId. The detail of CART_ITEMS_ADDING holds operationId, cartToken (null on the add that creates the cart), lines, and enrollment when the add claims an enrollment pack. The detail of CART_ITEMS_SETTLED holds operationId, outcome ("success" or "error"), cartToken, and the cart the add resolved with, when there is one. That cart can still be filling. Code that needs the final items should use the value the add resolves with, whenCartSettled(), or onCartChange(). See Build a custom cart drawer. State events can describe optimistic changes. Use cart operation events when you need a mutation’s success or failure rather than a display update. A received real-time update does not by itself emit CART_OPERATION_SUCCESS or CART_OPERATION_ERROR.
The example assumes your page contains an element with id="cart-summary-count". You can also use the built-in fluid-cart-count element described under cart display. State-event details can include cart, handledByWidget, and widgetId. SDK-dispatched cart events also include a unique eventId and an ISO timestamp. Treat widgetId as a producer identifier, not as a transport selector: Action Cable updates retain the historical widgetId: "pusher" value. Use eventId if your integration needs to deduplicate the same dispatch. For loading indicators around widget actions, listen for CART_LOADING_START and CART_LOADING_END on window. These are widget loading signals, not a success or failure result for every SDK method.

Cart operation events

These seven methods emit a consistent success or error event on window:
  • addCartItems()
  • addEnrollmentPack()
  • setEnrollment()
  • updateCartItems()
  • decrementCartItem()
  • removeCartItemById()
  • updateCartItemVariant()
Listen once to react to these operations across custom controls and FairShare widgets:
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. For addCartItems(), addEnrollmentPack() and setEnrollment(), that is the filled cart. An error includes the raw thrown error and a human-readable message. When an error reaches the public operation wrapper, all seven methods emit CART_OPERATION_ERROR. addCartItems() and decrementCartItem() then resolve undefined to preserve their historical contract. The other five methods rethrow the error. A no-op result from addCartItems(), addEnrollmentPack(), setEnrollment(), decrementCartItem(), or updateCartItemVariant() emits no success event. So does a fill that fails. updateCartItems() emits success when its void operation completes.

Cart population failures

When the server cannot fill a new cart, the cart stays empty. For example, none of the items may be sold in the shopper’s country. The call that created the cart resolves undefined, and no CART_OPERATION_SUCCESS fires. The SDK emits CART_POPULATION_FAILED on window for the cart it currently holds:
The example assumes your page contains an element with id="cart-notice". The event relies on real-time sync, which is always on in a Fluid storefront. The SDK leaves the empty cart in place, so the shopper can add to it again. A failure for a cart the SDK has since cleared or replaced is ignored. When the built-in toast shows errors, it also shows this event. It uses apiMessage when present and the error message otherwise. Your error message override replaces both. See cart feedback.

Analytics

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

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