Get Booking
Retrieve a single booking by its ID.
Endpointโ
GET /v1/bookings/{id}
Authenticationโ
Requires an API key with the bookings:read scope.
Parametersโ
| Parameter | Type | Location | Description |
|---|---|---|---|
id | integer | path | The booking ID |
Responseโ
Success (200 OK)โ
{
"data": {
"id": 123,
"type": "rental",
"line_types": ["rental"],
"status": "confirmed",
"payment_status": "partial",
"source": "Online Booking",
"quote": null,
"attribution": {
"gclid": "EAIaIQobChMI...",
"gbraid": null,
"wbraid": null,
"fbclid": null,
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "summer-rentals",
"utm_term": null,
"utm_content": null,
"landing_url": "https://example.com/book?gclid=EAIaIQobChMI...",
"ref": "summer-flyer"
},
"start_date": "2026-01-15T09:00:00+00:00",
"end_date": "2026-01-17T17:00:00+00:00",
"duration_label": "3 Days / 2 Nights",
"multi_day": true,
"checked_in_at": null,
"completed_at": null,
"no_show_at": null,
"no_show_by": null,
"no_show_emails": true,
"currency": "USD",
"pricing": {
"subtotal": 250.00,
"total": 281.00,
"discount": {
"enabled": true,
"type": "percentage",
"value": 10
},
"payment_method_discount": null,
"promo_code": {
"code": "SUMMER10",
"amount": 15.00
},
"voucher": null,
"taxes": [
{
"name": "GST",
"rate": 10,
"amount": 21.00,
"included_in_price": false
}
],
"security_deposit": 50.00
},
"pickup_location": {
"id": 1,
"name": "Main Store",
"address": "123 Beach Road, Bondi NSW 2026, AU"
},
"return_location": {
"id": 1,
"name": "Main Store",
"address": "123 Beach Road, Bondi NSW 2026, AU"
},
"customer": {
"id": 456,
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "0412345678",
"phone_country_code": "+61"
},
"products": [
{
"id": 1,
"product_id": 10,
"product_name": "Mountain Bike",
"variation_id": 20,
"variation_name": "Large",
"bundle_in_booking_id": null,
"content_picks": [],
"fulfillment_status": "confirmed",
"quantity": 2,
"shortage_quantity": 1,
"rental_start": "2026-01-15T09:00:00+00:00",
"rental_end": "2026-01-17T17:00:00+00:00",
"price": 100.00,
"interval_units": "day",
"price_per_interval": 50.00,
"max_schedule_interval": null,
"additional_units": null,
"additional_unit_price": null,
"picked_up": null,
"returned": null
}
],
"experiences": [
{
"id": 55,
"experience_id": 3,
"experience_name": "Guided Coastal Excursion",
"schedule_id": 45,
"start_at": "2026-11-21T01:30:00+00:00",
"end_at": "2026-11-21T03:00:00+00:00",
"booking_option_id": 4321,
"booking_option_label": "Group class",
"unit_name": null,
"unit_name_plural": null,
"unit_summary": null,
"rate_category_id": null,
"quantity": 3,
"max_participants": 2,
"booked_participants": 6,
"actual_participants": 6,
"unit_price": 279.00,
"price": 809.10,
"below_min_fee_amount": null,
"below_min_fee_label": null,
"volume_discount_amount": 27.90,
"extras": [],
"package_choices": []
}
],
"bundles": [],
"payments": [
{
"id": 789,
"amount": 100.00,
"payment_method": "credit_card",
"offline_method": null,
"status": "completed",
"transaction_id": "txn_abc123",
"payment_provider": "stripe",
"gateway_reference": "pi_3Nabc123",
"gateway_refund_reference": null,
"stripe_fee": 3.20,
"stripe_fee_tax": 0.32,
"platform_fee": 1.00,
"payout_id": "po_1Nexample",
"reference": null,
"payment_date": "2026-01-10T00:00:00+00:00",
"created_at": "2026-01-10T14:30:00+00:00"
}
],
"custom_charges": [
{
"id": 1,
"description": "Delivery fee",
"quantity": 1,
"unit_price": 20.00,
"price": 20.00
}
],
"tags": [
{
"id": 1,
"name": "VIP"
}
],
"notes": [
{
"id": 1,
"text": "Customer requested early pickup",
"created_by": {
"id": 5,
"name": "Jane Smith"
},
"created_at": "2026-01-10T10:00:00+00:00"
}
],
"custom_fields": [
{
"field_id": 1,
"label": "License Number",
"field_type": "text",
"value": "DL-123456",
"formatted_value": "DL-123456"
}
],
"created_at": "2026-01-10T09:00:00+00:00",
"updated_at": "2026-01-10T14:30:00+00:00"
},
"meta": {
"request_id": "req_abc123",
"timestamp": "2026-01-15T12:00:00+00:00"
}
}
Cancelled Bookingโ
Cancelled bookings include additional cancellation details:
{
"data": {
"id": 123,
"status": "cancelled",
"cancellation": {
"reason": "change_in_travel_plans",
"notes": "Customer rescheduling for next month"
},
...
}
}
Response Fieldsโ
Bookingโ
| Field | Type | Description |
|---|---|---|
id | integer | Unique booking identifier |
type | string | rental or experience |
status | string | See Booking Status |
payment_status | string | unpaid, partial, paid, refunded |
source | string | Where the booking was created (e.g., "Online Booking", "POS") |
quote | object|null | Present when the booking began life as a quote: id, quote_number (e.g. "Q-123"), accepted_at (ISO 8601). The quote endpoints still serve its proposal history. null for bookings that never were a quote |
start_date | string | ISO 8601 datetime |
end_date | string | ISO 8601 datetime. For a multi-day experience departure this is the return instant (a later day) |
rental_window | object|null | When the gear is out, as start and end ISO 8601 datetimes. On a booking with gear and an activity, start_date and end_date cover both, and this is the gear's part. null when the booking has no gear |
duration_label | string | Owner-facing duration. For a multi-day experience departure this is the trip length in tour-operator phrasing (days first, nights = days โ 1), e.g. "3 Days / 2 Nights"; otherwise the elapsed duration |
multi_day | boolean | true when this is a multi-day experience departure (one booking spanning several days) |
checked_in_at | string | null |
completed_at | string | null |
no_show_at | string|null | When staff marked the booking as a no-show (ISO 8601). null unless status is no_show. One person in a group is on participants[].no_show_at instead |
no_show_by | object|null | Who marked it: id and name. null when it was marked with an API key, which has no person behind it |
no_show_emails | boolean|null | true when marking the whole booking now makes it read no_show, so email_customer would send the We missed you email. false when part of it already went ahead and the mark would leave it as it is. Use it to decide whether to offer an "Email the customer" choice |
currency | string | ISO 4217 currency code |
pricing | object | Pricing breakdown |
pickup_location | object|null | Pickup location (id, name, address) |
return_location | object|null | Return location (id, name, address) |
customer | object | Customer details |
products | array | Products in booking (rentals). Each line carries shortage_quantity โ see Shortage on a rental line |
experiences | array | Experiences in booking. Each line carries start_at and end_at (ISO 8601, UTC): when it actually runs. On an open-window experience that is the start chosen for that day and that start plus the experience length; otherwise the session's own start, and its start plus the experience length. A booking can hold the same experience on several days, one line per day |
bundles | array | Bundles in booking |
payments | array | Payment transactions |
passes_sold | array | Passes bought on this booking: id, name, holder_name, code, price, visits_total (null = unlimited), visits_left, status. Single-booking responses only |
gift_cards_sold | array | Gift cards bought on this booking: id, amount, currency, recipient_name, recipient_email, message, status (pending until paid, then issued; cancelled if the booking is cancelled first), voucher_id and code (both null until issued), issued_at. Single-booking responses only |
custom_charges | array | Additional charges |
tags | array | Associated tags |
notes | array | Staff notes |
cancellation | object | Only present for cancelled bookings |
custom_fields | array | Custom field values for this booking |
participants | array | Per-participant rows (experiences and multi-person rentals). Each carries a waivers array (see Participant Waiver Status), plus gear_sizes and missing (see Participant Sizes and Missing Answers). checked_in_at and no_show_at say whether the person came; no_show_at is null once they check in. Use id with Mark a No Show |
payment_provider | string | The gateway this shop takes card payments on: stripe, paystack, rapyd, authorizenet or tilopay. Read it before building a card form, rather than assuming Stripe |
security_deposit_status | string | Security-deposit lifecycle: none, held, charged, released, captured. The amount lives on pricing.security_deposit. |
deposit_saved_card_available | boolean | true when the card from an online checkout was saved and the deposit can be held on it without the customer present |
card_readers_available | boolean | false when the shop's payment provider has no card readers, so in-person card collection is not offered. Only Stripe offers them today |
has_booking_request | boolean | true when the booking came in as a request, so GET /v1/booking-requests/{id} returns it. Single-booking responses only |
fit_ticket_available | boolean | true when an item or experience on the booking takes a fit (set on it or on its product type), so GET /v1/bookings/{id}/fit-ticket returns one rather than 422. Single-booking responses only |
security_deposit_lots | array | Present on single-booking responses when the deposit is split into parts (e.g. a group where each participant pays their own). One entry per part โ see Split Security Deposits. Empty array when not split. |
created_at | string | ISO 8601 datetime |
updated_at | string | ISO 8601 datetime |
Rental fulfillment and inventoryโ
Each product line carries fulfillment_status: confirmed, picked_up, returned, cancelled, or no_show. Use it for the line's status. Tracked rentals record pickup and return on their inventory_items; the line's picked_up and returned timestamps can remain null.
inventory_items contains stock reserved directly for that rental's booking and selected variation. It excludes reservations for extras, linked kit contents, and experience gear, even when they use the same product. Each item carries its inventory-log id, inventory_id, identifier, location, quantity, picked_up, and returned. Read these item timestamps when offering partial pickup or return.
fulfillment_items is present on single-booking responses. It groups each rental's own stock, extras, and linked kit parts for pickup and return. Use these rows when presenting individual or group selection; each row supplies its kind, quantity, product_name, inventory-log id (or a pib_ line ID for untracked stock), fulfillment_status, and pickup and return timestamps. Completed rows remain visible. Repeated lines for the same product keep their own stock rows.
rate_label describes the saved quoted rate, for example day for a daily rate or a named duration for a total price. rate_mode is perUnit or total for saved quotes, and null on older lines. Show price_per_interval with rate_label, and use price for the line total. Later catalog edits do not change a saved quote's wording.
Payment Fieldsโ
Each entry in payments names the gateway that took the money:
| Field | Type | Description |
|---|---|---|
payment_provider | string | stripe, paystack, rapyd, authorizenet or tilopay |
gateway_reference | string|null | The gateway's own id for the payment (a Stripe PaymentIntent, a Paystack reference, a Rapyd payment id, an Authorize.net transaction id or a Tilopay order number). null for cash, bank transfer and other offline payments |
gateway_refund_reference | string|null | The gateway's own id for a refund, which is a separate transaction from the payment it reverses. null on payment rows and on offline refunds |
stripe_fee | number|null | The fee Stripe took on this payment |
stripe_fee_tax | number|null | The tax Stripe charged on its fee (for example GST or VAT), where Stripe charges one |
platform_fee | number|null | The EquipDash fee taken from this payment |
payout_id | string|null | The Stripe payout this payment went out in (po_...) |
stripe_fee, stripe_fee_tax, platform_fee and payout_id are null until Stripe has settled the charge, and always null on payments not taken through Stripe.
Split Security Depositsโ
A booking's security deposit can be collected in multiple parts, each with its
own amount and lifecycle, optionally linked to a participant. When split, the
booking-level security_deposit_status is an aggregate (held while any part
is held, released once every part is released, and so on) and
security_deposit_lots carries the detail:
"security_deposit_lots": [
{
"id": 12,
"name": "Jane Doe",
"booking_participant_id": 45,
"participant_email": "jane.doe@example.com",
"amount": 200.00,
"status": "held",
"hold_error": null,
"taken_by": "Cash"
}
]
| Field | Type | Description |
|---|---|---|
id | integer | The deposit part's identifier |
name | string | Display name โ the linked participant's name, or a custom label |
booking_participant_id | integer|null | The participant paying this part, when linked |
participant_email | string|null | That participant's email (used for payment links) |
amount | number | This part's amount |
status | string | none, held, charged, released, captured |
hold_error | string|null | Last collection failure for this part (e.g. a card decline) |
taken_by | string|null | How the part was collected (Card, Cash, โฆ) once held/charged |
Participant Waiver Statusโ
Each participant carries a waivers array โ one entry per waiver/form that applies to the booking โ so you can render per-person completion exactly like the dashboard:
"waivers": [
{ "form_id": 5, "form_name": "Liability Waiver", "signed": true, "on_file": false, "valid_until": null, "response_id": 91 },
{ "form_id": 8, "form_name": "Membership Consent", "signed": true, "on_file": true, "valid_until": "2027-07-22", "response_id": 74 },
{ "form_id": 9, "form_name": "Health Declaration", "signed": false, "on_file": false, "valid_until": null, "response_id": null }
]
| Field | Type | Description |
|---|---|---|
form_id | integer | The waiver/form identifier |
form_name | string | The waiver/form name |
signed | boolean | true when this participant has satisfied the form โ by a signature on this booking or a still-valid consent on file. Never re-ask when true |
on_file | boolean | true when signed is satisfied by a consent on file โ a still-valid signature carried over from an earlier booking โ rather than a fresh signature on this booking |
valid_until | string|null | Date (YYYY-MM-DD) the consent on file remains valid through; null unless on_file is true |
response_id | integer|null | The satisfying form response id (use with the waiver response endpoints to fetch the signed record); null when unsatisfied |
Participant Sizes and Missing Answersโ
When an experience on the booking asks each person their size of an item, or asks a question of the shop's own, each participant carries what they gave and what is still to come:
{
"id": 45,
"first_name": "Jane",
"last_name": "Doe",
"gear_sizes": [
{ "product_id": 41, "item": "Wetsuit", "size": "M" }
],
"missing": ["Helmet size", "Can you swim 50m?"]
}
| Field | Type | Description |
|---|---|---|
gear_sizes | array | One row per item this person gave a size for: product_id, item (the item's name) and size. A size given for an item the experience no longer asks about stays here. Empty when there are none |
missing | string[] | The questions this person has not answered yet, by label: sizes and the shop's own questions. Empty when nothing is missing |
The answers to the shop's own questions are in custom_fields. A booking can be saved with
something still missing; set it later with Update Participant. What each
experience asks is listed by List Questions.
Pricing Objectโ
| Field | Type | Description |
|---|---|---|
subtotal | number | Price before tax. |
total | number | Total including tax. |
discount | object | Manual discount on the booking (enabled, and when enabled type, value, amount). |
payment_method_discount | object|null | The in-person payment-method discount (cash / debit / bank transfer). null when none is applied, otherwise { "rate": <percent>, "amount": <currency>, "label": <string> }. Apply or clear it with PUT /v1/bookings/{id}/payment-method-discount. |
promo_code | object|null | Applied promo code (code, amount) or null. |
voucher | object|null | Applied voucher / gift card (code, amount) or null. |
taxes | array | Tax lines: name, rate, amount, included_in_price. |
security_deposit | number|null | Security-deposit amount, or null when none. |
Custom Fieldsโ
| Field | Type | Description |
|---|---|---|
field_id | integer | Custom field definition ID |
label | string | Field display label |
field_type | string | Field type: text, textarea, number, date, datetime |
value | string|null | Raw value |
formatted_value | string|null | Formatted value for display |
Custom field definitions can be retrieved via GET /v1/settings/custom-fields.
Booking Statusโ
| Status | Description |
|---|---|
draft | Booking is being created |
confirmed | Booking is confirmed, awaiting pickup/check-in |
picked_up | Customer has picked up items (rental) |
checked_in | Customer has checked in (experience) |
returned | Items have been returned (rental) |
completed | Booking is complete |
no_show | The customer never came. The seat stays sold, the revenue is kept, the rental items are free for other bookings, and any balance is still due. See Mark a No Show |
cancelled | Booking has been cancelled |
Shortage on a rental lineโ
Each entry in products reports how much of the line was covered by stock the shop actually had:
| Field | Type | Description |
|---|---|---|
shortage_quantity | integer | How many units of this line were sold past on-hand stock. 0 means the line was fully covered by real stock |
A non-zero value means the product is set to
keep selling when sold out and this booking used
part of that allowance โ the shop needs to source that many extra units before the pickup date. The
line is a normal confirmed line in every other respect; quantity is still the full quantity booked,
not the covered part.
When the gear is outโ
A booking that holds gear and an activity (a lesson, a tour) has a start_date and end_date
that cover both. Each entry in products carries the gear's own window:
| Field | Type | Description |
|---|---|---|
rental_start | string|null | ISO 8601 datetime the gear is picked up |
rental_end | string|null | ISO 8601 datetime the gear is due back |
Both are null on lines saved before these fields existed. Read the booking's rental_window
for those.
Group booking rules on an experience lineโ
A group-priced experience line reports its quantity in groups (quantity), with max_participants
people covered per group. When the experience carries booking rules, the line also returns:
| Field | Type | Description |
|---|---|---|
below_min_fee_amount | number|null | Fee charged once because the line has fewer groups than the experience's minimum. null when no fee applied |
below_min_fee_label | string|null | The shop's name for that fee. null = show the localized default ("Small-group fee") |
volume_discount_amount | number|null | Money taken off for booking multiple groups. null when no discount applied |
Both amounts are already folded into price โ the fee added, the discount subtracted. Render them as
sub-lines for transparency; never add or subtract them from price again.
The booking option on an experience lineโ
When the shop sells an experience more than one way, the line says which way it was sold as. See Booking options.
| Field | Type | Description |
|---|---|---|
booking_option_id | integer|null | The booking option this line was sold as. null on a line taken before the shop set its options up |
booking_option_label | string|null | The option's name as it read when the booking was taken. Null unless the shop sells that experience more than one way - see the note below |
The label is a snapshot, so renaming the option or retiring it never rewrites an existing booking. A shop that sells its experience one way still gets both fields filled, with the single option it has.
Lines sold per unitโ
| Field | Type | Description |
|---|---|---|
unit_name | string|null | What each group was sold as ("canoe"), when the experience is priced per unit. null on an ordinary group or per-person line |
unit_name_plural | string|null | The plural that goes with it ("canoes"). null when unit_name is null |
unit_summary | string|null | The line as the shop reads it: "2 canoes ยท 4 people", or "3 canoes" when the experience has no people limit per canoe and no headcount was asked. null when unit_name is null |
Both are a snapshot of the word the line was sold under, so renaming it on the experience never
rewrites a booking. When unit_name is set, quantity is the number of units and
booked_participants is the number of people: "quantity": 2, "booked_participants": 4 reads as
2 canoes, 4 people. When it is null, quantity means what it always has.
Options picked inside a kitโ
A kit is a product made of other products (a camping kit holds a tent, sleeping bags and a cooler). When the shop lets the customer pick the option for a part, each line in products says what was picked.
| Field | Type | Description |
|---|---|---|
content_picks | array | One entry per part the customer picked an option for: {"part_id": 957, "part": "YETI Tundra (Cooler)", "option": "65 QT", "text": "YETI Tundra (Cooler): 65 QT"}. Empty on a line that is not a kit, or when nothing was picked |
text is the line the shop's own screens and emails print. To set the options when creating a booking, send content_variations on the product line (see Create a booking).
A booking on several daysโ
| Field | Type | Description |
|---|---|---|
check_in_day | object|null | On a booking with the same activity on several days, the day the next check-in call checks in: today, else the most recent day missed, else the next day to come. Same shape as day_to_check_in. null on a one-day booking and once every day is checked in |
day_to_check_in | object|null | On a booking with the same activity on several days, the day still to check in, dated today or later: {"date": "2026-11-23", "starts_at": "2026-11-23T00:00:00+00:00"}. null on a one-day booking and once no day is still to come (the booking can then be completed) |
Errorsโ
| Status | Code | Description |
|---|---|---|
| 401 | authentication_required | No API key provided |
| 401 | invalid_api_key | Invalid API key |
| 403 | insufficient_scope | API key lacks bookings:read scope |
| 403 | forbidden | Booking belongs to different supplier |
| 404 | resource_not_found | Booking does not exist |
Example Requestโ
curl -X GET "https://app.equipdash.com/api/v1/bookings/123" \
-H "Authorization: Bearer eqd_live_abc123xyz789..."
Example Error Responseโ
{
"error": {
"code": "resource_not_found",
"message": "The requested booking was not found."
},
"meta": {
"request_id": "req_def456"
}
}