Metadata-Version: 2.4
Name: kquika-ssystem
Version: 2.0.2
Summary: Kquika's S-System: Predict flight disruption, price the passenger-rights exposure it carries, and rebook before it costs you.
License: MIT
Keywords: s-system,airline-operations,aviation,disruption-prediction,passenger-rights,eu261,rebooking,ancillary-pricing,airport-operations,api-client
Author: "Kquika, Inc."
Author-email: support@kquika.com
Requires-Python: >=3.9,<4.0
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Requires-Dist: attrs (>=22.2.0)
Requires-Dist: httpx (>=0.20.0,<0.29.0)
Requires-Dist: python-dateutil (>=2.8.0,<3.0.0)
Project-URL: Documentation, https://www.s-system.cloud/documentation
Project-URL: Homepage, https://www.s-system.cloud
Description-Content-Type: text/markdown

# kquika-ssystem

The Python client for S-System, the airline operations platform from Kquika.

Flight operations and airport operations: live status, on-time performance,
route analytics, stand utilization and terminal congestion, from the platform
that forecasts disruption up to four days out.

```bash
pip install kquika-ssystem
```

**Install `kquika-ssystem`, import `ssystem`.** The distribution name carries
the company prefix. The import is the bare product name.

```python
import ssystem
```

Python 3.9 or later. MIT licensed.

Also available for TypeScript as
[`@kquika-inc/s-system`](https://www.npmjs.com/package/@kquika-inc/s-system).

## Data provenance

Every flight carries `data_confidence`, so your code can read the origin of a
record before acting on it.

| Value | Meaning |
|---|---|
| `live_feed` | Observed from the live provider feed. |
| `database` | Observed on an earlier read and persisted. |

Every record this API returns is an observation. `live_feed` is the current
reading from the provider; `database` is the same reading persisted from an
earlier call, so it may lag the feed. Neither is an estimate.

Fields are left null where the source carries no value. A null
`delay_minutes` means no time was reported.

## Denominators

`on_time_percentage` is calculated over `measured_flights`, and both counts
are in the response. Flights that reported no time are excluded from that
denominator, so other ratios can be derived from the same payload.

`on_time` counts departures within `on_time_threshold_minutes`, which is
returned on the response and defaults to 15. Read it rather than assuming it.

`on_time_percentage` is null when the figure cannot be measured, and
`ontime_unavailable_reason` says why. Three cases:

- Nothing was measured.
- Coverage was too thin to describe the operation.
- The sample was censored: every flight carrying a time was late, and none
  departed early or on schedule. This happens when the upstream feed publishes
  a delay only when there is one, so "on time" and "unknown" collapse into the
  same absence. A rate over only late flights reads near zero whatever the
  real punctuality is, so no rate is returned at all.

`gate_conflicts` is keyed on airport and gate together, so gate labels are
only compared within a single station.

## What you can call

| | Plan |
|---|---|
| **List flights** with origin, destination and date filters | Standard |
| **One flight** by number | Standard |
| **Metrics**: on-time performance, average delay, gate conflicts | Standard |
| **Search** by number, route or date | Standard |
| **Route analytics**: performance grouped by route | Professional |
| **Refresh** the live feed on demand | Professional |
| **Airport overview**: movements, delay, stand utilization | Standard |
| **Passenger heatmap**: density by zone, measured or modeled | Professional |
| **Congestion**: current level plus 1h and 3h forecast | Professional |
| **Disruption lists**: the flights most at risk, with causes and actions | IOCC Briefing |
| **Aircraft rotations**: how a delay travels through the day | Disruption Prediction or IOCC Briefing |
| **Passengers, crew and fuel**: counts, duty margins and tankering | The matching capability, or IOCC Briefing |
| **Stations and airfield congestion** | Airport Heatmap or IOCC Briefing |

Passenger intelligence is delivered through the application and through
scheduled data delivery. Contact your account manager about direct access for
your integration.

## Plans and rate limits

Each key carries an hourly request limit, set with your plan. Every response
reports it in `X-RateLimit-Limit`, with what remains in `X-RateLimit-Remaining`
and in the `quota` block, so read it there instead of hardcoding a number. A
refused request returns 429 with `Retry-After`, in seconds.

API access starts at Standard. Starter covers the dashboard and basic
passenger insights without programmatic access.

Capabilities follow the plan too. `GET /subscription` returns the feature
codes your account carries, so an integration can hide what it cannot reach
instead of surfacing a 403 to a user who cannot act on it.

---

# Using the client

## Getting started

```python
from ssystem import AuthenticatedClient
from ssystem.api.flight_operations import list_flights

client = AuthenticatedClient(
    base_url="https://www.s-system.cloud",
    token="sk_live_your_key_here",
    auth_header_name="X-API-Key",
    prefix="",              # the key goes in bare, with no "Bearer "
)

with client as c:
    res = list_flights.sync(client=c, origin="JFK", limit=25)

    if not res.success:
        print(res.message)
    else:
        for f in res.data.flights:
            print(f.flight_number, f.origin, f.destination, f.data_confidence)
```

`prefix=""` matters. The default prepends `Bearer `, and this API expects the
key on its own in `X-API-Key`.

**Check `success` before reading `data`.** Every response carries
`{success, data, message}`, and `data` is null when `success` is false.

## `data_confidence`

```python
from ssystem.models import FlightDataConfidence

for flight in res.data.flights:
    if flight.data_confidence == FlightDataConfidence.LIVE_FEED:
        schedule(flight)
```

`live_feed` is the current reading from the provider. `database` is the same
reading persisted from an earlier call, so it may lag the feed.

## Nulls

`None` carries meaning in each of these fields.

| Field | `None` means |
|---|---|
| `delay_minutes` | No time was reported. |
| `scheduled_departure` | No schedule source covers this flight. |
| `departure_gate` | Unassigned, or the source carries no gate. |
| `on_time_percentage` | Nothing was measured. |

Averaging a list that contains `None` as though it were zero will understate
delay on exactly the flights you know least about.

## Airport operations

```python
from ssystem.api.airport_operations import (
    get_airport_overview, get_airport_heatmap, get_airport_congestion,
)

ov = get_airport_overview.sync(client=c, airport_code="JFK")
print(ov.data.departures_today, ov.data.on_time_percentage,
      ov.data.gate_conflicts)

heat = get_airport_heatmap.sync(client=c, airport_code="JFK")
print(heat.data.data_source)            # measured, or modelled
for p in heat.data.points:
    print(p.zone, p.intensity, p.wait_time_minutes)

cong = get_airport_congestion.sync(client=c, airport_code="JFK", hours=24)
for r in cong.data:
    print(r.timestamp, r.congestion_level, r.avg_wait_minutes, "->", r.predicted_1h)
```

`avg_wait_minutes` covers queueing zones only: security, check-in,
immigration and customs. Gates and lounges are out of scope.

Points come from the sensor or survey readings an airport shares, and are
modeled where it shares none; `lidar_available` keeps its name for
compatibility and is true when readings are available. Check `data_source` on
the heatmap response before acting on occupancy or wait times. `measured` means a sensor, gate read or throughput count is behind the
figure. `modelled` means it is derived from terminal layout and time of day
with no sensor behind it, in which case two calls seconds apart can return
different values with no underlying event. Do not diff them to infer movement.


Heatmap and congestion require Professional. Overview is Standard.

## Flight metrics and route analytics

```python
from ssystem.api.flight_operations import get_flight_metrics, get_route_analytics

m = get_flight_metrics.sync(client=c)
print(m.data.on_time, "of", m.data.measured_flights, "measured")
print("of", m.data.total_flights, "scheduled")
```

Two denominators are returned. `on_time_percentage` divides by
`measured_flights`. Dividing by `total_flights` yourself treats an unreported
flight as on time.

`gate_conflicts` is null when no flight carried both a gate and a scheduled
time, which means the check could not run. Null and 0 carry different
meanings here.

```python
routes = get_route_analytics.sync(client=c, days=30)   # Professional
for r in routes.data:
    print(r.route, r.on_time_percentage, "over", r.measured_flights)
```

## Operations

The disruption lists, rotations, passengers, crew, fuel and stations your
operations team works from.

```python
from ssystem.api.operations import get_disruptions, get_rotation
from ssystem.models import GetDisruptionsKind

risk = get_disruptions.sync(client=c, kind=GetDisruptionsKind.DAILY)
for flight in risk.data["items"]:
    print(flight["flight_number"], flight["probability"], flight["action"])

day = get_rotation.sync(client=c, tail="N123XX", seed=45)   # a 45 minute what-if
```

Each needs the capability shown in **What you can call** and a key carrying its
permission. Dates are `YYYY-MM-DD` and default to today; times are UTC.

## Errors

| Code | Meaning |
|---|---|
| `unauthorized` | No valid key. Check `X-API-Key`. |
| `forbidden` | The key lacks the permission for this endpoint. |
| `plan_required` | Your plan does not cover this endpoint. |
| `rate_limited` | Back off for `retry_after_seconds`. |
| `not_found` | No such flight or station among yours. |
| `bad_request` | A parameter is missing or malformed; `message` says which. |
| `server_error` | Ours to fix. Retry once, then contact support. |

`error` is a stable code and safe to branch on. `message` is for a human and
its wording may change.

`plan_required` is a billing matter: route analytics and refresh need
Professional, as do heatmap and congestion.

On 429, wait for `retry_after_seconds` before the next call. Rejected
requests count toward the limit.

## Async

Every operation has an async form.

```python
page = await list_flights.asyncio(client=c, limit=25)
```

## Support

An API key, a plan change, or a capability you need that your plan does not
carry: [www.s-system.cloud](https://www.s-system.cloud)

S-System is built by Kquika, Inc.
