# Join the waitlist

> The checkout.hosted.join_waitlist operation: POST /api/v1/public/checkout_sessions/{sessionId}/waitlist in the REST API and the checkout_hosted_join_waitlist tool in the MCP server.

When a sale is paused for the customer's location (the session is `blocked` because the seller isn't
registered there yet), the customer can ask to be told when the brand can sell there: “Notify me when
{brand} can sell in {country}” (spec §23). The entry stores the email, the country, what they wanted to buy
and its value, and stays `pending` until the customer confirms through the link in the email (double
opt-in; the link works for 7 days). Joining again sends a new link; a confirmed entry stays confirmed.

Public: the hosted page calls it with the session key.

## At a glance

- **REST:** `POST /api/v1/public/checkout_sessions/{sessionId}/waitlist`
- **MCP tool:** `checkout_hosted_join_waitlist`
- **Operation ID:** `checkout.hosted.join_waitlist`
- **Scope:** Brand
- **Permission:** `checkout:write`
- **Risk tier:** `write`
- **Dry run:** Not supported
- **Idempotency:** `Idempotency-Key` required
- **Modes:** Test and live
- **Authentication:** None (a public endpoint, rate-limited per IP address)
- **Since:** M4

## Request

### Path parameters

| Field       | Type      | Description                         |
| ----------- | --------- | ----------------------------------- |
| `sessionId` | `cs_…` ID | The checkout session's ID (`cs_…`). |

### Body

A JSON object (`Content-Type: application/json`):

| Field     | Type                                      | Required | Description                                                                                                                         |
| --------- | ----------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `key`     | string                                    | No       | The session key from the hosted URL (`?key=…`). Required without an API key; signed-in callers with `checkout:write` don't need it. |
| `email`   | string                                    | Yes      | Where the confirmation and, later, the notification go.                                                                             |
| `consent` | boolean                                   | Yes      | The customer agreed to “Notify me when {brand} can sell in {country}”.                                                              |
| `locale`  | one of `en`, `de`, `fr`, `hr`, `it`, `es` | No       | The language the consent was shown in: it is stored in that language, and the emails use it.                                        |

## Response

`200 OK` with a JSON object:

| Field                                | Type                                                          | Description                                                                                                                                                                                      |
| ------------------------------------ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id`                                 | `cs_…` ID                                                     |                                                                                                                                                                                                  |
| `object`                             | `"checkout.hosted_session"`                                   |                                                                                                                                                                                                  |
| `livemode`                           | boolean                                                       |                                                                                                                                                                                                  |
| `status`                             | one of `open`, `processing`, `complete`, `expired`, `blocked` |                                                                                                                                                                                                  |
| `mode`                               | one of `payment`, `subscription`, `topup`, `setup`            |                                                                                                                                                                                                  |
| `currency`                           | string                                                        |                                                                                                                                                                                                  |
| `brand`                              | object                                                        |                                                                                                                                                                                                  |
| `brand.slug`                         | string                                                        |                                                                                                                                                                                                  |
| `brand.name`                         | string                                                        |                                                                                                                                                                                                  |
| `brand.primaryColor`                 | string or null                                                |                                                                                                                                                                                                  |
| `brand.termsUrl`                     | string or null                                                |                                                                                                                                                                                                  |
| `brand.privacyUrl`                   | string or null                                                |                                                                                                                                                                                                  |
| `brand.supportEmail`                 | string or null                                                |                                                                                                                                                                                                  |
| `seller`                             | object                                                        | The merchant disclosure: “Sold by {legal name}, {address}, {VAT ID}” (spec §29.1).                                                                                                               |
| `seller.legalName`                   | string                                                        |                                                                                                                                                                                                  |
| `seller.address`                     | string                                                        |                                                                                                                                                                                                  |
| `seller.taxId`                       | string                                                        |                                                                                                                                                                                                  |
| `lineItems`                          | array of object                                               |                                                                                                                                                                                                  |
| `lineItems[].id`                     | string                                                        |                                                                                                                                                                                                  |
| `lineItems[].description`            | string                                                        |                                                                                                                                                                                                  |
| `lineItems[].quantity`               | integer                                                       |                                                                                                                                                                                                  |
| `lineItems[].amount`                 | money                                                         |                                                                                                                                                                                                  |
| `lineItems[].recurring`              | object or null                                                |                                                                                                                                                                                                  |
| `lineItems[].adjustableQuantity`     | object or null                                                |                                                                                                                                                                                                  |
| `lineItems[].discount`               | money or null                                                 |                                                                                                                                                                                                  |
| `subscription`                       | object or null                                                | Subscription sessions: the trial, what is due today and the promotion code.                                                                                                                      |
| `topup`                              | object or null                                                | Top-up sessions (spec §14.3): what the customer's wallet receives.                                                                                                                               |
| `setup`                              | object or null                                                | Setup sessions: whether saving the card also pays the subscription's first invoice.                                                                                                              |
| `collectBusinessDetails`             | one of `auto`, `required`, `never`                            |                                                                                                                                                                                                  |
| `prefill`                            | object                                                        |                                                                                                                                                                                                  |
| `prefill.email`                      | string or null                                                |                                                                                                                                                                                                  |
| `prefill.name`                       | string or null                                                |                                                                                                                                                                                                  |
| `prefill.country`                    | string or null                                                |                                                                                                                                                                                                  |
| `prefill.subdivision`                | string or null                                                |                                                                                                                                                                                                  |
| `prefill.business`                   | object or null                                                |                                                                                                                                                                                                  |
| `quote`                              | object or null                                                |                                                                                                                                                                                                  |
| `blocked`                            | object or null                                                |                                                                                                                                                                                                  |
| `waitlist`                           | object or null                                                |                                                                                                                                                                                                  |
| `payment`                            | object                                                        |                                                                                                                                                                                                  |
| `payment.started`                    | boolean                                                       |                                                                                                                                                                                                  |
| `payment.intent`                     | one of `payment`, `setup` or null                             | `payment`: a charge now; `setup`: the card is saved without a charge.                                                                                                                            |
| `payment.component`                  | one of `fake`, `stripe_payment_element`, `redirect` or null   | How the payment details are collected: the fake processor's test cards, the Stripe Payment Element, or `redirect` (the buyer pays on the processor's page, Mollie; confirm answers its address). |
| `payment.publishableKey`             | string or null                                                |                                                                                                                                                                                                  |
| `payment.paymentMethod`              | object or null                                                |                                                                                                                                                                                                  |
| `payment.upToDate`                   | boolean                                                       | The prepared payment is for the current quote's total.                                                                                                                                           |
| `legal`                              | object                                                        |                                                                                                                                                                                                  |
| `legal.termsAccepted`                | boolean                                                       |                                                                                                                                                                                                  |
| `legal.immediatePerformanceRequired` | boolean                                                       |                                                                                                                                                                                                  |
| `legal.immediatePerformanceText`     | string                                                        |                                                                                                                                                                                                  |
| `successUrl`                         | string or null                                                | Set once the session is complete: `successUrl?cs_id=…`.                                                                                                                                          |
| `cancelUrl`                          | string or null                                                |                                                                                                                                                                                                  |
| `expiresAt`                          | date-time                                                     |                                                                                                                                                                                                  |
| `locale`                             | object                                                        | What decides the page's language (spec §14.2): an explicit choice on the page, then `preferred`, then the browser's languages, then `brand`, then English.                                       |
| `locale.preferred`                   | array of string                                               | The session's language, then its customer's, where set (BCP 47): the page's language before the visitor's.                                                                                       |
| `locale.brand`                       | array of string                                               | The brand's checkout languages; the first is its default.                                                                                                                                        |

## Examples

### A consumer in the UK

```http
POST /api/v1/public/checkout_sessions/cs_01m4tx5nj8emwbyf7y9vcf48aa/waitlist
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "key": "Zk3tq8Vb2xQ9mN4rP7sL1yH6cJ0wE5aD-uT_fG8hK2o",
  "email": "oliver@example.com",
  "consent": true
}
```

Response (`200`):

```json
{
  "id": "cs_01m4tx5nj8emwbyf7y9vcf48aa",
  "object": "checkout.hosted_session",
  "livemode": false,
  "status": "blocked",
  "mode": "payment",
  "currency": "EUR",
  "brand": {
    "slug": "genno",
    "name": "Genno",
    "primaryColor": null,
    "termsUrl": "https://genno.example/terms",
    "privacyUrl": "https://genno.example/privacy",
    "supportEmail": null
  },
  "seller": {
    "legalName": "Etna Labs AG",
    "address": "Dammstrasse 16, 6300 Zug, Switzerland",
    "taxId": "CHE-181.927.786 MWST"
  },
  "lineItems": [
    {
      "id": "1",
      "description": "Genno credits",
      "quantity": 1,
      "amount": {
        "amount": "100000000",
        "currency": "EUR"
      },
      "recurring": null,
      "adjustableQuantity": null,
      "discount": null
    }
  ],
  "subscription": null,
  "topup": null,
  "setup": null,
  "collectBusinessDetails": "auto",
  "prefill": {
    "email": "oliver@example.com",
    "name": null,
    "country": "GB",
    "subdivision": null,
    "business": null
  },
  "quote": null,
  "blocked": {
    "reason": "registration_required",
    "country": "GB",
    "countryName": "United Kingdom",
    "waitlistOffered": true,
    "businessOffered": true
  },
  "waitlist": {
    "entryId": "wl_01m4tx5nj8emwbyf7y9vcf48ah",
    "status": "pending",
    "email": "oliver@example.com",
    "consentText": "Notify me when Genno can sell in United Kingdom"
  },
  "payment": {
    "started": false,
    "intent": null,
    "component": null,
    "publishableKey": null,
    "paymentMethod": null,
    "upToDate": false
  },
  "legal": {
    "termsAccepted": false,
    "immediatePerformanceRequired": true,
    "immediatePerformanceText": "I want the service to start now, and I understand that I lose my right to withdraw once it has started."
  },
  "successUrl": null,
  "cancelUrl": "https://shop.example/cart",
  "expiresAt": "2026-10-15T10:00:00.000Z",
  "locale": {
    "preferred": [],
    "brand": ["en"]
  }
}
```

## Errors

| Code                                                                                                   | HTTP status | When                                                                                                           | What to do                                                                                                                       |
| ------------------------------------------------------------------------------------------------------ | ----------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found)               | 404         | No such checkout session for this brand and mode, or (on the hosted page) the session key is missing or wrong. | Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.                             |
| [`checkout_session_not_open`](https://ownrecord.io/docs/reference/errors.md#checkout_session_not_open) | 409         | The session is complete, expired, or a payment for it is being processed (`details.status`).                   | The session is complete, expired or waiting for a payment's outcome (`details.status`). Create a new session for a new purchase. |
| [`waitlist_not_available`](https://ownrecord.io/docs/reference/errors.md#waitlist_not_available)       | 409         | The sale isn't paused for the customer's location, so there is no waitlist.                                    | The customer can buy now: continue the checkout. The waitlist opens when the quote is blocked (spec §23).                        |
| [`waitlist_consent_required`](https://ownrecord.io/docs/reference/errors.md#waitlist_consent_required) | 400         | The customer didn't agree to be notified.                                                                      | Ask the customer to tick the consent (`Notify me when … can sell in …`) before joining.                                          |
| [`checkout_details_required`](https://ownrecord.io/docs/reference/errors.md#checkout_details_required) | 409         | The customer's country isn't known yet.                                                                        | Submit the customer's email and country first, so the tax can be quoted.                                                         |

It can also return these [common errors](https://ownrecord.io/docs/reference.md#common-errors): [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed), [`api_version_unsupported`](https://ownrecord.io/docs/reference/errors.md#api_version_unsupported), [`invalid_json`](https://ownrecord.io/docs/reference/errors.md#invalid_json), [`unsupported_media_type`](https://ownrecord.io/docs/reference/errors.md#unsupported_media_type), [`scope_required`](https://ownrecord.io/docs/reference/errors.md#scope_required), [`idempotency_key_required`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_required), [`idempotency_key_reused`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://ownrecord.io/docs/reference/errors.md#idempotency_in_progress), [`dry_run_not_supported`](https://ownrecord.io/docs/reference/errors.md#dry_run_not_supported), [`rate_limited`](https://ownrecord.io/docs/reference/errors.md#rate_limited), [`internal_error`](https://ownrecord.io/docs/reference/errors.md#internal_error).
