Vouchers
Operator endpoints for gift vouchers: configure what guests can buy, issue
complimentary or paid vouchers yourself, and look up and redeem codes at the
till. All routes are scoped to a venue you can access; issuing and redeeming
require the operator role (client). Guest voucher
purchase runs through the widget endpoints.
Endpoints
Section titled “Endpoints”| Method | Path | Purpose | Auth |
|---|---|---|---|
| GET | /api/my-venues/:venueId/voucher-settings |
Read voucher configuration | operator |
| PUT | /api/my-venues/:venueId/voucher-settings |
Update voucher configuration | operator |
| GET | /api/my-venues/:venueId/vouchers |
List issued vouchers | operator |
| POST | /api/my-venues/:venueId/voucher-intent |
Create a paid voucher PaymentIntent | operator |
| POST | /api/my-venues/:venueId/vouchers |
Issue a voucher (comp or paid) | operator |
| GET | /api/my-venues/:venueId/vouchers/lookup |
Preview a voucher by code | operator |
| POST | /api/my-venues/:venueId/vouchers/redeem |
Redeem a voucher code | operator |
Configure vouchers
Section titled “Configure vouchers”GET returns the current settings merged with defaults; PUT upserts them.
Amounts are in pence, fixed_amounts is an array of preset values (or null
for none), and min_amount_pence must not exceed max_amount_pence.
curl -X PUT "https://thesidedoor.co/api/my-venues/VENUE_ID/voucher-settings" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "enabled": true, "expiration_months": 12, "min_amount_pence": 2500, "max_amount_pence": 50000, "fixed_amounts": [2500, 5000, 10000], "allow_custom": true, "min_qty": 1, "max_qty": 10, "terms": "Valid for 12 months. Not redeemable for cash." }'const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/voucher-settings", { method: "PUT", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ enabled: true, expiration_months: 12, min_amount_pence: 2500, max_amount_pence: 50000, fixed_amounts: [2500, 5000, 10000], allow_custom: true, min_qty: 1, max_qty: 10, terms: "Valid for 12 months. Not redeemable for cash.", }), },);const data = await res.json();$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/voucher-settings");curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => "PUT", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$token}", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "enabled" => true, "expiration_months" => 12, "min_amount_pence" => 2500, "max_amount_pence" => 50000, "fixed_amounts" => [2500, 5000, 10000], "allow_custom" => true, "min_qty" => 1, "max_qty" => 10, "terms" => "Valid for 12 months. Not redeemable for cash.", ]),]);$data = json_decode(curl_exec($ch), true);{ "success": true }Reading the settings back:
curl "https://thesidedoor.co/api/my-venues/VENUE_ID/voucher-settings" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN"const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/voucher-settings", { headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}` } },);const data = await res.json();$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/voucher-settings");curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Authorization: Bearer {$token}"],]);$data = json_decode(curl_exec($ch), true);{ "data": { "venue_id": "ven_123", "enabled": 1, "expiration_months": 12, "min_amount_pence": 2500, "max_amount_pence": 50000, "fixed_amounts": [2500, 5000, 10000], "allow_custom": 1, "min_qty": 1, "max_qty": 10, "terms": "Valid for 12 months. Not redeemable for cash." }}List issued vouchers
Section titled “List issued vouchers”Returns vouchers for the venue and its sister venues, newest first.
curl "https://thesidedoor.co/api/my-venues/VENUE_ID/vouchers" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN"const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/vouchers", { headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}` } },);const data = await res.json();$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/vouchers");curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Authorization: Bearer {$token}"],]);$data = json_decode(curl_exec($ch), true);{ "data": [ { "id": "vch_1", "code": "A1B2-C3D4-E5F6", "amount_pence": 5000, "status": "active", "expires_at": "2027-07-03", "venue_id": "ven_123", "venue_name": "The Attic" } ]}Issue a complimentary voucher
Section titled “Issue a complimentary voucher”Issue a comp voucher directly - no payment. The comp/paid selector is the
mode field; anything other than "paid" is treated as "comp".
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/vouchers" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "amount_pence": 5000, "mode": "comp", "recipient_name": "Sam Lee", "recipient_email": "sam@example.com", "message": "Thanks for being a great guest!" }'const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/vouchers", { method: "POST", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ amount_pence: 5000, mode: "comp", recipient_name: "Sam Lee", recipient_email: "sam@example.com", message: "Thanks for being a great guest!", }), },);const data = await res.json();$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/vouchers");curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$token}", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "amount_pence" => 5000, "mode" => "comp", "recipient_name" => "Sam Lee", "recipient_email" => "sam@example.com", "message" => "Thanks for being a great guest!", ]),]);$data = json_decode(curl_exec($ch), true);{ "success": true, "id": "vch_2", "code": "G7H8-J9K0-L1M2", "emailed": true }Issue a paid voucher
Section titled “Issue a paid voucher”For a paid voucher, first create a captured PaymentIntent with
POST /api/my-venues/:venueId/voucher-intent (amount_pence, min 50), collect
payment client-side, then issue the voucher with mode: "paid" and the
payment_intent_id.
# 1. Create the PaymentIntentcurl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/voucher-intent" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"amount_pence":5000}'
# 2. After payment succeeds, issue the vouchercurl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/vouchers" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"amount_pence":5000,"mode":"paid","payment_intent_id":"pi_...","recipient_email":"sam@example.com"}'const intent = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/voucher-intent", { method: "POST", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ amount_pence: 5000 }), },).then((r) => r.json());
// ...confirm intent.client_secret with Stripe.js, then:const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/vouchers", { method: "POST", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ amount_pence: 5000, mode: "paid", payment_intent_id: intent.intent_id, recipient_email: "sam@example.com", }), },);const data = await res.json();$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/voucher-intent");curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$token}", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode(["amount_pence" => 5000]),]);$intent = json_decode(curl_exec($ch), true);// ...confirm $intent["client_secret"] with Stripe, then POST /vouchers with mode "paid".{ "client_secret": "pi_..._secret_...", "intent_id": "pi_...", "publishable_key": "pk_live_...", "amount_pence": 5000 }Look up a voucher
Section titled “Look up a voucher”Preview a code before redeeming - check the balance, status and whether it is
redeemable at this venue. Codes are accepted grouped (XXXX-XXXX-XXXX) or as a
plain 12-character string. This endpoint is rate-limited (429 + Retry-After).
curl "https://thesidedoor.co/api/my-venues/VENUE_ID/vouchers/lookup?code=A1B2-C3D4-E5F6" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN"const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/vouchers/lookup?code=A1B2-C3D4-E5F6", { headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}` } },);const data = await res.json();$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/vouchers/lookup?code=A1B2-C3D4-E5F6");curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Authorization: Bearer {$token}"],]);$data = json_decode(curl_exec($ch), true);{ "found": true, "voucher": { "id": "vch_1", "code": "A1B2-C3D4-E5F6", "amount_pence": 5000, "status": "active", "expires_at": "2027-07-03", "venue_name": "The Attic" }, "redeemable": true, "reason": "ok"}Redeem a voucher
Section titled “Redeem a voucher”Mark a voucher as redeemed. Send the code and an optional note. The response
carries a reason: ok on success, or one of not_found, wrong_venue,
refunded, already_redeemed or expired on failure (with success: false).
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/vouchers/redeem" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"code":"A1B2-C3D4-E5F6","note":"Redeemed against table 12"}'const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/vouchers/redeem", { method: "POST", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ code: "A1B2-C3D4-E5F6", note: "Redeemed against table 12", }), },);const data = await res.json();$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/vouchers/redeem");curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$token}", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "code" => "A1B2-C3D4-E5F6", "note" => "Redeemed against table 12", ]),]);$data = json_decode(curl_exec($ch), true);{ "success": true, "reason": "ok", "voucher": { "id": "vch_1", "code": "A1B2-C3D4-E5F6", "amount_pence": 5000, "status": "redeemed" }}