Metadata-Version: 2.4
Name: kquika-ssystem
Version: 1.0.7
Summary: 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
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. |

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.

`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 |
| **LiDAR heatmap**: passenger density by zone | Professional |
| **Congestion**: current level plus 1h and 3h forecast | Professional |

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

## Plans

Your rate limit follows your plan. Read it from the response headers instead
of hardcoding it.

| Plan | Rate limit | Burst |
|---|---|---|
| Standard | 100 requests/minute | 200/minute |
| Professional | 500 requests/minute | 1,000/minute |
| Enterprise | 2,000 requests/minute | 5,000/minute |

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="SDQ", 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="SDQ")
print(ov.data.departures_today, ov.data.on_time_percentage,
      ov.data.gate_conflicts)

heat = get_airport_heatmap.sync(client=c, airport_code="SDQ")
if not heat.data.lidar_available:
    # This station has no LiDAR coverage, so points is empty.
    print("No LiDAR here.")
else:
    for p in heat.data.points:
        print(p.zone, p.intensity, p.wait_time_minutes)

cong = get_airport_congestion.sync(client=c, airport_code="SDQ", 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.

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)
```

## 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`. |

`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, per_page=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.
