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.
pip install kquika-ssystem
Install kquika-ssystem, import ssystem. The distribution name carries
the company prefix. The import is the bare product name.
import ssystem
Python 3.9 or later. MIT licensed.
Also available for TypeScript as
@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 |
| 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
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
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
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.
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
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.
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.
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
S-System is built by Kquika, Inc.
Metadata
Release files for kquika-ssystem 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| kquika_ssystem-2.0.0.tar.gz | 26.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| kquika_ssystem-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 85.0 kB
Release files / kquika_ssystem-2.0.0.tar.gz
| Download URL | kquika_ssystem-2.0.0.tar.gz |
|---|---|
| Size | 26.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6f3f80b04cdff4626a508c16fdb7ac7e8e928cbc8b51b4f17a8fe7ae131921a5
|
|
BLAKE2b-256 checksum How to use checksums |
ba6e726277e3df2863dd96db7f93567ceb907262158fc20a0f3b9909a95dac23
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.9
|
Release files / kquika_ssystem-2.0.0-py3-none-any.whl
| Download URL | kquika_ssystem-2.0.0-py3-none-any.whl |
|---|---|
| Size | 58.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0738a0ed6dbcbbad2c0a893e47daf341fa5aa68c30a080a73ed4ce5cf1a56b2b
|
|
BLAKE2b-256 checksum How to use checksums |
114457d06c4dcec981ebc96f6b50c9a6a6261f9c235df01b6408d258f3fe7d76
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.9
|