---
title: "Create a guest checkout"
method: POST
path: "/checkouts"
tags: ["Payments"]
---

# Create a guest checkout

`POST /checkouts`

## Request

- Base URL: `https://api.aisle.wedding/v1`
- URL: `https://api.aisle.wedding/v1/checkouts`
- Auth: HTTP bearer

Requires an API key with the payments scope and full access. Call this endpoint only from your server. Send only the returned client_secret and stripe_publishable_key to your browser, load Stripe.js with that key, mount Stripe Elements with the client secret, and call stripe.confirmPayment in the browser. The key is Aisle's: the PaymentIntent is created on Aisle's Stripe account and paid out to the couple, so a publishable key of your own cannot confirm it, and Stripe.js takes no connected account. Never send the Aisle bearer key to browser JavaScript.

Aisle owns admission, ticket, room, instalment, currency, status, and fee values. Only a registry contribution accepts a caller-chosen amount. Accommodation checkouts use the same durable room hold, household share, and recovery rules as Aisle's guest site.

A registry contribution names an invited guest with guest_id, or carries the giver's own contributor_name and contributor_email when they are not on the guest list. Send one or the other. A gift without a guest_id needs the wedding's public_registry_enabled switch, which GET /wedding returns and PATCH /wedding sets; with the switch off the answer is 403. Stripe emails the receipt to contributor_email, and GET /registry/contributions returns the typed name.

A successful response creates a pending Aisle ledger row. Stripe confirmation and Aisle settlement happen asynchronously, so poll GET /payments/{payment_id}. This POST has no general idempotency-key contract. If the response is lost, reconcile with the payment list before deliberately creating another checkout. Do not retry blindly.

## Request body

- union
  - object
    - `type` 'registry_contribution', required
    - `guest_id` string: The invited guest who is giving. Omit it for a giver who is not on the guest list, and send contributor_name and contributor_email instead.
    - `contributor_name` string: Who to thank. Required without a guest_id, and rejected beside one.
    - `contributor_email` string, email: Where Stripe sends the receipt. Required without a guest_id, even for an anonymous gift, and rejected beside one.
    - `registry_item_id` string, required
    - `amount` union, required: The donor-chosen amount, greater than 0 and no more than 10000.
      - number
      - string
    - `message` string, nullable
    - `is_anonymous` boolean
  - object
    - `type` 'accommodation', required
    - `guest_id` string, required
    - `accommodation_id` string, nullable: A room to claim in guest-choice mode. Omit it to use the guest assignment.
    - `pay_in_full` boolean
    - `share` boolean: When true, use the canonical household-share accommodation charge.
  - object
    - `type` 'admission', required
    - `guest_id` string, required
  - object
    - `type` 'ticket', required
    - `guest_id` string, required
    - `event_id` string, required

## Response `200`

Success.

- object
  - `data` Checkout, required
    - `payment_id` string, required
    - `client_secret` string, nullable, required: Pass it to Stripe Elements in the browser. Do not store it as ledger state.
    - `stripe_publishable_key` string, required: Aisle's Stripe publishable key, for loadStripe() in the browser. It is public, and it is the only key that confirms this client_secret.
    - `amount` string, required: A decimal currency amount serialized as a string.
    - `base_amount` string, required: A decimal currency amount serialized as a string.
    - `service_fee` string, required: A decimal currency amount serialized as a string.
    - `currency` string, required
    - `instalment` 'deposit' | 'balance', nullable, required
    - `charge_total` string, nullable, required: A decimal currency amount serialized as a string.
    - `share` boolean, required

## Other responses

- `400`: The request itself could not be read, such as a body that is not a JSON object. A field we refuse is validation_failed instead.
- `401`: The API key is missing, malformed, or no longer valid.
- `402`: The operation requires an active Aisle membership for this wedding.
- `403`: The key is valid but not permitted to do this.
- `404`: No such resource inside the key's wedding.
- `405`: That HTTP method is not supported here. See the Allow header.
- `409`: The request collided with the current state of the resource.
- `415`: A request body must be sent as application/json.
- `422`: The request was well-formed but a field was not acceptable. Every field at fault is named in error.details.
- `429`: Too many requests. Retry after the time given in Retry-After.
- `500`: Something went wrong on our side.

---

[API](https://skmtc.dev/aisle/apis/aisle-api.md) · [All operations](https://skmtc.dev/aisle/apis/aisle-api/llms.txt) · [OpenAPI document](https://skmtc.dev/aisle/apis/aisle-api/revisions/689a2f2420cc?raw)
