Update Experience
Update an existing experience.
Endpointโ
PATCH /v1/experiences/{id}
Authenticationโ
Requires an API key with the experiences:write scope.
Parametersโ
| Parameter | Type | Location | Description |
|---|---|---|---|
id | integer | path | The experience ID |
Request Bodyโ
All fields are optional. Only provided fields will be updated.
| Field | Type | Description |
|---|---|---|
name | string | Experience name (max 255 characters) |
unique_code | string | Unique code |
brief_description | string | Short description |
long_description | string | Full description |
category_id | integer | Primary category ID. Use category_ids for multiple categories. |
category_ids | integer[] | Replace the experience's categories with this set (primary first). The first id becomes the primary. Takes precedence over category_id. |
status | string | active or inactive |
duration_value | number | Duration value (minimum: 0.1, decimals allowed, required when provided) |
duration_unit | string | Minutes, Hours, or Days (required when provided) |
price_applies | string | yearRound or seasonal |
price_structure | string | participant or group |
default_capacity | integer | Default capacity per session (for private experiences this is the maximum group size) |
is_private | boolean | Private or shared? Private = the first booking takes the whole departure. Set false for shared slots where groups fill seats individually until capacity. On per-person pricing it is saved on the experience's booking option (exclusive), and the seats stay seats |
min_people_per_booking | integer | The smallest party the booking site takes (e.g. 10 for a party). Works on per-person pricing, and on a private experience priced per group with no unit name, where it counts people in that one party. A shared experience priced per group is refused: use min_groups_per_booking. Making an experience shared, or giving it a unit name, clears it. Staff can still book fewer in POS. null clears it |
list_as_experience | boolean | Set false to sell the experience only on connected marketplaces: it stays active and fully manageable, but is hidden from the booking widget, POS and the shop's own website. Defaults to true |
suggest_in_cart | boolean | false leaves this experience out of the suggestions shown in the cart, on the confirmation page and in the confirmation email. true lets it be suggested again. |
staff_only | boolean | Set true so only the shop's team can book it: it stays in POS, the app, this API and Dash, and is hidden from the booking widget, embeds and the shop's own website. Only applies while list_as_experience is true. |
shares_places_with_id | integer or null | No |
booking_mode | string | instant, request, or flexible_request. request uses published departures. flexible_request lets the customer propose a date and start time. See Booking Requests |
requires_guide | boolean | Guide availability link: when true, a time slot only sells while enough of its assigned guides are free โ a guide locked onto an overlapping booked departure is not free. Guides are assigned per schedule (see Schedules โ Assigning guides) |
guides_needed | integer | Guides each departure needs before it can take bookings (default 1). Only meaningful when requires_guide is true |
equipment | array | Replace the gear list. Rows: {product_id (required), units_basis (booking|participant|session|unit), units_per (default 1), rate_category_id (optional: the one price this gear belongs to), ask_size (optional: true asks each person their size of this item, false stops asking, left out keeps it as it was)}. Rows left out are removed, and stop asking for a size. See Gear per price and Asking each person their size |
gear_per_price | boolean | true lets each price hold its own gear. false clears the gear set per price and keeps the gear every price uses |
location | string | Where the experience takes place |
min_booking_notice | boolean | Require advance booking |
min_booking_notice_value | integer | Notice period value |
min_booking_notice_unit | string | hours, days |
same_day_cutoff_time | string|null | Same-day cut-off in the shop's time zone, 24-hour "HH:MM" such as "08:30". Online bookings for that day close at this time; later days are not affected. A session that starts earlier closes at its start. Works alongside the notice length, and the stricter one wins. Sending a time turns min_booking_notice on; null removes the cut-off. |
deposit_type | string|null | percentage, fixed (one amount for the booking) or per_person (an amount for each person booked) for this experience's own deposit to book. null goes back to the shop's default deposit |
deposit_value | number|null | The percent (up to 100) or the fixed amount (up to 99999999.99). Sent alone, it changes the amount and keeps the type |
participants_required | boolean|null | Require participant details. true = always, false = never, null = follow the shop-wide default |
unit_name | string|null | What each group is, for example canoe. Up to 40 characters. null goes back to plain groups. See Create experience |
unit_name_plural | string|null | The plural, when the worked-out one is wrong. Up to 40 characters |
default_groups_capacity | integer|null | Group booking rules โ most groups one time slot can take. null = unlimited. Silently ignored unless the experience is group-priced, shared and not a package |
min_groups_per_booking | integer|null | Fewest groups per booking. null = no minimum |
below_min_groups_fee | number|null | Charged once per experience line when it has fewer groups than the minimum. null = bookings under the minimum are rejected instead |
below_min_groups_fee_label | string|null | Customer-facing name for that fee (max 255). null = localized "Small-group fee" |
volume_discount_from_group | integer|null | Discount threshold โ groups from this one onward (minimum 2) get the discount |
volume_discount_percent | number|null | Percent (0โ100) off each group from the threshold onward. Group base price only |
show_per_person_price | boolean | Also show an approximate per-person price on the widget. Display only |
people_discount_from | integer|null | Group discount on per-person prices - fewest people in one booking (minimum 2) that earns the discount. null turns it off. See Create experience |
people_discount_percent | number|null | Percent (0-100) off every per-person line once a booking reaches people_discount_from people. null turns it off |
required_certifications | string[] | Guide requirements - what a guide should hold to run this experience. Replaces the saved list; [] clears it. Warn-only: a guide without one is flagged when you assign them, never blocked. Values: Guide requirements |
required_languages | string[] | Guide requirements - what a guide should speak, as two-letter codes. Replaces the saved list; [] clears it. Same warn-only behavior. Values: Guide requirements |
counter_price | object | This item's counter price: mode (shop, same, more or less) and percent, e.g. {"mode": "more", "percent": 15} |
Group booking rulesโ
Group-priced experiences that share their slots (price_structure: "group", is_private: false, not a
package) can carry booking rules. The rules are enforced everywhere a booking is created โ this API,
the booking widget, the point of sale and the assistant โ so a quote and a charge always agree:
- Minimum groups โ a booking below
min_groups_per_bookingeither paysbelow_min_groups_feeonce, or is rejected with a validation error when no fee is configured. - Multi-group discount โ every group from
volume_discount_from_grouponward getsvolume_discount_percentoff that group's base price. - Groups per slot โ
default_groups_capacitycaps how many groups a departure can hold, independent of participant seats. Override it for a single departure withgroups_capacityon the schedule endpoints.
Both amounts are folded into the experience line's price, and are also returned separately
(below_min_fee_amount, below_min_fee_label, volume_discount_amount) so you can itemize them.
Sending any rule field for an ineligible experience stores null rather than returning an error.
Example Requestโ
curl -X PATCH "https://app.equipdash.com/api/v1/experiences/15" \
-H "Authorization: Bearer eqd_live_abc123xyz789..." \
-H "Content-Type: application/json" \
-d '{
"name": "Beginner Surf Lesson - All Ages",
"default_capacity": 10
}'
Responseโ
Success (200 OK)โ
Returns the updated experience resource. See Get Experience for response structure.
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 different supplier |
| 404 | resource_not_found | Experience does not exist |
| 422 | validation_error | Invalid request data |
| 422 | equipment_invalid | A gear row is wrong: an item that is not yours, a price not on this experience, or ask_size on an item with no sizes |