# Deletes all linked reservations from a block booking schedule

`DELETE /api/bookings/block-bookings/{scheduleId}`

- **Success:** `200 OK`
- **Products:** Operator (`FOH`)
- **Features:** Front of House Generic Access (`FOHGENERIC`)

HTML version: [Deletes all linked reservations from a block booking schedule](https://support.gladstonesoftware.cloud/reference/bookings/deletes-all-linked-reservations-from-a-block-booking-schedule)

## Overview

Cancels the reservations behind a block booking — a recurring series such as a weekly club night —
in one call, and tidies up the schedule behind them when it can.

`deleteType` decides the scope:

- **`All`** removes every booking in the series, and the schedule itself if nothing had to be
  skipped. `scheduleDeleted` tells you whether the schedule went.
- **`AllFromHere`** removes only the bookings starting on or after `deleteDateFrom`, leaving the
  earlier ones and the schedule in place. The stored recurrence is trimmed at the cut-off at the
  same time, so the occurrences you removed are not regenerated later. Use it to end a series
  early.

Bookings that have been **paid for, or whose invoice has been collated, are never deleted**. They
are reported in `skippedBookings` with a reason and left exactly as they were, so invoiced history
survives. One skipped booking is enough to keep the whole schedule alive even with `All`, because
the retained bookings still point at it.

Everything that can be deleted is deleted in one all-or-nothing operation, and a cancellation
record is kept for each one, carrying `cancellationReasonCodeId` and `cancellationComments`. Those
records are marked as not chargeable, so this call raises no dishonour fee.

Read the response carefully: **both lists carry one entry per booked member, not per booking**, so
a booking with three members on it appears three times, once per sales invoice. Deduplicate on
`bookingId` if you are counting occurrences.

To remove a single occurrence rather than the tail of a series, use the single-reservation delete;
`deleteType` of `ThisDateOnly` is rejected here even though it appears in the list of valid values
in the error message.

## Endpoint

`DELETE {base_url}/api/bookings/block-bookings/{scheduleId}`

`{base_url}` is the environment URL issued to your integration. See [Authenticating with Gladstone APIs](../../guides/authenticating-with-gladstone-apis.md).

## Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `scheduleId` | string (uuid) | Yes | The block booking schedule whose reservations you are cancelling — the `scheduleId` returned when the series was created by [Create a block booking schedule with recurring reservations](create-a-block-booking-schedule-with-recurring-reservations.md). It identifies the whole series. A GUID with no schedule behind it fails with `Schedule with ID '{scheduleId}' not found`. |

## Request body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `deleteType` | string | Yes | How much of the series to remove, matched case-insensitively. `All` deletes every booking and, if none were skipped, the schedule and activity with them; `AllFromHere` deletes only the bookings starting on or after `deleteDateFrom` and keeps the schedule. Required — omitting it fails with `Delete Type must be specified`. Anything unrecognised fails with `Invalid Delete Type '{value}'. Valid values are: All, AllFromHere, ThisDateOnly`; note that the third value in that message is a lie of sorts, because `ThisDateOnly` is then rejected with a `422`. It also governs `deleteDateFrom`: see that field. |
| `deleteDateFrom` | string (date-time) | No | The cut-off for `AllFromHere`: every booking whose start is on or after this moment is removed, and everything earlier is left alone. Required with `AllFromHere` (`DeleteDateFrom must be specified when DeleteType is 'AllFromHere'`) and must be omitted with `All` (`DeleteDateFrom must be null when DeleteType is 'All'`) — the two are strictly paired, so you cannot send both or neither. Compared against each booking's start time, so a cut-off falling mid-way through an occurrence's day removes that occurrence only if it starts at or after the value you send. |
| `cancellationComments` | string | No | Free text written on to the cancellation record kept for each deleted booking — why the series was pulled, who authorised it. **Truncated to 100 characters**, with the last three replaced by an ellipsis, so keep it short. Defaults to `Booking deleted` when omitted. It is recorded against every deleted booking in the request, not per occurrence. |
| `cancellationReasonCodeId` | integer (int32) | Yes | The coded reason the bookings were cancelled, from your system's cancellation reason codes; it is what reporting groups cancellations by. Required — omitting it fails with `Cancellation Reason Code ID must be specified` — and the code must exist **and still be active**, or the request fails with `Cancellation reason code '{id}' is not a valid, active cancellation reason code` before anything is deleted. |

## Sample request

```bash title="cURL"
curl -X DELETE '{base_url}/api/bookings/block-bookings/{scheduleId}' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true' \
  -H 'Content-Type: application/json' \
  -d '{
  "deleteType": "string",
  "deleteDateFrom": "2026-08-14T19:00:00Z",
  "cancellationComments": "string",
  "cancellationReasonCodeId": 12345
}'
```

## Response fields

| Field | Type | Description |
|-------|------|-------------|
| `scheduleId` | string (uuid) | The schedule the request acted on, echoed back from the path. Present even when nothing was deleted. |
| `deletedBookings` | array of object | One entry for every **booked member** that was removed — not one per booking. A booking with three members on it contributes three entries sharing a `bookingId`. Empty when everything was skipped or the series had no bookings left. |
| `deletedBookings[].bookingId` | integer (int32) | The booking that was removed. Repeats across entries when the booking had more than one member on it. |
| `deletedBookings[].salesInvoiceId` | integer (int32) | The sales invoice raised for that member's place on the booking, for reconciling against your own records. `0` when the place had no invoice. The invoice itself is not credited or voided by this call — only unpaid, uncollated bookings reach deletion, so there is nothing to reverse. |
| `deletedBookings[].startDateTime` | string (date-time) | When the deleted occurrence was due to start, as the site's wall-clock time. Useful for reporting what was cancelled, since the bookings no longer exist to be read back. |
| `deletedBookings[].endDateTime` | string (date-time) | When the deleted occurrence was due to end, on the same wall-clock basis as `startDateTime`. |
| `skippedBookings` | array of object | One entry per booked member that was **left in place** because it had been paid for or collated. These bookings still exist and still hold their slots; if you need them gone, resolve the invoice first. Any entry here also prevents the schedule and activity being deleted, even with `deleteType` of `All`. |
| `skippedBookings[].bookingId` | integer (int32) | The booking that was kept. As with `deletedBookings`, it repeats once per member on that booking. |
| `skippedBookings[].salesInvoiceId` | integer (int32) | The sales invoice that caused the booking to be kept — the one to credit, void or collect against before the booking can be removed. |
| `skippedBookings[].reason` | string | Why the booking was kept, as one of two fixed strings: `Booking has been paid` when the member's place or its invoice is anything other than unpaid, or `Booking has a collated invoice` when an unpaid invoice has already been rolled into a collated one. Intended for display and for branching; no other values are produced. |
| `scheduleDeleted` | boolean | Whether the recurring schedule itself was removed. Only ever `true` when `deleteType` was `All` **and** `skippedBookings` is empty; with `AllFromHere` it is always `false`, because the earlier bookings still reference the schedule. When `false`, the schedule remains and can still be amended. |
| `activityDeleted` | boolean | Intended to report that the activity behind the series was removed, but **it is currently always `false`**, including on a full `All` delete that removed the schedule. Do not branch on it. |

## Sample response

```json title="200 OK"
{
  "scheduleId": "b7f3c1e2-9a44-4f2b-8c17-0d5e9a1b6c33",
  "deletedBookings": [
    {
      "bookingId": 12345,
      "salesInvoiceId": 12345,
      "startDateTime": "2026-08-14T19:00:00Z",
      "endDateTime": "2026-08-14T19:00:00Z"
    }
  ],
  "skippedBookings": [
    {
      "bookingId": 12345,
      "salesInvoiceId": 12345,
      "reason": "Booking has been paid"
    }
  ],
  "scheduleDeleted": false,
  "activityDeleted": false
}
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | `deleteType` is missing or unusable — `Delete Type must be specified`, or `Invalid Delete Type '{value}'. Valid values are: All, AllFromHere, ThisDateOnly`. |
| `400` | Bad request | `deleteDateFrom` does not match `deleteType` — `DeleteDateFrom must be null when DeleteType is 'All'`, or `DeleteDateFrom must be specified when DeleteType is 'AllFromHere'`. |
| `400` | Bad request | The cancellation reason is missing or unusable — `Cancellation Reason Code ID must be specified`, or `Cancellation reason code '{id}' is not a valid, active cancellation reason code`. Nothing is deleted. |
| `400` | Bad request | Deletion failed — `A database error occurred while deleting the block bookings`. Deletion is all-or-nothing, so nothing was removed. |
| `404` | Not found | No block booking schedule has that id — `Schedule with ID '{scheduleId}' not found`. Also what you get on a second `All` delete, once the first has removed the schedule. |
| `422` | Unprocessable entity | `deleteType` was `ThisDateOnly` — `Delete Type 'ThisDateOnly' is not supported for delete operations`. The value is recognised, which is why it is listed as valid in the `400` message, but this endpoint cannot act on a single occurrence. |
| `500` | Internal server error | An unexpected server-side failure, with an empty body. |
