I Built an Autonomous Phone Verification Agent (Full Code + Tutorial)

Dev.to / 4/7/2026

💬 OpinionDeveloper Stack & InfrastructureTools & Practical Usage

Key Points

  • The article explains why autonomous phone verification agents fail: major services (e.g., Stripe, Google, WhatsApp) perform carrier/line-type lookups and automatically reject VoIP/cloud numbers.
  • It demonstrates via a Twilio lookup API example that cloud phone providers commonly return line_type as “voip,” leading to consistent verification rejection.
  • The proposed fix is to use real-SIM-based number provisioning (via Telnyx) so carrier lookup returns line_type “mobile,” matching what verification providers expect.
  • It claims the approach enables an autonomous agent to complete phone verification end-to-end in about 3.5 seconds and provides full code plus a tutorial workflow.
  • The core takeaway is that verification success depends less on agent intelligence and more on using phone number infrastructure aligned with carrier verification rules.

You built an AI agent that can browse the web, fill forms, and make decisions. But it hits a wall every single time:

"This phone number cannot be used for verification."

Stripe. WhatsApp. Google. All of them run a carrier lookup. All of them block VoIP. And every cloud phone API returns line_type: VoIP.

Your agent is stuck. Not because it's dumb. Because the infrastructure is wrong.

Today I'll show you how to fix it. Full code. Real results.

The Problem in 30 Seconds

When Stripe receives a phone number, it doesn't just send an SMS. First, it queries the LERG/NPAC databases to check: what type of number is this?

$ curl https://lookups.twilio.com/v2/PhoneNumbers/+16505550001
{
  "line_type_intelligence": {
    "type": "voip",
    "carrier": "Twilio Inc."
  }
}

Result: REJECTED. Stripe blocks VoIP numbers for verification. Always.

The same check happens at Google, WhatsApp, Telegram, banks. If your agent uses a cloud phone number, it will fail.

The Fix: Real SIM Infrastructure

The solution isn't a hack. It's the right infrastructure. AgentSIM provisions numbers on real physical SIM cards through Telnyx. Carrier lookup returns line_type: mobile -- exactly what Stripe, Google, and WhatsApp expect.

$ agentsim.provision({ country: "US" })
{
  "number": "+14155551234",
  "carrier": "T-Mobile",
  "line_type": "mobile"
}

Building the Agent

Here's the complete code. Three steps. ~3.5 seconds end to end.

Step 1: Install

pip install agentsim

Step 2: Provision a Number

import asyncio
from agentsim import AgentSIM

async def main():
    agentsim = AgentSIM(api_key="your-api-key")

    number = await agentsim.provision({
        "country": "US",
        "capabilities": ["sms"],
    })

    print(f"Number: {number.number}")
    print(f"Carrier: {number.carrier}")
    # Number: +14155551234
    # Carrier: T-Mobile

Step 3: Wait for OTP

    otp = await number.wait_for_otp(timeout=30_000)

    print(f"OTP: {otp.code}")
    print(f"Service: {otp.service}")
    # OTP: 847291
    # Service: stripe

That's it. The OTP is parsed automatically -- code extracted, service detected, structured JSON returned. No regex. No human reading SMS.

Full Autonomous Flow with Playwright

from playwright.async_api import async_playwright

async def verify_on_stripe():
    number = await agentsim.provision({"country": "US"})

    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page()
        await page.goto("https://connect.stripe.com/setup")
        await page.fill("input[name='phone']", number.number)
        await page.click("button[type='submit']")

        otp = await number.wait_for_otp(timeout=30_000)
        await page.fill("input[name='code']", otp.code)
        await page.click("button[type='submit']")

        print("Phone verified")
        await browser.close()

Real Performance Numbers

This isn't theoretical. Here's what's running in production:

  • Provision time: 212ms average
  • OTP delivery: 3.5s average
  • Cost: $0.99 per session (provision + OTP + release)

Compare to alternatives:

Solution Cost Carrier Result
Twilio $1.15/number + usage line_type: VoIP (blocked)
JoltSMS $50/number/month line_type: mobile (works)
Shared virtual $0.30-2/number line_type: VoIP (blocked)
AgentSIM $0.99/session line_type: mobile (works)

At 100 verifications/month: JoltSMS costs $5,000. AgentSIM costs $99. 50x cheaper.

Why This Matters for AI Agents

AI agents are autonomous by design. They browse, decide, and act. But if every action that requires phone verification needs a human to read an SMS, your agent isn't autonomous -- it's a puppet.

Real SIM infrastructure removes the last human bottleneck. Your agent can:

  • Create and verify Stripe Connect accounts
  • Set up WhatsApp Business API
  • Verify Google accounts for service access
  • Register on any platform requiring SMS verification

All without human involvement.

MCP Native

If you're building with Claude Code, Cursor, or Windsurf -- AgentSIM has a built-in MCP server. One command to add it:

claude mcp add agentsim -- npx -y @agentsim/mcp-server

Now your agent can provision numbers through natural language: "I need a US phone number to verify a Stripe account"

Try It Free

AgentSIM gives you 10 free sessions per month -- no credit card, no commitment. If the OTP doesn't arrive, you're not charged.

Get started at agentsim.dev/sign-up

One session = one number, one OTP, one verification. Your agent does the rest.

Open source at github.com/agentsimdev/agentsim. Docs at docs.agentsim.dev.