# Create a new booking

`POST /api/bookings`

- **Success:** `200 OK`
- **Products:** Operator (`FOH`), Consumer (`CONSUMER`) (any one of these products, not all)
- **Features:** Online Bookings (`ONLINEBOOK`), Front of House Generic Access (`FOHGENERIC`) (any one of these features, not all)

HTML version: [Create a new booking](https://support.gladstonesoftware.cloud/reference/bookings/create-a-new-booking)

## Overview

Converts one or more temporary booking leases into confirmed bookings, generating the
associated sales invoices in the process. This is the final call in the booking flow —
by the time you reach it you must already hold a valid lease and a matching pricing quote.

Because a lease expires, treat this call as time-sensitive: if it returns `422`, the slot
was taken or the lease lapsed between quoting and confirming, and you must restart from
availability.

**Use this endpoint to:**

- Complete a booking from a lease you created earlier
- Confirm several slots in a single atomic-per-item request
- Generate invoices and payment records alongside the booking
- Finalise group bookings that include additional bookees

Authenticate first — see [Authenticating with Gladstone APIs](../../guides/authenticating-with-gladstone-apis.md).

## Endpoint

`POST {base_url}/api/bookings`

`{base_url}` is the environment URL issued to your integration, for example
`https://yourorganisation.gladstonego.cloud`.

## Request headers

| Name | Required | Description |
|------|----------|-------------|
| `Authorization` | Yes | `Bearer {accessToken}` from [API Key Authentication](../../guides/api-key-authentication.md). |
| `X-Use-SSO` | Yes | Always `true` for partner integrations. |
| `Content-Type` | Yes | `application/json` |

## Request body

The body wraps a list, so a single request can confirm several leases at once.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `bookings` | array | Yes | One entry per lease being confirmed. An empty array is rejected with `400`. |
| `bookings[].leaseId` | string | Yes | The lease returned by the create-lease call. Single-use — a lease cannot be confirmed twice. |
| `bookings[].bookingId` | integer | No | Existing booking id when amending rather than creating. Omit or send `0` for a new booking. |
| `bookings[].memberId` | integer | Yes | The member the booking belongs to. |
| `bookings[].payingMemberId` | integer | No | The member being charged, when this differs from `memberId` — for example a parent paying for a child. Defaults to `memberId`. |
| `bookings[].pricingQuote` | object | Yes | The signed quote obtained from pricing. Must match the lease, or the request is rejected. |
| `bookings[].pricingQuote.memberId` | integer | Yes | Member the quote was issued for. |
| `bookings[].pricingQuote.totalPrice.amount` | decimal | Yes | Total amount payable. |
| `bookings[].pricingQuote.totalPrice.currency` | string | Yes | ISO currency code. Maximum 10 characters. |
| `bookings[].pricingQuote.breakdown` | object | No | Per-price-level breakdown of the total. |
| `bookings[].pricingQuote.paidForbyUsageSub` | string | No | Set when the booking is covered by a usage-based subscription rather than being charged. |
| `bookings[].pricingQuote.usagesRemaining` | integer | No | Remaining usages on the covering subscription. |
| `bookings[].pricingQuote.signature` | string | Yes | Signature over the quote. Pass through unchanged. |

The `pricingQuote` is signed. Do not construct or modify it by hand — pass through
the object exactly as pricing returned it, or the signature check fails.

## Sample request

```bash title="cURL"
curl -X POST 'https://yourorganisation.gladstonego.cloud/api/bookings' \
  -H 'Authorization: Bearer eyJhbGciOi...' \
  -H 'X-Use-SSO: true' \
  -H 'Content-Type: application/json' \
  -d '{
    "bookings": [
      {
        "leaseId": "b7f3c1e2-9a44-4f2b-8c17-0d5e9a1b6c33",
        "memberId": 104728,
        "payingMemberId": 104728,
        "pricingQuote": {
          "memberId": 104728,
          "totalPrice": { "amount": 8.50, "currency": "GBP" },
          "breakdown": {
            "currency": "GBP",
            "memberPrice": {
              "priceLevelId": "PL-STD",
              "totalPrice": 8.50,
              "productPrices": [
                {
                  "id": "PRD-BADMIN-45",
                  "quantity": 1,
                  "timeBandId": "TB-PEAK",
                  "amount": 8.50,
                  "taxCodeId": "T-STD",
                  "taxRate": 20.0
                }
              ]
            }
          },
          "signature": "9f2b...c41a"
        }
      }
    ]
  }'
```

## Response fields

| Field | Type | Description |
|-------|------|-------------|
| `bookings` | array | One entry per confirmed booking. |
| `bookings[].leaseID` | string | The lease that was consumed. Use it to correlate the response back to your request. |
| `bookings[].slotReference` | string | Reference for the booked slot. |
| `bookings[].bookingID` | integer | The new booking's internal id. Use this for amend and cancel calls. |
| `bookings[].bookingRef` | integer | Customer-facing booking reference. Null when the site does not issue one. |
| `bookings[].salesInvoiceIds` | array | Ids of the invoices raised. Pass these to the payment endpoints to collect payment. |
| `bookings[].bookeePriceLevels` | array | Price level applied to each bookee. |
| `bookings[].keyBookeeBookingInfo` | object | Details of the primary bookee. |
| `discountDetails` | array | Discounts applied across the request. |
| `discountDetails[].slotReference` | string | Slot the discount applied to. |
| `discountDetails[].discountType` | string | The kind of discount applied. |
| `discountDetails[].discountAmount` | decimal | Amount deducted. |

## Sample response

```json title="200 OK"
{
  "bookings": [
    {
      "leaseID": "b7f3c1e2-9a44-4f2b-8c17-0d5e9a1b6c33",
      "slotReference": "SLT-2026-08-14-1900-BC2",
      "bookingID": 8842190,
      "bookingRef": 449281,
      "salesInvoiceIds": [ 1290844 ],
      "bookeePriceLevels": [
        { "id": "PL-STD", "description": "Standard", "count": 1, "price": 8.50 }
      ],
      "keyBookeeBookingInfo": {
        "priceLevelId": "PL-STD",
        "price": 8.50
      }
    }
  ],
  "discountDetails": []
}
```

```json title="422 Unprocessable Entity"
{
  "unprocessableBookings": [
    {
      "memberId": 104728,
      "slotReference": "SLT-2026-08-14-1900-BC2",
      "unprocessableReason": "LeaseExpired"
    }
  ]
}
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | The body is missing, `bookings` is empty, or a required field is absent. |
| `401` | Unauthorized | Missing, expired or out-of-scope bearer token. |
| `422` | Unprocessable entity | The request was well-formed but one or more bookings could not be created — expired lease, slot taken, or a pricing quote that no longer matches. Inspect `unprocessableBookings[].unprocessableReason` per item. |
| `429` | Too many requests | Rate limit exceeded. Honour the `Retry-After` header. |
| `500` | Internal server error | Unexpected failure. Safe to retry once with the same lease; if the lease was consumed you will receive `422`. |

A `422` is **partial** — some bookings in the request may have succeeded. Always reconcile
the returned `bookings` array against what you sent rather than assuming all-or-nothing.
