
# Checkout sessions

A checkout session is a cart made somewhere else that the customer completes in WhatsApp. You create it, you get a `url`, and the customer opens it on their phone: WhatsApp starts a chat with the shop with a message like *"Hi Mama Njeri's! I'd like to complete my order (C-7K2Q9)"* ready to send. When they send it, the shop shows that cart for review, then takes delivery or pickup and payment (M-Pesa, card, or cash on delivery) as usual.

Use it for:

- **Your website or app.** "Order on WhatsApp" instead of building a checkout.
- **Ads.** A landing page or Click-to-WhatsApp ad that drops the customer straight into a ready cart.
- **AI agents.** An assistant shops for someone and hands them a link to confirm and pay.
- **Sales over chat.** Send a customer a link for exactly what they asked for.

The order it becomes carries the session's `source` and `attribution`, so you can see which site, campaign or agent sold what.

## Create a checkout session

`POST /v1/checkout_sessions`

```bash
curl $KIBANDA_API/v1/checkout_sessions \
  -H "Authorization: Bearer $KIBANDA_KEY" -H "Content-Type: application/json" \
  -d '{
    "items": [{ "external_id": "SKU-1001", "quantity": 2 }, { "product": "pr_9f2c", "quantity": 1 }],
    "source": "website",
    "attribution": { "utm_source": "instagram", "utm_campaign": "october" }
  }'
```

| Parameter | |
|---|---|
| `items` | **Required.** 1–50 of `{ product \| external_id \| code, quantity }`. |
| `source` | `website`, `agent`, `ad`, `link` or `api` (default). Copied to the order. |
| `customer` | `{ phone, name }` — if `phone` is set, only that WhatsApp number can use the link. |
| `attribution` | Your tracking fields (≤ 2 KB), e.g. UTM tags. Copied to the order. |
| `expires_in` | Seconds, 300 to 604800. Default 86400 (24 h). |
| `external_id`, `metadata` | |

```json
{
  "id": "cs_…",
  "object": "checkout_session",
  "code": "C-7K2Q9",
  "url": "https://wa.me/254700000000?text=Hi%20Mama%20Njeri%27s!%20I%27d%20like%20to%20complete%20my%20order%20(C-7K2Q9)",
  "status": "open",
  "items": [{ "product": "pr_1001", "quantity": 2 }, { "product": "pr_9f2c", "quantity": 1 }],
  "source": "website",
  "customer": null,
  "order": null,
  "attribution": { "utm_source": "instagram", "utm_campaign": "october" },
  "expires_at": 1792802400,
  "created": 1792716000
}
```

Redirect the customer to `url` (or show it as a QR code on desktop).

### What the customer sees

Prices are checked when they open it: if something sold out or was archived since, it's left out and they're told. Quantities are capped at what's in stock.

### Status

`open` → `claimed` (someone sent the code; it's now theirs) → `completed` (their order was placed; `order` is set) — or `expired`. A completed link can't be reused; a claimed link can't be used by another number.

## Retrieve, list, expire

- `GET /v1/checkout_sessions/{id}`
- `GET /v1/checkout_sessions` — filters: `status`, `created_gte`, `created_lt`
- `POST /v1/checkout_sessions/{id}/expire`

The `checkout_session.completed` [event](https://kibanda.africa/docs/events) fires when its order is placed.

## Without a server: the shop page and button

Every shop has a public page at `https://api.kibanda.africa/s/<shop-slug>` — a catalog with quantities and an **Order on WhatsApp** button. Use it as a link in bio or an ad landing page; UTM tags on the URL are recorded on the order.

To add the button to any website, no API key needed:

```html
<script src="https://api.kibanda.africa/s/<shop-slug>/button.js" async></script>

<button data-kibanda-product="pr_9f2c" data-quantity="1">Order on WhatsApp</button>
```

Or build your own cart and call `Kibanda.checkout([{ product: "pr_9f2c", quantity: 2 }])` — it creates the session and opens WhatsApp. Behind it is the public endpoint `POST /s/<shop-slug>/checkout` with `{ "items": [...] }`, which returns `{ url, code }`.
