Get a flight booking
Retrieve the full booking through one booking_id field that accepts an internal UUID, a supplier order id or a PNR, with the PDF link.
POST/api/v1/flights/get_booking
Retrieve a booking by its PNR, its supplier order id or its FX-Port id: the status, the prices, the ticket number, the links of the PDF tickets and the ACD state.
Permission: Read. Rate group: booking (1,200 requests per minute per key).
Identifying the booking
The body has one field, booking_id, and its value can be any of these:
booking_id value | Description |
|---|---|
The FX-Port booking id (a UUID) | Recommended: stable and unambiguous. Returned as postProcessing.bookingDbId by book and as id here. |
| The supplier order id | booking.reference of the booking response: an ord_... for Duffel, a base64-like text for Amadeus. Stored in the amadeus_id column for both suppliers. |
| The PNR | The airline record locator. Not unique across suppliers. |
The lookup tries the PNR first, then the order id, then the UUID, inside your agency and your key's environment. A booking that is not yours, or that belongs to the other environment, is answered 404 booking_not_found.
| Field | Type | Required | Description |
|---|---|---|---|
booking_id | string | Yes | One of the three identifiers above. order_id and pnr are accepted as other names of the same field. |
include_api_response | boolean | No | true adds booking.apiResponse: the stored answer of the booking call, with the full passenger list. Default false. |
Legacy names: bookingId, orderId and includeApiResponse still work and are answered with a deprecated_field warning. If booking_id is sent together with order_id or pnr and the values differ, booking_id wins and an ignored_field warning names the dropped one.
Request example
curl https://api.fx-port.com/api/v1/flights/get_booking \
-H "Authorization: Bearer fxp_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"booking_id": "711371c3-00aa-4be2-b790-9f0ca2ccfdb7"
}'Response example
An Amadeus Algeria booking, held and then paid (real response of 2026-11-01, trimmed: the internal columns are left out and the links and ids are fake). order_id, pnr, pdf_url and pdf_url_no_price are the snake_case twins of amadeus_id, booking_id, bucket_link and bucket_link_no_price; acd_required and requires_acd say whether ACD passports are expected:
{
"environment": "sandbox",
"success": true,
"requestId": "0c2b315c",
"processingTime": 0.272,
"booking": {
"id": "711371c3-00aa-4be2-b790-9f0ca2ccfdb7",
"booking_id": "Y7PAEU",
"amadeus_id": "eJzTd9ePNA9wdA0FAAs8AmE",
"order_id": "eJzTd9ePNA9wdA0FAAs8AmE",
"pnr": "Y7PAEU",
"status": "confirmed",
"created_at": "2026-11-01T15:26:14.871035+00:00",
"paid_at": "2026-11-01T15:26:21.961664+00:00",
"updated_at": "2026-11-01T15:26:21.998944+00:00",
"total_price": 4930.37,
"agency_commission": 4.93,
"currency": "DZD",
"departure_airport": "ALG",
"arrival_airport": "ORN",
"departure_date": "2026-12-22T19:45:00",
"arrival_date": "2026-12-22T20:45:00",
"return_departure_date": null,
"return_arrival_date": null,
"included_checked_bags": "0",
"ticketing_agreement": "DELAY_TO_CANCEL",
"supplier_name": "Amadeus Algeria",
"supplier_id": "amadeus_aqc_dz_1",
"ticket_number": "124-2446977397",
"bucket_link": "https://s3.example.com/flight-bookings/Y7PAEU-JAMES-SMITH.pdf",
"bucket_link_no_price": "https://s3.example.com/flight-bookings/Y7PAEU-JAMES-SMITH-no-price.pdf",
"pdf_url": "https://s3.example.com/flight-bookings/Y7PAEU-JAMES-SMITH.pdf",
"pdf_url_no_price": "https://s3.example.com/flight-bookings/Y7PAEU-JAMES-SMITH-no-price.pdf",
"email_sent": false,
"require_acd": false,
"acd_required": false,
"requires_acd": false,
"acd_submitted": false,
"acd_links": null,
"acd_amount": null,
"acd_paid": false,
"acd_documents_revision": 0,
"acd_documents": null,
"has_changed": false,
"new_flight_details": null,
"voided_at": null,
"refund_amount": null,
"refund_currency": null,
"refund_method": null,
"agent_id": null,
"environment": "sandbox",
"pricingBreakdown": {
"supplier_currency": "DZD",
"agency_currency": "DZD",
"base_price": 3160.0,
"taxes_and_fees": 1765.44,
"agency_commission": 4.93,
"final_price": 4930.37,
"b2b_price": 4925.44,
"created_at": "2026-11-01T15:26:22.176516+00:00",
"environment": "sandbox"
},
"travelerPricing": [
{
"traveler_id": "1",
"traveler_type": "ADULT",
"fare_option": "STANDARD",
"supplier_currency": "DZD",
"agency_currency": "DZD",
"base": 3160.0,
"total": 4930.37,
"b2b_price": 4925.44,
"created_at": "2026-11-01T15:26:15.133066+00:00",
"environment": "sandbox"
}
],
"balanceOperations": []
}
}The booking is a database row, so its keys are snake_case; only pricingBreakdown, travelerPricing, balanceOperations and apiResponse are camelCase. The row has more keys than shown (the void history, the details of a changed schedule ...): they are internal, can change and are not part of the contract. Use the keys of the table below. The ids of your agency and of the API key are not returned, and neither are the storage keys of the ACD passports. The booking also carries the twins order_id (next to amadeus_id), pnr (next to booking_id), pdf_url and pdf_url_no_price (next to bucket_link and bucket_link_no_price).
Key fields
| Field | Description |
|---|---|
id | The FX-Port UUID of the booking. Use it as the key when you store or re-read a booking. |
booking_id | The PNR. Not unique; prefer id. |
amadeus_id | The supplier's order id. The name is historical: it also holds the ord_... of a Duffel order. This is the order_id of pay_order, cancel_order and cancel_quote. |
status | confirmed, awaiting_payment (a hold), cancelled, partial_refund (a Duffel order cancelled with a refund), failed (the supplier refused the booking). Other values (voided, refunded, expired) can appear for changed orders. |
total_price, agency_commission, currency | The final price, your commission and the currency of the agency. |
pricingBreakdown | supplier_currency, agency_currency, base_price, taxes_and_fees, agency_commission, final_price, b2b_price: b2b_price is what was debited. The rate and the ACD details are not here. |
travelerPricing[n] | The price of each traveler, as in search but in snake_case. |
departure_airport, arrival_airport, departure_date, arrival_date, return_departure_date, return_arrival_date | The route; the dates are local times without a zone. |
ticket_number | The e-ticket number(s), as one text (several numbers are joined by commas). Can be null for a while after an instant Amadeus booking: see Get the ticket number. In the Duffel sandbox it is the text 1. |
bucket_link, bucket_link_no_price | The PDF of the ticket with and without the fare. null until generated. These are public links: see Get the ticket PDF. |
ticketing_agreement | The ticketing-time-limit agreement of an Amadeus booking, for example DELAY_TO_CANCEL. |
require_acd, acd_required, requires_acd, acd_submitted | The ACD state. acd_required and requires_acd are true for an ACD booking whose passports FX-Port did not waive (the same value as acd.acd_required of get_acd_documents); require_acd is the stored flag. acd_submitted is a boolean, never null: false until every traveler has a passport. See ACD passport uploads. |
acd_documents, acd_links, acd_amount, acd_paid, acd_documents_revision | The passports of an ACD booking. acd_documents is null until a passport is uploaded through the API, then it has one entry for each traveler: traveler_id, traveler_name, traveler_type, link, filename, content_type, size (bytes), format, uploaded_at, replaced_count, previous_links[] (link, uploaded_at, replaced_at: the files that were replaced) and source. acd_links lists the addresses of every passport file, also the ones FX-Port staff added from the dashboard. These links are public: see Security: file links are public. FX-Port's own storage keys are never returned. For the state of each traveler use get_acd_documents. acd_amount is the ACD amount in euros, saved when the set became complete (informational); acd_paid says whether FX-Port's team marked it as paid; acd_documents_revision goes up with each upload that stored a file. |
has_changed, new_flight_details | Set when the airline changed the schedule after ticketing. |
refund_amount, refund_currency, refund_method | The refund of a cancelled Duffel order (partial_refund, method balance). |
voided_at | When the ticket was voided. |
email_sent | Whether the confirmation e-mail went out. |
environment | sandbox or live. |
balanceOperations | The ledger entries of this booking (debits, refunds), each with only id, flight_booking_id, operation, amount, currency, description, created_at, b2b_price and final_price. Empty in the sandbox. |
An ACD booking with a passport
The ACD keys of the booking of an ACD fare whose passport was uploaded and then replaced once (real response of 2026-11-01, trimmed to these keys; the name and the links are fake). Every other key is the one of the first example.
{
"booking": {
"booking_id": "Y7HWMD",
"require_acd": true,
"acd_required": true,
"requires_acd": true,
"acd_submitted": true,
"acd_links": ["https://s3.example.com/fx-port/acd_passports/Y7HWMD/1/20261101142432_087a6dc8.png"],
"acd_amount": 235.0,
"acd_paid": false,
"acd_documents_revision": 2,
"acd_documents": [
{
"traveler_id": "1",
"traveler_name": "JANE DOE",
"traveler_type": "ADULT",
"link": "https://s3.example.com/fx-port/acd_passports/Y7HWMD/1/20261101142432_087a6dc8.png",
"filename": "rescan.png",
"content_type": "image/png",
"size": 69,
"format": "png",
"uploaded_at": "2026-11-01T14:24:33.057044+00:00",
"replaced_count": 1,
"previous_links": [
{
"link": "https://s3.example.com/fx-port/acd_passports/Y7HWMD/1/20261101142430_9b354245.pdf",
"uploaded_at": "2026-11-01T14:24:31.256905+00:00",
"replaced_at": "2026-11-01T14:24:33.057044+00:00"
}
],
"source": "api"
}
]
}
}The PDF
The PDF is generated after the booking, typically in 10 to 30 seconds:
Call
get_bookingand look atbooking.bucket_link.If it is
null, the PDF is still being made: wait 5 to 10 seconds and read again. A failed booking never gets one, so stop after about two minutes.When it has a value it is the download address of the PDF. A held booking gets a hold voucher, not a ticket; after the payment the link points to the ticket.
POST / returns the same links with a ticket_ready flag.
Errors
| Status | Code | When | What to do |
|---|---|---|---|
400 | bad_request | No booking_id (booking_id is required). | Send it. |
400 | invalid_booking_id | booking_id is not a valid token: letters, digits and - _ . : = ~, up to 128 characters. | Send the id as you received it. |
400 | invalid_json, invalid_body | The body is not a JSON object. | Send a JSON object. |
404 | booking_not_found | No booking with that id in your agency and environment (a booking of another agency is answered the same way). | Check the id and the key. |
Related
- Book a flight, Get the ticket PDF and Get the ticket number.
- Booking detail: the same booking across products, by GET.