Skip to main content

Event packages API

An event package is a ready-made bundle of activities, for example "Team day: mini golf + laser tag". Customers book a package as a booking group: one hold, one price, one payment.

A package has:

  • a list of activities (a product at a site, in order)
  • party size limits
  • a price: a fixed total, a per-person bundle price, or the sum of the activities' own prices
  • an active flag and a public flag

For how staff set up packages in the admin UI, see Event packages.

Customer endpoints​

These endpoints need the x-tenant-id header and, at the moment, a signed-in user (Authorization: Bearer <token>).

MethodPathDescription
GET/api/v1/event-packagesList active, public packages.
GET/api/v1/event-packages/{slug}Get one active package by its slug.

Example response item:

{
"id": "pkg_team_day",
"name": "Team day",
"description": "Mini golf and laser tag for your team",
"slug": "team-day",
"minPartySize": 10,
"maxPartySize": 40,
"bundlePricePerPerson": 55.0,
"fixedPrice": null,
"imageUrl": null,
"isActive": true,
"isPublic": true,
"holdTtlMinutes": null,
"items": [
{
"id": "item_1",
"productId": "p_golf",
"siteId": "s_center",
"sortOrder": 0,
"durationOverride": null,
"isRequired": true
}
]
}

The slug lookup returns any active package, public or not, so you can share a private package by its link.

Admin endpoints​

Admin endpoints need a staff token with the manage_catalog permission.

MethodPathDescription
GET/api/v1/admin/event-packagesList all packages, including inactive and private ones.
POST/api/v1/admin/event-packagesCreate a package.
GET/api/v1/admin/event-packages/{id}Get a package.
PATCH/api/v1/admin/event-packages/{id}Update a package. Send only the fields you change.
DELETE/api/v1/admin/event-packages/{id}Delete a package. Existing booking groups are not affected.
POST/api/v1/admin/event-packages/{id}/itemsAdd an activity.
PATCH/api/v1/admin/event-packages/{id}/items/{itemId}Change an activity's order, duration or required flag.
DELETE/api/v1/admin/event-packages/{id}/items/{itemId}Remove an activity.

Create a package​

{
"name": "Team day",
"description": "Mini golf and laser tag for your team",
"minPartySize": 10,
"maxPartySize": 40,
"bundlePricePerPerson": 55.0,
"isActive": true,
"isPublic": false,
"holdTtlMinutes": 30,
"items": [
{ "productId": "p_golf", "siteId": "s_center", "sortOrder": 0 },
{ "productId": "p_laser", "siteId": "s_center", "sortOrder": 1 }
]
}
FieldRequiredDescription
nameYesDisplay name. The slug is made from it and must be unique.
minPartySizeYesSmallest group, at least 1.
maxPartySizeYesLargest group, up to 500.
descriptionNoMarketing text.
bundlePricePerPersonNoPrice per person for the whole package.
fixedPriceNoTotal price, whatever the party size.
imageUrlNoPackage image.
isActiveNoDefault true.
isPublicNoListed to customers. Default false.
holdTtlMinutesNoHow long a group hold lasts, 5–120 minutes.
itemsNoActivities. You can also add them later.

Each item takes productId, siteId, and optionally sortOrder, durationOverride (minutes) and isRequired. The product must belong to the site, or the request fails with 400.

If you change the name, the slug changes too, and old links stop working.

Pricing​

When a group is priced, the first rule that applies wins:

  1. fixedPrice: the group total.
  2. bundlePricePerPerson: multiplied by the party size.
  3. Neither set: the sum of each activity's own price.

The total is then split across the group's bookings in proportion to each activity's own price. Partial refunds use this split.