REST API

API Documentation

Send a raw Sabre or Amadeus PNR and get back a fully structured itinerary — not just flights, but hotels, cars, cruises, tours, transfers, insurance, passengers, seats, e-tickets, SSRs/meals, fares and remarks. It's the same engine that powers the web app. Grab your API key from your dashboard.

What it decodes

FlightsSabre & Amadeus air segments, airline names + logos, cabin, times, next-day arrivals with resolved arrival dates, flight duration, status
PassengersNames, type (ADT/CHD/INF), per-traveller seats & e-tickets, frequent flyer
E-ticketsTicket numbers matched to each passenger and airline (interline-aware)
HotelsProperty name, city, check-in/out, room type, guests, rate, confirmation
CarsSupplier, vehicle category, pickup/return date, time & location
CruisesShip, cabin/stateroom, category, sailing dates
Tours & TransfersExcursions/sightseeing and airport↔hotel transfers with dates
InsuranceProvider and policy number
SSRs & MealsSpecial requests, meal codes (e.g. VGML), APIS/DOCS, wheelchair
Fares & PaymentBase/tax/total, form of payment (PAN masked), endorsements
Remarks & ContactsFree-text remarks, phone/email contacts, record locator, ticketing time limit

Recent additions

Geo & timezone dataEach flight segment now includes origin/destination country, latitude/longitude, IANA timezone + short abbreviation, combined departure_datetime / arrival_datetime with weekday, Haversine distance_km / distance_miles, transit_time to the next leg, operated_by and aircraft
Arrival datesEach flight now returns arrival_date (segments) and arrivalDate / arrivalRawDate (model) — explicit next-day dates (e.g. 705P/10OCT) and “+1 day” markers are resolved automatically
Flight durationEvery flight returns duration (e.g. “11h 55m”) plus durationMinutes on the model — timezone-accurate (DST-aware) using a bundled offline airport dataset, and also shown on rendered itineraries
Layover timesConnection gaps between consecutive legs are calculated and labelled on rendered itineraries (e.g. “2h 30m layover in London”)
12-hour timesTimes display as friendly 6:00 PM on rendered itineraries, while the JSON keeps 24-hour HH:MM
Year-normalised datesRendered dates always include a 4-digit year (e.g. 12 Dec 2026), handling trips that cross New Year
Local-time noteDeparture/arrival are clearly marked as local airport time to avoid long-haul confusion
Manual builderBuild an itinerary from scratch (no PNR) with searchable offline airline & airport autocomplete and calendar date / time pickers

The /api/convert JSON returns arrival_date and duration per flight, and keeps raw 24-hour HH:MM times and ISO dates. Purely visual touches (12-hour times, layovers, “+1 day”, local-time note) are applied when you render an itinerary via the builder, shareable link or PDF/HTML export.

POST
https://pnrdecode.com/api/convert

Parses a raw PNR/itinerary string and returns enriched flight segments plus a rich model object containing every non-flight service. Auto-detects Sabre vs Amadeus and reports a confidence score.

Authentication

Pass your API key as a Bearer token. Requests without a valid key return 401; the public API requires the Conversion API plan (403 otherwise). Once your monthly plan limit is reached, requests return 429 until the next billing cycle.

Header
Authorization: Bearer YOUR_API_KEY

Example request

cURL
curl -X POST https://pnrdecode.com/api/convert \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"pnr_text": "*ABC123\n 1.1SMITH/JOHN MR\n 2 EK 202Y 09OCT JFKDXB HK1 1010P 705P\n 4 HHL EK HK1 DXB 10OCT-17OCT\n   ATLANTIS THE PALM"}'
Request body
{
  "pnr_text": "raw multi-line GDS itinerary string"
}

Send the PNR exactly as displayed in your GDS — including hotel (HHL/9H), car (CCR/9C), cruise, tour, transfer, insurance, seat and e-ticket lines. Multi-line native Sabre and Amadeus formats are supported.

Example response

200 OK — application/json
{
  "gds": "Sabre",
  "gds_confidence": 0.83,
  "segments": [
    {
      "gds": "Sabre",
      "airline_code": "EK",
      "airline_name": "Emirates",
      "airline_logo_url": "https://img.logo.dev/emirates.com?token=...",
      "flight_number": "202",
      "booking_class": "Y",
      "cabin_class": "Economy",
      "date_raw": "09OCT",
      "date": "9 Oct",
      "arrival_date": "10 Oct",
      "origin_code": "JFK",
      "origin_name": "John F. Kennedy International Airport",
      "origin_city": "New York",
      "destination_code": "DXB",
      "destination_name": "Dubai International Airport",
      "destination_city": "Dubai",
      "departure_time": "22:10",
      "arrival_time": "19:05",
      "duration": "11h 55m",
      "status_code": "HK1",
      "status": "Confirmed",
      "record_locator": "ABC123",
      "seat": "22A",
      "eticket": "1761234567890",
      "checkin_baggage": "2PC",
      "carry_on_baggage": "7KG",
      "frequent_flyer": "EK123456789",
      "meal": "Vegetarian (Indian)",
      "origin_country": "United States",
      "destination_country": "United Arab Emirates",
      "origin_latitude": 40.63975, "origin_longitude": -73.77893,
      "destination_latitude": 25.25278, "destination_longitude": 55.36444,
      "origin_timezone": "America/New_York", "destination_timezone": "Asia/Dubai",
      "origin_timezone_short": "EDT", "destination_timezone_short": "+04",
      "departure_datetime": "2026-10-09 22:10", "departure_day": "Fri",
      "arrival_datetime": "2026-10-10 19:05", "arrival_day": "Sat",
      "distance_km": 11000, "distance_miles": 6835,
      "transit_time": { "minutes": 150, "hours": 2.5 },
      "operated_by": null,
      "aircraft": null
    }
  ],
  "model": {
    "source":  { "gds": "Sabre", "confidence": 0.83, "level": "MEDIUM" },
    "pnr":     { "recordLocator": "ABC123", "creationDate": "2026-10-01", "officeId": "NYCXY1234", "receivedFrom": "JOHN SMITH" },
    "passengers": [
      {
        "id": "1.1", "lastName": "Smith", "firstName": "John", "title": "MR",
        "passengerType": "ADT", "passengerTypeName": "Adult",
        "seat": "22A", "eticket": "1761234567890", "frequentFlyer": "EK123456789",
        "tickets": [ { "airline": "EK", "number": "1761234567890" } ],
        "raw": "1.1SMITH/JOHN MR", "confidence": 0.85
      }
    ],
    "flights": [
      {
        "type": "AIR", "segmentNumber": 2,
        "marketingCarrier": "EK", "operatingCarrier": null, "codeshare": false,
        "airlineName": "Emirates", "flightNumber": "202",
        "bookingClass": "Y", "cabin": "Economy",
        "departureAirport": "JFK", "departureCity": "New York", "departureCountry": "United States",
        "arrivalAirport": "DXB", "arrivalCity": "Dubai", "arrivalCountry": "United Arab Emirates",
        "date": "2026-10-09", "rawDate": "09OCT",
        "arrivalDate": "2026-10-10", "arrivalRawDate": "10OCT", "arrivalNextDay": true,
        "departureTime": "22:10", "arrivalTime": "19:05",
        "duration": "11h 55m", "durationMinutes": 715,
        "statusCode": "HK", "statusDescription": "Confirmed", "passengerCount": 1,
        "terminal": null, "equipment": null, "meal": null, "seat": null,
        "gds": "Sabre", "confidence": 0.97
      }
    ],
    "hotels": [
      {
        "type": "HOTEL", "hotelName": "Atlantis The Palm", "city": "DXB", "address": null,
        "checkIn": "2026-10-10", "checkOut": "2026-10-17",
        "roomType": "Deluxe Ocean Room", "guests": "2 Adults",
        "rate": "450.00", "currency": "USD", "confirmationNumber": "H889900",
        "cancellation": null, "guarantee": null,
        "raw": "4 HHL EK HK1 DXB 10OCT-17OCT ATLANTIS THE PALM", "confidence": 0.8
      }
    ],
    "cars": [
      {
        "type": "CAR", "supplier": "Hertz", "supplierCode": "ZE", "city": "DXB",
        "pickupLocation": "DXB", "dropoffLocation": "DXB",
        "pickupDate": "2026-10-10", "pickupTime": "21:00",
        "dropoffDate": "2026-10-17", "dropoffTime": "06:00",
        "vehicleCategory": "Suv", "transmission": "Automatic",
        "rate": null, "currency": null, "confirmationNumber": "AVS456123",
        "raw": "5 CCR ZE HK1 DXB 10OCT-17OCT/HERTZ", "confidence": 0.7
      }
    ],
    "cruises": [
      {
        "type": "CRUISE", "shipName": "MSC Euribia", "category": "Balcony", "cabin": "12034",
        "sailingStart": "2026-10-13", "sailingEnd": "2026-10-17",
        "confirmationNumber": "CRUISE12345", "city": "DXB",
        "raw": "6 OTH CRUISE MSC EURIBIA ...", "confidence": 0.7
      }
    ],
    "tours": [
      {
        "type": "TOUR", "name": "Dubai Desert Safari", "city": "DXB", "date": "2026-10-12",
        "pickup": null, "timeFrom": "15:00", "timeTo": "22:00", "duration": null,
        "confirmationNumber": "T1", "raw": "TOUR DUBAI DESERT SAFARI 12OCT 1500-2200", "confidence": 0.75
      }
    ],
    "transfers": [
      { "type": "TRANSFER", "detail": "Airport-Hotel", "city": "DXB", "date": "2026-10-13",
        "confirmationNumber": null, "raw": "TRF DXB AIRPORT-HOTEL 13OCT", "confidence": 0.7 }
    ],
    "rail":      [],
    "insurance": [
      { "type": "INSURANCE", "provider": "Travel Insurance", "policyNumber": "ABC123456",
        "city": null, "raw": "INSURANCE TRAVEL INSURANCE POLICY ABC123456", "confidence": 0.75 }
    ],
    "seats": [
      { "type": "SEAT", "seats": [ { "seat": "22A", "passengerId": "1.1", "segment": "2" } ],
        "raw": "ST/22A/P1/S2", "confidence": 0.85 }
    ],
    "ssr": [
      { "code": "VGML", "description": "Vegetarian (Indian)", "airline": "EK", "status": "HK",
        "passengerId": "1.1", "text": "HK1/P1", "raw": "SSR VGML EK HK1/P1", "recognized": true,
        "confidence": 0.9, "flightIndex": 0, "associationConfidence": 0.9 }
    ],
    "osi":       [],
    "tickets": [
      { "kind": "ticket", "ticketNumber": "1761234567890", "airlinePrefix": "176", "status": "ISSUED",
        "passengerId": "1.1", "passengerName": null, "raw": "FA PAX 176-1234567890/ETEK/P1",
        "confidence": 0.85, "associationConfidence": 0.9 }
    ],
    "emds":      [],
    "payments":  [],
    "fares":     [],
    "remarks":   [],
    "contacts":  [
      { "type": "CONTACT", "kind": "email", "phone": null, "email": "john.smith@example.com",
        "belongsTo": null, "raw": "CTCE JOHN.SMITH//EXAMPLE.COM", "confidence": 0.8 }
    ],
    "addresses": [],
    "ticketing": {
      "ticketTimeLimit": null, "validatingCarrier": "EK", "receivedFrom": "JOHN SMITH",
      "endorsement": null, "commission": null, "corporateDiscount": null, "nonRefundable": null
    },
    "confidence":      { "overall": 0.82, "level": "MEDIUM", "uncertainCount": 0 },
    "validation":      { "ok": true, "notes": [] },
    "unknownSegments": [],
    "errors":          [],
    "classifiedLines": [ { "lineNumber": 1, "raw": "*ABC123", "text": "*ABC123", "type": "PNR_HEADER", "confidence": 0.9 } ]
  },
  "extras": {
    "frequent_flyer": [], "meals": [], "special_assistance": [], "ssr": [], "contacts": [],
    "fare": {}, "baggage": [], "eticket_numbers": [], "record_locator": null, "conditions": []
  },
  "warnings": [],
  "error": null,
  "calls_remaining": 19
}

Every array is always present (empty [] when the PNR has none). In segments, date / arrival_date are short display strings; in model, dates are ISO YYYY-MM-DD and times are 24-hour HH:MM. Anything the parser couldn't confidently map appears in model.unknownSegments, and any credit-card PAN in the source is masked.

Response fields

Complete list of keys returned per segment type. Keys marked optional are omitted when the PNR has no such data; every other key is always present (value may be null). Airport geo/timezone fields on segments[] are derived offline from the bundled airports dataset by IATA code.

Flight — segments[] (flat, enriched)
gdsstringSabre · Amadeus · Generic
airline_codestring2-letter IATA marketing carrier
airline_namestringResolved airline name (falls back to the code)
airline_logo_urlstring | nullLogo URL when available
flight_numberstring
booking_classstringRBD letter, e.g. Y
cabin_classstringEconomy · Premium Economy · Business · First
date_rawstringDeparture date as written, e.g. 09OCT
datestringDeparture date display, e.g. 9 Oct
arrival_datestringResolved arrival date display (explicit /DDMMM, +1 markers and overnight legs handled)
origin_code / destination_codestringIATA airport codes
origin_name / destination_namestringAirport name (falls back to the code)
origin_city / destination_citystringCity (empty string when unknown)
departure_time / arrival_timestringLocal airport time, 24-hour HH:MM
durationstringTimezone-aware block time, e.g. 11h 55m (empty when it can't be computed)
status_codestringRaw GDS status incl. pax count, e.g. HK1
statusstringConfirmed · Waitlisted · Pending · Cancelled …
record_locatorstringOptional — only present when the PNR carries the data (airline locator on the line)
next_daybooleanOptional — only present when the PNR carries the data (only on native multi-line PNRs)
seat, eticket, checkin_baggage, carry_on_baggage, frequent_flyer, mealstringOptional — only present when the PNR carries the data
origin_country / destination_countrystring | nullCountry name from the airports dataset
origin_latitude, origin_longitude, destination_latitude, destination_longitudenumber | nullDecimal degrees
origin_timezone / destination_timezonestring | nullIANA zone, e.g. Asia/Kolkata
origin_timezone_short / destination_timezone_shortstring | nullAbbreviation at the local date/time, e.g. IST, GMT, +03
departure_datetime / arrival_datetimestring | nullLocal, YYYY-MM-DD HH:MM
departure_day / arrival_daystring | null3-letter weekday, e.g. Sat
distance_km / distance_milesnumber | nullGreat-circle (Haversine) distance, rounded
transit_timeobject{ minutes, hours } gap to the next segment's departure (timezone-aware); {} on the last segment
operated_by / aircraftstring | nullOperating carrier / equipment when present in the PNR, else null
Flight — model.flights[]
type"AIR"
segmentNumbernumber | nullGDS element number
marketingCarrier / operatingCarrierstring | nulloperatingCarrier is reserved; currently null
codesharebooleanReserved; currently false
airlineName, flightNumber, bookingClass, cabinstring
departureAirport / arrivalAirportstringIATA codes
departureCity, departureCountry, arrivalCity, arrivalCountrystring | null
date / arrivalDatestringISO YYYY-MM-DD
rawDate / arrivalRawDatestring | nullAs written in the PNR, e.g. 10OCT
departureTime / arrivalTimestring24-hour HH:MM local
arrivalNextDaybooleanTrue when a +1/#1 marker (or overnight roll-over) applies
duration / durationMinutesstring / number | nullTimezone-aware
statusCode / statusDescriptionstringe.g. HK / Confirmed
passengerCountnumber | null
terminal, equipment, meal, seatstring | nullReserved slots; populated when present on the line
gds, confidencestring, number
Hotel — model.hotels[]
type"HOTEL"
hotelName, city, addressstring | null
checkIn / checkOutstring | nullISO YYYY-MM-DD
roomType, guestsstring | null
rate, currencystring | null
confirmationNumber, cancellation, guaranteestring | null
raw, confidencestring, numberSource text and 0–1 confidence
Car — model.cars[]
type"CAR"
supplier, supplierCodestring | nulle.g. Hertz / ZE
city, pickupLocation, dropoffLocationstring | null
pickupDate / dropoffDatestring | nullISO YYYY-MM-DD
pickupTime / dropoffTimestring | null24-hour HH:MM
vehicleCategory, transmissionstring | null
rate, currency, confirmationNumberstring | null
raw, confidencestring, number
Cruise — model.cruises[]
type"CRUISE"
shipName, category, cabinstring | null
sailingStart / sailingEndstring | nullISO YYYY-MM-DD
confirmationNumber, citystring | null
raw, confidencestring, number
Excursion / Tour — model.tours[]
type"TOUR"
name, citystring | null
datestring | nullISO YYYY-MM-DD
pickup, timeFrom, timeTo, durationstring | null
confirmationNumberstring | null
raw, confidencestring, number
Transfer / Rail — model.transfers[] · model.rail[]
type"TRANSFER"
detail, citystring | null
datestring | nullISO YYYY-MM-DD
confirmationNumberstring | null
raw, confidencestring, number
Other model collections
passengers[]objectid, lastName, firstName, title, passengerType, passengerTypeName, raw, confidence + optional seat, eticket, frequentFlyer, tickets[{airline, number}]
insurance[]objecttype, provider, policyNumber, city, raw, confidence
seats[]objecttype, seats[{seat, passengerId, segment}], raw, confidence
ssr[]objectcode, description, airline, status, passengerId, text, raw, recognized, confidence, flightIndex, associationConfidence + document{} (DOCS) / frequentFlyer (FQTV)
tickets[]objectkind, ticketNumber, airlinePrefix, status, passengerId, passengerName, raw, confidence, associationConfidence
emds[] · payments[] · fares[]objectemdNumber · method, brand, maskedNumber, last4, expiry · baseFare, taxes, total, currency, fareBasis
contacts[] · addresses[] · osi[] · remarks[]objecttype/kind, phone, email, belongsTo · kind, text · code, carrier, text · type, qualifier, text
pnr · ticketingobjectrecordLocator, creationDate, officeId, receivedFrom · ticketTimeLimit, validatingCarrier, receivedFrom, endorsement, commission, corporateDiscount, nonRefundable
confidence · validation · errors[] · classifiedLines[] · unknownSegments[]objectParser diagnostics: overall score, sanity notes, unmatched lines with reasons, per-line classification
Top level
gds / gds_confidencestring | null / numberDetected GDS and 0–1 confidence
segments[]arrayFlat enriched flights (above)
modelobjectUniversal PNR Model (above)
extrasobjectfrequent_flyer[], meals[], special_assistance[], ssr[], contacts[], fare{}, baggage[], eticket_numbers[], record_locator, conditions[] — legacy aggregate; may be {} for native multi-line PNRs
warnings[]string[]Unknown airline/airport codes
errorstring | null
calls_remainingnumber | nullnull on unlimited tiers

Status codes

200Success — parsed itinerary + model returned
401Missing or invalid API key
403Valid key, but the Conversion API plan is required
429Monthly call limit reached for your plan