VirtualSMS
    VirtualSMS
    Ask AI:
    ← Back to Blog
    Technical

    Published: April 27, 2026 | 11 min read

    Building an AI agent that needs to sign up for accounts, verify users, or run multi-account ops? Phone verification is the gate that breaks most workflows. This guide ships ~30-line tool wrappers for LangChain, OpenAI Assistants, CrewAI, and Anthropic Claude tool-use, all backed by a real-SIM API that actually delivers.

    Build an AI Agent That Verifies Phone Numbers (LangChain / OpenAI / Claude)

    AI agent phone verification — LangChain, OpenAI Assistants, CrewAI, Claude tool-use

    Why AI Agents Need Phone Verification

    The moment you build an agent that signs up for any real platform, ai agent phone verification stops being optional. WhatsApp wants a phone. Telegram wants a phone. Google, Discord, Tinder, every consumer app and most B2B platforms gate sign-up behind an SMS code. The agent gets to the verification step and stalls — unless you wired it with a tool that can buy a number and read the code.

    Common workflows that hit this wall:

    • Account-creation pipelines. Agents that provision fresh accounts on a target platform (lead-gen, multi-region marketing, support automation) need a verified number per account.
    • KYC + identity verification. Agents that simulate the new-user funnel for testing or compliance audits need real-SIM coverage to mirror production behaviour.
    • Multi-account ops. Agencies running multiple ad accounts, business pages, or regional Telegram channels need fresh, individually-routed numbers per account to avoid the cluster-flag heuristics.
    • Support automation. Bots that interact with carrier-verified services on behalf of a user need to read inbound SMS as a first-class signal.

    The integration is straightforward — the trick is using a verification API that delivers reliably. The mechanics are unpacked in the VoIP vs physical SIM deep-dive; the short version is that real-SIM numbers verify cleanly on platforms where VoIP numbers bounce instantly. Pick that as the foundation and the agent ergonomics flow from there.

    Agent Framework Primer — LangChain vs OpenAI vs CrewAI vs Claude

    Before the code: a quick orientation on which framework expects what shape of tool. The verify-phone integration is the same logical operation everywhere; the wrapping changes per framework.

    FrameworkTool definition shapeBest when
    LangChainPython function with @tool decoratorComposable chains, RAG-heavy workflows, LangGraph state machines
    OpenAI AssistantsJSON-schema function spec + dispatcherHosted threads, file search, when you want OpenAI to manage state
    CrewAI@tool decorator + Agent role assignmentMulti-agent teams with explicit role separation
    Anthropic Claude tool-useJSON-schema in API call tools arraySingle-call agentic workloads, long-context reasoning
    Claude MCP serverAlready wired - no code neededClaude Desktop, Claude Code - see the Claude MCP setup guide

    If you’re on Claude specifically, skip the boilerplate entirely - the VirtualSMS MCP server gives you 18 SMS-verification tools wired directly into Claude Desktop, Claude Code, and any Claude API caller using tool-use. The rest of this post is for the LangChain / OpenAI / CrewAI / generic-Python path.

    The Integration Shape — Calling VirtualSMS From An Agent

    Every framework boils down to the same three calls against the VirtualSMS REST API:

    1. POST /v1/orders - buy a real-SIM number for a service+country combo. Returns the phone number and an order ID.
    2. GET /v1/orders/{id} - poll for the SMS code. Returns the parsed code as soon as the SMS lands. Auto-extracts the 4-8 digit verification code; you don’t need to regex it out yourself.
    3. POST /v1/orders/{id}/cancel - cancel an order. Auto-refunds if no SMS arrived. Use this in your timeout path.

    Authentication is a Bearer token in the Authorization header. Get one in 30 seconds at the API page - no KYC, no platform fee, no minimum spend. The same operations are available via the MCP server for AI-native callers.

    💡 Discovery endpoints are free to call. list_services, list_countries, check_price, and find_cheapest don’t require auth and don’t consume budget - let the agent plan before committing spend.

    Code: LangChain Tool Wrapper (Python)

    Drop this into your agent’s tool list and the agent can verify any service VirtualSMS supports. ~30 lines, no extra dependencies beyond requests.

    from langchain.tools import tool
    import requests, time, os
    
    API = "https://api.virtualsms.io/v1"
    KEY = os.environ["VIRTUALSMS_API_KEY"]
    H = {"Authorization": f"Bearer {KEY}"}
    
    @tool
    def verify_phone(service: str, country: str = "uk") -> dict:
        """Buy a real-SIM number for the given service+country, wait for the
        verification SMS, and return the parsed code. Auto-cancels on timeout."""
        order = requests.post(
            f"{API}/orders", headers=H,
            json={"service": service, "country": country},
        ).json()
        oid = order["id"]
        deadline = time.time() + 300  # 5 min
        while time.time() < deadline:
            sms = requests.get(f"{API}/orders/{oid}", headers=H).json()
            if sms.get("code"):
                return {"phone": order["phone"], "code": sms["code"]}
            time.sleep(3)
        requests.post(f"{API}/orders/{oid}/cancel", headers=H)
        return {"error": "timeout - order auto-cancelled and refunded"}

    Notes on what the agent does with this:

    • The agent decides service and country from context - “verify a Telegram account from the UK” → service=telegram, country=uk.
    • The 5-minute deadline is generous - most SMS land in 30-60 seconds. Tighten if you have stricter SLA needs.
    • Cancel-on-timeout is the safety net: failed activations auto-refund, so the agent doesn’t consume budget on dead orders.
    • For higher-throughput batches, swap the polling loop for the WebSocket-backed wait_for_code endpoint - same wrapper shape, no wasted HTTP.

    Code: OpenAI Assistants Function Definition (Python)

    Assistants register tools as JSON-schema function specs. The handler dispatches calls back to your Python function. The schema body is what the model sees when deciding whether and how to call the function.

    # OpenAI Assistants - function definition + handler
    client.beta.assistants.create(
        name="Verifier",
        model="gpt-4o",
        tools=[{
            "type": "function",
            "function": {
                "name": "verify_phone",
                "description": "Buy a real-SIM number, wait for the SMS code, return it.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "service": {"type": "string", "description": "e.g. whatsapp, telegram, google"},
                        "country": {"type": "string", "description": "ISO country code"},
                    },
                    "required": ["service"],
                },
            },
        }],
    )
    
    # Inside your run-loop tool-handler, dispatch the call:
    def handle_tool_call(call):
        if call.function.name == "verify_phone":
            args = json.loads(call.function.arguments)
            return verify_phone(args["service"], args.get("country", "uk"))

    Two notes specific to Assistants:

    • Schema descriptions matter. The phrasing of description directly drives whether the model invokes the tool when it should. “Buy a real-SIM number, wait for the SMS code, return it” is the right level of specificity.
    • The tool runs in your process, not OpenAI’s. That means your VirtualSMS API key never leaves your environment - no need to upload it to OpenAI’s platform.

    Code: CrewAI Tool Integration

    CrewAI uses the same @tool decorator as LangChain but wires tools to specific Agent roles rather than to a single chain. The natural pattern: a dedicated “Provisioner” agent owns verification, and other agents (Researcher, Writer, Outreach) hand off to it when they need a verified account.

    from crewai import Agent
    from crewai.tools import tool
    
    @tool("verify_phone")
    def verify_phone(service: str, country: str = "uk") -> dict:
        """Buy a real-SIM virtual number for service+country and return the code."""
        return _verify_phone_impl(service, country)  # same body as the LangChain tool
    
    verifier = Agent(
        role="Account Provisioner",
        goal="Provision verified accounts on demand",
        backstory="Specialises in handling phone-verification gates so other agents can focus on domain work.",
        tools=[verify_phone],
        verbose=True,
    )

    With this in place, a Crew can include the Provisioner alongside any other roles. The Crew’s task DAG handles the “verify the account before the next step” orchestration, and the Provisioner is the only agent that holds the API key.

    Code: Anthropic Claude Tool-Use

    Claude tool-use is a single API call that returns either a final answer or a structured tool-call request. Wire your Python handler against the tool name and feed results back via tool_result messages. Same code shape as the others, with the schema declared in the API call rather than in a decorator.

    # Claude API - tool-use definition (Python SDK)
    tools = [{
        "name": "verify_phone",
        "description": "Buy a real-SIM virtual number for service+country, wait for the SMS code, return it.",
        "input_schema": {
            "type": "object",
            "properties": {
                "service": {"type": "string"},
                "country": {"type": "string"},
            },
            "required": ["service"],
        },
    }]
    
    resp = client.messages.create(
        model="claude-opus-4-7",
        max_tokens=1024,
        tools=tools,
        messages=[{"role": "user", "content": "Verify a fresh Telegram account. Use a UK number."}],
    )
    # When resp.stop_reason == "tool_use", call verify_phone(...) and feed result back as tool_result.

    For Claude specifically, the bigger leverage is the MCP server - see the Claude MCP setup guide. With MCP, the entire verify_phone wrapper above becomes “install the server, prompt Claude.” Use raw tool-use when you’re on Claude API directly with custom orchestration; use MCP when the agent runs inside Claude Desktop or Claude Code.

    Why VoIP Breaks Agent Workflows

    The single most common reason an otherwise-correct agent fails to verify accounts: it’s wired against a VoIP-backed service. Twilio, Bandwidth, Plivo, Vonage, and the long tail of cheap VoIP resellers are detected at the carrier-prefix level by every major consumer platform. The detection is deterministic and instant - the SMS never leaves the platform’s queue.

    • WhatsApp - VoIP rejected at registration, no exceptions.
    • Telegram - VoIP rejected; agent burns budget on dead activations forever.
    • Tinder / Bumble / Hinge - VoIP rejected; among the strictest in consumer apps.
    • Discord - VoIP plus shared-aggregator ranges both blocked.
    • Google account verification - VoIP rejected on most regions.
    • Banks, brokerages, crypto exchanges - VoIP rejected as a rule, not an exception.

    For an agent, the failure mode is uniquely bad: the request looks successful to the API (number purchased, no error), the agent waits for the SMS, the SMS never arrives because the platform queued nothing, and the timeout fires. The agent retries the same combo, hits the same wall. The fix is upstream - verify-phone tools must be wired to a real-SIM API, not VoIP. Every code sample above assumes VirtualSMS as the backend for that reason.

    Cost + Reliability at Agent Scale

    Agent workloads tend to operate at higher throughput than a human user would - fan-out across services, batch verifications for testing, recurring KYC simulations. The economics shift accordingly. A few things worth knowing:

    • Activations from $0.05 per SMS code, with the exact price visible per service+country on the live pricing page.
    • Auto-refund on no-SMS - failed activations don’t consume budget. The agent loop can retry without cost paranoia.
    • 120 requests/min per API key default rate limit. Production accounts can be lifted higher; email [email protected] with your expected throughput.
    • Discovery endpoints are unauthenticated - let the agent plan country/service combos before committing budget.
    • UK / Germany / US for highest delivery - these are the highest-trust countries for the strict-detection platforms. If your agent is verifying WhatsApp, Tinder, or Discord, default to one of these and only fall back to mid-tier countries when stock runs thin.

    Builders who’ve already integrated and want the same flow at higher volumes (5-figure activations/month) - the API is the right surface for that, and we have a deeper virtual numbers for developer QA post on patterns that scale cleanly. For Claude-specific workflows, the MCP path skips the wrapper code entirely - see post 1 of the AI/MCP series for the install + workflow examples.

    ✅ Pre-launch checklist: hit /v1/balance (auth wired), call /v1/services (server reachable), run a single POST /v1/orders for a low-cost service to validate end-to-end before turning the agent loose on production traffic.

    Ask AI about this article

    Get a summary or follow-up answer in your favourite AI assistant.

    Frequently Asked Questions

    Can OpenAI Assistants make phone calls?

    OpenAI Assistants don't dial phone numbers themselves — they call functions you provide via the tool-use mechanism. To handle phone verification, you define a verify_phone function (with a JSON schema), and when the agent decides it needs a number, it triggers your function which calls VirtualSMS's REST API. The agent never touches the phone network directly; the API does the carrier-level work and the agent just consumes the resulting SMS code.

    How do I add SMS verification to LangChain?

    Wrap a verify_phone helper in @tool, register it in your agent's tool list, and the agent gains the ability to call it autonomously. The tool body hits POST /v1/orders to buy a real-SIM number, polls or websocket-waits for the SMS, and returns {"phone", "code"} to the calling chain. Total integration is roughly 30 lines of Python and works identically with create_react_agent, AgentExecutor, and LangGraph nodes.

    Do AI agents need real phone numbers?

    Almost always — yes. Agents that try to verify on VoIP-backed APIs (Twilio, Bandwidth, etc.) hit the same carrier-prefix rejection that humans hit, except the agent has no judgment to retry differently. WhatsApp, Telegram, Tinder, Discord, banking apps, and most major platforms run carrier-level VoIP detection. Real-SIM is the difference between an agent that completes verification on the first attempt and one that loops on timeout retries forever.

    What's the cheapest phone verification API for AI agents?

    VirtualSMS activations start from $0.05 per SMS code on the API, billed identically to dashboard or MCP usage. Discovery endpoints (list services, list countries, check price, find cheapest) are free to call so the agent can plan before committing spend. There's no per-month minimum, no API platform fee, and unused balance never expires — the cost-to-verify floor is the activation itself.

    Can Claude tool-use call my Twilio?

    Technically yes — Claude can call any function you expose. Whether the verification will actually succeed is the question, and for most platforms the answer with Twilio is no. Twilio numbers are detected as VoIP at the carrier-prefix level by WhatsApp, Telegram, Tinder, Discord, Google, and the rest. If you're building an agent that must reliably pass these verifications, swap Twilio for a real-SIM API like VirtualSMS — the integration shape is identical.

    How do I handle SMS timeouts in an AI agent loop?

    Set a hard deadline (we recommend 5 minutes for interactive agents, longer for bulk batches), poll the order endpoint or use the wait-for-code WebSocket, and call cancel_order on timeout — the activation auto-refunds if no SMS arrived. The pattern is in every code sample on this page: a deadline-bounded wait, a single cancel call on timeout, and a structured return so the agent can decide whether to retry with a different country.

    Published:
    VirtualSMS
    Engineering

    VirtualSMS

    Maintained by the VirtualSMS team. We've been shipping real-SIM SMS verification infrastructure since 2025 — 2000+ services across 145+ countries, MCP server v1.2.0 listed on Smithery and the official MCP registry. Open source, MIT licensed.

    Last updated:

    Related Articles

    Get an API Key in 30 Seconds

    Real-SIM verification API · 2,000+ services · 145+ countries · 120 rpm/key · Activations from $0.05 · Auto-refund on no-SMS