AgentSIMOTP sessions for agents
← Blog
5 min read

How Carrier Lookup Blocks AI Agents — And When Programmable Numbers Work

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, what it means for AI agents, and where programmable numbers actually fit.


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?

ServiceBlock BehaviorWhat You See
StripeHard block"This phone number cannot be used for verification"
WhatsAppHard block"Unsupported phone numbers, such as VoIP"
AmazonSilent failureCode never arrives
Microsoft EntraRisk-basedError 399287 "BadReputation"
VercelHard blockRegistration rejected
BanksSilent or vagueCodes not delivered

The pattern is consistent: VoIP = blocked. A mobile-classified number on a real cellular carrier = accepted by these platforms. Programmable numbers — including AgentSIM — are not mobile-classified and are not the right tool for strict consumer-platform signups on this list.

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" = real cellular, "nonFixedVoip" = blocked by strict platforms
print(f"Carrier: {lti['carrier_name']}") # Who owns the number

What the types mean:

Line TypeDescriptionOTP Success
mobileNumber registered on a cellular carrier with an IMSI✅ Accepted by strict consumer platforms
fixedVoipVoIP tied to a physical address❌ Blocked by most services
nonFixedVoipVoIP with no physical address (Twilio, Vonage, programmable numbers)❌ Blocked by most services
landlineTraditional 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, including AgentSIM.

Where Programmable Numbers Fit: Flows You Own and CI/QA

Strict consumer platforms (Stripe, Google, WhatsApp, banks) require a real, mobile-classified number — one that cannot be a programmable CPaaS number. If a reader needs to pass those signups, a programmable number is the wrong tool.

The right fit for programmable numbers is:

  • Auth flows you own — testing your own app's login, 2FA, or signup SMS flow in dev, staging, or CI.
  • Browser-agent QA — running automated agents through registration flows on services you control.
  • Verified-compatible targets — services empirically known to accept programmable numbers. Check the AgentSIM support map for what's confirmed to work.

For those cases, AgentSIM gives your agent a programmable US number with a parsed OTP payload and delivery diagnostics:

import agentsim
 
async with agentsim.provision(agent_id="my-agent") as session:
    print(f"Number: {session.number}")
 
    # Trigger the SMS from the service under test, then wait for it to arrive
    otp = await session.wait_for_otp(timeout=120)
    print(f"Code: {otp.code}")

If no OTP arrives, you can inspect the raw messages to classify the outcome — whether the service rejected the number outright, silently dropped the SMS, or hit an anti-bot gate:

messages = await session.get_messages()
# Inspect messages to distinguish: no_sms, sms_no_otp, phone_rejected, anti_bot_gate

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 a number is actively registered on a network

Even a mobile-classified number hits these gates. And for programmable numbers, the carrier-lookup gate itself may already reject — delivery is not guaranteed on strict platforms. Check the support map before assuming a target will work.

Cost Comparison

SolutionPer-VerificationBest For
Twilio$1.15/number + SMS feesProgrammable SMS — not strict consumer signup
Vonage$1.00/number + SMS feesProgrammable SMS — not strict consumer signup
Prepaid SIM (manual)$5-10 + laborOne-off personal account setup
AgentSIM$0.99/sessionAuth flows you own, CI/QA, verified-compatible targets

Free tier: 10 sessions/month. No subscription, no idle numbers.

Try It

pip install agentsim-sdk
import agentsim
 
agentsim.api_key = "your-api-key"
 
async with agentsim.provision(agent_id="carrier-test") as session:
    print(f"Number: {session.number}")
    # Trigger the OTP from your service under test
    otp = await session.wait_for_otp(timeout=120)
    print(f"OTP: {otp.code}")

Get an API key at agentsim.dev. For strict consumer-platform signups that require a mobile-classified number, programmable numbers (AgentSIM included) may be rejected before SMS — check the support map.


AgentSIM provisions programmable US numbers for AI agents — built for auth flows you own, CI/QA pipelines, and browser-agent testing on verified-compatible services.