Booking Tickets

This guide covers the complete booking process, from creating a booking to receiving confirmed tickets.

Understanding the Booking Lifecycle

The booking process includes these stages:

  1. Booking: A temporary reservation that holds your selected offers. Bookings expire if not converted to orders within a set time (check the expiresAt field).

  2. Order: The confirmed purchase. Creating an order pre-books the tickets with the train operator. At this point, tickets are reserved but not yet issued.

  3. Finalized Order: Completes the purchase and triggers ticket issuance. After finalization, tickets are automatically generated.

  4. Tickets Issued: Digital tickets become available for download. This usually happens within 15 minutes of finalization.

Creating a Booking

Start by creating a booking from a journey offer. This reserves the journey but doesn't confirm it yet. You'll add passenger details and select specific offers next.

Example: Create a booking
graphql
mutation CreateBooking {
  createBooking(journeyOffer: "7a341862-5c91-4cbc-82f1-010c8bd7e7e8") {
    id
    passengers {
      id
      age
      type
    }
    requirements {
      passportNumber
      dateOfBirth
      nationality
      email
      tel
    }
    selections {
      ... on JourneyOfferSelection {
        offers {
          ...OfferFragment
        }
        journey {
          ... on JourneySelection {
            itinerary {
              ... on Stopover {
                location {
                  name
                }
              }
              ... on SegmentCollection {
                status
                segments {
                  departureAt
                  arrivalAt
                  origin {
                    name
                  }
                  destination {
                    name
                  }
                }
                offers {
                  ...OfferFragment
                }
              }
            }
          }
        }
      }
    }
  }
}

fragment OfferFragment on Offer {
  id
  price {
    amount
    currency
  }
  parts {
    ... on AdmissionPart {
      conditions {
        description
        type
      }
      flexibility
      serviceClass
      comfortClass
    }
    ... on ReservationPart {
      conditions {
        description
        type
      }
      flexibility
      comfortClass
      accommodation {
        type
      }
    }
  }
}
mutation CreateBooking {
  createBooking(journeyOffer: "cb860c0d-cac4-48c2-91c9-dce0fc54a868") {
    id
    passengers {
      id
      age
      type
    }
    requirements {
      passportNumber
      dateOfBirth
      nationality
      email
      tel
    }
    selections {
      ... on JourneyOfferSelection {
        offers {
          ...OfferFragment
        }
        journey {
          ... on JourneySelection {
            itinerary {
              ... on Stopover {
                location {
                  name
                }
              }
              ... on SegmentCollection {
                status
                segments {
                  departureAt
                  arrivalAt
                  origin {
                    name
                  }
                  destination {
                    name
                  }
                }
                offers {
                  ...OfferFragment
                }
              }
            }
          }
        }
      }
    }
  }
}

fragment OfferFragment on Offer {
  id
  price {
    amount
    currency
  }
  parts {
    ... on AdmissionPart {
      conditions {
        description
        type
      }
      flexibility
      serviceClass
      comfortClass
    }
    ... on ReservationPart {
      conditions {
        description
        type
      }
      flexibility
      comfortClass
      accommodation {
        type
      }
    }
  }
}

The booking includes requirements that tell you what passenger information is needed. Different train operators require different details. Some need passport numbers, others just names and dates of birth.

Booking expiration

Bookings expire if not converted to orders. Check the expiresAt field to see how long you have.

Adding Passenger Details

Before you can create an order, you must provide all required passenger information. The booking's requirements field tells you exactly what's needed.

One passenger must be marked as the contact person (isContactPerson: true). This person receives booking confirmations and is contacted if there are issues. The contact person must provide both email and phone number.

Example: Update passenger details
graphql
mutation UpdatePassengers {
  updateBooking(
    id: "503776b6-3d98-4903-adab-1b5ba9f64e80"
    passengers: [
      {
        id: "b9ddd550-1970-45c7-8cab-52d0c89a89ac"
        email: "jane.doe@example.com"
        isContactPerson: true
        birthDate: "1980-02-15"
        nationality: "NL"
        firstName: "Jane"
        lastName: "Doe"
        title: MS
      }
    ]
  ) {
    id
    passengers {
      ... on FullPassenger {
        id
        isContactPerson
        email
        birthDate
        nationality
        firstName
        lastName
        title
      }
    }
  }
}
mutation UpdatePassengers {
  updateBooking(
    id: "503776b6-3d98-4903-adab-1b5ba9f64e80"
    passengers: [
      {
        id: "b9ddd550-1970-45c7-8cab-52d0c89a89ac"
        email: "jane.doe@example.com"
        isContactPerson: true
        birthDate: "1980-02-15"
        nationality: "NL"
        firstName: "Jane"
        lastName: "Doe"
        title: MS
      }
    ]
  ) {
    id
    passengers {
      ... on FullPassenger {
        id
        isContactPerson
        email
        birthDate
        nationality
        firstName
        lastName
        title
      }
    }
  }
}

Selecting Offers

When you create a booking, the API automatically selects default offers (usually the most affordable options). You can change these selections if you want different fare types or service levels.

Each journey segment has multiple offers available. Update the booking (updateBooking) to select the offers you want:

Example: Select specific offers
graphql
mutation SelectOffer {
  updateBooking(
    id: "503776b6-3d98-4903-adab-1b5ba9f64e80"
    selections: [{ offer: { id: "7057ab29-2656-48b1-91c4-77e75ebd2849" } }]
  ) {
    selections {
      ... on JourneyOfferSelection {
        offers {
          id
          price {
            amount
            currency
          }
          parts {
            ... on AdmissionPart {
              flexibility
              serviceClass
              comfortClass
            }
            ... on ReservationPart {
              flexibility
              comfortClass
              accommodation {
                type
              }
            }
          }
        }
      }
    }
  }
}
mutation SelectOffer {
  updateBooking(
    id: "503776b6-3d98-4903-adab-1b5ba9f64e80"
    selections: [{ offer: { id: "b61af44a-1a04-4956-b84a-ec6c9116ade7" } }]
  ) {
    selections {
      ... on JourneyOfferSelection {
        offers {
          id
          price {
            amount
            currency
          }
          parts {
            ... on AdmissionPart {
              flexibility
              serviceClass
              comfortClass
            }
            ... on ReservationPart {
              flexibility
              comfortClass
              accommodation {
                type
              }
            }
          }
        }
      }
    }
  }
}

Selecting Seat Preferences

Some offers include place properties: options for seat preferences, sleeping accommodations, or special requirements. These might include:

  • Window or aisle seat preference
  • Upper or lower berth (for night trains)
  • Special meal requirements
  • Accessibility needs

Some place properties are required (you must select an option), while others are optional. Check the required field to see which ones you need to set. Use updatePart to set place properties.

Example: Select seat preferences
graphql
query GetBooking {
  node(id: "503776b6-3d98-4903-adab-1b5ba9f64e80") {
    ... on Booking {
      selections {
        ... on JourneyOfferSelection {
          offers {
            parts {
              ... on ReservationPart {
                id
                placeProperties {
                  id
                  type
                  required
                  availableOptions {
                    id
                    value
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
query GetBooking {
  node(id: "503776b6-3d98-4903-adab-1b5ba9f64e80") {
    ... on Booking {
      selections {
        ... on JourneyOfferSelection {
          offers {
            parts {
              ... on ReservationPart {
                id
                placeProperties {
                  id
                  type
                  required
                  availableOptions {
                    id
                    value
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
graphql
mutation UpdatePart {
  updatePart(
    id: "e62d06a7-30d7-4806-83b2-a41183b9a923"
    booking: "503776b6-3d98-4903-adab-1b5ba9f64e80"
    placeProperties: [{
      propertyId: "cc3f7817-a919-484d-a6d3-4df3a519be11",
      optionId: "6b7c4e88-d72a-4fd7-be2d-d26513bdc5e8"
    }]
  ) {
    selections {
      ... on JourneyOfferSelection {
        offers {
          parts {
            ... on ReservationPart {
              id
              placeProperties {
                selectedOption {
                  id
                  value
                }
              }
            }
          }
        }
      }
    }
  }
}
mutation UpdatePart {
  updatePart(
    id: "f2588b13-0ea1-42cc-993c-6491f33181e6"
    booking: "503776b6-3d98-4903-adab-1b5ba9f64e80"
    placeProperties: [{
      propertyId: "380a14b9-1a2d-4f31-abd4-6bd6c5399b56",
      optionId: "79a97e8f-0f06-4d6c-80ad-ef95e96ceb53"
    }]
  ) {
    selections {
      ... on JourneyOfferSelection {
        offers {
          parts {
            ... on ReservationPart {
              id
              placeProperties {
                selectedOption {
                  id
                  value
                }
              }
            }
          }
        }
      }
    }
  }
}

Using the Offer Selection Embed

For a ready-made user interface, consider using the Offer Selection Embed. The embed provides an intuitive interface for selecting an offer, place properties and ancillaries, useful to quickly set up a booking flow on your website without writing any custom UI code.

html
<aa-offer-selection
  publicApiKey="my-api-key"
  booking="booking-id"
  offer="offer-id"></aa-offer-selection>
<aa-offer-selection
  publicApiKey="my-api-key"
  booking="booking-id"
  offer="offer-id"></aa-offer-selection>

Creating and Finalizing Orders

Once your booking has all passenger details and selected offers, you're ready to create an order. How you do this depends on your payment method:

Payment Methods

Most API users don't use the payment gateway. Instead, they use one of these methods:

  1. Wallet (Pre-paid Credits): Most common for API integrations. You maintain a balance of credits that are used for orders. Credits are deducted when you finalize an order.

  2. Payment Gateway: For end-customer payments. Redirects customers to All Aboard's payment page to pay, then automatically creates and finalizes the order. See Payments for details.

  3. Invoice: Available for vetted commercial clients only. Orders are invoiced monthly.

Using Wallet or Invoice

If you're using wallet credits or invoice billing, create the order manually:

  1. Create the order: Call createOrder. This pre-books the tickets with the train operator
  2. Finalize the order: Call finalizeOrder. This completes the purchase and triggers ticket issuance

Both steps happen immediately. There's no payment redirect.

Example: Create and finalize order (wallet/invoice)
graphql
mutation CreateOrder {
  createOrder(booking: "503776b6-3d98-4903-adab-1b5ba9f64e80") {
    id
    status
    reference
  }
}

mutation FinalizeOrder {
  finalizeOrder(order: "b81b4895-28c3-422a-beb7-d16a418d1d6c") {
    id
    status
    reference
  }
}
mutation CreateOrder {
  createOrder(booking: "503776b6-3d98-4903-adab-1b5ba9f64e80") {
    id
    status
    reference
  }
}

mutation FinalizeOrder {
  finalizeOrder(order: "15c34be0-add3-4f5d-be30-1374e6d446cf") {
    id
    status
    reference
  }
}

Creating an order can take up to 30 seconds because it pre-books tickets with train operators. Use WebSocket connections to avoid timeouts and see progress updates.

Using Payment Gateway

If you're collecting payment from end customers, use the payment gateway flow (createPayment). This automatically creates and finalizes the order after payment:

Example: Create payment (gateway)
graphql
mutation CreatePayment {
  createPayment(
    booking: "503776b6-3d98-4903-adab-1b5ba9f64e80"
    successUrl: "https://example.com/success/{order}"
    cancelUrl: "https://example.com/cancel"
  ) {
    url
  }
}
mutation CreatePayment {
  createPayment(
    booking: "503776b6-3d98-4903-adab-1b5ba9f64e80"
    successUrl: "https://example.com/success/{order}"
    cancelUrl: "https://example.com/cancel"
  ) {
    url
  }
}

Redirect the customer to the returned URL. After payment, they're redirected back to your successUrl with the order ID, and the order is automatically finalized.

See Payments for complete details on the payment gateway flow.

Retrieving Tickets

Once an order is finalized, tickets are automatically issued. Fetch them using the node query. This usually takes 15 minutes or more. Train operators need time to generate and deliver the tickets.

Tickets come in different formats depending on the operator:

PDF Tickets

Most tickets are PDF files that passengers can download and show on their phone or print. These are the most common format.

Some operators require passengers to check in online before departure. The API provides a check-in URL where passengers complete the process and receive their tickets.

Ticket Collection References

Some UK operators issue "Ticket on Departure" references. Passengers use these at station ticket machines to collect physical tickets.

Example: Get tickets from finalized order
graphql
query GetTickets {
  node(id: "2dfaea11-cfba-4fc7-bea1-f5f742d5c14e") {
    ... on Order {
      items {
        ... on JourneyOrderItem {
          resources {
            ... on PdfTicket {
              url
            }
            ... on CheckInResource {
              url
            }
            ... on TicketOnDeparture {
              reference
              description
            }
          }
        }
      }
    }
  }
}
query GetTickets {
  node(id: "b3a4b4e7-6e37-46e7-98a6-0d4ebfe01f29") {
    ... on Order {
      items {
        ... on JourneyOrderItem {
          resources {
            ... on PdfTicket {
              url
            }
            ... on CheckInResource {
              url
            }
            ... on TicketOnDeparture {
              reference
              description
            }
          }
        }
      }
    }
  }
}

Ticket availability

Tickets may not be available immediately after finalization. Poll the order every few minutes until resources appear. Most tickets are available within 15 minutes, but some can take longer.

Complete Flow Summary

The complete booking flow from start to finish:

  1. Search for journeys between locations
  2. Get offers for the journey you want
  3. Create booking from the offer (createBooking)
  4. Add passenger details (required information)
  5. Select offers (if you want different options than defaults)
  6. Select seat preferences (if applicable)
  7. Create order (createOrder to pre-book tickets)
  8. Finalize order (finalizeOrder to complete purchase and trigger ticket issuance)
  9. Retrieve tickets (download PDFs or get collection references)

For detailed information on each step, see the relevant sections in this documentation.