Skip to content

Flights

The Flights navigation group in Arkana covers everything to do with air travel: the cached fares that price offers, the routes that keep that cache warm, the actual flight bookings and their ticketing lifecycle, an observability log, and the settings that steer automated search and repricing.

Item Manages
Flights (Aerticket) Live Aerticket flight-search console (read-only)
Flight Bookings Air bookings and their ticketing lifecycle
Flights Logs Observability timeline for Aerticket bookings (nested under Flight Bookings)
Flight Cache Routes Configured routes the populator searches to fill the cache
Dynamic Flights Cache Cached fare snapshots that price offers
Re-Pricing Price tolerance settings, applied to both checkout booking and ticketing (admin)
Search Filters Filters applied to automated cache searches (admin)

The Flights (Aerticket) item is a live search console — a Livewire page that queries Aerticket directly (one-way, round-trip or multi-city, up to 9 passengers) and lets an operator book a fare from the results. It is not database-backed; results are held for the session only.

Dynamic Flights Cache holds the fare snapshots that offers are priced from. Each entry belongs to a cache route, has per-leg segments, and can be bound to offers.

Cached prices are reference totals for a party of 2 adults, not per-person amounts — the populator always searches with DEFAULT_PAX_COUNT = 2, so base_price, tax and total_price are 2-adult totals (baggage upsell is quoted per passenger). Downstream consumers derive the per-person fare by dividing by the reference party size, then multiply by the actual party size — never by dividing a cached total by the real passenger count. The exact rule and consumer list are in Dynamic Flight Cache.

Cache entries carry a status (pending, searching, completed, failed, expired, timed out) and an expiry. The table is a rich operator comparison view — route, stops, arrival compliance, price, baggage, fare position — grouped by route. Bulk actions execute searches (re-caching completed entries) and delete unbound caches (keeping any entry bound to an offer, since those act as pricing history). A stats widget shows totals and the Look-to-Book ratio; see Look-to-Book (L2B) Tracking.

Flight Cache Routes are the configured origin/destination chains (with trip duration and domestic/multi-city flags) that the populator repeatedly searches to keep the cache warm.

A route is Active, Auto-Invalidated, or Inactive. Auto-invalidation is automatic and threshold-based: after a configured number of consecutive empty searches the route stops receiving search jobs. The per-record Reactivate action clears the invalidation and resumes searches; a View Caches action deep-links to that route’s cache entries. (There is no bulk-invalidate control in Arkana — invalidation happens in the background, and Reactivate is the manual reversal.) Route health and cache statistics are shown on the view page. See Dynamic Flight Cache.

Flight Bookings manages air bookings, whether created from the Aerticket API, from checkout, or entered manually. Each booking tracks a ticket status: pending, not_issued, pending_reprice_approval, ticketing, issued, voided or failed.

The ticketing lifecycle is driven by table/row actions that dispatch queued Aerticket jobs:

  • Issue Ticket / Fastlane Ticketing — promote a booking toward issued (fastlane requires at least 5 minutes since booking creation).
  • Approve Repricing / Reject Repricing — shown only at pending_reprice_approval, when a fare changed between booking and ticketing; approving continues issuance at the new price, rejecting resets to not_issued.
  • Retrieve Booking — pulls the latest PNR/segment status from Aerticket.
  • Cancel Booking / Void — with loud warnings when a ticket is already issued.
  • View Available Ancillaries — book baggage/meal ancillaries (only before issuance).

The ticketing → issued promotion itself happens asynchronously in the queued jobs, gated by FlightBooking::canIssueTicket(). Rebooking is only offered for bookings with an issued ticket.

Two things now happen without anyone pressing a button. A card payment confirmed through Redsys reserves the flight immediately, so the booking passes straight through Pending Flight Booking; an offline confirmation (bank transfer, or a card charged by hand) does not, and waits for the operator already handling it. And because the airline holds our price only until midnight of the booking day, unissued reservations are re-priced before that deadline. Small moves are absorbed within the configured tolerance and announced; larger ones raise the usual Approve Repricing decision, just earlier than it used to appear. When a fare is beyond saving the reservation is left alone — the seat is worth more than the price — and it shows up under the Fare expired, needs attention filter for someone to decide by hand. The exception is a reservation the airline itself cancelled for never being ticketed: there the seat is already lost, so a replacement is booked automatically. Cancellations made from Arkana are never re-booked. See AerTicket Integration for the API flows and Flight Search UI for the search interface.

Operations sometimes buys a leg of a paid booking outside Arkana, usually in Aerticket Cockpit. Our Aerticket API cannot see those PNRs, because Cockpit and the API HUB are separate Aerticket products, so they can’t be retrieved or imported. Without a record, the leg stays unbooked, the booking sits in Flight Booking Failed, the client’s trip page shows the sold flight, and the real cost never reaches the margin. An admin therefore enters the flight by hand on the booking.

Where: booking view, Flight section, the leg’s Mark as booked outside header action. Only admins see it, and only while the leg has no flight booking and the booking is in Pending Flight Booking, Flight Booking In Progress or Flight Booking Failed (the same conditions as Book Flight / Retry).

Form:

  • PNR: one code, or several for a split booking (QMTGZL, OGUBHP). Saved in upper case.
  • Total price paid in €, covering all travellers on the leg.
  • Cabin and optional Notes.
  • Flight rows: airline name, flight number (AI 2568 or a bare 2568), from/to airport, departure and arrival. Times are local to each airport and saved exactly as typed. A domestic leg has one Flight list. An international leg has an Outbound list and a Return list. Each list takes up to 4 rows (Add connection), and each row must depart from the airport where the previous row lands, after it lands.

What saving does:

  • Creates one Flight Booking for the leg with source Manual Entry, marked confirmed, paid and ticket issued, in EUR. It is not an Aerticket booking, so Issue Flight does not apply and it doesn’t appear in Flights Logs.
  • Replaces that leg’s flight on the booking. The booking view, the client trip page and Trips to Deliver then show the entered flight. The sold flight is kept in the checkout snapshot, and the activity log records the before and after.
  • Leaves the client price, the offer and the other legs unchanged. The cost breakdown compares the price entered with the leg’s checkout fare, and the margin absorbs the difference.
  • Once every leg has a flight booking, the booking moves to Flights Confirmed and the save notification says so.

Correcting it: legs entered by hand get an Edit external flight action (admins only) that opens the same form, pre-filled. A leg booked through Arkana cannot be replaced this way.

Date warning: the entered flight can land on different days from the sold one. The check compares days only, not times: the departure for a domestic leg, and the outbound and return departure and arrival for an international leg. When the days differ, the save notification stays on screen until dismissed and the leg shows a permanent Dates differ from the sold flight line. Itinerary days, hotels and insurance were built on the sold dates, so review them. Saving is never blocked, and nobody else is notified.

Known gaps:

  • In the cost breakdown, a manual leg’s link points to Flights Logs, which excludes manual entries, so the link opens a not-found page.

Source: backend/app/Filament/Resources/Bookings/Actions/MarkLegBookedOutsideAction.php, backend/app/Services/Booking/OutsideFlightBookingService.php

Flights Logs is a read-only observability view over Aerticket-sourced flight bookings (manual bookings are excluded — they have no PNR/ticket lifecycle). It reuses the same model and permission as Flight Bookings and is nested under it in the navigation.

Each log exposes the PNR, a deep link to the parent booking, route, ticket/PNR/retrieve statuses, pricing (including any reprice difference and the Aerticket flow id to quote to Aerticket support), and an activity timeline that merges the audit log, retrieve history and a synthetic reprice event. The same audit data is shipped to Loki for centralized log search.

Both settings pages are admin-only.

Re-Pricing sets the tolerance (minimum and maximum EUR) for fare changes. Within tolerance, the new price is auto-accepted; outside it, the booking enters pending_reprice_approval for manual approval. The same tolerance governs both moments a fare can move: at ticket issuance, and at the hourly sweep that re-prices reservations whose fare is about to expire.

Search Filters configures the filters sent to Aerticket for automated cache searches only (not manual admin searches or route validation): baggage policy, direct-flights-only, max stops, excluded airlines, cabin classes, airline alliances, fare sources, closed user groups, and a latest-arrival-time flag. The page also documents (read-only) the code-level ranking policy used to prune and sort results.

BookFlight is a manual flight-booking page reached only via URL — it is hidden from the navigation (shouldRegisterNavigation = false) and launched from the “Book Flight” action on the search console’s results. It loads the selected fare from a per-user session, lets the operator pick or create passengers (validating the exact adult/child/infant breakdown against the search), verifies the fare, and dispatches the Aerticket create-booking job.

It enforces two staging safeguards so real, non-refundable purchases can’t happen outside production (via EnvironmentGuard::isStagingOrUat(), which fails safe to “staging” unless explicitly production):

  • Flydubai (FZ) bookings are blocked in staging/UAT.
  • Instant-purchase fares are blocked in staging/UAT (checked after fare verification).