Skip to content

Bundles, promo codes & tags

The catalogue resources that dress up bookings: bundles of paid add-ons, promo codes for discounts, and tags for classifying guests and reservations. This page also covers copy-from, which clones a settings scope from another of your venues. Every endpoint is under /api/my-venues/:venueId/… and is operator (client role, venue-scoped) - send an Authorization: Bearer token from the Authentication flow. Prices are integer pence.

Method Path Purpose Auth
GET/POST /api/my-venues/:venueId/bundles List/create bundles operator
PUT/DELETE /api/my-venues/:venueId/bundles/:id Update/delete a bundle operator
POST /api/my-venues/:venueId/bundles/:id/image Upload bundle banner image operator
POST /api/my-venues/:venueId/bundles/:id/items Add a bundle item operator
PUT/DELETE /api/my-venues/:venueId/bundles/:id/items/:itemId Update/delete an item operator
PUT /api/my-venues/:venueId/bundles/:id/items/reorder Persist a drag-reordered item list operator
POST /api/my-venues/:venueId/bundles/:id/items/:itemId/image Upload item image operator
POST /api/my-venues/:venueId/copy-from Copy a settings scope from another venue operator
GET/POST /api/my-venues/:venueId/promo-codes List/create promo codes operator
PUT/DELETE /api/my-venues/:venueId/promo-codes/:id Update/delete a promo code operator
POST /api/my-venues/:venueId/promo-codes/:id/reset Reset redemption count operator
GET /api/my/tag-catalogue Account-wide default tags operator
GET /api/my-venues/:venueId/tag-catalogue Venue tag catalogue operator
POST/DELETE /api/my-venues/:venueId/tags Add/remove a custom tag operator
PATCH /api/my-venues/:venueId/tags Set/clear a tag colour or rename a custom tag operator
POST /api/my-venues/:venueId/tag-categories Add a custom category operator
PATCH /api/my-venues/:venueId/tag-categories Update category visibility operator

A bundle has a name, an optional applicable_profiles array ("tables", "events"; omit to apply to both), and an optional image_url for the wide banner shown above the bundle in the booking wizard and widget. To set it, POST .../bundles/:id/image with a base64 data URL in a data field (max 2 MB, cropped to a 4:1 aspect); the response returns { "success": true, "url": "…" }. PUT .../bundles/:id with image_url: null removes it. Items live under a bundle, each with a name, price (pence), optional max_qty and image_url.

An item can also carry an optional variant_groups array of configurable option sets (for example “Size” or “Add-ons”). Each group is { "id", "name", "type", "options" }, where type is "single" (pick one) or "multi" (pick any number), and each option is { "id", "label", "price" } with price a non-negative pence modifier added on top of the item price. You may omit each id on create and one is generated for you; omit variant_groups (or send an empty array) for a plain item.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/bundles" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"VIP Package","applicable_profiles":["tables"]}'
{ "success": true, "id": "bnd_vip" }

Then POST /api/my-venues/:venueId/bundles/:id/items to add an item:

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/bundles/bnd_vip/items" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Bottle of Champagne","price":12000,"max_qty":5}'
{ "success": true, "id": "itm_champ" }

Update an item with PUT .../bundles/:id/items/:itemId and delete it with DELETE .../bundles/:id/items/:itemId. To give an item a picture, POST .../bundles/:id/items/:itemId/image with a base64 data URL in a data field (max 2 MB); the response returns { "success": true, "url": "…" } and stores it as the item’s image_url.

PUT /api/my-venues/:venueId/bundles/:id/items/reorder persists a drag-reordered item list. Send { "item_ids": [...] } with every item id in the order you want; each item’s sort order is set to its position in the array. item_ids is required (an empty list returns 400).

Terminal window
curl -X PUT "https://thesidedoor.co/api/my-venues/VENUE_ID/bundles/bnd_vip/items/reorder" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"item_ids":["itm_champ","itm_cake","itm_flowers"]}'

POST /api/my-venues/:venueId/copy-from clones a scope of settings from a source venue you also own into this one. This overwrites the target scope. Provide source_venue_id and a scope.

Allowed scope values: bundles, shifts, staffing, access-rules, availability, tables, notifications, payment-policies, access-profiles, admission-rules, promo-codes, client-tags, reservation-tags, guestlist-tags, branding, widgets, vouchers. Any other value returns 400.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/copy-from" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"source_venue_id":"SOURCE_VENUE_ID","scope":"bundles"}'
{ "success": true, "copied": 4 }

A promo code has a name and a unique code (uppercased server-side). Its discount is set by discount_type, which is either "percent" (the default) or "amount":

  • Percent (discount_type: "percent"): set discount_pct (1–100). You may add an optional discount_cap_pence “up to” cap so a percentage discount never exceeds that many pence.
  • Amount (discount_type: "amount"): set discount_amount_pence (greater than 0), a flat discount in pence.

Optional max_uses caps total redemptions, and max_per_person_uses caps how many times a single guest can use the code. expires_at is an optional ISO timestamp. A duplicate code for the same venue returns 409.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/promo-codes" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Summer Launch","code":"SUMMER25","discount_type":"percent","discount_pct":25,"discount_cap_pence":2000,"max_uses":100,"max_per_person_uses":1,"expires_at":"2026-09-01T00:00:00.000Z"}'
{ "success": true, "id": "promo_summer" }

For a flat discount instead, send "discount_type": "amount" with "discount_amount_pence" (for example {"name":"Fiver off","code":"FIVER", "discount_type":"amount","discount_amount_pence":500}).

Update with PUT .../promo-codes/:id and delete with DELETE .../promo-codes/:id. To zero the redemption counter without deleting the code:

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/promo-codes/promo_summer/reset" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{ "success": true }

Tags come in three kinds: guest (CRM labels), reservation (booking labels) and guestlist (guest-list request labels). Platform defaults are read-only; you can add venue-custom tags and categories on top. GET /api/my-venues/:venueId/tag-catalogue?kind=guest returns the merged view (defaults + custom + category flags); GET /api/my/tag-catalogue returns just the account-wide defaults.

POST /api/my-venues/:venueId/tag-categories creates a category with kind and name. Category visibility is tuned later with PATCH /api/my-venues/:venueId/tag-categories (allow_guest_select, show_on_slip, show_in_summary).

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/tag-categories" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"kind":"guest","name":"VIP"}'
{ "success": true }

Then POST /api/my-venues/:venueId/tags adds a tag under it with kind, category and label, plus an optional colour (a #rgb or #rrggbb hex; an invalid value returns 400):

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/tags" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"kind":"guest","category":"VIP","label":"Regular"}'
{ "success": true }

Remove a custom tag with DELETE /api/my-venues/:venueId/tags - pass kind, category and label as query-string parameters (platform defaults cannot be removed).

PATCH /api/my-venues/:venueId/tags sets or clears a tag’s colour, and (for a custom tag) renames its label. This is separate from PATCH /api/my-venues/:venueId/tag-categories, which tunes category visibility. Send kind, category and label to identify the tag, then:

  • colour: a #rgb or #rrggbb hex to set it, or "" / null to clear it. A colour can be set on any tag, including a platform default. Omit the key to leave the colour unchanged.
  • newLabel: a new label to rename a custom tag.
Terminal window
curl -X PATCH "https://thesidedoor.co/api/my-venues/VENUE_ID/tags" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"kind":"guest","category":"VIP","label":"Regular","colour":"#8b5cf6","newLabel":"Regulars"}'