Creating a Reservation
Once the price and vacancy of the trip selected by the user is confirmed (and seats/ancillaries have been added to the basket) the next step is to call the /reservations/create endpoint to create a reservation.
A reservation is a temporary block of a place on the ride that ensures seat availability at the moment of purchase (confirmation). Reservations hold for 10 minutes in general, and, if not confirmed will be automatically cancelled.
It is important to note that even if you have implemented the reservations workflow, your integration will still work with carriers that do not support reservations in their own system. The flow will work in a standardised way in the API, while the reservation itself is simulated.
Reservations are a helpful tool to ensure that the customer retains their booking and seat throughout the checkout process. Without a reservation, it is possible that while the user is buying their ticket their bus or seat could be booked out, resulting in the user losing their trip.
Important Update for Existing Partners: The payload for /reservations/create has been significantly simplified under our new Offers API flow. You no longer need to send redundant trip details (carrier, stations, fare classes) in the root of the payload; you now simply pass the verified offer_id and passenger mapping. For information about our new flow please check the New Offers Flow Explained guide for a step-by-step walkthrough of the changes.
Making a Reservation Request
In principle the reservation request can be simply requested by using the offer_id as the minimum required field. This id includes all the information about the connection, fare, passenger, currency constellation for the further flow.
{
"offers": [
{
"id": "a6e62c29-7141-48f1-af5f-0e829f69e5a1|0"
}
]
}
Note that most carriers require passenger details only in the /reservations/confirm request, but there are a few that require some details to be included as part of the /reservations/create request. This information is available from the /connections/vacancy endpoint. For more details check our Dynamic Passenger Fields guide.
When these are required by the carrier for the /reservations/create request, you must include these details in your request.
{
"email": "john.smith@email.com",
"offers": [
{
"id": "a6e62c29-7141-48f1-af5f-0e829f69e5a1|0"
}
],
"passengers": [
{
"type": "PNOS",
"id": "pax-33-1",
"first_name": "John",
"last_name": "Smith",
"birthdate": "1997-10-22"
},
{
"type": "PNOS",
"id": "pax-11-2",
"first_name": "Ana",
"last_name": "Smith",
"birthdate": "1997-10-22"
}
]
}
Defining Passenger Type
When searching for trips you can include the exact age of each passenger. However, in the request to create a reservation you must match the age of the passenger to the passenger type as defined by the carrier and included the passenger ID, the same way as done with the /connections/vacancy request. To understand more about it check our Passenger Type guide.
Return Trips
In the case of a return trip, please add the offer_id 's from the offers selected for each bound. This means that the /reservations/create request will include two offer_id values for a return journey.
Adding Seats
When creating a reservation, you can include specific seat selections for your passengers by adding a seat_selections array to your request. Seats can either be included in the main standalone offer for free, or they can come with a fee requiring a separate add-on offer . For each seat, you must provide the segment_id, the passenger_id, and the exact seat_id retrieved from the availability response. For full request payloads and detailed instructions on both free and paid seat scenarios, please refer to our comprehensive guide on Selecting Seats.
Reading Expiration Time
The typical reservation duration is set at 10 minutes, however some carriers can hold it for a few hours or even days (such as SNCF). The expires_at parameter indicates until when a certain reservation is valid and can be confirmed.
Some carriers do not support the reservation flow in their own system. While the API workflow works in exactly the same way, the response shows the value expires_at = null . This means that in reality, the availability and seats are not reserved in the carrier's system and in this scenario we recommend to set the value to 10 minutes to match the default of most carriers to keep the flow consistent to the user.
Best Practices
- Cancel the reservation when the user aborts the flow: If the checkout is aborted by the user by clicking on a cancel button or by moving back to the search results page, it is recommended to cancel the reservation to avoid blocking seats. This can be done from the /reservation/cancel endpoint.
- Read the price from the response: It is important to read the price from the /reservations/create response and display the value to the user in the the following steps, to ensure the user is presented with the most updated price for the trip.
- Read the list of required booking fields: Read the info in the /connections/vacancy response and check our Dynamic Passenger Fields guide. We recommend that you store this data to dynamically show the required fields when creating a reservation.
Enterprise Features
Before a reservation is created you can allow users to book additional ancillaries. For more details, check our guide on Ancillaries.
If any discount cards are applied as part of the flow, they can be added to the /reservations/create request and will affect the price that appears in the response. The details of the cards applied also appear in the response. For more details, check our guide on Discount Cards.
Next Step
If the reservation is created successfully, the user can proceed to the checkout page to complete their details and payment, where the reservation can be confirmed.
API Examples
Sample Request to /reservations/create
{
"email": "john.smith@email.com",
"offers": [
{
"id": "a6e62c29-7141-48f1-af5f-0e829f69e5a1|0"
}
],
"passengers": [
{
"type": "PNOS",
"id": "pax-33-1",
"first_name": "John",
"last_name": "Smith",
"birthdate": "1997-10-22"
},
{
"type": "PNOS",
"id": "pax-11-2",
"first_name": "Ana",
"last_name": "Smith",
"birthdate": "1997-10-22"
}
]
}
Sample Response from /reservations/create
{
"data": {
"id": "RBA643P7",
"type": "reservations",
"attributes": {
"total_price": 9200,
"original_price": 9200,
"state": "created",
"created_at": "2025-11-28T16:55",
"confirmed_at": null,
"cancelled_at": null,
"failed_at": null,
"processing_started_at": null,
"processing_deadline": null,
"expires_at": "2025-11-28T18:25",
"terms_version": null,
"title": null,
"first_name": null,
"last_name": null,
"email": "john.smith@email.com",
"phone": null,
"city": null,
"zip_code": null,
"country_code": null,
"street_and_number": null,
"gender": null,
"country_of_birth": null,
"government_id_type": null,
"marketing_carrier_reservation_ids": [
"CS3MGX_Smith_JCBRXV"
],
"agent_id": null,
"retailer_booking_number": null,
"customer_id": null
},
"relationships": {
"fare_class": {
"data": {
"id": "SNCF-FARE-4",
"type": "fare_classes"
}
},
"return_fare_class": {
"data": null
},
"departure_station": {
"data": {
"id": "FRLYSLYN",
"type": "stations"
}
},
"arrival_station": {
"data": {
"id": "FRPARPRG",
"type": "stations"
}
},
"marketing_carrier": {
"data": {
"id": "SNCF",
"type": "marketing_carriers"
}
},
"booking": {
"data": null
},
"utm_params": {
"data": null
},
"errors": {
"data": []
},
"segments": {
"data": [
{
"id": "STIO-FRLYSLYN-FRPARPRG-2025-11-30T10:04-2025-11-30T12:09-0",
"type": "segments"
}
]
},
"reservation_passengers": {
"data": [
{
"id": "R-PNOS-1-STIO-FRLYSLYN-FRPARPRG-2025-11-30T10:04-2025-11-30T12:09",
"type": "reservation_passengers"
},
{
"id": "R-PNOS-2-STIO-FRLYSLYN-FRPARPRG-2025-11-30T10:04-2025-11-30T12:09",
"type": "reservation_passengers"
}
]
},
"applied_cards": {
"data": []
},
"ancillaries": {
"data": []
},
"required_attributes": {
"data": [
{
"id": "RBA643P7-87feeb31-4f5c-48c6-8eb1-015aeb7f94cf",
"type": "required_attributes"
}
]
},
"custom_fields": {
"data": []
},
"fees": {
"data": []
}
}
},
"jsonapi": {
"version": "1.0"
},
"meta": {
"currency": "EUR",
"locale": "en"
},
"included": [
{
"id": "STIO-FRLYSLYN-FRPARPRG-2025-11-30T10:04-2025-11-30T12:09-0",
"type": "segments",
"attributes": {
"departure_time": "2025-11-30T10:04",
"arrival_time": "2025-11-30T12:09",
"line": "6612",
"line_prefix": "TGV INOUI"
},
"relationships": {
"departure_station": {
"data": {
"id": "FRLYSLYN",
"type": "stations"
}
},
"arrival_station": {
"data": {
"id": "FRPARPRG",
"type": "stations"
}
},
"marketing_carrier": {
"data": {
"id": "SNCF",
"type": "marketing_carriers"
}
},
"segment_passengers": {
"data": [
{
"id": "PNOS-1-STIO-FRLYSLYN-FRPARPRG-2025-11-30T10:04-2025-11-30T12:09-0",
"type": "segment_passengers"
},
{
"id": "PNOS-2-STIO-FRLYSLYN-FRPARPRG-2025-11-30T10:04-2025-11-30T12:09-0",
"type": "segment_passengers"
}
]
}
}
},
{
"id": "FRLYSLYN",
"type": "stations",
"attributes": {
"code": "FRLYSLYN",
"name": "Lyon Part Dieu Train Station"
}
},
{
"id": "FRPARPRG",
"type": "stations",
"attributes": {
"code": "FRPARPRG",
"name": "Paris Gare de Lyon Hall 1 & 2 Train Station"
}
},
{
"id": "SNCF",
"type": "marketing_carriers",
"attributes": {
"code": "SNCF",
"trade_name": "SNCF",
"legal_name": "SNCF"
}
},
{
"id": "PNOS-1-STIO-FRLYSLYN-FRPARPRG-2025-11-30T10:04-2025-11-30T12:09-0",
"type": "segment_passengers",
"attributes": {
"seat_number": null
},
"relationships": {
"ancillaries": {
"data": []
}
}
},
{
"id": "PNOS-2-STIO-FRLYSLYN-FRPARPRG-2025-11-30T10:04-2025-11-30T12:09-0",
"type": "segment_passengers",
"attributes": {
"seat_number": null
},
"relationships": {
"ancillaries": {
"data": []
}
}
},
{
"id": "R-PNOS-1-STIO-FRLYSLYN-FRPARPRG-2025-11-30T10:04-2025-11-30T12:09",
"type": "reservation_passengers",
"attributes": {
"first_name": "John",
"last_name": "Smith",
"serial_code": null,
"government_id_type": null,
"nationality": null,
"gender": null,
"country_of_birth": null,
"birthdate": "1997-10-22",
"type": "PNOS"
},
"relationships": {
"required_attributes": {
"data": [
{
"id": "R-PNOS-1-STIO-FRLYSLYN-FRPARPRG-2025-11-30T10:04-2025-11-30T12:09-b7b9af64-97d6-462d-955f-4db4d43cce92",
"type": "passenger_required_attributes"
}
]
}
}
},
{
"id": "R-PNOS-2-STIO-FRLYSLYN-FRPARPRG-2025-11-30T10:04-2025-11-30T12:09",
"type": "reservation_passengers",
"attributes": {
"first_name": "Ana",
"last_name": "Smith",
"serial_code": null,
"government_id_type": null,
"nationality": null,
"gender": null,
"country_of_birth": null,
"birthdate": "1997-10-22",
"type": "PNOS"
},
"relationships": {
"required_attributes": {
"data": [
{
"id": "R-PNOS-2-STIO-FRLYSLYN-FRPARPRG-2025-11-30T10:04-2025-11-30T12:09-01cb517c-79de-4d6e-8df8-32cd01f7a48b",
"type": "passenger_required_attributes"
}
]
}
}
},
{
"id": "R-PNOS-1-STIO-FRLYSLYN-FRPARPRG-2025-11-30T10:04-2025-11-30T12:09-b7b9af64-97d6-462d-955f-4db4d43cce92",
"type": "passenger_required_attributes",
"attributes": {
"mandatory": [
"birthdate",
"first_name",
"last_name"
],
"endpoint": "reservations/confirm"
}
},
{
"id": "R-PNOS-2-STIO-FRLYSLYN-FRPARPRG-2025-11-30T10:04-2025-11-30T12:09-01cb517c-79de-4d6e-8df8-32cd01f7a48b",
"type": "passenger_required_attributes",
"attributes": {
"mandatory": [
"birthdate",
"first_name",
"last_name"
],
"endpoint": "reservations/confirm"
}
},
{
"id": "SNCF-FARE-4",
"type": "fare_classes",
"attributes": {
"code": "FARE-4",
"name": "Second Class - Cheapest"
}
},
{
"id": "RBA643P7-87feeb31-4f5c-48c6-8eb1-015aeb7f94cf",
"type": "required_attributes",
"attributes": {
"mandatory": [
"email",
"first_name",
"last_name",
"terms_accepted"
],
"endpoint": "reservations/confirm"
}
}
]
}
On this page
- Creating a Reservation