Vouchers
Sell and manage gift vouchers from the venue's own site, with the same API key as the bookings.
The site decides the amount (a fixed value, or derived from a game's price: its own logic); MyEscapeRoom just takes an amount, 1.00 to 1,000.00 euros, and mints the code. A voucher is for the whole venue, or for one room (roomSlug), is valid for 180 days, and is spent against a booking (voucherCode on POST /api/embed/bookings) or redeemed in person by a host. Selling a voucher: 1) POST /api/embed/vouchers with { amountCents, buyerName?, buyerEmail?, roomSlug?, notifyBuyer? }; the voucher comes back pending_payment, with a clientSecret and a stripePublishableKey. 2) Confirm the payment in the buyer's browser with Stripe.js: stripe = Stripe(stripePublishableKey); stripe.confirmPayment({ clientSecret, … }). 3) Poll GET /api/embed/vouchers/{code} until status is active (normally seconds; Stripe's delivery time is not ours to promise, so keep polling for a while before telling a buyer their payment failed). 4) Show the buyer the code. MyEscapeRoom also emails it to the buyer once the voucher is active, when you gave a buyerEmail; send notifyBuyer: false if your site sends its own email. A voucher that is not active can not be spent: it is treated exactly like an unknown code. Fees. No service fee is charged when a voucher is sold: the buyer pays the amount and nothing else, the venue receives the amount less Stripe's card processing fee on it, and MyEscapeRoom keeps nothing (the money is transferred to the venue's Stripe account within minutes of the payment, once Stripe has recorded the fee). The normal service fee is charged when a booking is later paid with a voucher: a voucher never reduces it. Already paid? Send collectPayment: false when the venue took the money itself (in its own shop or by its own payment provider): the voucher is active at once, with no payment, a null clientSecret and no fee. Permission. Selling a voucher with payment, reading one by its code and cancelling a pending sale work with any key. Listing the venue's vouchers, selling with collectPayment: false and cancelling an active voucher the venue sold itself each reveal or mint bearer money, so they need a key the venue has granted "May manage vouchers" on its dashboard API page (403 API_KEY_NOT_PERMITTED otherwise). Grant it only to a key used from your own server: a key in a web page can be called with any body by any visitor. The buyer's name and email in a voucher's answer are null for a key that was granted neither "May manage vouchers" nor "May read guest details". Invoices. A sale charged through MyEscapeRoom at a Belgian venue can be invoiced, only on request: send invoice (the buyer's name or company, VAT number, address and email) with the sale, or later POST /api/embed/vouchers/{code}/invoice-request (once the voucher is active that needs a key granted "May manage vouchers", because the gift's recipient holds the code too and a request cannot be corrected), until the 15th of the month after the payment. MTEC Games VOF then issues the venue's invoice in its company's name for the full amount (VAT falls due when a voucher is sold) and emails it to the buyer; there is no service fee, so no second invoice. GET /api/embed/vouchers/{code} shows invoice.state. A sale the venue collected itself (collectPayment false) is never invoiced by MyEscapeRoom. Cancelling: POST /api/embed/vouchers/{code}/cancel cancels a voucher still pending_payment (its payment is cancelled too, unless it has already gone through: 409 VOUCHER_PAID), and an active voucher sold with collectPayment: false that nobody has spent. A voucher paid online can not be cancelled through the API, and refunds of sold vouchers are not offered.
| Method | Path | What it does |
|---|---|---|
| GET | /api/embed/vouchers | The venue's gift vouchers, newest first (needs "May manage vouchers") |
| POST | /api/embed/vouchers | Sell a gift voucher |
| GET | /api/embed/vouchers/{code} | One voucher by its code, with its redemptions |
| POST | /api/embed/vouchers/{code}/invoice-request | Ask for the invoice of a voucher sale |
| POST | /api/embed/vouchers/{code}/cancel | Cancel a voucher |
The venue's gift vouchers, newest first (needs "May manage vouchers")#
/api/embed/vouchersAPI key (embed)Parameters
| Name | In | Type | Description |
|---|---|---|---|
status | query | string | pending_payment, active or cancelled |
limit | query | integer | At most 200 |
offset | query | integer |
Responses
| Status | Meaning |
|---|---|
200 | { vouchers: [{ code, status, amountCents, remainingCents, expiresAt, roomSlug, buyerName, buyerEmail, paidAt, soldOnline, createdAt }], total } |
400 | INVALID_INPUT |
401 | UNAUTHORIZED — no key, an unknown or revoked one, or a venue that is not live. The 401 carries no CORS headers, so a browser sees a failed request rather than this body. |
403 | ORIGIN_NOT_ALLOWED — the request carries an Origin that is not one of the venue's allowed origins (and not the portal's own site). Nothing is done. A call with no Origin header (from a server) is never refused for this; API_KEY_NOT_PERMITTED — the key was not granted "May manage vouchers" |
Sell a gift voucher#
/api/embed/vouchersAPI key (embed)Creates a voucher worth amountCents, narrowed to one room when roomSlug is given (it must be a room of the key's venue). With collectPayment true (the default) the voucher is pending_payment and the answer carries the PaymentIntent's clientSecret and the stripePublishableKey to confirm it with Stripe.js; the voucher becomes active when Stripe reports the payment succeeded, which you read by polling GET /api/embed/vouchers/{code}. A failed card attempt leaves it pending for the buyer to retry. With collectPayment false the venue took the money itself: the voucher is active at once, nothing is charged and clientSecret and stripePublishableKey are null; that needs a key granted "May manage vouchers" (403 API_KEY_NOT_PERMITTED otherwise). No service fee is charged on a sale. When buyerEmail is given and notifyBuyer is true (the default) MyEscapeRoom emails the buyer the voucher (venue, code, value, room if narrowed, expiry date and a link to book) as soon as it is active: when the payment succeeds, or right away with collectPayment false. Send notifyBuyer false when your site sends its own email. An optional invoice (the same "Need an invoice?" object as POST /api/bookings: buyerKind, name, vatNumber for an EU business, address, postalCode, city, country, email) asks MyEscapeRoom to invoice the sale: once the payment succeeds, MTEC Games VOF issues the venue's invoice in its company's name (the sale is a single-purpose voucher, so the VAT falls due when it is sold), for the full amount, with no service fee invoice because a sale has none, and emails it to the buyer (over Peppol as well to a Belgian business that receives them). It is only for a sale charged through MyEscapeRoom at a Belgian venue: with collectPayment false it is refused (422 INVOICE_NOT_AVAILABLE), because a venue that took the money invoices it itself. If the venue's invoicing profile is not complete, or the voucher is for any room and the venue's rooms are taxed at different VAT rates, the venue is emailed the buyer's details to issue the invoice itself instead. Ask later with POST /api/embed/vouchers/{code}/invoice-request.
Request body
| Field | Type | Description |
|---|---|---|
amountCentsrequired | integer | The voucher's value, in cents: 100 to 100000 |
roomSlugoptional | string | Narrow the voucher to one room of the venue; any room otherwise |
buyerNameoptional | string | |
buyerEmailoptional | string | Also receives Stripe's payment receipt, and, unless notifyBuyer is false, the voucher by email once it is active |
notifyBuyeroptional | boolean | Email the buyer their voucher (code, value, expiry, link to book) when it becomes active. False when your site sends its own email. Needs buyerEmail |
collectPaymentoptional | boolean | False when the venue took the money itself: the voucher is active at once, with no payment |
invoiceoptional | object | Ask for the sale to be invoiced. Not with collectPayment false (422 INVOICE_NOT_AVAILABLE); Belgian venues only |
Example request
curl -X POST https://myescaperoom.eu/api/embed/vouchers \
-H "Authorization: Bearer $MER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"amountCents":10000,"buyerName":"Sofie V.","buyerEmail":"sofie@example.com"}'Example request body
{
"amountCents": 10000,
"buyerName": "Sofie V.",
"buyerEmail": "sofie@example.com"
}Responses
| Status | Meaning |
|---|---|
201 | { voucher, clientSecret, stripePublishableKey } — the last two null with collectPayment false. voucher is { code, status, amountCents, remainingCents, expiresAt, roomSlug, buyerName, buyerEmail, paidAt, soldOnline, createdAt }. Confirm the payment with Stripe.js: stripe = Stripe(stripePublishableKey); stripe.confirmPayment({ clientSecret, … }). |
400 | INVALID_JSON; INVALID_INPUT — for example an amount outside 100 to 100000 |
401 | UNAUTHORIZED — no key, an unknown or revoked one, or a venue that is not live. The 401 carries no CORS headers, so a browser sees a failed request rather than this body. |
403 | ORIGIN_NOT_ALLOWED — the request carries an Origin that is not one of the venue's allowed origins (and not the portal's own site). Nothing is done. A call with no Origin header (from a server) is never refused for this; API_KEY_NOT_PERMITTED — collectPayment false with a key not granted "May manage vouchers" |
404 | ROOM_NOT_FOUND — no such room at the key's venue |
409 | VOUCHER_CANCELLED — the voucher was cancelled while its payment was being set up; nothing is charged |
422 | INVOICE_NOT_AVAILABLE — an invoice with collectPayment false, or for a venue outside Belgium |
502 | STRIPE_ERROR — the voucher was cancelled, retry |
503 | STRIPE_NOT_CONFIGURED — the venue cannot take cards yet |
One voucher by its code, with its redemptions#
/api/embed/vouchers/{code}API key (embed)Poll this after the buyer confirms the payment until status is active. redemptions lists every draw against the balance, newest first: { amountCents, bookingRef (null for a host redeeming in person), reversed, createdAt }. A draw is reversed once it was given back, because its booking was cancelled or released. invoice is where the sale's invoice stands: { available (charged through MyEscapeRoom, at a Belgian venue, not cancelled), requested, state (none, pending — asked for and on its way, issued, or venue_issues — the venue was emailed to invoice it itself), number (the invoice number once issued), deadline (ISO; null until the payment succeeded), canRequest }. The PDF is emailed to the buyer, never served through this API.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
coderequired | path | string |
Responses
| Status | Meaning |
|---|---|
200 | { voucher: { code, status, amountCents, remainingCents, expiresAt, roomSlug, buyerName, buyerEmail, paidAt, soldOnline, createdAt, redemptions, invoice } }. buyerName and buyerEmail are null unless the key was granted "May manage vouchers" or "May read guest details". |
401 | UNAUTHORIZED — no key, an unknown or revoked one, or a venue that is not live. The 401 carries no CORS headers, so a browser sees a failed request rather than this body. |
403 | ORIGIN_NOT_ALLOWED — the request carries an Origin that is not one of the venue's allowed origins (and not the portal's own site). Nothing is done. A call with no Origin header (from a server) is never refused for this |
404 | VOUCHER_NOT_FOUND — no such voucher at the key's venue |
Ask for the invoice of a voucher sale#
/api/embed/vouchers/{code}/invoice-requestAPI key (embed)For a buyer who asks after the sale. The body is the same invoice object as POST /api/embed/vouchers. Only for a sale charged through MyEscapeRoom at a Belgian venue (a voucher sold with collectPayment false, or cancelled, is 422 INVOICE_NOT_AVAILABLE), until 23:59 Brussels time on the 15th of the month after the payment (422 INVOICE_DEADLINE_PASSED); a sale still waiting for its payment can be asked for already. One request per voucher: a second is 409 INVOICE_ALREADY_REQUESTED, and it cannot be corrected through the API. While the voucher is still pending_payment any key may call it (the buyer's checkout); once it is active the key must be granted "May manage vouchers" (403 API_KEY_NOT_PERMITTED), because the gift's recipient holds the code too and a request cannot be corrected. The answer is the invoice state only, never the buyer's details. The invoice is issued shortly afterwards and emailed to the buyer; poll GET /api/embed/vouchers/{code} for its invoice.state.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
coderequired | path | string |
Example request body
{
"buyerKind": "business",
"name": "Test Buyer NV",
"vatNumber": "BE0712345630",
"address": "Straat 1",
"postalCode": "1000",
"city": "Brussel",
"country": "BE",
"email": "billing@testbuyer.be"
}Responses
| Status | Meaning |
|---|---|
201 | { invoice } — the voucher's invoice state, as on GET /api/embed/vouchers/{code} |
400 | INVALID_JSON; INVALID_INPUT — for example an EU business without its VAT number |
401 | UNAUTHORIZED — no key, an unknown or revoked one, or a venue that is not live. The 401 carries no CORS headers, so a browser sees a failed request rather than this body. |
403 | ORIGIN_NOT_ALLOWED — the request carries an Origin that is not one of the venue's allowed origins (and not the portal's own site). Nothing is done. A call with no Origin header (from a server) is never refused for this |
404 | VOUCHER_NOT_FOUND — no such voucher at the key's venue |
409 | INVOICE_ALREADY_REQUESTED |
422 | INVOICE_NOT_AVAILABLE or INVOICE_DEADLINE_PASSED |
Cancel a voucher#
/api/embed/vouchers/{code}/cancelAPI key (embed)A voucher still pending_payment is cancelled together with its payment. Whether it is unpaid is asked of Stripe, not read from the voucher: a payment that went through before its webhook landed counts as paid (409 VOUCHER_PAID; poll until the voucher is active), one still processing is 409 PAYMENT_PROCESSING (try again later), and Stripe not answering is 502 STRIPE_ERROR with nothing cancelled. An active voucher the venue sold with collectPayment false is cancelled while nobody has spent any of it (409 VOUCHER_IN_USE once they have); that needs a key granted "May manage vouchers" (403 API_KEY_NOT_PERMITTED). An active voucher that was paid online is never cancelled here (409 VOUCHER_PAID): refunding a sold voucher is not offered. Cancelling a voucher that is already cancelled is a no-op that answers 200.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
coderequired | path | string |
Responses
| Status | Meaning |
|---|---|
200 | { voucher } — cancelled, now or already |
401 | UNAUTHORIZED — no key, an unknown or revoked one, or a venue that is not live. The 401 carries no CORS headers, so a browser sees a failed request rather than this body. |
403 | ORIGIN_NOT_ALLOWED — the request carries an Origin that is not one of the venue's allowed origins (and not the portal's own site). Nothing is done. A call with no Origin header (from a server) is never refused for this; API_KEY_NOT_PERMITTED — an active voucher, and the key was not granted "May manage vouchers" |
404 | VOUCHER_NOT_FOUND |
409 | VOUCHER_PAID — paid online, so it stays; PAYMENT_PROCESSING — Stripe is still processing a pending voucher's payment, try again later; VOUCHER_IN_USE — part of an active voucher was already spent |
502 | STRIPE_ERROR — Stripe could not be asked whether a pending voucher is paid; nothing was cancelled, retry |