SKOOR Risk Money movement. Skoored by AI.

Rule

The rule studio: draft → backtest → activate with two approvers → live alerts.

A bank authors rules as data over the same features the scorer uses. A rule never changes a Skoor: it opens an alert (detector rule:<id>) that always waits for a person. Activation needs a backtest against the tenant's own last 90 days that is younger than 24 hours, a second approver, and writes a versioned rules policy on the record chain.

Rule

FieldTypeNotes
idstringStable id, lowercase.
namestring
scope"transfer" | "entity" | "counterparty" | "program"Default transfer; only transfer-scoped rules fire today.
programIdstring | null (uuid)null = every program on the tenant.
whenRuleCondition[]AND of conditions; at least one.
action"alert" | "hold" | "review" | "log"
severity"low" | "medium" | "high"
status"draft" | "testing" | "active" | "paused" | "archived"
note (optional)string

RuleCondition

FieldTypeNotes
field"amountCents" | "rail" | "direction" | "type" | "status" | "counterpartyCountry" | "cardDecisionReason" | "entity.verificationStatus" | "entity.pepStatus" | "entity.isHighRisk" | "entity.requiresScreening" | "entity.screeningAgeDays" | "entity.count30d" | "velocity24hCount" | "velocity24hSumCents" | "entity.priorTransfers" | "entity.priorReturns" | "entity.achDebits60d" | "entity.unauthorizedReturns60d" | "structuringWindowCount" | "counterparty.firstTime" | "counterparty.n" | "counterparty.priorReturns" | "counterparty.priorUnauthorizedReturns" | "program.n90d" | "program.medianCents" | "program.p95Cents" | "program.dailyAvgCents30d" | "program.declaredMonthlyVolumeCents" | "program.unauthorizedReturnRate60d" | "declared.countries" | "typology.roundTrip" | "typology.layeringHops" | "typology.dormantDays" | "typology.justBelowThreshold"A fixed vocabulary over the same features the scorer uses.
op"gt" | "gte" | "lt" | "lte" | "eq" | "neq" | "in" | "not_in" | "between" | "is_null" | "not_null"
value (optional)string | number | boolean | null | string | number | boolean | null[]Scalar (string, number, boolean, null) or an array of scalars for in / not_in / between; omitted for is_null / not_null.

Backtest

FieldTypeNotes
keystring
ruleIdstring
atstring (date-time)
daysinteger
scannedintegerTransfers replayed (capped at 1000).
sampledbooleanTrue when the cap truncated the window.
matchedinteger
matchedSharenumber | null
wouldHoldinteger
wouldAlertinteger
overlapWithExistingAlertsinteger
byBandRecord<string, integer>
sampleTransferIdsstring[]

RulesVersion

FieldTypeNotes
idstring
versionstring
rulesRule[]
createdAtstring (date-time)
activeboolean
note (optional)string

Endpoints

get/api/rules

List rules with their last backtest

AuthBearer + X-Operator
OperationRule · GET /api/rules

Parameters

NameInTypeNotes
tenant (optional)querystringTenant slug. Optional: the bearer token already proves the tenant. Pass it to be explicit.

Responses

200 — Every rule on the tenant, each with its latest backtest, plus the field vocabulary and operators the DSL accepts. object

FieldTypeNotes
rulesRule & object[]
fieldsstring[]
operatorsstring[]

401 — Bearer token missing or unknown. Error

FieldTypeNotes
errorstringWhat went wrong, in one sentence.
requestId (optional)stringPresent once the gateway is live: the X-Request-Id of the failed request.

Example

curl -s "https://skoor.ai/risk/api/rules?tenant=demo" \
  -H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Operator: you@bank.example"

post/api/rules

Create or update a draft rule

AuthBearer + X-Operator
OperationRule · POST /api/rules

Parameters

NameInTypeNotes
tenant (optional)querystringTenant slug. Optional: the bearer token already proves the tenant. Pass it to be explicit.
Idempotency-Key (optional)headerstring1–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) · RuleDraft

FieldTypeNotes
idstring
namestring
scope (optional)"transfer" | "entity" | "counterparty" | "program"
programId (optional)string | null (uuid)
whenRuleCondition[]
action (optional)"alert" | "hold" | "review" | "log"
severity (optional)"low" | "medium" | "high"
note (optional)string

Responses

201 — The rule as stored (status draft). Rule

FieldTypeNotes
idstringStable id, lowercase.
namestring
scope"transfer" | "entity" | "counterparty" | "program"Default transfer; only transfer-scoped rules fire today.
programIdstring | null (uuid)null = every program on the tenant.
whenRuleCondition[]AND of conditions; at least one.
action"alert" | "hold" | "review" | "log"
severity"low" | "medium" | "high"
status"draft" | "testing" | "active" | "paused" | "archived"
note (optional)string

400 — Invalid rule; issues lists the Zod problems. Error

FieldTypeNotes
errorstringWhat went wrong, in one sentence.
requestId (optional)stringPresent once the gateway is live: the X-Request-Id of the failed request.

401 — Bearer token missing or unknown. Error

FieldTypeNotes
errorstringWhat went wrong, in one sentence.
requestId (optional)stringPresent once the gateway is live: the X-Request-Id of the failed request.

409 — The rule is active; pause it before editing. Error

FieldTypeNotes
errorstringWhat went wrong, in one sentence.
requestId (optional)stringPresent once the gateway is live: the X-Request-Id of the failed request.

Example

curl -s -X POST "https://skoor.ai/risk/api/rules?tenant=demo" \
  -H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Operator: you@bank.example" \
  -H "Content-Type: application/json" \
  -d '{"id":"large-first-time-wire","name":"Large wire to a first-time counterparty","when":[{"field":"rail","op":"eq","value":"wire"},{"field":"counterparty.firstTime","op":"eq","value":true},{"field":"amountCents","op":"gte","value":1000000}],"action":"alert","severity":"high"}'

post/api/rules/{id}/backtest

Backtest a rule against the tenant's own transfers

AuthBearer + X-Operator
OperationRule · POST /api/rules/{id}/backtest

Parameters

NameInTypeNotes
idpathstringRule id.
tenant (optional)querystringTenant slug. Optional: the bearer token already proves the tenant. Pass it to be explicit.

Request body (application/json) · object

FieldTypeNotes
days (optional)integerWindow in days (default 90).

Responses

200 — What the rule would have matched: scanned (capped at 1000, then sampled), matched, share, would-hold, overlap with existing alerts, by band, and sample transfer ids. Backtest

FieldTypeNotes
keystring
ruleIdstring
atstring (date-time)
daysinteger
scannedintegerTransfers replayed (capped at 1000).
sampledbooleanTrue when the cap truncated the window.
matchedinteger
matchedSharenumber | null
wouldHoldinteger
wouldAlertinteger
overlapWithExistingAlertsinteger
byBandRecord<string, integer>
sampleTransferIdsstring[]

401 — Bearer token missing or unknown. Error

FieldTypeNotes
errorstringWhat went wrong, in one sentence.
requestId (optional)stringPresent once the gateway is live: the X-Request-Id of the failed request.

404 — Rule not found. Error

FieldTypeNotes
errorstringWhat went wrong, in one sentence.
requestId (optional)stringPresent once the gateway is live: the X-Request-Id of the failed request.

Example

curl -s -X POST "https://skoor.ai/risk/api/rules/large-first-time-wire/backtest?tenant=demo" \
  -H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Operator: you@bank.example" \
  -H "Content-Type: application/json" \
  -d '{"days":90}'

post/api/rules/{id}/activate

Activate a rule with a second approver

Needs a backtest younger than 24 hours and an approver distinct from X-Operator. Writes a new rules version and chains a periodic_review action (target rule, <id>@<version>) on the rule's program, else the tenant's first program.

AuthBearer + X-Operator
OperationRule · POST /api/rules/{id}/activate

Parameters

NameInTypeNotes
idpathstringRule id.
tenant (optional)querystringTenant slug. Optional: the bearer token already proves the tenant. Pass it to be explicit.
Idempotency-Key (optional)headerstring1–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

FieldTypeNotes
approverIdstring

Responses

200 — The active rule, the rules version written, and the action id recorded on the chain (null when none). object

FieldTypeNotes
ruleRule
versionRulesVersion
actionIdstring | null

401 — Bearer token missing or unknown. Error

FieldTypeNotes
errorstringWhat went wrong, in one sentence.
requestId (optional)stringPresent once the gateway is live: the X-Request-Id of the failed request.

404 — Rule not found. Error

FieldTypeNotes
errorstringWhat went wrong, in one sentence.
requestId (optional)stringPresent once the gateway is live: the X-Request-Id of the failed request.

409 — No fresh backtest, same approver, or the rule is archived. Error

FieldTypeNotes
errorstringWhat went wrong, in one sentence.
requestId (optional)stringPresent once the gateway is live: the X-Request-Id of the failed request.

Example

curl -s -X POST "https://skoor.ai/risk/api/rules/large-first-time-wire/activate?tenant=demo" \
  -H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Operator: you@bank.example" \
  -H "Content-Type: application/json" \
  -d '{"approverId":"second.approver@bank.example"}'

post/api/rules/{id}/pause

Pause an active rule

AuthBearer + X-Operator
OperationRule · POST /api/rules/{id}/pause

Parameters

NameInTypeNotes
idpathstringRule id.
tenant (optional)querystringTenant slug. Optional: the bearer token already proves the tenant. Pass it to be explicit.

Responses

200 — The rule with status paused. Rule

FieldTypeNotes
idstringStable id, lowercase.
namestring
scope"transfer" | "entity" | "counterparty" | "program"Default transfer; only transfer-scoped rules fire today.
programIdstring | null (uuid)null = every program on the tenant.
whenRuleCondition[]AND of conditions; at least one.
action"alert" | "hold" | "review" | "log"
severity"low" | "medium" | "high"
status"draft" | "testing" | "active" | "paused" | "archived"
note (optional)string

401 — Bearer token missing or unknown. Error

FieldTypeNotes
errorstringWhat went wrong, in one sentence.
requestId (optional)stringPresent once the gateway is live: the X-Request-Id of the failed request.

404 — Rule not found. Error

FieldTypeNotes
errorstringWhat went wrong, in one sentence.
requestId (optional)stringPresent once the gateway is live: the X-Request-Id of the failed request.

Example

curl -s -X POST "https://skoor.ai/risk/api/rules/large-first-time-wire/pause?tenant=demo" \
  -H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Operator: you@bank.example"

← All objects