How Carrier Lookup Blocks Your AI Agent's Phone Number
Every OTP service runs a carrier lookup before sending verification codes. If your number returns 'VoIP', the code is never sent. Here's how it works and how to check.
Your AI agent needs to verify a phone number. You provision one from Twilio, Vonage, or any virtual number provider. The verification code never arrives. No error, no explanation — just silence.
The reason: carrier lookup. Every major service checks your number's line type before sending an OTP. If it returns voip, the SMS is never dispatched.
What Is Carrier Lookup?
When a service like Stripe or WhatsApp receives a phone number for verification, they query a carrier lookup API. This API checks telecom databases (LERG, NPAC, HLR) and returns metadata about the number:
{
"phone_number": "+15551234567",
"line_type_intelligence": {
"type": "nonFixedVoip",
"carrier_name": "Twilio Inc.",
"mobile_country_code": null,
"mobile_network_code": null
}
}That nonFixedVoip classification is the kill switch. The service sees it and silently drops your verification request.
Which Services Block VoIP?
| Service | Block Behavior | What You See |
|---|---|---|
| Stripe | Hard block | "This phone number cannot be used for verification" |
| Hard block | "Unsupported phone numbers, such as VoIP" | |
| Amazon | Silent failure | Code never arrives |
| Microsoft Entra | Risk-based | Error 399287 "BadReputation" |
| Vercel | Hard block | Registration rejected |
| Banks | Silent or vague | Codes not delivered |
The pattern is consistent: VoIP = blocked. Mobile = accepted.
How to Check Your Number
Before using any number with your AI agent, run a carrier lookup yourself. Here's how with the Twilio Lookup API:
from twilio.rest import Client
client = Client("ACCOUNT_SID", "AUTH_TOKEN")
result = client.lookups.v2.phone_numbers("+15551234567").fetch(
fields="line_type_intelligence"
)
lti = result.line_type_intelligence
print(f"Type: {lti['type']}") # "mobile" = good, "nonFixedVoip" = blocked
print(f"Carrier: {lti['carrier_name']}") # Who owns the numberWhat the types mean:
| Line Type | Description | OTP Success |
|---|---|---|
mobile | Real SIM on cellular network | ✅ Accepted everywhere |
fixedVoip | VoIP tied to a physical address | ❌ Blocked by most services |
nonFixedVoip | VoIP with no physical address (Twilio, Vonage) | ❌ Blocked by most services |
landline | Traditional phone line | ⚠️ Can't receive SMS |
Why Twilio Numbers Always Fail
Twilio owns its number ranges. The LERG (Local Exchange Routing Guide) database permanently maps those ranges to Twilio's OCN (Operating Company Number). No matter what you do, a carrier lookup on a Twilio number will always return:
carrier_name: "Twilio"
type: "nonFixedVoip"
This isn't a bug — it's how the telecom system classifies numbers. Twilio numbers are genuinely VoIP. The same applies to Vonage, Bandwidth, and every other virtual number provider.
The Fix: Real SIM Infrastructure
The only way to pass carrier lookup is to use numbers provisioned on real SIM infrastructure — numbers that are registered on cellular networks with actual IMSI values and carrier connections.
import agentsim
async with agentsim.provision(agent_id="my-agent") as session:
print(f"Number: {session.number}")
# Carrier lookup returns: type: "mobile", carrier: "T-Mobile USA"
# Use session.number for verification...
otp = await session.wait_for_otp(timeout=120)
print(f"Code: {otp.code}")When you run a Twilio Lookup on an AgentSIM number:
{
"line_type_intelligence": {
"type": "mobile",
"carrier_name": "T-Mobile USA"
}
}The difference is at the infrastructure level. AgentSIM provisions on real SIM cards connected to cellular networks. The number genuinely is mobile — it's not a software trick or API wrapper.
Important: Carrier Lookup ≠ Guaranteed Acceptance
Passing carrier lookup is necessary but not always sufficient. Some services apply additional checks:
- Behavioral analysis — Account creation velocity, IP reputation, browser fingerprinting
- Number reputation — Some number ranges get flagged from overuse
- Geographic consistency — IP location vs. phone number area code
- HLR queries — Real-time checks on whether the SIM is actively registered on a network
Carrier lookup returning mobile gets you past the first gate. The other gates depend on the specific service and how you're using the number.
Cost Comparison
| Solution | Per-Verification | Carrier Lookup Result |
|---|---|---|
| Twilio | $1.15/number + SMS fees | nonFixedVoip ❌ |
| Vonage | $1.00/number + SMS fees | nonFixedVoip ❌ |
| Prepaid SIM | $5-10 + manual labor | mobile ✅ |
| AgentSIM | $0.99/session | mobile ✅ |
Free tier: 10 sessions/month. No subscription, no idle numbers.
Try It
pip install agentsim-sdkimport agentsim
agentsim.api_key = "your-api-key"
async with agentsim.provision(agent_id="carrier-test") as session:
print(f"Number: {session.number}")
# Now use this number for verification
otp = await session.wait_for_otp(timeout=120)
print(f"OTP: {otp.code}")Get an API key at agentsim.dev.
AgentSIM provisions real SIM-backed mobile numbers for AI agent verification. Carrier lookup returns mobile, not voip.