# Submit the customer's details

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

The hosted page's first step: the customer's email, country and, for a business, the company name, tax ID and
address. The tax ID is checked with its register (VIES, HMRC, the Swiss UID register). Then the tax engine
quotes the sale from the location evidence: the billing country, the IP country the page captured, and the
card's country once a payment method is chosen (spec §13.2).

- A sale Ownrecord can tax is quoted (a new quote version; valid for 30 minutes): the customer, their evidence
  set and the quote are stored.
- A sale it can't tax with confidence is paused (spec §1.3): the session becomes `blocked` with the reason and
  `checkout.session.blocked` is emitted; the page offers the waitlist and, where it helps, buying as a
  business. Nothing about the customer is stored then.

Submitting again (other details, or after the quote expired) quotes again. Public: the hosted page calls it
with the session key.

## At a glance

- **REST:** `POST /api/v1/public/checkout_sessions/{sessionId}/details`
- **MCP tool:** `checkout_hosted_submit_details`
- **Operation ID:** `checkout.hosted.submit_details`
- **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      | The customer's email: receipts and invoices go there.                                                                                                                   |
| `name`                        | string                                    | No       | The customer's name.                                                                                                                                                    |
| `country`                     | string                                    | Yes      | The country the customer lives in (pre-filled from the IP address).                                                                                                     |
| `subdivision`                 | string                                    | No       | The state or region, where the regime needs it (US).                                                                                                                    |
| `business`                    | object                                    | No       | Buying for a business: company name, tax ID and billing address (spec §13.2).                                                                                           |
| `business.name`               | string                                    | Yes      |                                                                                                                                                                         |
| `business.taxId`              | object                                    | No       | The company's VAT or tax ID, checked with its register.                                                                                                                 |
| `business.taxId.type`         | string                                    | Yes      | The tax ID's type: `eu_vat`, `gb_vat`, `ch_uid`/`ch_vat`, `no_org`/`no_vat` or `us_ein`. Other types are kept but can't be checked (`unverified`).                      |
| `business.taxId.value`        | string                                    | Yes      | The number as the customer gave it, with or without the country prefix and separators.                                                                                  |
| `business.taxId.country`      | string                                    | Yes      | The country that issued the tax ID (ISO 3166-1 alpha-2; `EL` = Greece).                                                                                                 |
| `business.address`            | object                                    | Yes      |                                                                                                                                                                         |
| `business.address.line1`      | string                                    | Yes      |                                                                                                                                                                         |
| `business.address.line2`      | string                                    | No       |                                                                                                                                                                         |
| `business.address.city`       | string                                    | Yes      |                                                                                                                                                                         |
| `business.address.postalCode` | string                                    | No       |                                                                                                                                                                         |
| `business.address.region`     | string                                    | No       |                                                                                                                                                                         |
| `business.address.country`    | string                                    | Yes      |                                                                                                                                                                         |
| `evidenceToken`               | string                                    | No       | The IP-country evidence the hosted page captured (signed by the server; opaque to clients).                                                                             |
| `promotionCode`               | string or null                            | No       | Subscription sessions: a promotion code to apply (`null` or empty removes the applied one).                                                                             |
| `quantities`                  | array of object                           | No       | New quantities of line items created with `adjustableQuantity`.                                                                                                         |
| `quantities[].lineItemId`     | string                                    | Yes      |                                                                                                                                                                         |
| `quantities[].quantity`       | integer (1 to 1000)                       | Yes      |                                                                                                                                                                         |
| `locale`                      | one of `en`, `de`, `fr`, `hr`, `it`, `es` | No       | The language the customer sees the page in (en, de, fr, hr, it, es). The session keeps it when it has no language yet: the customer, the invoice 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 Germany

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

{
  "key": "Zk3tq8Vb2xQ9mN4rP7sL1yH6cJ0wE5aD-uT_fG8hK2o",
  "email": "anna@example.com",
  "country": "DE"
}
```

Response (`200`):

```json
{
  "id": "cs_01m4tx5nj8emwbyf7y9vcf48aa",
  "object": "checkout.hosted_session",
  "livemode": false,
  "status": "open",
  "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": "anna@example.com",
    "name": null,
    "country": "DE",
    "subdivision": null,
    "business": null
  },
  "quote": {
    "id": "tq_01m4tx5nj8emwbyf7y9vcf48ab",
    "decision": "charge",
    "customerType": "b2c",
    "country": "DE",
    "lines": [
      {
        "id": "1",
        "description": "Genno credits",
        "quantity": 1,
        "treatment": "charge",
        "net": {
          "amount": "84033613",
          "currency": "EUR"
        },
        "tax": {
          "amount": "15966387",
          "currency": "EUR"
        },
        "gross": {
          "amount": "100000000",
          "currency": "EUR"
        },
        "ratePpm": "190000",
        "jurisdictionId": "DE",
        "jurisdictionName": "Germany",
        "taxName": "VAT",
        "regimeId": "EU_OSS_NON_UNION",
        "pendingRegistration": false,
        "taxBehavior": "inclusive"
      }
    ],
    "totals": {
      "net": {
        "amount": "84033613",
        "currency": "EUR"
      },
      "tax": {
        "amount": "15966387",
        "currency": "EUR"
      },
      "gross": {
        "amount": "100000000",
        "currency": "EUR"
      }
    },
    "inclusive": true,
    "reverseCharge": false,
    "reverseChargeWording": null,
    "validUntil": "2026-10-14T10:30:00.000Z",
    "unverifiedRules": false
  },
  "blocked": null,
  "waitlist": null,
  "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"]
  }
}
```

### A consumer where the seller can't sell yet

The UK needs a registration before the first consumer sale: the waitlist is offered.

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

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

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": null,
  "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.                                                                                            |
| [`checkout_business_details_required`](https://ownrecord.io/docs/reference/errors.md#checkout_business_details_required)   | 400         | The session sells to businesses only and no company was given.                                                 | Give the company name and the billing address (street, city, country) when buying as a business (spec §13.2).                                                                                                               |
| [`tax_id_invalid`](https://ownrecord.io/docs/reference/errors.md#tax_id_invalid)                                           | 400         | The business tax ID is malformed for its type (`details.reason`).                                              | Check the number and its country for typing errors (`details.reason` says what is wrong), then send it again. A Northern Ireland business enters its GB VAT number.                                                         |
| [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed)                                     | 400         | A field is missing or malformed, or the email isn't the session's customer's.                                  | Fix the fields listed in `details.issues` and send the request again.                                                                                                                                                       |
| [`upstream_timeout`](https://ownrecord.io/docs/reference/errors.md#upstream_timeout)                                       | 502         | The tax-ID register didn't answer in time. Nothing changed.                                                    | Retry the request with the same Idempotency-Key after a short wait.                                                                                                                                                         |
| [`checkout_promotion_code_not_allowed`](https://ownrecord.io/docs/reference/errors.md#checkout_promotion_code_not_allowed) | 400         | A promotion code on a session that doesn't take them (`allowPromotionCodes`).                                  | Create the session with `allowPromotionCodes: true`, or with `promotionCode` to apply one for the customer. Promotion codes apply to `subscription` sessions.                                                               |
| [`promotion_code_not_redeemable`](https://ownrecord.io/docs/reference/errors.md#promotion_code_not_redeemable)             | 409         | The promotion code is inactive, expired, used up or not valid for this customer (`details.reason`).            | Check `details.reason` and tell the customer: the code may have expired, be used up, belong to another customer, need a larger purchase or be for first-time customers only.                                                |
| [`checkout_quantity_not_adjustable`](https://ownrecord.io/docs/reference/errors.md#checkout_quantity_not_adjustable)       | 400         | A new quantity for a line created without `adjustableQuantity` (`details.line_item_id`).                       | Only line items created with `adjustableQuantity` take a new quantity on the hosted page, within its `min` and `max`.                                                                                                       |
| [`checkout_amount_invalid`](https://ownrecord.io/docs/reference/errors.md#checkout_amount_invalid)                         | 400         | A new quantity is outside the line's `adjustableQuantity` bounds.                                              | Give a quantity from 1 to 1,000 for fixed prices; for a custom-amount price give `customAmount` within the price's minimum and maximum, in whole minor units of its currency, with quantity 1. `param` names the line item. |
| [`customer_deleted`](https://ownrecord.io/docs/reference/errors.md#customer_deleted)                                       | 400         | A top-up's customer was deleted after the session was created.                                                 | Create a new customer for this buyer. Deleted customers stay readable for the records they belong to, but can't be changed.                                                                                                 |

It can also return these [common errors](https://ownrecord.io/docs/reference.md#common-errors): [`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).
