Authentication: secret keys vs publishable keys
Every request to /v1 carries one API key as a bearer token:
Authorization: Bearer sk_live_...or
Authorization: Bearer pk_live_...There are two kinds. Using the wrong one for the job is the single most common integration mistake — read this page before you write any code.
Secret keys (sk_live_… / sk_test_…)
Section titled “Secret keys (sk_live_… / sk_test_…)”- Live only on your server. Never send one to a browser, a mobile app, or a log you don’t control.
- Can do anything your operator granted: read guest details, create and cancel bookings, manage rates.
- Default rate limit: 300 requests/minute, burst 50.
Publishable keys (pk_live_… / pk_test_…)
Section titled “Publishable keys (pk_live_… / pk_test_…)”- Safe to embed in a public page — that’s the point. It’s what the widget uses.
- Hard-capped, on our server, to four things: check availability (including
the per-night calendar, which is the same
scope), get a quote, create a hold, and start a Stripe-hosted checkout for
that hold. On the calendar endpoint specifically, a
pk_key never receives a night’soccupants(guest id, label, state) — that field issk_/operator-session only. - Must be sent from an allowlisted origin. We check the browser’s
Originheader against the origins registered for that key; a request from any other origin is refused. - Tighter rate limit: 60 requests/minute per key+IP, plus a separate 10/minute/IP cap on hold creation specifically (this stops one visitor from squatting all your inventory with holds).
Why a hold from a pk_ key isn’t a booking
Section titled “Why a hold from a pk_ key isn’t a booking”A hold made with a publishable key is unconfirmed inventory only. Turning it
into a confirmed booking needs a succeeded card payment — either through the
sk_-only PaymentIntent route (your own server-side checkout) or through
checkout:create (a pk_-reachable hosted-checkout handoff — what the
widget uses). Either way, the actual charge and the confirmation check both
happen on our server and Stripe’s, never in the browser. That server-side
gate is what makes it safe to put a pk_ key in a page anyone can
view-source.
Card payment (Stripe) is live: confirming a hold requires a succeeded payment, checked server-side. See Holds and confirmation for the full mechanics.
Test mode
Section titled “Test mode”sk_test_… and pk_test_… hit the exact same API, against the operator’s
sandbox. Reservations made with a test key are flagged test, and payments
run in Stripe’s test mode. Build and test against _test_ keys; switch to
_live_ keys only when you go to production — the request shape doesn’t
change, only the prefix.
Getting a key
Section titled “Getting a key”There’s no sign-up form for you as an integrator. Your operator contact — an admin on the tenant’s dashboard — issues the key and hands you the plaintext once, at creation.
If a key is compromised, tell your operator contact immediately — they can revoke it from their dashboard, and revocation takes effect on the very next request.
Next steps
Section titled “Next steps”- Quickstart — your first request with a real key.
- Errors — how a wrong-key-kind request comes back (spoiler:
404, not403). - Rate limits — the limits above, in full.