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
Specials
Show today's or this week's specials with renderSpecialsWidget and its Now on marker, or build your own cards on client.specials.
The same SDK file that renders the booking widget also shows a venue's specials: the dishes and menu-item deals the venue runs, each with its price and daily window. Two ways in, both on the same Specials API:
renderSpecialsWidget— one call, a list of cards inside an element you choose, style-isolated like the booking widget. The special running right now is marked Now on. Use it on a "Today" or "This week" page, or on a screen in the venue.- The headless client —
client.specials({ date, days })next to the booking and event calls of Custom forms. Use it when the site already has its own cards and only needs the data.
Specials are open to every plan, so nothing here depends on the venue's tier.
Install
Load the SDK as for the booking widget (JavaScript SDK) and add an element for the specials:
<div id="bookdineplay-specials"></div>
<script src="https://cdn.bookdineplay.com/sdk/v0/bookdineplay.js"></script>Render the specials widget
HTML
<script>
window.BookDinePlay.renderSpecialsWidget({
container: '#bookdineplay-specials',
venueSlug: 'your-venue',
apiBaseUrl: 'https://api.bookdineplay.com',
publishableKey: 'bdp_pk_your_publishable_key',
view: 'today',
locale: 'en',
theme: 'auto'
});
</script>JavaScript
// Headless: your own markup on the same data. The answer is null when the venue offers no specials.
const client = window.BookDinePlay.createClient({
apiBaseUrl: 'https://api.bookdineplay.com',
venueSlug: 'your-venue',
publishableKey: 'bdp_pk_your_publishable_key'
});
const response = await client.specials({ days: 7 });
for (const day of response?.days ?? []) {
for (const special of day.specials) {
console.log(day.date, special.title, special.price, response.currency);
}
}The call returns the widget instance, or null when it refused to render (When it refuses to render). The instance has one method, destroy(), which stops its timer and any request in flight.
Options
| Option | Required | Meaning |
|---|---|---|
container |
yes | A CSS selector or a DOM element. The widget renders inside it. |
venueSlug |
yes | Your venue's slug. |
apiBaseUrl |
yes | https://api.bookdineplay.com. Only different for a private deployment. |
publishableKey |
yes | The venue's bdp_pk_… key. Never a secret key. |
view |
no | today (default): today's specials under "Today's specials". Or week: the next seven days under "This week", with one heading per day that has specials. Anything else counts as today. |
locale |
no | en (default) or de: the widget's own texts, the day headings and the money format. Any de-* tag counts as de. language is accepted as an alias. The venue's titles and descriptions come in the language the venue wrote them in. |
theme |
no | auto (follow the visitor's system setting, default), light or dark. |
What the guest sees
Each special is a card with its picture (when it has a usable one), the title, the price, the item's name when it differs from the title, the description, the item's tags and a line with the daily window: 17:00–22:00, "(next day)" appended when it ends after midnight, or "All day". A special cheaper than the item's regular price shows the regular price struck through, with "Regular price" read out to screen readers. Within a day the cards keep the API's order (Specials API).
- Today lists the first day of the answer: yesterday's late windows that are still running first, marked "(from yesterday)", then today's specials.
- This week asks for seven days and lists only the days that have specials, each under its own date heading. A late window carried over from the previous day appears only under the first day; on every later day it is already listed under the day it started.
- Now on marks the special whose window contains the venue's current time, with a pulsing dot that stops for visitors who prefer reduced motion. A special carried over from yesterday that has ended is dimmed.
The title is a real heading and the cards are a list, so a screen reader announces them as such.
Time zone and refresh
"Now on" is always computed in the venue's time zone, taken from the answer's timezone, never from the visitor's browser. A guest in another country therefore sees the same marker the venue's own staff would. The widget re-evaluates it every minute without a request. When the venue's calendar day changes it fetches again, once per venue day, so a screen left open overnight rolls over to the new day's specials on its own.
A failed request never blanks the widget. The last answer stays on screen and the next minute's tick tries again, at most one request a minute, with one console warning for the first failure. Only a first load that fails leaves nothing to show until a retry succeeds.
Pictures
The API may answer a special's picture as a path relative to the BookDinePlay app, which would resolve against your site and break. The widget therefore shows a picture only when its address is an absolute https URL, and shows the card without one otherwise. (On a page served over plain http, as in local development, an absolute http address is accepted too.) A picture that fails to load is removed rather than left as a broken-image box. The pictures carry an empty alt, because the title already names the special.
One instance per container
Calling renderSpecialsWidget again on the same container replaces the first widget: the earlier one stops its timer and request and gives up the container, so no orphaned timer keeps running. Use a separate container for a "today" and a "week" widget on one page. A widget whose container has left the page stops by itself.
Renders nothing when empty
A venue with no specials in the period (nothing published, nothing running that day) gets no widget at all: no frame, no heading, no border, only your empty container. The same holds while the first request is still loading, when the first request failed, and when the answer is 404. Give the container no height or placeholder of its own, so the page does not show a hole.
When it refuses to render
renderSpecialsWidget returns null and writes one line to the browser console, never throwing into your page — the same three refusals as renderBookingWidget (When it refuses to render): the container was not found, venueSlug or apiBaseUrl is missing, or publishableKey is missing or not a bdp_pk_… key.
Theming
The specials widget renders in the same isolated root as the other widgets and reads the same nine --bdp-* custom properties from the host page: --bdp-accent for the "Now on" marker and the tags, --bdp-surface for the cards, --bdp-radius for their corners. Theming lists every property with its default; there is no specials-specific property.
The headless client
client.specials(params, { signal }) calls GET /api/venues/{venueSlug}/specials with the client's publishable key. params is optional: date (yyyy-MM-dd, the venue-local first day) and days (1 to 14) are sent only when given, and the API defaults to the venue's today and one day. It resolves the response body (slug, timezone, currency and days[]), or null for a 404, where the other reads reject. Any other failure rejects with a BookDinePlayError.
Two pure helpers are exposed for pages that draw their own cards. BookDinePlay.helpers.venueLocalNow(timezone, now) returns the venue's local date and time for an instant, and BookDinePlay.helpers.isSpecialOnAt(occurrenceDate, windowStart, windowEnd, localDate, localTime) answers whether a special is running at that moment, counted from its occurrenceDate as the widget does.
Next steps
- Specials API — every field of the answer, and how the venue's time zone and late windows work.
- Theming — colors, radius and font.
- Custom forms — the other calls of the same client.
- WordPress plugin — the same widget as
[bookdineplay_specials]. - .NET SDK —
GetSpecialsAsyncfor server-side code.