Create Booking Option
Add another way to sell an experience.
The new option lands at the bottom of the list. Use Reorder booking options to move it.
Endpointโ
POST /v1/experiences/{id}/booking-options
Authenticationโ
Requires an API key with the experiences:write scope. There is no separate booking-options scope.
Path Parametersโ
| Parameter | Type | Description |
|---|---|---|
id | integer | Experience ID |
Request Bodyโ
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | What the shop calls this way of booking, for example Private session. 1 to 120 characters |
price_structure | string | No | participant (a price per person) or group (one price for the whole party). Defaults to participant |
exclusive | boolean | No | true when booking this takes the whole session, so nobody else can join it. Defaults to false |
min_people | integer | No | Smallest party this option takes, at least 1. Omit or send null for no minimum of its own |
max_people | integer | No | Largest party this option takes, at least 1. Omit or send null for no limit of its own |
default_groups_capacity | integer | No | How many groups one session sells under this option, at least 1. Omit or send null to use the experience's own number |
unit_name | string | No | What each group is under this option, for example canoe. Up to 40 characters. Omit or send null to follow the experience's unit_name |
unit_name_plural | string | No | The plural, when the worked-out one is wrong. Up to 40 characters. Omit it and canoe reads canoes |
duration_value | number | No | This option's own length, greater than zero. Only accepted with duration_unit |
duration_unit | string | No | minutes, hours or days. Only accepted with duration_value |
Leave both duration fields out and the option runs for as long as the experience says.
Example Requestโ
curl -X POST "https://app.equipdash.com/api/v1/experiences/1234567/booking-options" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Private session",
"price_structure": "group",
"exclusive": true,
"unit_name": null,
"unit_name_plural": null,
"min_people": 1,
"max_people": 4,
"duration_value": 90,
"duration_unit": "minutes"
}'
Responseโ
Success (201 Created)โ
{
"data": {
"id": 4322,
"experience_id": 1234567,
"name": "Private session",
"price_structure": "group",
"exclusive": true,
"unit_name": null,
"unit_name_plural": null,
"min_people": 1,
"max_people": 4,
"default_groups_capacity": null,
"duration": {
"value": 90,
"unit": "minutes"
},
"sort_order": 1,
"archived": false,
"archived_at": null,
"created_at": "2026-02-01T10:00:00+00:00",
"updated_at": "2026-02-01T10:00:00+00:00"
},
"meta": {
"request_id": "req_abc123",
"timestamp": "2026-02-01T10:00:00+00:00"
}
}
Errorsโ
| Status | Code | Description |
|---|---|---|
| 401 | authentication_required | No API key provided |
| 401 | invalid_api_key | Invalid API key |
| 403 | insufficient_scope | API key lacks experiences:write scope |
| 403 | forbidden | Experience belongs to a different supplier |
| 404 | resource_not_found | Experience does not exist |
| 422 | validation_error | Invalid request body |
Validation Rulesโ
nameis required and must be 1 to 120 charactersprice_structuremust beparticipantorgroupmin_peopleandmax_peoplemust each be at least 1, andmin_peoplecannot be greater thanmax_peopleduration_valuemust be greater than zero, and needsduration_unitwith it. Sending one without the other is refuseddefault_groups_capacitymust be at least 1. A session that takes no groups could never be booked
Where the message lands
EquipDash checks these rules in the one place every surface writes through, so the portal, the point of sale and this API all refuse the same request. Those messages come back under the field name in error.details, whatever the field actually at fault was. Read the message, not the field name:
{
"error": {
"code": "validation_error",
"message": "The given data was invalid.",
"details": [
{ "field": "name", "message": "The fewest people cannot be more than the most people." }
]
},
"meta": { "request_id": "req_abc123" }
}
Notesโ
- Adding a second live option is what tells the shop's booking page to offer a choice. While an experience has one option, no chooser appears anywhere.
- A new option has no price of its own until one is set for it. Give it one with Add pricing, naming this option's
idasbooking_option_id. A booking naming an option with no price is refused with422 booking_creation_failed. default_groups_capacityis a ceiling underexclusive, never an override of it. An option that books out the session takes the whole session however many groups this number allows.