Trakt System SDK
Client libraries for the Trakt System Integrations API: fleet predictions and maintenance forecasts, in a few lines of code.
Trakt System predicts which components on your fleet need attention, when, and what to do about them. This SDK gives you that data directly, with authentication, retries, and rate limits handled for you.
Full endpoint reference, including request and response schemas for every route: https://trakt.tech/api-documentation
Install
Python
pip install kquika-trakt # core
pip install "kquika-trakt[pandas]" # with DataFrame support
The distribution is named kquika-trakt and the import is trakt. That
difference is normal: the package you install and the module you import do not
have to share a name.
Node / TypeScript
npm install @kquika-inc/trakt
Requires Node 18 or newer. TypeScript types are included.
Quickstart
Python
from trakt import Trakt
trakt = Trakt(token="YOUR_API_KEY") # or set TRAKT_TOKEN
# What can this token do?
cfg = trakt.config()
print(cfg.access_level, cfg.max_predictions, cfg.can_export)
# Per-component predictions, most urgent first
for c in trakt.components():
print(c.name, c.aircraft_tail_number, c.health,
c.failure_probability, c.recommended_action)
# The next 90 days of maintenance, soonest first
for item in trakt.forecast(days=90):
if item.is_overdue:
print("OVERDUE:", item.tail_number, item.component_name)
# Straight to a DataFrame for planning
df = trakt.components_dataframe()
# Fleet-level rollup that matches the dashboards: health, composite average
# confidence, prediction coverage, and 30-day survival
summary = trakt.fleet_summary()
print(summary.fleet_health, summary.avg_confidence, summary.survival_30d)
# Everything that changed since you last looked. Not charged against your
# interactive call allowance, so you can poll it every thirty seconds.
for change in trakt.iter_delta(since="2026-06-01T00:00:00Z"):
print(change.component_name, change.health_band, change.days_until_due)
print("resume from", trakt.last_cursor)
# Why a prediction says what it says
why = trakt.explanation(1421)
print(why.risk_level, why.method, why.most_likely_failure_mode)
for driver in why.top_contributors[:3]:
print(" ", driver.feature, driver.contribution, driver.direction)
Node / TypeScript
import { Trakt } from "@kquika-inc/trakt";
const trakt = new Trakt({ token: process.env.TRAKT_TOKEN! });
const cfg = await trakt.config();
console.log(cfg.access_level, cfg.max_predictions);
// Per-component predictions, most urgent first
const components = await trakt.components();
for (const c of components) {
console.log(c.name, c.aircraft_tail_number, c.health, c.recommended_action);
}
// The next 90 days of maintenance, soonest first
const forecast = await trakt.forecast({ days: 90 });
for (const item of forecast) {
if (item.is_overdue) console.log("OVERDUE:", item.tail_number, item.component_name);
}
// Fleet-level rollup that matches the dashboards
const summary = await trakt.fleetSummary();
console.log(summary.fleet_health, summary.avg_confidence, summary.survival_30d);
// Everything that changed since you last looked. Not charged against your
// interactive call allowance, so you can poll it every thirty seconds.
for await (const change of trakt.iterDelta({ since: "2026-06-01T00:00:00Z" })) {
console.log(change.component_name, change.health_band, change.days_until_due);
}
console.log("resume from", trakt.lastCursor);
// Why a prediction says what it says
const why = await trakt.explanation(1421);
console.log(why.prediction?.risk_level, why.explanation?.method);
Full endpoint coverage
Both clients cover every token-callable endpoint. The table maps each method to the route it calls, so a spec or a server log line ties back to a call site.
| Method (Python / Node) | Endpoint |
|---|---|
config / config |
GET /api/integrations/config |
health_check / healthCheck |
GET /api/health-check |
token_info / tokenInfo |
GET /api/token/info |
integration_status / integrationStatus |
GET /api/integrations/status |
components / components |
GET /api/integrations/components/extended |
available_predictions / availablePredictions |
GET /api/integrations/predictions/available |
forecast / forecast |
GET /api/integrations/planner/forecast |
planner_grid / plannerGrid |
GET /api/integrations/planner/grid |
failure_windows / failureWindows |
GET /api/integrations/predictions/failure-windows |
failure_instances / failureInstances |
GET /api/integrations/predictions/failure-instances |
probability_between / probabilityBetween |
GET /api/integrations/predictions/probability-between |
select_predictions / selectPredictions |
POST /api/integrations/predictions/select |
export_predictions / exportPredictions |
POST /api/integrations/predictions/export |
convert_prediction / convertPrediction |
POST /api/integrations/planner/convert-prediction |
submit_optimizer_feedback / submitOptimizerFeedback |
POST /api/integrations/optimizer/feedback |
aircraft / aircraft |
GET /api/integrations/aircraft/extended |
fleet_export / fleetExport |
GET /api/integrations/fleet/export |
fleet_summary / fleetSummary |
GET /api/integrations/fleet/summary |
scenarios, create_scenario / scenarios, createScenario |
GET, POST /api/integrations/scenarios |
asset_configurations, create_asset_configuration / assetConfigurations, createAssetConfiguration |
GET, POST /api/integrations/asset-configurations |
maintenance_programs / maintenancePrograms |
GET /api/integrations/maintenance-programs |
submit_sensor_data / submitSensorData |
POST /api/v1/sensor-data/batch |
submit_aircraft / submitAircraft |
POST /api/v1/aircraft/batch |
submit_components / submitComponents |
POST /api/v1/components/batch |
submit_maintenance / submitMaintenance |
POST /api/v1/maintenance/batch |
submit_work_orders / submitWorkOrders |
POST /api/v1/work-orders/batch |
delta, iter_delta / delta, iterDelta |
GET /api/integrations/predictions/delta |
bulk_export / bulkExport |
GET /api/integrations/fleet/bulk-export |
explanation / explanation |
GET /api/integrations/predictions/{id}/explanation |
explanations / explanations |
POST /api/integrations/predictions/explanations/bulk |
convert_predictions_bulk / convertPredictionsBulk |
POST /api/integrations/planner/convert-predictions/bulk |
quota / quota |
GET /api/integrations/quota |
Two entries in that table are on their way out. select_predictions and
export_predictions stop answering on 2026-12-31; use delta and
bulk_export instead. Both clients warn you once per endpoint when they see the
sunset header on a response, so you find out from your own logs rather than from
the endpoint going quiet.
Staying in sync
Polling for changes used to mean spending your call allowance on requests that mostly returned nothing new. The change feed exists so it does not.
cursor = load_cursor() # whatever you stored last run
page = trakt.delta(cursor=cursor, limit=500)
for change in page:
upsert(change)
if page.next_cursor:
save_cursor(page.next_cursor)
Or let the client follow the cursor to the end:
for change in trakt.iter_delta(cursor=cursor):
upsert(change)
save_cursor(trakt.last_cursor)
Each row is the current state of a component rather than a diff against a snapshot we do not hold, so a consumer that misses a page and resumes from its stored cursor converges on its own. There is no recovery path to write.
If you would rather be told than ask, register a webhook endpoint and Trakt posts to it on a health band change, a new critical prediction, or an overdue crossing. Configure that in the app under Integrations, Event Notifications.
Understanding a prediction
Every prediction can explain itself: which readings moved the estimate, in which direction, and how the risk divides across failure modes.
why = trakt.explanation(component_id)
print(why.explanation_text)
print("attribution from:", why.method)
for driver in why.top_contributors:
print(driver.feature, driver.contribution, driver.direction)
print("most likely mode:", why.most_likely_failure_mode)
print(why.failure_mode_probabilities)
A positive contribution raises failure risk and a negative one lowers it.
Read method before you cite any of it. It names how the attribution was
produced, and reporting a heuristic as a model output is the kind of mistake a
reviewer catches and you do not.
For a batch, explanations() takes up to fifty component ids in one call.
Working at fleet scale
# Two hundred conversions in one request, with per-row results
result = trakt.convert_predictions_bulk(
items=[{"component_id": cid} for cid in approved],
defaults={"work_type": "inspection"},
dry_run=True, # validate first, write nothing
)
print(result["succeeded"], "of", result["requested"])
for row in result["results"]:
if not row["success"]:
print("row", row["index"], "failed:", row["error"])
# The whole fleet in one pass, as a file
export = trakt.bulk_export(format="csv")
open(export["filename"], "w").write(export["content"])
Rows in a bulk conversion are independent, so a row that fails validation leaves
the rest of the batch intact. Read results rather than trusting the status
code. The call is not idempotent: repeating it creates a second set of work
orders.
Sending data in
The five batch methods accept up to 1000 records per call and report a partial
success rather than raising. A 200 does not mean every row landed, so read the
counts:
result = trakt.submit_sensor_data([
{"component_id": 1, "timestamp": "2026-02-13T09:00:00Z",
"temperature": 85.2, "external_id": "fdr-abc-001"},
])
print(result["stored"], result["duplicates"], result["rejected"])
for error in result["errors"]:
print(error["row"], error["reason"])
Rows that fail validation or that name a component outside your company are
rejected on their own, with the index they occupied in your array, while the
rest of the batch is stored. Supplying external_id makes retries idempotent: a
repeat of the same identifier at the same timestamp comes back as a duplicate
rather than being written twice.
Chunking above 1000 is left to you, so a partial failure stays attributable to a specific request instead of being hidden inside a loop the client ran for you.
Handling errors
Both clients raise typed errors, so you can catch the case you care about.
from trakt import (
AuthenticationError, PermissionError_, RateLimitError, EndpointRetiredError
)
try:
components = trakt.components()
except AuthenticationError:
print("The token was not accepted.")
except PermissionError_:
print("This token's access level does not cover that call.")
except RateLimitError:
print("An allowance is exhausted. The client already retried with backoff.")
except EndpointRetiredError as e:
print("That endpoint is gone. Use", e.successor)
import {
AuthenticationError, PermissionError, RateLimitError, EndpointRetiredError
} from "@kquika-inc/trakt";
try {
const components = await trakt.components();
} catch (e) {
if (e instanceof AuthenticationError) console.error("The token was not accepted.");
else if (e instanceof PermissionError) console.error("Access level does not cover that call.");
else if (e instanceof RateLimitError) console.error("An allowance is exhausted.");
else if (e instanceof EndpointRetiredError) console.error("Gone. Use", e.successor);
else throw e;
}
RateLimitError names which of the three allowances ran out. Call quota() to
read your position and the reset time rather than guessing.
Deprecation notices
When you call an endpoint scheduled for retirement, the response carries a
Sunset date and a link to its replacement. The client is the layer that hides
HTTP from you, so it surfaces that rather than swallowing it. Otherwise the
deadline arrives unread and the first signal is the endpoint going quiet.
Python raises a TraktDeprecationWarning, once per endpoint per client:
import warnings
from trakt import TraktDeprecationWarning
warnings.simplefilter("error", TraktDeprecationWarning) # fail your CI on one
warnings.simplefilter("ignore", TraktDeprecationWarning) # or silence it
Node calls console.warn by default, and takes a handler:
const trakt = new Trakt({
token: process.env.TRAKT_TOKEN!,
onDeprecation: (notice) => {
logger.warn({ path: notice.path, sunset: notice.sunset,
successor: notice.successor }, notice.message);
},
});
GET /api/integrations/deprecations returns the whole schedule as JSON, so a
build step can check your exposure without waiting to trip over it.
What the clients do for you
- Auth. Set the token once; every request carries the bearer header.
- Retries. A rate limit or a transient server failure is retried with
exponential backoff and jitter, honoring
Retry-Afterwhen it is sent. A rejected token or a permission error is not retried, because retrying will not fix it. - Typed errors.
AuthenticationError,PermissionError,RateLimitError,NotFoundError,ServerError. - Flattened objects. The nested prediction, survival, and maintenance blocks
are lifted onto the component, so
healthandrecommended_actionare one attribute away. - Useful ordering. Components come back most urgent first; forecast items come back soonest first.
Reading the fields
| Field | Meaning |
|---|---|
health |
0 to 100, where higher is healthier. |
health_trend |
stable, declining, or critical. |
predicted_rul_hours / predicted_rul_days |
Remaining useful life before attention is due. |
failure_probability |
0 to 1, the modeled chance of failure in the near term. |
recommended_action |
do_nothing, monitor, inspect, repair, or replace. |
priority |
The urgency band for planning. |
task_reference |
The task identifier from your source system, so a row ties back to its task. |
days_until_due |
Negative means the item is already past due. |
Access levels
Your token is issued at one of three levels, which control both the endpoints it can reach and how many records a request returns:
read_only: predictions, forecasts, explanations, and the change feedread_write: adds exports, bulk operations, and work order conversionfull: everything
A call outside your token's level raises a permission error. Call config() to
see the level and limits for your token rather than guessing.
Allowances
Consumption is measured on three independent meters, so keeping your systems in sync never competes with the budget your interface needs:
| Meter | What it covers | Priced |
|---|---|---|
interactive |
Requests your application makes in response to something happening | Per call, against your plan's daily and monthly quota |
feed |
Change feed polling | For a poll every thirty seconds, on every level including read_only |
bulk |
Whole-fleet exports and batch writes | Once per operation, whatever the volume |
A fifty thousand row export therefore costs the same as a five row one, and holding a live mirror of fleet state costs nothing from the allowance your users draw on.
q = trakt.quota()
print(q.interactive.daily_remaining, "interactive calls left today")
print(q.feed.daily_remaining, "feed polls left today")
print(q.bulk.monthly_remaining, "bulk operations left this month")
Every response also carries your live position in the X-Trakt-Quota-* headers.
Exhausting a meter returns 429 with Retry-After set to the seconds until that
window resets, which both clients honor automatically.
Need a client in another language?
The SDKs are generated from an OpenAPI specification, which the API serves directly, so the contract you generate from is always the one the service is running:
curl -O https://trakt.tech/api/openapi.yaml # as authored
curl -O https://trakt.tech/api/openapi.json # for tooling that wants JSON
Both are unauthenticated, because the spec describes the shape of the API rather than any data. Every endpoint it documents still needs a bearer token.
Point your generator of choice at it, for example:
openapi-generator-cli generate \
-i https://trakt.tech/api/openapi.yaml \
-g go -o ./trakt-go
Citation
If Trakt informs a paper, technical report, reliability study, or regulatory submission, cite the release you actually ran.
Two things here are citable and they are not the same. Cite Trakt System when your results depend on its predictions, which is the usual case. Cite the client library only when the work is about the client itself, or when a reviewer needs to reproduce the exact calls you made.
Citing Trakt System
The API documentation renders the current platform citation in BibTeX, APA, IEEE, and CITATION.cff, generated from the running service so the version is never stale: https://trakt.tech/api-documentation#citation
That page is the source to copy from. This README deliberately does not restate the platform version, because a version pinned in a package README goes out of date the moment the service ships a release.
Citing this client
BibTeX
@misc{kquika2026traktpy,
title = {Trakt System Python SDK},
author = {{Kquika, Inc.}},
year = {2026},
version = {1.3.0},
publisher = {{Kquika, Inc.}},
howpublished = {\url{https://pypi.org/project/kquika-trakt/}},
url = {https://pypi.org/project/kquika-trakt/},
note = {Computer software, version 1.3.0}
}
@misc{kquika2026traktjs,
title = {Trakt System Node SDK},
author = {{Kquika, Inc.}},
year = {2026},
version = {1.2.0},
publisher = {{Kquika, Inc.}},
howpublished = {\url{https://www.npmjs.com/package/@kquika-inc/trakt}},
url = {https://www.npmjs.com/package/@kquika-inc/trakt},
note = {Computer software, version 1.2.0}
}
@misc is used because every BibTeX style accepts it. On biblatex you can change
the type to @software and drop howpublished.
APA 7th
Kquika, Inc. (2026). Trakt System Python SDK (Version 1.3.0) [Computer software]. https://pypi.org/project/kquika-trakt/
Kquika, Inc. (2026). Trakt System Node SDK (Version 1.2.0) [Computer software]. https://www.npmjs.com/package/@kquika-inc/trakt
In text: (Kquika, Inc., 2026).
IEEE
Kquika, Inc., "Trakt System Python SDK," version 1.3.0, 2026. [Online]. Available: https://pypi.org/project/kquika-trakt/
Kquika, Inc., "Trakt System Node SDK," version 1.2.0, 2026. [Online]. Available: https://www.npmjs.com/package/@kquika-inc/trakt
CITATION.cff
Drop this in the root of a repository that depends on Trakt and reference managers will pick it up. Keep the entry for the client you actually use.
cff-version: 1.2.1
message: "If you use Trakt in your work, please cite it as below."
title: "Trakt System Python SDK"
type: software
version: "1.3.0"
license: MIT
url: "https://pypi.org/project/kquika-trakt/"
repository-artifact: "https://pypi.org/project/kquika-trakt/"
authors:
- name: "Kquika, Inc."
For the Node client, change title to Trakt System Node SDK, version to
1.2.0, and both URLs to
https://www.npmjs.com/package/@kquika-inc/trakt.
Reporting the version
Pin the version in your methods section. The client reports itself in the
User-Agent on every request, so a server log line and a paper can be tied
together:
trakt-python/1.3.0
trakt-node/1.2.0
Read it at run time rather than transcribing it, so the number in your write up cannot drift from the number that ran:
import trakt
print(trakt.__version__)
import { VERSION } from "@kquika-inc/trakt";
console.log(VERSION);
Predictions also depend on which models produced them, and those version
independently of both the API and this client. Call GET /models/status at run
time and record the model version alongside the API version, so a reviewer can
tell which models produced your numbers.
Support
API reference: https://trakt.tech/api-documentation
Questions, a token, or a raised limit: support@kquika.com
License
MIT
Release files for kquika-trakt 1.3.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_trakt-1.3.0.tar.gz | 26.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| kquika_trakt-1.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:53.1 kB
Release files / kquika_trakt-1.3.0.tar.gz
| Download URL | kquika_trakt-1.3.0.tar.gz |
|---|---|
| Size | 26.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ba300f2ee7bbf095db50e38b3b6d06739885dcccf5b26df6cdcbe4ab80dc1bfb
|
|
BLAKE2b-256 checksum How to use checksums |
28091e0fbb3f824f93bb9d4941c9e494a57fdb366b918bce9dbd73f1ad36cef5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.9
|
Release files / kquika_trakt-1.3.0-py3-none-any.whl
| Download URL | kquika_trakt-1.3.0-py3-none-any.whl |
|---|---|
| Size | 26.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
aa612a925f47edcc21493bde401dd3b07f39ff8bb04d97efac9bd3ff5b88014a
|
|
BLAKE2b-256 checksum How to use checksums |
7917b56bd639752690b6af65b3068a34c59742fd5e42abb462999b10528a8683
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.9
|