The Alps2Alps Public API is a free, key-less HTTP API that lets AI agents and developer integrations discover Alpine transfer routes, retrieve real-time prices from the same booking engine that powers the website, look up verified accommodation entries, and generate checkout links that land the end user directly on the booking form with everything pre-filled. The entire flow works with GET requests only — no POST needed — so even chat agents that can only open URLs can drive the booking funnel.
No authentication is required. All endpoints are rate-limited per IP. All responses are application/json.
https://booking.alps2alps.com/api/public/v1/https://booking.alps2alps.com/openapi/public-v1.json. Import it directly into Postman, Insomnia, or any AI agent framework that accepts an OpenAPI URL (OpenAI function calling, Anthropic tool use, LangChain, AutoGen, and others).Alps2Alps is a private Alpine transfer service (airport / train station ↔ ski resort). This API lets you take a user from “I want to go from Geneva to Chamonix on the 22nd” to a ready-to-pay booking page — without any auth and without leaving GET requests if that’s all your runtime supports.
Minimum end-to-end flow (works with GET only):
GET /api/public/v1/locations/search?q=Geneva→ resolve names to codes (airport-1,resort-11,train_station-7,city-48).GET /api/public/v1/transfer-options?from=airport-1&to=resort-11&date=2026-07-22&time=14:30&adults=2→ live prices per vehicle. The response includes ready-made links — no need to construct URLs manually:
response.quote_url— pre-filled step-2 link (vehicle picker). Use this when the user hasn’t chosen a vehicle yet.response.outbound.vehicles[i].booking_url— per-vehicle step-3 link (Your Details, vehicle pre-selected). Use this after the user picks a vehicle.If you can POST, use
POST /api/public/v1/checkout-linkwhen you also need to pre-fill accommodation, flight numbers, or free-text driver notes. That returns a stable tokenised URL valid for 24 hours.Adding any
return_*parameter flips the request to a return trip. Omitted return fields automatically mirror the matching outbound value, so the simplest return URL is just…&return_date=…&return_time=….
Everything you need to integrate is linked from these discovery files:
https://booking.alps2alps.com/.well-known/api-catalog — IETF API catalogue.https://booking.alps2alps.com/.well-known/agent-skills/index.json — AI agent skill manifest with URL templates, friendly aliases, and example prompts.https://booking.alps2alps.com/openapi/public-v1.json — Full OpenAPI 3.1 spec (v1.4.0)./locations/search to resolve the user’s pickup and drop-off names into airport-… / resort-… / city-… codes./accommodations?resort_id=…&q=… with at least 2 characters of the hotel name. Pick the matching entry and confirm the exact name with the user before using its id./transfer-options with the location codes plus passenger, luggage, and date inputs. The response includes passengers (confirming the passenger counts used), luggage per direction, and max_passengers / max_luggage per vehicle so you can tell users which vehicles fit their group. For return trips, each vehicle also carries a total_price for the combined journey. Present prices, vehicle types, travel time, and any promo discount. Always confirm the returned pick_up_date_time / return.pick_up_date_time back to the user — those are the actual times the driver will use.booking_url field on that vehicle to send them directly to step 3 (Your Details) with everything pre-filled. If you need to pre-fill an accommodation, flight number, or driver notes as well, use POST /checkout-link instead.For chat agents that can only fetch URLs, the same end-to-end flow is possible without ever issuing a POST:
GET /locations/search?q=… to resolve names to codes.GET /api/public/v1/transfer-options?from=…&to=…&date=…&time=…&adults=… to fetch live prices. The JSON response already contains the links — just use them directly:
response.quote_url — lands the user on step 2 (vehicle picker).response.outbound.vehicles[i].booking_url — lands the user on step 3 with that vehicle pre-selected./api/public/v1/locations/searchSearch for supported pickup and drop-off locations: resorts, airports, train stations, and cities.
| Parameter | Required | Notes |
|---|---|---|
q | Yes | Search term. Strings shorter than 2 characters return an empty array. |
A flat array of matching locations. Resort codes follow the pattern resort-{id}; transport hub codes follow {type}-{id} (e.g. airport-1, train_station-7, city-48).
[
{ "code": "airport-1", "name": "Geneva Airport", "type": "airport", "country": "Switzerland" },
{ "code": "resort-11", "name": "Chamonix", "type": "resort", "country": "France" }
]
400 INVALID_PARAMS — q parameter missing entirely.curl "https://booking.alps2alps.com/api/public/v1/locations/search?q=cham"
→ Try it live: search for “Geneva”
/api/public/v1/accommodationsTyped hotel lookup against the verified accommodation catalogue used by the booking funnel’s step-3 autocomplete. Results are scoped to a 10 km radius around the supplied resort. The intended flow is a typed lookup — the user names their hotel, the agent passes it as q scoped to the resort, and picks the matching id to send to /checkout-link.
| Parameter | Required | Default | Notes |
|---|---|---|---|
resort_id | Yes | — | Numeric resort id from a resort-{id} location code. |
q | Yes | — | Substring of the accommodation name (accent-insensitive). Min 2, max 100 characters. |
limit | No | 20 | Hard-capped at 50. |
{
"data": [
{
"id": 38959,
"name": "Clos 66",
"address": "66 Clos des Charmilles, Chamonix",
"latitude": 45.9123,
"longitude": 6.8694
}
],
"total": 4
}
total is the count before limit is applied, so the caller can tell when results were truncated.
Important: Only
idvalues returned by this endpoint may be passed into/checkout-linkasaccommodation_id. Free-typed hotel names are not accepted, ensuring every order receives a verified name and address pair.
400 INVALID_PARAMS — resort_id missing or not an integer, or q missing or shorter than 2 characters.404 RESORT_NOT_FOUND — resort id is unknown, inactive, or has no coordinates.curl "https://booking.alps2alps.com/api/public/v1/accommodations?resort_id=11&q=clos"
→ Try it live: search “clos” near Chamonix (resort 11)
/api/public/v1/transfer-optionsReturns real-time prices for every bookable vehicle type on the requested route, in the requested currency, with the requested passenger and luggage configuration. Nothing is persisted — this is a quote-only endpoint. Two request flavours share the same response envelope:
book\forms\Transfer field names. Recommended for programmatic clients with full control over headers and body.from, to, date, time, …). For AI agents and chat tools that construct URLs by hand. See the Deep links section for the full alias table.Important — time vs pickup time: By default,
timeandreturn_timeare interpreted as flight times (is_flightandreturn_is_flightdefault to1). The system calculates the actual pickup time from the flight time — for a return leg, the resort pickup will be earlier than the stated flight time.If the user states a desired pickup time rather than a flight time (e.g. “pick us up at 14:30”, “leave the resort at 18:00”), set
is_flight=0and/orreturn_is_flight=0. Otherwise the quoted pickup time will be wrong.Always confirm the returned
pick_up_date_time/return.pick_up_date_timeback to the user — those are the actual times the driver will use.Example: A request with
return_time=18:00and the defaultreturn_is_flight=1(resort → airport) returns"return.pick_up_date_time": "2026-07-26 14:20:00"— the system worked back from an 18:00 flight. To get an 18:00 pickup, send&return_is_flight=0.
Accepts application/json or application/x-www-form-urlencoded.
| Field | Type | Required | Notes |
|---|---|---|---|
route_from_code | string | Yes | e.g. airport-1 |
route_to_code | string | Yes | e.g. resort-11 |
outbound_date | string | Yes | YYYY-MM-DD |
outbound_time_hours | int | Yes | 0–23 |
outbound_time_minutes | int | Yes | 0–59 |
outbound_selected_time_is_flight | int (0/1) | No (default 1) | 1 = time is a flight arrival time, pickup calculated. 0 = time is the literal pickup time. |
is_return | int (0/1) | No (default 0) | When 1, all return_* fields are required |
adult_count | int | Yes | ≥ 1 |
children_count | int | No | |
infant_count | int | No | |
children_age_seat_count | int | No | Number of child-seat-aged children |
children_age_booster_count | int | No | Number of booster-seat-aged children |
luggage_count | int | No | |
skibag_count | int | No | |
has_ski_equipment | int (0/1) | No | |
currency_code | string | No (default EUR) | ISO 4217. Unknown/inactive codes return 400 CURRENCY_NOT_SUPPORTED. |
promo_code | string | No | Silently ignored if invalid |
For return trips, mirror the outbound fields with a return_ prefix: return_route_to_code, return_date, return_time_hours, return_time_minutes, return_selected_time_is_flight (default 1 — see time note above), return_adult_count, return_children_count, return_infant_count, return_children_age_seat_count, return_children_age_booster_count, return_luggage_count, return_skibag_count, return_has_ski_equipment.
All outbound and return aliases are documented in the Deep links section. The following extra parameters are only relevant to GET requests and are not part of the POST body:
| Parameter | Type | Required | Description |
|---|---|---|---|
child_ages | string | No | Comma-separated ages of children in the group, e.g. 8,12. Informational only — not used for pricing or vehicle selection. The value is echoed back in passengers.child_ages and preserved in the generated quote_url and booking_url. |
return_child_ages | string | No | Same as child_ages for the return leg. Preserved in generated URLs only. |
The booking system selects vehicles based on
adults,children, andchild_seats/boosterscounts — not individual child ages. Thechild_agesparameter exists so that AI assistants and integrations can confirm back to the user that their input was received. If specific seating requirements apply (child seat vs booster), use thechild_seatsandboostersparameters.
One-way, 2 adults, 2 bags:
curl "https://booking.alps2alps.com/api/public/v1/transfer-options?from=airport-1&to=resort-11&date=2026-07-22&time=14:30&adults=2&luggage=2"
→ Try it live: Geneva Airport → Chamonix, one-way
Return trip, 2 adults + 1 child + 3 bags (realistic AI-chat scenario):
curl "https://booking.alps2alps.com/api/public/v1/transfer-options?from=airport-1&to=resort-11&date=2026-07-22&time=14:30&adults=2&children=1&luggage=3&return_date=2026-07-29&return_time=10:00"
→ Try it live: return trip, 2 adults + 1 child + 3 bags
Example GET response (all fields populated, one-way trip):
{
"disclaimer": "Prices shown are real-time and calculated using the same engine as the booking website.",
"quote_url": "https://booking.alps2alps.com/book/quick-search?from=airport-1&to=resort-11&date=2026-07-22&time=14%3A30&adults=2",
"route": {
"from": "Geneva Airport",
"from_code": "airport-1",
"to": "Chamonix",
"to_code": "resort-11",
"distance_km": 99,
"duration_minutes": 100,
"travel_time": "01:40:00"
},
"currency": "EUR",
"passengers": {
"adults": 4,
"children": 2,
"child_ages": [8, 12],
"infants": 0,
"child_seats": 0,
"boosters": 0
},
"outbound": {
"pick_up_date_time": "2026-07-22 14:30:00",
"luggage": {
"normal_suitcases": 2,
"ski_equipment": 0
},
"vehicles": [
{
"vehicle_type_id": 10,
"name": "Standard minivan",
"price": 247,
"max_passengers": 8,
"max_luggage": 8,
"offer_code": "requested",
"total_price": null,
"booking_url": "https://booking.alps2alps.com/book/quick-checkout?from=airport-1&to=resort-11&date=2026-07-22&time=14%3A30&adults=4&children=2&vehicle=10"
},
{
"vehicle_type_id": 4,
"name": "VIP",
"price": 418.50,
"max_passengers": 7,
"max_luggage": 7,
"offer_code": "requested",
"total_price": null,
"booking_url": "https://booking.alps2alps.com/book/quick-checkout?from=airport-1&to=resort-11&date=2026-07-22&time=14%3A30&adults=4&children=2&vehicle=4"
}
]
},
"return": null,
"promo_code_applied": false
}
For a return trip, each vehicle in both the outbound and return blocks additionally carries a total_price:
{
"vehicle_type_id": 11,
"name": "Standard XL minivan",
"price": 257.21,
"max_passengers": 8,
"max_luggage": 8,
"offer_code": "requested",
"total_price": 473.81,
"booking_url": "https://booking.alps2alps.com/book/quick-checkout?from=airport-1&to=resort-11&..."
}
GET-only fields (
nullwhen using POST):
quote_url— ready-made step-2 link pre-filled with all the current search parameters. Use this when the user hasn’t chosen a vehicle yet.vehicles[].booking_url— ready-made step-3 checkout link for each vehicle, with that vehicle pre-selected. After the user picks a vehicle, pass this URL directly to them.Note on URL encoding: The
quote_urlandbooking_urlvalues in the JSON response use a literal&character to separate query parameters (e.g.…children=2¤cy=EUR), which is correct for URL strings inside JSON. Some tools — including certain browser DevTools panels and AI chat interfaces — may visually render¤cyas¤cybecause¤is an HTML entity (the ¤ symbol). This is a display-only rendering artefact. The actual URL returned by the API is correct. Copy the raw value from the JSON response, not from a rendered HTML view.Fields present on both GET and POST:
route.from_code/route.to_code— the location codes echoed from the request.passengers— the full passenger configuration after defaults are applied. Includeschild_ages(array of integers, ornullif not provided or on POST).outbound.luggage/return.luggage— luggage used when pricing each leg (normal_suitcases,ski_equipment). Confirms what the engine used.vehicles[].max_passengers— maximum passengers this vehicle can carry. All returned vehicles already passed the capacity filter, so they are confirmed suitable for the group.vehicles[].max_luggage— maximum suitcases this vehicle can carry.vehicles[].total_price— return trips only. The combined price for this vehicle type across both legs, rounded to 2 decimal places.nullon one-way trips. Do not attempt to sum leg prices manually — usetotal_pricewhen displaying the combined journey cost.Promo code response fields:
When a valid promo was applied:
"promo_code": "AMI10", "promo_code_applied": true, "promo_code_discount": { "type": "percent", "value": 5 }When a promo code was submitted but is not valid for this route, date, or group:
"promo_code": "AMI10", "promo_code_applied": false, "promo_code_message": "Promo code is not valid for this route, date, or group."
400 INVALID_PARAMS — body empty, validation failure, or malformed date.400 CURRENCY_NOT_SUPPORTED — currency not in the active currency list (GET and POST).404 ROUTE_NOT_FOUND — location code combination does not map to an active route.422 UNSUPPORTED_ROUTE — station-to-station, resort-to-resort, or other funnel-rejected combinations.422 MANUAL_BOOKING_REQUIRED — route requires manual handling.429 RATE_LIMITED — too many requests from this IP. Back off and retry.500 INTERNAL_ERROR — pricing engine threw an unrecognised exception.One-way:
curl -X POST -H "Content-Type: application/json" \
-d '{
"route_from_code": "airport-1",
"route_to_code": "resort-11",
"outbound_date": "2026-07-22",
"outbound_time_hours": 14,
"outbound_time_minutes": 30,
"outbound_selected_time_is_flight": 1,
"is_return": 0,
"adult_count": 2,
"luggage_count": 2,
"currency_code": "EUR"
}' \
"https://booking.alps2alps.com/api/public/v1/transfer-options"
Return trip, 2 adults + 1 child + 3 bags (realistic AI-chat scenario):
curl -X POST -H "Content-Type: application/json" \
-d '{
"route_from_code": "airport-1",
"route_to_code": "resort-11",
"outbound_date": "2026-07-22",
"outbound_time_hours": 14,
"outbound_time_minutes": 30,
"outbound_selected_time_is_flight": 1,
"is_return": 1,
"adult_count": 2,
"children_count": 1,
"luggage_count": 3,
"currency_code": "EUR",
"return_date": "2026-07-29",
"return_time_hours": 10,
"return_time_minutes": 0,
"return_selected_time_is_flight": 0,
"return_adult_count": 2,
"return_children_count": 1,
"return_luggage_count": 3
}' \
"https://booking.alps2alps.com/api/public/v1/transfer-options"
/api/public/v1/checkout-linkAccepts the same body as /transfer-options plus a few optional pre-fill fields. Returns a one-shot URL valid for 24 hours. Use this endpoint when you need to pre-fill an accommodation, flight number, or driver notes alongside the booking — for everything else, the booking_url field in the /transfer-options GET response is simpler.
| Field | Type | Notes |
|---|---|---|
outbound_vehicle_type_id | int | Optional. Defaults to the cheapest available outbound vehicle. |
return_vehicle_type_id | int | Optional. Only used when is_return = 1. |
outbound_flight_number | string | Optional. Alphanumeric + hyphen, max 16 chars. |
return_flight_number | string | Optional. Only used when is_return = 1. |
accommodation_id | int | Optional. Must be an id returned by /accommodations and within 10 km of the route’s resort. |
additional_info | string | Optional. Free-text driver note. Max 1000 chars. |
return_additional_info | string | Optional. Driver note for the return leg. Only used when is_return = 1. |
{
"checkout_url": "https://alps2alps.com/book/public-checkout/8f1c2c…",
"expires_at": "2026-05-28 09:14:22",
"currency": "EUR",
"promo_code_applied": true
}
All errors from /transfer-options, plus:
400 INVALID_PARAMS — accommodation_id is not a positive integer.400 VALIDATION_ERROR — accommodation id unknown, outside the route’s resort radius, or route has no resort side.422 NO_BOOKABLE_VEHICLE — no vehicle had a usable price on this route.429 RATE_LIMITED — too many requests from this IP. Back off and retry.500 INTERNAL_ERROR — could not persist the checkout link.curl -X POST -H "Content-Type: application/json" \
-d '{
"route_from_code": "airport-1",
"route_to_code": "resort-11",
"outbound_date": "2026-07-22",
"outbound_time_hours": 14,
"outbound_time_minutes": 30,
"outbound_selected_time_is_flight": 1,
"is_return": 0,
"adult_count": 2,
"luggage_count": 2,
"currency_code": "EUR",
"outbound_vehicle_type_id": 4,
"outbound_flight_number": "BA123",
"accommodation_id": 38959,
"additional_info": "Please call on arrival."
}' \
"https://booking.alps2alps.com/api/public/v1/checkout-link"
A stateless family of GET endpoints that lets simple AI agents and chat tools drive the booking flow with plain URLs — no POST needed, no DB row, no expiry. In most cases the quote_url and booking_url fields returned by GET /transfer-options are already constructed for you — the manual URL building below is for cases where you need full control over parameters or cannot make a prior API call.
The trade-off vs POST /checkout-link: deep links cannot carry an accommodation id, a flight number, or free-text driver notes (those require server-side validation). Use POST /checkout-link when you need those extras.
All three deep-link endpoints translate the same compact query-string aliases. The minimum viable URL is just from + to + date + time.
Outbound / shared:
| Alias | Canonical field | Default | Notes |
|---|---|---|---|
from | route_from_code | — | Required. e.g. airport-1 |
to | route_to_code | — | Required. e.g. resort-11 |
date | outbound_date | — | Required. YYYY-MM-DD |
time | outbound_time_hours + _minutes | — | Required. HH:MM. Interpreted as flight arrival time by default (is_flight=1). Set is_flight=0 for literal pickup time. |
is_flight | outbound_selected_time_is_flight | 1 | 1 = time is flight arrival, pickup calculated. 0 = time is literal pickup time. |
adults | adult_count | 2 | |
children | children_count | 0 | |
child_ages | — (GET only) | — | Comma-separated child ages, e.g. 8,12. Echoed in passengers.child_ages and preserved in generated URLs. Informational only. |
infants | infant_count | 0 | |
child_seats | children_age_seat_count | 0 | |
boosters | children_age_booster_count | 0 | |
luggage | luggage_count | 2 | |
ski_bags | skibag_count | 0 | |
ski | has_ski_equipment | 0 | |
currency | currency_code | EUR | Unknown/inactive codes return 400 CURRENCY_NOT_SUPPORTED on the JSON endpoints. The browser deep links (quick-search, quick-checkout) silently fall back to EUR so a stale value never breaks a user landing in the funnel. |
promo | promo_code | — | Same silent-on-failure behaviour as POST |
Return leg — any return_* parameter (or return=1) implicitly enables is_return=1. Omitted return fields auto-mirror the matching outbound value, so the simplest return URL is just …&return_date=…&return_time=…:
| Alias | Canonical field | Mirror default | Notes |
|---|---|---|---|
return_to | return_route_to_code | outbound from | |
return_date | return_date | — | |
return_time | return_time_hours + _minutes | — | Interpreted as flight departure time by default (return_is_flight=1). The calculated resort pickup will be earlier. Set return_is_flight=0 for literal resort pickup time. |
return_is_flight | return_selected_time_is_flight | outbound is_flight | 1 = return_time is the flight departure time, pickup calculated automatically. 0 = return_time is the literal resort pickup time. |
return_adults | return_adult_count | outbound adults | |
return_children | return_children_count | outbound children | |
return_child_ages | — (GET only) | outbound child_ages | Comma-separated child ages for the return leg. Preserved in generated URLs only. |
return_infants | return_infant_count | outbound infants | |
return_child_seats | return_children_age_seat_count | outbound child_seats | |
return_boosters | return_children_age_booster_count | outbound boosters | |
return_luggage | return_luggage_count | outbound luggage | |
return_ski_bags | return_skibag_count | outbound ski_bags | |
return_ski | return_has_ski_equipment | outbound ski |
Unknown query keys (e.g. utm_source=…) are silently ignored.
/api/public/v1/transfer-options (quote)Same response shape as the POST flavour. Returns JSON, never persists anything. The response includes quote_url and per-vehicle booking_url fields ready to use.
One-way:
curl "https://booking.alps2alps.com/api/public/v1/transfer-options?from=airport-1&to=resort-11&date=2026-07-22&time=14:30&adults=2&luggage=2¤cy=EUR"
→ Try it live: Geneva Airport → Chamonix, one-way
Return trip, 2 adults + 1 child + 3 bags — because return fields auto-mirror outbound, only return_date and return_time need to be added:
curl "https://booking.alps2alps.com/api/public/v1/transfer-options?from=airport-1&to=resort-11&date=2026-07-22&time=14:30&adults=2&children=1&luggage=3&return_date=2026-07-29&return_time=10:00"
→ Try it live: return trip, 2 adults + 1 child + 3 bags
/book/quick-search (land on step 2)Stateless deep link that lands the browser on step 2 of the booking funnel (vehicle selection) with prices already calculated. Equivalent to the quote_url returned by GET /transfer-options. Useful when you want to construct the link manually without a prior API call.
One-way:
Return trip, 2 adults + 1 child + 3 bags:
Failures (validation error, unsupported route, route not found, malformed date) redirect to /book/?step=1 so the user lands on the clean booking form — they never see an error page.
/book/quick-checkout (land on step 3)Stateless equivalent of POST /checkout-link. Lands the browser on step 3 (Your Details) with the funnel hydrated from the query string. Equivalent to the booking_url field on each vehicle in the GET /transfer-options response. The vehicle parameter pre-picks the vehicle type.
One-way, pre-picked vehicle:
Return trip, 2 adults + 1 child + 3 bags, pre-picked vehicle:
Additional quick-checkout parameters:
| Alias | Notes |
|---|---|
vehicle | Outbound vehicle_type_id from /transfer-options. If omitted, the funnel auto-picks the cheapest vehicle. |
return_vehicle | Return leg vehicle type. Defaults to vehicle for return trips. |
accommodation_id, flight numbers, and driver notes are not supported on the GET flow. UsePOST /checkout-linkfor those.
| Need | Use |
|---|---|
| JSON-only, full control, machine-to-machine | POST /api/public/v1/transfer-options |
| Quote in a URL (chat, email, blog) | GET /api/public/v1/transfer-options |
Hand user to vehicle picker (step 2) — use the ready-made quote_url from the response, or build manually | GET /book/quick-search |
Hand user to step 3 with a pre-picked vehicle — use the ready-made booking_url from the response, or build manually | GET /book/quick-checkout |
| Hand user to step 3 with accommodation / driver notes / flight numbers / 24h-expiring link | POST /api/public/v1/checkout-link |
All errors share the same JSON envelope:
{ "error": { "code": "UNSUPPORTED_ROUTE", "message": "The routes from station to station is not supported" } }
| HTTP | Code | When |
|---|---|---|
| 400 | INVALID_PARAMS | Missing or invalid request fields, malformed dates, or validation failures. |
| 400 | CURRENCY_NOT_SUPPORTED | Unknown or inactive currency code on a JSON endpoint (GET or POST). |
| 400 | VALIDATION_ERROR | accommodation_id not found, not in range, or not applicable to this route. |
| 404 | RESORT_NOT_FOUND | /accommodations could not resolve the resort. |
| 404 | ROUTE_NOT_FOUND | Location code combination does not map to an active route. |
| 422 | UNSUPPORTED_ROUTE | Funnel rejects this destination-type combination (e.g. station-to-station). |
| 422 | MANUAL_BOOKING_REQUIRED | Route requires manual handling; not bookable online. |
| 422 | NO_BOOKABLE_VEHICLE | No vehicle had a usable price on this route. |
| 429 | RATE_LIMITED | Per-IP request limit exceeded. Back off and retry with exponential backoff. |
| 500 | INTERNAL_ERROR | Catch-all for all other unhandled exceptions. |
The API requires no authentication and is rate limited per client IP. When the limit is exceeded the API returns HTTP 429 with the standard error envelope:
{ "error": { "code": "RATE_LIMITED", "message": "Too many requests. Please slow down and retry." } }
locations/search → transfer-options → optionally checkout-link. The pricing endpoints have a lower allowance than the lookup endpoints.429, back off and retry with exponential backoff rather than retrying immediately.Exact per-minute numbers are intentionally not published so they can be tuned without changing the contract. Treat 429 as “slow down”, not a permanent failure.
Pass any active ISO 4217 currency code in currency_code (POST) or currency (GET alias) — e.g. EUR, GBP, CHF, USD. The default is EUR.
GET and POST /transfer-options, POST /checkout-link) — an unknown or inactive currency code returns 400 CURRENCY_NOT_SUPPORTED. Agents calling these endpoints should handle that error rather than assuming an EUR fallback./book/quick-search, /book/quick-checkout) — an invalid currency= value silently falls back to EUR so a stale parameter never breaks a user landing in the funnel.For non-EUR responses the disclaimer field in /transfer-options notes that the exact checkout total may shift slightly due to live FX rates (sourced from the ECB, same as the booking website).
Pass promo_code (POST) or promo (GET alias) on either /transfer-options or /checkout-link. The code is validated server-side. If validation fails or the promo service is temporarily unreachable, the code is silently ignored and promo_code_applied returns false — the request itself still succeeds.
When a code is submitted but not applied, the response includes promo_code (echo of the submitted code) and promo_code_message explaining why it was not applied (for example, the code is expired or not valid for the chosen route). promo_code_applied remains false. The response itself still succeeds — prices are returned at full rate.
When a promo is applied on /transfer-options, the response includes promo_code_discount with a type (e.g. "percent") and value. See the Response section above for both promo code scenarios.
The API is browser-callable with no additional configuration:
Access-Control-Allow-Origin: *Access-Control-Allow-Headers: Content-Type, AcceptAccess-Control-Allow-Methods: GET, POST, OPTIONSOPTIONS preflight returns HTTP 204 with no body.