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

# Customer

> Customer profiles, order history, and subscription management

# Customer

The customer module gives you access to customer profiles, order history, and subscriptions. Use it to build account dashboards, order tracking pages, and subscription management UIs.

***

## Get Customer Profile

```typescript theme={null}
const customer = await tagada.customer.getProfile(customerId);
```

### By Email

```typescript theme={null}
const customer = await tagada.customer.getByEmail('jane@example.com');
// Returns Customer or null if not found
```

***

## Update Profile

```typescript theme={null}
const updated = await tagada.customer.updateProfile(customerId, {
  firstName: 'Jane',
  lastName: 'Doe',
  phone: '+33612345678',
});
```

***

## Orders

### List Orders

```typescript theme={null}
const { orders, total } = await tagada.customer.getOrders(customerId, {
  limit: 10,
  offset: 0,
});
```

### Get Single Order

```typescript theme={null}
const order = await tagada.customer.getOrder(orderId);
// order.items            — line items on this order
// order.relatedOrders    — child orders from accepted upsells
//                          (metadata.mainOrderId === order.id)
```

### Get an Order on the Thank-You Page

Accepted post-purchase offers create **separate child orders**, not extra
lines on the main order — and they land **asynchronously**. The first fetch
right after an accept usually misses them. Pass `waitForRelatedOrders: true`
and the SDK polls for you:

```typescript theme={null}
const order = await tagada.customer.getOrder(orderId, {
  waitForRelatedOrders: true, // polls until relatedOrders is non-empty
  timeoutMs: 8000,            // optional, default 8000
  intervalMs: 2000,           // optional, default 2000
});

// Render one block per order:
const allOrders = [order, ...(order.relatedOrders ?? [])];
```

<Note>
  On timeout the latest snapshot is returned — it never throws. A customer who
  declined every offer simply gets an order with an empty `relatedOrders` after
  `timeoutMs`. In React, prefer the [`useOrder` hook](#useorder--thank-you-pages)
  which renders the main order immediately and fills in the upsells in the
  background. Worked example: [Basic post-purchase](/developer-tools/funnel-demos/basic-post-purchase#thank-you-related-orders).
</Note>

***

## Subscriptions

### List Subscriptions

```typescript theme={null}
const subscriptions = await tagada.customer.getSubscriptions(customerId);
```

### Get Single Subscription

```typescript theme={null}
const subscription = await tagada.customer.getSubscription(subscriptionId);
```

***

## React Hook

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

function CustomerDashboard({ customerId }: { customerId: string }) {
  const {
    customer,
    orders,
    subscriptions,
    isLoading,
    error,
    loadCustomer,
    loadOrders,
    loadSubscriptions,
    updateProfile,
  } = useCustomer(customerId); // auto-loads profile when customerId is provided

  useEffect(() => {
    if (customerId) {
      loadOrders(customerId);
      loadSubscriptions(customerId);
    }
  }, [customerId]);

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <div>
      <h1>Welcome, {customer?.firstName}</h1>

      <h2>Orders</h2>
      {orders.map((order) => (
        <div key={order.id}>
          Order #{order.orderNumber} — {order.status}
        </div>
      ))}

      <h2>Subscriptions</h2>
      {subscriptions.map((sub) => (
        <div key={sub.id}>
          {sub.name} — {sub.status}
        </div>
      ))}
    </div>
  );
}
```

### Full Hook API

| Property / Method                 | Description                                                                        |
| --------------------------------- | ---------------------------------------------------------------------------------- |
| `customer`                        | Current customer profile (null until loaded)                                       |
| `orders`                          | Array of customer orders                                                           |
| `subscriptions`                   | Array of customer subscriptions                                                    |
| `isLoading`                       | True during any async operation                                                    |
| `error`                           | Last error, if any                                                                 |
| `loadCustomer(customerId)`        | Load customer profile (called automatically if `customerId` is passed to the hook) |
| `loadOrders(customerId, opts?)`   | Fetch orders. Optional: `{ limit?, offset? }`                                      |
| `loadSubscriptions(customerId)`   | Fetch all subscriptions                                                            |
| `updateProfile(customerId, data)` | Update customer name, phone, etc.                                                  |

***

## `useOrder` — Thank-You Pages

`useCustomer` is for account dashboards (you have a `customerId`). On a
**thank-you page** you have an `orderId` from the URL — use `useOrder`. It
loads the order, renders it immediately, and keeps watching in the
background for the child orders created by accepted upsells:

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

function ThankYouPage() {
  const orderId = new URLSearchParams(window.location.search).get('orderId');
  const { order, relatedOrders, isLoading, error } = useOrder(orderId);

  if (isLoading || !order) return <p>Loading your order…</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <div>
      <h1>Thank you!</h1>

      {/* Main order — the checkout purchase */}
      <OrderBlock title="Your order" order={order} />

      {/* One block per accepted upsell — appears automatically when it lands */}
      {relatedOrders.map((o) => (
        <OrderBlock key={o.id} title="Added to your order" order={o} />
      ))}
    </div>
  );
}
```

No manual polling: with the default `watchRelatedOrders: true`, the hook
refetches every 2s for up to 8s while `relatedOrders` is empty, then stops.
Upsell blocks pop in as soon as the child orders exist.

### `useOrder` API

| Property / Method | Description                                               |
| ----------------- | --------------------------------------------------------- |
| `order`           | The order (null until loaded)                             |
| `relatedOrders`   | Child orders from accepted upsells (`[]` until they land) |
| `isLoading`       | True during the initial fetch only                        |
| `error`           | Last error, if any                                        |
| `refresh()`       | Refetch the order once                                    |

| Option               | Default | Description                                    |
| -------------------- | ------- | ---------------------------------------------- |
| `watchRelatedOrders` | `true`  | Keep refetching while `relatedOrders` is empty |
| `watchTimeoutMs`     | `8000`  | How long to keep watching                      |
| `watchIntervalMs`    | `2000`  | Delay between refetches                        |
