Decode a PNR
POST https://keyflight.io/api/v1/pnr/decode
Content-Type: application/json
Request body
| Field | Values | Default |
text |
Required. The booking as the GDS shows it, up to 20,000 characters. The format is recognised from the text. |
— |
options.view |
table, lines2, lines3, whatsapp: the layout of itinerary, see Itinerary views. |
table |
options.timeFormat |
"24" (18:30), "12" (6:30 PM) |
"24" |
options.dateFormat |
"short" (3 May 2026), "numeric" (03.05.2026) |
"short" |
options.show.logo |
true / false. Airline logos (HTML only). |
true |
options.show.airports |
true / false. Airport names next to the city. |
true |
options.show.cabin |
true / false. Cabin and booking class: Economy (Y). |
false |
options.show.status |
true / false. Segment status: Confirmed, Waitlisted. |
false |
options.show.passengers |
true / false. Passenger names above the flights. |
false |
options.show.pnr |
true / false. The booking reference above the flights. |
false |
All options are optional. An unknown option or value answers 400 invalid_option instead of a silent default. The options change only itinerary: the fields of the segments always carry ISO dates and 24-hour times.
Response
| Field | Meaning |
pnrCode | The booking reference found in the text, or null. |
passengers[].name | A passenger name as the PNR writes it. |
segments[].airlineCode | IATA code of the airline. |
segments[].airlineName | Airline name; an unknown code is its own name. |
segments[].flightNumber | Flight number without leading zeros: "950" for UA0950. |
segments[].bookingClass | Booking class letter, or null. |
segments[].cabin | By the booking class: Economy, Premium Economy, Business, First Class. |
segments[].status | Status code as in the PNR ("HK2"), or null. |
segments[].statusText | Confirmed, Waitlisted, or the code itself; null without a status. |
segments[].logoUrl | URL of the airline logo, 64×64 PNG (a plane silhouette when we have none). |
segments[].departure.code | IATA code of the airport. |
segments[].departure.city | City, or null. |
segments[].departure.airport | Airport name, or null. |
segments[].departure.date | Local date at the airport, YYYY-MM-DD, or null when the text has none. |
segments[].departure.time | Local time at the airport, HH:MM (24 h), or null. |
segments[].arrival | The same fields for the arrival airport. |
itinerary.view | The view used. |
itinerary.text | The itinerary as plain text. |
itinerary.html | The itinerary as e-mail HTML (tables, inline styles); null for whatsapp. |
A PNR has no years in its dates. The API takes the year from the date the booking was created (the RP line of Amadeus, the footer of Sabre); without it, each flight gets the nearest date in the future, and the next flights are not earlier than the one before.
Example
The Amadeus booking from the Amadeus PNR converter, sent with Node.js or Python:
// Node.js 18+ (fetch is built in), in an ES module or an async function
const text = `RP/LHRBA/LHRBA BA/BA 26APR26/1200Z PQ7XNR
PQ7XNR/BA QLHR 03MAY
1.JOHNSON JOHN
2.JOHNSON JANE
3 BA 178 Y 03MAY 7 LHRJFK HK2 0855 1205 03MAY E BA/PQ7XNR
4 BA 117 Y 10MAY 7 JFKLHR HK2 1830 0640 11MAY E BA/PQ7XNR
5 TKT/TIME LIMIT
6 OPC LHRBA-10MAY:1900/1S2/Q TKT/T-BA
7 FA PAX 125-2196837482/ETBA/GBP560.20/03MAY26/LHRBA2104/00390755/S3-4`;
const response = await fetch('https://keyflight.io/api/v1/pnr/decode', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.KEYFLIGHT_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ text, options: { "view": "table" } }),
});
const data = await response.json();
if (response.ok) {
data.segments.forEach((s) => console.log(s.airlineCode, s.flightNumber, s.departure.date));
} else {
console.error(response.status, data.error, data.message);
}
import os
import requests
text = """RP/LHRBA/LHRBA BA/BA 26APR26/1200Z PQ7XNR
PQ7XNR/BA QLHR 03MAY
1.JOHNSON JOHN
2.JOHNSON JANE
3 BA 178 Y 03MAY 7 LHRJFK HK2 0855 1205 03MAY E BA/PQ7XNR
4 BA 117 Y 10MAY 7 JFKLHR HK2 1830 0640 11MAY E BA/PQ7XNR
5 TKT/TIME LIMIT
6 OPC LHRBA-10MAY:1900/1S2/Q TKT/T-BA
7 FA PAX 125-2196837482/ETBA/GBP560.20/03MAY26/LHRBA2104/00390755/S3-4"""
response = requests.post(
"https://keyflight.io/api/v1/pnr/decode",
headers={"Authorization": f"Bearer {os.environ['KEYFLIGHT_API_KEY']}"},
json={"text": text, "options": { "view": "table" }},
timeout=30,
)
data = response.json()
if response.ok:
for s in data["segments"]:
print(s["airlineCode"], s["flightNumber"], s["departure"]["date"])
else:
print(response.status_code, data["error"], data["message"])
The answer, made by the API code when this page was built (itinerary.html is shortened here, it is shown in full below):
{
"pnrCode": "PQ7XNR",
"passengers": [
{
"name": "JOHNSON JOHN"
},
{
"name": "JOHNSON JANE"
}
],
"segments": [
{
"airlineCode": "BA",
"airlineName": "British Airways",
"flightNumber": "178",
"bookingClass": "Y",
"cabin": "Economy",
"status": "HK2",
"statusText": "Confirmed",
"logoUrl": "https://keyflight.io/img/airlines/BA.png",
"departure": {
"code": "LHR",
"city": "London",
"airport": "London Heathrow Airport",
"date": "2026-05-03",
"time": "08:55"
},
"arrival": {
"code": "JFK",
"city": "New York",
"airport": "John F Kennedy International Airport",
"date": "2026-05-03",
"time": "12:05"
}
},
{
"airlineCode": "BA",
"airlineName": "British Airways",
"flightNumber": "117",
"bookingClass": "Y",
"cabin": "Economy",
"status": "HK2",
"statusText": "Confirmed",
"logoUrl": "https://keyflight.io/img/airlines/BA.png",
"departure": {
"code": "JFK",
"city": "New York",
"airport": "John F Kennedy International Airport",
"date": "2026-05-10",
"time": "18:30"
},
"arrival": {
"code": "LHR",
"city": "London",
"airport": "London Heathrow Airport",
"date": "2026-05-11",
"time": "06:40"
}
}
],
"itinerary": {
"view": "table",
"text": "BA 178 · British Airways\n3 May 2026 08:55 London (LHR), London Heathrow Airport\n3 May 2026 12:05 New York (JFK), John F Kennedy International Airport\n\nBA 117 · British Airways\n10 May 2026 18:30 New York (JFK), John F Kennedy International Airport\n11 May 2026 06:40 London (LHR), London Heathrow Airport",
"html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size…"
}
}