Booking Requests
An experience or a rental product can be set to Request to book (booking_mode: "request").
Online bookings for it arrive as requests. Each one holds its time or its stock until the business
answers or the reply deadline passes. Nothing is confirmed, and nothing is charged, until the
request is approved.
An experience can also use booking_mode: "flexible_request". The customer proposes a date and
start time instead of choosing a published departure. Its configured duration supplies the end
time. The business can approve that time, decline it, or offer another date and start time.
A request is a booking with status: "requested", so it has the same ID as the booking it becomes.
state shows where the request stands:
state | Meaning |
|---|---|
waiting | Waiting on the business to answer |
offered | The business offered a different time or different dates, and is waiting on the customer |
approved | Approved and confirmed, still unpaid |
confirmed | Approved and paid |
declined | Declined by the business, or turned down by the customer |
lapsed | Nobody answered before request.expires_at |
Scopesโ
requests:read to list and read requests. requests:write to approve, decline and suggest.
The request objectโ
{
"id": 1234,
"booking_number": "1234",
"status": "requested",
"state": "waiting",
"type": "rental",
"is_flexible_time_request": false,
"experience": null,
"starts_at": "2026-09-18T00:00:00+00:00",
"ends_at": "2026-09-20T00:00:00+00:00",
"schedule_id": null,
"party_size": 0,
"items": [
{ "name": "Touring bike", "quantity": 2 }
],
"customer": { "id": 55, "name": "Jane Doe", "email": "jane.doe@example.com" },
"total": 120.0,
"total_formatted": "$120.00",
"currency": "usd",
"request": {
"message": "Two of us, first time out.",
"submitted_at": "2026-09-16T02:10:00+00:00",
"expires_at": "2026-09-17T02:10:00+00:00",
"decided_at": null,
"decline_reason": null,
"offered_at": null,
"card_on_file": false
}
}
| Field | Description |
|---|---|
type | experience for a scheduled departure, rental for products with a pickup and return |
is_flexible_time_request | true when an experience customer proposed the time instead of choosing a published departure |
starts_at / ends_at | UTC. The departure for an experience; the pickup and return for a rental |
schedule_id, party_size, experience | Experience requests only |
items | What the customer asked for: each bundle once, and each product not in a bundle |
request.expires_at | The reply deadline. The time or stock is held until then |
request.card_on_file | true when a card was saved at request time and will be charged on approval |
List requestsโ
GET /v1/booking-requests
| Parameter | Type | Description |
|---|---|---|
state | string | waiting, offered, approved, declined or lapsed |
search | string | A booking number (with or without #), or the customer's name or email |
per_page | integer | 1 to 100, default 25 |
Get a requestโ
GET /v1/booking-requests/{id}
Approveโ
POST /v1/booking-requests/{id}/approve
Confirms the booking after checking the time or stock is still free.
| Field | Type | Description |
|---|---|---|
guide_staff_id | integer | Optional. The staff member who leads a guided departure. Without it, a request for a customer-chosen start time gets any guide free and qualified at that time |
The response carries a payment block:
payment.status | What happened |
|---|---|
charged | The saved card was charged |
fell_back_to_link | The card could not be charged, so the customer was emailed a payment link |
collect_later | The business takes no payments online and collects payment itself |
nothing_due | Nothing was due |
Returns 409 slot_unavailable when the time or the stock has gone, or when no guide can run it.
Declineโ
POST /v1/booking-requests/{id}/decline
| Field | Type | Description |
|---|---|---|
reason | string | For the business's own records |
message | string | A note to the customer |
alternative_schedule_ids | integer[] | Experience requests only: up to 5 open departures to offer instead |
Nothing is charged, and the time or stock is released straight away.
Suggest something elseโ
POST /v1/booking-requests/{id}/suggest
For a scheduled experience request, send schedule_id: another published departure of the same
experience.
For a flexible experience request, send proposed_start_at. The experience duration supplies the
new end time. ISO 8601 values with an offset are read as that instant. Values without an offset are
read in the shop's time zone. The start must fit the shop's opening hours and finish by closing;
List Request Start Times returns the times that do.
For a rental request, send pickup_at and return_at (ISO 8601; a time with no offset is read in the
shop's time zone). The products are checked for the new dates and the total is recalculated.
| Field | Type | Description |
|---|---|---|
schedule_id | integer | Experience requests |
proposed_start_at | datetime | Flexible experience requests |
pickup_at | datetime | Rental requests, with return_at |
return_at | datetime | Rental requests, after pickup_at |
note | string | A note to the customer |
The request moves to offered, and its deadline restarts on the business's offer window. The
customer confirms from the link in their email.
curl -X POST "https://app.equipdash.com/api/v1/booking-requests/1234/suggest" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"pickup_at": "2026-09-19T00:00:00+00:00", "return_at": "2026-09-21T00:00:00+00:00"}'
Webhooksโ
booking_request.created, booking_request.approved and booking_request.declined. A lapse also
sends booking_request.declined.