Kirelta Decisions Account
API

Three calls, and you have a verdict

Kirelta takes rows of numbers — the same feature vectors you feed your model — and tells you whether they still look like the data the model was trained on. Everything below is copy-paste ready.

Base URL . Authenticate data calls with the header X-API-Key. Get a key on the account page.

Train a baseline

Send a batch of rows that represent healthy behaviour — data from a period when the model was working well. Kirelta learns the shape of that data and picks its own monitor for it. Every row must have the same number of features.

POST/fit?model=NAME

Returns

{ "status": "fitted", "model": "credit-risk", "n": 300, "features": 3, "variant": "static", "reason": "baseline looks unimodal (BIC favours K=1) -> calibrated single-Gaussian Kirelta", "variant_confidence": "high" }

Assess a batch

Now send recent rows — the ones you actually want a verdict on. Kirelta compares them against the baseline and answers in one object.

POST/assess?model=NAME

Read the verdict

This is the whole product. Everything the console shows you is built from these fields — nothing else is computed anywhere.

{ "model": "t_e573d9984466::credit-risk", "verdict": "UNTRUSTED", "action": "BLOCK / escalate to a human", "flagged_rate": 1.0, "drift_alarmed": true, "n": 80, "martingale": 2203.05, "alarm_threshold": 20.0, "drift_started_at": 1, "feature_importance": [ { "feature": 2, "importance": 0.3770 }, { "feature": 1, "importance": 0.3561 }, { "feature": 0, "importance": 0.2669 } ], "top_features": [2, 1, 0], "notes": ["baseline looks contaminated: ~20% of 'normal' points are outliers..."], "variant": "static", "temporal": { "ac1": 0.024, "thinning_k": 1 } }
verdictTRUSTED · DEGRADED · UNTRUSTED — the call itself. Branch on this.
actionThe engine's recommendation in words, e.g. ALLOW, REVIEW (elevated abstention), BLOCK / escalate to a human.
flagged_rateFraction of rows in this batch that fell outside the trained range. 0.01.0.
drift_alarmedtrue when the sequential test fires. This is the anytime-valid alarm — its false-alarm rate is bounded over the whole run, not per batch.
nHow many rows were assessed.
top_featuresColumn indices that contributed most to the deviation, most unusual first.
martingale
alarm_threshold
How close this batch came to the alarm. The martingale is accumulated evidence against "no drift"; the alarm fires the moment it reaches alarm_threshold (= 1/α). A batch at 9 / 20 is not alarmed and is not fine — it is nearly halfway to a block. Every other tool gives you only the binary. Evidence accumulates over the rows of a batch and resets on the next call, so read it per batch.
drift_started_atIndex of the first row where drift was declared. Absent when nothing alarmed.
feature_importanceThe real share of the deviation each feature carries, summing to 1.0 — not just an ordering. top_features is kept for compatibility.
notesThe engine's own warnings. The one worth reading: "baseline looks contaminated" means the data you trained on may itself contain anomalies — which changes how you should read every verdict that comes from it.
slow_drift_ratePresent only when the baseline itself is aging. Catches the slow drift that never trips a single batch.
temporal.ac1Lag-1 autocorrelation measured in this batch. The drift alarm assumes your rows are exchangeable; when ac1 climbs above 0.3 that assumption weakens and the alarm becomes less reliable — the per-row flags stay valid. Kirelta measures this and tells you, rather than letting you over-trust the alarm.
trendPresent only when applicable: {"state":"recovering","window":8} means this model was alarmed recently and is now improving. It never replaces verdict — read both.

Wire it into your service

The usual shape: assess the batch before you act on the predictions, and branch on the verdict.

import requests KIRELTA = "" KEY = "kir_your_key_here" def can_i_trust(model, rows): r = requests.post(f"{KIRELTA}/assess?model={model}", headers={"X-API-Key": KEY}, json={"rows": rows}, timeout=10) r.raise_for_status() return r.json() verdict = can_i_trust("credit-risk", recent_feature_rows) if verdict["verdict"] == "UNTRUSTED": escalate_to_human(verdict) # don't act on the model's output elif verdict["verdict"] == "DEGRADED": log_for_review(verdict) # act, but flag it serve(predictions) else: serve(predictions) # trusted

Everything else

The rest of the surface, in one place.

GET/models

Every model in your tenant, and how many features each expects.

GET/model/meta?model=NAME

Which monitor Kirelta chose for this model and why — useful when you want to justify a verdict.

GET/usage

Your plan, checks used today, models against your limit.

POST/keys   POST/keys/revoke

Create and revoke API keys. Session auth (Authorization: Bearer), not key auth — or just use the account page.

GET/account/export   DELETE/account

Download everything held about your account, or erase it completely.

GET/events   GET/alerts   POST/alerts

Trust events — what changed. Kirelta POSTs an event to your webhook when a model's verdict changes, not on every reading: a model assessed a thousand times while broken sends one event, not a thousand. An escalation from degraded to untrusted always gets through, cooldown or not — hearing "degraded" and then silence is the most dangerous thing this system could do to you. Kirelta notifies; it never acts on your systems.

It only sees what you send it. There is no scheduler. If your service stops calling /assess, Kirelta goes quiet, and no event will tell you that you have gone blind — keep that check in your own uptime monitoring.

GET/health

No auth. Returns {"status":"ok"} when the engine is up.

When something fails

400The body wasn't what the endpoint expected. The message says what was wrong.
401Missing or revoked API key.
404That model hasn't been fitted in your tenant yet.
429Rate limited. Back off and retry.

A model exists only after /fit. If you get a 404 on /assess, fit the baseline first.