> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thecleanlife.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Booking

> POST /partners/bookings — Create a new booking.

## Overview

Creates a new booking on the CleanLife platform on behalf of one of your customers. This is the core endpoint of the Partner API.

The booking creation flow varies based on your partner account's `paymentResponsibility` setting:

* **`CLEANOS` responsibility:** CleanLife handles payment. Depending on the service price, the booking may transition to `waiting payment` (CleanLife sends a payment link asynchronously) or directly to `in progress` (free service).
* **`PARTNER` responsibility:** Your system handles payment. The booking is set to `in progress` immediately, bypassing CleanLife payment processing. You are expected to confirm payment later via `POST /partners/bookings/:bookingId/confirm-payment`.

***

## Endpoint

```
POST /partners/bookings
```

## Authentication

Requires a valid API Key with the `partner_bookings_create` permission.

## Request Headers

| Header         | Required | Value                |
| -------------- | -------- | -------------------- |
| `x-api-key`    | Yes      | Your partner API key |
| `Content-Type` | Yes      | `application/json`   |

***

## Request Body

```json theme={null}
{
  "externalReference": "ORDER-12345",
  "contactId": "00000000-0000-0000-0000-000000000001",
  "addressId": "00000000-0000-0000-0000-000000000002",
  "serviceId": "00000000-0000-0000-0000-000000000004",
  "date": "2026-06-20",
  "timeslot": {
    "startAt": "09:00",
    "endAt": "12:00"
  }
}
```

### Field Reference

| Field               | Type            | Required | Description                                                                                                                                                          |
| ------------------- | --------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `contactId`         | UUID            | **Yes**  | Customer contact ID from `POST /partners/contacts` (`data.id`).                                                                                                      |
| `addressId`         | string (UUID)   | **Yes**  | Service address ID from `POST /partners/contacts` (`data.addressId`) or an existing address on the contact.                                                          |
| `serviceId`         | UUID            | **Yes**  | Service ID from `GET /partners/services?addressId=...`. Must be available at the booking address. Category is resolved automatically — do **not** send `categoryId`. |
| `timeslot`          | object          | **Yes**  | Appointment timeslot.                                                                                                                                                |
| `timeslot.startAt`  | string          | **Yes**  | Start time in `HH:MM` or `HH:MM:SS` format (Riyadh local time).                                                                                                      |
| `timeslot.endAt`    | string          | **Yes**  | End time in `HH:MM` or `HH:MM:SS` format (Riyadh local time).                                                                                                        |
| `date`              | ISO date string | **Yes**  | Service date in `YYYY-MM-DD` format (Riyadh local date).                                                                                                             |
| `externalReference` | string          | No       | Your own reference ID for this booking (e.g., your internal order number). Must be unique per partner. Max 150 characters.                                           |

***

## Example Request

```bash theme={null}
curl -X POST "https://apiv3.thecleanlife.dev/v1/partners/bookings" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "externalReference": "ORDER-20260615-001",
    "contactId": "aaaaaaaa-0000-0000-0000-000000000001",
    "addressId": "bbbbbbbb-0000-0000-0000-000000000002",
    "serviceId": "dddddddd-0000-0000-0000-000000000004",
    "date": "2026-06-20",
    "timeslot": {
      "startAt": "09:00",
      "endAt": "12:00"
    }
  }'
```

***

## Success Response

**HTTP Status:** `200 OK`

```json theme={null}
{
  "success": true,
  "data": {
    "bookingId": "11111111-0000-0000-0000-000000000001",
    "externalReference": "ORDER-20260615-001",
    "appointmentId": "22222222-0000-0000-0000-000000000002",
    "status": "in progress",
    "paymentStatus": "NOT_REQUIRED",
    "trackingReference": "SA-0042",
    "date": "2026-06-20T00:00:00.000Z",
    "timeslot": {
      "startAt": "09:00",
      "endAt": "12:00",
      "endsAtNextDay": false
    },
    "appointment": {
      "id": "22222222-0000-0000-0000-000000000002",
      "name": "SA-0042",
      "status": "Scheduled",
      "scheduledStartDateTime": "2026-06-20T09:00:00+03:00",
      "scheduledEndDateTime": "2026-06-20T12:00:00+03:00"
    }
  }
}
```

### Response Fields

| Field                    | Type          | Description                                                                                                         |
| ------------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------- |
| `bookingId`              | UUID          | CleanLife booking ID. Use this for all subsequent booking operations.                                               |
| `externalReference`      | string / null | The `externalReference` you provided, or `null` if not provided.                                                    |
| `appointmentId`          | UUID / null   | The service appointment ID, or `null` if not yet scheduled.                                                         |
| `status`                 | string        | Booking status. See [Booking Statuses](#booking-statuses).                                                          |
| `paymentStatus`          | string        | Payment status. See [Payment Statuses](#payment-statuses).                                                          |
| `trackingReference`      | string        | A human-readable reference (usually the service appointment name). Use this when communicating with your customers. |
| `date`                   | date          | The service date.                                                                                                   |
| `timeslot.startAt`       | string        | Start time of the appointment.                                                                                      |
| `timeslot.endAt`         | string        | End time of the appointment.                                                                                        |
| `timeslot.endsAtNextDay` | boolean       | `true` if the appointment spans midnight.                                                                           |
| `appointment`            | object / null | Appointment details if assigned, otherwise `null`.                                                                  |
| `appointment.status`     | string        | See [Appointment Statuses](#appointment-statuses).                                                                  |

### Booking Statuses

| Status            | Description                                                                 |
| ----------------- | --------------------------------------------------------------------------- |
| `in progress`     | Booking is active and the service has been scheduled.                       |
| `waiting payment` | Booking is pending payment from the customer (CLEANOS responsibility only). |
| `success`         | Service was completed successfully.                                         |
| `canceled`        | Booking was cancelled.                                                      |
| `failed`          | Booking failed (payment or validation error).                               |

### Payment Statuses

| Status         | Description                                                                                                                                                  |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `NOT_REQUIRED` | No payment needed (free service or no-payment-model).                                                                                                        |
| `PENDING`      | Payment has not yet been confirmed. For PARTNER responsibility: awaiting your `confirm-payment` call. For CLEANOS responsibility: awaiting customer payment. |
| `PAID`         | Payment has been confirmed (either CleanLife payment record exists, or partner called `confirm-payment`).                                                    |
| `FAILED`       | Payment process failed.                                                                                                                                      |
| `CANCELLED`    | Booking was cancelled.                                                                                                                                       |

### Appointment Statuses

| Status            | Description                              |
| ----------------- | ---------------------------------------- |
| `New`             | Appointment created, not yet scheduled.  |
| `Scheduled`       | Appointment has been assigned to a team. |
| `Confirmed`       | Appointment confirmed.                   |
| `In The Way`      | Team is traveling to the location.       |
| `In The location` | Team has arrived.                        |
| `In Progress`     | Service is underway.                     |
| `Finished`        | Service work is done.                    |
| `Completed`       | Appointment fully completed.             |
| `Cannot Complete` | Team could not complete the service.     |
| `Cancelled`       | Appointment was cancelled.               |

***

## Error Responses

| HTTP Status | Code                                         | Description                                                                   |
| ----------- | -------------------------------------------- | ----------------------------------------------------------------------------- |
| `400`       | `VALIDATION_ERROR`                           | One or more required fields are missing or invalid (e.g. missing `serviceId`) |
| `401`       | `UNAUTHORIZED`                               | Invalid or missing API key                                                    |
| `403`       | `FORBIDDEN`                                  | Missing `partner_bookings_create` permission                                  |
| `404`       | `RESOURCE_NOT_FOUND` / `SERVICE_NOT_ALLOWED` | `serviceId` not found or not enabled for your partner account                 |
| `409`       | `DUPLICATE_EXTERNAL_REFERENCE`               | The `externalReference` is already used by another booking under your account |
| `422`       | `BOOKING_CREATION_FAILED`                    | The booking could not be completed — typically a payment or validation error  |

***

## Business Rules

1. **`externalReference` uniqueness:** If you provide an `externalReference`, it must be unique across all bookings for your partner account. Duplicate values result in a `409` error. This is your primary tool for preventing duplicate bookings — generate a unique ID on your side before calling the API.

2. **`serviceId` is required.** Choose a `serviceId` from `GET /partners/services?addressId=...` for the same address. Do not send `categoryId` — the platform resolves the service category automatically.

3. **Partner-specific pricing.** You do not send a price in the request. The booking amount is determined by the price configured for your partner account for the selected service (returned in `GET /partners/services`). A catalog price of `0` means **deferred payment** — the booking is created and confirmed immediately (`success`) with no upfront payment.

4. **`contactId` is required.** Obtain it from `POST /partners/contacts` before creating a booking.

5. **Timeslot interpretation.** All timeslot times (`startAt`, `endAt`) are interpreted as **Asia/Riyadh local time** (UTC+3).

6. **Payment flow — CLEANOS responsibility:**
   * If the booking total is zero (free service), it goes directly to `in progress`.
   * If the booking requires payment, CleanLife sends a payment link asynchronously. The booking enters `waiting payment`. Poll `GET /partners/bookings/:bookingId/status` to track payment outcome.

7. **Payment flow — PARTNER responsibility:**
   * The booking is immediately set to `in progress`.
   * You must call `POST /partners/bookings/:bookingId/confirm-payment` once you collect payment from your customer.

8. **Failed reference save.** In the rare event that a booking is created but the partner reference cannot be saved, the booking is marked as `FAILED` so you can safely retry with the same `externalReference`.

***

## Notes

* The `appointmentId` may be `null` immediately after creation in some scheduling flows. Poll `GET /partners/bookings/:bookingId/status` until an appointment is assigned.
* The `trackingReference` is the value you should display to your customers for tracking purposes.
* Do not rely on the `appointment` object being present at creation time.

***

## Integration Tips

* Always use `externalReference` to tie CleanLife bookings back to your internal orders. Without it, deduplication on retry is much harder.
* Call `POST /partners/contacts` first, then pass the returned `id` as `contactId` and `addressId` in this request.
* List bookable services with `GET /partners/services?addressId=...` using the same address. Use the returned `price` as the amount to charge your customer.
* Verify available timeslots first using `GET /partners/timeslots/available` before creating a booking.

***

## Common Mistakes

| Mistake                                            | Consequence                                                                  | Fix                                                                                                                                         |
| -------------------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| Not providing `externalReference`                  | Cannot deduplicate retries                                                   | Always generate and pass a unique reference                                                                                                 |
| Not calling `POST /partners/contacts` first        | Missing or invalid `contactId` / `addressId`                                 | Register the customer via contacts before booking                                                                                           |
| Using `HH:MM:SS` vs `HH:MM` inconsistently         | Both formats are accepted                                                    | Use `HH:MM` for consistency                                                                                                                 |
| Passing a date in UTC instead of Riyadh local      | Booking created on wrong date                                                | Always use `YYYY-MM-DD` in Riyadh local time                                                                                                |
| Reusing `externalReference` after a failed booking | `409 DUPLICATE_EXTERNAL_REFERENCE` if the failed booking reference was saved | The system compensates failed orphaned bookings; if you receive `422 BOOKING_CREATION_FAILED`, the reference is not saved and you can retry |

***

## Related Endpoints

* `POST /partners/contacts` — Create contact and optional address; returns `id` (as `contactId`) and `addressId`
* `GET /partners/services?addressId=...` — List services available at the booking address
* `GET /partners/bookings/:bookingId/status` — Poll booking status
* `PATCH /partners/bookings/:bookingId/cancel` — Cancel the booking
* `POST /partners/bookings/:bookingId/confirm-payment` — Confirm payment (PARTNER responsibility only)
