Documentation Index
Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt
Use this file to discover all available pages before exploring further.
GET /api/v1/decision-traces
List decision traces with offset-based pagination. Traces are only recorded when tracing is enabled in tenant settings and the request passes the sample rate check.
Query Parameters
| Parameter | Type | Default | Description |
|---|
customerId | string | — | Filter traces for a specific customer |
requestId | string | — | Filter by request/interaction ID |
limit | integer | 50 | Max results (max 200) |
offset | integer | 0 | Pagination offset |
Response
{
"traces": [
{
"id": "trace_001",
"customerId": "CUST001",
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"decisionFlowKey": "default-flow",
"pipeline": [
{ "stage": "qualification", "candidates": 47, "passed": 32, "durationMs": 12 },
{ "stage": "contact_policy", "candidates": 32, "passed": 28, "durationMs": 8 },
{ "stage": "scoring", "candidates": 28, "durationMs": 15 },
{ "stage": "ranking", "topScore": 0.872, "durationMs": 2 },
{ "stage": "arbitration", "method": "priority_weighted", "durationMs": 3 }
],
"result": {
"count": 5,
"topOffer": { "offerId": "offer_001", "score": 0.872 }
},
"totalDurationMs": 42,
"createdAt": "2026-03-16T14:30:00.000Z"
}
],
"total": 1250,
"limit": 50,
"offset": 0
}
GET /api/v1/decision-traces/
Get a single decision trace with full pipeline detail.
Response
Returns the complete trace object with all pipeline stages, scoring details, and result.
Enabling Decision Traces
Decision traces are controlled by two tenant settings:
| Setting | Description |
|---|
decisionTraceEnabled | Master toggle for trace recording |
decisionTraceSampleRate | Sampling rate (0.0 - 1.0). Set to 1.0 to trace every request |
Configure these via the Settings API or the platform UI under Settings.
At high traffic volumes, set the sample rate below 1.0 to avoid excessive storage. A 10% sample rate (0.1) typically provides sufficient forensic coverage.
JSON Field Shapes
Each trace persists four JSON arrays that capture the forensic detail of the decision. Downstream aggregators (the selection_frequency, anomaly_candidates, and why_not_ranked endpoints in Dashboard Data) expect the following shapes on newly-written rows. Older rows written before a field was added are still readable — fields default to null in the aggregation queries.
scoringResults
Best-first list of offers that reached the scoring stage.
[
{ "offerId": "off_premium_card", "score": 0.89, "rank": 1 },
{ "offerId": "off_gold_plus", "score": 0.71, "rank": 2 }
]
selectedOffers
The final ranked result returned to the caller, in delivery order.
[
{ "offerId": "off_premium_card", "score": 0.89, "rank": 1 },
{ "offerId": "off_gold_plus", "score": 0.71, "rank": 2 }
]
qualificationResults
One row per offer that the qualification stage evaluated. passed=false indicates a rejection; ruleId identifies the rule that evaluated.
[
{ "offerId": "off_premium_card", "passed": true, "reason": "passed" },
{ "offerId": "off_restricted", "passed": false, "reason": "segment_mismatch", "ruleId": "rule_42" }
]
One row per offer that the contact-policy stage evaluated. blocked=true indicates the policy suppressed the offer for this customer.
[
{ "offerId": "off_premium_card", "blocked": false, "reason": "passed" },
{ "offerId": "off_weekly_promo", "blocked": true, "reason": "frequency_cap", "policyId": "pol_email_daily_cap" }
]
POST /api/v1/decisions//narrative
Generate an LLM-written natural-language explanation of a single decision
trace. The feature is opt-in per tenant — see LLM Explanations.
Request Body
{
"mode": "regulator",
"noCache": false
}
| Field | Type | Default | Description |
|---|
mode | "regulator" | "agent" | "customer" | "regulator" | Audience for the explanation. Changes tone, length, and format. |
noCache | boolean | false | When true, bypass the cache and force a fresh LLM call. |
Response
{
"narrative": "The system recommended offer_premium_card for customer CUST001 because ...",
"mode": "regulator",
"model": "claude-sonnet-4-7",
"cached": false,
"tokens": { "input": 1420, "output": 310 },
"createdAt": "2026-04-18T21:04:18.000Z"
}
| Field | Type | Description |
|---|
narrative | string | The generated explanation. Prose for regulator and customer modes, structured JSON for agent mode. |
mode | string | Echoes the requested mode. |
model | string | Identifier of the LLM used. |
cached | boolean | true if the result was served from Redis. |
tokens.input / tokens.output | number | LLM token counts when reported by the provider. |
createdAt | ISO-8601 string | Creation timestamp of the narrative (cached or fresh). |
Auth, Limits, and Tenancy
- Requires tenant authentication (session or API key).
- Rate limited to 20 requests / minute / tenant. Exceeding returns
429.
- Tenant opt-in required:
tenantSettings.aiAnalyzerSettings.llmExplanationsEnabled = true. Otherwise returns 403 with
"LLM explanations are not enabled for this tenant.".
- The decision trace must belong to the authenticated tenant or the response is
404.
Audit Log (regulator mode)
When mode = "regulator", a row is appended to AuditLog:
{
"tenantId": "tenant_abc",
"action": "generate_narrative",
"entityType": "decision_trace",
"entityId": "trace_001",
"entityName": "regulator narrative",
"changes": {
"mode": "regulator",
"model": "claude-sonnet-4-7",
"cached": false,
"narrativePreview": "..."
}
}
Caching
Results are cached in Redis for 7 days under the composite key
(tenantId × decisionTraceId × mode × model × inputsHash). Repeating the
same request returns cached: true instantly.
POST /api/v1/decisions//shap
Return exact per-feature TreeSHAP contributions for a recorded decision’s
gradient_boosted scoring step. Designed for EU AI Act Article 13/22 audit
workflows: the response is a mathematically-grounded, additivity-verified
breakdown of every feature’s effect on the raw margin (logit space).
Unlike the LLM narrative endpoint, this returns raw numbers — deterministic,
cacheable, and auditable independent of any LLM availability. Pair the two
when you need both prose and numerics in a regulator export.
Request Body
{
"modelId": "mdl_premium_card_gbm",
"offerId": "off_premium_card",
"attributes": {
"recent_transaction_count": 12,
"tenure_months": 36,
"average_balance": 15400,
"segment_index": 2
},
"round": 6
}
| Field | Type | Default | Description |
|---|
modelId | string | required | The AlgorithmModel.id used to score the trace. Must be tenant-owned and modelType = "gradient_boosted". |
offerId | string | optional | The candidate offer the SHAP is being computed for. Echoed in the audit log. |
attributes | object | required | The customer/offer/context attributes passed to the scorer at decision time. Required because raw attributes are not persisted on the trace (PII minimization). |
round | integer | 6 | Decimal places for output (0 = raw doubles). |
Response
{
"decisionTraceId": "trace_001",
"modelId": "mdl_premium_card_gbm",
"modelName": "Premium Card GBM",
"offerId": "off_premium_card",
"shapValues": {
"recent_transaction_count": 1.314,
"tenure_months": 0.428,
"average_balance": -0.211,
"segment_index": 0.083
},
"baseline": -0.602,
"rawMargin": 1.012,
"additivityResidual": 0.0,
"featureCount": 4
}
| Field | Type | Description | | |
|---|
shapValues | object | Per-feature Shapley contributions in raw-margin (logit) space. | | |
baseline | number | Cover-weighted expected raw-margin across the ensemble. | | |
rawMargin | number | The chosen leaf-value sum for these attributes. sigmoid(rawMargin) = score. | | |
additivityResidual | number | ` | rawMargin − baseline − Σ shapValues | `. Should be ≈ 0; non-zero indicates a malformed model. |
featureCount | number | Number of features that received a non-zero contribution. | | |
Additivity guarantee
For any input x:
sum(shapValues) + baseline = rawMargin
score(x) = sigmoid(rawMargin)
This identity is built into the algorithm (Lundberg, Erion, Lee 2018,
Algorithm 2 — path-dependent variant). The endpoint reports
additivityResidual so consumers can verify the invariant on-wire.
Probability-space approximation
SHAP values are reported in raw-margin space — the only space where the
additivity identity holds. To approximate a feature’s effect on the
probability, use:
delta_p_i ≈ sigmoid(baseline + shap_i) − sigmoid(baseline)
This is monotone with shap_i but not strictly additive in probability
space. UI surfaces typically show both: the raw φ for compliance, and a
sigmoid-mapped delta for human-readable display.
Auth, Limits, and Tenancy
- Requires tenant authentication (session or API key).
- Rate limited to 30 requests / minute / tenant.
- Tenant opt-in required:
tenantSettings.aiAnalyzerSettings.llmExplanationsEnabled = true (same flag as the narrative endpoint).
- The decision trace, the model, and the request must all belong to the same tenant. Cross-tenant lookup returns
404.
- Returns
400 if the model’s modelType is not gradient_boosted or if it has no trained trees.
Audit Log
Every successful call writes:
{
"tenantId": "tenant_abc",
"action": "compute_shap",
"entityType": "decision_trace",
"entityId": "trace_001",
"entityName": "shap for Premium Card GBM / off_premium_card",
"changes": {
"modelId": "mdl_premium_card_gbm",
"modelName": "Premium Card GBM",
"offerId": "off_premium_card",
"featureCount": 4,
"baseline": -0.602,
"rawMargin": 1.012,
"additivityResidual": 0.0
}
}
This ensures DSAR exports and regulator queries can trace which decisions
have had SHAP attributions computed and when.
Roles
| Endpoint | Allowed Roles |
|---|
GET /decision-traces | admin, editor, viewer |
GET /decision-traces/{id} | admin, editor, viewer |
POST /decisions/{id}/narrative | admin, editor, viewer (tenant-scoped) |
POST /decisions/{id}/shap | admin, editor, viewer (tenant-scoped) |
See also: LLM Explanations | Dashboards | Decision Flows