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.Sdk and BookDinePlay.Shared are 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 to null without a request) and client.payDeposit({ reservationReference, amount, currency, voucherCode }). BookDinePlay.helpers.parseVoucherCode and formatVoucherCode read 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 (voucherCode in 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 reports onlineDepositsAvailable. The optional language: 'de' translates that step.
  • API — GET /api/venues/{venueSlug} gains onlineDepositsAvailable: true only 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/offers lists what a venue sells online (on every plan; onlineSaleAvailable and unavailableReason say whether a checkout can start), and POST /api/venues/{venueSlug}/vouchers/checkout buys one through Stripe Checkout on the venue's own account (Premium, a payout account that can sell; honours Idempotency-Key like 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 one 404 voucher-not-found for 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, then 429 with Retry-After (Rate limits).
  • API — A voucher pays online: POST /api/qr/{token}/payment (which now takes an optional body), POST /api/venues/{venueSlug}/payment-intents and POST …/events/{eventSlug}/tickets/checkout take an optional voucherCode. 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, and checkoutUrl is 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/paidInFull on TabPaymentResponse, voucherAmount/cardAmount on PaymentIntentResponse, voucherAmount/amountDue on EventTicketCheckoutResponse, voucherCredits/amountDue on TableSessionResponse (vouchers staff applied at the table), depositVoucherAmount on ReservationResponse and AdminReservationSummary, and voucherAmount on OperatorEventRegistrationDto. All are null (or false) when no voucher is involved. Twelve new problem types, voucher-not-found to voucher-hold-live (Gift voucher problems).
  • API — POST /api/venues/{venueSlug}/payment-intents is stricter, with or without a voucher: amount and currency must be exactly the deposit the booking owes (otherwise 400), and a booking that no longer waits for its deposit — cancelled, confirmed by the venue, finished, or already paid — is refused with 409 and reason deposit-not-payable or deposit-already-paid instead 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 — IBookDinePlayClient gained four members: GetVoucherOffersAsync, StartVoucherCheckoutAsync, GetVoucherAsync (keyless: KeylessRouteHandler strips the key; null for every refusal) and a StartTabPaymentAsync(token, voucherCode, …) overload. Hand-written implementations must add them and every consumer must recompile against the new BookDinePlay.Shared (mocks are unaffected). CreatePaymentIntentRequest.VoucherCode and EventTicketCheckoutRequest.VoucherCode take a voucher on the existing calls, and AddBookDinePlayClient now mints an Idempotency-Key for the voucher checkout as well (.NET SDK).
  • WordPress — [bookdineplay_vouchers venue="…" language="de"] renders the voucher shop, with the same api, theme and key attributes as the other shortcodes (WordPress plugin).
  • API — Menu items have a stable id: items[].id on GET /api/venues/{venueSlug}/menus (and MenuItemDto.Id, a trailing member) is server-minted and survives a rename, so reference an item by id, not by name. It is null only for an item stored before ids existed (Menus).
  • Operator API — PUT /api/operator/venue/menus carries the item id too. 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; an id the venue does not have, or one used twice, is refused with 400 (errors.menu) and nothing is saved.
  • Operator API — The console's gift voucher routes under /api/operator/venue/voucher-settings and /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. DemoVenueResetResponse gained a trailing vouchersDeleted.
  • 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/me reports legalAcceptanceRequired until 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 the PaidButUnavailable state with 409 and the problem type reservation-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}/registrations and POST /api/venues/{venueSlug}/events/{eventSlug}/tickets/checkout now accept an Idempotency-Key header, 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 with idempotency-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 checkoutUrl reached 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 AddBookDinePlayClient now mints an Idempotency-Key for 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.csv with 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.Shared gains 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}/payment freezes 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, so POST …/close is 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 no Idempotency-Key header is needed (QR codes and table sessions).
  • API — While a tab payment is live, POST /api/qr/{token}/orders is refused with 409 (the amount being collected is already fixed) and GET /api/qr/{token}/session gains two trailing fields: paymentPending (always present, false for every tab with no live payment, so existing responses are unchanged in meaning) and paymentUrl, 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 — IBookDinePlayClient gained 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 new depositRefund (NoOnlineRefund — the default and every venue's behaviour before this — RefundOnGuestCancel, or ForfeitOnGuestCancel). POST /api/reservations/{cancelToken}/cancel gains one problem type: 502 reservation-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 a 502 and not the settled-policy 409 reservation-deposit-not-refundable (Reservations, Errors).
  • API — reservation-deposit-not-refundable now means the venue's own choice rather than a missing feature: a venue that switches depositRefund away from NoOnlineRefund stops 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 — AdminReservationSummary gained a trailing depositRefundedAt (null until the deposit was refunded in full), on GET /api/operator/venue/reservations and GET /api/admin/reservations.
  • API — An Idempotency-Key on POST /api/venues/{venueSlug}/reservations is 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.refunded previously 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: seatSold on Resources (always present, default false — 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 its capacity combined — a 31-seat event area no longer goes off sale to a party of four. Availability slots for a seat-sold resource gain seatsRemaining ("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/resources accept a nullable seatSold — omitting it on an update leaves the resource's current mode untouched (create still defaults to exclusive).
  • API — POST /api/venues/{venueSlug}/reservations accepts an optional Idempotency-Key header (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 — same reference, same cancelToken — 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 new 409 idempotency-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 second CreateReservationAsync overload taking idempotencyKey before the cancellation token — the existing three-argument signature is untouched, so a caller compiled against an earlier BookDinePlay.Shared keeps binding.
  • .NET SDK — A client registered with AddBookDinePlayClient now mints an Idempotency-Key itself for POST /api/venues/{venueSlug}/reservations when 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) for GET /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 a fetch to show the guest what they booked before offering the button. Built like client.ticket(): no key header, no venue segment, the same BookDinePlayError mapping. The .NET SDK's GetRegistrationAsync already 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 400 naming the field instead of reaching the database and failing there as a 500. Most visible on reservations: email was 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-Key retry whose extras arrive 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 with 409 idempotency-key-reused for 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 — seatSold and Idempotency-Key are both additive: a venue that never sets seatSold sees byte-identical availability responses, and a reservation create with no Idempotency-Key header 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 a 400 instead.

v0.12.1 — 2026-09-23

  • API — Two new problem types on POST /api/operator/venue/payouts/onboarding-link, which previously answered 500 when Stripe refused: 409 connect-not-enabled (the platform has not signed up for Connect — nothing the venue can do) and 409 connect-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/checkout opens a Stripe Checkout session on the venue's own connected account (EventTicketCheckoutRequest — the same fields as a free registration, plus optional successUrl/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: 409 ticket-sales-not-enabled (the single guest-facing refusal folding together "plan lacks ticket sales", "payout account not connected" and "event not Paid"), 409 payouts-not-connected (operator-facing routes only), 409 refund-not-available (a guest's own cancel of a Paid registration the refund policy no longer allows), and 403 tenant-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 to checkoutUrl instead 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. New createClient/renderEventsWidget options successUrl/cancelUrl. ticket-sales-not-enabled and payouts-not-connected render the identical sentence, on purpose (Events).
  • WordPress — [bookdineplay_events]/[bookdineplay_event] gain success_url/cancel_url attributes, passed straight through to the widget (WordPress plugin).
  • .NET SDK — IBookDinePlayClient gained two members: CheckoutEventTicketsAsync and GetRegistrationAsync — hand-written implementations must add them (mocks are unaffected), the same 0.x precedent as the five members added in v0.10.0. BookDinePlayApiException gained the constants TenantSuspendedType, PayoutsNotConnectedType and RefundNotAvailableType (.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 billing interval (Monthly or Yearly) and the tenant's legal acceptances; the response carries a Stripe Checkout checkoutUrl that starts a 14-day card-upfront trial.
  • API — Two new problem types: 403 tenant-suspended on every /api/venues/** route once a venue's subscription has lapsed, been suspended, or a self-serve sign-up never finished paying; and 409 billing-managed-by-stripe on PUT /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=false for past ones), reads one with its registration window (…/events/{eventSlug} — registration.open and reason), and registers guests for free events (POST …/events/{eventSlug}/registrations) with one named ticket per attendee, a BDP-E-XXXX reference, 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} and POST /api/event-registrations/{cancelToken}/cancel need 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: 409 registration-closed with reason (closed, sold-out, past, not-open) and remaining: 0 when sold out, and 409 ticket-sales-not-enabled for a paid event until online ticket sales ship. POST …/events/{eventSlug}/tickets/checkout exists as a stub answering the latter; registering on a venue whose plan lacks events is 403 feature-not-in-plan. A broken registration rule is a 400 whose errors dictionary carries the messages under registration.
  • 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; eventSlug renders one event for a page of its own and onNavigate(slug, summary) routes to the host's pages. The headless client gains events(), event(), registerForEvent(), ticket() and cancelEventRegistration() (the last two send no key); BookDinePlayError lifts type, reason, remaining and errors off the problem and adds messages(). createClient no longer requires venueSlug up front — only the venue-scoped calls throw without it, so a ticket or cancel page needs just apiBaseUrl and publishableKey (Events).
  • WordPress — [bookdineplay_events venue="…" layout="grid|list" language="en|de"] renders the events widget and [bookdineplay_event venue="…" event="…"] one event directly; both take api, theme and key like the booking shortcode (WordPress plugin).
  • .NET SDK — IBookDinePlayClient gained five members: GetEventsAsync, GetEventAsync, RegisterForEventAsync, GetTicketAsync and CancelEventRegistrationAsync — hand-written implementations must add them (mocks are unaffected). BookDinePlayApiException carries Type, Reason, Remaining, Errors, Messages and Extensions plus the constants RegistrationClosedType and TicketSalesNotEnabledType. AddBookDinePlayClient registers a KeylessRouteHandler that strips X-BookDinePlay-Key and a Bearer bdp_… Authorization header 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-plan with a requiredPlan extension naming the tier that unlocks it (Errors).
  • API — A Starter venue's resources and resourceTypes omit its game-type resources entirely; guests never see them (Venue).
  • API — Availability for a resourceType the venue's plan does not offer returns 200 with empty slots and notice: "resource-type-not-offered"; reserving that type anyway is refused with the same feature-not-in-plan problem 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 as BookDinePlayError; the widget now runs on it, and renderBookingWidget refuses a key that is not a bdp_pk_… publishable key (returns null with a console message) instead of rendering and failing with 403 (Custom forms).
  • API — Opening hours may close after midnight (opens 18:00, closes 02: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 publishable bdp_pk_… key from an allowed origin in the browser, a secret bdp_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 accept durationMinutes, 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 — phone on 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 in sri.txt next to it) and sdk/v0/bookdineplay.js (five-minute alias). renderBookingWidget now requires publishableKey and takes theme (auto, light, dark); nine --bdp-* custom properties theme the widget from the host page; window.BookDinePlay.version names the loaded release (JavaScript SDK, Theming).
  • JavaScript SDK — durationMinutes is sent only when the guest picked a length; the venue's default applies otherwise.
  • .NET SDK — BookDinePlay.Sdk and BookDinePlay.Shared are on nuget.org, versioned in lockstep with the release (.NET SDK).
  • WordPress — The plugin ships as bookdineplay-<version>.zip on the release, loads the SDK from the v0 alias, stores the publishable key under Settings → BookDinePlay, and the shortcode gains a key attribute (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: de for German title and detail; 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 accepts extras: [{ "extraId": "…", "quantity": 1 }] and returns priced extras lines and extrasTotal.
  • API — Per-game pricing: a slot can carry pricingModel: "PerGame"; a reservation accepts and returns games (1–10).
  • API — Group bookings: a party too large for one resource is offered a group slot (groupResourceCount, groupResourceNames); the reservation returns groupReference and groupResources.
  • API — New resource type BowlingLane; food ordering is a per-resource setting (allowsFoodOrdering on resources).
  • JavaScript SDK, WordPress — BowlingLane in the resource-type list and in the plugin's default types; 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.