Report
Actor, program and weekly reports, plus the examiner record.
Reports are built from rows the platform already persisted: the current Skoor with its reasons, history and band transitions, transfers in the window, alerts and dispositions. The record is two hash chains per tenant (dispositions, actions); verification recomputes every hash and reports the first break, and the export is JSON lines an examiner can walk for a date range.
ActorReport
No percentiles across banks; n and confidence say how much history stands behind the number.
| Field | Type | Notes |
|---|
| kind | const "actor" | |
| type | "entity" | "counterparty" | "agent" | |
| id | string | |
| name | string | null | |
| programId | string (uuid) | |
| generatedAt | string (date-time) | |
| current | object | null | |
| history | SkoorPoint[] | |
| transitions | BandTransition[] | |
| signalTrends | object | null | |
| transfers | TransfersSummary | |
| alerts | object[] | |
| alerts[].id | string (uuid) | |
| alerts[].detector | string | |
| alerts[].status | string | |
| alerts[].route | string | null | |
| alerts[].openedAt | string (date-time) | |
| alerts[].summary | string | |
| dispositions | object[] | |
| dispositions[].alertId | string (uuid) | |
| dispositions[].decidedBy | string | |
| dispositions[].decision | string | |
| dispositions[].overturnsDraft | boolean | null | |
| dispositions[].createdAt | string (date-time) | |
ProgramReport
| Field | Type | Notes |
|---|
| kind | const "program" | |
| id | string (uuid) | |
| name | string | |
| generatedAt | string (date-time) | |
| current | object | null | |
| history | object[] | |
| history[].asOf | string (date-time) | |
| history[].programSkoor | integer | null | |
| history[].band | "clear" | "review" | "hold" | "unscored" | |
| history[].n | integer | |
| transitions | BandTransition[] | |
| kris | Record<string, KriValue> | |
| kriDeltas | object[] | |
| kriDeltas[].name | string | |
| kriDeltas[].from | number | null | |
| kriDeltas[].to | number | null | |
| kriDeltas[].delta | number | null | |
| kriDeltas[].statusFrom | string | null | |
| kriDeltas[].statusTo | string | |
| kriDeltas[].n | integer | |
| rank | object | null | |
| transfers | TransfersSummary | |
| alertsByDetector | object[] | |
| alertsByDetector[].detector | string | |
| alertsByDetector[].route | string | null | |
| alertsByDetector[].count | integer | |
WeeklyReport
| Field | Type | Notes |
|---|
| kind | const "weekly" | |
| key | string | weekly:<programId>:<week> |
| programId | string (uuid) | |
| programName | string | |
| isoWeek | string | e.g. 2026-W37 |
| from | string (date-time) | |
| to | string (date-time) | |
| generatedAt | string (date-time) | |
| programSkoor | object | |
| programSkoor.current | integer | null | |
| programSkoor.prior | integer | null | |
| programSkoor.band | string | |
| programSkoor.n | integer | |
| kris | object[] | |
| kris[].name | string | |
| kris[].value | number | null | |
| kris[].prior | number | null | |
| kris[].delta | number | null | |
| kris[].status | string | |
| kris[].priorStatus | string | null | |
| kris[].n | integer | |
| kris[].unit | string | |
| kris[].threshold | number | null | |
| alerts | object | |
| alerts.total | integer | |
| alerts.byDetector | object[] | |
| alerts.byDetector[].detector | string | |
| alerts.byDetector[].route | string | null | |
| alerts.byDetector[].count | integer | |
| alerts.byStatus | Record<string, integer> | |
| enteredHold | object[] | |
| enteredHold[].type | string | |
| enteredHold[].id | string | |
| enteredHold[].skoor | integer | null | |
| enteredHold[].n | integer | |
| enteredHold[].at | string (date-time) | |
| dispositions | object | |
| dispositions.total | integer | |
| dispositions.byPlatform | integer | |
| dispositions.byPerson | integer | |
| dispositions.overturned | integer | |
| timeToDecisionHours | object | Closed alerts in the week. |
| timeToDecisionHours.median | number | null | |
| timeToDecisionHours.p90 | number | null | |
| timeToDecisionHours.n | integer | |
| transfers | object | |
| transfers.count | integer | |
| transfers.volumeCents | string | Integer cents as a string (bigint-safe). |
| transfers.returns | object | |
| transfers.returns.any | integer | |
| transfers.returns.unauthorized | integer | |
| transfers.bands | Record<string, integer> | |
| summary | string | Plain-text summary written from a template, never a model. |
ChainReport
| Field | Type | Notes |
|---|
| ok | boolean | |
| checked | integer | |
| firstBreakAt | object | null | |
| chains | object | |
| chains.dispositions | object | |
| chains.dispositions.ok | boolean | |
| chains.dispositions.checked | integer | |
| chains.actions | object | |
| chains.actions.ok | boolean | |
| chains.actions.checked | integer | |
RecordLine
One JSON object per line. policy first ({version, source: tenant|default, from, to}); then every Alert, Disposition and Action in the range, in time order, with all their fields.
| Field | Type | Notes |
|---|
| kind | "policy" | "alert" | "disposition" | "action" | |
Endpoints
get/api/reports/actor/{type}/{id}
Actor report
| Auth | Bearer + X-Operator |
|---|
| Operation | Report · GET /api/reports/actor/{type}/{id} |
|---|
Parameters
| Name | In | Type | Notes |
|---|
| type | path | "entity" | "counterparty" | "agent" | entity, counterparty or agent. |
| id | path | string | Actor id. |
| tenant (optional) | query | string | Tenant slug. Optional: the bearer token already proves the tenant. Pass it to be explicit. |
Responses
200 — The current Skoor with reasons, history, band transitions, signal trends, transfers, alerts and dispositions for the actor. ActorReport
| Field | Type | Notes |
|---|
| kind | const "actor" | |
| type | "entity" | "counterparty" | "agent" | |
| id | string | |
| name | string | null | |
| programId | string (uuid) | |
| generatedAt | string (date-time) | |
| current | object | null | |
| history | SkoorPoint[] | |
| transitions | BandTransition[] | |
| signalTrends | object | null | |
| transfers | TransfersSummary | |
| alerts | object[] | |
| alerts[].id | string (uuid) | |
| alerts[].detector | string | |
| alerts[].status | string | |
| alerts[].route | string | null | |
| alerts[].openedAt | string (date-time) | |
| alerts[].summary | string | |
| dispositions | object[] | |
| dispositions[].alertId | string (uuid) | |
| dispositions[].decidedBy | string | |
| dispositions[].decision | string | |
| dispositions[].overturnsDraft | boolean | null | |
| dispositions[].createdAt | string (date-time) | |
400 — type must be entity, counterparty, or agent. Error
| Field | Type | Notes |
|---|
| error | string | What went wrong, in one sentence. |
| requestId (optional) | string | Present once the gateway is live: the X-Request-Id of the failed request. |
401 — Bearer token missing or unknown. Error
| Field | Type | Notes |
|---|
| error | string | What went wrong, in one sentence. |
| requestId (optional) | string | Present once the gateway is live: the X-Request-Id of the failed request. |
404 — Unknown actor on this tenant. Error
| Field | Type | Notes |
|---|
| error | string | What went wrong, in one sentence. |
| requestId (optional) | string | Present once the gateway is live: the X-Request-Id of the failed request. |
Example
curl -s "https://skoor.ai/risk/api/reports/actor/entity/enti_sim_acme?tenant=demo" \
-H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Operator: you@bank.example"
get/api/reports/program/{id}
Program report
| Auth | Bearer + X-Operator |
|---|
| Operation | Report · GET /api/reports/program/{id} |
|---|
Parameters
| Name | In | Type | Notes |
|---|
| id | path | string (uuid) | Program id. |
| tenant (optional) | query | string | Tenant slug. Optional: the bearer token already proves the tenant. Pass it to be explicit. |
Responses
200 — The Program Risk Skoor with history, KRIs and their deltas, rank inside the bank, transfers and alerts by detector. ProgramReport
| Field | Type | Notes |
|---|
| kind | const "program" | |
| id | string (uuid) | |
| name | string | |
| generatedAt | string (date-time) | |
| current | object | null | |
| history | object[] | |
| history[].asOf | string (date-time) | |
| history[].programSkoor | integer | null | |
| history[].band | "clear" | "review" | "hold" | "unscored" | |
| history[].n | integer | |
| transitions | BandTransition[] | |
| kris | Record<string, KriValue> | |
| kriDeltas | object[] | |
| kriDeltas[].name | string | |
| kriDeltas[].from | number | null | |
| kriDeltas[].to | number | null | |
| kriDeltas[].delta | number | null | |
| kriDeltas[].statusFrom | string | null | |
| kriDeltas[].statusTo | string | |
| kriDeltas[].n | integer | |
| rank | object | null | |
| transfers | TransfersSummary | |
| alertsByDetector | object[] | |
| alertsByDetector[].detector | string | |
| alertsByDetector[].route | string | null | |
| alertsByDetector[].count | integer | |
401 — Bearer token missing or unknown. Error
| Field | Type | Notes |
|---|
| error | string | What went wrong, in one sentence. |
| requestId (optional) | string | Present once the gateway is live: the X-Request-Id of the failed request. |
404 — Unknown program on this tenant. Error
| Field | Type | Notes |
|---|
| error | string | What went wrong, in one sentence. |
| requestId (optional) | string | Present once the gateway is live: the X-Request-Id of the failed request. |
Example
curl -s "https://skoor.ai/risk/api/reports/program/a1e0c2d4-6b7f-4d8e-9a3b-0c1d2e3f4a55?tenant=demo" \
-H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Operator: you@bank.example"
get/api/reports/weekly/{programId}
Weekly program risk report
| Auth | Bearer + X-Operator |
|---|
| Operation | Report · GET /api/reports/weekly/{programId} |
|---|
Parameters
| Name | In | Type | Notes |
|---|
| programId | path | string (uuid) | Program id. |
| tenant (optional) | query | string | Tenant slug. Optional: the bearer token already proves the tenant. Pass it to be explicit. |
| week (optional) | query | string | ISO week (YYYY-Www). Default: the last complete week. |
| rebuild (optional) | query | "1" | Pass 1 to rebuild a stored report. |
Responses
200 — The stored report for the week, built on first request. WeeklyReport
| Field | Type | Notes |
|---|
| kind | const "weekly" | |
| key | string | weekly:<programId>:<week> |
| programId | string (uuid) | |
| programName | string | |
| isoWeek | string | e.g. 2026-W37 |
| from | string (date-time) | |
| to | string (date-time) | |
| generatedAt | string (date-time) | |
| programSkoor | object | |
| programSkoor.current | integer | null | |
| programSkoor.prior | integer | null | |
| programSkoor.band | string | |
| programSkoor.n | integer | |
| kris | object[] | |
| kris[].name | string | |
| kris[].value | number | null | |
| kris[].prior | number | null | |
| kris[].delta | number | null | |
| kris[].status | string | |
| kris[].priorStatus | string | null | |
| kris[].n | integer | |
| kris[].unit | string | |
| kris[].threshold | number | null | |
| alerts | object | |
| alerts.total | integer | |
| alerts.byDetector | object[] | |
| alerts.byDetector[].detector | string | |
| alerts.byDetector[].route | string | null | |
| alerts.byDetector[].count | integer | |
| alerts.byStatus | Record<string, integer> | |
| enteredHold | object[] | |
| enteredHold[].type | string | |
| enteredHold[].id | string | |
| enteredHold[].skoor | integer | null | |
| enteredHold[].n | integer | |
| enteredHold[].at | string (date-time) | |
| dispositions | object | |
| dispositions.total | integer | |
| dispositions.byPlatform | integer | |
| dispositions.byPerson | integer | |
| dispositions.overturned | integer | |
| timeToDecisionHours | object | Closed alerts in the week. |
| timeToDecisionHours.median | number | null | |
| timeToDecisionHours.p90 | number | null | |
| timeToDecisionHours.n | integer | |
| transfers | object | |
| transfers.count | integer | |
| transfers.volumeCents | string | Integer cents as a string (bigint-safe). |
| transfers.returns | object | |
| transfers.returns.any | integer | |
| transfers.returns.unauthorized | integer | |
| transfers.bands | Record<string, integer> | |
| summary | string | Plain-text summary written from a template, never a model. |
401 — Bearer token missing or unknown. Error
| Field | Type | Notes |
|---|
| error | string | What went wrong, in one sentence. |
| requestId (optional) | string | Present once the gateway is live: the X-Request-Id of the failed request. |
404 — Unknown program. Error
| Field | Type | Notes |
|---|
| error | string | What went wrong, in one sentence. |
| requestId (optional) | string | Present once the gateway is live: the X-Request-Id of the failed request. |
Example
curl -s "https://skoor.ai/risk/api/reports/weekly/a1e0c2d4-6b7f-4d8e-9a3b-0c1d2e3f4a55?tenant=demo&week=2026-W37" \
-H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Operator: you@bank.example"
get/api/record/verify
Verify the record chains
| Auth | Bearer + X-Operator |
|---|
| Operation | Report · GET /api/record/verify |
|---|
Parameters
| Name | In | Type | Notes |
|---|
| tenant (optional) | query | string | Tenant slug. Optional: the bearer token already proves the tenant. Pass it to be explicit. |
Responses
200 — Every disposition and action hash recomputed from stored fields; the first break, if any. ChainReport
| Field | Type | Notes |
|---|
| ok | boolean | |
| checked | integer | |
| firstBreakAt | object | null | |
| chains | object | |
| chains.dispositions | object | |
| chains.dispositions.ok | boolean | |
| chains.dispositions.checked | integer | |
| chains.actions | object | |
| chains.actions.ok | boolean | |
| chains.actions.checked | integer | |
401 — Bearer token missing or unknown. Error
| Field | Type | Notes |
|---|
| error | string | What went wrong, in one sentence. |
| requestId (optional) | string | Present once the gateway is live: the X-Request-Id of the failed request. |
Example
curl -s "https://skoor.ai/risk/api/record/verify?tenant=demo" \
-H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Operator: you@bank.example"
Response
{
"ok": true,
"checked": 412,
"firstBreakAt": null,
"chains": {
"dispositions": {
"ok": true,
"checked": 380
},
"actions": {
"ok": true,
"checked": 32
}
}
}
get/api/record/export
Examiner export (JSON lines)
| Auth | Bearer + X-Operator |
|---|
| Operation | Report · GET /api/record/export |
|---|
Parameters
| Name | In | Type | Notes |
|---|
| tenant (optional) | query | string | Tenant slug. Optional: the bearer token already proves the tenant. Pass it to be explicit. |
| from (optional) | query | string (date-time) | Start of the range (ISO 8601). Default 30 days ago. |
| to (optional) | query | string (date-time) | End of the range. Default now. |
Responses
200 — application/x-ndjson, served as an attachment: the policy line first, then alerts, dispositions and actions in time order. RecordLine · application/x-ndjson
| Field | Type | Notes |
|---|
| kind | "policy" | "alert" | "disposition" | "action" | |
400 — Bad date. Error
| Field | Type | Notes |
|---|
| error | string | What went wrong, in one sentence. |
| requestId (optional) | string | Present once the gateway is live: the X-Request-Id of the failed request. |
401 — Bearer token missing or unknown. Error
| Field | Type | Notes |
|---|
| error | string | What went wrong, in one sentence. |
| requestId (optional) | string | Present once the gateway is live: the X-Request-Id of the failed request. |
Example
curl -s "https://skoor.ai/risk/api/record/export?tenant=demo&from=2026-08-18T00%3A00%3A00Z&to=2026-09-17T00%3A00%3A00Z" \
-H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Operator: you@bank.example"