Real-time decisioning.
One HTTP call.
Three endpoints cover the whole integration surface a bank actually needs: transaction-level decisioning, sanctions / PEP / adverse-media screening, and KYC onboarding. JSON request, JSON response, JWT auth, sub-500ms p99 on the scoring path.
- Base URL
- api.kestrelfin.com
- Auth
- JWT · Bearer
- Latency p99
- < 500 ms
- OpenAPI
- GET /docs
Bearer token from your tenant.
Every request carries a Supabase JWT signed for your bank's tenant. The engine validates HS256 against the shared secret in production and falls back to JWKS for rotated keys. Tokens carry the caller's org_id and persona; row-level security enforces the rest.
curl https://api.kestrelfin.com/ready \
-H "Authorization: Bearer $KESTREL_TOKEN"POST /transactions/score
Per-transaction decisioning. Returns a score (0–100), a decision band (approve / review / hold / reject), and a reason array your operations team can show on a hold screen. Inline sanctions screening fires automatically on either side of the transaction when the payload carries a name.
curl https://api.kestrelfin.com/transactions/score \
-X POST \
-H "Authorization: Bearer $KESTREL_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"transaction_external_id": "TXN-2026-04-29-00001",
"amount": 5500000,
"currency": "BDT",
"channel": "BEFTN",
"from_account_id": "acct_1029",
"to_account_id": "acct_5814",
"from_account_metadata": { "name": "Mohammad Karim", "account_open_days": 12 },
"to_account_metadata": { "name": "Padma Trading Ltd" }
}'{
"log_id": "9f2b…",
"score": 78,
"decision": "hold",
"confidence": 0.91,
"reasons": [
{ "code": "amount_very_large", "weight": 25, "evidence": { "amount_bdt": 5500000 } },
{ "code": "new_account_high_value","weight": 18, "evidence": { "open_days": 12 } },
{ "code": "from_sanctions_hit", "weight": 35, "evidence": { "list": "OFAC", "match": 0.91 } }
],
"cross_bank_flag": false,
"latency_ms": 142,
"request_id": "c0807049-80e3-41d0-a78b-eb7ede8096d2"
}Decision bands
| Score | Decision | Bank action |
|---|---|---|
| 0–29 | approve | release immediately |
| 30–59 | review | queue for analyst review post-clearing |
| 60–79 | hold | hold pending CAMLCO sign-off |
| 80–100 | reject | do not clear; raise STR |
POST /screening/entity
Fuzzy match a candidate against a 27,000+ record watchlist pool aggregating OFAC, UN, UK FCDO, and BB Domestic, with a ComplyAdvantage adapter for paid PEP and adverse-media feeds. Used inline by the scoring endpoint and by the KYC onboarding endpoint; available standalone for ad-hoc checks.
curl https://api.kestrelfin.com/screening/entity \
-X POST \
-H "Authorization: Bearer $KESTREL_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Mohammad Karim",
"date_of_birth": "1978-04-22",
"nationality": "BD",
"national_id": "1234567890123",
"min_score": 0.7,
"list_sources": ["OFAC", "UN", "UK_OFSI", "BB_DOMESTIC", "PEP"]
}'POST /customers
Onboard a customer with inline screening on the primary candidate and every beneficial owner. Returns a composed risk score, a decision (low / medium / high / declined), and per-party screening hits. A direct primary hit at score ≥ 0.9 forces a decline regardless of any other signal — onboarding a sanctioned party is a regulatory violation we don't let through. A periodic re-screening Beat task at 03:00 BDT picks up newly-listed parties against the existing customer book and emits Alerts and Cases on new hits.
The 12 Bangladesh-relevant rails.
The channel field on every scoring request must be one of these. Anything else returns 422.
- NPSB
- BEFTN
- RTGS
- MFS_BKASH
- MFS_NAGAD
- MFS_ROCKET
- CASH
- CHEQUE
- CARD
- WIRE
- LC
- DRAFT
Standardised envelope. Every route.
Non-2xx responses always carry the same shape. Pair the request_id with our structured logs to trace any single call end-to-end.
{
"detail": "Insufficient role",
"request_id": "c0807049-80e3-41d0-a78b-eb7ede8096d2",
"code": "auth.insufficient_role"
}| HTTP | Meaning | Typical cause |
|---|---|---|
| 401 | missing / invalid token | JWT expired, secret rotated, header malformed |
| 403 | role insufficient | e.g. bank persona writing a regulator-only resource |
| 402 | plan does not include feature | starter tier calling a Professional-only endpoint |
| 422 | request shape invalid | missing field, unknown channel, score out of range |
| 429 | rate limited | retry with exponential backoff; honour Retry-After |
| 500 | engine error | retry once; if it persists open a ticket with the request_id |
Authoritative is the live OpenAPI.
This page covers the three endpoints most banks integrate against. The complete surface (130+ routes — STR / SAR / CTR / IER / TBML lifecycle, alerts, cases, agentic investigations, dissemination ledger, admin, AI helpers) is auto-generated from the engine and lives at kestrel-engine.onrender.com/docs. Authentication is the same JWT.