# Creating a booking

These endpoints create a booking, in the order described in the
[booking flow](https://developers.cliento.com/docs/widget-api/booking-flow.md). The reserve call returns a reservation id, the
`cbUuid`. Pass it in every following call.

## Reserve a slot

```
POST /booking/reserve
```

Holds a slot so no one else can book it while the customer fills in their
details.

**Request**

| Field | Required | Description |
| --- | --- | --- |
| `slotKey` | Yes | The `key` of a slot from the [slots endpoint](https://developers.cliento.com/docs/widget-api/availability.md) |
| `cbUuid` | No | Your current reservation id, when the customer picks a new time. That hold is released before the new one is made |
| `captchaResponse` | With captcha | A reCAPTCHA token when the account requires one, otherwise `null`, see [Captcha](https://developers.cliento.com/docs/widget-api.md#captcha) |

```json
{
  "slotKey": "MzE3MToxMjgxNjo2ODgxMToxNzkzMzQ3MjAwMDAwOjQ1OmZhbHNlOjU5NS4wMDpOVUxMOg"
}
```

**Response 200**

```json
{
  "cbUuid": "4674c65b-a64f-43a5-94c7-af3b59053cc6",
  "cbRef": "mK0k22O3",
  "reservationExpiry": "2026-10-23T09:46:24Z",
  "services": [
    { "id": 68811, "name": "Women's haircut", "price": 595.0, "priceFrom": false, "duration": 45 }
  ],
  "price": 595.0
}
```

The `cbUuid` in the response is the id of the new reservation. Pass it in all
following calls. `cbRef` is the short booking reference shown to the customer.
The reservation expires at `reservationExpiry`, about five minutes after the
call.

**Errors**

| Status | When |
| --- | --- |
| 410 | The slot is already taken or held by someone else. Fetch slots again |

## Release a reservation

```
POST /booking/release
```

Releases a held slot. Call it when the customer abandons the booking, so the slot
opens up for others right away. A new reserve call with the current `cbUuid`
releases the old hold by itself. Reservations that are
not released expire on their own.

**Request**

```json
{ "cbUuid": "4674c65b-a64f-43a5-94c7-af3b59053cc6" }
```

**Response 204**

No body.

## Add customer details

```
POST /booking/customer
```

Attaches the customer's details to the reservation.

**Request**

| Field | Required | Description |
| --- | --- | --- |
| `cbUuid` | Yes | The reservation to attach the customer to |
| `name` | Yes | Full name |
| `phone` | Yes | Mobile number in E.164 format, for example `+46701234567` |
| `email` | See settings | Required when `web_requireEmail` is on |
| `note` | No | Message from the customer, free text |
| `personalNumber` | See settings | Swedish personal identity number, required when `web_requirePNo` is on |
| `personalNumberType` | With `personalNumber` | `SE_PNO`, or `INTL_PNO` for a foreign number |
| `orgName`, `orgNo` | No | Company name and organisation number for company bookings |
| `orgNoType` | With `orgNo` | `SE_ORG` |
| `vehicleRegNo` | See settings | Vehicle registration number, used by workshops |
| `vehicleRegNoType` | With `vehicleRegNo` | `SE_VEHICLE` |
| `customFields` | No | Answers to the account's [custom fields](https://developers.cliento.com/docs/widget-api/reference-data.md#fetch-custom-fields), a list of `{key, type, label, value}` |
| `allowMarketing` | No | The customer accepted marketing |
| `bookedSpecificResource` | No | `true` when the customer picked a specific resource, `false` when your UI picked one for them |
| `captchaResponse` | With captcha | A reCAPTCHA token when the account requires one, otherwise `null`, see [Captcha](https://developers.cliento.com/docs/widget-api.md#captcha) |

```json
{
  "cbUuid": "4674c65b-a64f-43a5-94c7-af3b59053cc6",
  "name": "Test Testsson",
  "phone": "+46701234567",
  "email": "test@example.com",
  "note": "",
  "customFields": [],
  "allowMarketing": false,
  "bookedSpecificResource": false
}
```

**Response 200**

The body has no information.

The account decides which fields your form must collect. Read that from the
preferences and features in its [settings](https://developers.cliento.com/docs/widget-api/reference-data.md#fetch-settings).

**Errors**

| Status | When |
| --- | --- |
| 404 | The `cbUuid` has no active reservation |

## Get confirmation options

```
POST /booking/confirmation-options
```

Call this after the customer details are saved. It tells you how the booking
must be confirmed, and triggers the confirmation PIN SMS when the account uses
SMS verification.

**Request**

```json
{ "cbUuid": "4674c65b-a64f-43a5-94c7-af3b59053cc6" }
```

**Response 200**

```json
{
  "cbUuid": "4674c65b-a64f-43a5-94c7-af3b59053cc6",
  "cbRef": "mK0k22O3",
  "reservationExpiry": "2026-10-23T09:46:24Z",
  "confirmationMethod": "NoPin",
  "paymentAmountIncVat": null,
  "paymentProviders": [],
  "allowDiscountVoucher": false,
  "saleItems": [],
  "stripeDestAccountId": null,
  "demoPin": null,
  "attributes": { "pbk_allowMarketing": false },
  "prefs": { "...": "same preference object as in settings, shortened here" }
}
```

| Field | Description |
| --- | --- |
| `confirmationMethod` | `NoPin`, `Pin` or `Payment`, see the [booking flow](https://developers.cliento.com/docs/widget-api/booking-flow.md#5-get-confirmation-options) |
| `paymentAmountIncVat` | Amount to pay online, `null` when no payment is required |
| `paymentProviders` | Available payment providers when payment is required: `Stripe`, `Swish`, `Klarna`, `PayOnSite` and `None`, see [Payments](https://developers.cliento.com/docs/widget-api/payments.md#when-payment-is-required) |
| `allowDiscountVoucher` | The customer may enter a discount or gift card code |
| `saleItems` | Line items for the payment |
| `stripeDestAccountId` | The Stripe account to charge when `Stripe` is a provider, otherwise `null` |
| `demoPin` | The PIN to confirm with on a demo account. `null` on every other account |

The call does not send a PIN SMS when the method is `Payment`, even on
accounts with SMS verification. See [Payments](https://developers.cliento.com/docs/widget-api/payments.md) for how the
PIN is requested when the customer chooses to pay on site.

A demo account is a test account that Cliento has set to send no messages. So it sends no PIN
by SMS. When a booking needs a PIN, a demo account returns it in `demoPin` instead. Show it to
the visitor and confirm with it.

## Confirm the booking

```
POST /booking/confirm
```

Turns the reservation into a real booking. Use this when `confirmationMethod`
is `NoPin` or `Pin`. Bookings that require payment are instead completed with
[`/booking/pay`](https://developers.cliento.com/docs/widget-api/payment-endpoints.md#pay-and-confirm), see
[Payments](https://developers.cliento.com/docs/widget-api/payments.md).

**Request**

| Field | Required | Description |
| --- | --- | --- |
| `cbUuid` | Yes | The reservation to confirm |
| `pin` | With `Pin` | The PIN code from the SMS. Send `null` when the method is `NoPin` |
| `captchaResponse` | With captcha | A reCAPTCHA token when the account requires one, otherwise `null`, see [Captcha](https://developers.cliento.com/docs/widget-api.md#captcha) |

```json
{ "cbUuid": "4674c65b-a64f-43a5-94c7-af3b59053cc6", "pin": null }
```

**Response 201**

```json
{
  "cbUuid": "4674c65b-a64f-43a5-94c7-af3b59053cc6",
  "cbRef": "mK0k22O3",
  "smsReminderEnabled": true,
  "emailConfirmSent": true,
  "smsConfirmSent": true,
  "paymentStatus": "Unpaid",
  "paymentProvider": "None"
}
```

The booking now exists in the calendar. Cliento sends the confirmation and
reminder messages; your client does not need to. Store `cbUuid` if your
client needs to look up or cancel the booking later, see
[Retrieving and cancelling a booking](https://developers.cliento.com/docs/widget-api/manage-booking.md). `cbRef` is the
booking reference shown to the customer, and a good transaction id for your
own tracking.

**Errors**

| Status | When |
| --- | --- |
| 402 | The booking requires payment. Use `/booking/pay` instead, see [Payments](https://developers.cliento.com/docs/widget-api/payments.md) |
| 403 | The PIN code was wrong. The reservation is still held, let the customer try again |
| 404 | The reservation expired or was released before the call. Reserve a new slot |
| 418 | The request was refused and the reservation is gone. Reserve a new slot |
