# Promotes a member from an alert list

`POST /api/bookings/{memberId}/promote-from-alert-list/{bookingId}`

- **Success:** `201 Created`
- **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: [Promotes a member from an alert list](https://support.gladstonesoftware.cloud/reference/bookings/promotes-a-member-from-an-alert-list)

## Overview

Converts a member's place on an alert list (waiting list) into a confirmed booking. Reach for this when a space is released on a full class and you want to move a specific waiting member onto it.

You send nothing but the two route values. The endpoint does the rest in one call: it prices the booking for that member — including any additional bookees already recorded against their alert-list entry — and then creates the booking. There is no lease and no separate pricing call, so none of the usual [pricing quote](../../guides/glossary.md) handling applies here. The member is recorded as paying for themselves; you cannot nominate a different paying member through this endpoint.

The booking is created **unpaid**. Any sales invoices raised are returned in `bookings[].salesInvoiceIds` and must be settled through the payments endpoints separately.

Two behaviours to plan for. The call is not idempotent — once a member has been promoted they are no longer on the alert list, so calling again fails. And the response has the same shape as the booking-creation response, so several of its fields describe a lease-based creation flow that does not apply here; see the field notes below.

## Endpoint

`POST {base_url}/api/bookings/{memberId}/promote-from-alert-list/{bookingId}`

`{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 |
|------|------|----------|-------------|
| `memberId` | integer (int32) | Yes | The member to promote. They must already hold an alert-list place on `bookingId` — this endpoint cannot add someone to a booking they were not queuing for. Pricing is calculated for this member, and they are also recorded as the paying member. |
| `bookingId` | integer (int32) | Yes | The booking to promote them onto — one dated instance of a class or activity, not the activity itself. It is used to build the pricing quote, so it must exist. For a class, take the value from the `bookingId` field inside the JSON `slotReferences` string returned by the sessions endpoints, such as [List all available sessions for a specific member](list-all-available-sessions-for-a-specific-member.md). |

## Sample request

```bash title="cURL"
curl -X POST '{base_url}/api/bookings/{memberId}/promote-from-alert-list/{bookingId}' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true'
```

## Response fields

| Field | Type | Description |
|-------|------|-------------|
| `memberId` | integer (int32) | **Not returned by this endpoint** — the response carries only `bookings` and `discountDetails`. Do not read this field; use the `memberId` you sent in the path. |
| `guardianMemberId` | integer (int32) | Never returned. As with `memberId`, it is not part of the response. |
| `bookings` | array of object | The bookings created by the promotion. This endpoint promotes one member onto one booking, so expect exactly one entry, for the `bookingId` you sent. |
| `bookings[].leaseID` | string | The [lease](../../guides/glossary.md) a booking was created from, in the shared create-booking response. Promotion works from an existing booking id rather than a lease, so no lease id is sent and none comes back. |
| `bookings[].slotReference` | string | The [slot reference](../../guides/glossary.md) the booking occupies, as an opaque JSON string. It is the key that ties an entry in `discountDetails` back to its booking. Treat it as a black box. |
| `bookings[].bookingID` | integer (int32) | The id of the booking the member now holds. It matches the `bookingId` you sent, and is the value to use for later calls such as marking attendance. |
| `bookings[].bookingRef` | integer (int32) | The customer-facing [booking reference](../../guides/glossary.md) for the member's place, distinct from `bookingID`. Nullable — not every site issues one. |
| `bookings[].salesInvoiceIds` | array of integer | The sales invoices raised for the booking. They are created **unpaid**, so a successful promotion does not mean the member has paid; pass these ids to the payments endpoints to settle them. Empty when the booking is zero-priced. If a multi-person discount was applied, the discounted invoice ids are appended here as well. |
| `bookings[].bookeePriceLevels` | array of object | What was charged, grouped by [price level](../../guides/glossary.md). For a party booking there is one entry per distinct price level across all bookees; for a single-person booking there is exactly one entry, taken from the pricing quote generated for the promotion. |
| `bookings[].bookeePriceLevels[].id` | string | The price level identifier, such as the adult or junior band the bookees were charged at. |
| `bookings[].bookeePriceLevels[].description` | string | The display name for the price level. A site- or activity-specific override is used when one is configured; otherwise the global description. Null if the price level has no description at either level. |
| `bookings[].bookeePriceLevels[].count` | integer (int32) | How many bookees were charged at this price level. Always `1` for a single-person booking. |
| `bookings[].bookeePriceLevels[].price` | number (double) | The total charged for all `count` bookees at this price level, not the per-bookee price. |
| `bookings[].bookeePriceLevels[].translations` | array of object | Translated forms of `description`, for tenants running more than one language. Null when the price level has no description configured. |
| `bookings[].bookeePriceLevels[].translations[].type` | string | |
| `bookings[].bookeePriceLevels[].translations[].culture` | string | The culture the translated text belongs to, used to pick the right variant for the member's language. |
| `bookings[].bookeePriceLevels[].translations[].text` | string | The translated text for that culture — use it in place of `description` when you are rendering in that language. |
| `bookings[].keyBookeeBookingInfo` | object | What the member themselves was charged, as opposed to their guests. The *key bookee* is the person the booking is in the name of. On a booking with no party records the member is by definition the key bookee, so this mirrors the single entry in `bookeePriceLevels`. On a party booking it is null when the member is paying for others but not attending. |
| `bookings[].keyBookeeBookingInfo.priceLevelId` | string | The price level the key bookee's own place was charged at. |
| `bookings[].keyBookeeBookingInfo.price` | number (double) | The total charged for the key bookee's own place. Nullable. |
| `discountDetails` | array of object | Booking discounts that were applied while creating the booking. Only present when the booking discounts feature is enabled for the tenant and a discount actually matched; otherwise the array is empty. One entry per booking that received a discount. |
| `discountDetails[].slotReference` | string | The slot reference of the booking this discount was applied to. Match it against `bookings[].slotReference` to work out which booking a discount belongs to. |
| `discountDetails[].discountType` | string | The kind of discount applied. Currently always `MultiPerson`, the discount for booking several people onto one slot. |
| `discountDetails[].discountAmount` | number (double) | The total value taken off across the discounted invoices for that booking. Nullable. |

## Sample response

```json title="201 Created"
{
  "memberId": 12345,
  "guardianMemberId": 12345,
  "bookings": [
    {
      "leaseID": "string",
      "slotReference": "string",
      "bookingID": 12345,
      "bookingRef": 1,
      "salesInvoiceIds": [
        12345
      ],
      "bookeePriceLevels": [
        {
          "id": "string",
          "description": "string",
          "count": 1,
          "price": 10.5,
          "translations": [
            {
              "type": "string",
              "culture": "string",
              "text": "string"
            }
          ]
        }
      ],
      "keyBookeeBookingInfo": {
        "priceLevelId": "string",
        "price": 10.5
      }
    }
  ],
  "discountDetails": [
    {
      "slotReference": "string",
      "discountType": "string",
      "discountAmount": 10.5
    }
  ]
}
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | The booking could not be read for a reason other than it being missing (`The booking could not be found: …`); the booking could not be priced for this member (`The price for the booking could not be calculated: …`); or the booking could not be created — for example the member is not on this booking's alert list, or the space has since gone (`The booking could not be promoted from the alert list: …`). A more specific message is appended after the colon, so read it. |
| `500` | Internal server error | An unexpected server-side failure — **including a `bookingId` that does not exist**. A missing booking returns `500`, not `404`, so a bad booking id surfaces here rather than as a client error. |
| `503` | Service unavailable | A part of the platform this call depends on — booking lookup, pricing or booking creation — could not be reached: `At least one of the services is unavailable.` The promotion did not happen; the call is safe to retry. |
