# Return booking sheets for the given resource group with member details

`GET /api/booking-sheets/{id}/with-member-details`

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

HTML version: [Return booking sheets for the given resource group with member details](https://support.gladstonesoftware.cloud/reference/bookings/return-booking-sheets-for-the-given-resource-group-with-member-details)

## Overview

Returns everything needed to draw a booking sheet — a day-by-day grid of one resource
group's bookable resources, the bookings on them, and the periods when they are closed —
with the people on each booking included.

A booking sheet is a group of bookable resources at a site, such as the courts in a
sports hall, configured together so they can be scheduled on one grid. You identify it by
the id returned when it was created with
[Creates a booking sheet](creates-a-booking-sheet.md).

The response is organised by day, not by resource: `resourceGroups` holds one entry per
day in the range on which at least one resource is open, and days on which nothing is open
are left out. `bookingSheet` carries the sheet's own details once, outside that list.

Two things catch integrators out:

- A booking is only returned if it lies **wholly** inside `fromDate`–`toDate`. Widen the
  range rather than trimming it if bookings seem to be missing.
- Day notes are only returned when you pass `siteId`. Without it `bookingSheet.notes` is
  always empty.

Use [the variant without member details](return-booking-sheets-for-the-given-resource-group-but-with-no-member-details.md)
where personal data is not needed — for example a public-facing availability display. To
re-read one booking on its own, use
[Return a single booking](return-a-single-booking-with-member-details-in-the-same-format-as-a-booking-shee.md).

## Endpoint

`GET {base_url}/api/booking-sheets/{id}/with-member-details`

`{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 |
|------|------|----------|-------------|
| `id` | string | Yes | The booking sheet you want, as returned when it was created with [Creates a booking sheet](creates-a-booking-sheet.md) — ids are generated with a `PRCP` prefix. The booking sheet must have at least one resource product attached, or the call fails with `400 Invalid booking sheet ID`. |

## Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `fromDate` | string (date-time) | Yes | The first day to return, as a date-time. Required despite being a query parameter — omit it and the call fails with `400 fromDate must be specified`. Send it at midnight; a time component narrows which bookings qualify, because a booking must start at or after this instant to be returned. |
| `toDate` | string (date-time) | Yes | The last day to return. Required — omit it and the call fails with `400 toDate must be specified`, and it must not be earlier than `fromDate`. A value at exactly midnight is widened to `23:59:59` on that date, so `2026-03-01`–`2026-03-07` covers all seven days; send any other time and it is used as given, which will exclude bookings ending later that day. |
| `siteId` | string | No | The site whose day notes you want. It does not filter the bookings or resources returned — its only effect is to populate `bookingSheet.notes`. Omit it and that array is always empty. |

## Sample request

```bash title="cURL"
curl -X GET '{base_url}/api/booking-sheets/{id}/with-member-details' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true'
```

## Response fields

| Field | Type | Description |
|-------|------|-------------|
| `resourceGroups` | array of object | One entry per day in the requested range on which at least one of the booking sheet's resources is open. Days with no opening times are dropped entirely, so this array is usually shorter than the number of days you asked for and you cannot index it by day offset — read the date part of `resourceGroups[].startTime` to see which day an entry covers. |
| `resourceGroups[].bookings` | array of object | The bookings falling on this day. A booking is placed on the first day matching the date of either its `startTime` or its `endTime`, so one running past midnight appears once only, under the earlier day. Only bookings lying wholly inside `fromDate`–`toDate` are returned: one that starts before `fromDate`, or ends after `toDate`, is omitted rather than truncated. |
| `resourceGroups[].bookings[].bookingId` | integer (int32) | The numeric identifier of this booking. Pass it to [Return a single booking](return-a-single-booking-with-member-details-in-the-same-format-as-a-booking-shee.md) to re-read the booking on its own. |
| `resourceGroups[].bookings[].recurringScheduleId` | string (uuid) | The block-booking schedule this booking was generated from. Every booking produced by the same schedule carries the same value, so you can group them. `null` for a one-off booking. |
| `resourceGroups[].bookings[].isBlockBooking` | boolean | Whether this booking forms part of a block booking. Also `false` when no value has been set. |
| `resourceGroups[].bookings[].id` | string | An absolute URL to this booking on `GET /api/booking-sheets/booking/{bookingId}`, built from the host that served your request. A convenience link — `bookingId` carries the same information. |
| `resourceGroups[].bookings[].startTime` | string (date-time) | When the booked period starts. Use it with `endTime` to place the booking on the sheet. |
| `resourceGroups[].bookings[].endTime` | string (date-time) | When the booked period ends. |
| `resourceGroups[].bookings[].activityId` | string | The activity being booked. Bookings sharing an `activityId` also share `description`, the two colour fields, `activityComments` and `pricedProducts`. |
| `resourceGroups[].bookings[].activityForeColorHex` | string | The activity's configured foreground (text) colour as a hex string, so a sheet can render every booking in its activity's colours. |
| `resourceGroups[].bookings[].activityBackColorHex` | string | The activity's configured background colour as a hex string. |
| `resourceGroups[].bookings[].description` | string | The activity's description — the name of the activity, not a note about this booking. Per-booking free text is in `bookingComments`. |
| `resourceGroups[].bookings[].maximumBookees` | integer (int32) | The maximum number of bookees the booking allows. Reported as `0` when the booking has no maximum recorded, which is not the same as "no places available". |
| `resourceGroups[].bookings[].numberOfBookees` | integer (int32) | How many places are taken: the sum of `bookedMembers[].partySize` over entries that are not on the waiting list and are not the host. Calculated only when member details are returned — it is `0` on [the variant without member details](return-booking-sheets-for-the-given-resource-group-but-with-no-member-details.md). |
| `resourceGroups[].bookings[].waitingListSize` | integer (int32) | The sum of `bookedMembers[].partySize` over entries that are on the waiting list and are not the host. Like `numberOfBookees`, it is `0` when member details are not returned. |
| `resourceGroups[].bookings[].pricedProducts` | array of object | The chargeable, non-resource products configured against the booking's activity — what a bookee can be sold for it. Derived from the activity, so every booking with the same `activityId` returns the same list. |
| `resourceGroups[].bookings[].pricedProducts[].id` | string | The product's identifier. |
| `resourceGroups[].bookings[].pricedProducts[].description` | string | The product's description. |
| `resourceGroups[].bookings[].resourceProducts` | array of object | The bookable resources this booking occupies, such as the courts or lanes. Each one also appears in the parent `resourceGroups[].resourceProducts`, which is how you position the booking against a column of the sheet. |
| `resourceGroups[].bookings[].resourceProducts[].id` | string | The resource product's identifier, matching one of `resourceGroups[].resourceProducts[].id`. |
| `resourceGroups[].bookings[].resourceProducts[].description` | string | The resource product's description. |
| `resourceGroups[].bookings[].bookedMembers` | array of object | Everyone on the booking, including anyone waiting. Always returned by this endpoint; [the variant without member details](return-booking-sheets-for-the-given-resource-group-but-with-no-member-details.md) omits the field from the JSON entirely. |
| `resourceGroups[].bookings[].bookedMembers[].id` | integer (int32) | The member's numeric id, or `0` when the place was booked for a non-member guest. When it is `0`, `firstNames` and `lastName` hold the guest name captured on the booking rather than a member record. |
| `resourceGroups[].bookings[].bookedMembers[].firstNames` | string | The member's forename(s) when `id` is greater than `0`, otherwise the non-member forename captured on the booking. |
| `resourceGroups[].bookings[].bookedMembers[].lastName` | string | The member's surname when `id` is greater than `0`, otherwise the non-member surname captured on the booking. |
| `resourceGroups[].bookings[].bookedMembers[].isOnWaitingList` | boolean | Whether this entry is a waiting-list place rather than a confirmed one. Waiting-list entries count towards `waitingListSize` instead of `numberOfBookees`. |
| `resourceGroups[].bookings[].bookedMembers[].salesStatusInd` | integer (enum) | Payment status of the sales invoice raised for this place: `0` unpaid, `1` part paid, `2` paid, `3` void, `4` part credited, `5` part credited and paid, `6` credited, `7` credit note, `8` pending. Reported as `0` when no status is set, so `0` means "unpaid or never set". |
| `resourceGroups[].bookings[].bookedMembers[].salesInvoiceId` | integer (int32) | The sales invoice raised for this place. `0` when no invoice exists, in which case `totalAmount` is also `0`. |
| `resourceGroups[].bookings[].bookedMembers[].bookingId` | integer (int32) | The booking this entry belongs to. Repeats the parent `bookings[].bookingId`. |
| `resourceGroups[].bookings[].bookedMembers[].bookingRef` | integer (int32) | Distinguishes the several entries on one booking: `bookingId` plus `bookingRef` identifies a single place. `0` when the place has no reference. |
| `resourceGroups[].bookings[].bookedMembers[].attendedInd` | boolean | Whether attendance has been recorded for this place. `false` covers both "did not attend" and "not yet marked" — the two are not distinguishable here. |
| `resourceGroups[].bookings[].bookedMembers[].waitingListDateTime` | string (date-time) | When the waiting-list entry was created, in UTC. `null` unless `isOnWaitingList` is `true`. |
| `resourceGroups[].bookings[].bookedMembers[].totalAmount` | number (double) | The total of the sales invoice identified by `salesInvoiceId`. `0` when there is no invoice. |
| `resourceGroups[].bookings[].bookedMembers[].partySize` | integer (int32) | How many places this single entry covers — one entry can stand for a group. Defaults to `1` when no size is set. `numberOfBookees` and `waitingListSize` are sums of this field. |
| `resourceGroups[].bookings[].bookedMembers[].bookingParties` | array of object | The breakdown of `partySize` by price level. Entries with no price level are dropped and entries sharing a price level are merged, so this array can have fewer entries than the party breakdown recorded on the booking — and empty even when `partySize` is greater than `0`. |
| `resourceGroups[].bookings[].bookedMembers[].bookingParties[].keyBookeeInd` | integer (int32) | `1` when any of the merged entries at this price level is the key bookee — the lead person on the booking — otherwise `0`. |
| `resourceGroups[].bookings[].bookedMembers[].bookingParties[].priceLevelId` | string | The price level charged for these places: the tariff, such as adult or junior, that sets the rate. Never empty, because entries without a price level are excluded. |
| `resourceGroups[].bookings[].bookedMembers[].bookingParties[].quantity` | integer (int32) | The number of places at this price level, summed across the merged entries. |
| `resourceGroups[].bookings[].bookedMembers[].phoneNo` | string | The member's mobile telephone number, falling back to their home number when no mobile is held. `null` when neither is recorded. |
| `resourceGroups[].bookings[].bookeeName` | string | The display name held against the booking — who the booking is under. |
| `resourceGroups[].bookings[].bookingType` | string | Either `Activity` or `Reservation`, taken from the activity's type. |
| `resourceGroups[].bookings[].activityComments` | string | Free-text comments configured on the activity, so the same text appears on every booking for that activity. `null` when none is set. |
| `resourceGroups[].bookings[].bookingComments` | string | Free-text comments recorded against this individual booking. `null` when none is set. |
| `resourceGroups[].bookingExceptions` | array of object | Periods on this day when one of the resources is closed to entry — derived from time bands attached to the resource that are flagged as restricting entry. Only exceptions lying wholly inside `fromDate`–`toDate` are returned. Render these as blocked-out areas of the sheet. |
| `resourceGroups[].bookingExceptions[].id` | string | The identifier of the time band that produces the restriction. It is not unique per occurrence — every occurrence of a recurring restriction repeats it — so do not use it as a row key. |
| `resourceGroups[].bookingExceptions[].description` | string | The time band's description, suitable for labelling the blocked-out area. |
| `resourceGroups[].bookingExceptions[].recurringExceptions` | object | Present only when `scheduleID` is set. A single summary of the whole recurring run, not a list of the individual occurrences. |
| `resourceGroups[].bookingExceptions[].recurringExceptions.days` | array of string | The days of the week the schedule was created for, as full English day names (`monday` to `sunday`). An empty list means every day. |
| `resourceGroups[].bookingExceptions[].recurringExceptions.startTime` | string (date-time) | The earliest start across every occurrence of the schedule — the outer bound of the run, not of this occurrence. The occurrence's own start is `bookingExceptions[].startTime`. |
| `resourceGroups[].bookingExceptions[].recurringExceptions.endTime` | string (date-time) | The latest end across every occurrence of the schedule. |
| `resourceGroups[].bookingExceptions[].scheduleID` | string (uuid) | The recurring schedule this exception belongs to. `null` for a one-off exception. Occurrences sharing a `scheduleID` are the same restriction repeated, and are the ones [Update one or more booking sheet exceptions](update-one-or-more-booking-sheet-exceptions.md) works on together. |
| `resourceGroups[].bookingExceptions[].notes` | string | Free text recorded when the exception was created. `null` when none was given. |
| `resourceGroups[].bookingExceptions[].resourceProduct` | object | The single resource product this exception closes. An exception applies to one product, not the whole group, so the other products on the sheet stay bookable for that period. |
| `resourceGroups[].bookingExceptions[].resourceProduct.id` | string | The resource product's identifier, matching one of `resourceGroups[].resourceProducts[].id`. |
| `resourceGroups[].bookingExceptions[].resourceProduct.description` | string | The resource product's description. |
| `resourceGroups[].bookingExceptions[].startTime` | string (date-time) | When this occurrence's restricted period starts. |
| `resourceGroups[].bookingExceptions[].endTime` | string (date-time) | When this occurrence's restricted period ends. Falls back to the same value as `startTime` when the exception has no end time set. |
| `resourceGroups[].id` | string | The booking sheet's identifier — the same value you passed as `id`. Repeated on every day entry. |
| `resourceGroups[].description` | string | The booking sheet's configured name. Repeated on every day entry. |
| `resourceGroups[].startTime` | string (date-time) | The earliest opening time across the resources open on this day. Together with `endTime` this gives the sheet's vertical extent for the day, and its date part identifies the day. |
| `resourceGroups[].endTime` | string (date-time) | The latest closing time across the resources open on this day. |
| `resourceGroups[].slotFrequency` | integer (int32) | The slot interval configured on the booking sheet, used to divide the grid into rows. `0` when the booking sheet has no interval set. |
| `resourceGroups[].siteId` | string | The site the booking sheet belongs to. |
| `resourceGroups[].siteDescription` | string | Always `null` on this endpoint. Do not rely on it for the site name. |
| `resourceGroups[].resourceProducts` | array of object | The booking sheet's bookable resources that are open on this day — the columns of the sheet. Only products flagged as a standard or density resource are included, and a product with no opening times on the day is left out. If none are open, the day is dropped from `resourceGroups` altogether. |
| `resourceGroups[].resourceProducts[].calendarId` | string | The opening-times calendar the resource follows. Both `openingTimes` and `capacities` are derived from it. |
| `resourceGroups[].resourceProducts[].densitySlotSize` | integer (int32) | The slot size configured against a density resource (`resourceType` `2`). `0` when none is configured. |
| `resourceGroups[].resourceProducts[].usage` | integer (int32) | Taken from the resource product's configured usage value; reported as `1` when the product has none. |
| `resourceGroups[].resourceProducts[].resourceType` | integer (int32) | How the resource is capacity-managed: `1` a standard resource, `2` a density resource, which carries a capacity limit per period in `capacities`. Reported as `1` when the product has no value. Products that are not resources at all never appear here. |
| `resourceGroups[].resourceProducts[].openingTimes` | array of object | When this resource is open on this day, one entry per time band on its calendar. Already filtered to the day, so you do not need to filter again. |
| `resourceGroups[].resourceProducts[].openingTimes[].timeBandId` | string | The time band that produces this opening period. The same id can appear in `bookingExceptions[].id` when that band restricts entry. |
| `resourceGroups[].resourceProducts[].openingTimes[].startTime` | string (date-time) | This day's date combined with the time band's start time. |
| `resourceGroups[].resourceProducts[].openingTimes[].endTime` | string (date-time) | This day's date combined with the time band's end time. |
| `resourceGroups[].resourceProducts[].capacities` | array of object | Capacity limits by period, for density resources (`resourceType` `2`) only — always empty for a standard resource. They are calculated once, for the weekday of `fromDate`, and then repeated unchanged on every day entry, so treat them as that weekday's pattern rather than a per-day figure. Request a single day at a time if you need day-accurate capacities. |
| `resourceGroups[].resourceProducts[].capacities[].startTime` | string (date-time) | When the period the limit applies to starts. |
| `resourceGroups[].resourceProducts[].capacities[].endTime` | string (date-time) | When the period ends. End times are normalised to `hh:mm:59`, so periods abut rather than overlap. |
| `resourceGroups[].resourceProducts[].capacities[].capacity` | integer (int32) | The density limit configured for that period, or `0` when none is set. |
| `resourceGroups[].resourceProducts[].id` | string | The resource product's identifier. Match it against `bookings[].resourceProducts[].id` to place a booking in the right column. |
| `resourceGroups[].resourceProducts[].description` | string | The resource product's description, suitable as the column heading. |
| `resourceGroups[].hasResourceProducts` | boolean | Always `false` on this endpoint. A day entry only exists when at least one resource is open, so it would carry no information anyway. |
| `bookingSheet` | object | The booking sheet itself, independent of any one day. Always present when the call succeeds, even if `resourceGroups` is empty. |
| `bookingSheet.id` | string | The booking sheet's identifier, the same value you passed as `id`. |
| `bookingSheet.description` | string | The booking sheet's configured name. |
| `bookingSheet.openingTimes` | object | The opening window configured on the booking sheet itself. This is not the same as `resourceGroups[].startTime`/`endTime`, which are computed from the resources actually open on a given day. |
| `bookingSheet.openingTimes.startTime` | string (date-time) | The configured opening time. |
| `bookingSheet.openingTimes.endTime` | string (date-time) | The configured closing time. |
| `bookingSheet.notes` | array of object | Day notes recorded against the site for dates in the requested range. **Only populated when you pass the `siteId` query parameter** — without it this array is always empty, even where notes exist. |
| `bookingSheet.notes[].date` | string (date-time) | The date the note applies to. The time component is midnight. |
| `bookingSheet.notes[].note` | string | The note text. |

## Sample response

```json title="200 OK"
{
  "resourceGroups": [
    {
      "bookings": [
        {
          "bookingId": 12345,
          "recurringScheduleId": "b7f3c1e2-9a44-4f2b-8c17-0d5e9a1b6c33",
          "isBlockBooking": true,
          "id": "string",
          "startTime": "2026-08-14T19:00:00Z",
          "endTime": "2026-08-14T19:00:00Z",
          "activityId": "string",
          "activityForeColorHex": "string",
          "activityBackColorHex": "string",
          "description": "string",
          "maximumBookees": 1,
          "numberOfBookees": 1,
          "waitingListSize": 1,
          "pricedProducts": [
            {
              "id": "string",
              "description": "string"
            }
          ],
          "resourceProducts": [
            {
              "id": "string",
              "description": "string"
            }
          ],
          "bookedMembers": [
            {
              "id": 12345,
              "firstNames": "string",
              "lastName": "string",
              "isOnWaitingList": true,
              "salesStatusInd": 0,
              "salesInvoiceId": 12345,
              "bookingId": 12345,
              "bookingRef": 1,
              "attendedInd": true,
              "waitingListDateTime": "2026-08-14T19:00:00Z",
              "totalAmount": 10.5,
              "partySize": 1,
              "bookingParties": [
                {
                  "keyBookeeInd": 1,
                  "priceLevelId": "string",
                  "quantity": 1
                }
              ],
              "phoneNo": "string"
            }
          ],
          "bookeeName": "string",
          "bookingType": "string",
          "activityComments": "string",
          "bookingComments": "string"
        }
      ],
      "bookingExceptions": [
        {
          "id": "string",
          "description": "string",
          "recurringExceptions": {
            "days": [
              "string"
            ],
            "startTime": "2026-08-14T19:00:00Z",
            "endTime": "2026-08-14T19:00:00Z"
          },
          "scheduleID": "b7f3c1e2-9a44-4f2b-8c17-0d5e9a1b6c33",
          "notes": "string",
          "resourceProduct": {
            "id": "string",
            "description": "string"
          },
          "startTime": "2026-08-14T19:00:00Z",
          "endTime": "2026-08-14T19:00:00Z"
        }
      ],
      "id": "string",
      "description": "string",
      "startTime": "2026-08-14T19:00:00Z",
      "endTime": "2026-08-14T19:00:00Z",
      "slotFrequency": 1,
      "siteId": "string",
      "siteDescription": "string",
      "resourceProducts": [
        {
          "calendarId": "string",
          "densitySlotSize": 1,
          "usage": 1,
          "resourceType": 1,
          "openingTimes": [
            {
              "timeBandId": "string",
              "startTime": "2026-08-14T19:00:00Z",
              "endTime": "2026-08-14T19:00:00Z"
            }
          ],
          "capacities": [
            {
              "startTime": "2026-08-14T19:00:00Z",
              "endTime": "2026-08-14T19:00:00Z",
              "capacity": 1
            }
          ],
          "id": "string",
          "description": "string"
        }
      ],
      "hasResourceProducts": true
    }
  ],
  "bookingSheet": {
    "id": "string",
    "description": "string",
    "openingTimes": {
      "startTime": "2026-08-14T19:00:00Z",
      "endTime": "2026-08-14T19:00:00Z"
    },
    "notes": [
      {
        "date": "2026-08-14T19:00:00Z",
        "note": "string"
      }
    ]
  }
}
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | `id must be specified` — the path id was empty. |
| `400` | Bad request | `fromDate must be specified` or `toDate must be specified` — either query parameter was omitted. |
| `400` | Bad request | `fromDate must be earlier or equal than toDate` — the range runs backwards. |
| `400` | Bad request | `Invalid booking sheet ID` — no booking sheet with that id exists, or it exists but has no resource products attached. Note that this "not found" case is returned as `400`, not `404`. |
| `500` | Internal server error | An unexpected server-side failure; the response body is empty. Retry, then raise a support ticket with the time of the call. |
