Gets a summary of bookings for a member, including discount information

GET /api/members/{memberId}/bookings-summary

Success: 200 OK

Overview

Assembles, in one call, everything a member's "my bookings" screen needs: their recent past bookings, their upcoming bookings, and the promotion figures behind each. The endpoint looks up member links, bookings and discount records on your behalf, and folds the results into a single object with two arrays, bookingHistory and futureBookings.

The history window is fixed at the last 30 days. It covers 30 days before today up to the moment of the call. There is no query parameter here to widen it, so a booking from two months ago will not appear no matter what you send. If you need older bookings, or paging, use List all past bookings with pagination (v2.0) instead. futureBookings has no equivalent limit: it reaches as far ahead as the member has booked.

Linked members are included, but only in one direction. The endpoint reads the requested member's links and, if that member is the primary of their link group, also fetches bookings for each linked member. A secondary member calling for themselves gets only their own bookings — they cannot see the primary's. Bookings belonging to a linked member are marked by keyBookeeMemberId and name, which is how you tell whose booking you are looking at.

Bookings are then grouped by slot reference, so that one underlying booking held by two people in the same link group appears as one group with two entries rather than as a duplicate. History groups come back most recent first; future groups come back soonest first. Both orderings are taken from the first booking in each group.

Only bookings held against a standard resource — a court, a lane, a room — are returned. Bookings that occupy capacity rather than a named resource are omitted entirely, silently, from both arrays.

Discount enrichment is best-effort and fails open. If the booking discount feature is not enabled for the tenant, the call still succeeds and every discountDetails comes back null; a null therefore tells you nothing about whether a promotion was applied. Discount figures are also withheld for any group where the requested member is not the member who made the bookings. Read the discountDetails field notes before you show these amounts to anyone — they come from the promotion's own records rather than from the booking's invoice.

You must ask for at least one of the two arrays: sending both includeBookingHistory=false and includeFutureBookings=false is rejected with 400. There is no pagination and no filtering, and the work grows with the size of the link group — a primary member with several linked members produces two lookups per member plus a paged sweep of discount records, so treat this as a page-load call rather than something to poll.

Endpoint

GET {base_url}/api/members/{memberId}/bookings-summary

{base_url} is the environment URL issued to your integration. See Authenticating with Gladstone APIs.

Path parameters

NameTypeRequiredDescription
memberIdinteger (int32)YesThe member whose bookings you want. If this member is the primary of a link group, the bookings of every member linked to them are returned as well; if they are a secondary, only their own are. Must be 1 or greater, or the call is rejected with 400 and the message {memberId} is an invalid member ID.

Query parameters

NameTypeRequiredDescription
includeBookingHistorybooleanNoWhether to populate bookingHistory. Defaults to true. Set it to false to skip the past-bookings lookups entirely — bookingHistory then comes back as an empty array rather than being absent. Cannot be false at the same time as includeFutureBookings.
includeFutureBookingsbooleanNoWhether to populate futureBookings. Defaults to true. Set it to false to skip the upcoming-bookings lookups — futureBookings then comes back as an empty array rather than being absent. Cannot be false at the same time as includeBookingHistory.

Sample request

cURL
curl -X GET '{base_url}/api/members/{memberId}/bookings-summary' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true'

Response fields

FieldTypeDescription
bookingHistoryarray of objectPast bookings, grouped by slot reference, most recent group first. Covers the last 30 days only — the window is fixed and cannot be changed from this endpoint. An empty array when includeBookingHistory is false, and equally when the member simply has nothing in the last 30 days; the two cases are indistinguishable.
bookingHistory[].bookingsarray of objectThe past bookings sharing this group's slot reference. More than one entry means the requested member and one of their linked members each hold a place on the same booking — that is what the grouping exists for. Every entry has the same slotReference, and the group's position in the array is taken from the first entry's dateTime.
bookingHistory[].bookings[].bookingIdinteger (int32)The identifier of the underlying booking — one activity occurrence at one time. Every member holding a place on that booking reports the same value, which is why a single group can contain several entries. This is the key to use when matching against the other booking endpoints.
bookingHistory[].bookings[].bookingRefinteger (int32)A reference identifying this member's place on the booking, distinct from bookingId. It is what the sales invoice and, for a party activity, the individual party lines are filed under, so it is the value that ties this booking to its money. Do not use it interchangeably with bookingId.
bookingHistory[].bookings[].slotReferencestringThe slot reference for the booking, and the key this group was formed on. Treat it as an opaque string: it is a JSON document encoded as a string and its internal structure is not part of the contract. Where a full reference could not be resolved, a minimal one built from bookingId alone is returned instead — which still groups correctly, but carries less inside it.
bookingHistory[].bookings[].namestringThe full name of the member this booking belongs to — the member named by keyBookeeMemberId, which for a linked member is not the member in the request path. Formed as first names followed by last name. Null when that member's record could not be read.
bookingHistory[].bookings[].keyBookeeMemberIdinteger (int32)The member whose booking this is: either the memberId you requested, or one of their linked members. Use it to attribute bookings within a group. It also gates the group's discount figures — discountDetails is only populated when the group's first booking belongs to the member you requested.
bookingHistory[].bookings[].activityIdstringThe identifier of the activity booked — badminton, a swim session, a fitness class. Stable across bookings of the same activity, so it is the value to key on when you need activity configuration this response does not carry.
bookingHistory[].bookings[].activityNamestringThe activity's short description as configured at the site, untranslated. Translated forms are in translations.
bookingHistory[].bookings[].activityDescriptionstringThe activity's long description as configured at the site, untranslated. A separate, fuller field than activityName, not a translation of it.
bookingHistory[].bookings[].dateTimestring (date-time)The booking's start date and time. This is what history groups are ordered on, most recent first, and what the fixed 30-day window is applied to.
bookingHistory[].bookings[].siteIdstringThe identifier of the site — the centre — the activity runs at.
bookingHistory[].bookings[].locationobjectThe resource the booking occupies — the court, lane or room. Where a booking covers several resources, only the first one found is reported.
bookingHistory[].bookings[].location.idstringThe product identifier of the resource, the same productId used by the product configuration endpoints.
bookingHistory[].bookings[].location.descriptionstringThe resource's description as configured, untranslated. Translated forms are in location.translations.
bookingHistory[].bookings[].location.translationsarray of objectTranslated forms of location.description. An empty array where the resource has no translations configured.
bookingHistory[].bookings[].location.translations[].typestringThe name of the property this text translates. The descriptions returned by this endpoint are translated under description.
bookingHistory[].bookings[].location.translations[].culturestringThe culture this text is for, as recorded against the translation — for example en-GB or cy-GB.
bookingHistory[].bookings[].location.translations[].textstringThe translated text. Match on culture and type to pick the one you want; there is no ordering guarantee and no fallback entry, so keep the untranslated sibling field as your default.
bookingHistory[].bookings[].attendedInCentrebooleanWhether the member was recorded as having attended in person. true only when attendance was marked and the activity is not configured as virtual-only, so it stays false for any booking nobody registered attendance against.
bookingHistory[].bookings[].attendedVirtuallybooleanWhether the member was recorded as having attended online. true only when attendance was marked and the activity is not configured as in-centre-only. Note the consequence: for an activity offered both ways, marking attendance sets both this and attendedInCentre to true. The pair reflects how the activity could be delivered, not which way the member actually turned up, so do not read one of them as proof of the other being false.
bookingHistory[].bookings[].keyBookeeIncludedIndbooleanWhether the member who made the booking is taking one of the booked places themselves, rather than booking purely on other people's behalf. Set from whether they were marked as attending at the time the booking was created. keyBookeeBookingInfo is populated only when this is true.
bookingHistory[].bookings[].paymentInfoobjectThe sales invoice raised for this member's place on the booking. Always present for a history booking, because history leaves out bookings that have no invoice.
bookingHistory[].bookings[].paymentInfo.salesInvoiceIdinteger (int32)The sales invoice this member's place on the booking was billed on. Found through bookingRef, not bookingId.
bookingHistory[].bookings[].paymentInfo.salesInvoiceTotalnumber (double)The invoice total — the amount charged for this member's place. For a non-party booking this same figure is repeated in bookeePriceLevels[].price and, where the booking member is attending, in keyBookeeBookingInfo.price. No currency is returned with it, and the response does not say whether it includes tax.
bookingHistory[].bookings[].paymentInfo.salesInvoiceStatusstringThe invoice status as a name — one of Unpaid, PartPaid, Paid, Void, PartCredited, PartCreditedPaid, Credited, CreditNote or Pending. Compare on the exact string; the numeric codes behind these names are not returned.
bookingHistory[].bookings[].paymentInfo.salesReceiptIdinteger (int32)The receipt the invoice was settled against, where one exists. Null on an unpaid or unallocated invoice. Where more than one receipt was allocated to the invoice, only the first is reported.
bookingHistory[].bookings[].translationsarray of objectTranslated forms of the activity's description. An empty array where the activity has no translations configured.
bookingHistory[].bookings[].translations[].typestringThe name of the property this text translates. The descriptions returned by this endpoint are translated under description.
bookingHistory[].bookings[].translations[].culturestringThe culture this text is for, as recorded against the translation — for example en-GB or cy-GB.
bookingHistory[].bookings[].translations[].textstringThe translated text. Match on culture and type to pick the one you want; there is no ordering guarantee and no fallback entry, so keep the untranslated sibling field as your default.
bookingHistory[].bookings[].bookeePriceLevelsarray of objectHow the charge breaks down by price level, and the shape depends on the activity. For a party activity there is one entry per price level, giving the number of people at that level and their combined total. For every other activity there is exactly one entry, whose count is hard-coded to 1 and whose price is the whole sales invoice total rather than a per-person price. Never multiply count by price.
bookingHistory[].bookings[].bookeePriceLevels[].idstringThe price level identifier — adult, junior, concession and so on. For a non-party booking this is the first price level found on the booking's invoice, and it is the only one reported even where the invoice carries several.
bookingHistory[].bookings[].bookeePriceLevels[].descriptionstringThe price level's display description. Where the site and activity have a description override configured for this price level, the override replaces the global description here.
bookingHistory[].bookings[].bookeePriceLevels[].countinteger (int32)The number of people at this price level. Meaningful for party activities only; for every other activity it is always 1, whatever number of places the booking actually covers.
bookingHistory[].bookings[].bookeePriceLevels[].pricenumber (double)The total charged at this price level, not a unit price. For a party activity it is the sum across everyone at that level. For any other activity it is the whole sales invoice total, repeated from paymentInfo.salesInvoiceTotal.
bookingHistory[].bookings[].bookeePriceLevels[].translationsarray of objectTranslated forms of the price level's description. Where a site-and-activity description override applies, its translations are returned here in place of the global ones.
bookingHistory[].bookings[].bookeePriceLevels[].translations[].typestringThe name of the property this text translates. The descriptions returned by this endpoint are translated under description.
bookingHistory[].bookings[].bookeePriceLevels[].translations[].culturestringThe culture this text is for, as recorded against the translation — for example en-GB or cy-GB.
bookingHistory[].bookings[].bookeePriceLevels[].translations[].textstringThe translated text. Match on culture and type to pick the one you want; there is no ordering guarantee and no fallback entry, so keep the untranslated sibling field as your default.
bookingHistory[].bookings[].keyBookeeBookingInfoobjectThe price level and amount attributable to the member who made the booking. Populated only when keyBookeeIncludedInd is true, and null otherwise. For a party activity it is read from the party line flagged as theirs; for any other activity it is a copy of the single bookeePriceLevels entry, so it repeats the whole invoice total rather than their share of it.
bookingHistory[].bookings[].keyBookeeBookingInfo.priceLevelIdstringThe price level applied to the booking member's own place.
bookingHistory[].bookings[].keyBookeeBookingInfo.pricenumber (double)The amount recorded against that place. For a party booking whose recorded total is zero — which is how bookings created in the legacy Plus2 system arrive, because that system did not record it — the endpoint recalculates the figure by summing the invoice lines at the same price level, and reports 0 when there are none. For a non-party booking this is the whole invoice total, not the member's share.
bookingHistory[].discountDetailsobjectPromotion figures for this group, aggregated from the discount usage records. Null more often than you would expect, and a null tells you nothing on its own: you get null when the group has no discount records, when the booking discount feature is not enabled for the tenant (in which case every discountDetails in the response is null and the call still returns 200), and when the member you requested is not the member who made the bookings in this group. Where a group's discount records span several members, only the requested member's records are counted — or, if none of them are theirs, those of whichever member appears first.
bookingHistory[].discountDetails.originalPricenumber (double)The total before the promotion was applied, summed across this group's discount records. It comes from the promotion's own price-level combination pricing, which is recorded separately from the booking's invoice, so do not assume it reconciles with paymentInfo.salesInvoiceTotal. No currency is returned alongside it, and the response does not say whether the figure includes tax.
bookingHistory[].discountDetails.discountedPricenumber (double)The equivalent total after the promotion was applied, summed across the same records. The same caveats as originalPrice apply: separate from the invoice, no currency, tax treatment unstated.
bookingHistory[].discountDetails.discountAmountnumber (double)The saving: originalPrice minus discountedPrice, computed per record and then summed. It always reconciles with the other two fields, even though none of the three is guaranteed to match the invoice.
bookingHistory[].discountDetails.discountSalesInvoiceIdsarray of integerThe distinct sales invoice ids recorded against this group's discount usage entries — the invoices the discount itself was filed against. The response does not say how these relate to paymentInfo.salesInvoiceId, so do not assume they are the same invoices.
bookingHistory[].discountDetails.promotionCodesarray of stringThe distinct promotion codes applied across the group, with blank entries dropped. This can be an empty array while the amount fields are populated, where the underlying records carry no code.
futureBookingsarray of objectBookings starting after the moment of the call, grouped by slot reference, soonest group first. No upper bound — it reaches as far ahead as the member has booked. An empty array when includeFutureBookings is false, and equally when the member has nothing booked.
futureBookings[].bookingsarray of objectThe upcoming bookings sharing this group's slot reference. More than one entry means the requested member and one of their linked members each hold a place on the same booking. Every entry has the same slotReference, and the group's position in the array is taken from the first entry's dateTime.
futureBookings[].bookings[].bookingUuidstring (uuid)The identifier of the booking lease this booking was created from, taken from the most recently created lease that has not yet expired. Null once every lease behind the booking has expired, which is the normal state for a booking made some time ago — so treat its absence as expected, not as an error.
futureBookings[].bookings[].bookingIdinteger (int32)The identifier of the underlying booking — one activity occurrence at one time. Every member holding a place on that booking reports the same value, which is why a single group can contain several entries. This is the key to use when matching against the other booking endpoints.
futureBookings[].bookings[].bookingRefinteger (int32)A reference identifying this member's place on the booking, distinct from bookingId. It is what the sales invoice and, for a party activity, the individual party lines are filed under, so it is the value that ties this booking to its money. Do not use it interchangeably with bookingId. May be null on a future booking that has not been assigned one.
futureBookings[].bookings[].slotReferencestringThe slot reference for the booking, and the key this group was formed on. Treat it as an opaque string: it is a JSON document encoded as a string and its internal structure is not part of the contract. Where a full reference could not be resolved, a minimal one built from bookingId alone is returned instead — which still groups correctly, but carries less inside it.
futureBookings[].bookings[].namestringThe full name of the member this booking belongs to — the member named by keyBookeeMemberId, which for a linked member is not the member in the request path. Formed as first names followed by last name. Null when that member's record could not be read.
futureBookings[].bookings[].keyBookeeMemberIdinteger (int32)The member whose booking this is: either the memberId you requested, or one of their linked members. Use it to attribute bookings within a group. It also gates the group's discount figures — discountDetails is only populated when the group's first booking belongs to the member you requested.
futureBookings[].bookings[].activityIdstringThe identifier of the activity booked — badminton, a swim session, a fitness class. Stable across bookings of the same activity, so it is the value to key on when you need activity configuration this response does not carry.
futureBookings[].bookings[].activityNamestringThe activity's short description as configured at the site, untranslated. Translated forms are in translations.
futureBookings[].bookings[].activityDescriptionstringThe activity's long description as configured at the site, untranslated. A separate, fuller field than activityName, not a translation of it.
futureBookings[].bookings[].imageUrlstringA picture for the activity. Where the activity's configured image reference is already an absolute URL beginning http, it is returned unchanged; otherwise it is expanded into a public CDN URL for your tenant. Null or empty when the activity has no image configured.
futureBookings[].bookings[].dateTimestring (date-time)The booking's start date and time. This is what future groups are ordered on, soonest first.
futureBookings[].bookings[].endDateTimestring (date-time)The booking's end date and time.
futureBookings[].bookings[].siteIdstringThe identifier of the site — the centre — the activity runs at.
futureBookings[].bookings[].siteNamestringThe site's display description, untranslated. Returned for future bookings only — history bookings carry siteId alone, so if you show a site name on both you must source it elsewhere for history.
futureBookings[].bookings[].siteTranslationsarray of objectTranslated forms of siteName. An empty array where the site has no translations configured.
futureBookings[].bookings[].siteTranslations[].typestringThe name of the property this text translates. The descriptions returned by this endpoint are translated under description.
futureBookings[].bookings[].siteTranslations[].culturestringThe culture this text is for, as recorded against the translation — for example en-GB or cy-GB.
futureBookings[].bookings[].siteTranslations[].textstringThe translated text. Match on culture and type to pick the one you want; there is no ordering guarantee and no fallback entry, so keep the untranslated sibling field as your default.
futureBookings[].bookings[].isRefundablebooleanWhether the booking meets the conditions for an automated refund. true only when the sales invoice is Paid, was taken through Gladstone's own payment provider, and carries a payment provider reference — or when the invoice total is zero. A booking paid by any other means reports false even though it was genuinely paid for, so this is a statement about how the money can be returned, not about entitlement to a refund. Null when no payment information could be resolved.
futureBookings[].bookings[].keyBookeeIncludedIndbooleanWhether the member who made the booking is taking one of the booked places themselves, rather than booking purely on other people's behalf. Set from whether they were marked as attending at the time the booking was created. keyBookeeBookingInfo is populated only when this is true.
futureBookings[].bookings[].locationobjectThe resource the booking occupies — the court, lane or room. Where a booking covers several resources, only the first one found is reported.
futureBookings[].bookings[].location.idstringThe product identifier of the resource, the same productId used by the product configuration endpoints.
futureBookings[].bookings[].location.descriptionstringThe resource's description as configured, untranslated. Translated forms are in location.translations.
futureBookings[].bookings[].location.translationsarray of objectTranslated forms of location.description. An empty array where the resource has no translations configured.
futureBookings[].bookings[].location.translations[].typestringThe name of the property this text translates. The descriptions returned by this endpoint are translated under description.
futureBookings[].bookings[].location.translations[].culturestringThe culture this text is for, as recorded against the translation — for example en-GB or cy-GB.
futureBookings[].bookings[].location.translations[].textstringThe translated text. Match on culture and type to pick the one you want; there is no ordering guarantee and no fallback entry, so keep the untranslated sibling field as your default.
futureBookings[].bookings[].inCentreobjectConfirmation state for an in-centre booking. Only one of inCentre and virtual carries real values: whichever matches how this booking was made. The other is returned with both of its flags false, which is not the same as being unconfirmed — check the right one of the pair before reading either flag.
futureBookings[].bookings[].inCentre.bookingConfirmedbooleanWhether the member holds a confirmed place rather than a waiting-list place. Always the exact opposite of onAlertList in the same object. Reported as false in whichever of inCentre / virtual does not apply to this booking.
futureBookings[].bookings[].inCentre.onAlertListbooleanWhether the member is on the waiting list for this booking rather than holding a place. Always the exact opposite of bookingConfirmed in the same object. Reported as false in whichever of inCentre / virtual does not apply to this booking.
futureBookings[].bookings[].virtualobjectConfirmation state for a virtual booking. Only one of inCentre and virtual carries real values: whichever matches how this booking was made. The other is returned with both of its flags false, which is not the same as being unconfirmed — check the right one of the pair before reading either flag.
futureBookings[].bookings[].virtual.bookingConfirmedbooleanWhether the member holds a confirmed place rather than a waiting-list place. Always the exact opposite of onAlertList in the same object. Reported as false in whichever of inCentre / virtual does not apply to this booking.
futureBookings[].bookings[].virtual.onAlertListbooleanWhether the member is on the waiting list for this booking rather than holding a place. Always the exact opposite of bookingConfirmed in the same object. Reported as false in whichever of inCentre / virtual does not apply to this booking.
futureBookings[].bookings[].paymentInfoobjectThe sales invoice raised for this member's place, looked up separately from the booking itself. Where no matching invoice is found, only salesInvoiceId is populated and the remaining fields stay at their defaults — a salesInvoiceTotal of 0 and a null salesInvoiceStatus mean "not found", not "free".
futureBookings[].bookings[].paymentInfo.salesInvoiceIdinteger (int32)The sales invoice this member's place on the booking was billed on. Found through bookingRef, not bookingId.
futureBookings[].bookings[].paymentInfo.salesInvoiceTotalnumber (double)The invoice total — the amount charged for this member's place. For a non-party booking this same figure is repeated in bookeePriceLevels[].price and, where the booking member is attending, in keyBookeeBookingInfo.price. No currency is returned with it, and the response does not say whether it includes tax.
futureBookings[].bookings[].paymentInfo.salesInvoiceStatusstringThe invoice status as a name — one of Unpaid, PartPaid, Paid, Void, PartCredited, PartCreditedPaid, Credited, CreditNote or Pending. Compare on the exact string; the numeric codes behind these names are not returned.
futureBookings[].bookings[].paymentInfo.salesReceiptIdinteger (int32)The receipt the invoice was settled against, where one exists. Null on an unpaid or unallocated invoice. Where more than one receipt was allocated to the invoice, only the first is reported.
futureBookings[].bookings[].translationsarray of objectTranslated forms of the activity's description. An empty array where the activity has no translations configured.
futureBookings[].bookings[].translations[].typestringThe name of the property this text translates. The descriptions returned by this endpoint are translated under description.
futureBookings[].bookings[].translations[].culturestringThe culture this text is for, as recorded against the translation — for example en-GB or cy-GB.
futureBookings[].bookings[].translations[].textstringThe translated text. Match on culture and type to pick the one you want; there is no ordering guarantee and no fallback entry, so keep the untranslated sibling field as your default.
futureBookings[].bookings[].bookeePriceLevelsarray of objectHow the charge breaks down by price level, and the shape depends on the activity. For a party activity there is one entry per price level, giving the number of people at that level and their combined total. For every other activity there is exactly one entry, whose count is hard-coded to 1 and whose price is the whole sales invoice total rather than a per-person price. Never multiply count by price.
futureBookings[].bookings[].bookeePriceLevels[].idstringThe price level identifier — adult, junior, concession and so on. For a non-party booking this is the first price level found on the booking's invoice, and it is the only one reported even where the invoice carries several.
futureBookings[].bookings[].bookeePriceLevels[].descriptionstringThe price level's display description. Where the site and activity have a description override configured for this price level, the override replaces the global description here.
futureBookings[].bookings[].bookeePriceLevels[].countinteger (int32)The number of people at this price level. Meaningful for party activities only; for every other activity it is always 1, whatever number of places the booking actually covers.
futureBookings[].bookings[].bookeePriceLevels[].pricenumber (double)The total charged at this price level, not a unit price. For a party activity it is the sum across everyone at that level. For any other activity it is the whole sales invoice total, repeated from paymentInfo.salesInvoiceTotal.
futureBookings[].bookings[].bookeePriceLevels[].translationsarray of objectTranslated forms of the price level's description. Where a site-and-activity description override applies, its translations are returned here in place of the global ones.
futureBookings[].bookings[].bookeePriceLevels[].translations[].typestringThe name of the property this text translates. The descriptions returned by this endpoint are translated under description.
futureBookings[].bookings[].bookeePriceLevels[].translations[].culturestringThe culture this text is for, as recorded against the translation — for example en-GB or cy-GB.
futureBookings[].bookings[].bookeePriceLevels[].translations[].textstringThe translated text. Match on culture and type to pick the one you want; there is no ordering guarantee and no fallback entry, so keep the untranslated sibling field as your default.
futureBookings[].bookings[].keyBookeeBookingInfoobjectThe price level and amount attributable to the member who made the booking. Populated only when keyBookeeIncludedInd is true, and null otherwise. For a party activity it is read from the party line flagged as theirs; for any other activity it is a copy of the single bookeePriceLevels entry, so it repeats the whole invoice total rather than their share of it.
futureBookings[].bookings[].keyBookeeBookingInfo.priceLevelIdstringThe price level applied to the booking member's own place.
futureBookings[].bookings[].keyBookeeBookingInfo.pricenumber (double)The amount recorded against that place. For a party booking whose recorded total is zero — which is how bookings created in the legacy Plus2 system arrive, because that system did not record it — the endpoint recalculates the figure by summing the invoice lines at the same price level, and reports 0 when there are none. For a non-party booking this is the whole invoice total, not the member's share.
futureBookings[].discountDetailsobjectPromotion figures for this group, aggregated from the discount usage records. Null more often than you would expect, and a null tells you nothing on its own: you get null when the group has no discount records, when the booking discount feature is not enabled for the tenant (in which case every discountDetails in the response is null and the call still returns 200), and when the member you requested is not the member who made the bookings in this group. Where a group's discount records span several members, only the requested member's records are counted — or, if none of them are theirs, those of whichever member appears first.
futureBookings[].discountDetails.originalPricenumber (double)The total before the promotion was applied, summed across this group's discount records. It comes from the promotion's own price-level combination pricing, which is recorded separately from the booking's invoice, so do not assume it reconciles with paymentInfo.salesInvoiceTotal. No currency is returned alongside it, and the response does not say whether the figure includes tax.
futureBookings[].discountDetails.discountedPricenumber (double)The equivalent total after the promotion was applied, summed across the same records. The same caveats as originalPrice apply: separate from the invoice, no currency, tax treatment unstated.
futureBookings[].discountDetails.discountAmountnumber (double)The saving: originalPrice minus discountedPrice, computed per record and then summed. It always reconciles with the other two fields, even though none of the three is guaranteed to match the invoice.
futureBookings[].discountDetails.discountSalesInvoiceIdsarray of integerThe distinct sales invoice ids recorded against this group's discount usage entries — the invoices the discount itself was filed against. The response does not say how these relate to paymentInfo.salesInvoiceId, so do not assume they are the same invoices.
futureBookings[].discountDetails.promotionCodesarray of stringThe distinct promotion codes applied across the group, with blank entries dropped. This can be an empty array while the amount fields are populated, where the underlying records carry no code.

Sample response

200 OK
{
  "bookingHistory": [
    {
      "bookings": [
        {
          "bookingId": 12345,
          "bookingRef": 1,
          "slotReference": "string",
          "name": "string",
          "keyBookeeMemberId": 12345,
          "activityId": "string",
          "activityName": "string",
          "activityDescription": "string",
          "dateTime": "2026-08-14T19:00:00Z",
          "siteId": "string",
          "location": {
            "id": "string",
            "description": "string",
            "translations": [
              {
                "type": "string",
                "culture": "string",
                "text": "string"
              }
            ]
          },
          "attendedInCentre": true,
          "attendedVirtually": true,
          "keyBookeeIncludedInd": true,
          "paymentInfo": {
            "salesInvoiceId": 12345,
            "salesInvoiceTotal": 10.5,
            "salesInvoiceStatus": "string",
            "salesReceiptId": 12345
          },
          "translations": [
            {
              "type": "string",
              "culture": "string",
              "text": "string"
            }
          ],
          "bookeePriceLevels": [
            {
              "id": "string",
              "description": "string",
              "count": 1,
              "price": 10.5,
              "translations": [
                {
                  "type": "string",
                  "culture": "string",
                  "text": "string"
                }
              ]
            }
          ],
          "keyBookeeBookingInfo": {
            "priceLevelId": "string",
            "price": 10.5
          }
        }
      ],
      "discountDetails": {
        "originalPrice": 10.5,
        "discountedPrice": 10.5,
        "discountAmount": 10.5,
        "discountSalesInvoiceIds": [
          12345
        ],
        "promotionCodes": [
          "string"
        ]
      }
    }
  ],
  "futureBookings": [
    {
      "bookings": [
        {
          "bookingUuid": "b7f3c1e2-9a44-4f2b-8c17-0d5e9a1b6c33",
          "bookingId": 12345,
          "bookingRef": 1,
          "slotReference": "string",
          "name": "string",
          "keyBookeeMemberId": 12345,
          "activityId": "string",
          "activityName": "string",
          "activityDescription": "string",
          "imageUrl": "string",
          "dateTime": "2026-08-14T19:00:00Z",
          "endDateTime": "2026-08-14T19:00:00Z",
          "siteId": "string",
          "siteName": "string",
          "siteTranslations": [
            {
              "type": "string",
              "culture": "string",
              "text": "string"
            }
          ],
          "isRefundable": true,
          "keyBookeeIncludedInd": true,
          "location": {
            "id": "string",
            "description": "string",
            "translations": [
              {
                "type": "string",
                "culture": "string",
                "text": "string"
              }
            ]
          },
          "inCentre": {
            "bookingConfirmed": true,
            "onAlertList": true
          },
          "virtual": {
            "bookingConfirmed": true,
            "onAlertList": true
          },
          "paymentInfo": {
            "salesInvoiceId": 12345,
            "salesInvoiceTotal": 10.5,
            "salesInvoiceStatus": "string",
            "salesReceiptId": 12345
          },
          "translations": [
            {
              "type": "string",
              "culture": "string",
              "text": "string"
            }
          ],
          "bookeePriceLevels": [
            {
              "id": "string",
              "description": "string",
              "count": 1,
              "price": 10.5,
              "translations": [
                {
                  "type": "string",
                  "culture": "string",
                  "text": "string"
                }
              ]
            }
          ],
          "keyBookeeBookingInfo": {
            "priceLevelId": "string",
            "price": 10.5
          }
        }
      ],
      "discountDetails": {
        "originalPrice": 10.5,
        "discountedPrice": 10.5,
        "discountAmount": 10.5,
        "discountSalesInvoiceIds": [
          12345
        ],
        "promotionCodes": [
          "string"
        ]
      }
    }
  ]
}

Errors

StatusMeaningWhen
400Bad requestTwo causes. Both includeBookingHistory and includeFutureBookings were sent as false — the body reads You must include either booking history or future bookings in the request. Or memberId is 0 or negative, giving {memberId} is an invalid member ID. A 400 from one of the lookups this call makes is also passed straight through, with a body naming the part that failed and quoting its response.
404Not foundThe member does not exist, or one of the lookups this call makes could not find them. The status and body are relayed verbatim from whichever lookup failed, so the body names it — for example Booking History Service returned 404: Member ID {id} does not exist or Member Link Service returned 404: …. Nothing partial is returned: a failure on any one of the fan-out calls aborts the whole response.
500Internal server errorAn unexpected failure while resolving links, fetching bookings or aggregating them — and also the catch-all for any failure status other than 400 or 404 from one of the lookups this call makes, so a 403 or 409 from one of them surfaces here as a 500 with an empty body.
503Service unavailablePart of the platform this call depends on could not be reached at all. The body reads At least one of the services is unavailable. This is the transient case — retry it, unlike a 400.

This page as markdown · All pages · llms.txt