Fraud Signals
One risk score from SIM-swap recency, BVN demographic changes and watchlist status. Built for account-takeover and onboarding fraud.
Combines SIM-swap recency, recent BVN demographic changes and the industry watchlist into one risk score from 0 to 100. Built for account takeover and onboarding fraud.
- Availability
- Sandbox and live
- Indicative price
- ₦200.00 per completed check
- Consent
- Your attestation (
client_attested). - MCP tool
check_signals
Body parameters
phonestringFormat: Nigerian mobile number,
0803…or+234803….bvnstringFormat: 11 digits.
reasonstringrequiredPurpose of the check. One of the 38 NIMC purpose codes. See the purpose code list.
consentobjectrequiredYour attestation that you obtained the data subject's consent for this purpose.
consent.obtainedbooleanrequiredAlways
true.
- Provide
phone,bvn, or both. The phone drives SIM-swap signals; the BVN drives demographic changes and the watchlist. matchis alwaysnull: a risk score is not a match. Readsummary.risk_scoreandsummary.risk_level.- Weights: watchlisted 60, SIM swap within 7 days 35 (within 30 days 15), BVN name change within 30 days 20, BVN phone change within 30 days 10. The score is capped at 100;
highfrom 60,mediumfrom 30.
Send an Idempotency-Key header so a retried request is never billed twice. See Idempotency.
curl -X POST http://localhost:4000/v1/signals \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"phone": "08099990000",
"bvn": "22222222225",
"reason": "financialProducts",
"consent": {
"obtained": true
}
}'A completed check returns 200 with a verification object. status is verified or not_found. If the provider has not answered in time you get 202 with status: "pending"; retrieve it later or wait for the verification.completed webhook.
{
"reference_id": "spm_8171f3a87cbe221341f7185f",
"object": "verification",
"product": "signals",
"method": "risk_signals",
"status": "verified",
"match": null,
"field_matches": null,
"field_confidence": null,
"mode": "sandbox",
"reason": "financialProducts",
"subject": "*******2225",
"summary": {
"risk_score": 100,
"risk_level": "high",
"factors": [
{
"code": "watchlisted",
"weight": 60,
"detail": "BVN is on the industry watchlist"
},
{
"code": "sim_swap_7d",
"weight": 35,
"detail": "SIM swapped 2 day(s) ago"
},
{
"code": "bvn_name_change_30d",
"weight": 20,
"detail": "Name changed on the BVN in the last 30 days"
},
{
"code": "bvn_phone_change_30d",
"weight": 10,
"detail": "Phone number changed on the BVN in the last 30 days"
}
],
"sim_swap_recent": true,
"days_since_sim_swap": 2,
"bvn_demographic_changes": 2,
"bvn_demographic_changes_30d": 2,
"watchlisted": true
},
"consent": {
"mechanism": "client_attested",
"consent_id": null,
"timestamp": "2026-10-19T09:41:07.512Z"
},
"source": "api",
"error": null,
"billing": {
"amount_kobo": 0,
"currency": "NGN"
},
"latency_ms": 520,
"created_at": "2026-10-19T09:41:07.512Z",
"updated_at": "2026-10-19T09:41:07.874Z"
}summary
risk_scoreintegerSum of factor weights, 0 to 100.
risk_levelstringlow,mediumorhigh.factorsarrayEach factor:
code,weightand a readabledetail.sim_swap_recentboolean | nullSIM swapped within 30 days.
nullwithout a phone.days_since_sim_swapinteger | nullDays since the last SIM swap.
bvn_demographic_changesinteger | nullNumber of demographic changes on the BVN.
nullwithout a BVN.bvn_demographic_changes_30dinteger | nullChanges in the last 30 days.
watchlistedboolean | nullBVN is on the industry watchlist.
Full-tier accounts calling the REST API also receive provider, provider_reference and data, the normalized record. MCP, webhooks, lists and bulk results never include it. See Response shaping.
{
"provider": "sandbox",
"provider_reference": "SBX6CB753DB2C",
"data": {
"risk_score": 100,
"risk_level": "high",
"factors": [
"…"
],
"sim_swap": {
"days_since_swap": 2
},
"bvn_changes": [
"…"
]
}
}Send these bodies with a sandbox key. More outcome triggers are on the Sandbox page.
{
"phone": "08099990000",
"bvn": "22222222225",
"reason": "financialProducts",
"consent": {
"obtained": true
}
}{
"phone": "08187654321",
"bvn": "22222222226",
"reason": "financialProducts",
"consent": {
"obtained": true
}
}{
"phone": "08031234567",
"bvn": "22222222221",
"reason": "financialProducts",
"consent": {
"obtained": true
}
}| Status | Code | Meaning |
|---|---|---|
400 | invalid_request | The body failed validation. details lists each field. |
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Live only: wallet balance is below the check price. |
403 | not_entitled | Your workspace is not enabled for this product or method. |
409 | idempotency_key_reused | The Idempotency-Key was used with a different body. |
422 | provider_rejected_request | The upstream registry rejected the request. |
503 | verification_unavailable | Temporary failure. Retry, with the same or a new Idempotency-Key. |
All errors share one shape. See Errors for the full list.
Questions? Email developers@speedmap.ng. This page is also available as Markdown.