Skip to main content

Manage passes

List passesโ€‹

GET /v1/passes

Scope store:read. Query: page, per_page, who_can_buy (everyone / staff_only / off), for_sale (true / false).

{
"data": [
{
"id": 4,
"name": "Season pass",
"description": null,
"price": 150.0,
"billing": "once",
"discount_percent": null,
"visits": 10,
"unlimited_visits": false,
"valid_from": "2026-07-01",
"valid_to": "2026-08-31",
"valid_for": null,
"valid_for_unit": null,
"validity": "Jul 1, 2026 - Aug 31, 2026",
"experience_applies_to": "experiences",
"rental_applies_to": "none",
"covers": "items",
"experience_ids": [12],
"product_ids": [],
"experience_category_ids": [],
"product_category_ids": [],
"who_can_buy": "everyone",
"for_sale": true,
"sold_online": true,
"created_at": "2026-06-01T08:00:00+00:00",
"updated_at": "2026-06-01T08:00:00+00:00"
}
],
"meta": { "current_page": 1, "per_page": 15, "total": 1, "total_pages": 1 }
}

validity is how long the pass works, in words, as the booking page shows it: the dates, or Valid for 12 months from purchase. It is null for a membership.

Get a passโ€‹

GET /v1/passes/{id}

Scope store:read. Returns one pass in the shape above, or 404.

Create a passโ€‹

POST /v1/passes

Scope store:write.

FieldTypeRequiredDescription
namestringyesWhat customers see, up to 120 characters
pricenumberyesIn the shop's currency. For a membership, the monthly fee
billingstringnoonce (default): a season pass, paid for once. monthly: a membership, charged every month; it has no visits or dates, so those fields are ignored
discount_percentnumberwith monthly1 to 100. The member discount, taken off every line the membership covers
visitsintegerno1 to 1000. Leave out or send null for unlimited
valid_fromdate Y-m-dnoFirst day it works
valid_todate Y-m-dnoLast day it works, on or after valid_from
valid_forintegernoInstead of dates: how long each pass works from the day it is bought. Up to 120 months or 3660 days. Not with valid_from / valid_to
valid_for_unitstringnomonths or days. Left out, a pass keeps the unit it has; a new one uses months
experience_applies_tostringnoWhich experiences it covers: all, categories, experiences or none
rental_applies_tostringnoWhich rental items it covers: all, categories, products or none
experience_category_ids, experience_idsinteger[]with categories / experiencesThe chosen experience categories or experiences
product_category_ids, product_idsinteger[]with categories / productsThe chosen rental categories or rental items
who_can_buystringnoeveryone (default): the booking page, POS and the app. staff_only: POS, the app, the API and Dash, never the booking page. off: not for sale; passes already sold keep working

A pass has to cover something: at least one of the two is not none, and a categories, experiences or products scope names at least one id. Otherwise the call returns 422. A category covers everything under it, its subcategories included. all covers every experience (or rental item) the shop sells, including ones added later. Ids that belong to another shop are ignored.

Sending valid_for together with valid_from or valid_to returns 422: a pass runs from purchase or between fixed dates. A monthly pass ignores both.

A monthly pass with no discount_percent returns 422. A shop that cannot take card payments through Stripe gets 422 memberships_need_stripe when it creates a monthly pass or switches one to monthly.

Older fieldsโ€‹

These still work, and map onto the fields above:

FieldMaps to
covers (items / categories) with the id liststhe matching *_applies_to for each module that has ids, none for the other
for_sale: falsewho_can_buy: off
sold_online: falsewho_can_buy: staff_only

The response still carries covers, for_sale and sold_online, worked out from the new fields. Read experience_applies_to, rental_applies_to and who_can_buy instead.

{
"name": "10 visit pass",
"price": 180,
"visits": 10,
"valid_from": "2026-07-01",
"valid_to": "2026-12-31",
"experience_applies_to": "categories",
"experience_category_ids": [3],
"rental_applies_to": "all",
"who_can_buy": "everyone"
}

Returns 201 with the pass.

A pass that runs for 12 months from the day each customer buys it:

{
"name": "10 visit pass",
"price": 115,
"visits": 10,
"valid_for": 12,
"valid_for_unit": "months",
"experience_applies_to": "all"
}

Update a passโ€‹

PATCH /v1/passes/{id}

Scope store:write. Send only the fields you change. Changing a pass never changes the passes customers already bought: each keeps the name, visits and dates it was sold with, and each member keeps the monthly price and discount they signed up at.

To switch a pass to running from purchase, send valid_for (its dates are cleared). To switch it back, send valid_from and/or valid_to on their own, or valid_for: null. Customer passes already sold keep the dates they were sold with.

Delete a passโ€‹

DELETE /v1/passes/{id}

Scope store:write. Returns 204. A pass that has been sold cannot be deleted and returns 409 pass_sold; set who_can_buy to off instead.