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
Authentication
How BookDinePlay API keys work — publishable versus secret, where each is allowed, how to send them, and what the API refuses.
Every call to /api/venues/** must present an API key. There is no anonymous tier. A key is scoped to one venue: it works for that venue's routes and is refused for every other.
Two key types
Publishable bdp_pk_… |
Secret bdp_sk_… |
|
|---|---|---|
| Lives in | Your public HTML, the widget, the WordPress plugin | Your server only |
| Protected by | An origin allowlist you maintain | Being secret (stored as a SHA-256 hash; shown once at creation) |
Origin header |
Required — a browser sent it | Forbidden — a browser must never hold it |
| Typical caller | The booking widget in a guest's browser | Your back end, using the .NET SDK or plain HTTP |
Create and revoke keys in the console under Venue → API keys (app.bookdineplay.com/operator/venue). A publishable key's value is visible there at any time; a secret key's value is shown exactly once.
Sending a key
Either header works; the widget and the SDK use the first:
X-BookDinePlay-Key: bdp_pk_your_publishable_key
Authorization: Bearer bdp_pk_your_publishable_keyNever put a key in a query string. A key in a URL ends up in access logs, Referer headers and browser history, and the API does not read it from there anyway.
curl
curl "https://api.bookdineplay.com/api/venues/your-venue" \
-H "X-BookDinePlay-Key: bdp_pk_your_publishable_key" \
-H "Origin: https://www.your-venue.example"JavaScript
const response = await fetch('https://api.bookdineplay.com/api/venues/your-venue', {
headers: { 'X-BookDinePlay-Key': 'bdp_pk_your_publishable_key' }
});
const venue = await response.json();C#
// Program.cs — server-side, with a SECRET key from configuration, never a literal.
builder.Services.AddBookDinePlayClient(
new Uri("https://api.bookdineplay.com"),
builder.Configuration["BookDinePlay:ApiKey"]!);
// Anywhere IBookDinePlayClient is injected:
var venue = await client.GetVenueAsync("your-venue", cancellationToken);Origins
A publishable key carries a list of allowed origins. An origin is scheme://host[:port] — https://www.your-venue.example, not a path, and not a bare host name. Matching is exact on scheme and host; the port must match too, unless the entry ends in :*:
http://localhost:*
https://staging.your-venue.example:*:* means "any port on exactly this scheme and host" — for local development on localhost, or a staging host that moves between ports. It is the only wildcard; there is no wildcard for scheme, host or subdomain.
A request whose Origin is on the list gets that origin back in Access-Control-Allow-Origin and the data it asked for; one that is not gets a 403 whose problem body the browser can still read — the API echoes your origin on rejections precisely so you can see the type — but no venue data. The allowlist is the CORS policy — there is no separate setting.
What the API refuses
Every refusal is an RFC 7807 problem response whose type ends in the reason below; each reason has its own section on Errors.
| Status | type suffix |
When | Fix |
|---|---|---|---|
| 401 | missing-api-key |
No key in either header | Send the key |
| 401 | invalid-api-key |
Unknown, revoked, or wrong-prefix key | Check the key in the console |
| 403 | venue-mismatch |
The key belongs to a different venue than the route names | Use that venue's key |
| 403 | origin-not-allowed |
Publishable key; the request's Origin is not on its list |
Add the origin in the console |
| 403 | secret-key-from-browser |
Secret key and an Origin header — a browser sent it |
Use a publishable key in browsers |
| 403 | publishable-key-without-origin |
Publishable key and no Origin — a server sent it |
Use a secret key on servers |
Unknown and revoked keys give the same answer on purpose: nobody can probe which one it is.
{
"type": "https://bookdineplay.com/docs/api/errors/origin-not-allowed",
"title": "Forbidden",
"status": 403,
"detail": "This origin is not on the API key's list of allowed origins."
}Rotating a key
Keys can coexist, so rotation never needs downtime:
- Create a new key of the same type with the same origins.
- Deploy it to your site or server.
- Revoke the old key in the console. Revocation is immediate.
Next steps
- Quickstart — put a publishable key to work in the widget.
- .NET SDK — server-side use with a secret key.