Home / Developers / Alps2Alps Public API — Developer Documentation

Alps2Alps Public API — Developer Documentation

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.

Base URL: https://booking.alps2alps.com/api/public/v1/
The full OpenAPI 3.1 spec is available at 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).

TL;DR for AI agents

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):

  1. GET /api/public/v1/locations/search?q=Geneva → resolve names to codes (airport-1, resort-11, train_station-7, city-48).
  2. 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_type_id.
  3. Hand the user one of:

If you can POST, use POST /api/public/v1/checkout-link instead of quick-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=….

Machine-readable discovery

Everything you need to integrate is linked from these discovery files:

  1. Search locations — call /locations/search to resolve the user’s pickup and drop-off names into airport-… / resort-… / city-… codes.
  2. (Optional) Search accommodations — call /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.
  3. Quote the trip — call /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.
  4. Generate a checkout link — once the user confirms a vehicle, call /checkout-link with the same body plus any optional extras (vehicle type id, flight number, accommodation id, driver notes).
  5. Hand the URL to the user — the returned 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.

Lightweight agents (no POST capability)

For chat agents that can only fetch URLs, the same end-to-end flow is possible without ever issuing a POST:

  1. (Optional) GET /locations/search?q=… to resolve names to codes.
  2. GET /api/public/v1/transfer-options?from=…&to=…&date=…&time=…&adults=… to fetch live prices.
  3. Hand the user either:

See the Deep links section below for the full alias reference and a POST vs GET decision matrix.


Endpoints

Search for supported pickup and drop-off locations: resorts, airports, train stations, and cities.

Query parameters

ParameterRequiredNotes
qYesSearch term. Strings shorter than 2 characters return an empty array.

Response

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" }
]

Errors

  • 400 INVALID_PARAMSq parameter missing entirely.

Example

curl "https://booking.alps2alps.com/api/public/v1/locations/search?q=cham"

2. GET /api/public/v1/accommodations

Read-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.

Query parameters

ParameterRequiredDéfautNotes
resort_idYesNumeric resort id from a resort-{id} location code.
qNon""Substring filter on name (accent-insensitive). Max 100 chars.
limitNon20Hard-capped at 50.

Response

{
  "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 id values returned by this endpoint may be passed into /checkout-link as accommodation_id. Free-typed hotel names are not accepted, ensuring every order receives a verified name and address pair.

Errors

  • 400 INVALID_PARAMSresort_id missing or not an integer.
  • 404 RESORT_NOT_FOUND — resort id is unknown, inactive, or has no coordinates.

Example

curl "https://booking.alps2alps.com/api/public/v1/accommodations?resort_id=11&q=clos&limit=5"

3. GET / POST /api/public/v1/transfer-options

Returns 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:

  • POST — canonical JSON body using book\forms\Transfer field names. Recommended for programmatic clients with full control over headers and body.
  • GET — friendly-alias query string (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.

Request body (POST)

Accepts application/json or application/x-www-form-urlencoded.

ChampTypeRequiredNotes
route_from_codestringYese.g. airport-1
route_to_codestringYese.g. resort-11
outbound_datestringYesYYYY-MM-DD
outbound_time_hoursintYes0–23
outbound_time_minutesintYes0–59
outbound_selected_time_is_flightint (0/1)Non1 = the time given is a flight arrival time
is_returnint (0/1)No (default 0)When 1, all return_* fields are required
adult_countintYes≥ 1
children_countintNon
infant_countintNon
children_age_seat_countintNonNumber of child-seat-aged children
children_age_booster_countintNonNumber of booster-seat-aged children
luggage_countintNon
skibag_countintNon
has_ski_equipmentint (0/1)Non
currency_codestringNo (default EUR)ISO 4217 currency code
promo_codestringNonSilently 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.

GET examples

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"

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"

Response

{
  "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 }

Errors

  • 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.

POST example

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"

Accepts 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.

Additional body fields

ChampTypeNotes
outbound_vehicle_type_idintOptional. Defaults to the cheapest available outbound vehicle.
return_vehicle_type_idintOptional. Only used when is_return = 1.
outbound_flight_numberstringOptional. Alphanumeric + hyphen, max 16 chars.
return_flight_numberstringOptional. Only used when is_return = 1.
accommodation_idintOptional. Must be an id returned by /accommodations and within 10 km of the route’s resort.
additional_infostringOptional. Free-text driver note. Max 1000 chars.
return_additional_infostringOptional. Driver note for the return leg. Only used when is_return = 1.

Response

{
  "checkout_url": "https://alps2alps.com/book/public-checkout/8f1c2c…",
  "expires_at":   "2026-05-28 09:14:22",
  "currency":     "EUR",
  "promo_code_applied": true
}

Errors

All errors from /transfer-options, plus:

  • 400 INVALID_PARAMSaccommodation_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.

Example

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.

Friendly alias → canonical field mapping

All three deep-link endpoints translate the same compact query-string aliases. The minimum viable URL is just from + to + date + time.

Outbound / shared:

AliasCanonical fieldDéfautNotes
fromroute_from_codeRequired. e.g. airport-1
toroute_to_codeRequired. e.g. resort-11
dateoutbound_dateRequired. YYYY-MM-DD
timeoutbound_time_hours + _minutesRequired. HH:MM (also accepts HHMM or H)
is_flightoutbound_selected_time_is_flight1Mirrors the website landing form
adultsadult_count2
childrenchildren_count0
infantsinfant_count0
child_seatschildren_age_seat_count0
boosterschildren_age_booster_count0
luggageluggage_count2
ski_bagsskibag_count0
skihas_ski_equipment0
currencycurrency_codeEURInvalid codes silently fall back to EUR on the quick-* routes
promopromo_codeSame 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=…:

AliasCanonical fieldMirror default
return_toreturn_route_to_codeoutbound from
return_datereturn_date
return_timereturn_time_hours + _minutes
return_is_flightreturn_selected_time_is_flightoutbound is_flight
return_adultsreturn_adult_countoutbound adults
return_childrenreturn_children_countoutbound children
return_infantsreturn_infant_countoutbound infants
return_child_seatsreturn_children_age_seat_countoutbound child_seats
return_boostersreturn_children_age_booster_countoutbound boosters
return_luggagereturn_luggage_countoutbound luggage
return_ski_bagsreturn_skibag_countoutbound ski_bags
return_skireturn_has_ski_equipmentoutbound ski

Unknown query keys (e.g. utm_source=…) are silently ignored.

3a. GET /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&currency=EUR"

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"

3b. GET /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.

3c. GET /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:

AliasNotes
vehicleSortie vehicle_type_id from /transfer-options. If omitted, the funnel auto-picks the cheapest vehicle.
return_vehicleReturn leg vehicle type. Defaults to vehicle for return trips.

accommodation_id, flight numbers, and driver notes are not supported on the GET flow. Use POST /checkout-link for those.

POST vs GET — which to use

NeedUse
JSON-only, full control, machine-to-machinePOST /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 vehicleGET /book/quick-checkout
Hand user to step 3 with accommodation / driver notes / flight numbers / 24h-expiring linkPOST /api/public/v1/checkout-link

Error envelope & error codes

All errors share the same JSON envelope:

{ "error": { "code": "UNSUPPORTED_ROUTE", "message": "The routes from station to station is not supported" } }
HTTPCodeWhen
400INVALID_PARAMSMissing or invalid request fields, malformed dates, or validation failures.
400CURRENCY_NOT_SUPPORTEDCurrency not in the active currency list.
400VALIDATION_ERRORaccommodation_id not found, not in range, or not applicable to this route.
404RESORT_NOT_FOUND/accommodations could not resolve the resort.
404ROUTE_NOT_FOUNDLocation code combination does not map to an active route.
422UNSUPPORTED_ROUTEFunnel rejects this destination-type combination (e.g. station-to-station).
422MANUAL_BOOKING_REQUIREDRoute requires manual handling; not bookable online.
422NO_BOOKABLE_VEHICLENo vehicle had a usable price on this route.
500INTERNAL_ERRORCatch-all for all other unhandled exceptions.

Currencies

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).


Promo codes

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.


CORS & HTTP methods

The API is browser-callable with no additional configuration:

  • Access-Control-Allow-Origin: *
  • Access-Control-Allow-Headers: Content-Type, Accept
  • Access-Control-Allow-Methods: GET, POST, OPTIONS
  • OPTIONS preflight returns HTTP 204 with no body.
  • CSRF validation is disabled on all public API endpoints.