SKOOR Risk Money movement. Skoored by AI.

Sandbox

Simulation endpoints for test_ keys.

Build Column-shaped events against a simulated program and push them through the same ingest, scoring, detection and triage as production, then read the result: the transfer's Skoor with its n, the alerts it opened, the label a return produced. Every endpoint requires a test principal and a program whose source is simulated; a Column-sourced program is refused (403).

SandboxResult

FieldTypeNotes
eventsstring[]Ids of the Column-shaped events stored (source = simulated).
transferId (optional)string
alertIdsstring (uuid)[]
skoorobject | null

Endpoints

post/api/sandbox/transfers

Simulate a transfer through its Column lifecycle events and score it.

Builds the same event sequence Column would deliver (ACH: initiated → submitted → settled [→ completed]; wire/realtime: initiated → completed; book: completed; card: authorization) and runs scoring, detection and triage before answering. entityId and counterpartyId must already exist on the program; without a counterparty one is minted.

AuthBearer + X-Operator
OperationSandbox · POST /api/sandbox/transfers

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) · object

FieldTypeNotes
programId (optional)string (uuid)The simulated program. One of programId / programSlug is required.
programSlug (optional)stringThe simulated program by slug.
rail"ach" | "wire" | "book" | "realtime" | "card"
direction"incoming" | "outgoing"
amountCentsinteger | stringInteger cents. A numeric string is accepted for amounts above 2^53.
status (optional)"initiated" | "settled" | "completed" | "manual_review" | "hold"Final state of the lifecycle. completed records an ok outcome label, as a completed Column transfer does.
type (optional)"CREDIT" | "DEBIT"ACH only. Defaults to CREDIT outgoing, DEBIT incoming.
entityId (optional)string
counterpartyId (optional)string
counterpartyCountry (optional)string
memo (optional)string
at (optional)string (date-time)Column created_at of the transfer. Defaults to now; backdate to build history.
cardDecision (optional)"approved" | "declined"card only
cardDecisionReason (optional)stringcard only, e.g. suspected_fraud

Responses

200 — What the pipeline produced. object

FieldTypeNotes
programstringProgram slug.
eventsstring[]Ids of the Column-shaped events stored, in order.
transferIdstring
transferSandboxTransfer
skoorSkoor
alertIdsstring (uuid)[]
alertsSandboxAlert[]
labelsSandboxLabel[]

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.

403 — Not a test principal, or the program is Column-sourced. 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/sandbox/transfers?tenant=demo" \
  -H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Operator: you@bank.example" \
  -H "Content-Type: application/json" \
  -d '{"request":{"programSlug":"northwind-payroll","rail":"ach","direction":"outgoing","type":"DEBIT","amountCents":250000,"entityId":"enti_sb_1a2b3c4d5e6f7081","memo":"vendor payment"},"response":{"program":"northwind-payroll","events":["evnt_sb_m1a2b3c4_5e6f7a8b1","evnt_sb_m1a2b3c4_9c0d1e2f2","evnt_sb_m1a2b3c4_3a4b5c6d3"],"transferId":"acht_sb_9f2c1e0a7b3d4c55","transfer":{"id":"acht_sb_9f2c1e0a7b3d4c55","rail":"ach","direction":"outgoing","type":"DEBIT","amountCents":"250000","currency":"USD","status":"SETTLED","entityId":"enti_sb_1a2b3c4d5e6f7081","counterpartyId":"cpty_sb_0a1b2c3d4e5f6071","counterpartyCountry":"US","returnCode":null,"columnCreatedAt":"2026-09-17T15:04:05.000Z"},"skoor":{"value":null,"band":"unscored","n":0,"version":"trs-v1","confidence":null},"alertIds":[],"alerts":[],"labels":[]}}'

post/api/sandbox/transfers/{id}/return

Return an ACH transfer with a NACHA code; the outcome label follows production rules.

Replays the stored transfer as ach.*_transfer.returned with return_details. Unauthorized codes (R05, R07, R10, R11, R29, R51) record a bad label; NSF and administrative codes record returned. Only ACH transfers can be returned.

AuthBearer + X-Operator
OperationSandbox · POST /api/sandbox/transfers/{id}/return

Parameters

NameInTypeNotes
idpathstringid
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
code"R01" | "R02" | "R03" | "R04" | "R05" | "R07" | "R08" | "R10" | "R11" | "R16" | "R29" | "R51"
at (optional)string (date-time)

Responses

200 — What the pipeline produced. object

FieldTypeNotes
programstringProgram slug.
eventsstring[]Ids of the Column-shaped events stored, in order.
transferIdstring
transferSandboxTransfer
skoorSkoor
alertIdsstring (uuid)[]
alertsSandboxAlert[]
labelsSandboxLabel[]

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.

403 — Not a test principal, or the program is Column-sourced. 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/sandbox/transfers/acht_sandbox_0001/return?tenant=demo" \
  -H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Operator: you@bank.example" \
  -H "Content-Type: application/json" \
  -d '{"request":{"code":"R10"},"response":{"program":"northwind-payroll","events":["evnt_sb_m1a2b3c4_7e8f9a0b4"],"transferId":"acht_sb_9f2c1e0a7b3d4c55","transfer":{"id":"acht_sb_9f2c1e0a7b3d4c55","rail":"ach","direction":"outgoing","type":"DEBIT","amountCents":"250000","currency":"USD","status":"RETURNED","entityId":"enti_sb_1a2b3c4d5e6f7081","counterpartyId":"cpty_sb_0a1b2c3d4e5f6071","counterpartyCountry":"US","returnCode":"R10","columnCreatedAt":"2026-09-17T15:04:05.000Z"},"skoor":{"value":null,"band":"unscored","n":0,"version":"trs-v1","confidence":null},"alertIds":[],"alerts":[],"labels":[{"label":"bad","source":"outcome:return","detail":"R10:unauthorized"}]}}'

post/api/sandbox/transfers/{id}/dispute

Open a cardholder dispute on a card transaction.

Replays the stored card transaction as card.transaction.dispute (event_type: dispute). The transfer row moves to status DISPUTE and is re-scored. Only card transactions can be disputed.

AuthBearer + X-Operator
OperationSandbox · POST /api/sandbox/transfers/{id}/dispute

Parameters

NameInTypeNotes
idpathstringid
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
reason (optional)"fraud" | "not_received" | "duplicate" | "other"
at (optional)string (date-time)

Responses

200 — What the pipeline produced. object

FieldTypeNotes
programstringProgram slug.
eventsstring[]Ids of the Column-shaped events stored, in order.
transferIdstring
transferSandboxTransfer
skoorSkoor
alertIdsstring (uuid)[]
alertsSandboxAlert[]
labelsSandboxLabel[]

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.

403 — Not a test principal, or the program is Column-sourced. 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/sandbox/transfers/acht_sandbox_0001/dispute?tenant=demo" \
  -H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Operator: you@bank.example" \
  -H "Content-Type: application/json" \
  -d '{"request":{"reason":"fraud"},"response":{"program":"northwind-payroll","events":["evnt_sb_m1a2b3c4_1c2d3e4f5"],"transferId":"ctxn_sb_5d6e7f8091a2b3c4","transfer":{"id":"ctxn_sb_5d6e7f8091a2b3c4","rail":"card","direction":"outgoing","type":null,"amountCents":"250000","currency":"USD","status":"DISPUTE","entityId":"enti_sb_1a2b3c4d5e6f7081","counterpartyId":null,"counterpartyCountry":"US","returnCode":null,"columnCreatedAt":"2026-09-17T15:04:05.000Z"},"skoor":{"value":null,"band":"unscored","n":0,"version":"trs-v1","confidence":null},"alertIds":[],"alerts":[],"labels":[]}}'

post/api/sandbox/entities

Onboard an entity through identity.verification events.

Emits identity.verification.created (UNVERIFIED), .pending, then the final status event, seconds apart, and runs the entity Skoor. agent marks the entity as an AI agent acting under an operator.

AuthBearer + X-Operator
OperationSandbox · POST /api/sandbox/entities

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) · object

FieldTypeNotes
programId (optional)string (uuid)The simulated program. One of programId / programSlug is required.
programSlug (optional)stringThe simulated program by slug.
type"PERSON" | "BUSINESS"
namestring
verificationStatus (optional)"UNVERIFIED" | "PENDING" | "VERIFIED" | "MANUAL_REVIEW" | "DENIED"
pepStatus (optional)"not_checked" | "no" | "yes" | "potential"
isHighRisk (optional)boolean
requiresScreening (optional)boolean
country (optional)string
expectedPaymentRails (optional)string[]
agent (optional)object
agent.operatorEntityId (optional)string
agent.purposestring
agent.scope (optional)string[]
at (optional)string (date-time)Entity created_at. Defaults to now.

Responses

200 — What the pipeline produced. object

FieldTypeNotes
programstring
eventsstring[]
entityIdstring
entitySandboxEntity

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.

403 — Not a test principal, or the program is Column-sourced. 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/sandbox/entities?tenant=demo" \
  -H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Operator: you@bank.example" \
  -H "Content-Type: application/json" \
  -d '{"request":{"programSlug":"northwind-payroll","type":"PERSON","name":"Dana Whitfield","verificationStatus":"VERIFIED"},"response":{"program":"northwind-payroll","events":["evnt_sb_m1a2b3c4_a1b2c3d46","evnt_sb_m1a2b3c4_e5f6a7b87","evnt_sb_m1a2b3c4_c9d0e1f28"],"entityId":"enti_sb_1a2b3c4d5e6f7081","entity":{"id":"enti_sb_1a2b3c4d5e6f7081","type":"PERSON","name":"Dana Whitfield","verificationStatus":"VERIFIED","isHighRisk":false,"pepStatus":"no","countryCode":"US"}}}'

post/api/sandbox/entities/{id}/verification

Change an entity’s verification decision.

Emits one identity.verification.<status> event for an entity already on the program (DENIED adds sanctions_match, MANUAL_REVIEW adds name_mismatch to review_reasons, as the simulator does).

AuthBearer + X-Operator
OperationSandbox · POST /api/sandbox/entities/{id}/verification

Parameters

NameInTypeNotes
idpathstringid
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
programId (optional)string (uuid)The simulated program. One of programId / programSlug is required.
programSlug (optional)stringThe simulated program by slug.
status"VERIFIED" | "MANUAL_REVIEW" | "DENIED"
at (optional)string (date-time)

Responses

200 — What the pipeline produced. object

FieldTypeNotes
programstring
eventsstring[]
entityIdstring
entitySandboxEntity

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.

403 — Not a test principal, or the program is Column-sourced. 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/sandbox/entities/enti_sandbox_0001/verification?tenant=demo" \
  -H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Operator: you@bank.example" \
  -H "Content-Type: application/json" \
  -d '{"request":{"programSlug":"northwind-payroll","status":"DENIED"},"response":{"program":"northwind-payroll","events":["evnt_sb_m1a2b3c4_0a1b2c3d9"],"entityId":"enti_sb_1a2b3c4d5e6f7081","entity":{"id":"enti_sb_1a2b3c4d5e6f7081","type":"PERSON","name":"Dana Whitfield","verificationStatus":"DENIED","isHighRisk":false,"pepStatus":"no","countryCode":"US"}}}'

post/api/sandbox/counterparties

Register a counterparty for later transfers.

Column has no counterparty webhook (counterparties arrive embedded in transfer events), so this writes the row directly with a Column-shaped counterparty object in raw. Use the returned id as counterpartyId on transfers.

AuthBearer + X-Operator
OperationSandbox · POST /api/sandbox/counterparties

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) · object

FieldTypeNotes
programId (optional)string (uuid)The simulated program. One of programId / programSlug is required.
programSlug (optional)stringThe simulated program by slug.
namestring
country (optional)string
routingNumber (optional)string
at (optional)string (date-time)

Responses

200 — What the pipeline produced. object

FieldTypeNotes
programstring
counterpartyIdstring
counterpartySandboxCounterparty

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.

403 — Not a test principal, or the program is Column-sourced. 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/sandbox/counterparties?tenant=demo" \
  -H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Operator: you@bank.example" \
  -H "Content-Type: application/json" \
  -d '{"request":{"programSlug":"northwind-payroll","name":"Blue Ridge Landscaping","country":"US","routingNumber":"021000021"},"response":{"program":"northwind-payroll","counterpartyId":"cpty_sb_0a1b2c3d4e5f6071","counterparty":{"id":"cpty_sb_0a1b2c3d4e5f6071","name":"Blue Ridge Landscaping","countryCode":"US","routingNumber":"021000021"}}}'

post/api/sandbox/patterns/{name}

Play a typology the detectors know and return the alerts it opened.

Patterns: structuring → structuring_pattern (Four ACH debits of $9,100–$9,900 from one entity inside 24 hours (5 hours apart). Hard signal: the third and fourth are held.); just_below_threshold → amount_just_below_threshold (A single $9,500 ACH debit with no other sub-threshold debit in 24 hours.); velocity → velocity_spike (Seven ACH credits from one entity inside two hours; the sixth onward exceeds five in 24 hours.); round_trip → round_trip (An outgoing ACH to a counterparty three days ago, then the same amount back from it today.); layering → layering_chain (Three similar-amount hops inside 48 hours: entity A → counterparty X, X → the entity, the entity → counterparty Y.); dormant_reactivation → dormant_reactivation (One transfer 75 days ago, silence, then three transfers inside 24 hours.); burst_then_dormant → burst_then_dormant (Six transfers on one day 20 days ago and nothing since; a KRI snapshot is taken so the snapshot-time detector runs.). Without entityId/counterpartyId the play creates its own actors. at is the play's end time (default now); history is placed relative to it.

AuthBearer + X-Operator
OperationSandbox · POST /api/sandbox/patterns/{name}

Parameters

NameInTypeNotes
namepathstringname
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
programId (optional)string (uuid)The simulated program. One of programId / programSlug is required.
programSlug (optional)stringThe simulated program by slug.
entityId (optional)string
counterpartyId (optional)string
at (optional)string (date-time)

Responses

200 — What the pipeline produced. object

FieldTypeNotes
programstring
pattern"structuring" | "just_below_threshold" | "velocity" | "round_trip" | "layering" | "dormant_reactivation" | "burst_then_dormant"
expectedDetectorstring
eventsstring[]
transferIdsstring[]
entityIdstring
entityIdsstring[]Entities the play created.
counterpartyIdsstring[]
alertIdsstring (uuid)[]
alertsSandboxAlert[]
snapshotId (optional)string (uuid)burst_then_dormant only: the KRI snapshot taken.

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.

403 — Not a test principal, or the program is Column-sourced. 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/sandbox/patterns/structuring?tenant=demo" \
  -H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Operator: you@bank.example" \
  -H "Content-Type: application/json" \
  -d '{"request":{"programSlug":"northwind-payroll"},"response":{"program":"northwind-payroll","pattern":"structuring","expectedDetector":"structuring_pattern","events":["evnt_sb_m1a2b3c4_0000000a1","evnt_sb_m1a2b3c4_0000000a2"],"transferIds":["acht_sb_01","acht_sb_02","acht_sb_03","acht_sb_04"],"entityId":"enti_sb_1a2b3c4d5e6f7081","entityIds":["enti_sb_1a2b3c4d5e6f7081"],"counterpartyIds":["cpty_sb_0a1b2c3d4e5f6071"],"alertIds":["0d4c7b6e-2f1a-4e5b-9c8d-7a6b5c4d3e2f"],"alerts":[{"id":"0d4c7b6e-2f1a-4e5b-9c8d-7a6b5c4d3e2f","detector":"structuring_pattern","severity":"high","subjectType":"entity","subjectId":"enti_sb_1a2b3c4d5e6f7081","status":"open","route":"reviewed"}]}}'

post/api/sandbox/reset

Delete a simulated program’s data rows.

Removes labels, dispositions, actions, alerts, actor Skoors, pre-flights, KRI snapshots, events, transfers, counterparties, accounts and entities of the program, in dependency order. Configuration (policies, keys, webhook endpoints) stays. Refused on a Column-sourced program.

AuthBearer + X-Operator
OperationSandbox · POST /api/sandbox/reset

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) · object

FieldTypeNotes
programId (optional)string (uuid)The simulated program. One of programId / programSlug is required.
programSlug (optional)stringThe simulated program by slug.

Responses

200 — What the pipeline produced. object

FieldTypeNotes
programstring
resetboolean
countsRecord<string, integer>

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.

403 — Not a test principal, or the program is Column-sourced. 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/sandbox/reset?tenant=demo" \
  -H "Authorization: Bearer test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Operator: you@bank.example" \
  -H "Content-Type: application/json" \
  -d '{"request":{"programSlug":"northwind-payroll"},"response":{"program":"northwind-payroll","reset":true,"counts":{"labels":1,"dispositions":0,"actions":0,"alerts":2,"actor_skoors":3,"preflights":0,"kri_snapshots":0,"events":12,"transfers":4,"counterparties":1,"accounts":0,"entities":1}}}'

← All objects