Getting started
The API is a plain REST API over HTTPS that returns JSON, authenticated with a single API key you generate yourself once your access is approved. The examples below use {BASE_URL} as a placeholder — your base URL is shown next to your key in the developer dashboard.
- 1
Apply
Tell us about your platform. We review every request by hand, usually within 1–2 business days.
- 2
Generate your key
Once approved, create your API key in the developer dashboard. It is shown only once.
- 3
Call the API
Send the key as an X-API-Key header on every request. That is the whole handshake.
Authentication
Send your key in the X-API-Key header on every request. There is no OAuth flow, no token exchange and no expiry — the key stays valid until you regenerate or revoke it.
curl -X GET '{BASE_URL}/b2b/api/apiv2/b2c/tours/search?term=cappadocia&page_size=5' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Accept: application/json'const res = await fetch(
'{BASE_URL}/b2b/api/apiv2/b2c/tours/search',
{
method: 'POST',
headers: {
'X-API-Key': process.env.TSB_API_KEY,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({ term: 'cappadocia', page_size: 5 }),
},
)
const data = await res.json()Rate limits & quotas
Two independent limits apply, both counted per partner — never shared with anyone else.
240 requests per minute
A burst limit. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining so you can pace yourself.
20000 requests per day
The default daily quota on approval. It resets at midnight UTC, and we raise it on request — tell us your expected volume and we will match it.
Exceeding either limit returns 429. Your current usage, broken down per endpoint, is visible in your developer dashboard.
Content rules
New tours are held back for 30 days. A tour added to our catalogue does not appear in partner search results or tour detail responses until it is 30 days old. This gives the tour time to be indexed on our own site first, so search engines see the original source. Everything older than that is fully available to you.
Pricing, dates and content are revalidated daily. Cache responses if you like, but refresh prices and availability at least once a day — and always re-check availability immediately before creating a booking.
Tour search & content
Search the catalogue and pull full tour content. These are the endpoints most integrations start with.
/b2b/api/apiv2/b2c/tours/searchSearch tours
Full catalogue search with faceted filters. Send filters as query parameters (GET) or as a JSON body (POST) — POST is recommended once you use array filters.
| Parameter | Type | Description |
|---|---|---|
term | string | Free-text search across tour titles and content. |
destination | string | Destination slug to scope the search to. |
category | string | Single category slug. |
categories | string[] | Several category slugs at once. |
activities | string[] | Activity slugs (see the activities endpoint). |
languages | string[] | Guiding language codes. |
price | [min, max] | Price range as a two-item array, in EUR. |
duration | [min, max] | Duration range in days (defaults 1–28). |
rating | number | Minimum review rating. |
start_location | integer | Pickup location id. |
end_location | integer | Drop-off location id. |
transports | string[] | Transport type slugs. |
accommodations | string[] | Accommodation type ids. |
physical_ratings | integer[] | Physical difficulty rating ids. |
ids | integer[] | Restrict the result to specific tour ids. |
order | string | Sort field. Defaults to created_at. |
page | integer | Page number, 1-based. |
page_size | integer | Results per page. Defaults to 10. |
Results respect the content embargo — see Content rules below.
/b2b/api/apiv2/b2c/tours/detail/{slug}Tour detail
The complete tour record: itinerary, inclusions, images, departure rules and review summary. {slug} is the tour slug returned by search.
/b2b/api/apiv1/b2c/quicksearch/toursQuick tour search
Type-ahead search for search boxes. Same engine as the full search but tuned for short, fast queries.
| Parameter | Type | Description |
|---|---|---|
term | string | What the user has typed so far. |
Pricing & availability
Live prices and departure availability. Every path exists in a b2c and a b2b variant: b2c returns retail prices, b2b returns your net (operator) price.
/b2b/api/apiv2/b2c/availability/{slug}Availability & price for a tour
Departure availability and pricing for one tour. Use /b2b/api/apiv2/b2b/availability/{slug} for net pricing.
| Parameter | Type | Description |
|---|---|---|
roomType | string | sng, dbl or trp. Defaults to dbl. |
date | YYYY-MM-DD | A single departure date. |
startDate | YYYY-MM-DD | Start of a date range. |
endDate | YYYY-MM-DD | End of a date range. |
pax | integer | Number of travellers. |
service_type | string | Service level. Defaults to regular. |
rooms | array | Room breakdown, as [{ id, pax, count }]. |
include_prices | yes | no | Include the price breakdown. |
include_rooms | yes | no | Include room options. |
/b2b/api/apiv2/b2c/prices/{type}Batch prices
One price per tour for a list of ids — what listing and category pages need. Use the b2b path for net prices.
| Parameter | Type | Description |
|---|---|---|
idsrequired | integer[] | Tour ids to price. |
roomType | string | sng, dbl or trp. Defaults to dbl. |
startDate | YYYY-MM-DD | Defaults to today. |
endDate | YYYY-MM-DD | Optional range end. |
/b2b/api/apiv2/b2c/pricemonths/{type}/{id}Monthly price calendar
Cheapest price per month for a tour — for a "from €X in May" calendar. A b2b variant is available for net prices.
Destinations & taxonomy
The reference data behind filters, menus and search boxes.
/b2b/api/apiv1/b2c/countries/listCountries
All countries with their id, name, slug and phone code.
/b2b/api/apiv1/b2c/quicksearch/locationsLocation search
Search destinations by name — cities, regions and countries.
| Parameter | Type | Description |
|---|---|---|
q | string | Search term. |
ids | string | Comma-separated ids, to resolve known locations instead of searching. |
limit | integer | Max results, 1–50. Defaults to 20. |
/b2b/api/apiv1/location-parents/{id}Location ancestors
The parent chain of a location (city → region → country), for breadcrumbs.
/b2b/api/apiv1/b2c/quicksearch/tour-categoriesTour categories
Category pages matching a term, with their titles and URLs.
| Parameter | Type | Description |
|---|---|---|
term | string | Search term. |
/b2b/api/apiv1/b2c/quicksearch/activitiesActivities
Activity list (hiking, diving, …) with id, name and slug — the values the activities filter accepts.
| Parameter | Type | Description |
|---|---|---|
term | string | Search term. |
/b2b/api/apiv1/b2c/tours/available-destinationsAvailable destinations
Destinations that currently have bookable tours.
/b2b/api/apiv1/b2c/tours/trending-destinationsTrending destinations
Destinations with the strongest recent demand.
Enquiries & bookings
Create demand on our side from your platform. Everything you create here is attributed to your partner account and appears in your dashboard.
/b2b/api/apiv1/bookings/new-enquiryCreate an enquiry
A traveller question about a tour. Creates an enquiry record and notifies the operator.
| Parameter | Type | Description |
|---|---|---|
tour_idrequired | integer | The tour being asked about. |
contact_namerequired | string | The traveller's name. |
contact_emailrequired | string | The traveller's email. |
messagerequired | string | The question, up to 5000 characters. |
phone_code | integer | Location id of the phone country code. |
contact_phone | string | Phone number without the country code. |
buyer_currency | USD | EUR | Currency to quote in. Defaults to EUR. |
No captcha is required on API-key requests — your key, quota and rate limit are the gate.
/b2b/api/apiv1/bookings/new-bookingCreate a booking
A full booking with travellers and rooms. Returns the booking with its reference_id and token, which you then use for payment.
| Parameter | Type | Description |
|---|---|---|
tour_idrequired | integer | The tour being booked. |
paxrequired | integer | Number of travellers. |
daterequired | YYYY-MM-DD | Departure date, today or later. |
service_typerequired | string | Service level, as returned by availability. |
seller_currencyrequired | string | Currency the tour is sold in. |
buyer_currencyrequired | string | Currency the traveller pays in. |
rooms | array | Required for tours with accommodation: [{ id: "dbl", pax, count }]. |
customersrequired | array | Travellers. The first is the lead and needs title, first_name, last_name, email, phone_code and phone. |
/b2b/api/apiv1/bookings/{referenceId}Booking detail
Read one booking. Pass the booking token as ?token= — the token scopes access to that single booking.
| Parameter | Type | Description |
|---|---|---|
tokenrequired | string | The token returned when the booking was created. |
/b2b/api/apiv1/bookings/{referenceId}/payment-requestOpen a payment request
Start a collection against a booking, for a payment page hosted on your own front end. The amount is calculated from the booking — the client cannot set it.
| Parameter | Type | Description |
|---|---|---|
tokenrequired | string | The booking token. |
payment_model | total | deposit | Collect the full remaining amount or just the deposit. |
/b2b/api/apiv1/bookings/{referenceId}/payment-request/{id}Payment request status
Poll the state of a payment request. Requires the same token.
| Parameter | Type | Description |
|---|---|---|
tokenrequired | string | The booking token. |
/b2b/api/apiv1/bookings/abandoned-cartReport an abandoned cart
Tell us a traveller started but did not finish a booking, so our team can follow up. Creates no booking record.
| Parameter | Type | Description |
|---|---|---|
sourcerequired | tsb | tst | Which storefront the cart came from. |
tourrequired | string | Tour slug. |
name | string | The traveller's name. |
email | string | The traveller's email. |
phone_code | integer | Location id of the phone country code. |
phone | string | Phone number. |
date | YYYY-MM-DD | Intended departure date. |
pax | integer | Number of travellers. |
Errors
Errors use standard HTTP status codes, with a JSON body carrying a message and — for validation failures — an errors object keyed by field name.
| Code | Meaning | What to do |
|---|---|---|
| 200 | OK | The request succeeded. |
| 401 | Unauthorized | The X-API-Key header is missing, or the key is not recognised. Check that you are sending the key you generated, not the one it replaced. |
| 403 | Forbidden | Your API access is suspended or not yet approved. Contact us if you believe this is a mistake. |
| 404 | Not found | The tour, booking or location does not exist — or, for token-scoped endpoints, the token does not match. |
| 422 | Unprocessable | Validation failed. The body contains a message and an errors object keyed by field name. |
| 429 | Too many requests | You exceeded either the per-minute rate limit or your daily quota. Check the X-RateLimit-Remaining header and back off. |
| 500 | Server error | Something failed on our side. Retry with backoff; if it persists, contact us with the time of the request. |
{
"message": "The given data was invalid.",
"errors": {
"tour_id": ["The selected tour id is invalid."],
"customers.0.email": ["The customers.0.email must be a valid email address."]
}
}Versioning
The version is part of the path: /b2b/api/apiv1/… and /b2b/api/apiv2/…. Both are live and maintained; which one an endpoint sits under is historical, not a quality difference.
Within a version we only make additive changes — new fields and new endpoints. We do not rename or remove fields you already rely on. Anything that would break an integration ships under a new version path, and we email every active partner before a version is retired.
Ready to build?
Apply for access and generate your key. Questions about which integration fits you? Our team is happy to help.