Developers

Partner API

Show an operator's experiences on your own site and book them there. One JSON API for the catalogue, live availability, quotes, bookings and cancellations.

Updated 2026-10-20

Who is the Partner API for?

Vendors and resellers who want to list experiences and take bookings on their own website or in their own system: travel desks, hotel and concierge sites, tour resellers, corporate-event planners. If you can make an HTTPS request from a server, you can integrate.

What can I do with it today?

  • Read the catalogue: experiences with pictures, descriptions and options priced for your account.
  • Check availability per day and per time slot.
  • Quote a cart: prices, fees and a capacity answer before you commit.
  • Create bookings that are invoiced to you on a monthly statement, or that the customer pays on our secure hosted payment page while the seats are held for them, with an Idempotency-Key so retries are safe.
  • List, read and cancel the bookings you created.
  • Practise end to end with free test keys that never charge anyone and never hold capacity.

Coming soon

Webhooks for booking and waiver events. Until then, poll GET /bookings/{ref} to see when a pay-link booking is paid or has expired.

What is the base URL?

Every route lives under /api/partner/v1 on the booking domain the operator gives you with your keys:

text
https://<your-booking-domain>/api/partner/v1

Try it with your test key:

curl
curl https://<your-booking-domain>/api/partner/v1/me \
  -H "Authorization: Bearer pk_test_AbC123dEf456GhI7.your-secret-here"

Test keys or live keys?

Start with a test key (pk_test_...). Test keys work as soon as your account is enabled, read the real catalogue and real availability, and create practice bookings that never charge anyone. Live keys (pk_live_...) are switched on by the operator when you go live; until then they answer SANDBOX_ONLY. See Authentication and Sandbox.

What does every response look like?

Every response uses one envelope. Success returns ok: true with your payload in data; failure returns ok: false with an error. details is optional. The same requestId is sent in the X-Request-Id header, so quote it when you contact us. You can send your own X-Request-Id to correlate calls.

jsonSuccess
{
  "ok": true,
  "data": { "...": "..." },
  "requestId": "req_8f3a1c"
}
jsonFailure (HTTP 400)
{
  "ok": false,
  "error": {
    "code": "VALIDATION",
    "message": "from must be YYYY-MM-DD.",
    "details": { "field": "from" }
  },
  "requestId": "req_8f3a1c"
}

Branch on error.code, not on the message text. The full list is on the Errors page.

How are dates, times and money formatted?

ValueFormatExample
DatesYYYY-MM-DD2026-11-14
TimesHH:mm, 24-hour, in the venue's local time, as shown on the operator's booking site14:30
MoneyInteger cents, USD29900 = $299.00

There are no time zone offsets to convert: send the time as it reads on the venue's clock.

What are the rate limits?

LimitDefaultApplies to
Per key60 requests/min (your account may differ; see rateLimitPerMinute in GET /me)Every route
Per IP120 requests/min (30 under /bookings)All routes
Bookings, per IP30 requests/minEverything under /bookings
Bookings, writes per key10 writes/minCreating and cancelling bookings

Going over any limit returns 429 RATE_LIMITED in the standard error envelope (requestId, matching the X-Request-Id header), with a Retry-After header (seconds) and the same number in details.retryAfterSeconds. Wait that long, then retry. Cache the catalogue; it changes rarely.

A per-IP limit is checked before your key is read. On a per-IP 429, X-RateLimit-Limit is the per-IP limit (120, or 30 under /bookings), not your key limit, and X-RateLimit-Remaining is 0. Browser apps: a per-IP 429 carries no CORS headers, so the browser hides it from your code. Keep each IP under 120 requests/min (30 under /bookings).

Every authenticated response also carries two headers so you can pace yourself before you hit the limit: X-RateLimit-Limit (your per-minute key limit) and X-RateLimit-Remaining (requests left in the current minute).

http
HTTP/1.1 200 OK
X-Request-Id: req_8f3a1c
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57

How do I avoid double bookings on a retry?

POST /bookings requires an Idempotency-Key header, unique per booking you create. Send the same key again and you get the original booking back with replayed: true instead of a second booking. Details on the Bookings page.

How does paging work?

GET /bookings is cursor-paged (limit 1 to 100, default 50). Pass the previous response's nextCursor as cursor; it is null on the last page. Treat the cursor as opaque.

How will I hear about API changes?

Before the API changes, we email your developer contact with what is changing, whether you need to act, and when. Keep that contact current with the operator: give them a name and an email address that someone actually reads, and tell them when it changes. If no developer contact is set, the notice goes to the operator's notification email for your account, then to your main email. Past changes are on the Changelog.

Is there a machine-readable spec?

Yes: /developers/openapi.yaml (OpenAPI 3.1, version 1.4.0). Import it into Postman, Insomnia or a code generator.

Where do I get keys?

Keys are issued by the operator you are integrating with, and the secret is shown once. To start a conversation, contact us. Webhooks are marked Coming soon wherever they appear.