Cart JS SDK

Make cart operations and listen to events. Used in Duda's native ecommerce, paid booking, membership, and more.

The Public Ecom SDK is a stable JavaScript API for cart, checkout, orders, and payments. It is exposed on the page as window.dmAPI.ecomm and is intended for third-party scripts and integrations. The window.dmAPI.ecomm namespace is only defined when the cart is installed on the site; otherwise it is undefined.

Relevant features

Use this SDK to work with the cart and checkout on sites using:

  • Duda's Native Store
  • Duda's Bookings with paid appointment types
  • Duda's Membership with paid plans

Accessing the SDK

The SDK is available globally after the cart loads:

// Wait for the SDK to be ready (e.g. after app boot)
await window.dmAPI.ecomm.ready;

// Use the SDK — async methods resolve to a [result, error] tuple
const [cart, error] = await window.dmAPI.ecomm.getCart({ cart_id: '...' });
  • window.dmAPI.ecomm — Public API instance. Available as soon as the loader runs; use ready to wait until the app has finished initializing.
  • ready — A Promise<void> that resolves when the SDK is fully initialized and methods can be called.

Availability: The window.dmAPI.ecomm namespace is only defined when the one of the relevant features is installed on the site. If ecom is not installed, window.dmAPI.ecomm will be undefined. Check for its presence before calling the API (e.g. if (window.dmAPI?.ecomm) { ... }).

Result tuples: Async methods do not throw. Instead they resolve to a [result, error] tuple: on success [result, undefined], on failure [undefined, error] where error is an EcomSDKError. Destructure and check error before using the result. The synchronous helpers (openCart, closeCart, clearCart, formatMoney, login) return their value directly and never produce a tuple. See Error handling for details. — note that formatMoney and login validate their input and throw InvalidPayloadSDKError if it is malformed. One async method, clearCart, is not tuple-wrapped: it returns a Promise<void> that rejects on failure. See Error handling for details.

Catalog data

Some methods require passing IDs from the store catalog.

These can be retrieved using the Store JS API.


Usage example

The following example waits for the SDK, adds a product to the cart, applies a discount, sets contact information, formats a price, and subscribes to cart updates. Async methods resolve to a [result, error] tuple — check error before using the result. All IDs and values are fake and for illustration only.

(async function () {
  await window.dmAPI.ecomm.ready;
  const sdk = window.dmAPI.ecomm;

  // Subscribe to cart updates (e.g. for analytics or UI sync)
  window.dmAPI.subscribeEvent('event-ecomm-cartUpdated', (event) => {
    // sync a custom cart badge, trigger analytics, etc.
  });

  // Open the cart UI so the customer sees it (synchronous, never throws)
  sdk.openCart();

  // Add a product to the cart
  const [, addError] = await sdk.addProduct({
    product_id: 'prod_tshirt_001',
    variation_id: 'var_tshirt_001_blue_m',
    quantity: 2,
  });
  if (addError) {
    // handle the failure (show a toast, abort the flow, etc.)
    return;
  }

  // Apply a discount code
  const [, discountError] = await sdk.addDiscount({ code: 'WELCOME10' });
  if (discountError) {
    // the code may be invalid or expired
  }

  // Set contact information
  await sdk.setContactInformation({
    email: '[email protected]',
    marketing_opt_in: true,
  });

  // Format a price for display (synchronous; uses the cart currency and locale by default)
  const formatted = sdk.formatMoney({ amount: 2999 });

  // Fetch the current cart
  const [cart, cartError] = await sdk.getCart({ cart_id: 'cart_abc123' });
  if (cartError) {
    // handle missing or inaccessible cart
  }

  // Fetch the logged-in customer's orders
  const [orders, ordersError] = await sdk.getOrders({ limit: 5, offset: 0 });
  if (ordersError) {
    // handle the failure (e.g. not authenticated)
  }
})();

Same flow with a one-off product purchase (buy now, no cart UI):

await window.dmAPI.ecomm.ready;
const sdk = window.dmAPI.ecomm;

const [, error] = await sdk.buyProduct({
  product_id: 'prod_ebook_001',
  variation_id: 'var_ebook_001_default',
  quantity: 1,
});
if (error) {
  // handle the failure
}
// On success, the cart is created automatically; complete checkout via the cart UI.

Reference

Cart UI

openCart()

Opens the cart UI (drawer or panel).

Returns: void

Example:

window.dmAPI.ecomm.openCart();

closeCart()

Closes the cart UI.

Returns: void

Example:

window.dmAPI.ecomm.closeCart();

Cart lifecycle

cart

The current cart, as a CartResponseDto — the same shape the cart methods return. This is a property, not a method: reading it costs nothing and performs no request, so you don't need to await it or handle an error tuple.

Type: CartResponseDto | nullnull when the visitor has no cart yet, or after clearCart().

Example:

await window.dmAPI.ecomm.ready;

const cart = window.dmAPI.ecomm.cart;
if (cart) {
  console.log(cart.id, cart.total, cart.items.length);
}

It reflects the latest cart the store received, so re-read it after any cart operation rather than holding on to an old value:

const [, error] = await window.dmAPI.ecomm.addProduct({
  product_id: 'prod_tshirt_001',
  variation_id: 'var_tshirt_001_blue_m',
});
if (!error) {
  console.log(window.dmAPI.ecomm.cart.items.length); // includes the new item
}

You can also keep it in sync by re-reading it inside an event handler:

window.dmAPI.subscribeEvent('event-ecomm-cartUpdated', () => {
  render(window.dmAPI.ecomm.cart);
});

Freshness: cart is updated by the cart operations performed on this page — it is not polled, so it will not pick up changes made elsewhere (another tab, another device, or server-side expiry).

getCart fetches from the server, but it never updates cart: the fresh data is returned in the [cart, error] tuple and nowhere else. Use the returned value directly.

const id = window.dmAPI.ecomm.cart?.id;
const [freshCart, error] = await window.dmAPI.ecomm.getCart({ cart_id: id });

if (!error) {
  render(freshCart); // use the returned cart...
  // ...not window.dmAPI.ecomm.cart, which is still the pre-fetch value
}

Treat it as read-only: the object is detached from the store's internal state, so modifying it will not change the actual cart — but every reader gets the same object, so a mutation is visible to other scripts on the page until the next cart update replaces it. Use the SDK methods to change the cart, and copy the object first if you need to transform it.


createCart(payload?)

Creates a new cart. If no cart exists, one is created automatically when needed; use this when you want to prefill email, addresses, metadata, or items.

ParameterTypeRequiredDescription
emailstringNoCustomer email.
shipping_addressPersonalAddressRequestDtoNoPrefilled shipping address.
billing_addressPersonalAddressRequestDtoNoPrefilled billing address.
metadataobjectNoCustom metadata.
itemsAddItemRequestDto[]NoInitial line items.
timezonestringNoCustomer timezone (defaults to browser).

Returns: Promise<[CreateCartResponse, undefined] | [undefined, EcomSDKError]>[cart, undefined] on success (e.g. CartResponseDto); [undefined, error] on failure.

Example:

const [cart, error] = await window.dmAPI.ecomm.createCart({
  email: '[email protected]',
  metadata: { source: 'landing_page' },
});
if (error) {
  // handle the failure
}

getCart(payload)

Fetches a cart from the server by ID.

To read the current cart, use the cart property instead — it is already available and costs no request. Reach for getCart when you need to read a different cart (for example a cart ID from an abandoned-cart link), or to force a fresh read of a cart that may have changed outside this page.

ParameterTypeRequiredDescription
cart_idstringYesCart ID.

Returns: Promise<[GetCartResponse, undefined] | [undefined, EcomSDKError]>[cart, undefined] on success; [undefined, error] on failure.

cart_id is required; calling getCart() with no argument throws InvalidPayloadSDKError. The current cart's ID is available as window.dmAPI.ecomm.cart?.id.

Example:

const [cart, error] = await window.dmAPI.ecomm.getCart({
  cart_id: 'cart_abc123',
});
if (error) {
  // handle missing or inaccessible cart
}

getCart is a pure read. It does not make the fetched cart current, and it does not update the cart property — even when you pass the current cart's ID. The fetched cart is returned in the tuple and nowhere else, so read it from there:

const [freshCart, error] = await window.dmAPI.ecomm.getCart({
  cart_id: window.dmAPI.ecomm.cart.id,
});

// freshCart          → what the server has now
// dmAPI.ecomm.cart   → unchanged by this call

clearCart()

Clears the current cart (removes all items and resets cart state).

Returns: Promise<void> — resolves once the cart has been cleared.

Example:

await window.dmAPI.ecomm.clearCart();

Cart items

addProduct(payload)

Adds a product (catalog item) to the current cart.

ParameterTypeRequiredDescription
product_idstringYesProduct identifier.
variation_idstringYesVariation identifier.
quantitynumberNoQuantity (default 1).
metadataobjectNoItem metadata.
product_customizationsProductCustomizationPayload[]NoOptions/customizations.

Returns: Promise<[AddProductResponse, undefined] | [undefined, EcomSDKError]>[updatedCart, undefined] on success; [undefined, error] on failure.

Example:

const [cart, error] = await window.dmAPI.ecomm.addProduct({
  product_id: 'prod_tshirt_001',
  variation_id: 'var_tshirt_blue_m',
  quantity: 2,
});
if (error) {
  // handle the failure
}

buyProduct(payload)

Adds a product to the cart in a “buy now” flow (e.g. from product page). Similar to addProduct with store catalog source.

ParameterTypeRequiredDescription
product_idstringYesProduct identifier.
variation_idstringYesVariation identifier.
plan_idstringNoSubscription plan ID if applicable.
quantitynumberNoQuantity.
metadataobjectNoItem metadata.
product_customizationsProductCustomizationPayload[]NoCustomizations.
cart_optionsCreateCartPayloadNoOptions used to prefill the cart that is auto-created for the purchase (email, addresses, metadata, timezone, items). Same shape as createCart.

Returns: Promise<[BuyProductResponse, undefined] | [undefined, EcomSDKError]>[updatedCart, undefined] on success; [undefined, error] on failure.

Example:

const [cart, error] = await window.dmAPI.ecomm.buyProduct({
  product_id: 'prod_ebook_001',
  variation_id: 'var_ebook_default',
  quantity: 1,
});
if (error) {
  // handle the failure
}

Prefilling the cart with cart_options

The "buy now" methods (buyProduct, buyMembership, buyBooking) create and use a cart automatically. Pass cart_options to seed that cart in the same call — it accepts the same fields as createCart (email, shipping_address, billing_address, metadata, items, timezone). This avoids a separate createCart round-trip when you already know the customer's details.

// Buy now and prefill the auto-created cart with the customer's email,
// a shipping address, and order metadata in a single call.
const [cart, error] = await window.dmAPI.ecomm.buyProduct({
  product_id: 'prod_ebook_001',
  variation_id: 'var_ebook_default',
  quantity: 1,
  cart_options: {
    email: '[email protected]',
    metadata: { source: 'product_page' },
    shipping_address: {
      full_name: 'Jane Doe',
      address_1: '123 Main St',
      city: 'Boston',
      region: 'MA',
      country: 'US',
      postal_code: '02101',
    },
  },
});
if (error) {
  // handle the failure
}

If a cart already exists, cart_options overwrites its matching details (same behavior as calling createCart directly).


updateItemQuantity(payload)

Updates the quantity of a cart line item.

ParameterTypeRequiredDescription
idstringYesLine item ID.
quantitynumberYesNew quantity.

Returns: Promise<[UpdateItemQuantityResponse, undefined] | [undefined, EcomSDKError]>[updatedCart, undefined] on success; [undefined, error] on failure.

Example:

const [cart, error] = await window.dmAPI.ecomm.updateItemQuantity({
  id: 'item_xyz789',
  quantity: 3,
});
if (error) {
  // handle the failure
}

removeItem(payload)

Removes a line item from the cart.

ParameterTypeRequiredDescription
idstringYesLine item ID.

Returns: Promise<[RemoveItemResponse, undefined] | [undefined, EcomSDKError]>[updatedCart, undefined] on success; [undefined, error] on failure.

Example:

const [cart, error] = await window.dmAPI.ecomm.removeItem({
  id: 'item_xyz789',
});
if (error) {
  // handle the failure
}

buyMembership(payload)

Adds a membership (subscription plan) to the cart.

ParameterTypeRequiredDescription
plan_idstringYesMembership plan ID.
metadataobjectNoOptional metadata.
cart_optionsCreateCartPayloadNoOptions used to prefill the cart that is auto-created for the purchase (email, addresses, metadata, timezone, items). Same shape as createCart.

Returns: Promise<[BuyMembershipResponse, undefined] | [undefined, EcomSDKError]>[updatedCart, undefined] on success; [undefined, error] on failure.

Example:

const [cart, error] = await window.dmAPI.ecomm.buyMembership({
  plan_id: 'plan_premium_annual',
});
if (error) {
  // handle the failure
}

buyBooking(payload)

Adds a booking to the cart.

ParameterTypeRequiredDescription
event_namestringYesEvent name.
event_type_idnumberYesEvent type ID.
slot_startstringYesSlot start time.
slot_durationnumberNoDuration.
time_zonestringYesTimezone.
metadataobjectNoOptional metadata.
fields_responsesRecord<string, string>NoForm/field responses.
customer_emailstringNoCustomer email.
customer_namestringNoCustomer name.
hosts_idsnumber[]NoHost IDs.
cart_optionsCreateCartPayloadNoOptions used to prefill the cart that is auto-created for the booking (email, addresses, metadata, timezone, items). Same shape as createCart. Note: customer_email takes precedence over cart_options.email.

Returns: Promise<[BuyBookingResponse, undefined] | [undefined, EcomSDKError]>[updatedCart, undefined] on success; [undefined, error] on failure.

Example:

const [cart, error] = await window.dmAPI.ecomm.buyBooking({
  event_name: 'Yoga Workshop',
  event_type_id: 1,
  slot_start: '2025-06-15T10:00:00',
  time_zone: 'America/New_York',
  customer_email: '[email protected]',
});
if (error) {
  // handle the failure
}

Discounts

addDiscount(payload)

Applies a discount coupon code to the cart.

ParameterTypeRequiredDescription
codestringYesDiscount (coupon) code.
force_applybooleanNoForce apply even if validation is strict.

Returns: Promise<[AddDiscountResponse, undefined] | [undefined, EcomSDKError]>[updatedCart, undefined] on success; [undefined, error] on failure (e.g. invalid or expired code).

Example:

const [cart, error] = await window.dmAPI.ecomm.addDiscount({ code: 'SAVE20' });
if (error) {
  // the code may be invalid or expired
}

removeDiscount(payload)

Removes an applied discount from the cart.

ParameterTypeRequiredDescription
idstringYesDiscount (application) ID.

Returns: Promise<[RemoveDiscountResponse, undefined] | [undefined, EcomSDKError]>[updatedCart, undefined] on success; [undefined, error] on failure.

Example:

const [cart, error] = await window.dmAPI.ecomm.removeDiscount({
  id: 'disc_abc123',
});
if (error) {
  // handle the failure
}

Checkout steps

setContactInformation(payload)

Sets the contact step (email, marketing opt-in, custom fields).

ParameterTypeRequiredDescription
emailstringYesCustomer email.
marketing_opt_inbooleanNoMarketing consent.
custom_fields`Record<string, stringnull>`NoCustom field values.

Returns: Promise<[SetContactInformationResponse, undefined] | [undefined, EcomSDKError]>[updatedCart, undefined] on success; [undefined, error] on failure.

Example:

const [cart, error] = await window.dmAPI.ecomm.setContactInformation({
  email: '[email protected]',
  marketing_opt_in: true,
});
if (error) {
  // handle the failure
}

setShippingAddress(payload)

Sets the shipping address and whether it is also used for billing.

ParameterTypeRequiredDescription
shipping_addressPersonalAddressRequestDtoYesShipping address.
use_shipping_address_as_billing_addressbooleanYesUse same address for billing.
custom_fields`Record<string, stringnull>`NoCustom fields.

Returns: Promise<[SetShippingAddressResponse, undefined] | [undefined, EcomSDKError]>[updatedCart, undefined] on success; [undefined, error] on failure.

Example:

const [cart, error] = await window.dmAPI.ecomm.setShippingAddress({
  shipping_address: {
    full_name: 'Jane Doe',
    address_1: '123 Main St',
    city: 'Boston',
    region: 'MA',
    country: 'US',
    postal_code: '02101',
  },
  use_shipping_address_as_billing_address: true,
});
if (error) {
  // handle the failure
}

setFulfillmentMethod(payload)

Sets the fulfillment method (shipping, pickup, etc.).

ParameterTypeRequiredDescription
shipping_instructionsstringNoShipping notes.
shipping_courier_idstringNoRequired for shipping.
shipping_localized_namestringNoDisplay name for shipping.
pickup_location_idstringNoRequired for pickup.
custom_fields`Record<string, stringnull>`NoCustom fields.

Returns: Promise<[SetFulfillmentMethodResponse, undefined] | [undefined, EcomSDKError]>[updatedCart, undefined] on success; [undefined, error] on failure.

Example:

const [cart, error] = await window.dmAPI.ecomm.setFulfillmentMethod({
  shipping_instructions: 'Leave at front door',
  shipping_courier_id: 'courier_standard',
});
if (error) {
  // handle the failure
}

setBillingAddress(payload)

Sets the billing address.

ParameterTypeRequiredDescription
billing_addressPersonalAddressRequestDtoYesBilling address.
custom_fields`Record<string, stringnull>`NoCustom fields.

Returns: Promise<[SetBillingAddressResponse, undefined] | [undefined, EcomSDKError]>[updatedCart, undefined] on success; [undefined, error] on failure.

Example:

const [cart, error] = await window.dmAPI.ecomm.setBillingAddress({
  billing_address: {
    full_name: 'Jane Doe',
    address_1: '123 Main St',
    city: 'Boston',
    region: 'MA',
    country: 'US',
    postal_code: '02101',
  },
});
if (error) {
  // handle the failure
}


setMetadata(payload, cartId?)

Sets or clears cart-level metadata.

ParameterTypeRequiredDescription
metadata`objectnull`NoKey-value metadata; null to clear.
cartIdstringNoCart ID (second argument; defaults to current cart).

Returns: Promise<[SetMetadataResponse, undefined] | [undefined, EcomSDKError]>[updatedCart, undefined] on success; [undefined, error] on failure.

Example:

const [cart, error] = await window.dmAPI.ecomm.setMetadata({
  metadata: { order_ref: 'REF-12345' },
});
if (error) {
  // handle the failure
}

Orders

getOrder(payload)

Fetches a single order by ID.

ParameterTypeRequiredDescription
order_idstringYesOrder ID.

Returns: Promise<[GetOrderResponse, undefined] | [undefined, EcomSDKError]>[order, undefined] on success (OrderResponseDto); [undefined, error] on failure.

Example:

const [order, error] = await window.dmAPI.ecomm.getOrder({
  order_id: 'ord_abc123',
});
if (error) {
  // handle the failure
}

getOrders(payload?)

Fetches the current customer’s orders with optional pagination and sort order.

ParameterTypeRequiredDescription
offsetnumberNoPagination offset.
limitnumberNoPage size.
direction`'asc''desc'`NoSort direction.

Returns: Promise<[GetOrdersResponse, undefined] | [undefined, EcomSDKError]>[orders, undefined] on success (OrdersResponseDto); [undefined, error] on failure.

Example:

const [orders, error] = await window.dmAPI.ecomm.getOrders({
  limit: 10,
  offset: 0,
  direction: 'desc',
});
if (error) {
  // handle the failure
}

Subscriptions & customer

getSubscriptions(payload)

Fetches the current customer’s subscriptions with pagination.

ParameterTypeRequiredDescription
limitnumberYesPage size.
offsetnumberYesPagination offset.

Returns: Promise<[GetSubscriptionsResponse, undefined] | [undefined, EcomSDKError]>[subscriptions, undefined] on success; [undefined, error] on failure.

Example:

const [subscriptions, error] = await window.dmAPI.ecomm.getSubscriptions({
  limit: 10,
  offset: 0,
});
if (error) {
  // handle the failure
}

getSubscription(payload)

Fetches a single subscription by ID (must belong to the current customer).

ParameterTypeRequiredDescription
subscription_idstringYesSubscription ID.

Returns: Promise<[GetSubscriptionResponse, undefined] | [undefined, EcomSDKError]>[subscription, undefined] on success; [undefined, error] on failure.

Example:

const [subscription, error] = await window.dmAPI.ecomm.getSubscription({
  subscription_id: 'sub_abc123',
});
if (error) {
  // handle the failure
}

requestSubscriptionCancellation(payload)

Requests cancellation for a subscription.

ParameterTypeRequiredDescription
subscription_idstringYesSubscription ID.

Returns: Promise<[RequestSubscriptionCancellationResponse, undefined] | [undefined, EcomSDKError]>[updatedSubscription, undefined] on success; [undefined, error] on failure.

Example:

const [subscription, error] =
  await window.dmAPI.ecomm.requestSubscriptionCancellation({
    subscription_id: 'sub_abc123',
  });
if (error) {
  // handle the failure
}

updateCustomer(payload)

Updates the logged-in customer profile (PATCH /customer/me). Requires an authenticated session.

ParameterTypeRequiredDescription
fullnamestringNoFull name.
marketing_opt_inbooleanNoMarketing consent.
languagestringNoLanguage code.
phonestringNoPhone number.
shipping_addressPersonalAddressRequestDtoNoShipping address fields.

Returns: Promise<[UpdateCustomerResponse, undefined] | [undefined, EcomSDKError]>[updatedCustomer, undefined] on success (CustomerResponseDto); [undefined, error] on failure.

Example:

const [customer, error] = await window.dmAPI.ecomm.updateCustomer({
  fullname: 'Jane Doe',
  phone: '+15551234567',
});
if (error) {
  // handle the failure
}

Utilities

formatMoney(payload)

Formats a number as a money string using the store’s currency and locale (or overrides).

ParameterTypeRequiredDescription
amountnumberYesAmount to format (e.g. cents).
overrideobjectNoOverride currency, locale, or custom format.
override.currencystringNoCurrency code.
override.localestringNoLocale for formatting.
override.customFormatCurrencyCustomFormatNoCustom format options.

Returns: string — Formatted money string (e.g. "$10.00").

Example (default behavior): uses the cart/store currency and locale settings.

window.dmAPI.ecomm.formatMoney({
  amount: 1999,
});

Example (override currency/locale/custom format):

window.dmAPI.ecomm.formatMoney({
  amount: 1999,
  override: {
    currency: 'USD',
    locale: 'en-US',
    customFormat: {
      groupSeparator: ',',
      decimalSeparator: '.',
      keepTrailingZeroesDecimals: true,
      symbol: '$',
      symbolPlacement: 'BEFORE_PRICE',
    },
  },
});

Events

window.dmAPI.subscribeEvent(eventName, handler)

Subscribes to cart lifecycle events via the DM API event bus. This is the supported way to listen for ecom events.

ParameterTypeRequiredDescription
eventNamestringYesOne of the event names below.
handler(event) => voidYesCallback invoked when the event is published. The event shape depends on the event (e.g. { type, cart } for cart events).

Event names:

EventDescription
event-ecomm-cartCreatedA new cart was created.
event-ecomm-cartUpdatedCart was updated (items, address, etc.).
event-ecomm-cartCompletedCart was completed (order placed).
event-ecomm-cartClearedCart was cleared.

Example:

window.dmAPI.subscribeEvent('event-ecomm-cartUpdated', (event) => {
  // Handle cart update
});

Authentication

login(payload)

Redirects the user to the login page. After sign-in, the user is redirected back; you can pass a return URL and query params.

ParameterTypeRequiredDescription
returnUrlstringNoURL to return to after login (defaults to current page).
returnUrlParamsRecord<string, string>NoQuery parameters to add to the return URL.

Returns: void (redirects the browser).

Example:

window.dmAPI.ecomm.login({
  returnUrl: '/account',
  returnUrlParams: { tab: 'orders' },
});

Payload types

Several method payloads reference named object types instead of inlining their fields (for example, product_customizations on addProduct is a ProductCustomizationPayload[]). This section defines each of those types, what it is used for, and — where the shape has nuance — how to build a valid value.

Types shown as TypeScript are exactly as validated by the SDK before a request is sent; a payload that fails this validation throws InvalidPayloadSDKError (see Error handling). Field types not covered here (string, number, boolean, object, Record<string, string | null>) are primitives or self-explanatory maps and are documented inline in each method's parameter table.

CartResponseDto

The cart. This is what every cart method resolves to — createCart, getCart, addProduct, addDiscount, the checkout step setters, and so on.

FieldTypeDescription
idstringCart ID. Pass this to getCart.
mode`'LIVE''TEST'`Whether the cart belongs to a live or test store.
status`'IN_PROGRESS''ABANDONED'`Server-side cart status. A completed cart becomes an order — see getOrder.
summaryPurchaseSummaryResponseDtoTotals breakdown (subtotal, discounts, shipping, fees, taxes). Prefer this over the legacy fields.
language`stringnull`Cart language.
email`stringnull`Customer email, once the contact step is filled.
currencystringCurrency code. Pass to formatMoney to render amounts.
itemsCartLineItemResponseDto[]Line items. Not a quantity count — see the note below.
billing_address`PersonalAddressResponseDtonull`Billing address.
shipping_address`PersonalAddressResponseDtonull`Shipping address.
shipping_method`CartShippingMethodResponseDtonull`The selected shipping method.
shipping_instructions`stringnull`Free-text delivery instructions.
pickup`PickupLocationResponseDtonull`The selected pickup location, when fulfilling by pickup.
discountsDiscountResponseDto[]Applied discounts.
taxesCartTaxResponseDto[]Calculated taxes.
subtotalnumberLegacy subtotal. Prefer summary.subtotal_amount.
totalnumberCart total.
createdstringWhen the cart was created.
updatedstringWhen the cart last changed.
user_agent`stringnull`User agent recorded on the cart.
ip_address`stringnull`IP address recorded on the cart.
metadata`objectnull`Whatever you stored with setMetadata.
tax_provider`'BUILT_IN''AVALARA''UNKNOWN'null`Which provider calculated the taxes.
available_shipping_rates`{rates: ShippingRateResponseDto[]}null`Rates to offer for the current address. Pass a rate id to setFulfillmentMethod.
available_pickup_locationsPickupLocationResponseDto[]Pickup locations to offer.
tax_mode`'TAXES_EXCLUDED_FROM_PRICE''TAX_INCLUDED_WITH_NET_PRICE''TAX_INCLUDED_WITH_GROSS_PRICE'`Whether displayed prices already include tax.
custom_fieldsCartCustomFieldResponseDto[] (optional)Checkout custom fields and their current values.
accepts_marketingbooleanWhether the customer opted into marketing.
payment`CartPaymentResponseDtonull`Payment methods and payment session state.
side_effects`{code: string}[]null`Notices the store raised while updating the cart (e.g. an item became unavailable).
errors{ shipping_methods?: { readable_code: string, message: string } }Per-area failures that did not fail the whole request — most commonly a shipping-rate lookup.

Counting items: items is the list of distinct line items, so items.length is not the number of products in the cart. Sum the quantities:

const [cart] = await window.dmAPI.ecomm.getCart({ cart_id: 'cart_abc123' });
const itemCount = (cart?.items ?? []).reduce(
  (total, item) => total + item.quantity,
  0,
);

Subscriptions: a cart contains a subscription when one of its items has a non-null plan (see CartLineItemResponseDto):

const subscriptionItem = cart?.items.find((item) => item.plan !== null);

PurchaseSummaryResponseDto

The totals breakdown on cart.summary. Every *_amount is in the cart's currency.

FieldTypeDescription
subtotal_amount`numbernull`Items subtotal, after item-level discounts.
original_subtotal_amount`numbernull` (optional)Subtotal before discounts, when it differs.
discount_amount`numbernull`Total savings from applied discounts.
shipping_amount`numbernull`Shipping cost.
fees`{id, name, amount, description?}[]null`Additional fees.
net_total_amount`numbernull`Total before taxes.
taxes`{id, name, percentage, total_amount}[]null`Taxes, itemized.
total_taxesnumberSum of all taxes.
total_amountnumberGrand total — what the customer pays.

CartLineItemResponseDto

One line in cart.items.

FieldTypeDescription
idstringLine item ID. Pass to updateItemQuantity / removeItem.
addedstringWhen the item was added.
product_id`stringnull`Catalog product ID.
variation_id`stringnull`Catalog variation ID.
external_product_id`stringnull`Product ID in an external catalog.
external_variation_id`stringnull`Variation ID in an external catalog.
namestringDisplay name.
description`stringnull`Display description.
image`stringnull`Image URL.
sku`stringnull`SKU.
plan`{ id, name, frequency: 'WEEKLY''MONTHLY''YEARLY', tag_line }null`Subscription plan, when the item is a subscription.
options{ name, value }[]Chosen variation options (size, colour, …).
product_customizationsProductCustomizationResponseDto[]Buyer-supplied customizations.
quantitynumberQuantity.
shippablebooleanWhether the item requires shipping.
unit_pricenumberPrice for one unit.
unit_weight`numbernull`Weight of one unit.
unit_dimensions`{height, width, length}null`Dimensions of one unit; each value may be null.
combined_weight`numbernull`unit_weight × quantity.
discounts`{ id, code, name, savings, type: 'RATE''AMOUNT', rate_or_amount_value }[]`Discounts applied to this line.
taxes{ id, name, rate, amount }[]Taxes on this line.
subtotalnumberLine subtotal.
original_subtotal`numbernull` (optional)Line subtotal before discounts.
totalnumberLine total.
metadataRecord<string, unknown>Metadata stored on the line item.
booking_intent`{slot_start, slot_duration, time_zone, reservation_valid_until, fields_responses}null`Reserved slot, for items added with buyBooking.

ProductCustomizationResponseDto

A buyer-supplied customization on a line item. Discriminate on type:

type ProductCustomizationResponseDto =
  | {
      type: 'TEXT';
      id: string;
      label: string;
      value?: string;
      price_modifier?: number;
    }
  | {
      type: 'BOOLEAN';
      id: string;
      label: string;
      value: boolean;
      price_modifier?: number;
    }
  | {
      type: 'OPTIONS';
      id: string;
      label?: string | null;
      value: string[];
      options_price_modifiers?: Array<number | null>;
      price_modifier?: number;
    }
  | {
      type: 'FILE';
      id: string;
      label: string;
      value: {
        filename: string;
        mimetype: string;
        size: number;
        url: string;
        key: string;
        handle: string;
        uploaded_at: string;
      }[];
      price_modifier?: number;
    };

PersonalAddressRequestDto

The address shape used for cart, checkout, and customer addresses. Used by createCart (shipping_address, billing_address), setShippingAddress, setBillingAddress, updateCustomer (shipping_address), and inside CreateCartPayload.

The name and street can each be supplied in one of two forms — a combined field or its split parts — but not both. The unused alternative must be omitted or null:

  • Name: either full_name, or both first_name and last_name.
  • Street: either address_1, or both street_name and street_number.
type PersonalAddressRequestDto = (
  // Name — pick ONE form
  | { full_name: string; first_name?: null; last_name?: null }
  | { full_name?: null; first_name: string; last_name: string }
) & (
  // Street — pick ONE form
  | { address_1: string; street_name?: null; street_number?: null }
  | { address_1?: null; street_name: string; street_number: string }
) & {
  address_2?: string | null;
  city: string; // required
  region?: string | null;
  sub_locality?: string | null;
  country: string; // required
  postal_code: string; // required
  phone?: string | null;
};

Example (combined form — the common case):

{
  full_name: 'Jane Doe',
  address_1: '123 Main St',
  city: 'Boston',
  region: 'MA',
  country: 'US',
  postal_code: '02101',
}

Example (split form):

{
  first_name: 'Jane',
  last_name: 'Doe',
  street_name: 'Main St',
  street_number: '123',
  city: 'Boston',
  region: 'MA',
  country: 'US',
  postal_code: '02101',
}

ProductCustomizationPayload

A single product customization (option) submitted with addProduct or buyProduct via product_customizations. It is a discriminated union on type — the shape of value depends on the customization's type. id is the identifier of the customization field configured on the product.

type ProductCustomizationPayload =
  | { type: 'TEXT'; id: string; value?: string }
  | { type: 'BOOLEAN'; id: string; value: boolean }
  | { type: 'OPTIONS'; id: string; value?: string[] }
  | { type: 'CHECKBOX'; id: string; value?: string[] }
  | { type: 'FILE'; id: string; value?: FileAttachment[] /* max 10 */ };

// value entry for a FILE customization
interface FileAttachment {
  url: string;
  filename: string;
  size: number;
  mimetype: string;
  handle: string;
  key: string;
  uploaded_at: string | Date; // ISO string, or a Date (serialized to ISO)
}

Notes:

  • CHECKBOX is a client-side convenience alias. It is normalized to OPTIONS before the request is sent, so CHECKBOX and OPTIONS are interchangeable on the wire.
  • value is optional for OPTIONS, CHECKBOX, and FILE: an untouched field can be submitted with no value, which the backend treats as an empty selection.
  • FILE accepts at most 10 attachments, and every FileAttachment field is required.

Example:

const [cart, error] = await window.dmAPI.ecomm.addProduct({
  product_id: 'prod_tshirt_001',
  variation_id: 'var_tshirt_blue_m',
  quantity: 1,
  product_customizations: [
    { type: 'TEXT', id: 'engraving', value: 'Happy Birthday' },
    { type: 'BOOLEAN', id: 'gift_wrap', value: true },
    { type: 'OPTIONS', id: 'size', value: ['medium'] },
  ],
});

AddItemRequestDto

A line item used to seed a cart via the items array of createCart / CreateCartPayload. It is a discriminated union on source; the base fields below are shared, and each source adds its own fields.

interface AddItemRequestDto {
  source: 'STORE_CATALOG' | 'MEMBERSHIPS' | 'BOOKINGS';
  plan_id?: string;
  quantity?: number;
  metadata?: object;
}

Source-specific shapes:

// source: 'STORE_CATALOG' — a catalog product
interface AddProductRequestDto extends AddItemRequestDto {
  source: 'STORE_CATALOG';
  product_id: string;
  variation_id: string;
  product_customizations?: ProductCustomizationPayload[];
}

// source: 'MEMBERSHIPS' — a subscription plan
interface AddMembershipRequestDto extends AddItemRequestDto {
  source: 'MEMBERSHIPS';
  plan_id: string;
  quantity: 1;
}

// source: 'BOOKINGS' — a booking slot
interface AddBookingRequestDto extends AddItemRequestDto {
  source: 'BOOKINGS';
  quantity: 1;
  event_name: string;
  event_type_id: number;
  slot_start: string;
  slot_duration?: number;
  time_zone: string;
  booking_fields_responses?: Record<string, unknown>;
}

Example (prefill a cart with one catalog product):

const [cart, error] = await window.dmAPI.ecomm.createCart({
  items: [
    {
      source: 'STORE_CATALOG',
      product_id: 'prod_tshirt_001',
      variation_id: 'var_tshirt_blue_m',
      quantity: 2,
    },
  ],
});

CreateCartPayload

The options accepted by createCart, and reused as cart_options by the "buy now" methods (buyProduct, buyMembership, buyBooking) to prefill the cart that is auto-created for the purchase. Every field is optional.

interface CreateCartPayload {
  email?: string;
  shipping_address?: PersonalAddressRequestDto;
  billing_address?: PersonalAddressRequestDto;
  metadata?: object;
  items?: AddItemRequestDto[];
  timezone?: string; // defaults to the browser's timezone
}

See the Prefilling the cart with cart_options example (under buyProduct).

CurrencyCustomFormat

Custom money-formatting options passed to formatMoney via override.customFormat. When omitted, the store's configured format is used.

interface CurrencyCustomFormat {
  groupSeparator: string; // thousands separator, e.g. ','
  decimalSeparator: string; // decimal separator, e.g. '.'
  keepTrailingZeroesDecimals: boolean; // keep trailing zeroes, e.g. '10.00'
  symbol: string; // currency symbol, e.g. '$'
  symbolPlacement: 'BEFORE_PRICE' | 'AFTER_PRICE';
}

Example: formats 1999 as "$19.99".

window.dmAPI.ecomm.formatMoney({
  amount: 1999,
  override: {
    customFormat: {
      groupSeparator: ',',
      decimalSeparator: '.',
      keepTrailingZeroesDecimals: true,
      symbol: '$',
      symbolPlacement: 'BEFORE_PRICE',
    },
  },
});

CheckoutCustomFieldZone

The checkout zone a custom field belongs to, used by setCustomFields. It is a string union:

type CheckoutCustomFieldZone =
  | 'CONTACT_INFO'
  | 'SHIPPING_ADDRESS'
  | 'SHIPPING_METHODS'
  | 'BILLING_ADDRESS'
  | 'PAYMENT_METHODS';

TypeScript

The public API is typed. Use the exported type IDmAPIEcomm for the interface and type window.dmAPI.ecomm accordingly (e.g. via global augmentation or a local declaration).


Error handling

Most async methods do not throw. Each tuple-returning method one resolves to a [result, error] tuple, so you handle failures by inspecting the second element instead of using try/catch:

  • Success: [result, undefined]result is the response, error is undefined.
  • Failure: [undefined, error]result is undefined, error is an EcomSDKError.

Always destructure the tuple and check error before using the result:

const [cart, error] = await window.dmAPI.ecomm.addProduct({
  product_id: 'prod_tshirt_001',
  variation_id: 'var_tshirt_001_blue_m',
  quantity: 1,
});

if (error) {
  // show a toast, fallback UI, or report to monitoring
  console.error(error.code, error.message);
  return;
}

// safe to use the result
console.log(cart);

If you only care about whether the call failed, you can skip the result with a hole:

const [, error] = await window.dmAPI.ecomm.addDiscount({ code: 'SAVE20' });
if (error) {
  // the code may be invalid or expired
}

The error object

error is always an instance of EcomSDKError with:

  • code — a stable, localizable error code (e.g. sdk_errors.common.network_error).
  • message — a human-readable description.

Common subclasses you may receive:

ErrorWhen it occurs
NetworkSDKErrorThe request could not reach the server (connectivity, timeout).
BadRequestSDKErrorThe server rejected the request (validation, invalid input).
InvalidPayloadSDKErrorThe payload failed client-side validation before any request was sent (missing or malformed fields); code sdk_errors.common.invalid_payload_error.
PaymentSDKErrorA payment could not be processed.
UnknownSDKErrorAny other/unexpected error; the original cause is on .details.

You can branch on the subclass or the code when you need specific handling:

import { NetworkSDKError } from '...'; // exported by the SDK package

const [orders, error] = await window.dmAPI.ecomm.getOrders({ limit: 5 });
if (error) {
  if (error instanceof NetworkSDKError) {
    // offer a retry
  } else {
    // generic failure handling
  }
}

This tuple-based handling applies to nearly every async method in the SDK (addProduct, buyProduct, getCart, getOrders, etc.). The synchronous helpers — openCart, closeCart, clearCart, formatMoney, and login — return their value directly, never produce a tuple, and do not throw.



Did this page help you?