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

# Checkout Flow

> Manage checkout sessions, cart, promo codes, and shipping

# Checkout Flow

The checkout module manages the full session lifecycle -- load a session, update the cart, apply promo codes, and handle shipping.

***

## Load a Checkout Session

A checkout session is typically created by the Node SDK on your server, then the token is passed to the frontend via URL parameter.

```typescript theme={null}
// Token from URL: /checkout?checkoutToken=ct_abc123&token=eyJ...
const checkoutToken = new URLSearchParams(window.location.search).get('checkoutToken');
const sessionToken = new URLSearchParams(window.location.search).get('token');

const session = await tagada.checkout.loadSession(checkoutToken, sessionToken);

// session.id          -- session ID (use for all subsequent calls)
// session.items       -- line items in the cart
// session.totals      -- subtotal, discount, shipping, tax, total
// session.customer    -- customer info if available
// session.currency    -- session currency (USD, EUR, etc.)
```

***

## Create a Checkout Session (Client-Side)

You can also create a session directly from the browser:

```typescript theme={null}
const session = await tagada.checkout.createSession({
  items: [{ variantId: 'var_xxx', quantity: 1 }],
  currency: 'USD',
  returnUrl: 'https://mystore.com/checkout',
});

// session.checkoutUrl   -- Tagada-hosted checkout URL (for reference)
// session.checkoutToken -- token to use with loadSession()
// session.sessionToken  -- JWT for authenticated calls
// session.customerId    -- assigned customer ID
```

***

## Update Cart

```typescript theme={null}
const updated = await tagada.checkout.updateCart(session.id, [
  { variantId: 'var_xxx', quantity: 2 },
  { variantId: 'var_yyy', quantity: 1 },
]);
// updated.totals reflects the new cart
```

***

## Customer & Address

The SDK uses a two-step pattern: first set customer identity, then set the address. Under the hood, both are sent in a single atomic API call when `updateAddress()` is called.

### Set Customer Info

`updateCustomer()` stores email, name, and phone **in memory**. No API call is made yet — the data is sent together with the address in the next step.

```typescript theme={null}
await tagada.checkout.updateCustomer(session.id, {
  email: 'jane@example.com',
  firstName: 'Jane',
  lastName: 'Doe',
  phone: '+33612345678',
});
```

### Set Address

`updateAddress()` sends customer info + address together in one atomic API call. The customer's `firstName`, `lastName`, and `phone` are automatically included in the address fields.

<Tabs>
  <Tab title="Shipped Product">
    ```typescript theme={null}
    // Billing defaults to shipping automatically
    await tagada.checkout.updateAddress(session.id, {
      shippingAddress: {
        line1: '123 Main St',
        city: 'San Francisco',
        state: 'CA',
        postalCode: '94102',
        country: 'US',
      },
    });
    ```
  </Tab>

  <Tab title="Digital Product">
    ```typescript theme={null}
    // No shipping needed — just billing country for tax calculation
    await tagada.checkout.updateAddress(session.id, {
      billingAddress: {
        country: 'US',
      },
    });
    ```
  </Tab>

  <Tab title="Separate Billing">
    ```typescript theme={null}
    // Different billing and shipping addresses
    await tagada.checkout.updateAddress(session.id, {
      shippingAddress: {
        line1: '123 Main St',
        city: 'San Francisco',
        postalCode: '94102',
        country: 'US',
      },
      billingAddress: {
        line1: '456 Oak Ave',
        city: 'New York',
        postalCode: '10001',
        country: 'US',
      },
    });
    ```
  </Tab>
</Tabs>

### Combined Method

If you prefer a single explicit call:

```typescript theme={null}
await tagada.checkout.updateCustomerAndAddress(session.id, {
  customer: {
    email: 'jane@example.com',
    firstName: 'Jane',
    lastName: 'Doe',
  },
  shippingAddress: {
    line1: '123 Main St',
    city: 'San Francisco',
    postalCode: '94102',
    country: 'US',
  },
});
```

<Note>
  **Address fields:** `firstName`, `lastName`, `phone` can be passed directly in the address object too — they override the values from `updateCustomer()`.
</Note>

***

## Promo Codes

```typescript theme={null}
// Apply
await tagada.checkout.applyPromoCode(session.id, 'SAVE20');

// Remove
await tagada.checkout.removePromoCode(session.id);

// Reload session to see updated totals
const updated = await tagada.checkout.loadSession(checkoutToken, sessionToken);
console.log(updated.totals.discount); // discount amount in cents
```

***

## Shipping

```typescript theme={null}
// Get available rates (requires address to be set first)
const rates = await tagada.checkout.getShippingRates(session.id);
// [{ id: 'rate_xxx', name: 'Standard', amount: 499, estimatedDays: 5 }]

// Select a rate
await tagada.checkout.selectShippingRate(session.id, rates[0].id);
```

<Tip>
  For **digital products**, skip shipping entirely — go straight from `updateAddress()` to payment.
</Tip>

***

## React Hook

```tsx theme={null}
import { useCheckout } from '@tagadapay/headless-sdk/react';

function CheckoutPage() {
  const {
    session,
    isLoading,
    error,
    refresh,
    createSession,
    updateCart,
    updateCustomer,
    updateAddress,
    applyPromo,
    removePromo,
    getShippingRates,
    selectShippingRate,
  } = useCheckout(checkoutToken, sessionToken);

  // All methods auto-refresh the session after completion
}
```

### Full Hook API

| Method                                                  | Description                                             |
| ------------------------------------------------------- | ------------------------------------------------------- |
| `session`                                               | Current checkout session (null until loaded)            |
| `isLoading`                                             | True during any async operation                         |
| `error`                                                 | Last error, if any                                      |
| `refresh()`                                             | Reload the session                                      |
| `createSession({ items, currency, returnUrl? })`        | Create a new session                                    |
| `updateCart(items)`                                     | Replace cart items                                      |
| `updateCustomer({ email, firstName, lastName, phone })` | Store customer identity (in memory)                     |
| `updateAddress({ shippingAddress?, billingAddress? })`  | Set addresses + persist customer data (single API call) |
| `applyPromo(code)`                                      | Apply a promo code                                      |
| `removePromo(promotionId?)`                             | Remove a promo code                                     |
| `getShippingRates()`                                    | Fetch available shipping rates                          |
| `selectShippingRate(rateId)`                            | Select a shipping rate                                  |
