Help and guidance for Risk Scoring System Documentation.
Streamlined scoring system with 7 core risk factors. High inbound volume is rewarded, high outbound volume is penalized.
The risk scoring system analyzes phone number usage patterns to identify potential spam or abusive behavior that could lead to carrier filtering or account suspension. The system calculates a risk score from 0-100, where higher scores indicate higher risk.
Impact: HIGH
Base Volume Scoring (for OUTBOUND-initiated conversations only):
> 50 outbound conversations/day: +30 points (VERY HIGH risk)40-50 outbound conversations/day: +20 points (HIGH risk)30-40 outbound conversations/day: +8 points (LOW risk)< 30 outbound conversations/day: 0 points (OK)Inbound Volume Bonus (high inbound volume is GOOD):
≥ 100 inbound conversations/day: 20 points (EXCELLENT - thriving business)50-100 inbound conversations/day: 15 points (GREAT - high organic demand)30-50 inbound conversations/day: 10 points (GOOD - solid organic traffic)15-30 inbound conversations/day: 5 points (DECENT - healthy inbound)< 15 inbound conversations/day: 0 points (NEUTRAL)Inbound Percentage Modifier (gradient - higher inbound % = better):
Why it matters: High conversation volume is only risky when it's outbound (cold outreach). High INBOUND conversation volume is fantastic - it means customers are reaching out to you! The scoring separates these: outbound volume adds risk, inbound volume gives bonuses. A business with 100+ inbound conversations/day is thriving, not spamming.
Note: Always evaluated.
Impact: MEDIUM
> 2,000 contacts: +15 points (HIGH risk)1,500-2,000 contacts: +8 points (WARNING)< 1,500 contacts: 0 points (OK)Why it matters: Accumulating thousands of contacts indicates potential broadcast/spam usage.
Note: Always evaluated.
Impact: VERY HIGH
< 20% reply rate: +35 points (VERY HIGH risk)20-30% reply rate: +20 points (HIGH risk)30-40% reply rate: +8 points (WARNING)40-50% reply rate: 0 points (OK)≥ 50% reply rate: 5 points (BONUS - excellent engagement)Why it matters: Low reply rates indicate messages aren't wanted or are perceived as spam. This is one of the strongest spam signals. The 3+ message threshold ensures we're measuring genuine engagement, not just a single acknowledgment.
Evaluation Threshold: Only evaluated once there are ≥10 total conversations (need sufficient sample size for meaningful rate).
Impact: HIGH
This metric evaluates the quality of engagement within conversations, focusing on inbound activity.
Inbound Message Count (per conversation):
< 3 inbound messages/conversation: +25 points (HIGH risk - low engagement)≥ 3 inbound messages/conversation: 0 points (OK - engaged recipients)Inbound/Outbound Ratio (within conversations):
< 20% inbound ratio: +20 points (HIGH risk - one-way communication)20-30% inbound ratio: +10 points (WARNING - weak engagement)≥ 30% inbound ratio: 0 points (OK - healthy back-and-forth)Why it matters: Shallow conversations with minimal inbound responses indicate spam. Real conversations have genuine back-and-forth exchanges where recipients actively participate.
Evaluation Thresholds:
Impact: VERY HIGH
> 60 new conversations/hour: +40 points (CRITICAL - obvious automation)40-60 new conversations/hour: +30 points (VERY HIGH risk - automation territory)25-40 new conversations/hour: +20 points (HIGH risk - suspicious pace)15-25 new conversations/hour: +10 points (WARNING - power user)< 15 new conversations/hour: 0 points (OK - human pace, ~1 per 4 minutes)Why it matters: Starting many new conversations rapidly is a hallmark of spam campaigns and mass outreach automation. This is more risky than message bursts within existing conversations. A human pace is roughly 1 new conversation every 3-4 minutes.
Note: Always evaluated. Looks at the maximum spike in any single hour over the 30-day window.
Impact: HIGH
> 200 messages/hour: +30 points (VERY HIGH risk - obvious automation)150-200 messages/hour: +20 points (HIGH risk - automation territory)100-150 messages/hour: +10 points (WARNING - power user)< 100 messages/hour: 0 points (OK - human pace)Why it matters: Sustained high-velocity sending is impossible for humans and indicates automation/botting. Over 200 messages per hour is a major red flag. However, this is less concerning than new conversation bursts if messages are going to existing, engaged contacts.
Note: Always evaluated. Looks at the maximum spike in any single hour over the 30-day window.
Impact: MEDIUM (Only computed with compute=true)
> 70% similar messages: +15 points (HIGH risk - robotic/templated)50-70% similar messages: +8 points (WARNING)< 50% similar messages: 0 points (OK)< 30% similar messages: 2 points (BONUS - natural variation)Why it matters: Repetitive templated messages are a spam hallmark. Natural conversations vary in content and length. SimHash provides a lightweight way to detect this without expensive text analysis.
Evaluation Threshold: Only evaluated if there are ≥20 qualifying messages (messages with ≥50 characters).
| Risk Factor | High Penalty | Warning | Bonus |
|---|---|---|---|
| Outbound Conversations/Day | +30 (>50), +20 (40-50) | +8 (30-40) | - |
| Inbound Conversations/Day | - | - | -5 to -20 (≥15 inbound/day) |
| Inbound % Modifier (gradient) | +20 (<20%), +10 (20-30%) | +5 (30-40%) | -2 to -15 (≥50%) |
| Total Contacts | +15 (>2000) | +8 (1500-2000) | - |
| Reply Rate | +35 (<20%), +20 (20-30%) | +8 (30-40%) | -5 (≥50%) |
| Inbound Message Count | +25 (<3/convo) | - | - |
| Inbound/Outbound Ratio | +20 (<20%) | +10 (20-30%) | - |
| New Conversation Bursts | +40 (>60/h), +30 (40-60/h), +20 (25-40/h) | +10 (15-25/h) | - |
| Message Bursts | +30 (>200/h), +20 (150-200/h) | +10 (100-150/h) | - |
| Message Similarity (SimHash) | +15 (>70%, ≥50 chars) | +8 (50-70%) | -2 (<30%) |
Maximum possible penalty: ~230 points (capped at 100)
Maximum possible bonus: -42 points (floor at 0)
These are computed every time, using efficient batch queries:
compute=true)These require expensive database joins and are cached for 24 hours:
For small organizations (≤5 numbers): Expensive metrics are auto-computed if not cached.
For large organizations (>5 numbers): Must explicitly request compute=true, with rate limiting (5-hour throttle between computes).
GET /organizations/:organizationId/analytics/risk-tolerance
Query Parameters:
compute=true - Force compute expensive metrics (rate-limited to once per 5 hours)Response:
{
"phone_numbers": [
{
"phone_number": "+15555551234",
"allocation_id": "alloc_abc123",
"risk_score": 12,
"risk_level": "low",
"metrics": {
"avg_outbound_conversations_per_day": 15.2,
"avg_inbound_conversations_per_day": 45.8,
"inbound_initiated_percentage": 75.1,
"total_contacts": 890,
"reply_rate": 52.5,
"avg_inbound_messages_per_conversation": 4.2,
"inbound_outbound_message_ratio": 0.38,
"max_new_conversations_per_hour": 12,
"max_messages_per_hour": 85,
"message_similarity_percentage": 32.1
},
"risk_factors": {
"outboundConversationsPerDay": {
"value": 15.2,
"score": 0,
"status": "ok",
"impact": "high"
},
"inboundConversationsPerDay": {
"value": 45.8,
"score": -10,
"status": "bonus",
"impact": "high"
},
"inboundPercentageModifier": {
"value": 0.751,
"score": -8,
"status": "bonus",
"impact": "high"
},
"replyRate": {
"value": 0.525,
"score": -5,
"status": "bonus",
"impact": "very_high"
},
"newConversationBursts": {
"value": 12,
"score": 0,
"status": "ok",
"impact": "very_high"
}
},
"daily_data": {
"conversations": [],
"messages": []
}
}
],
"period_days": 30,
"calculated_at": 1701388800000,
"computed_with_expensive_metrics": true
}
Only dedicated is included in risk scoring. Trial/shared/2fa numbers are excluded as they don't have real usage patterns suitable for risk analysis.
risk-tolerance:v4.1:{organizationId}For organizations with >5 numbers, queries are processed sequentially (one allocation at a time) to avoid Cloudflare Workers CPU limits. Small orgs use batch queries for speed.
The system uses a conversations table that pre-aggregates:
total_conversations: Count of unique external_id per allocationconversations_with_replies: Count where inbound_count >= 3 (3+ inbound messages = meaningful reply)initiated_by: 'inbound' or 'outbound' (who sent first message)allocation_id: Phone number allocationexternal_id: Unique conversation identifierdirection: 'inbound' or 'outbound'time_sent: Message timestamptext_length: Character countsimhash_text: Template similarity hashcontact_id: Unique contact identifierprotocol: 'sms', 'imessage', or 'rcs'≥ 90% inbound-initiated80-90% inbound-initiated: 12 points (GREAT - very organic)70-80% inbound-initiated: 8 points (GOOD - mostly organic)60-70% inbound-initiated: 5 points (DECENT - leaning organic)50-60% inbound-initiated: 2 points (OK - balanced)40-50% inbound-initiated: 0 points (NEUTRAL)30-40% inbound-initiated: +5 points (WARNING - leaning outbound)20-30% inbound-initiated: +10 points (HIGH risk - heavy outbound)< 20% inbound-initiated: +20 points (VERY HIGH risk - cold outreach dominant)