# List all past bookings with pagination (v2.0)

`GET /api/members/v2/{memberId}/past-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: [List all past bookings with pagination (v2.0)](https://support.gladstonesoftware.cloud/reference/members/list-all-past-bookings-with-pagination-v20)

## Overview

Returns a member's past bookings one page at a time. A booking counts as past when its **start** time falls before the upper bound (`dateTimeTo`, which defaults to the moment you call), so a session that has started but not yet finished is included. Results come back newest first, ordered on that start time, inside an object with two parts: `pastBookingData` holds the page, and `metaData` holds the total, the page size and offset actually applied, and ready-made URLs for the first, last, previous and next pages.

Use it to drive a paged booking-history screen or to walk a long history in fixed-size chunks: request the first page, then follow `metaData.next` until it comes back `null`. The navigation URLs are built from the URL of your own request and repeat whichever date filters you sent, so you can follow them verbatim.

What changed from v1.0 (`GET /api/members/{memberId}/past-bookings`). The `limit` and `offset` query parameters and the `metaData` envelope are new — v1.0 returns a bare array with no total and no way to page. v2.0 sorts newest first, where v1.0 applies no sort at all. Against that, v2.0 returns a smaller booking object: `activityTranslations`, `siteName` and `siteTranslations` come back from v1.0 only, so if you rely on translated activity or site text, or on the site's display name, you must either stay on v1.0 or source that text elsewhere. One behavioural trap comes with paging: `offset` must be strictly less than the total number of matching bookings, and a member with nothing in range has a total of `0`, so even the default `offset=0` fails with `400` where v1.0 would return `[]`. Handle that status as "no history", not as a malformed request.

## Endpoint

`GET {base_url}/api/members/v2/{memberId}/past-bookings`

`{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 whose booking history you want. Existence is checked before the paging and date parameters are validated, so an unknown id fails with `404` rather than returning an empty page. |

## Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `dateTimeFrom` | string (date-time) | No | Inclusive lower bound applied to each booking's start time (`startDateTime >= dateTimeFrom`). Must be strictly in the past — a value at or after the current UTC time is rejected with `400`. Omit it to apply no lower bound. It is echoed into the `metaData` navigation URLs, formatted as `yyyy-MM-ddTHH:mm:ss`. |
| `dateTimeTo` | string (date-time) | No | Exclusive upper bound applied to each booking's start time (`startDateTime < dateTimeTo`). Must not be in the future and must not be earlier than `dateTimeFrom`. Omit it and it defaults to the current UTC time. It filters on start time only, so a booking that started before this bound but finishes after it is still returned. |
| `limit` | integer (int32) | No | How many bookings to return in one page. Defaults to `10` when omitted. Must be greater than `0` and no greater than `250`; anything outside that range is rejected with `400`. The value actually applied is echoed back in `metaData.resultSet.limit`. |
| `offset` | integer (int32) | No | How many of the matching bookings to skip before the page starts, counting from the newest. Defaults to `0`. Must be `0` or greater, and must be strictly less than the total number of matching bookings — `offset` equal to or above the total is rejected with `400`, which means a member with no bookings in range fails even at the default `0`. Prefer following `metaData.next` to stepping the value yourself. |

## Sample request

```bash title="cURL"
curl -X GET '{base_url}/api/members/v2/{memberId}/past-bookings' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true'
```

## Response fields

| Field | Type | Description |
|-------|------|-------------|
| `pastBookingData` | array of object | The requested page of past bookings, ordered by `startDateTime` descending (newest first). Holds at most `limit` entries, and fewer on the final page. |
| `pastBookingData[].bookingId` | integer (int32) | Identifier of the booking this entry records. This is the value other bookings endpoints accept as a booking id. |
| `pastBookingData[].bookingRef` | integer (int32) | The reference held against this member's place on the booking, not against the booking itself — do not use it to identify a booking, use `bookingId`. An entry with no reference held comes back as `0` rather than `null`. |
| `pastBookingData[].activityId` | string | Identifier of the activity that was booked. It is the same activity identifier the booking restrictions endpoints take as `activityId`, so you can feed it straight back in to check whether the member may book that activity again. |
| `pastBookingData[].activityName` | string | The activity's short description — display text, not an identifier, and not translated. Unlike v1.0, this version returns no translations alongside it. |
| `pastBookingData[].activityDescription` | string | The activity's long description: the fuller free-text version of `activityName`, likewise untranslated. |
| `pastBookingData[].startDateTime` | string (date-time) | When the booked session starts. This is the field the `dateTimeFrom` and `dateTimeTo` filters are applied to, and the field the page is sorted on. |
| `pastBookingData[].endDateTime` | string (date-time) | When the booked session ends. Returned for display only — neither date filter looks at it. |
| `pastBookingData[].siteId` | string | Identifier of the site the booked activity belongs to, read from the activity rather than from the booking. Only the identifier is returned; unlike v1.0 there is no site name in this version, so resolve the display name from your own site lookup. |
| `metaData` | object | Paging information for this request: the navigation URLs and the counts that describe the page you were given. |
| `metaData.start` | string | URL of the first page — your request with `offset=0` and the `limit` that was applied, carrying forward any `dateTimeFrom` and `dateTimeTo` you sent. Always populated, including when you are already on the first page. |
| `metaData.end` | string | URL of the last page, with the offset of that page worked out from the total and the applied `limit`. Always populated. |
| `metaData.previous` | string | URL of the previous page, or `null` when `offset` is `0`. Where the previous page would start before the beginning, the offset is clamped to `0`. |
| `metaData.next` | string | URL of the next page, or `null` once `offset + limit` reaches the total — that null is how you know to stop walking. |
| `metaData.resultSet` | object | The counts describing this page, all reported after defaults have been applied. |
| `metaData.resultSet.count` | integer (int32) | How many entries are actually in `pastBookingData` for this page. Lower than `limit` on the final page. |
| `metaData.resultSet.offset` | integer (int32) | The offset that was applied — `0` when you omitted `offset`. |
| `metaData.resultSet.limit` | integer (int32) | The page size that was applied — `10` when you omitted `limit`. |
| `metaData.resultSet.total` | integer (int32) | How many bookings match `memberId` and the date filters in total, ignoring paging. Use it to size a pager, and remember that `offset` must stay below it. |

## Sample response

```json title="200 OK"
{
  "pastBookingData": [
    {
      "bookingId": 12345,
      "bookingRef": 1,
      "activityId": "string",
      "activityName": "string",
      "activityDescription": "string",
      "startDateTime": "2026-08-14T19:00:00Z",
      "endDateTime": "2026-08-14T19:00:00Z",
      "siteId": "string"
    }
  ],
  "metaData": {
    "start": "string",
    "end": "string",
    "previous": "string",
    "next": "string",
    "resultSet": {
      "count": 1,
      "offset": 1,
      "limit": 1,
      "total": 1
    }
  }
}
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | `limit` is `0` or negative ("Limit must be greater than 0") or above 250 ("Limit cannot be greater than 250"); `offset` is negative ("Offset must be greater than or equal to 0") or is not less than the number of matching bookings ("Offset value must be less than the total number of records: {total}"), which includes the default `offset=0` when the member has no bookings in range; `dateTimeFrom` is at or after the current UTC time ("The supplied dateTimeFrom must be in the past"); `dateTimeTo` is in the future ("The supplied dateTimeTo must be in the past"); or `dateTimeFrom` is later than `dateTimeTo` ("dateTimeTo must be in the past and after dateTimeFrom"). |
| `404` | Not found | No member exists with the supplied `memberId` — "Member ID {memberId} does not exist". Checked first, so it wins over any `400`. |
| `500` | Internal server error | |
