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

# Bookings

> Customer endpoints to create, list, view, and cancel bookings.

# Bookings

Customer-facing booking endpoints. Every endpoint here calls `requireSession`,
so a valid Better Auth session cookie is required. Bookings are scoped to the
signed-in customer — you can only read or cancel your own.

<Info>
  **Base URL:** `https://theroyalglow.in` · **Auth:** Better Auth session;
  **minimum role `customer`** on all endpoints below (any authenticated user is
  at least a customer). Money is an integer in **paise**; dates are `YYYY-MM-DD`;
  times are `HH:mm` (24-hour). Requests without a session return
  `UNAUTHENTICATED` (401).
</Info>

## POST /api/bookings

Creates a booking request for the signed-in customer. The booking is created
with status `pending` and a generated booking number. Pricing and total
duration are computed server-side from the selected services (GST-inclusive
paise), and `endTime` is derived from `startTime` + total duration.

**Minimum role:** `customer` (`requireSession`)

```http theme={null}
POST /api/bookings
Content-Type: application/json
```

### Request body

Validated by `createBookingSchema` (`@rgss/types`).

| Name          | Type       | Required | Description                                                                                                                     |
| ------------- | ---------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `branchId`    | `string`   | Yes      | Non-empty. Branch must exist and have status operational.                                                                       |
| `serviceType` | `enum`     | Yes      | salon or spa. All selected services must match this type.                                                                       |
| `bookingDate` | `string`   | Yes      | YYYY-MM-DD.                                                                                                                     |
| `startTime`   | `string`   | Yes      | HH:mm (24-hour).                                                                                                                |
| `serviceIds`  | `string[]` | Yes      | At least one non-empty id. De-duplicated server-side; every id must be an existing, active service of the matching serviceType. |
| `notes`       | `string`   | No       | Max 500 characters.                                                                                                             |
| `leadId`      | `string`   | No       | Optional Meta-ad lead id for attribution.                                                                                       |

```json theme={null}
{
  "branchId": "br_rayasandra01",
  "serviceType": "salon",
  "bookingDate": "2026-06-15",
  "startTime": "11:00",
  "serviceIds": ["svc_haircut001", "svc_beardtrim01"],
  "notes": "Prefer a window seat if available."
}
```

### Response

Returns `201 Created`. The payload contains the new booking's id, generated
booking number, and status.

```json theme={null}
{
  "success": true,
  "data": {
    "id": "bk_8f2a1c9e4d",
    "bookingNumber": "BK-RS-2606-H-38291",
    "status": "pending"
  }
}
```

The booking number format is `BK-{branchCode}-{YYMM}-{H|S}-{5 digits}` —
`H` for salon, `S` for spa.

### Errors

<AccordionGroup>
  <Accordion title="UNAUTHENTICATED — 401">
    No active session.
  </Accordion>

  <Accordion title="VALIDATION_ERROR — 400">
    Body fails `createBookingSchema`; branch not found or not operational; a service
    id is unknown, inactive, or a type mismatch; or no active staff is available.
  </Accordion>

  <Accordion title="INTERNAL_ERROR — 500">
    Unexpected/transient failure. `retryable: true`.
  </Accordion>
</AccordionGroup>

<Info>
  All pre-condition failures (branch state, service existence/activeness, type
  mismatch, no available staff) are raised as `badRequest`, so they surface as
  `VALIDATION_ERROR` with a 400 — not as booking-domain codes.
</Info>

***

## GET /api/bookings

Lists all bookings for the signed-in customer, newest first. Each booking
includes its `services` (the `booking_service` snapshot rows, ordered by
`displayOrder`).

**Minimum role:** `customer` (`requireSession`)

```http theme={null}
GET /api/bookings
```

### Response

```json theme={null}
{
  "success": true,
  "data": {
    "bookings": [
      {
        "id": "bk_8f2a1c9e4d",
        "bookingNumber": "BK-RS-2606-H-38291",
        "branchId": "br_rayasandra01",
        "customerId": "usr_abc123",
        "status": "pending",
        "serviceType": "salon",
        "bookingDate": "2026-06-15",
        "startTime": "11:00:00",
        "endTime": "12:00:00",
        "totalAmountPaise": 130000,
        "totalDurationMinutes": 60,
        "notes": "Prefer a window seat if available.",
        "isWalkin": false,
        "isMembershipSession": false,
        "offerId": null,
        "spaMembershipId": null,
        "confirmedAt": null,
        "completedAt": null,
        "cancellationReason": null,
        "cancelledAt": null,
        "rejectionReason": null,
        "rejectedAt": null,
        "rescheduleCount": 0,
        "createdAt": "2026-06-01T06:15:00.000Z",
        "updatedAt": "2026-06-01T06:15:00.000Z",
        "services": [
          {
            "id": "bs_1",
            "bookingId": "bk_8f2a1c9e4d",
            "serviceId": "svc_haircut001",
            "staffId": "stf_default01",
            "serviceNameSnapshot": "Signature Haircut",
            "priceAtBookingPaise": 80000,
            "durationMinutes": 45,
            "displayOrder": 0
          }
        ]
      }
    ]
  }
}
```

### Errors

<AccordionGroup>
  <Accordion title="UNAUTHENTICATED — 401">
    No active session.
  </Accordion>

  <Accordion title="INTERNAL_ERROR — 500">
    Unexpected/transient failure. `retryable: true`.
  </Accordion>
</AccordionGroup>

***

## GET /api/bookings/\[id]

Returns a single booking (with its `services`) owned by the signed-in customer.

**Minimum role:** `customer` (`requireSession`)

```http theme={null}
GET /api/bookings/bk_8f2a1c9e4d
```

### Path parameters

| Name | Type     | Required | Description           |
| ---- | -------- | -------- | --------------------- |
| `id` | `string` | Yes      | Path. The booking id. |

<Info>
  If the booking does not exist **or** belongs to another customer, the handler
  returns `404 NOT_FOUND` (not 403) so it never reveals which booking ids exist.
</Info>

### Response

```json theme={null}
{
  "success": true,
  "data": {
    "booking": {
      "id": "bk_8f2a1c9e4d",
      "bookingNumber": "BK-RS-2606-H-38291",
      "branchId": "br_rayasandra01",
      "customerId": "usr_abc123",
      "status": "confirmed",
      "serviceType": "salon",
      "bookingDate": "2026-06-15",
      "startTime": "11:00:00",
      "endTime": "12:00:00",
      "totalAmountPaise": 130000,
      "totalDurationMinutes": 60,
      "notes": null,
      "isWalkin": false,
      "isMembershipSession": false,
      "offerId": null,
      "spaMembershipId": null,
      "confirmedAt": "2026-06-01T07:00:00.000Z",
      "completedAt": null,
      "cancellationReason": null,
      "cancelledAt": null,
      "rejectionReason": null,
      "rejectedAt": null,
      "rescheduleCount": 0,
      "createdAt": "2026-06-01T06:15:00.000Z",
      "updatedAt": "2026-06-01T07:00:00.000Z",
      "services": [
        {
          "id": "bs_1",
          "bookingId": "bk_8f2a1c9e4d",
          "serviceId": "svc_haircut001",
          "staffId": "stf_default01",
          "serviceNameSnapshot": "Signature Haircut",
          "priceAtBookingPaise": 80000,
          "durationMinutes": 45,
          "displayOrder": 0
        }
      ]
    }
  }
}
```

### Errors

<AccordionGroup>
  <Accordion title="UNAUTHENTICATED — 401">
    No active session.
  </Accordion>

  <Accordion title="NOT_FOUND — 404">
    Booking does not exist or is not owned by the caller.
  </Accordion>

  <Accordion title="INTERNAL_ERROR — 500">
    Unexpected/transient failure. `retryable: true`.
  </Accordion>
</AccordionGroup>

***

## POST /api/bookings/\[id]/cancel

Cancels a booking owned by the signed-in customer. Only bookings in status
`pending` or `confirmed` can be cancelled. Sets status to `cancelled` and
records the reason and timestamp.

**Minimum role:** `customer` (`requireSession`)

```http theme={null}
POST /api/bookings/bk_8f2a1c9e4d/cancel
Content-Type: application/json
```

### Path parameters

| Name | Type     | Required | Description           |
| ---- | -------- | -------- | --------------------- |
| `id` | `string` | Yes      | Path. The booking id. |

### Request body

The body is optional and validated by `cancelBookingSchema`. An empty or missing
body is accepted.

| Name     | Type     | Required | Description                                            |
| -------- | -------- | -------- | ------------------------------------------------------ |
| `reason` | `string` | No       | Max 500 characters. Stored as the cancellation reason. |

```json theme={null}
{
  "reason": "Plans changed, will rebook next week."
}
```

### Response

```json theme={null}
{
  "success": true,
  "data": {
    "id": "bk_8f2a1c9e4d",
    "status": "cancelled",
    "cancelledAt": "2026-06-02T09:20:00.000Z"
  }
}
```

### Errors

<AccordionGroup>
  <Accordion title="UNAUTHENTICATED — 401">
    No active session.
  </Accordion>

  <Accordion title="NOT_FOUND — 404">
    Booking does not exist or is not owned by the caller.
  </Accordion>

  <Accordion title="BOOKING_ALREADY_CANCELLED — 409">
    Booking is not in a cancellable status (`pending` or `confirmed`) — e.g. already
    `cancelled`, `completed`, `in_progress`, `no_show`, or `rejected`.
  </Accordion>

  <Accordion title="INTERNAL_ERROR — 500">
    Unexpected/transient failure. `retryable: true`.
  </Accordion>
</AccordionGroup>


## Related topics

- [Low-Level Design](/content/docs/system-design/low-level-design.md)
- [Booking System](/content/docs/features/booking.md)
- [Admin — Bookings](/content/docs/api-reference/admin-bookings.md)
- [Analytics](/content/docs/analytics.md)
- [Admin & Staff Guide](/content/docs/product/admin-staff-guide.md)
