Authentication
API keys
The API authenticates the partner, not the traveller. One credential — an API key — identifies your account, decides what you may call, and is the thing every invoice line traces back to.
Sending a key
Pass the key as a bearer token on every request. There is no session, no login call and no token exchange.
GET /v1/account HTTP/1.1
Authorization: Bearer vcb_live_7Kq2xY…
Accept: application/jsonThere is one way in and it is this header. An earlier version of this page also documented passing the key in a WebSocket subprotocol for a streaming endpoint at /v1/stream. That endpoint does not exist, so neither does that handshake.
Keys never leave your servers
Two environments
Not enforced by the host yet
wrong_environment, and the refusal names the base URL to send the call to instead of telling you to rotate a key that was never the problem. What decides is the kind of key each deployment is configured to accept — and today a single deployment accepts both, so the check has nothing to refuse. Separating the two hosts is planned; until that is live, a deployment of yours wired with the wrong key will not fail on its first call. Check the key prefix against the base URL in your own start-up configuration — that is the guarantee you are actually relying on.Scopes
Every key carries an explicit list of scopes, and every endpoint requires one. A key with no scope for a route is rejected before the request reaches any supplier.
Scopes are named <resource>:<action>. There is no generic read or write action — the actions are per resource, and these 11 are the complete list the gateway enforces, with every route each one opens:
Where the key form and the gateway differ
bookings:read, bookings:cancel and stream:subscribe. They can be granted and they guard no route — a key holding them gains nothing. Conversely transfers:search and transfers:book are enforced by the gateway but missing from the form, so if you sell the products behind them, ask your Vacabee contact to have them added to your key.The scopes actually granted to a key are shown on the key in the portal and returned by GET /v1/account. A rejected call names the one it was missing, so you never have to guess:
{
"error": {
"type": "insufficient_scope",
"message": "The API key is missing the scope \"hotels:book\".",
"requestId": "a4f1c358-6b2e-5acb-8ef5-0c3d0bcc35f5"
}
}Branch on insufficient_scope — that is the literal value; there is no missing_scope. requestId is a plain UUID with no prefix, and docUrl only appears when the deployment has a documentation base URL configured, so treat it as optional.
Grant the narrowest set that does the job — with one limitation worth designing around: reading a booking back needs the same …:book scope as creating or cancelling one. A reconciliation job that only reads therefore cannot be given a key that is unable to cancel. If that matters, keep the key on a system that cannot issue cancellations rather than expecting the scope to enforce it.
IP allow lists
Each key can be pinned to a list of source addresses or CIDR ranges. A request from anywhere else is refused regardless of how valid the key is. This is the cheapest mitigation there is for a leaked credential, and it costs nothing if your egress addresses are stable.
Leave the list empty and the key is accepted from anywhere. A list that would allow everything is refused rather than stored, so say it by leaving the list empty.
IPv4 ranges only
403 ip_not_allowed, with no hint as to why. If your egress is IPv6, list the individual addresses.If your egress is dynamic, an allow list is not the tool: keys have no expiry you can set at creation, so there are no short-lived keys to fall back on. Use a stable egress address, or leave the list empty and rely on keeping the secret out of reach.
Rotation
Keys are stored as a SHA-256 hash. We cannot show you an existing secret, recover one, or read one out of a log — the plaintext exists exactly once, in the response that created it. Store it in your secret manager at that moment.
- Rotating a key issues a new secret and gives the old one an expiry in the near future, so both work while you roll out. Deploy the new secret, then let the old one lapse or revoke it early.
- Do not use the last-used timestamp to decide that traffic has moved. The field is shown in the portal but nothing updates it, so a key that is still serving live traffic looks unused. Confirm the cutover from your own side — your logs, or the
X-Request-Idof calls you know you made with the new secret — before you revoke anything. - Revocation is immediate: the gateway caches the key catalogue for 60 seconds but is invalidated on revoke, so a killed key stops working in under a second.
- Use separate keys per system — checkout, back office, batch jobs. One compromised component then costs you one rotation, not a coordinated one across your estate.
- Every key operation is recorded in an audit trail with the portal user who performed it. It is not exposed in the portal or over the API today, so if you need it for a compliance review, ask your Vacabee contact for an export rather than promising your auditor self-service access.
Live keys need an approval first
vcb_live_ key fails with 400 until your partner account has been approved for production keys. That approval is granted by hand on our side, so it is a lead time rather than a click: ask for it days before your launch date, not on the day. Test keys are unaffected.Travellers
Your travellers do not have Vacabee accounts and never authenticate with us. There is no traveller resource on our side: we hold no per-traveller record you can address, and no identifier of yours is stored against one.
X-Partner-Customer-Ref is not read
X-Partner-Customer-Ref header and that we keep the mapping. The header is allowed through CORS and read by nothing — sending it is silently ignored, which is exactly the kind of mistake that surfaces only when you rely on the mapping. There is also no DELETE /v1/customers/{ref}: that route does not exist, so do not put it in your own deletion process or in a data processing agreement.What does tie your records to ours is externalReference on each booking or order: your own value, echoed back, and the thing to quote in support. What we store per booking is what the supplier needs — guest or passenger names and the contact details you send. If a traveller exercises a deletion request, raise it with your Vacabee contact; there is no self-service endpoint for it today.

