Policy
The automated-or-reviewed line, decision clocks, the limit ladder, program autonomy.
Policy is versioned data, never code: which detectors the platform may close alone and in which band, the history floor, which actions need two approvers, how long each SLA tier may wait, the per-band caps for entities and counterparties, and a per-program autonomy tier that widens only after the labelled set shows a detector is safe (and narrows on its own when overturns rise). Every alert and disposition records the policy version in force.
Policy
| Field | Type | Notes |
|---|
| id | string (uuid) | |
| tenantId | string (uuid) | |
| programId | string | null (uuid) | null = tenant-wide; set = a program's autonomy tier / limits. |
| version | string | |
| body | object | PolicyBody, ClockPolicy, LimitLadder or a program autonomy body, by version prefix. |
| active | boolean | |
| createdAt | string (date-time) | |
PolicyBody
| Field | Type | Notes |
|---|
| version | string | |
| autoClosableDetectors | string[] | Detectors the platform may close alone. |
| autoCloseBands | "clear" | "review" | "hold" | "unscored"[] | v1: clear only. |
| minProgramN | integer | History floor for any automated decision. |
| alwaysReviewed | string[] | |
| twoApproverActions | "clear_hold" | "cancel_transfer" | "pause_card" | "suspend_card_account" | "freeze_account" | "request_to_program" | "periodic_review"[] | |
| holdBandAutoHold | boolean | Hold band → held before anyone decides. |
ClockPolicy
Hours a decision may wait, by SLA tier. Defaults 1 / 24 / 72 / 168.
| Field | Type | Notes |
|---|
| autoHours | number | |
| standardHours | number | |
| complexHours | number | |
| appealHours | number | |
LimitLadder
| Field | Type | Notes |
|---|
| counterparty | Ladder | |
| entity | Ladder | |
| rescreenDays | object | Re-screen cadence by band. |
| rescreenDays.clear | integer | |
| rescreenDays.review | integer | |
| rescreenDays.hold | integer | |
| rescreenDays.unscored | integer | |
LimitEvaluation
| Field | Type | Notes |
|---|
| hits | LimitHit[] | |
| hard | boolean | True when any hit is hard (an actor in the hold band). |
| bands | object | |
| bands.entity | "clear" | "review" | "hold" | "unscored" | null | |
| bands.counterparty | "clear" | "review" | "hold" | "unscored" | null | |
| rescreen | object | |
| rescreen.entity | object | null | |
| rescreen.counterparty | object | null | |
| ladder | LimitLadder | |
ProgramAutonomy
| Field | Type | Notes |
|---|
| programId | string (uuid) | |
| tier | "supervised" | "standard" | "trusted" | |
| version | string | null | Active program version; null = policy v1 only. |
| granted | string[] | |
| effective | PolicyBody | |
| eligibility | DetectorEligibility[] | |
| lastChangeAt | string | null (date-time) | |
| nextChangeAllowedAt | string | null (date-time) | Cadence: one widening per week. |
| history | object[] | |
| history[].version | string | |
| history[].createdAt | string (date-time) | |
| history[].body | ProgramPolicyBody | |
| history[].active | boolean | |
Endpoints
get/api/limits/ladder
The tenant's limit ladder
| Auth | Bearer + X-Operator |
|---|
| Operation | Policy · GET /api/limits/ladder |
|---|
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 — Per-band caps for counterparties and entities and the re-screen cadence; the default ladder when the tenant has not written one. LimitLadder
| Field | Type | Notes |
|---|
| counterparty | Ladder | |
| entity | Ladder | |
| rescreenDays | object | Re-screen cadence by band. |
| rescreenDays.clear | integer | |
| rescreenDays.review | integer | |
| rescreenDays.hold | integer | |
| rescreenDays.unscored | 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/limits/ladder?tenant=demo" \
-H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Operator: you@bank.example"
get/api/limits/evaluate
Evaluate an amount against the ladder
| Auth | Bearer + X-Operator |
|---|
| Operation | Policy · GET /api/limits/evaluate |
|---|
Parameters
| Name | In | Type | Notes |
|---|
| tenant (optional) | query | string | Tenant slug. Optional: the bearer token already proves the tenant. Pass it to be explicit. |
| programId (optional) | query | string (uuid) | Program id. |
| amountCents (optional) | query | string | Integer cents. |
| entityId (optional) | query | string | Entity to evaluate, if any. |
| counterpartyId (optional) | query | string | Counterparty to evaluate, if any. |
Responses
200 — Limit hits (hard when an actor is in the hold band), the actors' bands, their re-screen cadence and the ladder used. LimitEvaluation
| Field | Type | Notes |
|---|
| hits | LimitHit[] | |
| hard | boolean | True when any hit is hard (an actor in the hold band). |
| bands | object | |
| bands.entity | "clear" | "review" | "hold" | "unscored" | null | |
| bands.counterparty | "clear" | "review" | "hold" | "unscored" | null | |
| rescreen | object | |
| rescreen.entity | object | null | |
| rescreen.counterparty | object | null | |
| ladder | LimitLadder | |
400 — programId and amountCents required. 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/limits/evaluate?tenant=demo&programId=a1e0c2d4-6b7f-4d8e-9a3b-0c1d2e3f4a55&amountCents=185000&entityId=enti_sim_acme&counterpartyId=cpty_sim_1" \
-H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Operator: you@bank.example"
get/api/autonomy/{programId}
A program's autonomy tier and eligibility
| Auth | Bearer + X-Operator |
|---|
| Operation | Policy · GET /api/autonomy/{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. |
Responses
200 — Tier, granted detectors, the effective policy, per-detector eligibility from the last 30 days of person decisions, and the version history. ProgramAutonomy
| Field | Type | Notes |
|---|
| programId | string (uuid) | |
| tier | "supervised" | "standard" | "trusted" | |
| version | string | null | Active program version; null = policy v1 only. |
| granted | string[] | |
| effective | PolicyBody | |
| eligibility | DetectorEligibility[] | |
| lastChangeAt | string | null (date-time) | |
| nextChangeAllowedAt | string | null (date-time) | Cadence: one widening per week. |
| history | object[] | |
| history[].version | string | |
| history[].createdAt | string (date-time) | |
| history[].body | ProgramPolicyBody | |
| history[].active | boolean | |
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/autonomy/a1e0c2d4-6b7f-4d8e-9a3b-0c1d2e3f4a55?tenant=demo" \
-H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Operator: you@bank.example"
post/api/autonomy/{programId}/activate
Grant a detector to the automated side
Needs an eligible detector (≥10 person decisions in 30 days, ≥90% matching the draft, none of the never-automate set) and a second approver distinct from X-Operator; at most one widening per week. Writes a new program policy version on the record.
| Auth | Bearer + X-Operator |
|---|
| Operation | Policy · POST /api/autonomy/{programId}/activate |
|---|
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. |
| Idempotency-Key (optional) | header | string | 1–255 characters. A replay with the same body returns the stored status and body with Idempotent-Replayed: true; a different body under the same key is 409. |
Request body (application/json, required) · object
| Field | Type | Notes |
|---|
| detector | string | |
| approverId | string | |
Responses
201 — The new version and tier. object
| Field | Type | Notes |
|---|
| version | string | |
| tier | "supervised" | "standard" | "trusted" | |
| granted | string[] | |
400 — detector and approverId required. 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 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. |
409 — Refused: not eligible, same approver, cadence, or never-automate. 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 -X POST "https://skoor.ai/risk/api/autonomy/a1e0c2d4-6b7f-4d8e-9a3b-0c1d2e3f4a55/activate?tenant=demo" \
-H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Operator: you@bank.example" \
-H "Content-Type: application/json" \
-d '{"detector":"repeat_pattern","approverId":"second.approver@bank.example"}'
post/api/autonomy/{programId}/demote
Run the demotion check now
Narrows the automated side for any granted detector whose overturn rate in the window is above 10%. The same check runs every 15 minutes.
| Auth | Bearer + X-Operator |
|---|
| Operation | Policy · POST /api/autonomy/{programId}/demote |
|---|
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. |
Responses
200 — Detectors demoted (empty when nothing changed) and the version written, if any. object
| Field | Type | Notes |
|---|
| demoted | string[] | |
| version | string | null | |
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 -X POST "https://skoor.ai/risk/api/autonomy/a1e0c2d4-6b7f-4d8e-9a3b-0c1d2e3f4a55/demote?tenant=demo" \
-H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Operator: you@bank.example"