> ## Documentation Index
> Fetch the complete documentation index at: https://docs.khaime.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Storefront + Cart

> Sell a catalog with a multi-item cart and embedded checkout.

# Storefront + Cart Checkout

Use the storefront flow when customers need to browse products, build a basket, and pay for several items at once. Three components work together:

* **`<khaime-storefront>`** — product grid with filtering, currency switching, and an add-to-cart drawer.
* **`<khaime-cart-page>`** — optional standalone cart page (for a dedicated `/cart` route).
* **`sdk.openCartCheckout()`** — opens the checkout modal with the current cart contents.

The cart is persisted client-side (UUID in `localStorage`) and mirrored server-side in Redis with a 14-day TTL, so customers keep their basket across sessions and devices (as long as the UUID is on the same browser).

<Note>
  Only physical products can be added to the cart. Digital downloads, event tickets, and subscriptions use direct checkout — render them with a [Pay Button](/sdks/embedded/quickstart) instead.
</Note>

## Minimal setup

```html theme={null}
<!DOCTYPE html>
<html>
<body>
  <khaime-storefront
    merchant-id="1234"
    cart-display="drawer"
  ></khaime-storefront>

  <script src="https://api.khaime.com/sdk/v2/khaime.js"></script>
  <script>
    const sdk = KhaimeSDK.init({ merchantId: '1234' });

    sdk.on({
      onAddToCart: (product, qty) => console.log('added', product.id, qty),
      onCartUpdated: ({ itemCount, subtotal }) => {
        document.getElementById('cart-count').textContent = itemCount;
      },
      onPaymentSuccess: ({ orderId }) => {
        window.location.href = '/thank-you?order=' + orderId;
      },
    });
  </script>
</body>
</html>
```

That's it — product clicks, add-to-cart, the checkout modal, and payment confirmation are all handled by the component.

## The full purchase flow

<Steps>
  <Step title="Customer lands on your page">
    `<khaime-storefront>` calls `GET /api/v1/sdk/storefront/bootstrap` (merchant branding, currencies, gateways) and `GET /api/v1/sdk/storefront/products` (the catalog).
  </Step>

  <Step title="Customer adds items">
    Clicking "Add to cart" on a product card dispatches `khaime:add-to-cart`. The SDK's `CartManager` updates `localStorage` and syncs to the server via `POST /api/v1/sdk/storefront/cart/items`.
  </Step>

  <Step title="Customer opens the cart">
    Depending on the `cart-display` attribute, the drawer slides open or the page navigates to `cartUrl`. Cart contents are re-hydrated from `GET /api/v1/sdk/storefront/cart/{cart_id}`.
  </Step>

  <Step title="Customer clicks Checkout">
    The SDK calls `sdk.openCartCheckout()` internally (or you can call it yourself from a custom button). This opens the cart-checkout modal.
  </Step>

  <Step title="Modal collects customer info + payment">
    The modal shows an email/name form, a shipping-address form (for physical goods), and then the Stripe Elements or Paystack UI based on the transaction currency.
  </Step>

  <Step title="Payment confirmed">
    The SDK calls `POST /api/v1/sdk/checkout/session/{sessionToken}/confirm`, emits `khaime:payment-success`, clears the cart, and fires your `onPaymentSuccess` callback.
  </Step>
</Steps>

## Storefront configuration

```html theme={null}
<khaime-storefront
  merchant-id="1234"
  category-slug="apparel"
  columns="3"
  limit="12"
  sort="newest"
  cart-display="drawer"
  cart-url="/cart"
></khaime-storefront>
```

| Attribute       | Description                                                               |
| --------------- | ------------------------------------------------------------------------- |
| `product-ids`   | Comma-separated product IDs to restrict the grid to a specific set.       |
| `category-slug` | Filter by a `ProductCategory` slug (or comma-separated slugs).            |
| `category-id`   | Filter by numeric `ProductCategory.id`.                                   |
| `type`          | Filter by product type (`physical`, `digital`, `service`, etc.).          |
| `sort`          | `newest`, `price_asc`, `price_desc`, etc.                                 |
| `columns`       | Grid columns (1–6).                                                       |
| `limit`         | Products per page.                                                        |
| `cart-display`  | `drawer` (default), `page`, or `both`. See below.                         |
| `cart-url`      | Destination when `cart-display` is `page` or `both`. Defaults to `/cart`. |

### Cart display modes

* **`drawer`** — Cart opens as a slide-out overlay on the current page. Best for single-page experiences.
* **`page`** — "View cart" links navigate to `cart-url`. Pair with a dedicated `<khaime-cart-page>` on that route.
* **`both`** — Drawer opens for quick reviews, but the "Checkout" CTA routes to `cart-url` as a pre-checkout review step.

## Standalone cart page

For a dedicated cart route, render `<khaime-cart-page>` on `/cart`:

```html theme={null}
<!-- /cart route -->
<khaime-cart-page
  merchant-id="1234"
  display="full"
  store-url="/"
></khaime-cart-page>
```

Or render a mini cart in a sidebar:

```javascript theme={null}
KhaimeSDK.cartPage({
  container: '#mini-cart',
  merchantId: '1234',
  display: 'mini',
  cartUrl: '/cart',
});
```

## Programmatic cart access

The SDK exposes `CartManager` so you can read or mutate the cart from your own UI:

```javascript theme={null}
const cart = sdk.cart();

cart.getItems();           // LocalCartItem[]
cart.getItemCount();       // number
cart.getSubtotal();        // number (minor units)
cart.addItem(product, 1);  // add/increment
cart.updateItem(productId, { quantity: 3 });
cart.removeItem(productId);
cart.clear();

// Open checkout with the current cart
await sdk.openCartCheckout({
  onSuccess: ({ orderId }) => { /* ... */ },
  onError: (err) => { /* ... */ },
});
```

## Events you'll want to handle

```javascript theme={null}
sdk.on({
  onProductClick: (product) => {
    // Analytics: track product views
  },
  onAddToCart: (product, quantity) => {
    // Analytics: track add-to-cart
  },
  onCartUpdated: (items, action) => {
    // action: 'add' | 'remove' | 'update' | 'clear' | 'hydrate'
    updateHeaderBadge(items.length);
  },
  onCurrencyChange: (currency) => {
    // Customer switched currency — re-render your own pricing if needed
  },
  onPaymentSuccess: ({ orderId, amount, currency, paymentMethod }) => {
    // Redirect, show receipt, clear UI
  },
  onPaymentError: ({ error, code }) => {
    showToast('Payment failed: ' + error);
  },
});
```

See the [events reference](/sdks/embedded/events) for the full payload shapes.

## Next steps

* [Programmatic checkout](/sdks/embedded/programmatic) — create sessions on your server.
* [Events reference](/sdks/embedded/events) — complete list of purchase events.
* [Webhooks](/webhooks/overview) — verify orders server-side before fulfilment.
