Sign in to see your venue's slug and publishable key in every sample.
Your account has no venue yet, so the samples keep their placeholders. Sign out
Signed in as · . Create a publishable key in the console and reload to see it here. Sign out
Signed in as · . The samples show your venue's publishable key. Sign out
Developer docs
Changelog
What changed in the public API, the JavaScript and .NET SDKs and the WordPress plugin, release by release, newest first.
Curated from the GitHub releases: only what an integration can notice is listed, and internal, console and infrastructure changes are left out. Versions are the vX.Y.Z tags; the same version names the CDN path, the NuGet packages and the WordPress zip of that release (Versions and releases).
v0.18.1 — 2026-10-12
- Internal — Nothing in this release changes the public API, the SDKs or the WordPress plugin.
BookDinePlay.SdkandBookDinePlay.Sharedare now published to nuget.org through NuGet Trusted Publishing instead of a stored API key; the packages themselves are built exactly as before.
v0.18.0 — 2026-10-09
- JavaScript SDK —
window.BookDinePlay.renderVoucherShop({ container, venueSlug, apiBaseUrl, publishableKey, locale, theme })sells the venue's gift vouchers: it lists the offers, takes the buyer and an optional recipient, gift message and delivery date, and sends the buyer to Stripe Checkout. A venue that cannot sell vouchers online gets a clear "not available" state instead of a form, and a balance check for an existing voucher sits underneath either way (Vouchers). - JavaScript SDK — New client methods:
client.voucherOffers(),client.checkoutVoucher(input, { idempotencyKey }),client.voucher(code)(keyless: no key is sent, and a string that is not a voucher code resolves tonullwithout a request) andclient.payDeposit({ reservationReference, amount, currency, voucherCode }).BookDinePlay.helpers.parseVoucherCodeandformatVoucherCoderead a code the way the API does, check symbol included. - JavaScript SDK —
renderEventsWidget's checkout for a paid event has a "Have a voucher?" field (voucherCodein the request).renderBookingWidget's confirmation has a "Pay deposit" step for a booking that still owes its deposit, by card or with a gift voucher; it is shown only when the venue reportsonlineDepositsAvailable. The optionallanguage: 'de'translates that step. - API —
GET /api/venues/{venueSlug}gainsonlineDepositsAvailable:trueonly when the venue takes payments and deposits, its plan includes online payments and deposits, and its payout account can sell (Venue profile). - API — Gift vouchers.
GET /api/venues/{venueSlug}/vouchers/offerslists what a venue sells online (on every plan;onlineSaleAvailableandunavailableReasonsay whether a checkout can start), andPOST /api/venues/{venueSlug}/vouchers/checkoutbuys one through Stripe Checkout on the venue's own account (Premium, a payout account that can sell; honoursIdempotency-Keylike ticket checkout). The voucher code is minted only once the payment arrives and reaches the buyer and the recipient by e-mail (Vouchers). - API —
GET /api/vouchers/{code}is a new keyless route — the eleventh: the code is the credential, like a ticket code, so treat it as one and never log it. It answers a voucher's value, balance, expiry and status, is not plan-gated, and answers one404voucher-not-foundfor every code that is not a voucher, so codes cannot be probed. It is the API's first rate-limited route: 30 lookups a minute per client, then429withRetry-After(Rate limits). - API — A voucher pays online:
POST /api/qr/{token}/payment(which now takes an optional body),POST /api/venues/{venueSlug}/payment-intentsandPOST …/events/{eventSlug}/tickets/checkouttake an optionalvoucherCode. The voucher pays first and the card the rest, at least €0.50 — the voucher pays a little less when the card would otherwise be charged under Stripe's minimum. A voucher that covers everything opens no payment page, andcheckoutUrlis then the success page, so a client that follows it keeps working. A refund gives the voucher part back to the voucher; neither paying with a voucher nor refunding is plan-gated (Paying with a voucher). - API — New trailing members:
voucherAmount/paidInFullonTabPaymentResponse,voucherAmount/cardAmountonPaymentIntentResponse,voucherAmount/amountDueonEventTicketCheckoutResponse,voucherCredits/amountDueonTableSessionResponse(vouchers staff applied at the table),depositVoucherAmountonReservationResponseandAdminReservationSummary, andvoucherAmountonOperatorEventRegistrationDto. All are null (orfalse) when no voucher is involved. Twelve new problem types,voucher-not-foundtovoucher-hold-live(Gift voucher problems). - API —
POST /api/venues/{venueSlug}/payment-intentsis stricter, with or without a voucher:amountandcurrencymust be exactly the deposit the booking owes (otherwise400), and a booking that no longer waits for its deposit — cancelled, confirmed by the venue, finished, or already paid — is refused with409andreasondeposit-not-payableordeposit-already-paidinstead of opening a second payment (Payment intents). - API — New booking references are six characters (
BDP-XXXXXX), group references too, so a busy platform no longer risks a collision; a create that does collide is retried with a fresh reference. References issued before stay valid with four characters, so treat a reference as an opaque string of either length. Event registration references (BDP-E-XXXX) are unchanged. - .NET SDK —
IBookDinePlayClientgained four members:GetVoucherOffersAsync,StartVoucherCheckoutAsync,GetVoucherAsync(keyless:KeylessRouteHandlerstrips the key;nullfor every refusal) and aStartTabPaymentAsync(token, voucherCode, …)overload. Hand-written implementations must add them and every consumer must recompile against the newBookDinePlay.Shared(mocks are unaffected).CreatePaymentIntentRequest.VoucherCodeandEventTicketCheckoutRequest.VoucherCodetake a voucher on the existing calls, andAddBookDinePlayClientnow mints anIdempotency-Keyfor the voucher checkout as well (.NET SDK). - WordPress —
[bookdineplay_vouchers venue="…" language="de"]renders the voucher shop, with the sameapi,themeandkeyattributes as the other shortcodes (WordPress plugin). - API — Menu items have a stable
id:items[].idonGET /api/venues/{venueSlug}/menus(andMenuItemDto.Id, a trailing member) is server-minted and survives a rename, so reference an item byid, not byname. It is null only for an item stored before ids existed (Menus). - Operator API —
PUT /api/operator/venue/menuscarries the itemidtoo. An item sent without one keeps the id of the stored item of the same menu with the same name, and only a new item gets a fresh one; anidthe venue does not have, or one used twice, is refused with400(errors.menu) and nothing is saved. - Operator API — The console's gift voucher routes under
/api/operator/venue/voucher-settingsand/api/operator/venue/vouchers: settings, issuing by hand, the list, void, expiry changes, lookup and redemption at the table (the code travels in the body, never in the URL), undo, refunding an online sale, resending and printing. None is plan-gated except that selling online needs Premium.DemoVenueResetResponsegained a trailingvouchersDeleted. - Operator API — Version 1.1 of the terms of service and the data processing agreement covers selling vouchers online. It is in force, so
GET /api/operator/mereportslegalAcceptanceRequireduntil the operator accepts it in the console.
v0.17.0 — 2026-10-06
- Operator API —
PUT /api/operator/venue/reservations/{reference}now refuses to edit a booking in thePaidButUnavailablestate with409and the problem typereservation-not-editable. Such a booking holds no slot, so moving it gave it a time that nothing protected, and another guest could book the same table. Resolve these bookings with a refund or by marking them sorted instead. - Internal — Nothing else in this release changes the public API, the SDKs or the WordPress plugin. It brings a tablet-first reservations console (timeline by default, per-type tabs, a reservation dialog that edits on tap, a self-refreshing page) that shows deposit and "paid but not available" state directly on the timeline.
v0.16.0 — 2026-09-30
- API —
POST /api/venues/{venueSlug}/events/{eventSlug}/registrationsandPOST /api/venues/{venueSlug}/events/{eventSlug}/tickets/checkoutnow accept anIdempotency-Keyheader, on the same contract reservations already had: up to 200 characters, scoped to the venue and to the account presenting it, honoured for 24 hours. A repeat with the same key and the same body replays the original response instead of creating a second registration. A key reused for a genuinely different body is refused withidempotency-key-reused; omitting the header changes nothing (Events). - API — For ticket checkout this is more than a duplicate guard. A retried checkout previously
created another pending registration holding seats for 31 minutes, while only the last
attempt's
checkoutUrlreached the caller — so a transient error or a second tap left inventory locked away by a purchase nobody completed, and a nearly-sold-out event could report itself sold out while the seats were not sold. A retry under the same key now returns the same Checkout session rather than opening a second one, and the first attempt's hold is never disturbed. - API — One new problem type on ticket checkout:
checkout-in-progress(409), for a retry that lands in the moment between the seat hold being taken and Stripe returning the session URL. Wait briefly and retry with the same key — it is a timing answer, not a refusal. - .NET SDK — A client registered with
AddBookDinePlayClientnow mints anIdempotency-Keyfor those two routes as well as for reservation create, when the caller supplies none — so an automatic transport-level retry reaches the API under a single key. A key you supply yourself is never replaced, and no other call gains a header. - Operator API — Tickets within a registration now come back in a stable order, and the CSV
export at
GET /api/operator/venue/events/{id}/registrations.csvwith them. The order was previously whatever the database happened to return, so two exports of unchanged data could disagree with each other.
v0.15.0 — 2026-09-30
- Internal — Nothing in this release changes the public API, the SDKs or the WordPress plugin. It adds a platform-admin route for giving an existing tenant a console login, so a venue set up by BookDinePlay no longer has to be reached by staff impersonation, and it moves BookDinePlay's own persistence tests onto a database that enforces unique indexes — the gap that let v0.13.0's deployment-time defect ship green.
BookDinePlay.Sharedgains three admin-only contract types (CreateOperatorRequest,UpdateOperatorRequest,OperatorSummary); they are purely additive, reachable only with platform-admin credentials, and no existing type, member or response shape changed.
v0.14.0 — 2026-09-29
- API — A guest can pay their table tab by card:
POST /api/qr/{token}/paymentfreezes the tab at its current total for 31 minutes and returns a Stripe Checkout session on the venue's own connected account (TabPaymentResponse { checkoutUrl, amount, currency, expiresAt }); the tab closes by itself when the payment lands, soPOST …/closeis not needed as well. Keyless like the rest of the QR group — the printed token is the credential — but it does require a plan with online payments, payments switched on, and completed Stripe payout onboarding. Calling it again while a payment is live returns the same checkout rather than opening a second payable one, so noIdempotency-Keyheader is needed (QR codes and table sessions). - API — While a tab payment is live,
POST /api/qr/{token}/ordersis refused with409(the amount being collected is already fixed) andGET /api/qr/{token}/sessiongains two trailing fields:paymentPending(always present,falsefor every tab with no live payment, so existing responses are unchanged in meaning) andpaymentUrl, the same checkout URL, so a second device at the table shows the payment in progress instead of starting another. The freeze lapses on its own if the guest abandons Checkout. - .NET SDK —
IBookDinePlayClientgained one member,StartTabPaymentAsync— hand-written implementations must add it (mocks are unaffected), the same 0.x precedent as the two members added in v0.12.0 and the five in v0.10.0. It sends no API key, like the other QR calls. - API — A reservation deposit taken through Stripe can now be refunded, and a deposit that arrives for a slot that has gone is no longer lost. The venue chooses what happens when a guest cancels a booking whose deposit was paid online, on
GET/PUT /api/operator/venue/cancellation-policy's newdepositRefund(NoOnlineRefund— the default and every venue's behaviour before this —RefundOnGuestCancel, orForfeitOnGuestCancel).POST /api/reservations/{cancelToken}/cancelgains one problem type:502reservation-refund-failed, for a refunding venue whose refund did not go through — nothing is cancelled and it is worth retrying, which is why it is a502and not the settled-policy409reservation-deposit-not-refundable(Reservations, Errors). - API —
reservation-deposit-not-refundablenow means the venue's own choice rather than a missing feature: a venue that switchesdepositRefundaway fromNoOnlineRefundstops producing it altogether, and a booking whose deposit was waived or taken in cash by staff never produced it in the first place — that case used to be indistinguishable from a real online payment and refused with it. - API —
AdminReservationSummarygained a trailingdepositRefundedAt(null until the deposit was refunded in full), onGET /api/operator/venue/reservationsandGET /api/admin/reservations. - API — An
Idempotency-KeyonPOST /api/venues/{venueSlug}/reservationsis now scoped to the account that presented it as well as to the venue. Any of your venue's API keys can replay a key another of them created, so rotating a key mid-flight — or creating from a server-side secret key and retrying from elsewhere — no longer risks a second booking; and a key your account uses can no longer be replayed or blocked by another account's keys, nor by BookDinePlay's own hosted booking pages for your venue, which now have a namespace of their own. Your own keys still share one namespace with each other, deliberately — they are one account. Nothing changes for the usual random-UUID-per-attempt key, and a key claimed before this release keeps working for its remaining 24 hours (Reservations). - Fixed — A reservation deposit refunded by hand in the venue's own Stripe dashboard now lands back on the booking. Its
charge.refundedpreviously matched nothing at all and the booking's state never changed.
v0.13.1 — 2026-09-29
- Fixed (internal) — Nothing in this release changes the public API, the SDKs or the WordPress plugin. It repairs the deployment-time data initializer, which v0.13.0 left failing: the seeder for our own demo venues checked whether an event already existed by its id, while the database enforces uniqueness on the venue and event slug together, so a slug already present under a different id was refused on insert. No customer venue, reservation or integration was affected — the API served requests normally throughout, and the database schema was already up to date.
v0.13.0 — 2026-09-29
- API — A bookable resource may now be sold by the seat instead of booked exclusively:
seatSoldon Resources (always present, defaultfalse— every existing resource keeps today's one-reservation-takes-the-whole-resource behaviour). A seat-sold resource lets several reservations share a time window up to itscapacitycombined — a 31-seat event area no longer goes off sale to a party of four. Availability slots for a seat-sold resource gainseatsRemaining("27 of 31 left"); it is entirely absent from the JSON for an exclusive resource, so an existing integration's responses are unaffected.POST/PUT /api/operator/venue/resourcesaccept a nullableseatSold— omitting it on an update leaves the resource's current mode untouched (create still defaults to exclusive). - API —
POST /api/venues/{venueSlug}/reservationsaccepts an optionalIdempotency-Keyheader (up to 200 characters, scoped to the venue, honoured for 24 hours): a repeat with the same key and the same request body replays the original reservation — samereference, samecancelToken— instead of creating a second one, so a client that could not tell a lost response from a lost request no longer has to guess. A key reused for a genuinely different body is refused with the new409idempotency-key-reused; omitting the header changes nothing (Reservations, Errors). - SDKs — The headless client's
reserve(input, { idempotencyKey })sends the new header, the booking widget mints one per attempt and reuses it across a guest's own retries after a failed submit, and the .NET SDK gains a secondCreateReservationAsyncoverload takingidempotencyKeybefore the cancellation token — the existing three-argument signature is untouched, so a caller compiled against an earlierBookDinePlay.Sharedkeeps binding. - .NET SDK — A client registered with
AddBookDinePlayClientnow mints anIdempotency-Keyitself forPOST /api/venues/{venueSlug}/reservationswhen the caller supplies none — a fresh value per call, attached ahead of any transport-level retry, so an automatic retry of one create (a .NET Aspire host's resilience handler retries POST by default) reaches the API under a single key rather than as several bookings. Two separate calls always get separate keys, and a key you supply yourself is never replaced. No other call gains a header. - SDKs — The headless client gains
client.registration(cancelToken)forGET /api/registrations/{cancelToken}— the third of the three keyless guest routes, which it had been missing while exposing the other two, so a cancel page had to hand-roll afetchto show the guest what they booked before offering the button. Built likeclient.ticket(): no key header, no venue segment, the sameBookDinePlayErrormapping. The .NET SDK'sGetRegistrationAsyncalready covered it (Events). - API — Every string field on a public request is now length-checked at the boundary against the same limit its column is configured with, so an over-long value is refused with a
400naming the field instead of reaching the database and failing there as a500. Most visible on reservations:emailwas previously unbounded from the widget and is now capped at 256 characters, matching what the event contracts already did. No limit was lowered — this closes the gap where a boundary and its column disagreed, which is why a generated resource code can no longer overflow either. - API — An
Idempotency-Keyretry whoseextrasarrive in a different order is now recognised as the same request. The fingerprint deciding "same request" is computed from the parsed body, but it hashed the extras list in arrival order, so a client rebuilding its cart from a dictionary could be refused with409idempotency-key-reusedfor a booking that was never made. Extras are sorted before hashing; differing quantities still mark a genuinely different request. Claims written before this release are still compared under the previous scheme, so a retry in flight across the upgrade is unaffected either way. - Operator API — Editing a reservation without moving it — party size, guest notes, phone — no longer reports
409"this time slot has since been booked" when the write fails for an unrelated reason. The conflict check re-queried the booking's own slot and matched the very row being edited; it now excludes it, so an unrelated failure surfaces as itself rather than as a slot collision that never happened. - Fixed —
seatSoldandIdempotency-Keyare both additive: a venue that never setsseatSoldsees byte-identicalavailabilityresponses, and a reservation create with noIdempotency-Keyheader behaves exactly as it always has. The one behaviour change worth knowing about is the length validation above — a request carrying an over-long value that previously reached the database now gets a400instead.
v0.12.1 — 2026-09-23
- API — Two new problem types on
POST /api/operator/venue/payouts/onboarding-link, which previously answered500when Stripe refused:409connect-not-enabled(the platform has not signed up for Connect — nothing the venue can do) and409connect-rejected(Stripe refused this venue's own details — country, VAT id or website shape — and the operator can correct them and retry). They are separate types because the operator's next step differs (Errors). - Payouts — The Stripe application fee is the BookDinePlay commission only. It previously also bundled an estimate of Stripe's processing fee, which under direct charges the venue's own account already pays — so a venue was billed for it twice and the effective rate was above the advertised 5 %. On a EUR 20.00 ticket the fee is now EUR 1.00 rather than EUR 1.55. No API shape changed; venues simply receive what the pricing page says they receive.
- Fixed — A failed payout onboarding no longer locks a venue out for 24 hours (Stripe caches a response, including an error, against an idempotency key), and an expired Stripe onboarding link now mints a fresh one instead of returning the operator to the billing page with no way forward.
v0.12.0 — 2026-09-23
- API — Paid events sell real tickets:
POST /api/venues/{venueSlug}/events/{eventSlug}/tickets/checkoutopens a Stripe Checkout session on the venue's own connected account (EventTicketCheckoutRequest— the same fields as a free registration, plus optionalsuccessUrl/cancelUrl;201 EventTicketCheckoutResponse { reference, checkoutUrl, expiresAt, cancelToken });GET /api/registrations/{cancelToken}joins the existing keyless-route exceptions (the ticket code and the cancel-route token) as a guest's own registration/ticket-and-payment-state page (Why three routes take no key). Four new problem types:409ticket-sales-not-enabled(the single guest-facing refusal folding together "plan lacks ticket sales", "payout account not connected" and "event not Paid"),409payouts-not-connected(operator-facing routes only),409refund-not-available(a guest's own cancel of a Paid registration the refund policy no longer allows), and403tenant-suspended(documented here; shipped in v0.11.0's onboarding change) (Events). - JavaScript SDK —
client.checkoutEventTickets(eventSlug, input)starts the Checkout session; the events widget's Paid-event form now shows a live total (Intl.NumberFormat) and a "Pay & register" button that redirects tocheckoutUrlinstead of ending in an in-widget confirmation — the earlier static "Tickets coming soon" state is gone, since a Premium venue with a connected payout account can now actually sell. NewcreateClient/renderEventsWidgetoptionssuccessUrl/cancelUrl.ticket-sales-not-enabledandpayouts-not-connectedrender the identical sentence, on purpose (Events). - WordPress —
[bookdineplay_events]/[bookdineplay_event]gainsuccess_url/cancel_urlattributes, passed straight through to the widget (WordPress plugin). - .NET SDK —
IBookDinePlayClientgained two members:CheckoutEventTicketsAsyncandGetRegistrationAsync— hand-written implementations must add them (mocks are unaffected), the same 0.x precedent as the five members added in v0.10.0.BookDinePlayApiExceptiongained the constantsTenantSuspendedType,PayoutsNotConnectedTypeandRefundNotAvailableType(.NET SDK).
v0.11.0 — 2026-09-23
- API — Self-serve sign-up (
POST /api/onboarding) now requires company and billing details in the same request:company(legal name, address, VAT id, billing e-mail, contact), a billinginterval(MonthlyorYearly) and the tenant's legalacceptances; the response carries a Stripe CheckoutcheckoutUrlthat starts a 14-day card-upfront trial. - API — Two new problem types:
403tenant-suspendedon every/api/venues/**route once a venue's subscription has lapsed, been suspended, or a self-serve sign-up never finished paying; and409billing-managed-by-stripeonPUT /api/admin/tenants/{id}when the tenant's plan and status are governed by an active Stripe subscription.
v0.10.0 — 2026-09-16
- API — Venue events. A venue on Pro or higher publishes events in the console; the public API lists them (
GET /api/venues/{venueSlug}/events,?upcoming=falsefor past ones), reads one with its registration window (…/events/{eventSlug}—registration.openandreason), and registers guests for free events (POST …/events/{eventSlug}/registrations) with one named ticket per attendee, aBDP-E-XXXXreference, ticket codes with QR pages and a cancel link; the guest gets the same by e-mail (Events). - API — Two keyless routes:
GET /api/tickets/{code}andPOST /api/event-registrations/{cancelToken}/cancelneed no API key and are not plan-gated — the code and the token are the guest's own e-mailed credentials, like the printed QR token (Why two routes take no key). - API — Two new problem types on registration:
409registration-closedwithreason(closed,sold-out,past,not-open) andremaining: 0when sold out, and409ticket-sales-not-enabledfor a paid event until online ticket sales ship.POST …/events/{eventSlug}/tickets/checkoutexists as a stub answering the latter; registering on a venue whose plan lacks events is403feature-not-in-plan. A broken registration rule is a400whoseerrorsdictionary carries the messages underregistration. - JavaScript SDK —
BookDinePlay.renderEventsWidget({ container, venueSlug, apiBaseUrl, publishableKey, layout, language, eventSlug, onNavigate, theme })renders a venue's events as cards, one event's detail, the registration form and a confirmation with ticket codes, in the same isolated root and with the same nine--bdp-*properties as the booking widget;eventSlugrenders one event for a page of its own andonNavigate(slug, summary)routes to the host's pages. The headless client gainsevents(),event(),registerForEvent(),ticket()andcancelEventRegistration()(the last two send no key);BookDinePlayErrorliftstype,reason,remaininganderrorsoff the problem and addsmessages().createClientno longer requiresvenueSlugup front — only the venue-scoped calls throw without it, so a ticket or cancel page needs justapiBaseUrlandpublishableKey(Events). - WordPress —
[bookdineplay_events venue="…" layout="grid|list" language="en|de"]renders the events widget and[bookdineplay_event venue="…" event="…"]one event directly; both takeapi,themeandkeylike the booking shortcode (WordPress plugin). - .NET SDK —
IBookDinePlayClientgained five members:GetEventsAsync,GetEventAsync,RegisterForEventAsync,GetTicketAsyncandCancelEventRegistrationAsync— hand-written implementations must add them (mocks are unaffected).BookDinePlayApiExceptioncarriesType,Reason,Remaining,Errors,MessagesandExtensionsplus the constantsRegistrationClosedTypeandTicketSalesNotEnabledType.AddBookDinePlayClientregisters aKeylessRouteHandlerthat stripsX-BookDinePlay-Keyand aBearer bdp_…Authorizationheader from the two keyless routes (.NET SDK).
v0.9.0 — 2026-09-16
- API — Plan tiers are enforced. A Starter tenant cannot create or edit a game-type resource (billiard table, dart board, shuffleboard, bowling lane, event area, other), open the floor plan, or manage employees — the operator API answers
403 feature-not-in-planwith arequiredPlanextension naming the tier that unlocks it (Errors). - API — A Starter venue's
resourcesandresourceTypesomit its game-type resources entirely; guests never see them (Venue). - API — Availability for a
resourceTypethe venue's plan does not offer returns200with emptyslotsandnotice: "resource-type-not-offered"; reserving that type anyway is refused with the samefeature-not-in-planproblem as the operator API.
v0.8.0 — 2026-09-16
- JavaScript SDK —
BookDinePlay.createClient({ apiBaseUrl, publishableKey, venueSlug })— a headless client for pages with their own forms:venue(),floorPlan(),availability(),reserve(), RFC 7807 errors asBookDinePlayError; the widget now runs on it, andrenderBookingWidgetrefuses a key that is not abdp_pk_…publishable key (returnsnullwith a console message) instead of rendering and failing with 403 (Custom forms). - API — Opening hours may close after midnight (
opens18:00,closes02:00); availability and reservations follow the span into the next day, and breaks stay same-day only (Opening hours).
v0.7.0 — 2026-09-16
- Docs — Tutorials: Booking flow (what the widget does end to end) and Azure Static Web Apps (zero to a live venue page); this changelog. No change to the public API, the SDKs or the WordPress plugin.
v0.6.0 — 2026-09-16
- API — Every
/api/venues/**call requires an API key: a publishablebdp_pk_…key from an allowed origin in the browser, a secretbdp_sk_…key on a server. A missing, wrong or misused key is refused with one of six RFC 7807 problem types (Authentication, Errors). - API — Booking lengths are configurable per resource type: the venue profile lists
bookingDurations, availability and reservations acceptdurationMinutes, and availability echoes the length its slots represent. - API — Availability and reservation creation resolve a resource's own booking length the same way, so a slot that was offered can no longer be refused for its length; a party that needs several resources is grouped identically by both calls.
- API —
phoneon reservation creation is optional: 3–40 characters when given, and a blank value counts as not supplied. - JavaScript SDK — Published on the CDN:
sdk/<version>/bookdineplay.js(immutable, with an SRI hash insri.txtnext to it) andsdk/v0/bookdineplay.js(five-minute alias).renderBookingWidgetnow requirespublishableKeyand takestheme(auto,light,dark); nine--bdp-*custom properties theme the widget from the host page;window.BookDinePlay.versionnames the loaded release (JavaScript SDK, Theming). - JavaScript SDK —
durationMinutesis sent only when the guest picked a length; the venue's default applies otherwise. - .NET SDK —
BookDinePlay.SdkandBookDinePlay.Sharedare on nuget.org, versioned in lockstep with the release (.NET SDK). - WordPress — The plugin ships as
bookdineplay-<version>.zipon the release, loads the SDK from thev0alias, stores the publishable key under Settings → BookDinePlay, and the shortcode gains akeyattribute (WordPress plugin). - Docs — This site.
v0.5.0 — 2026-09-09
- No change to the public API, the SDKs or the WordPress plugin. Operator console only.
v0.4.1 — 2026-09-02
- No change to the public API, the SDKs or the WordPress plugin. Operator console only.
v0.4.0 — 2026-07-23
- API — Messages and problem responses are localized: send
Accept-Language: defor Germantitleanddetail; English is the default (Errors). The guest's confirmation email uses the language of the request that created the reservation. - API — Bookable extras: the venue profile lists
extras; a reservation acceptsextras: [{ "extraId": "…", "quantity": 1 }]and returns pricedextraslines andextrasTotal. - API — Per-game pricing: a slot can carry
pricingModel: "PerGame"; a reservation accepts and returnsgames(1–10). - API — Group bookings: a party too large for one resource is offered a group slot (
groupResourceCount,groupResourceNames); the reservation returnsgroupReferenceandgroupResources. - API — New resource type
BowlingLane; food ordering is a per-resource setting (allowsFoodOrderingon resources). - JavaScript SDK, WordPress —
BowlingLanein the resource-type list and in the plugin's defaulttypes; the widget collects games per player and extras where the venue offers them.
Releases before v0.4.0 predate the public integration paths and are not listed.