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 pervehicle_type_id.- Hand the user one of:
GET /book/quick-search?from=airport-1&to=resort-11&date=2026-07-22&time=14:30— lands on step 2 (vehicle picker).GET /book/quick-checkout?…&vehicle=<vehicle_type_id>— lands on step 3 with the chosen vehicle pre-selected.If you can POST, use
POST /api/public/v1/checkout-linkinstead ofquick-checkout— that flow can additionally pre-fill accommodation, flight numbers, and free-text driver notes, and 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./locations/search to resolve the user’s pickup and drop-off names into airport-… / resort-… / city-… codes./accommodations?resort_id=… once the resort side is known so the user can confirm a specific hotel. Always confirm the chosen entry with the user before sending its id./transfer-options with the location codes plus passenger, luggage, and date inputs. Present prices, vehicle types, travel time, and any promo discount to the user./checkout-link with the same body plus any optional extras (vehicle type id, flight number, accommodation id, driver notes).checkout_url is valid for 24 hours. Opening it lands the user on booking step 3 (Your Details) with all fields pre-filled. They only need to enter contact details and complete payment.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.GET /book/quick-search?… to land them on step 2 (vehicle picker), orGET /book/quick-checkout?…&vehicle=… to land them straight on step 3 with the vehicle pre-picked.See the Deep links section below for the full alias reference and a POST vs GET decision matrix.
/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/accommodationsRead-only access to the verified accommodation catalogue used by the booking funnel’s hotel autocomplete. Results are scoped to a 10 km radius around the supplied resort.
| Parameter | Required | Défaut | Notes |
|---|---|---|---|
resort_id | Yes | — | Numeric resort id from a resort-{id} location code. |
q | Non | "" | Substring filter on name (accent-insensitive). Max 100 chars. |
limit | Non | 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.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&limit=5"
→ Try it live: accommodations 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.Accepts application/json or application/x-www-form-urlencoded.
| Champ | 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) | Non | 1 = the time given is a flight arrival time |
is_return | int (0/1) | No (default 0) | When 1, all return_* fields are required |
adult_count | int | Yes | ≥ 1 |
children_count | int | Non | |
infant_count | int | Non | |
children_age_seat_count | int | Non | Number of child-seat-aged children |
children_age_booster_count | int | Non | Number of booster-seat-aged children |
luggage_count | int | Non | |
skibag_count | int | Non | |
has_ski_equipment | int (0/1) | Non | |
currency_code | string | No (default EUR) | ISO 4217 currency code |
promo_code | string | Non | 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, 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.
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
{
"disclaimer": "Prices shown are real-time and calculated using the same engine as the booking website.",
"route": {
"from": "Geneva Airport",
"to": "Chamonix",
"distance_km": 99,
"duration_minutes": 100,
"travel_time": "01:40:00"
},
"currency": "EUR",
"outbound": {
"pick_up_date_time": "2026-07-22 14:30:00",
"vehicles": [
{ "vehicle_type_id": 2, "name": "Standard/economy", "price": 175, "offer_code": "requested" },
{ "vehicle_type_id": 10, "name": "Standard minivan", "price": 247, "offer_code": "requested" },
{ "vehicle_type_id": 4, "name": "VIP", "price": 418.50, "offer_code": "requested" }
]
},
"return": null,
"promo_code_applied": false
}
When a valid promo is applied, the response also includes:
"promo_code_discount": { "type": "percent", "value": 5 }
400 INVALID_PARAMS — body empty, validation failure, or malformed date.400 CURRENCY_NOT_SUPPORTED — currency not in the active currency list.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.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 heures. Opening the URL lands the user on booking step 3 (Your Details) with all fields pre-filled — they only need to enter contact details and pay.
| Champ | 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.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. 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 and are impractical in a URL). Use deep links for quick lookups and lightweight handoffs; use POST /checkout-link when you need accommodation pre-fill, flight numbers, driver notes, or a 24h-expiring stamped link.
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 | Défaut | 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 (also accepts HHMM or H) |
is_flight | outbound_selected_time_is_flight | 1 | Mirrors the website landing form |
adults | adult_count | 2 | |
children | children_count | 0 | |
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 | Invalid codes silently fall back to EUR on the quick-* routes |
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 |
|---|---|---|
return_to | return_route_to_code | outbound from |
return_date | return_date | — |
return_time | return_time_hours + _minutes | — |
return_is_flight | return_selected_time_is_flight | outbound is_flight |
return_adults | return_adult_count | outbound adults |
return_children | return_children_count | outbound children |
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.
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 et 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. Useful for handing the user off into the normal funnel once the agent has resolved the route and date inputs.
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. 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 | Sortie 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) | GET /book/quick-search |
| Hand user to step 3 with a pre-picked vehicle | 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 | Currency not in the active currency list. |
| 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. |
| 500 | INTERNAL_ERROR | Catch-all for all other unhandled exceptions. |
Pass any active ISO 4217 currency code in currency_code (POST) or currency (GET aliases) — e.g. EUR, GBP, CHF, USD. The default is EUR. Invalid codes on the quick-* GET routes silently fall back to EUR.
For non-EUR responses the disclaimer field in /transfer-options is extended to note 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 et promo_code_applied returns false — the request itself still succeeds. The caller can retry or surface the unapplied state to the user.
When a promo is applied on /transfer-options, the response includes promo_code_discount with a type (e.g. "percent") and value.
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.