> ## Documentation Index
> Fetch the complete documentation index at: https://voyant.travel/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Flights

> The live-API flights vertical: a provider-neutral connector contract, multi-connection fan-out search with itinerary fingerprinting, booking-time snapshot capture, and a swappable reference-data provider.

`@voyant-travel/flights` is the flights vertical for OTA, tour-operator, and DMC deployments. Flights are modeled as supplier integrations and sourced inventory: Voyant is not an airline or a flight-operator system, and the module never tries to be one.

Flights are unlike every other vertical. There is no slow-moving inventory to pre-project, no marketing copy to overlay on "LHR to JFK on BA177", and no semantic-search use case (customers specify route, dates, and passengers, then expect live offers). The module reflects that: it adopts only the catalog-plane surfaces that add real value (booking snapshots, provenance, webhooks, source disconnection) and opts out of the rest (search-index projection, editorial overlays, embeddings, drift detection). Live multi-connection fan-out replaces the index.

The package is opt-in. Templates that need flights (a tour-package vertical, a corporate-travel storefront, a cruise reseller offering coordinated flights) register it; the rest skip it entirely.

## Key concepts

These terms come from the shared [glossary](/docs/concepts/glossary) and the flight contract.

* **The flight lifecycle: search, price, book, order**. A flight provider integrates by implementing five core methods on the `FlightConnectorAdapter`: `searchFlights` (returns offers), `priceOffer` (revalidates an offer), `bookFlight` (creates an order, held or ticketed), `getOrder`, and `cancelOrder`. If any of the five cannot be implemented, the connection is not a flight connection.
* **Slice-based search**. A search request carries `slices`, where each slice is `{ origin, destination, departureDate }`. One slice is a one-way, two is a round-trip, three or more is a multi-city or open-jaw. Slices generalize cleanly where flat origin / destination / return-date shapes cannot.
* **Intent-driven booking**. The book request carries a `paymentIntent` discriminated union. `{ type: "hold" }` returns a confirmed order to ticket later, `{ type: "card", ... }` returns a ticketed order, and `{ type: "ticket_on_credit" }` covers the GDS agency model. The default is hold. Consumers declare intent rather than branching on capability discovery.
* **Capability-gated methods**. Alongside the five core methods sit optional ones declared per connection: holds, seat maps, seat selection, ancillaries, check-in, exchange, refund, void, special service requests, and branded fares. An adapter that does not declare a capability stubs the method with `CAPABILITY_NOT_SUPPORTED`.
* **Itinerary fingerprint**. A deterministic key derived from a `FlightOffer`'s segments (carrier codes, flight numbers, airports, times, cabin). Two providers selling the same flight produce identical fingerprints, which is how fan-out deduplicates.
* **Booking snapshot**. At book time the module captures the frozen `FlightOffer` plus `FlightOrder`, the segments, the PNR, the fare breakdown, and the source pointer into a `booking_catalog_snapshot` row. This is the one catalog-plane surface flights fully adopt, because refunds, exchanges, and audits months later need the frozen offer and order.

### How it relates to the catalog and Connect

The flight contract shapes (`FlightConnectorAdapter`, `FlightOffer`, `FlightOrder`, `MergedFlightOffer`, capability ids, `paymentIntent`) mirror voyant-cloud's `connect-flight-contract` so adapters stay portable between Voyant and a Voyant Catalog flight integration. [Connect flights](/docs/connect/connect-sdk) provide the connector ecosystem (Hisky, Amadeus, Duffel, Sabre, Travelport NDC, and operator-built GDS adapters), each implementing the same contract this module orchestrates.

## What it owns

* The flight contract: `./contract/types` (offers, orders, segments, requests, capability ids, the `paymentIntent` union), `./contract/adapter` (the `FlightConnectorAdapter` interface), and `./contract/schemas` (Zod runtime schemas for HTTP, queue, RPC, and adapter boundaries).
* Multi-connection orchestration: `./orchestration/fingerprint` (the itinerary fingerprint helper) and `./orchestration/fan-out` (parallel search across all of an operator's flight connections, per-provider timeout and circuit breaker, dedupe by fingerprint, merged result with a cheapest offer plus alternates).
* Booking-time snapshot capture under `./snapshot`, which builds the catalog plane's capture input from a `FlightOffer` and `FlightOrder` pair.
* The reference-data layer: the `ReferenceDataProvider` contract under `./reference/contract`, plus shipped implementations including `./reference/local-postgres` (plain tables in the operator's own database, no external service) and `./reference/static-bundle`.
* The `/v1/{admin,public}/flights/search` and `/v1/{admin,public}/flights/orders/*` routes, mounted by templates that need flights.

## Working with it

### Multi-connection fan-out search

An agency wired to several providers gets one merged result set without writing fan-out, dedupe, or partial-failure handling. One slow or failing provider does not tank the search; whichever providers respond come back, and the rest are flagged per connection.

```ts theme={null}
import { fanOutFlightSearch } from "@voyant-travel/flights/orchestration/fan-out"

const result = await fanOutFlightSearch({
  adapters: [hiskyAdapter, amadeusAdapter, charterConsolidatorAdapter],
  request: {
    slices: [
      { origin: "LHR", destination: "JFK", departureDate: "2026-10-15" },
      { origin: "JFK", destination: "LHR", departureDate: "2026-10-22" },
    ],
    passengers: { adults: 2 },
    cabin: "economy",
  },
  perConnectionTimeoutMs: 5000,
})

// result.offers: merged across connections, deduped by itinerary fingerprint,
//                 sorted cheapest first.
// result.perConnection: status and latency per connection.
```

### Validate at a wire boundary

Use the shipped Zod schemas rather than re-declaring runtime validators when you expose the contract over HTTP, queues, or RPC.

```ts theme={null}
import { flightBookRequestSchema } from "@voyant-travel/flights/contract/schemas"
import type { FlightBookRequest } from "@voyant-travel/flights/contract/types"

const request: FlightBookRequest = flightBookRequestSchema.parse(await req.json())
```

### Book with an explicit payment intent

```ts theme={null}
const heldOrder = await adapter.bookFlight(ctx, {
  offerId,
  passengers,
  paymentIntent: { type: "hold" }, // returns a confirmed order; call ticketOrder later
})

const ticketedOrder = await adapter.bookFlight(ctx, {
  offerId,
  passengers,
  paymentIntent: { type: "card", /* card details */ }, // returns a ticketed order
})
```

### Hydrate reference data from the operator's own database

Airlines, airports, and aircraft are global IATA-coded reference data, not flight catalog data. They sit behind a swappable provider. The simplest valid first-party option is plain Postgres tables in the operator's own database, with no external service and no network call.

```ts theme={null}
import { createLocalPostgresReferenceProvider } from "@voyant-travel/flights/reference/local-postgres"

const reference = createLocalPostgresReferenceProvider({ db })

const ba = await reference.getAirline("BA")
// → { iataCode: "BA", icaoCode: "BAW", name: "British Airways", country: "GB" }
```

Voyant Data is the hosted default provider. Static bundles, internal data lakes, third-party services (OAG, Cirium), and GDS-bundled feeds are all first-class alternatives, declared per deployment. No consumer-facing route is aware of which provider is underneath.

## Links to other modules and Connect

* **catalog and bookings**. Flights opt into the booking snapshot graph: a booked flight writes a `booking_catalog_snapshot` row with `entity_module: "flights"` and the frozen offer, order, segments, fare breakdown, and source pointer.
* **provenance and webhooks**. Every flight order carries the standard provenance tuple, and `catalog.booking.committed` and `.cancelled` events fire on the standard webhook pipeline.
* **source disconnection**. If a provider connection is hard-disconnected, preserved booking snapshots stay queryable for refund and audit while live capability against that source stops.
* **Connect**. Flight adapters reach the module through Connect's connector ecosystem or as operator-built packages. Because the contract is borrowed from voyant-cloud's `connect-flight-contract`, the same adapter works on both sides. See the [Connect SDK](/docs/connect/connect-sdk).

What flights deliberately stay out of: search-index projection, editorial overlays, embeddings and semantic search, indexed pricing tiers, and drift detection. Live fan-out is the design, so there is nothing to index, overlay, embed, or drift-check.

## React package

`@voyant-travel/flights-react` is the flights client tier: headless data hooks and a fetch client at the root and `./hooks`, `./client`, and `./query-keys`, plus styled UI and full page compositions under `./ui`. The styled subpaths add optional peers (`@voyant-travel/ui`, `@voyant-travel/relationships-react` for CRM-backed contact and billing pickers, and the finance checkout UI).

`FlightsPage` renders search, filtering, the per-leg round-trip picker, the offer detail sheet, and the booking handoff. The route owns URL validation and navigation:

```tsx theme={null}
import { FlightsPage } from "@voyant-travel/flights-react/ui"

<FlightsPage
  search={search}
  onSearchChange={(next, options) => updateRouteSearch(next, options)}
  onBookOffer={({ outboundOfferId, returnOfferId, passengers, cabin }) =>
    goToBooking({ outboundOfferId, returnOfferId, passengers, cabin })
  }
/>
```

`FlightBookingPage` renders the repricing, ancillaries, seat-map, passenger, billing, payment, and confirmation flow. Router behavior, booking submission, and payment capabilities are callbacks or slots, so applications keep deployment-specific ownership.

## Next steps

<CardGroup cols={2}>
  <Card title="Connect SDK" icon="plug" href="/docs/connect/connect-sdk">
    The flight connector ecosystem and the shared contract.
  </Card>

  <Card title="Modules overview" icon="grid-2" href="/docs/platform/modules">
    How verticals compose into a Voyant app.
  </Card>

  <Card title="Data model" icon="table" href="/docs/concepts/how-it-is-built">
    How schemas, links, and snapshots are authored.
  </Card>

  <Card title="Glossary" icon="book-open" href="/docs/concepts/glossary">
    The shared domain language flights speaks.
  </Card>
</CardGroup>
