In this volume · VOLUME 04
Travel Operations
Booking Lifecycle Ticketing & PNR Refunds & Cancellations Voids, Reissues & Adjustments Non-Air Products ADM / ACM Memos

Chapter 4.2 — Ticketing & PNR Management

1. Purpose

This chapter defines how travoBooks interfaces with airline reservation systems to create, hold, modify, and ticket PNRs (Passenger Name Records), and how the issued e-ticket and its TST (Transitional Stored Ticket) records map into platform state. It covers GDS-issued (BSP) and NDC-issued workflows, fare-rule capture, the ticketing time-limit enforcement, and the distinction between PNR creation (a hold) and ticketing (a financial event).

2. Why it matters in modern travel accounting

Ticketing is the financial trigger in air travel — it is the moment at which the supplier (airline, via BSP) and the partner (agent) crystallise an obligation. Mis-handling ticketing produces: - ADMs — unticketed PNR fees, churn fees, ticket-after-departure fees - Revenue loss — lost commission from late ticketing - Customer disputes — wrong name on ticket, wrong fare booked, no e-ticket issued - Settlement errors — BSP file mismatches

Modern travel accounting depends on a precise model of PNR vs ticket vs settlement.

3. Industry relevance

The PNR / ticket model in travoBooks mirrors IATA's Resolution 722g and the underlying EDIFACT / NDC schemas. Industry vocabulary (PNR, TST, fare basis, ATPCO, EMD, ticket image) is preserved verbatim so that staff trained on Amadeus / Sabre / Travelport recognise the system immediately.

4. Compliance considerations

  • IATA Resolution 850m — agent code on every ticket, accurate fare construction.
  • BSP rules — ticketing deadlines, void windows, name-change restrictions vary by country.
  • IFRS 15 — ticket issuance is the customer-side performance-obligation trigger; service is not delivered until the flight is flown but the supplier obligation crystallises now.
  • Tax invoices — many jurisdictions require ticket-level tax breakdown (YQ/YR carrier-imposed surcharge, government taxes) for VAT recoverability.

5. Business logic

5.1 PNR vs Ticket

Concept Definition travoBooks table
PNR Passenger Name Record — supplier-side reservation; identifies traveller(s), segments, contact info; tracked by record locator (ABC123). May exist without a ticket. booking_pnrs
TST Transitional Stored Ticket — fare calculation attached to PNR; defines what would be issued; expires at fare timelimit. booking_tsts
Ticket Actual financial document — 13-digit e-ticket number; the obligation that BSP settles. booking_tickets
EMD Electronic Miscellaneous Document — for ancillaries (bag, seat, lounge) tied to the same passenger; settled like a ticket. booking_emds

A booking may contain: 1 PNR, 1+ TSTs (one per fare component), 1+ tickets (one per passenger), 0+ EMDs.

5.2 PNR creation flow

  1. Agent (or API consumer) builds a booking from offer selection.
  2. travoBooks sends Air_SellFromRecommendation (Amadeus) / OTA_AirBookRQ (Sabre) / OrderCreate (NDC).
  3. Supplier returns record locator + segment statuses.
  4. travoBooks stores booking_pnrs.record_locator, pnr_status, created_at, timelimit_at.
  5. Booking moves to HELD.

5.3 TST & fare timelimit

When a fare is quoted and attached: 1. travoBooks calls Fare_PricePNRWithBookingClass / OrderPriceRQ. 2. Supplier returns one or more TSTs with timelimit and currency. 3. travoBooks stores TST snapshot in booking_tsts (with raw XML / JSON for audit). 4. The earliest TST timelimit becomes the booking's ticketing_deadline.

The scheduler enforces the deadline: - T-24h → email reminder to selling agent + mid-office. - T-2h → SMS escalation. - T-0 → auto-action per partner config (auto_void_at_timelimit, auto_extend_via_supplier, or keep_open).

5.4 Ticketing (issuance)

  1. Pre-flight validation: payment status (cash) OR credit available (corporate); TST still valid; PNR fares unchanged on re-price.
  2. travoBooks calls Ticket_CreateTSTFromPricingDocIssuance_IssueTicket (Amadeus) / OrderChange with IssuanceRQ (NDC).
  3. Supplier returns ticket number(s).
  4. travoBooks persists booking_tickets rows: ticket_number, pax_id, tst_id, issued_at, commission_pct, commission_amount, tax_breakdown JSON.
  5. Posts JE in the same DB transaction as ticket persistence (Chapter 4.1 invariant).
  6. Generates e-ticket PDF, attaches to booking documents.
  7. Emits ticket.issued event.

5.5 Fare components & tax breakdown

A ticket's tax_breakdown captures each XT (tax code) line as returned by the GDS:

[
  { "code": "BD", "name": "Bangladesh Departure Tax", "amount": 500, "currency": "BDT" },
  { "code": "YQ", "name": "Carrier Imposed Surcharge", "amount": 12000, "currency": "BDT" },
  { "code": "YR", "name": "Carrier Imposed Misc", "amount": 800, "currency": "BDT" }
]

This drives: - VAT-recovery reporting (carrier-imposed vs government taxes differ in deductibility) - Tax-invoice line items per jurisdiction - BSP file matching (BSP lists per-tax amounts)

5.6 Reissue (exchange)

Reissue replaces an existing ticket with a new one for the same passenger.

  1. Original ticket marked status = REISSUED, replaced_by_ticket_id set.
  2. New ticket inserted with replaces_ticket_id link.
  3. Fare difference JE: debit AR (customer pays more) or credit AR (residual to customer credit balance).
  4. Reissue fee applied per fare rules / partner config.
  5. Commission recall: original commission may be partially clawed back; new commission accrued on new fare.

5.7 Void

Same-day void (per supplier rules; typically same calendar day in PNR/BSP country timezone): 1. Validate void window not closed. 2. Call supplier void endpoint. 3. Mark ticket status = VOIDED, voided_at. 4. Reversing JE posts (full reversal of issuance JE). 5. Customer refund (cash) or AR reduction (credit) posted.

5.8 EMD (ancillaries)

EMDs are handled identically in lifecycle but with their own document numbers and a link to the parent ticket. Bag fees, seat fees, lounge access, premium meal — each generates a separate EMD with its own settlement.

5.9 ATPCO / fare basis preservation

The platform stores the fare basis code (e.g., KLOWBD, YOWFLEX) and the full fare rules text. This is non-negotiable: when a customer asks "can I refund?" or "can I change?", the answer comes from the captured fare rules, not from generic policy.

6. Inputs → processing → outputs

Issue ticket from priced PNR

Input: booking_id (state = HELD with priced TSTs), payment_status = OK or credit available.

Processing: 1. Validate state, payment, credit, TST validity. 2. Begin DB transaction. 3. Call supplier issuance API (idempotent — replays return existing ticket numbers). 4. Persist tickets, EMDs. 5. Compute and post JE. 6. Update booking state → ISSUED. 7. Commit. 8. Async: generate e-ticket PDF, dispatch emails, fire webhooks.

Output: Array of ticket numbers, e-ticket PDF URL, JE reference.

7. Module dependencies

Direction Module
Depends on Booking, Customer, Supplier, Tax Config, Payment, JE Engine, Supplier Integration
Depended on by Refund, Reissue, Void, BSP Import (matches our tickets to BSP records), ADM/ACM (memos reference ticket numbers)

8. Security & permissions

Permission Allows
tickets.read.partner View tickets
tickets.issue.partner Trigger issuance
tickets.void.partner Same-day void
tickets.reissue.partner Reissue
tickets.refund.partner Refund (delegates to refund module)

Ticket numbers themselves are not secret but treated as PII for log-redaction in customer-facing surfaces.

9. Validation rules

Code Condition
TICKET_TST_EXPIRED TST timelimit passed
TICKET_PRICE_CHANGED Re-price returned different total
TICKET_NAME_MISMATCH PNR name differs from booking traveller
TICKET_DUPLICATE_ISSUE Idempotency check found existing ticket
TICKET_VOID_WINDOW_CLOSED Void attempted past window
TICKET_VOID_DIFFERENT_BSP_DAY Void attempted in different BSP day from issue
TICKET_REISSUE_SAME_FARE Reissue would not change fare (suggest void+rebook)
TICKET_FARE_RULE_VIOLATION Operation violates captured fare rules
TICKET_EMD_PARENT_VOIDED EMD operation on ticket already voided
TICKET_SUPPLIER_REJECTED Supplier rejected — error preserved

10. Error handling

Supplier rejections at issuance are particularly sensitive: the PNR may have been auto-cancelled supplier-side. travoBooks captures the raw error, marks booking state safely (back to HELD or to ERROR), notifies the agent, and does not post any JE for a failed issuance.

If issuance succeeded supplier-side but the response failed mid-transmission, the idempotency-key replay recovers the ticket numbers on the next attempt.

11. Real-world examples

Example A — Standard BSP ticket issuance

Beta Corp booking: 1 passenger, EK DAC-DXB, USD 600 base + USD 80 YQ + USD 50 government taxes = USD 730.

Booking HELD with PNR ABC123, TST timelimit 2026-05-28 23:59
→ Agent triggers issue
→ Supplier returns ticket 176-2400000123
→ JE posted (per Chapter 5.1 example)
→ Booking ISSUED
→ E-ticket PDF emailed to Beta's travel coordinator

Example B — Reissue with fare difference

Customer changes return date; new fare USD 800.

Original ticket 176-2400000123 marked REISSUED
New ticket 176-2400000456 issued
Fare difference USD 70 (800 − 730) + USD 25 reissue fee
JE: Debit Customer AR USD 95
    Credit Supplier/BSP Payable USD 70
    Credit Reissue Fee Revenue (4032) USD 25
Original commission USD 36 partially recalled — JE adjusts commission receivable

Example C — Late void prevented

Agent attempts to void at 23:55 local but supplier BSP day rolled over at 23:59 UTC.

Validation rule TICKET_VOID_DIFFERENT_BSP_DAY fires
Operation rejected with explanation
Refund workflow suggested instead

12. Step-by-step workflow

sequenceDiagram autonumber actor A as Agent participant T as travoBooks participant DB as MySQL participant S as Supplier (GDS/NDC) A->>T: Issue ticket(booking_id) T->>DB: BEGIN; SELECT booking + tsts FOR UPDATE T->>T: Validate state, TST, payment, credit T->>S: TicketIssueRQ (idempotency_key) S-->>T: TicketIssueRS {ticket_numbers} T->>DB: INSERT booking_tickets T->>DB: INSERT journal_entries + lines T->>DB: UPDATE booking SET state=ISSUED, issued_at=NOW() T->>DB: UPDATE customer_balances + supplier_balances T->>DB: COMMIT T-->>A: 200 {tickets, je_id} T--)T: Async: generate PDF, send email, fire webhook

13. Database tables touched

Table Role
booking_pnrs Supplier PNR records
booking_tsts Fare-price snapshots
booking_tickets Issued tickets
booking_emds Ancillary documents
booking_tax_breakdown Per-XT tax lines
booking_fare_rules Captured fare-rule text
journal_entries / _lines Financial impact
audit_logs Operational events
booking_history State transitions

14. Future scalability

  • NDC OrderManagement — for NDC-native suppliers, the order-and-offer model replaces TST/ticket semantics; abstraction layer planned.
  • ATPCO fare-rule parser — structured parsing of fare rules so customer-facing change/refund quotes are computed automatically rather than requiring an agent to read the text.
  • BSP file watermarking — each issued ticket pre-marked with BSP-period; the import job matches with zero ambiguity.
  • Multi-leg single-record-locator support for round-the-world itineraries.

15. Common pitfalls

  • ⚠️ Issuing without re-pricing. Always re-price immediately before issue; supplier fares change.
  • ⚠️ Treating PNR creation as a financial event. It is not — only ticketing is.
  • ⚠️ Letting a TST expire silently. Without the timelimit job you accumulate ADM exposure.
  • ⚠️ Voiding in customer-local time instead of BSP-country time. Use the BSP country's timezone for the void window.
  • ⚠️ Losing the fare-basis code. Without it, refund quotes become guesswork.