Risk Scoring
Combine signals from a phone number, email, IP address, device fingerprint, and declared identity into a single risk score from 0–100. Each request returns the contributing factors and an actionable recommendation, so you can automate low-risk approvals and route the rest to manual review.
🚀 Quick Start
curl -X POST https://api.afriroute.ai/api/v1/identity/risk-score \
-H "Authorization: Bearer $AFRIROUTE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+251911234567",
"email": "[email protected]",
"ip_address": "196.190.1.100",
"device_fingerprint": "fp_abc123"
}'
📡 Endpoint
Compute Risk Score
POST /v1/identity/risk-score
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
phone_number | string | No | E.164 number to assess for VoIP/fraud history |
email | string | No | Email to check for validity and domain reputation |
ip_address | string | No | IP for geolocation and blacklist checks |
device_fingerprint | string | No | Device ID for velocity and known-device checks |
customer_info | object | No | Declared name/DOB for cross-signal matching |
At least one signal is required. More signals produce a more accurate score.
💻 Code Samples
Node.js
const res = await fetch('https://api.afriroute.ai/api/v1/identity/risk-score', {
method: 'POST',
headers: { 'Authorization': 'Bearer $AFRIROUTE_API_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({
phone_number: '+251911234567',
email: '[email protected]',
ip_address: '196.190.1.100',
device_fingerprint: 'fp_abc123',
customer_info: { full_name: 'Abebe Kebede', date_of_birth: '1990-05-15' }
})
});
const data = await res.json();
if (data.recommendation === 'proceed') approve();
Python
import requests
res = requests.post(
'https://api.afriroute.ai/api/v1/identity/risk-score',
headers={'Authorization': 'Bearer $AFRIROUTE_API_KEY'},
json={
'phone_number': '+251911234567',
'email': '[email protected]',
'ip_address': '196.190.1.100',
'device_fingerprint': 'fp_abc123'
}
)
print(res.json()['risk_level'], res.json()['recommendation'])
📊 Response
{
"risk_score": 12,
"risk_level": "low",
"recommendation": "proceed",
"factors": [
{ "factor": "phone_risk", "score": 5, "details": "Real mobile number, known carrier" },
{ "factor": "email_risk", "score": 3, "details": "Valid email, domain age 5 years" },
{ "factor": "geo_risk", "score": 2, "details": "IP matches declared country" },
{ "factor": "device_risk", "score": 2, "details": "Known device, no suspicious activity" }
],
"checks": {
"phone_verified": true,
"email_valid": true,
"ip_blacklisted": false,
"device_known": true,
"velocity_check": "passed",
"name_match": "high_confidence"
}
}
🎯 Score Bands
| Score | Level | Recommendation |
|---|---|---|
| 0–20 | Low ✅ | proceed — auto-approve |
| 21–50 | Medium ⚠️ | review — optional manual review |
| 51–75 | High 🚨 | manual_review — require human approval |
| 76–100 | Very high ❌ | reject — likely fraud |
💡 Best Practices
- Pass every signal you have — device fingerprint and IP dramatically improve accuracy.
- Treat the score as advisory, not a hard gate; combine it with your own business rules.
- Re-score at key events (signup, first payout, password reset), not just once at onboarding.
- Store the
factorsarray for audit and dispute resolution. - Monitor velocity — a clean device seen across many accounts is a strong fraud signal.
⚠️ Error Handling
| Code | HTTP | Description |
|---|---|---|
NO_SIGNALS_PROVIDED | 400 | Request contained no scorable signals |
INVALID_IP | 400 | ip_address is malformed |
INVALID_EMAIL | 400 | email is malformed |
SCORING_UNAVAILABLE | 503 | A scoring subsystem is temporarily degraded |
See the error code reference for the full list.
📚 Related Resources
Last Updated: May 2026 | Need help? [email protected]