Webhooks
Have your server told when a booking or a gift voucher changes, instead of polling.
Add an https endpoint on the dashboard's API page (up to five per venue; anyone who may manage API keys may) and choose its events: voucher.sold (a voucher became active: its payment succeeded, or it was created without payment), voucher.redeemed (some balance was spent, by a host or by an online booking, which draws the voucher when its hold is made, before payment; an abandoned or expired hold sends voucher.redemption_reversed; data.redemption has source, amountCents and, online, bookingRef), voucher.redemption_reversed (a spend was given back) and voucher.cancelled (an active voucher cancelled or deleted; one cancelled while still pending payment was never sold and sends nothing), booking.confirmed (a booking became confirmed: its online payment succeeded; data.booking has the ref, status, room, slot with the venue's time zone, party size, amounts in minor units, payment mode and the guest's name, email and phone), booking.cancelled (a confirmed booking was cancelled by the player, the venue, an API key or MyEscapeRoom; data.booking.cancellation has cancelledBy, reason, refundedCents and refundStatus; an unpaid hold that was released or ran out was never confirmed and sends nothing) and booking.rescheduled (the venue moved a confirmed booking to another session of the same room; data.booking has the new slot and data.previousSlot the start and end it left); the dashboard's "Send test event" sends a ping to one endpoint. Each event is a POST with the JSON body { id: "evt_…", type, createdAt, venueId, data: { voucher, redemption? } } for a voucher event, where voucher is the voucher as GET /api/embed/vouchers/{code} reads it, and data: { booking } for a booking event. Headers: MER-Webhook-Id (the event id), MER-Webhook-Timestamp (Unix seconds) and MER-Signature (v1= and the hex HMAC-SHA256 of <timestamp>.<raw body> keyed with the endpoint's whsec_… secret); verify it over the raw body, in constant time, and reject timestamps older than five minutes. Answer 2xx within 10 seconds; the response body is ignored and redirects are not followed. Anything else is retried with exponential backoff (10 minutes, doubling; eight attempts in all over about 21 hours), then marked failed on the dashboard. Delivery is at least once and events can arrive out of order: dedupe on the event id. The URL must be https to a public host (private, loopback and link-local addresses are refused when saved and again before each delivery). Full guide with a Node verification snippet: /docs/webhooks.