{"openapi":"3.1.0","info":{"title":"Mulisa Screening API","version":"1.0.0","description":"Real-time AML transaction screening: rule-first decisioning with blacklists, typed YAML rules, behavioral profiles, and advisory ML scores. Generated from the endpoint catalog — the same source that drives the interactive console docs. Component schemas are derived from Zod (lib/api-zod-schemas/) so shapes always match the runtime.","contact":{"name":"JengaCore","url":"https://aml.jengacore.com"}},"servers":[{"url":"/api","description":"Console origin — same host, no CORS"}],"security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"tags":[{"name":"Screening"},{"name":"Transactions"},{"name":"Cases"},{"name":"Rules"},{"name":"Typologies"},{"name":"Sandbox"},{"name":"Blacklists"},{"name":"Profiles"},{"name":"Networks"},{"name":"Webhooks"},{"name":"Sanctions"},{"name":"Reporting"},{"name":"Onboarding"},{"name":"Settings"},{"name":"Activity"},{"name":"Meta"},{"name":"Feedback"},{"name":"Approvals"},{"name":"Analytics"},{"name":"Account"}],"paths":{"/v1/screen":{"post":{"operationId":"postScreen","summary":"Screen a transaction","description":"Screens a single transaction and returns an advisory decision in real time. Evaluation order is deterministic: blacklists first (any hit flags at maximum confidence), then active rules whose matched weights sum into risk_score, then the advisory ML score. The transaction is flagged when risk_score reaches your risk_threshold — blocking is always your decision. transaction.id is an instance-wide idempotency key: retries return the original result with HTTP 200 without duplicate cases, statistics, graph updates, or webhooks. Errors use a stable envelope with code, message, request_id, retryable, details, and docs_url; see docs/screening-errors.md.\n\n**Auth:** API key — `Authorization: Bearer jc_test_...` or `X-Api-Key`. Console sessions may omit it.","tags":["Screening"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreeningRequest"},"example":{"transaction":{"id":"txn_20260707_0042","amount":1250000,"currency":"KES","type":"transfer","channel":"api","timestamp":"2026-07-07T09:14:00Z","reference":"INV-2211","country_from":"KE","country_to":"NG"},"sender":{"id":"usr_8f2k1","name":"Amina Odhiambo","account":"0114589022","institution_id":"KCBLKENX","country":"KE","kyc_level":"standard","risk_score":0.35,"pep":false},"receiver":{"id":"usr_m1092","name":"Chidi Nwosu","account":"3308812304","institution_id":"GTBINGLA","country":"NG","kyc_level":"basic"},"metadata":{"device_id":"dev_a81xz","ip":"105.163.2.11","geo":"Nairobi","narrative":"invoice payment"}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreeningResponse"},"example":{"screening_id":"scr_x81ka02f","status":"flagged","confidence":0.82,"risk_score":0.7,"risk_threshold":0.6,"rule_results":[{"rule_id":"high-value-cross-border","name":"High-value cross-border transfer","matched":true,"weight":0.7,"severity":"high","detail":"Transfers above 1M crossing borders require review."}],"model_score":0.47,"blacklist_hits":[],"latency_ms":12,"timestamp":"2026-07-07T09:14:01Z"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/screen/iso20022":{"post":{"operationId":"postScreenIso20022","summary":"Screen an ISO 20022 pacs.008","description":"Screens an ISO 20022 pacs.008 (FIToFICstmrCdtTrf) message. Send the JSON representation of the document — the adapter maps debtor/creditor, agents (BICs), settlement amount, and remittance info to the canonical model, derives country from the agent BIC, then runs the identical pipeline as POST /v1/screen. Designed for a scheme/switch to route native clearing messages through screening without reformatting. The response adds an iso20022 block (message_id, end_to_end_id, uetr) and the normalized_request. One CdtTrfTxInf per call.\n\n**Auth:** API key — `Authorization: Bearer jc_test_...` or `X-Api-Key`. Console sessions may omit it.","tags":["Screening"],"x-beta":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"Document.FIToFICstmrCdtTrf":{"type":"object","description":"The pacs.008 document. The top-level Document envelope is optional. GrpHdr provides MsgId/CreDtTm; CdtTrfTxInf carries PmtId, IntrBkSttlmAmt, Dbtr/DbtrAgt/DbtrAcct, Cdtr/CdtrAgt/CdtrAcct, and RmtInf."}},"required":["Document.FIToFICstmrCdtTrf"]},"example":{"Document":{"FIToFICstmrCdtTrf":{"GrpHdr":{"MsgId":"MSG-20260707-001","CreDtTm":"2026-07-07T09:14:00Z","NbOfTxs":"1"},"CdtTrfTxInf":{"PmtId":{"EndToEndId":"E2E-2211","TxId":"txn_20260707_0042","UETR":"a1b2c3d4-..."},"IntrBkSttlmAmt":{"Ccy":"KES","value":"1250000"},"IntrBkSttlmDt":"2026-07-07","Dbtr":{"Nm":"Amina Odhiambo"},"DbtrAcct":{"Id":{"Othr":{"Id":"0114589022"}}},"DbtrAgt":{"FinInstnId":{"BICFI":"KCBLKENX"}},"Cdtr":{"Nm":"Chidi Nwosu"},"CdtrAcct":{"Id":{"Othr":{"Id":"3308812304"}}},"CdtrAgt":{"FinInstnId":{"BICFI":"GTBINGLA"}},"RmtInf":{"Ustrd":["invoice payment"]}}}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/screen/mojaloop":{"post":{"operationId":"postScreenMojaloop","summary":"Screen a Mojaloop transaction","description":"Screens a Mojaloop transaction object (the payload exchanged during the quote/transfer flow). The adapter maps payer/payee partyIdInfo to the canonical model — fspId becomes institution_id (the emitting FSP) and MSISDN identifiers infer the country from the calling code — then runs the identical pipeline as POST /v1/screen. Designed for a Mojaloop hub to screen inline. The response adds a mojaloop block (transaction_id, quote_id) and the normalized_request.\n\n**Auth:** API key — `Authorization: Bearer jc_test_...` or `X-Api-Key`. Console sessions may omit it.","tags":["Screening"],"x-beta":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"transactionId":{"type":"string","description":"Mojaloop transaction identifier."},"amount":{"type":"object","description":"{ amount, currency } — e.g. { \"amount\": \"1250000\", \"currency\": \"KES\" }."},"payer":{"type":"object","description":"Payer party: { partyIdInfo: { partyIdType, partyIdentifier, fspId }, name?, personalInfo? }."},"payee":{"type":"object","description":"Payee party: same shape as payer."},"transactionType":{"type":"object","description":"{ scenario, initiator, initiatorType } — scenario maps to the canonical transaction type."},"note":{"type":"string","description":"Free-text note, mapped to metadata.narrative."}},"required":["transactionId","amount","payer","payee"]},"example":{"transactionId":"b51ec534-ee48-4575-b6a9-ead2955b8069","quoteId":"7c23e6c0-1a2b-4f3d-9e8a-2b1c0d4e5f6a","amount":{"amount":"1250000","currency":"KES"},"transactionType":{"scenario":"TRANSFER","initiator":"PAYER","initiatorType":"CONSUMER"},"payer":{"partyIdInfo":{"partyIdType":"MSISDN","partyIdentifier":"254712345678","fspId":"umojafsp"},"name":"Amina Odhiambo"},"payee":{"partyIdInfo":{"partyIdType":"MSISDN","partyIdentifier":"233201234567","fspId":"gtbfsp"},"name":"Chidi Nwosu"},"note":"invoice payment"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/screen/iso8583":{"post":{"operationId":"postScreenIso8583","summary":"Screen an ISO 8583 message","description":"Screens an ISO 8583 financial transaction message (MTI 0100/0200). The adapter maps DE2 (PAN), DE4 (amount), DE103 (commission) and other data elements to the canonical model, then runs the identical screening pipeline. Designed for card acquirers and switches routing native ISO 8583 traffic through screening. The response adds an iso8583 block with the adapted request and any parsing warnings.\n\n**Auth:** API key — `Authorization: Bearer jc_test_...` or `X-Api-Key`. Console sessions may omit it.","tags":["Screening"],"x-beta":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mti":{"type":"string","description":"4-digit message type indicator (e.g. \"0100\", \"0200\")."},"fields":{"type":"object","description":"Bitmap-indexed data elements keyed by field number (e.g. \"2\": \"...\" for PAN)."}},"required":["mti","fields"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/transactions":{"get":{"operationId":"getTransactions","summary":"List screened transactions","description":"Lists screened transactions from reporting history, newest first, with pagination. The response includes total, limit, offset, and a counts object ({ all, cleared, flagged }) computed before the status filter so status tabs stay accurate for the active filter set.\n\n**Auth:** Console session (any role).","tags":["Transactions"],"parameters":[{"name":"status","in":"query","required":false,"description":"cleared | flagged","schema":{"type":"string","enum":["cleared","flagged"]}},{"name":"type","in":"query","required":false,"description":"Transaction type filter (transfer, card, cash_deposit, remittance, mobile_money).","schema":{"type":"string"}},{"name":"channel","in":"query","required":false,"description":"api | mobile | branch | agent","schema":{"type":"string","enum":["api","mobile","branch","agent"]}},{"name":"currency","in":"query","required":false,"description":"Currency code filter, e.g. KES.","schema":{"type":"string"}},{"name":"country","in":"query","required":false,"description":"Corridor filter — matches country_from OR country_to.","schema":{"type":"string"}},{"name":"reviewed","in":"query","required":false,"description":"true | false","schema":{"type":"boolean"}},{"name":"disposition","in":"query","required":false,"description":"true_positive | false_positive | escalated","schema":{"type":"string","enum":["true_positive","false_positive","escalated"]}},{"name":"q","in":"query","required":false,"description":"Full-text search on id, names, and accounts.","schema":{"type":"string"}},{"name":"date_from","in":"query","required":false,"description":"Inclusive lower bound on transaction timestamp (ISO date).","schema":{"type":"string"}},{"name":"date_to","in":"query","required":false,"description":"Inclusive upper bound; date-only values mean end of day.","schema":{"type":"string"}},{"name":"amount_min","in":"query","required":false,"description":"Minimum transaction amount.","schema":{"type":"number"}},{"name":"amount_max","in":"query","required":false,"description":"Maximum transaction amount.","schema":{"type":"number"}},{"name":"risk_min","in":"query","required":false,"description":"Minimum risk_score (0..1).","schema":{"type":"number"}},{"name":"limit","in":"query","required":false,"description":"Page size, max 500 (default 25).","schema":{"type":"number"}},{"name":"offset","in":"query","required":false,"description":"Zero-based pagination offset.","schema":{"type":"number"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"patchTransactions","summary":"Review / disposition a record","description":"Marks a screening record as reviewed and/or sets the analyst disposition. Dispositions are the training labels for the Phase 2 supervised model — see docs/ml-roadmap.md. Escalated dispositions generate SAR drafts.\n\n**Auth:** Console session — disposition requires the analyst role.","tags":["Transactions"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"screening_id":{"type":"string","description":"The screening decision to update."},"reviewed":{"type":"boolean","description":"Mark the record reviewed."},"disposition":{"type":"string","enum":["true_positive","false_positive","escalated"],"description":"true_positive | false_positive | escalated"},"note":{"type":"string","description":"Optional analyst note, included in SAR drafts."}},"required":["screening_id"]},"example":{"screening_id":"scr_x81ka02f","reviewed":true,"disposition":"escalated","note":"Structuring pattern across 3 counterparties."}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/transactions/import":{"post":{"operationId":"postTransactionsImport","summary":"Bulk-import transactions","description":"Bulk-screens a CSV/JSON batch into the transaction history (unlike the sandbox, results are persisted). dry_run: true validates without screening. Idempotent: duplicate transaction ids are skipped. Requires analyst role.\n\n**Auth:** Console session — analyst role required.","tags":["Transactions"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionImport"},"example":{"raw":"string","filename":"string","dry_run":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/cases":{"get":{"operationId":"getCases","summary":"List cases","description":"Lists investigation cases, newest activity first, with queue stats and the distinct set of emitting institutions (the FSP triage dimension for switch / central-bank deployments). Non-cleared screening decisions automatically open or attach to a case per subject.\n\n**Auth:** Console session (any role).","tags":["Cases"],"parameters":[{"name":"status","in":"query","required":false,"description":"open | investigating | escalated | closed","schema":{"type":"string","enum":["open","investigating","escalated","closed"]}},{"name":"priority","in":"query","required":false,"description":"low | medium | high | critical","schema":{"type":"string","enum":["low","medium","high","critical"]}},{"name":"assignee","in":"query","required":false,"description":"Analyst id, or \"unassigned\".","schema":{"type":"string"}},{"name":"institution","in":"query","required":false,"description":"Emitting FSP (institution_id) of the case subject.","schema":{"type":"string"}},{"name":"sla","in":"query","required":false,"description":"breached — only cases past their SLA due time.","schema":{"type":"string"}},{"name":"q","in":"query","required":false,"description":"Search on case id, subject name, or subject account.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaseList"},"example":{"items":[],"total":-9007199254740991,"stats":{"open":-9007199254740991,"investigating":-9007199254740991,"escalated":-9007199254740991,"closed":-9007199254740991},"institutions":[],"assignees":[]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postCases","summary":"Open a case manually","description":"Opens a case manually — e.g. from an external referral, regulator request, or offline investigation. System-generated cases are created automatically by the screening pipeline; use this only for cases that did not originate from an alert.\n\n**Auth:** Console session — analyst role required.","tags":["Cases"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","description":"Human-readable case title."},"subject":{"type":"object","description":"Case subject. Requires subject.account; optional name, institution_id, country, role (sender | receiver)."},"priority":{"type":"string","enum":["low","medium","high","critical"],"description":"low | medium | high | critical (default medium). Sets the SLA due time."},"note":{"type":"string","description":"Optional opening note added to the timeline."}},"required":["title","subject"]},"example":{"title":"Regulator referral — suspected mule ring","priority":"high","subject":{"account":"0114589022","name":"Amina Odhiambo","institution_id":"KCBLKENX","country":"KE","role":"receiver"},"note":"Referred by UIF on 2026-07-08."}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Case"},"example":{"id":"string","environment":"test","subject":{"account":"string","name":"string","institution_id":"string","country":"string","role":"sender"},"title":"string","status":"open","priority":"low","source":"rule","assignee":"string","alerts":[],"events":[],"resolution":"confirmed_suspicious","resolution_note":"string","sla_due_at":"string","created_at":"string","updated_at":"string","closed_at":"string"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/cases/{id}":{"get":{"operationId":"getCase","summary":"Fetch a case","description":"Fetches a single case with its full audit timeline plus the complete screening records of every linked alert, so an investigator sees the underlying transactions, rule hits, and typology breaches in one call.\n\n**Auth:** Console session (any role).","tags":["Cases"],"parameters":[{"name":"id","in":"path","required":true,"description":"Case id (e.g. case_20260705_0015).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Case"},"example":{"id":"string","environment":"test","subject":{"account":"string","name":"string","institution_id":"string","country":"string","role":"sender"},"title":"string","status":"open","priority":"low","source":"rule","assignee":"string","alerts":[],"events":[],"resolution":"confirmed_suspicious","resolution_note":"string","sla_due_at":"string","created_at":"string","updated_at":"string","closed_at":"string"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"patchCase","summary":"Act on a case","description":"Performs an analyst action. Status transitions are validated (open→investigating/closed, investigating→escalated/closed, escalated→closed/investigating, closed→open to reopen). Priority changes re-derive the SLA. Every action appends an immutable event to the case timeline (the audit trail).\n\n**Auth:** Console session — analyst role required.","tags":["Cases"],"parameters":[{"name":"id","in":"path","required":true,"description":"Case id.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["open","investigating","escalated","closed"],"description":"open | investigating | escalated | closed (validated transition)."},"assignee":{"type":"string","description":"Assign / reassign to an analyst; empty string unassigns."},"priority":{"type":"string","enum":["low","medium","high","critical"],"description":"low | medium | high | critical — re-derives the SLA due time."},"note":{"type":"string","description":"Append an investigation note."},"resolution":{"type":"string","enum":["confirmed_suspicious","false_positive","reported","no_action"],"description":"confirmed_suspicious | false_positive | reported | no_action — closes the case."},"resolution_note":{"type":"string","description":"Optional rationale recorded with the resolution."}}},"example":{"resolution":"reported","resolution_note":"STR filed with UIF, ref 2026-0442."}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/rules":{"get":{"operationId":"getRules","summary":"List rules","description":"Lists all rules with status, version, and live performance stats (trigger_count, hit_rate — updated on every screening).\n\n**Auth:** Console session (any role).","tags":["Rules"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleList"},"example":{"items":[]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postRules","summary":"Create a rule","description":"Creates a rule from typed YAML. The YAML is validated against the field catalog and operator set before acceptance. See the Rule YAML guide for the schema.\n\n**Auth:** Console session — analyst role required.","tags":["Rules"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"yaml":{"type":"string","description":"Rule definition in typed YAML."},"status":{"type":"string","description":"draft (default) | active | disabled"}},"required":["yaml"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rule"},"example":{"id":"string","name":"string","description":"string","severity":"low","weight":0,"status":"active","version":-9007199254740991,"yaml":"string","trigger_count":0,"hit_rate":0,"created_at":"string","updated_at":"string"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/rules/bulk":{"post":{"operationId":"postRulesBulk","summary":"Bulk create / upsert rules","description":"Creates or upserts many rules in one request — the surface behind the console’s bulk import and infra-as-code tooling like the Terraform provider (which renders a rule set per environment and posts it here). Accepts a multi-document YAML string (documents separated by \"---\") or a \"rules\" array. Each rule is validated independently and reported with its own outcome (created / replaced / skipped / error). Use on_conflict=replace for idempotent syncs.\n\n**Auth:** Console session — analyst role required.","tags":["Rules"],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"yaml":{"type":"string","description":"Multiple rule documents separated by \"---\". Provide this OR \"rules\"."},"rules":{"type":"array","items":{},"description":"Array of rule YAML strings, or objects { yaml, status }. Provide this OR \"yaml\"."},"on_conflict":{"type":"string","description":"skip (default) keeps existing; replace upserts (idempotent); error fails conflicting items."},"atomic":{"type":"boolean","description":"When true, validate everything first and apply nothing if any item errors. Default false."},"default_status":{"type":"string","description":"draft (default) | active — status for items that don’t set their own."}}},"example":{"on_conflict":"replace","default_status":"active","yaml":"rule:\n  id: high-value-cross-border\n  name: High-value cross-border\n  severity: high\n  weight: 0.7\n  when:\n    all:\n      - field: transaction.amount\n        op: gt\n        value: 1000000\n---\nrule:\n  id: dormant-account-burst\n  name: Dormant account burst\n  severity: medium\n  weight: 0.5\n  when:\n    all:\n      - field: profile.new_counterparty\n        op: eq\n        value: true"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"applied":true,"summary":{"total":2,"created":1,"replaced":1,"skipped":0,"errors":0},"results":[{"index":0,"id":"high-value-cross-border","name":"High-value cross-border","outcome":"replaced"},{"index":1,"id":"dormant-account-burst","name":"Dormant account burst","outcome":"created"}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/rules/{id}":{"get":{"operationId":"getRule","summary":"Fetch a rule","description":"Fetches a single rule by id, including its YAML source and stats.\n\n**Auth:** Console session (any role).","tags":["Rules"],"parameters":[{"name":"id","in":"path","required":true,"description":"Rule id (matches the id in the YAML).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rule"},"example":{"id":"string","name":"string","description":"string","severity":"low","weight":0,"status":"active","version":-9007199254740991,"yaml":"string","trigger_count":0,"hit_rate":0,"created_at":"string","updated_at":"string"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"putRule","summary":"Update a rule","description":"Updates rule YAML and/or status. The rule id inside the YAML must match the path id — create a new rule to change the id. YAML updates increment the rule version.\n\n**Auth:** Console session — analyst role required.","tags":["Rules"],"parameters":[{"name":"id","in":"path","required":true,"description":"Rule id.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"yaml":{"type":"string","description":"New YAML (validated; bumps version)."},"status":{"type":"string","enum":["active","draft","disabled"],"description":"active | draft | disabled"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteRule","summary":"Delete a rule","description":"Permanently deletes a rule.\n\n**Auth:** Console session — admin role required.","tags":["Rules"],"parameters":[{"name":"id","in":"path","required":true,"description":"Rule id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/rules/{id}/versions":{"get":{"operationId":"getRuleVersions","summary":"List rule versions","description":"Returns the full version history for a rule, newest first. Each entry records the YAML snapshot, version number, status at that version, and who made the change.\n\n**Auth:** Console session (any role).","tags":["Rules"],"parameters":[{"name":"id","in":"path","required":true,"description":"Rule id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/typologies":{"get":{"operationId":"getTypologies","summary":"List typologies","description":"Lists all typologies with status, version, and live trigger stats.\n\n**Auth:** Console session (any role).","tags":["Typologies"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TypologyList"},"example":{"items":[]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postTypologies","summary":"Create a typology","description":"Creates a typology from typed YAML. The YAML is validated for structure, weights, and thresholds, and every referenced rule_id must already exist.\n\n**Auth:** Console session — analyst role required.","tags":["Typologies"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"yaml":{"type":"string","description":"Typology definition in typed YAML."},"status":{"type":"string","description":"draft (default) | active"}},"required":["yaml"]},"example":{"yaml":"typology:\n  id: money-mule-receiver\n  name: Money mule receiver\n  category: money_mule\n  rules:\n    - rule_id: rapid-inbound-velocity\n      weight: 0.4\n    - rule_id: new-sender-burst\n      weight: 0.3\n    - rule_id: pass-through-account\n      weight: 0.3\n  alert_threshold: 0.6\n  interdict_threshold: 0.9","status":"active"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Typology"},"example":{"id":"string","name":"string","description":"string","category":"string","rules":[],"alert_threshold":0,"interdict_threshold":0,"status":"active","version":-9007199254740991,"yaml":"string","trigger_count":0,"created_at":"string","updated_at":"string"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/typologies/{id}":{"get":{"operationId":"getTypology","summary":"Fetch a typology","description":"Fetches a single typology by id, including its YAML source, member rules, thresholds, and stats.\n\n**Auth:** Console session (any role).","tags":["Typologies"],"parameters":[{"name":"id","in":"path","required":true,"description":"Typology id (matches the id in the YAML).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Typology"},"example":{"id":"string","name":"string","description":"string","category":"string","rules":[],"alert_threshold":0,"interdict_threshold":0,"status":"active","version":-9007199254740991,"yaml":"string","trigger_count":0,"created_at":"string","updated_at":"string"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"putTypology","summary":"Update a typology","description":"Updates typology YAML and/or status. The id inside the YAML must match the path id — create a new typology to change the id. Referenced rules must exist; YAML updates increment the version.\n\n**Auth:** Console session — analyst role required.","tags":["Typologies"],"parameters":[{"name":"id","in":"path","required":true,"description":"Typology id.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"yaml":{"type":"string","description":"New YAML (validated; bumps version)."},"status":{"type":"string","enum":["active","draft","disabled"],"description":"active | draft | disabled"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteTypology","summary":"Delete a typology","description":"Permanently deletes a typology. Member rules are unaffected.\n\n**Auth:** Console session — admin role required.","tags":["Typologies"],"parameters":[{"name":"id","in":"path","required":true,"description":"Typology id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/typologies/{id}/versions":{"get":{"operationId":"getTypologyVersions","summary":"List typology versions","description":"Returns the full version history for a typology, newest first. Each entry records the YAML snapshot, version number, status at that version, and who made the change.\n\n**Auth:** Console session (any role).","tags":["Typologies"],"parameters":[{"name":"id","in":"path","required":true,"description":"Typology id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sandbox/run":{"post":{"operationId":"postSandboxRun","summary":"Run a sandbox simulation","description":"Runs transactions through the full engine without persisting anything to reporting history.\n\n**Auth:** Console session (any role).","tags":["Sandbox"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"transactions":{"type":"array","items":{},"description":"ScreeningRequest[] to evaluate."},"rule_ids":{"type":"array","items":{"type":"string"},"description":"Restrict evaluation to specific rules (defaults to all active)."},"include_drafts":{"type":"boolean","description":"Also evaluate draft rules."},"yaml":{"type":"string","description":"Ad-hoc rule YAML to test without saving."},"yaml_only":{"type":"boolean","description":"Evaluate only the ad-hoc YAML rule."}},"required":["transactions"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sandbox/sample":{"get":{"operationId":"getSandboxSample","summary":"Get sample transactions","description":"Returns a ready-made set of representative sample transactions for use as sandbox input.\n\n**Auth:** Console session (any role).","tags":["Sandbox"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sandbox/scenarios":{"get":{"operationId":"getSandboxScenarios","summary":"Get test scenarios","description":"Returns YAML test scenarios — predefined rule + typology configurations with matching transaction samples for manual or automated testing.\n\n**Auth:** Console session (any role).","tags":["Sandbox"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/blacklists":{"get":{"operationId":"getBlacklists","summary":"List blacklist entries","description":"Lists blacklist entries. Expired entries (past expires_at) remain listed but are skipped during screening.\n\n**Auth:** Console session (any role).","tags":["Blacklists"],"parameters":[{"name":"list","in":"query","required":false,"description":"accounts | institutions | corridors | devices | transaction_types","schema":{"type":"string","enum":["accounts","institutions","corridors","devices","transaction_types"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlacklistList"},"example":{"items":[]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postBlacklists","summary":"Add a blacklist entry","description":"Adds an entry. Any screening hit on a non-expired entry results in status \"flagged\" with maximum confidence, regardless of rules or model scores.\n\n**Auth:** Console session — analyst role required.","tags":["Blacklists"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"list":{"type":"string","enum":["accounts","institutions","corridors","devices","transaction_types"],"description":"accounts | institutions | corridors | devices | transaction_types"},"value":{"type":"string","description":"The value to match (account number, BIC, \"KE->NG\" corridor, ...)."},"reason":{"type":"string","description":"Audit note."},"expires_at":{"type":"string","format":"date-time","description":"Optional expiry; entry is ignored after this time."},"min_amount":{"type":"number","description":"Only match at or above this amount."},"corridor":{"type":"string","description":"Restrict the entry to a corridor."}},"required":["list","value"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlacklistEntry"},"example":{"id":"string","list":"accounts","value":"string","reason":"string","source":"manual","expires_at":null,"created_at":"string","min_amount":0,"corridor":"string"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/blacklists?id={id}":{"delete":{"operationId":"deleteBlacklists","summary":"Remove an entry","description":"Removes a blacklist entry by id.\n\n**Auth:** Console session — analyst role required.","tags":["Blacklists"],"parameters":[{"name":"id","in":"query","required":true,"description":"Entry id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/profiles":{"get":{"operationId":"getProfiles","summary":"List behavioral profiles","description":"Lists behavioral profiles built from screening history. subject_id is the sender account number. A profile is created from the subject’s first screened transaction and matures (emerging → established → mature) as history accrues; the confidence field reflects how much history backs it.\n\n**Auth:** Console session (any role).","tags":["Profiles"],"parameters":[{"name":"risk_band","in":"query","required":false,"description":"low | medium | high","schema":{"type":"string","enum":["low","medium","high"]}},{"name":"q","in":"query","required":false,"description":"Search on subject.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"number"}},{"name":"offset","in":"query","required":false,"description":"Pagination offset.","schema":{"type":"number"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/profiles/{subject_id}":{"get":{"operationId":"getProfile","summary":"Fetch a profile","description":"Full profile: derived features (typical amounts, hours, channels, corridors), risk band, embedding metadata, and recent_transactions[].\n\n**Auth:** Console session (any role).","tags":["Profiles"],"parameters":[{"name":"subject_id","in":"path","required":true,"description":"Sender account number.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/profiles/{subject_id}/score":{"post":{"operationId":"postProfileScore","summary":"What-if scoring","description":"Scores a candidate transaction against the profile without screening it. Returns anomaly_score and per-feature deviations — useful for pre-flight checks and tuning profile-aware rules.\n\n**Auth:** Console session (any role).","tags":["Profiles"],"parameters":[{"name":"subject_id","in":"path","required":true,"description":"Sender account number.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"transaction":{"type":"object","description":"{ amount, type?, channel?, country_to?, country_from?, timestamp? }"},"receiver_account":{"type":"string","description":"Candidate counterparty for new-counterparty detection."}},"required":["transaction"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/profiles/{subject_id}/neighbors":{"get":{"operationId":"getProfileNeighbors","summary":"Peer group","description":"Profiles most similar in embedding space — the subject’s behavioral peer group.\n\n**Auth:** Console session (any role).","tags":["Profiles"],"parameters":[{"name":"subject_id","in":"path","required":true,"description":"Sender account number.","schema":{"type":"string"}},{"name":"k","in":"query","required":false,"description":"Neighbors to return (default 5, max 20).","schema":{"type":"number"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/profiles/{subject_id}/network":{"get":{"operationId":"getProfileNetwork","summary":"Counterparty network","description":"Counterparty network graph served from the incrementally-maintained graph index (updated O(1) per screening — no history rescans). Returns { network: { root, nodes[], edges[], truncated } }. Nodes carry depth, risk band, and blacklist status; edges carry txn_count, total_amount, flagged_count, corridors, and first/last seen.\n\n**Auth:** Console session (any role).","tags":["Profiles"],"x-beta":true,"parameters":[{"name":"subject_id","in":"path","required":true,"description":"Sender account number.","schema":{"type":"string"}},{"name":"depth","in":"query","required":false,"description":"Traversal depth, 1–6 (default 1). Node cap 300.","schema":{"type":"number"}},{"name":"min_txn","in":"query","required":false,"description":"Minimum transactions per edge.","schema":{"type":"number"}},{"name":"flagged_only","in":"query","required":false,"description":"Only include flagged edges.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/profiles/{subject_id}/trace":{"get":{"operationId":"getProfileTrace","summary":"Follow-the-money trace","description":"Directed, time-aware path search over the pre-aggregated edge graph — answers \"where did the money go\" (outbound) or \"where did it come from\" (inbound). Money in must precede money out at each hop. Returns { trace: { root, direction, paths[], truncated } }; each path carries ordered hops, bottleneck volume, per-hop attenuation, and a suspicious flag when any edge on the path has flagged activity. Paths are ranked by volume.\n\n**Auth:** Console session (any role).","tags":["Profiles"],"x-beta":true,"parameters":[{"name":"subject_id","in":"path","required":true,"description":"Sender account number.","schema":{"type":"string"}},{"name":"direction","in":"query","required":false,"description":"outbound | inbound (default outbound).","schema":{"type":"string","enum":["outbound","inbound"]}},{"name":"max_hops","in":"query","required":false,"description":"Maximum path depth, 1–6 (default 4).","schema":{"type":"number"}},{"name":"max_paths","in":"query","required":false,"description":"Maximum paths returned (default 25).","schema":{"type":"number"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/profiles/build":{"post":{"operationId":"postProfilesBuild","summary":"Rebuild profiles","description":"Triggers an async profile (re)build over screening history. Returns a build job (202 Accepted) — poll the status endpoint.\n\n**Auth:** Console session (any role).","tags":["Profiles"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/profiles/build/{job_id}":{"get":{"operationId":"getProfilesBuildJob","summary":"Poll build job","description":"Polls the status of a profile build job. Returns { job: { job_id, status, subjects_processed, subjects_total, ... } }.\n\n**Auth:** Console session (any role).","tags":["Profiles"],"parameters":[{"name":"job_id","in":"path","required":true,"description":"Job id from POST /profiles/build.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/profiles/resolve":{"get":{"operationId":"getProfilesResolve","summary":"List entity alias candidates","description":"Returns entity alias candidates for identity resolution — accounts that may belong to the same entity. Surface pending candidates for analyst review.\n\n**Auth:** Console session (any role).","tags":["Profiles"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"patchProfilesResolve","summary":"Review an alias candidate","description":"Approves or rejects an entity alias candidate. Approved aliases merge the profiles; rejected candidates are dismissed.\n\n**Auth:** Console session — analyst role required.","tags":["Profiles"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityAliasReview"},"example":{"id":"string","status":"approved","by":"string","note":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/networks":{"get":{"operationId":"getNetworks","summary":"List extracted networks","description":"Full-graph network extraction: every connected community in the transaction graph, scored as a unit. Returns { overview: { networks[], patterns[], links[], node_count, edge_count } }. Each network carries a composite risk_score (flag rate, blacklist members, high-risk profiles, detected patterns), member/volume stats, and top accounts. patterns[] are structural motifs (fan_in, fan_out, pass_through, cycle) with strength scores; links[] connect networks via shared institutions or name-based identity matches. Recomputed only when new transactions land — cached per graph-index version.\n\n**Auth:** Console session (any role).","tags":["Networks"],"x-beta":true,"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"overview":{"generated_at":"2026-07-11T09:14:01Z","node_count":209,"edge_count":160,"networks":[{"id":"net_0111797308","label":"Daniel Mensah network","node_count":34,"edge_count":41,"txn_count":122,"total_amount":48120000,"flag_rate":0.31,"risk_score":0.78,"pattern_types":["fan_in","pass_through"],"top_accounts":[{"account":"0111797308","name":"Daniel Mensah","txn_count":38,"total_amount":9100000}],"countries":["KE","TZ","UG"],"institutions":["KCBLKENX","CRDBTZTZ"]}],"patterns":[{"id":"pat_fan_in_0111797308","type":"fan_in","hub":"0111797308","hub_name":"Daniel Mensah","accounts":["0111797308","0117917122"],"score":0.82,"txn_count":27,"network_id":"net_0111797308","detail":"9 distinct senders converge on this account within the window."}],"links":[{"network_a":"net_0111797308","network_b":"net_0117917122","kind":"shared_institution","value":"KCBLKENX","detail":"Both networks transact through KCBLKENX."}]}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/networks/{id}":{"get":{"operationId":"getNetwork","summary":"Fetch an extracted network","description":"One extracted network in full: summary stats, the renderable graph ({ nodes[], edges[] } — same shape as the counterparty network), the structural patterns detected inside it, and its cross-network links. 404 if the network id no longer exists (networks are re-extracted as the graph evolves).\n\n**Auth:** Console session (any role).","tags":["Networks"],"x-beta":true,"parameters":[{"name":"id","in":"path","required":true,"description":"Network id (e.g. net_0111797308) from GET /v1/networks.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks":{"get":{"operationId":"getWebhooks","summary":"List webhooks","description":"Lists registered endpoints (secrets redacted), the complete event catalog, and the 100 most recent delivery records.\n\n**Auth:** API key — `Authorization: Bearer jc_test_...` or `X-Api-Key`. Console sessions may omit it.","tags":["Webhooks"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookList"},"example":{"items":[]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postWebhooks","summary":"Register a webhook","description":"Registers a public HTTPS endpoint for versioned AML events. The HMAC secret is returned once. Signatures use t=<unix>,v1=<hex> over timestamp.raw_body. Simulate mode sends real signed test requests with the same timeout, retry, dead-letter, and replay behavior as live delivery.\n\n**Auth:** Console session — admin role required.","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreate"},"example":{"url":"https://core.yourbank.example/aml/webhook","events":["screening.*","case.status_changed","sar.submitted"],"transport":"https"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"},"example":{"webhook":{"id":"wh_9k2m1x0a","url":"https://core.yourbank.example/aml/webhook","events":["screening.*","case.status_changed","sar.submitted"],"secret":"whsec_f81ka02fb4c1d9e2","transport":"https","active":true,"created_at":"2026-07-14T09:14:01Z"}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"patchWebhooks","summary":"Update a webhook","description":"Updates the URL, subscriptions, transport, description, or active state of an endpoint.\n\n**Auth:** Console session — admin role required.","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookUpdate"},"example":{"id":"string","url":"string","events":[],"transport":"https","active":false,"description":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks/deliveries/{id}/replay":{"post":{"operationId":"replayWebhookDelivery","summary":"Replay a dead-letter delivery","description":"Re-signs the retained raw payload and resets the retry budget for a dead-letter delivery.\n\n**Auth:** Console session — admin role required.","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"description":"Webhook delivery id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks?id={id}":{"delete":{"operationId":"deleteWebhooks","summary":"Delete a webhook","description":"Removes a webhook endpoint. In-flight deliveries are not cancelled.\n\n**Auth:** Console session — admin role required.","tags":["Webhooks"],"parameters":[{"name":"id","in":"query","required":true,"description":"Webhook id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks/alert-test":{"post":{"operationId":"postWebhookAlertTest","summary":"Test the failure-notification destination","description":"Sends a synthetic delivery-failure notification to the destination configured in organization settings (webhook_alert_url), so it can be verified before a real outage. Returns 422 when no destination is set and 502 with the upstream error when the destination rejects the message.\n\n**Auth:** Console session — admin role required.","tags":["Webhooks"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sanctions/screen":{"post":{"operationId":"postSanctionsScreen","summary":"Ad-hoc name screening","description":"Screens one or more names against the active watchlists in real time — for KYC onboarding, pre-payout checks, or on-demand queries. Returns match results with scores and hit/monitor/clear decisions per name.\n\n**Auth:** API key — `Authorization: Bearer jc_test_...` or `X-Api-Key`. Console sessions may omit it.","tags":["Sanctions"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SanctionsScreenRequest"},"example":{"name":"string","names":[],"min_score":0}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sanctions/entities":{"get":{"operationId":"getSanctionsEntities","summary":"List sanctions entities","description":"Returns all watchlist entities currently loaded across all active sources.\n\n**Auth:** Console session (any role).","tags":["Sanctions"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sanctions/lists":{"get":{"operationId":"getSanctionsLists","summary":"List watchlist sources","description":"Returns the configured watchlist sources with operational status, entity counts, and provider mode.\n\n**Auth:** Console session (any role).","tags":["Sanctions"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"patchSanctionsLists","summary":"Toggle a watchlist","description":"Enables or disables a sanctions watchlist source. Disabled sources are skipped during screening.\n\n**Auth:** Console session — admin role required.","tags":["Sanctions"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SanctionsListToggle"},"example":{"source":"OFAC_SDN","enabled":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postSanctionsListsRefresh","summary":"Refresh watchlists","description":"Triggers a manual refresh of all watchlist feeds. Returns the diff summary (added, updated, removed per source).\n\n**Auth:** Console session — analyst role required.","tags":["Sanctions"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sanctions/matches":{"get":{"operationId":"getSanctionsMatches","summary":"List whitelisted matches","description":"Returns the false-positive whitelist — (entity, account) pairs that analysts have cleared so the match is suppressed on future screenings.\n\n**Auth:** Console session (any role).","tags":["Sanctions"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postSanctionsMatches","summary":"Clear a match (false positive)","description":"Marks a sanctions match as a confirmed false positive, adding it to the whitelist so the match is suppressed on future screens.\n\n**Auth:** Console session — analyst role required.","tags":["Sanctions"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SanctionsMatchClear"},"example":{"entity_id":"string","account":"string","query_name":"string","reason":"string","by":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteSanctionsMatches","summary":"Re-activate a match","description":"Removes a whitelist entry, re-activating the sanctions match for future screenings. Requires the match_id query parameter.\n\n**Auth:** Console session — analyst role required.","tags":["Sanctions"],"parameters":[{"name":"match_id","in":"query","required":true,"description":"The whitelist entry id to remove.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sanctions/ingest":{"get":{"operationId":"getSanctionsIngest","summary":"Ingest freshness stats","description":"Returns current sanctions data freshness: last-updated timestamps per source and total entity count.\n\n**Auth:** Console session (any role).","tags":["Sanctions"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postSanctionsIngest","summary":"Trigger list ingestion","description":"Triggers a fresh download and ingestion of one or all sanctions lists. Accepts an optional { source } to refresh a single list. In production this runs on a 6-hour cron.\n\n**Auth:** Console session — analyst role required.","tags":["Sanctions"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sanctions/rescreen":{"post":{"operationId":"postSanctionsRescreen","summary":"Continuous re-screening","description":"Re-runs sanctions screening across the full stored history against the current lists + whitelist. Opens cases for counterparties that newly match after a list update.\n\n**Auth:** Console session — analyst role required.","tags":["Sanctions"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sanctions/custom-lists":{"get":{"operationId":"getSanctionsCustomLists","summary":"Get client watchlist","description":"Returns the client-managed watchlist with schema, column definitions, and entity count.\n\n**Auth:** Console session (any role).","tags":["Sanctions"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postSanctionsCustomLists","summary":"Upload client watchlist","description":"Uploads a CSV or XLSX file to replace the client-managed watchlist. Replaces the entire list atomically.\n\n**Auth:** Console session — admin role required.","tags":["Sanctions"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"patchSanctionsCustomLists","summary":"Toggle client watchlist","description":"Enables or disables the client-managed watchlist for screening.\n\n**Auth:** Console session — admin role required.","tags":["Sanctions"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sanctions/custom-lists/template":{"get":{"operationId":"getSanctionsCustomListsTemplate","summary":"Get CSV template","description":"Returns a CSV template showing the required columns for the client watchlist import.\n\n**Auth:** Console session (any role).","tags":["Sanctions"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/metrics":{"get":{"operationId":"getMetrics","summary":"Dashboard metrics","description":"Aggregated reporting metrics: totals, flag rate, top triggered rules, and 14-day trend data.\n\n**Auth:** Console session (any role).","tags":["Reporting"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sars":{"get":{"operationId":"getSars","summary":"List SAR drafts","description":"Suspicious Activity Report drafts, generated from escalated alert dispositions. Each draft includes subject, counterparty, matched rules, and a generated narrative ready for compliance review. Export from the SAR Drafts console page.\n\n**Auth:** Console session (any role).","tags":["Reporting"],"x-beta":true,"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sars/{id}/export":{"get":{"operationId":"getSarExport","summary":"Export SAR draft","description":"Returns the SAR draft in a downloadable format suitable for filing with the regulator.\n\n**Auth:** Console session (any role).","tags":["Reporting"],"x-beta":true,"parameters":[{"name":"id","in":"path","required":true,"description":"SAR draft id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sars/{id}/status":{"patch":{"operationId":"patchSarStatus","summary":"Advance SAR workflow","description":"Advances the SAR sign-off workflow: draft → under_review → approved → submitted. The approved/submitted transitions require admin role.\n\n**Auth:** Console session — analyst or admin role required depending on transition.","tags":["Reporting"],"parameters":[{"name":"id","in":"path","required":true,"description":"SAR draft id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SarStatusUpdate"},"example":{"status":"under_review","by":"string","note":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/demo-requests":{"post":{"operationId":"postDemoRequest","summary":"Request a demo","description":"Landing-page demo intake. Records the request against the activity trail and routes it to a solutions engineer. Provisions nothing — instances are deployed per institution, not signed up for.\n\n**Auth:** Public.","tags":["Onboarding"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DemoRequest"},"example":{"contactName":"string","workEmail":"user@example.com","institution":"string","country":"","role":"","deploymentInterest":"managed","volumeBand":"not-sure","message":""}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DemoRequestResponse"},"example":{"reference":"string","status":"string","deployment_interest":"managed","nextSteps":[]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/onboarding/status":{"get":{"operationId":"getOnboardingStatus","summary":"Get onboarding checklist","description":"Returns the first-run checklist state — derived from what the org has actually done: created a test key, screened a transaction, activated a rule, and reviewed a sanctions match.\n\n**Auth:** Console session (any role).","tags":["Onboarding"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"putOnboardingStatus","summary":"Dismiss or restore checklist","description":"Dismisses the onboarding checklist so it does not show on subsequent visits, or restores it if previously dismissed.\n\n**Auth:** Console session (any role).","tags":["Onboarding"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingStatusDismiss"},"example":{"dismissed":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/settings/organization":{"get":{"operationId":"getSettingsOrganization","summary":"Get organization","description":"Returns the institution profile: name, country, institution type, and active API key count. Raw API keys are never returned from this endpoint.\n\n**Auth:** Console session (any role).","tags":["Settings"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"patchSettingsOrganization","summary":"Update organization","description":"Updates organization profile fields.\n\n**Auth:** Console session — admin role required.","tags":["Settings"],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Institution name (2–80 chars)."},"country":{"type":"string","description":"ISO 3166-1 alpha-2 country code."},"institution_type":{"type":"string","description":"bank | psp | mfi | sacco | fintech"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/settings/api-keys":{"get":{"operationId":"getSettingsApiKeys","summary":"List API keys","description":"Lists the API keys with masked values, environment, and last-used timestamps.\n\n**Auth:** Console session (any role).","tags":["Settings"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postSettingsApiKeys","summary":"Create API key","description":"Sandbox keys return HTTP 201 with outcome created and the plaintext key once. Live keys return HTTP 202 with outcome pending_approval and are created only after approval by a different administrator. The approving checker receives the plaintext live key once in the approval response; subsequent reads never expose it.\n\n**Auth:** Console session — admin role required.","tags":["Settings"],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","description":"Human-readable label, e.g. \"Core banking integration\"."},"environment":{"type":"string","enum":["test","live"],"description":"test | live (default test)"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"outcome":"created","key":{"id":"key_a1b2c3d4","plaintext_key":"jc_test_...","label":"Core banking integration","environment":"test","created_at":"2026-07-07T12:00:00.000Z"}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteSettingsApiKeys","summary":"Revoke API key","description":"Revokes an API key by id. Revoked keys stop authenticating immediately.\n\n**Auth:** Console session — admin role required.","tags":["Settings"],"parameters":[{"name":"id","in":"query","required":true,"description":"The key id to revoke.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"patchSettingsApiKeys","summary":"Rotate an API key","description":"Rotates an API key, producing a new key and optionally keeping the old one alive for a grace period. Live key rotations go through maker-checker approval.\n\n**Auth:** Console session — admin role required.","tags":["Settings"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyRotate"},"example":{"action":"string","id":"string","grace_minutes":-9007199254740991,"label":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/settings/models":{"get":{"operationId":"getSettingsModels","summary":"Get model config","description":"Returns the active ML model (mock or trained artifact) and governance settings.\n\n**Auth:** Console session (any role).","tags":["Settings"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"patchSettingsModels","summary":"Update model governance","description":"Updates mutable governance settings: shadow mode, drift thresholds, and challenger model toggle.\n\n**Auth:** Console session — admin role required.","tags":["Settings"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelGovernance"},"example":{"governance":{"shadow_mode":false,"drift_threshold":0,"drift_window_days":1,"alert_on_drift":false,"challenger_enabled":false}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/settings/retention":{"get":{"operationId":"getSettingsRetention","summary":"Get retention policy","description":"Returns the current data retention policy with jurisdiction presets, category labels, and the PII field inventory.\n\n**Auth:** Console session (any role).","tags":["Settings"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"patchSettingsRetention","summary":"Update retention policy","description":"Updates the data retention policy. The jurisdiction preset and per-category retention days are validated against statutory minimums.\n\n**Auth:** Console session — admin role required.","tags":["Settings"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetentionUpdate"},"example":{"jurisdiction_preset":"string","categories":null,"note":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/settings/invitations":{"get":{"operationId":"getSettingsInvitations","summary":"List invitations","description":"Lists pending and accepted team invitations.\n\n**Auth:** Console session (any role).","tags":["Settings"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postSettingsInvitations","summary":"Create invitation","description":"Invites a user to join the team. The invitee receives an email with an acceptance link. Rate-limited to 10 invites/minute and 100 invites/day.\n\n**Auth:** Console session — admin role required.","tags":["Settings"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationCreate"},"example":{"email":"user@example.com","name":"string","role":"analyst"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/activity":{"get":{"operationId":"getActivity","summary":"Activity / audit log","description":"Returns the unified, append-only activity log — both console user actions (rule edits, case decisions, watchlist toggles, key management) and API requests (screening calls with method, path, status, latency, and the calling API key). Time-ordered newest-first and immutable: entries are never modified or deleted through the API. Use it for compliance audit trails, incident forensics, and usage monitoring.\n\n**Auth:** Console session — analyst role required.","tags":["Activity"],"parameters":[{"name":"category","in":"query","required":false,"description":"user_action | api_request | system","schema":{"type":"string","enum":["user_action","api_request","system"]}},{"name":"status","in":"query","required":false,"description":"success | denied | error","schema":{"type":"string","enum":["success","denied","error"]}},{"name":"resource_type","in":"query","required":false,"description":"Filter by resource, e.g. rule, case, sanctions_match, api_key, screening.","schema":{"type":"string"}},{"name":"q","in":"query","required":false,"description":"Free-text search across summary, action, actor, path, and resource id.","schema":{"type":"string"}},{"name":"since","in":"query","required":false,"description":"ISO timestamp lower bound.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Page size (default 100, max 200).","schema":{"type":"number"}},{"name":"offset","in":"query","required":false,"description":"Pagination offset.","schema":{"type":"number"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"total":1284,"items":[{"id":"act_9f2a1c7b","timestamp":"2026-07-08T09:41:12.004Z","category":"user_action","action":"sanctions.match_clear","actor":{"kind":"user","id":"a.wanjiku","name":"a.wanjiku"},"resource":{"type":"sanctions_match","id":"pep-44120"},"summary":"Cleared sanctions match for pep-44120 as false positive — DOB mismatch","status":"success"},{"id":"act_1b7d33e0","timestamp":"2026-07-08T09:40:58.771Z","category":"api_request","action":"POST","actor":{"kind":"api_key","id":"key_live_2","name":"Production key (live)"},"summary":"POST /api/v1/screen → 200","status":"success","method":"POST","path":"/api/v1/screen","status_code":200,"latency_ms":42}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/health":{"get":{"operationId":"getHealth","summary":"Health check","description":"Lightweight health check returning overall status, storage mode (mock or database), database connectivity, loaded rule count, and a coarse per-dependency status list. Probes local dependencies only. Returns 503 when the database is configured but unreachable; a degraded Redis or sanctions provider still returns 200. Used by load balancers and monitoring.\n\n**Auth:** Public.","tags":["Meta"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/health/dependencies":{"get":{"operationId":"getHealthDependencies","summary":"Dependency health detail","description":"Full live status for every external dependency — Postgres, Redis, and the sanctions provider — with per-probe latency, error codes, and remediation hints. Distinguishes not_configured (a supported deployment mode) from down (a fault). The outbound sanctions provider check is cached for roughly 60 seconds. Always returns 200 when authorized; /api/v1/health owns the 503 semantics.\n\n**Auth:** Console session — viewer role required.","tags":["Meta"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/readiness":{"get":{"operationId":"getReadiness","summary":"Readiness probe","description":"Readiness probe — returns 200 when the server is ready to accept traffic.\n\n**Auth:** Public.","tags":["Meta"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/openapi":{"get":{"operationId":"getOpenapi","summary":"OpenAPI 3.1 spec","description":"The machine-readable OpenAPI 3.1 specification for this API, generated from the same endpoint catalog that renders these docs — so the spec and the docs can never drift. YAML by default; use it to generate typed clients, run contract tests, or import into Postman/Insomnia.\n\n**Auth:** Public.","tags":["Meta"],"parameters":[{"name":"format","in":"query","required":false,"description":"json — return the spec as JSON instead of YAML.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/environment":{"get":{"operationId":"getEnvironment","summary":"Get console environment","description":"Returns the currently selected console environment (test or live).\n\n**Auth:** Console session (any role).","tags":["Meta"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"putEnvironment","summary":"Switch console environment","description":"Switches the console environment between test and live. Persisted in an httpOnly cookie.\n\n**Auth:** Console session — analyst role required.","tags":["Meta"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentUpdate"},"example":{"environment":"test"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/feedback":{"get":{"operationId":"getFeedback","summary":"List feedback labels","description":"Lists analyst feedback labels (true_positive, false_positive, suspicious) plus aggregated stats — newest first.\n\n**Auth:** Console session (any role).","tags":["Feedback"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postFeedback","summary":"Label a screening","description":"Manually labels a screening record for ML training feedback. Case resolutions and SAR filings write labels automatically; this endpoint covers ad-hoc labeling.\n\n**Auth:** Console session — analyst role required.","tags":["Feedback"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackCreate"},"example":{"screening_id":"string","label":"true_positive","note":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/feedback/export":{"get":{"operationId":"getFeedbackExport","summary":"Export feedback labels","description":"Exports all feedback labels for ML training pipeline consumption.\n\n**Auth:** Console session (any role).","tags":["Feedback"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/approvals":{"get":{"operationId":"getApprovals","summary":"List approval requests","description":"Lists maker-checker approval requests for pending, approved, rejected, and cancelled items. Used by administrators to review and act on change requests.\n\n**Auth:** Console session — viewer role required.","tags":["Approvals"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/approvals/{id}":{"get":{"operationId":"getApproval","summary":"Fetch approval request","description":"Fetches a single approval request by id.\n\n**Auth:** Console session — viewer role required.","tags":["Approvals"],"parameters":[{"name":"id","in":"path","required":true,"description":"Approval request id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postApprovalDecision","summary":"Decide an approval","description":"Approves, rejects, or cancels a pending approval request. Live API key creations and rotations require a second admin to approve.\n\n**Auth:** Console session — admin role required.","tags":["Approvals"],"parameters":[{"name":"id","in":"path","required":true,"description":"Approval request id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApprovalDecision"},"example":{"decision":"approve","reason":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/approvals/sweep":{"post":{"operationId":"postApprovalsSweep","summary":"Sweep for overdue approvals","description":"Scans pending approval requests and sends the time-based notifications: an escalation once a request has gone unactioned past APPROVAL_ESCALATE_AFTER_HOURS (default 24), and a warning before it lapses at its 7-day expiry. Intended for a scheduler on an hourly cadence. Idempotent — each stage is recorded per request, so repeated sweeps never notify twice. Returns { examined, notified, stages }.\n\n**Auth:** API key required — `Authorization: Bearer jc_live_...` or `X-Api-Key`. Machine callers only; a console session is not accepted.","tags":["Approvals"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/backtest":{"post":{"operationId":"postBacktest","summary":"Backtest a rule or typology","description":"Replays historical production screenings through a candidate rule/typology YAML and diffs the decision against the live config. Returns newly flagged, no-longer-flagged counts, label breakdowns, and example transactions.\n\n**Auth:** Console session — analyst role required.","tags":["Analytics"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BacktestRequest"},"example":{"yaml":"string","kind":"rule","window":"30d","limit":500}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/benchmark":{"get":{"operationId":"getBenchmark","summary":"Get latest benchmark","description":"Returns the most recent benchmark result (latency percentiles and ML model card) or null if none has been run.\n\n**Auth:** Console session (any role).","tags":["Analytics"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postBenchmark","summary":"Run a benchmark","description":"Runs the screening engine through N iterations to produce latency percentiles (p50, p75, p95, p99), a histogram, and the ML model card.\n\n**Auth:** Console session — analyst role required.","tags":["Analytics"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BenchmarkRequest"},"example":{"n":50}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/analytics/effectiveness":{"get":{"operationId":"getAnalyticsEffectiveness","summary":"Rule / typology effectiveness","description":"Per-rule or per-typology effectiveness over time: triggers, hit rate, and precision derived from feedback labels. Supports 7d, 30d, 90d, and all-time windows.\n\n**Auth:** Console session (any role).","tags":["Analytics"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/invitations/accept":{"post":{"operationId":"postInvitationAccept","summary":"Accept an invitation","description":"Accepts a team invitation using the token from the invite URL. Requires an authenticated session with a verified identity provider.\n\n**Auth:** Authenticated session.","tags":["Account"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationAccept"},"example":{"token":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"jc_live_... / jc_test_..."},"apiKeyHeader":{"type":"apiKey","in":"header","name":"X-Api-Key"}},"schemas":{"Party":{"type":"object","properties":{"id":{"type":"string","description":"Stable party identifier (account or wallet)."},"name":{"type":"string","description":"Full name (legal or registered)."},"account":{"type":"string","description":"Account number or wallet id."},"institution_id":{"type":"string","description":"Issuing financial institution."},"country":{"type":"string","description":"ISO 3166-1 alpha-2 country code."},"kyc_level":{"type":"string","enum":["none","basic","standard","enhanced"],"description":"Client due-diligence tier."},"risk_score":{"description":"Client-provided prior risk score (0..1).","type":"number","minimum":0,"maximum":1},"pep":{"description":"Politically exposed person flag.","type":"boolean"}},"required":["id","name","account","institution_id","country","kyc_level"],"additionalProperties":false},"Transaction":{"type":"object","properties":{"id":{"type":"string","description":"Instance-wide idempotency key."},"amount":{"type":"number","description":"Transaction amount in minor units."},"currency":{"type":"string","description":"ISO 4217 currency code."},"type":{"type":"string","enum":["transfer","card","cash_deposit","remittance","mobile_money"],"description":"Transaction type."},"channel":{"type":"string","enum":["api","branch","agent","mobile"],"description":"Originating channel."},"timestamp":{"type":"string","description":"ISO 8601 timestamp."},"reference":{"description":"External reference (e.g. source system tx id).","type":"string"},"country_from":{"type":"string","description":"Origin ISO 3166-1 alpha-2."},"country_to":{"type":"string","description":"Destination ISO 3166-1 alpha-2."}},"required":["id","amount","currency","type","channel","timestamp","country_from","country_to"],"additionalProperties":false},"ScreeningRequest":{"type":"object","properties":{"transaction":{"type":"object","properties":{"id":{"type":"string","description":"Instance-wide idempotency key."},"amount":{"type":"number","description":"Transaction amount in minor units."},"currency":{"type":"string","description":"ISO 4217 currency code."},"type":{"type":"string","enum":["transfer","card","cash_deposit","remittance","mobile_money"],"description":"Transaction type."},"channel":{"type":"string","enum":["api","branch","agent","mobile"],"description":"Originating channel."},"timestamp":{"type":"string","description":"ISO 8601 timestamp."},"reference":{"description":"External reference (e.g. source system tx id).","type":"string"},"country_from":{"type":"string","description":"Origin ISO 3166-1 alpha-2."},"country_to":{"type":"string","description":"Destination ISO 3166-1 alpha-2."}},"required":["id","amount","currency","type","channel","timestamp","country_from","country_to"],"additionalProperties":false},"sender":{"type":"object","properties":{"id":{"type":"string","description":"Stable party identifier (account or wallet)."},"name":{"type":"string","description":"Full name (legal or registered)."},"account":{"type":"string","description":"Account number or wallet id."},"institution_id":{"type":"string","description":"Issuing financial institution."},"country":{"type":"string","description":"ISO 3166-1 alpha-2 country code."},"kyc_level":{"type":"string","enum":["none","basic","standard","enhanced"],"description":"Client due-diligence tier."},"risk_score":{"description":"Client-provided prior risk score (0..1).","type":"number","minimum":0,"maximum":1},"pep":{"description":"Politically exposed person flag.","type":"boolean"}},"required":["id","name","account","institution_id","country","kyc_level"],"additionalProperties":false},"receiver":{"type":"object","properties":{"id":{"type":"string","description":"Stable party identifier (account or wallet)."},"name":{"type":"string","description":"Full name (legal or registered)."},"account":{"type":"string","description":"Account number or wallet id."},"institution_id":{"type":"string","description":"Issuing financial institution."},"country":{"type":"string","description":"ISO 3166-1 alpha-2 country code."},"kyc_level":{"type":"string","enum":["none","basic","standard","enhanced"],"description":"Client due-diligence tier."},"risk_score":{"description":"Client-provided prior risk score (0..1).","type":"number","minimum":0,"maximum":1},"pep":{"description":"Politically exposed person flag.","type":"boolean"}},"required":["id","name","account","institution_id","country","kyc_level"],"additionalProperties":false},"metadata":{"type":"object","properties":{"device_id":{"type":"string"},"ip":{"type":"string"},"geo":{"type":"string"},"narrative":{"type":"string"},"batch_id":{"type":"string"}},"additionalProperties":{}}},"required":["transaction","sender","receiver"],"additionalProperties":false},"ScreeningResponse":{"type":"object","properties":{"screening_id":{"type":"string"},"status":{"type":"string","enum":["cleared","flagged"]},"confidence":{"type":"number","minimum":0,"maximum":1},"risk_score":{"type":"number","minimum":0,"maximum":1,"description":"Capped sum of matched rule weights."},"risk_threshold":{"type":"number","minimum":0,"maximum":1,"description":"The institution’s configured flag threshold."},"rule_results":{"type":"array","items":{"type":"object","properties":{"rule_id":{"type":"string"},"name":{"type":"string"},"matched":{"type":"boolean"},"weight":{"type":"number","minimum":0,"maximum":1},"severity":{"type":"string","enum":["low","medium","high","critical"]},"detail":{"type":"string"}},"required":["rule_id","name","matched","weight","severity"],"additionalProperties":false}},"model_score":{"type":"number"},"blacklist_hits":{"type":"array","items":{"type":"object","properties":{"list":{"type":"string","enum":["accounts","institutions","corridors","devices","transaction_types"]},"entry_id":{"type":"string"},"value":{"type":"string"},"reason":{"type":"string"}},"required":["list","entry_id","value"],"additionalProperties":false}},"ml":{"description":"Advisory ML scores; absent when scoring fails (fail-open).","type":"object","properties":{"model_id":{"type":"string"},"model_version":{"type":"string"},"scores":{"type":"object","properties":{"anomaly_score":{"type":"number","minimum":0,"maximum":1},"fp_likelihood":{"type":"number","minimum":0,"maximum":1}},"required":["anomaly_score","fp_likelihood"],"additionalProperties":false},"explanations":{"type":"array","items":{"type":"object","properties":{"feature":{"type":"string"},"contribution":{"type":"number","minimum":0,"maximum":1},"detail":{"type":"string"}},"required":["feature","contribution","detail"],"additionalProperties":false}},"latency_ms":{"type":"number"}},"required":["model_id","model_version","scores","explanations","latency_ms"],"additionalProperties":false},"latency_ms":{"type":"number"},"timestamp":{"type":"string"}},"required":["screening_id","status","confidence","risk_score","risk_threshold","rule_results","model_score","blacklist_hits","latency_ms","timestamp"],"additionalProperties":false},"RuleResult":{"type":"object","properties":{"rule_id":{"type":"string"},"name":{"type":"string"},"matched":{"type":"boolean"},"weight":{"type":"number","minimum":0,"maximum":1},"severity":{"type":"string","enum":["low","medium","high","critical"]},"detail":{"type":"string"}},"required":["rule_id","name","matched","weight","severity"],"additionalProperties":false},"MlScoreBlock":{"type":"object","properties":{"model_id":{"type":"string"},"model_version":{"type":"string"},"scores":{"type":"object","properties":{"anomaly_score":{"type":"number","minimum":0,"maximum":1},"fp_likelihood":{"type":"number","minimum":0,"maximum":1}},"required":["anomaly_score","fp_likelihood"],"additionalProperties":false},"explanations":{"type":"array","items":{"type":"object","properties":{"feature":{"type":"string"},"contribution":{"type":"number","minimum":0,"maximum":1},"detail":{"type":"string"}},"required":["feature","contribution","detail"],"additionalProperties":false}},"latency_ms":{"type":"number"}},"required":["model_id","model_version","scores","explanations","latency_ms"],"additionalProperties":false},"MlExplanation":{"type":"object","properties":{"feature":{"type":"string"},"contribution":{"type":"number","minimum":0,"maximum":1},"detail":{"type":"string"}},"required":["feature","contribution","detail"],"additionalProperties":false},"BlacklistHit":{"type":"object","properties":{"list":{"type":"string","enum":["accounts","institutions","corridors","devices","transaction_types"]},"entry_id":{"type":"string"},"value":{"type":"string"},"reason":{"type":"string"}},"required":["list","entry_id","value"],"additionalProperties":false},"Rule":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"severity":{"type":"string","enum":["low","medium","high","critical"]},"weight":{"type":"number","minimum":0,"maximum":1},"status":{"type":"string","enum":["active","draft","disabled"]},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"yaml":{"type":"string","description":"Full YAML rule definition."},"trigger_count":{"default":0,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"hit_rate":{"default":0,"type":"number","minimum":0,"maximum":1},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","severity","weight","status","version","yaml","trigger_count","hit_rate","created_at","updated_at"],"additionalProperties":false},"Typology":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"rules":{"type":"array","items":{"type":"object","properties":{"rule_id":{"type":"string"},"weight":{"type":"number","minimum":0,"maximum":1}},"required":["rule_id","weight"],"additionalProperties":false}},"alert_threshold":{"type":"number","minimum":0,"maximum":1},"interdict_threshold":{"type":"number","minimum":0,"maximum":1},"status":{"type":"string","enum":["active","draft","disabled"]},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"yaml":{"type":"string","description":"Full YAML typology definition."},"trigger_count":{"default":0,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","category","rules","alert_threshold","status","version","yaml","trigger_count","created_at","updated_at"],"additionalProperties":false},"Case":{"type":"object","properties":{"id":{"type":"string"},"environment":{"type":"string","enum":["test","live"]},"subject":{"type":"object","properties":{"account":{"type":"string"},"name":{"type":"string"},"institution_id":{"type":"string"},"country":{"type":"string"},"role":{"type":"string","enum":["sender","receiver"]}},"required":["account","name","institution_id","country","role"],"additionalProperties":false},"title":{"type":"string"},"status":{"type":"string","enum":["open","investigating","escalated","closed"]},"priority":{"type":"string","enum":["low","medium","high","critical"]},"source":{"type":"string","enum":["rule","typology","blacklist","sanctions","manual"]},"assignee":{"type":"string"},"alerts":{"type":"array","items":{"type":"object","properties":{"screening_id":{"type":"string"},"transaction_id":{"type":"string"},"timestamp":{"type":"string"},"status":{"type":"string","enum":["cleared","flagged"]},"amount":{"type":"number"},"currency":{"type":"string"},"matched_rule_ids":{"type":"array","items":{"type":"string"}},"breached_typology_ids":{"type":"array","items":{"type":"string"}},"sanctions_entity_ids":{"type":"array","items":{"type":"string"}},"max_severity":{"type":"string","enum":["low","medium","high","critical"]}},"required":["screening_id","transaction_id","timestamp","status","amount","currency","matched_rule_ids","breached_typology_ids","sanctions_entity_ids","max_severity"],"additionalProperties":false}},"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"at":{"type":"string"},"actor":{"type":"string"},"type":{"type":"string","enum":["created","alert_attached","status_changed","priority_changed","assigned","note_added","resolved","reopened"]},"detail":{"type":"string"}},"required":["id","at","actor","type","detail"],"additionalProperties":false}},"resolution":{"type":"string","enum":["confirmed_suspicious","false_positive","reported","no_action"]},"resolution_note":{"type":"string"},"sla_due_at":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"closed_at":{"type":"string"}},"required":["id","subject","title","status","priority","source","alerts","events","sla_due_at","created_at","updated_at"],"additionalProperties":false},"BlacklistEntry":{"type":"object","properties":{"id":{"type":"string"},"list":{"type":"string","enum":["accounts","institutions","corridors","devices","transaction_types"]},"value":{"type":"string"},"reason":{"type":"string"},"source":{"type":"string","enum":["manual","api","rule_escalated"]},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"min_amount":{"type":"number"},"corridor":{"type":"string"}},"required":["id","list","value","source","created_at"],"additionalProperties":false},"Webhook":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}},"transport":{"default":"https","type":"string","enum":["https","simulate"]},"description":{"type":"string"},"secret":{"type":"string"},"active":{"default":true,"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","url","events","transport","active","created_at","updated_at"],"additionalProperties":false},"ApiKey":{"type":"object","properties":{"id":{"type":"string"},"masked_key":{"type":"string","description":"Masked display value (e.g. jct_test_a1b2****d4)."},"label":{"type":"string"},"environment":{"type":"string","enum":["test","live"]},"created_at":{"type":"string"},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"revoked":{"default":false,"type":"boolean"},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"replaced_by":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","masked_key","label","environment","created_at","revoked"],"additionalProperties":false},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":{}}},"required":["error"],"additionalProperties":false},"DemoRequest":{"type":"object","properties":{"contactName":{"type":"string","minLength":2,"maxLength":120,"description":"Full name of the person requesting the demo.","examples":["Jane Muthoni"]},"workEmail":{"type":"string","maxLength":254,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","description":"Work email address. Personal inboxes are accepted but slow the follow-up.","examples":["jane.muthoni@yourbank.example"]},"institution":{"type":"string","minLength":2,"maxLength":160,"description":"Institution or company name.","examples":["YourBank PLC"]},"country":{"default":"","description":"Country of operation.","examples":["KE"],"type":"string","maxLength":80},"role":{"default":"","description":"Job title of the contact.","examples":["Head of Compliance"],"type":"string","maxLength":120},"deploymentInterest":{"type":"string","enum":["managed","on-premise","undecided"],"description":"Managed service, on-premise deployment, or undecided.","examples":["managed"]},"volumeBand":{"default":"not-sure","description":"Estimated monthly screening volume.","examples":["100k-2m"],"type":"string","enum":["under-100k","100k-2m","2m-50m","50m-500m","over-500m","not-sure"]},"message":{"default":"","description":"Anything specific the prospect wants covered in the demo.","type":"string","maxLength":2000}},"required":["contactName","workEmail","institution","country","role","deploymentInterest","volumeBand","message"],"additionalProperties":false},"DemoRequestResponse":{"type":"object","properties":{"reference":{"type":"string","description":"Demo request reference code (e.g. DEMO-...)."},"status":{"type":"string","const":"received","description":"Submission status."},"deployment_interest":{"type":"string","enum":["managed","on-premise","undecided"],"description":"Echoed deployment interest."},"nextSteps":{"type":"array","items":{"type":"string"},"description":"What happens next."}},"required":["reference","status","deployment_interest","nextSteps"],"additionalProperties":false},"CaseList":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"environment":{"type":"string","enum":["test","live"]},"subject":{"type":"object","properties":{"account":{"type":"string"},"name":{"type":"string"},"institution_id":{"type":"string"},"country":{"type":"string"},"role":{"type":"string","enum":["sender","receiver"]}},"required":["account","name","institution_id","country","role"],"additionalProperties":false},"title":{"type":"string"},"status":{"type":"string","enum":["open","investigating","escalated","closed"]},"priority":{"type":"string","enum":["low","medium","high","critical"]},"source":{"type":"string","enum":["rule","typology","blacklist","sanctions","manual"]},"assignee":{"type":"string"},"alerts":{"type":"array","items":{"type":"object","properties":{"screening_id":{"type":"string"},"transaction_id":{"type":"string"},"timestamp":{"type":"string"},"status":{"type":"string","enum":["cleared","flagged"]},"amount":{"type":"number"},"currency":{"type":"string"},"matched_rule_ids":{"type":"array","items":{"type":"string"}},"breached_typology_ids":{"type":"array","items":{"type":"string"}},"sanctions_entity_ids":{"type":"array","items":{"type":"string"}},"max_severity":{"type":"string","enum":["low","medium","high","critical"]}},"required":["screening_id","transaction_id","timestamp","status","amount","currency","matched_rule_ids","breached_typology_ids","sanctions_entity_ids","max_severity"],"additionalProperties":false}},"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"at":{"type":"string"},"actor":{"type":"string"},"type":{"type":"string","enum":["created","alert_attached","status_changed","priority_changed","assigned","note_added","resolved","reopened"]},"detail":{"type":"string"}},"required":["id","at","actor","type","detail"],"additionalProperties":false}},"resolution":{"type":"string","enum":["confirmed_suspicious","false_positive","reported","no_action"]},"resolution_note":{"type":"string"},"sla_due_at":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"closed_at":{"type":"string"}},"required":["id","subject","title","status","priority","source","alerts","events","sla_due_at","created_at","updated_at"],"additionalProperties":false}},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"stats":{"type":"object","properties":{"open":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"investigating":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"escalated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"closed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["open","investigating","escalated","closed"],"additionalProperties":false},"institutions":{"type":"array","items":{"type":"string"}},"assignees":{"type":"array","items":{"type":"string"}}},"required":["items","total","stats","institutions","assignees"],"additionalProperties":false},"RuleList":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"severity":{"type":"string","enum":["low","medium","high","critical"]},"weight":{"type":"number","minimum":0,"maximum":1},"status":{"type":"string","enum":["active","draft","disabled"]},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"yaml":{"type":"string","description":"Full YAML rule definition."},"trigger_count":{"default":0,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"hit_rate":{"default":0,"type":"number","minimum":0,"maximum":1},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","severity","weight","status","version","yaml","trigger_count","hit_rate","created_at","updated_at"],"additionalProperties":false}}},"required":["items"],"additionalProperties":false},"TypologyList":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"rules":{"type":"array","items":{"type":"object","properties":{"rule_id":{"type":"string"},"weight":{"type":"number","minimum":0,"maximum":1}},"required":["rule_id","weight"],"additionalProperties":false}},"alert_threshold":{"type":"number","minimum":0,"maximum":1},"interdict_threshold":{"type":"number","minimum":0,"maximum":1},"status":{"type":"string","enum":["active","draft","disabled"]},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"yaml":{"type":"string","description":"Full YAML typology definition."},"trigger_count":{"default":0,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","category","rules","alert_threshold","status","version","yaml","trigger_count","created_at","updated_at"],"additionalProperties":false}}},"required":["items"],"additionalProperties":false},"BlacklistList":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"list":{"type":"string","enum":["accounts","institutions","corridors","devices","transaction_types"]},"value":{"type":"string"},"reason":{"type":"string"},"source":{"type":"string","enum":["manual","api","rule_escalated"]},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"min_amount":{"type":"number"},"corridor":{"type":"string"}},"required":["id","list","value","source","created_at"],"additionalProperties":false}}},"required":["items"],"additionalProperties":false},"WebhookList":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}},"transport":{"default":"https","type":"string","enum":["https","simulate"]},"description":{"type":"string"},"secret":{"type":"string"},"active":{"default":true,"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","url","events","transport","active","created_at","updated_at"],"additionalProperties":false}}},"required":["items"],"additionalProperties":false},"OrganizationSettings":{"type":"object","properties":{"organization":{"type":"object","properties":{"name":{"type":"string","description":"Institution name."},"country":{"type":"string","description":"ISO 3166-1 alpha-2 country code."},"institution_type":{"type":"string","description":"Institution type."},"risk_threshold":{"type":"number","minimum":0,"maximum":1,"description":"The institution’s configured flag threshold (0..1)."},"created_at":{"type":"string","description":"Institution record creation timestamp."},"api_key_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Count of non-revoked API keys."},"pinned_fields":{"type":"array","items":{"type":"string","enum":["name","country","institution_type","risk_threshold"]},"description":"Fields set by this deployment’s configuration. Read-only: a PATCH touching one returns 409."}},"required":["name","country","institution_type","risk_threshold","created_at","api_key_count","pinned_fields"],"additionalProperties":false,"description":"Organization settings."}},"required":["organization"],"additionalProperties":false},"OrganizationUpdate":{"type":"object","properties":{"name":{"description":"Institution name.","type":"string","minLength":2,"maxLength":80},"country":{"description":"ISO 3166-1 alpha-2 country code.","type":"string","pattern":"^[A-Z]{2}$"},"institution_type":{"description":"Institution type.","type":"string","maxLength":32},"risk_threshold":{"description":"The institution’s configured flag threshold (0..1). Changes go through maker-checker approval.","type":"number","minimum":0,"maximum":1},"webhook_alert_url":{"description":"HTTPS destination for webhook delivery-failure notifications (e.g. a Slack incoming webhook). Send an empty string to clear it. Never returned in full — reads give a masked hint.","type":"string","maxLength":2048}},"additionalProperties":false},"ApiKeyList":{"type":"object","properties":{"keys":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"masked_key":{"type":"string"},"label":{"type":"string"},"environment":{"type":"string","enum":["test","live"]},"created_at":{"type":"string"},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"revoked":{"default":false,"type":"boolean"},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"replaced_by":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","masked_key","label","environment","created_at","revoked"],"additionalProperties":false}}},"required":["keys"],"additionalProperties":false},"ApiKeyCreate":{"type":"object","properties":{"label":{"description":"Human-readable label.","type":"string","maxLength":48},"environment":{"default":"test","description":"API key environment.","type":"string","enum":["test","live"]}},"required":["environment"],"additionalProperties":false},"ApiKeyRotate":{"type":"object","properties":{"action":{"type":"string","const":"rotate"},"id":{"type":"string","description":"Key id to rotate."},"grace_minutes":{"description":"Old key grace period in minutes.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"label":{"description":"New key label.","type":"string","maxLength":48}},"required":["action","id"],"additionalProperties":false},"InvitationCreate":{"type":"object","properties":{"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","description":"Invitee email address."},"name":{"type":"string","minLength":1,"maxLength":120,"description":"Invitee full name."},"role":{"default":"analyst","description":"Assigned role.","type":"string","enum":["admin","compliance_officer","analyst","viewer"]}},"required":["email","name","role"],"additionalProperties":false},"ModelGovernance":{"type":"object","properties":{"governance":{"type":"object","properties":{"shadow_mode":{"type":"boolean"},"drift_threshold":{"type":"number","minimum":0,"maximum":1},"drift_window_days":{"type":"integer","minimum":1,"maximum":90},"alert_on_drift":{"type":"boolean"},"challenger_enabled":{"type":"boolean"}},"additionalProperties":false}},"required":["governance"],"additionalProperties":false},"ProfileList":{"type":"object","properties":{"profiles":{"type":"array","items":{"type":"object","properties":{"subject_id":{"type":"string"},"risk_band":{"type":"string","enum":["low","medium","high"]},"anomaly_score":{"type":"number","minimum":0,"maximum":1},"maturity":{"type":"string"},"confidence":{"type":"number","minimum":0,"maximum":1},"txn_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"features":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["subject_id","risk_band","anomaly_score","maturity","confidence","txn_count","features","created_at","updated_at"],"additionalProperties":false}},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]},"has_more":{"type":"boolean"},"built_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"embedding_model":{"type":"string"}},"required":["profiles","total","next_cursor","has_more","built_at","embedding_model"],"additionalProperties":false},"ProfileDetail":{"type":"object","properties":{"profile":{"type":"object","properties":{"subject_id":{"type":"string"},"risk_band":{"type":"string","enum":["low","medium","high"]},"anomaly_score":{"type":"number","minimum":0,"maximum":1},"maturity":{"type":"string"},"confidence":{"type":"number","minimum":0,"maximum":1},"txn_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"features":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["subject_id","risk_band","anomaly_score","maturity","confidence","txn_count","features","created_at","updated_at"],"additionalProperties":false},"recent_transactions":{"type":"array","items":{"type":"object","properties":{"screening_id":{"type":"string"},"transaction_id":{"type":"string"},"amount":{"type":"number"},"currency":{"type":"string"},"status":{"type":"string"},"timestamp":{"type":"string"}},"required":["screening_id","amount","currency","status","timestamp"],"additionalProperties":false}}},"required":["profile","recent_transactions"],"additionalProperties":false},"ProfileScoreRequest":{"type":"object","properties":{"transaction":{"type":"object","properties":{"amount":{"type":"number","exclusiveMinimum":0},"type":{"type":"string"},"channel":{"type":"string"},"country_to":{"type":"string"},"country_from":{"type":"string"},"timestamp":{"type":"string"}},"required":["amount"],"additionalProperties":false},"receiver_account":{"type":"string"}},"required":["transaction"],"additionalProperties":false},"ProfileNeighbors":{"type":"object","properties":{"neighbors":{"type":"array","items":{"type":"object","properties":{"subject_id":{"type":"string"},"similarity":{"type":"number","minimum":0,"maximum":1},"risk_band":{"type":"string","enum":["low","medium","high"]},"txn_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["subject_id","similarity","risk_band","txn_count"],"additionalProperties":false}}},"required":["neighbors"],"additionalProperties":false},"ProfileNetwork":{"type":"object","properties":{"network":{"type":"object","properties":{"root":{"type":"string"},"nodes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"depth":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"risk_band":{"type":"string"},"blacklisted":{"type":"boolean"},"txn_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","depth","risk_band","blacklisted","txn_count"],"additionalProperties":false}},"edges":{"type":"array","items":{"type":"object","properties":{"source":{"type":"string"},"target":{"type":"string"},"txn_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total_amount":{"type":"number"},"flagged_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"corridors":{"type":"array","items":{"type":"string"}}},"required":["source","target","txn_count","total_amount","flagged_count","corridors"],"additionalProperties":false}},"truncated":{"type":"boolean"}},"required":["root","nodes","edges","truncated"],"additionalProperties":false}},"required":["network"],"additionalProperties":false},"ProfileTrace":{"type":"object","properties":{"trace":{"type":"object","properties":{"root":{"type":"string"},"direction":{"type":"string","enum":["outbound","inbound"]},"paths":{"type":"array","items":{"type":"object","properties":{"hops":{"type":"array","items":{"type":"object","properties":{"account":{"type":"string"},"amount":{"type":"number"},"currency":{"type":"string"},"timestamp":{"type":"string"}},"required":["account","amount","currency","timestamp"],"additionalProperties":false}},"bottleneck_volume":{"type":"number"},"suspicious":{"type":"boolean"},"length":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["hops","bottleneck_volume","suspicious","length"],"additionalProperties":false}},"truncated":{"type":"boolean"}},"required":["root","direction","paths","truncated"],"additionalProperties":false}},"required":["trace"],"additionalProperties":false},"ProfileBuildJob":{"type":"object","properties":{"job":{"type":"object","properties":{"job_id":{"type":"string"},"status":{"type":"string"},"started_at":{"type":"string"},"completed_at":{"type":"string"},"subjects_processed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"subjects_total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["job_id","status"],"additionalProperties":false}},"required":["job"],"additionalProperties":false},"SandboxRunRequest":{"type":"object","properties":{"transactions":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}},"run_scenarios":{"type":"boolean"},"scenario_ids":{"type":"array","items":{"type":"string"}},"rule_ids":{"type":"array","items":{"type":"string"}},"include_drafts":{"type":"boolean"},"yaml":{"type":"string"},"yaml_only":{"type":"boolean"},"typology_yaml":{"type":"string"},"typology_only":{"type":"boolean"}},"additionalProperties":false},"SandboxRunResponse":{"type":"object","properties":{"run_id":{"type":"string"},"started_at":{"type":"string"},"duration_ms":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"summary":{"type":"object","properties":{"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"cleared":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"flagged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"avg_confidence":{"type":"number","minimum":0,"maximum":1}},"required":["total","cleared","flagged","avg_confidence"],"additionalProperties":false},"results":{"type":"array","items":{"type":"object","properties":{"request":{"type":"object","properties":{},"additionalProperties":{}},"response":{"type":"object","properties":{},"additionalProperties":{}}},"required":["request","response"],"additionalProperties":false}}},"required":["run_id","started_at","duration_ms","summary","results"],"additionalProperties":false},"SandboxSample":{"type":"object","properties":{"transactions":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}}},"required":["transactions"],"additionalProperties":false},"TransactionList":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]},"has_more":{"type":"boolean"},"counts":{"type":"object","properties":{"all":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"cleared":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"flagged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["all","cleared","flagged"],"additionalProperties":false}},"required":["items","total","limit","offset","next_cursor","has_more","counts"],"additionalProperties":false},"TransactionPatch":{"type":"object","properties":{"screening_id":{"type":"string"},"reviewed":{"type":"boolean"},"disposition":{"type":"string","enum":["true_positive","false_positive","escalated"]},"note":{"type":"string"}},"required":["screening_id"],"additionalProperties":false},"TransactionImport":{"type":"object","properties":{"raw":{"type":"string","minLength":1},"filename":{"type":"string"},"dry_run":{"type":"boolean"}},"required":["raw"],"additionalProperties":false},"NetworkOverview":{"type":"object","properties":{"overview":{"type":"object","properties":{"generated_at":{"type":"string"},"node_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"edge_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"networks":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}},"patterns":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}},"links":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}}},"required":["generated_at","node_count","edge_count","networks","patterns","links"],"additionalProperties":false}},"required":["overview"],"additionalProperties":false},"NetworkDetail":{"type":"object","properties":{"network":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"node_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"edge_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"txn_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total_amount":{"type":"number"},"flag_rate":{"type":"number","minimum":0,"maximum":1},"risk_score":{"type":"number","minimum":0,"maximum":1},"pattern_types":{"type":"array","items":{"type":"string"}},"top_accounts":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}},"nodes":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}},"edges":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}}},"required":["id","node_count","edge_count","txn_count","total_amount","flag_rate","risk_score","pattern_types","top_accounts","nodes","edges"],"additionalProperties":false}},"required":["network"],"additionalProperties":false},"ActivityList":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"timestamp":{"type":"string"},"category":{"type":"string"},"action":{"type":"string"},"actor":{"type":"object","properties":{"kind":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"required":["kind","id"],"additionalProperties":false},"resource":{"type":"object","properties":{"type":{"type":"string"},"id":{"type":"string"}},"required":["type","id"],"additionalProperties":false},"summary":{"type":"string"},"status":{"type":"string"},"method":{"type":"string"},"path":{"type":"string"},"status_code":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"latency_ms":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","timestamp","category","action","actor","summary","status"],"additionalProperties":false}},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["items","total"],"additionalProperties":false},"DashboardMetrics":{"type":"object","properties":{"total_transactions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"flagged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"cleared":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"flagged_rate":{"type":"number","minimum":0,"maximum":1},"by_type":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"by_channel":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"by_currency":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"rule_effectiveness":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{},"additionalProperties":{}}},"risk_distribution":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"environment":{"type":"string"}},"required":["total_transactions","flagged","cleared","flagged_rate","by_type","by_channel","by_currency","rule_effectiveness","risk_distribution","environment"],"additionalProperties":false},"SarList":{"type":"object","properties":{"sars":{"type":"array","items":{"type":"object","properties":{"sar_id":{"type":"string"},"screening_id":{"type":"string"},"status":{"type":"string"},"created_at":{"type":"string"},"escalated_by":{"type":"string"},"subject":{"type":"object","properties":{"name":{"type":"string"},"account":{"type":"string"},"institution_id":{"type":"string"},"country":{"type":"string"}},"required":["name","account","institution_id","country"],"additionalProperties":false},"counterparty":{"type":"object","properties":{"name":{"type":"string"},"account":{"type":"string"},"institution_id":{"type":"string"},"country":{"type":"string"}},"required":["name","account","institution_id","country"],"additionalProperties":false},"transaction":{"type":"object","properties":{"id":{"type":"string"},"amount":{"type":"number"},"currency":{"type":"string"},"type":{"type":"string"},"corridor":{"type":"string"},"timestamp":{"type":"string"}},"required":["id","amount","currency","type","corridor","timestamp"],"additionalProperties":false},"matched_rules":{"type":"array","items":{"type":"object","properties":{"rule_id":{"type":"string"},"name":{"type":"string"},"severity":{"type":"string"}},"required":["rule_id","name","severity"],"additionalProperties":false}},"narrative":{"type":"string"}},"required":["sar_id","screening_id","status","created_at","subject","counterparty","transaction","matched_rules","narrative"],"additionalProperties":false}},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["sars","total"],"additionalProperties":false},"WebhookCreate":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"minItems":1,"type":"array","items":{"type":"string"}},"transport":{"default":"https","type":"string","enum":["https","simulate"]},"description":{"type":"string","maxLength":120}},"required":["url","events","transport"],"additionalProperties":false},"WebhookUpdate":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"events":{"minItems":1,"type":"array","items":{"type":"string"}},"transport":{"type":"string","enum":["https","simulate"]},"active":{"type":"boolean"},"description":{"type":"string","maxLength":120}},"required":["id"],"additionalProperties":false},"BacktestRequest":{"type":"object","properties":{"yaml":{"type":"string","minLength":1},"kind":{"default":"rule","type":"string","enum":["rule","typology"]},"window":{"default":"30d","type":"string","enum":["7d","30d","90d","all"]},"limit":{"default":500,"type":"integer","minimum":-9007199254740991,"maximum":2000}},"required":["yaml","kind","window","limit"],"additionalProperties":false},"Health":{"type":"object","properties":{"status":{"type":"string","enum":["ok","degraded"]},"storage":{"type":"string","enum":["mock","database"]},"db":{"type":"string","enum":["not-configured","ok","error"]},"rules":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["status","storage","db"],"additionalProperties":false},"Environment":{"type":"object","properties":{"environment":{"type":"string","enum":["test","live"]}},"required":["environment"],"additionalProperties":false},"EnvironmentUpdate":{"type":"object","properties":{"environment":{"type":"string","enum":["test","live"]}},"required":["environment"],"additionalProperties":false},"ScreeningIso20022Request":{"type":"object","properties":{"Document":{"type":"object","properties":{"FIToFICstmrCdtTrf":{"type":"object","properties":{"GrpHdr":{"type":"object","properties":{"MsgId":{"type":"string","description":"Unique message identifier"},"CreDtTm":{"type":"string","description":"Creation date and time"},"NbOfTxs":{"type":"string","description":"Number of transactions"}},"required":["MsgId","CreDtTm","NbOfTxs"],"additionalProperties":false,"description":"Group header"},"CdtTrfTxInf":{"type":"object","properties":{"PmtId":{"type":"object","properties":{"EndToEndId":{"description":"End-to-end identifier","type":"string"},"TxId":{"description":"Transaction identifier","type":"string"},"UETR":{"description":"Universal end-to-end transaction reference","type":"string"}},"additionalProperties":false,"description":"Payment identification"},"IntrBkSttlmAmt":{"type":"object","properties":{"Ccy":{"type":"string","description":"Currency code"},"value":{"type":"string","description":"Settlement amount"}},"required":["Ccy","value"],"additionalProperties":false,"description":"Interbank settlement amount"},"IntrBkSttlmDt":{"description":"Interbank settlement date","type":"string"},"Dbtr":{"type":"object","properties":{"Nm":{"type":"string","description":"Debtor name"}},"required":["Nm"],"additionalProperties":false,"description":"Debtor"},"DbtrAcct":{"type":"object","properties":{"Id":{"type":"object","properties":{"Othr":{"type":"object","properties":{"Id":{"type":"string","description":"Debtor account identifier"}},"required":["Id"],"additionalProperties":false}},"required":["Othr"],"additionalProperties":false}},"required":["Id"],"additionalProperties":false,"description":"Debtor account"},"DbtrAgt":{"type":"object","properties":{"FinInstnId":{"type":"object","properties":{"BICFI":{"type":"string","description":"Debtor agent BIC"}},"required":["BICFI"],"additionalProperties":false}},"required":["FinInstnId"],"additionalProperties":false,"description":"Debtor agent"},"Cdtr":{"type":"object","properties":{"Nm":{"type":"string","description":"Creditor name"}},"required":["Nm"],"additionalProperties":false,"description":"Creditor"},"CdtrAcct":{"type":"object","properties":{"Id":{"type":"object","properties":{"Othr":{"type":"object","properties":{"Id":{"type":"string","description":"Creditor account identifier"}},"required":["Id"],"additionalProperties":false}},"required":["Othr"],"additionalProperties":false}},"required":["Id"],"additionalProperties":false,"description":"Creditor account"},"CdtrAgt":{"type":"object","properties":{"FinInstnId":{"type":"object","properties":{"BICFI":{"type":"string","description":"Creditor agent BIC"}},"required":["BICFI"],"additionalProperties":false}},"required":["FinInstnId"],"additionalProperties":false,"description":"Creditor agent"},"RmtInf":{"description":"Remittance information","type":"object","properties":{"Ustrd":{"description":"Unstructured remittance information","type":"array","items":{"type":"string"}}},"additionalProperties":false}},"required":["PmtId","IntrBkSttlmAmt","Dbtr","DbtrAcct","DbtrAgt","Cdtr","CdtrAcct","CdtrAgt"],"additionalProperties":false,"description":"Credit transfer transaction information"}},"required":["GrpHdr","CdtTrfTxInf"],"additionalProperties":false}},"required":["FIToFICstmrCdtTrf"],"additionalProperties":false,"description":"ISO 20022 FIToFICstmrCdtTrf document"}},"required":["Document"],"additionalProperties":false,"description":"ISO 20022 pacs.008 screening request"},"ScreeningMojaloopRequest":{"type":"object","properties":{"transactionId":{"type":"string","description":"Mojaloop transaction identifier"},"quoteId":{"description":"Quote request identifier","type":"string"},"amount":{"type":"object","properties":{"amount":{"type":"string","description":"Transfer amount"},"currency":{"type":"string","description":"Currency code"}},"required":["amount","currency"],"additionalProperties":false,"description":"Transfer amount"},"transactionType":{"description":"Transaction type details","type":"object","properties":{"scenario":{"type":"string","description":"Transaction scenario (e.g. TRANSFER)"},"initiator":{"type":"string","description":"Transaction initiator (e.g. PAYER)"},"initiatorType":{"type":"string","description":"Initiator type (e.g. CONSUMER)"}},"required":["scenario","initiator","initiatorType"],"additionalProperties":false},"payer":{"type":"object","properties":{"partyIdInfo":{"type":"object","properties":{"partyIdType":{"type":"string","description":"Party identifier type (e.g. MSISDN)"},"partyIdentifier":{"type":"string","description":"Party identifier value"},"fspId":{"type":"string","description":"Financial service provider ID"}},"required":["partyIdType","partyIdentifier","fspId"],"additionalProperties":false,"description":"Payer party identifier info"},"name":{"description":"Payer display name","type":"string"},"personalInfo":{"description":"Payer personal information","type":"object","properties":{"givenName":{"type":"string"},"familyName":{"type":"string"},"dateOfBirth":{"type":"string"},"placeOfBirth":{"type":"string"},"nationality":{"type":"string"}},"additionalProperties":false}},"required":["partyIdInfo"],"additionalProperties":false,"description":"Payer party"},"payee":{"type":"object","properties":{"partyIdInfo":{"type":"object","properties":{"partyIdType":{"type":"string","description":"Party identifier type (e.g. MSISDN)"},"partyIdentifier":{"type":"string","description":"Party identifier value"},"fspId":{"type":"string","description":"Financial service provider ID"}},"required":["partyIdType","partyIdentifier","fspId"],"additionalProperties":false,"description":"Payee party identifier info"},"name":{"description":"Payee display name","type":"string"},"personalInfo":{"description":"Payee personal information","type":"object","properties":{"givenName":{"type":"string"},"familyName":{"type":"string"},"dateOfBirth":{"type":"string"},"placeOfBirth":{"type":"string"},"nationality":{"type":"string"}},"additionalProperties":false}},"required":["partyIdInfo"],"additionalProperties":false,"description":"Payee party"},"note":{"description":"Free-text note mapped to metadata.narrative","type":"string"}},"required":["transactionId","amount","payer","payee"],"additionalProperties":false,"description":"Mojaloop transaction screening request"},"OnboardingStatusDismiss":{"type":"object","properties":{"dismissed":{"type":"boolean","description":"True to dismiss the checklist, false to restore it"}},"required":["dismissed"],"additionalProperties":false,"description":"Onboarding checklist dismiss/restore request"},"FeedbackCreate":{"type":"object","properties":{"screening_id":{"type":"string","description":"Screening record to label"},"label":{"type":"string","enum":["true_positive","false_positive","suspicious"],"description":"Analyst feedback label"},"note":{"description":"Optional analyst note","type":"string","maxLength":500}},"required":["screening_id","label"],"additionalProperties":false,"description":"Feedback label creation request"},"ApprovalDecision":{"type":"object","properties":{"decision":{"type":"string","enum":["approve","reject","cancel"],"description":"Approval decision"},"reason":{"description":"Rationale for the decision","type":"string","maxLength":500}},"required":["decision"],"additionalProperties":false,"description":"Approval decision request"},"SarStatusUpdate":{"type":"object","properties":{"status":{"type":"string","enum":["under_review","approved","submitted"],"description":"Target SAR workflow status"},"by":{"description":"Reviewer/approver name","type":"string"},"note":{"description":"Optional note for the status transition","type":"string"}},"required":["status"],"additionalProperties":false,"description":"SAR workflow status update request"},"SanctionsScreenRequest":{"type":"object","properties":{"name":{"description":"Single name to screen","type":"string"},"names":{"description":"Multiple names to screen (alternative to name)","type":"array","items":{"type":"string"}},"min_score":{"description":"Minimum score threshold to surface candidates","type":"number","minimum":0,"maximum":1}},"additionalProperties":false,"description":"Sanctions name screening request"},"SanctionsListToggle":{"type":"object","properties":{"source":{"type":"string","enum":["OFAC_SDN","UN_CONSOLIDATED","EU_FSF","UK_HMT","OPENSANCTIONS_PEP","ADVERSE_MEDIA","CUSTOM_CLIENT"],"description":"Sanctions source identifier"},"enabled":{"type":"boolean","description":"Enable or disable the watchlist"}},"required":["source","enabled"],"additionalProperties":false,"description":"Sanctions list enable/disable request"},"SanctionsMatchClear":{"type":"object","properties":{"entity_id":{"type":"string","description":"Sanctions entity identifier"},"account":{"type":"string","description":"Account number to clear"},"query_name":{"description":"Name used in the original query","type":"string"},"reason":{"description":"Reason for clearing the match","type":"string"},"by":{"description":"Analyst who cleared the match","type":"string"}},"required":["entity_id","account"],"additionalProperties":false,"description":"Sanctions false-positive clearance request"},"EntityAliasReview":{"type":"object","properties":{"id":{"type":"string","description":"Entity alias identifier to review"},"status":{"type":"string","enum":["approved","rejected"],"description":"Review decision"},"by":{"description":"Reviewer name","type":"string"},"note":{"description":"Optional review note","type":"string"}},"required":["id","status"],"additionalProperties":false,"description":"Entity alias review request"},"InvitationAccept":{"type":"object","properties":{"token":{"type":"string","description":"Invitation token from the invite URL"}},"required":["token"],"additionalProperties":false,"description":"Invitation acceptance request"},"RetentionUpdate":{"type":"object","properties":{"jurisdiction_preset":{"type":"string","description":"Jurisdiction preset identifier"},"categories":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"retention_days":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"expiry_action":{"type":"string","enum":["purge","anonymise"]}},"required":["retention_days","expiry_action"],"additionalProperties":false}},"note":{"description":"Change rationale","type":"string","maxLength":500}},"required":["jurisdiction_preset","categories"],"additionalProperties":false,"description":"Data retention policy update request"},"BenchmarkRequest":{"type":"object","properties":{"n":{"default":50,"description":"Number of benchmark iterations (capped at 200)","type":"integer","minimum":1,"maximum":200}},"required":["n"],"additionalProperties":false,"description":"Benchmark run request"}}}}