Skip to main content

Flight Data

Nexa's flight-predictor consumes real-world flight data from multiple sources to detect disruptions, predict cancel/delay risk, and trigger case provisioning automatically. Unlike the booking and wallet integrations (which are tenant-scoped), the flight predictor is a shared platform service — it consumes public flight + weather data with no PII, and serves every tenant from a single deployment.

What we use it for

CapabilityVendorUse
Flight schedule + state streamAeroAPIPrimary flight-state source
Backup flight stateAviationStackFailover when AeroAPI degrades
Tracking enrichment (selective)FlightAwareSpecific flight metadata
Weather dataNOAA / equivalentCancel/delay prediction features

Architecture

Disruption detection

The flight predictor:

  1. Subscribes to AeroAPI's flight-state stream.
  2. Normalizes events to the canonical FlightStateEvent shape.
  3. Runs the dual-head model (cancel probability + delay minutes) for every flight in the operating window.
  4. Persists predictions to its own store.
  5. When a confirmed cancellation or significant delay is detected (probability > policy threshold or partner-confirmed event), publishes a FlightDisrupted event on the per-tenant workflow topic.

The per-tenant topic prefix is resolved from the flight's airline URN — the predictor is shared platform, but the events it emits are tenant-scoped because they carry tenant-relevant data.

Why a shared platform service?

A flight-data ingest pipeline doesn't need to be per-tenant — flight schedules and state are public information, identical regardless of which airline owns the flight. Running per-tenant copies of the predictor would:

  • Multiply AeroAPI burn rate by tenant count (AeroAPI is paid per request).
  • Multiply model-inference cost by tenant count.
  • Create operational divergence (one tenant's predictor running an old model version).

Instead, a single predictor runs the model once per flight per inference cycle and fans the result out to whichever tenant owns each flight via per-tenant workflow topics. This is the shared-platform pattern described in Architecture.

Authentication

AeroAPI: API key, Nexa-managed (the credential is held by Nexa, not by the tenant).

Tenants do not procure or manage AeroAPI credentials. The cost is bundled in the Nexa subscription.

Rate limiting & cost control

AeroAPI charges per request. The platform applies several controls to keep cost predictable:

  • Per-flight ingest cadence — flights closer to departure are ingested more frequently (every 1–5 minutes); flights > 12 hours out are ingested every 30 minutes.
  • Per-airport prioritization — airports with active disruptions get higher cadence than quiet airports.
  • Platform-wide traffic shaping on AeroAPI requests keeps total burn under the configured budget regardless of worker count.

The credit-burn dashboard (operator role ADMIN) shows tenants their share of consumption — even though they don't pay AeroAPI directly, they see the resource attribution.

Failover

When AeroAPI returns 5xx or stops streaming, the worker fails over to AviationStack. Failover is per-flight, not per-cluster — a degraded AeroAPI doesn't disable ingest for flights that are still resolving via AeroAPI.

The two sources have slightly different schemas; the canonical FlightStateEvent mapper handles both. AeroAPI is preferred when both are available — its event stream is higher-fidelity.

Disruption thresholds

A flight transitions to "disrupted" when any of the following:

  • Vendor-confirmed cancellation: status: CANCELLED from AeroAPI / AviationStack.
  • Vendor-confirmed delay: scheduled-vs-estimated departure delta > policy threshold (typically 4 hours).
  • Predicted high-confidence cancellation: model probability > tenant-configured threshold (default 80%) with > 3 hours' lead time.

The first two are deterministic; the third is predictive. Predictive disruptions create shadow contingency cases (a use case named B1 in the platform's use-case catalog) — preliminary cases that the system pre-computes inventory for, ready to upgrade to a real case the moment the airline confirms.

Tenant routing

Each flight URN carries the operating airline as part of the flight identifier (urn:flight:LA500@20260513:vendor:aeroapi). The predictor resolves the airline → tenant via the platform airline registry and publishes to {airline}.flights.disrupted.

A single tenant's case orchestrator subscribes only to its own topic. There is no fan-out — topic-level access controls prevent one tenant from seeing another tenant's flights.

Real-time fan-out to operators

The disruption dashboard in the operations console shows flights at risk in real time. The data flow:

  1. The predictor writes the prediction to its store and publishes a low-volume real-time event on the operator API's presence channel.
  2. Operator UIs subscribed to the dashboard receive the event over the same live session they use for case-state changes.
  3. The dashboard re-renders the at-risk list without polling.

Operators see the predictor's confidence and the underlying features (weather warnings, airport congestion, day-of-week / season factors) and can opt to manually pre-stage inventory ahead of the airline's official disruption call.

Data retention

  • Flight events: 90 days.
  • Predictions: 365 days (used for the accuracy report).
  • Disruption signals: forever (linked to cases).

Compliance

The flight predictor consumes no PII. Flight schedules, weather, airport state are all public information. The predictor's database has no airline-specific PII; the airline data appears only in the case provisioned downstream.

Onboarding (tenant)

A new tenant doesn't onboard with the predictor — it's already running. The tenant just needs to:

  • Provide the airline URN (urn:airline:<token>) for routing.
  • Configure the predictor threshold in tenant policy (default 80%).
  • Optionally, add a list of monitored airports / routes (for prioritized ingest cadence).

That's it. The first disruption signal flows automatically.

Cross-reference

Was this helpful?