The OTP Problem
Your agent fills out a signup form, enters a phone number, and clicks “Send Code.” A 6-digit code arrives via SMS. For a human, this takes 5 seconds. For an agent, this is one of the hardest problems in web automation.
OTP verification is the single most common blocker for autonomous agents. It combines three challenges: owning a phone number that services accept, receiving the SMS programmatically, and extracting the code from unstructured text. This guide shows you how to solve all three.
Why OTP Verification Is Hard for Agents
Challenge 1: Getting a Number That Works
Most online services reject VoIP numbers. If your agent uses a Twilio number to sign up for Stripe or Uber, the SMS never arrives. The service silently drops it because the number is flagged as non-mobile in carrier databases.
Solution: Use a real SIM number. AgentCall provisions numbers from actual mobile carriers, so they pass the same verification checks as a personal phone.
Challenge 2: Receiving the SMS
Even with a valid number, your agent needs a way to access incoming messages. You could set up a webhook, poll an API, or use a helper service. Each approach has latency and reliability tradeoffs.
Solution: AgentCall's sms.waitForOTP() method handles this with a single async call. It waits for an incoming SMS on the specified number, extracts the OTP, and returns it — with configurable timeout.
Challenge 3: Parsing the Code
OTP messages have no standard format. Some say “Your code is 583016”, others say “583016 is your verification code for Acme”, and some embed the code in a URL. Regex alone isn't enough for production use.
Solution: AgentCall's OTP extraction is trained on patterns from hundreds of services. It handles numeric codes, alphanumeric codes, and codes embedded in links.
Implementation: Step by Step
Step 1: Provision a Number
import AgentCall from 'agentcall';
const client = new AgentCall({ apiKey: 'ac_live_...' });
const number = await client.numbers.provision({
country: 'US',
type: 'sim',
label: 'signup-agent-01',
});
console.log(number.number); // +15672901611Step 2: Use the Number on a Signup Form
Your agent (browser automation, Playwright, Puppeteer, etc.) navigates to the signup page and enters the provisioned number in the phone field.
// Example with Playwright
await page.fill('input[name="phone"]', number.number);
await page.click('button:has-text("Send Code")');Step 3: Wait for the OTP
const otp = await client.sms.waitForOTP(number.id, {
timeout: 60000, // 60 second timeout
});
console.log(otp); // "583016"The waitForOTP() call blocks until an OTP is detected in an incoming SMS, or the timeout is reached. It returns just the code — no parsing required.
Step 4: Enter the Code
// Type the OTP into the verification form
await page.fill('input[name="otp"]', otp);
await page.click('button:has-text("Verify")');Alternative: Webhook-Based OTP
If you prefer an event-driven architecture, you can use webhooks instead of polling:
// Register a webhook for SMS events
await client.webhooks.create({
url: 'https://your-agent.com/webhook',
events: ['sms.received'],
});
// Your webhook handler receives:
// {
// event: "sms.received",
// data: {
// from: "+1800STRIPE",
// body: "Your Stripe code is 583016",
// otp: "583016",
// numberId: "num_abc123"
// }
// }The otp field is automatically extracted and included in the webhook payload when the message contains a verification code.
Best Practices
- One number per agent: Never share numbers between agents. OTP messages need to be unambiguously routed to the correct agent.
- Set reasonable timeouts: Most OTPs arrive within 10-30 seconds. A 60-second timeout covers edge cases without blocking too long.
- Label your numbers: Use the
labelfield when provisioning so you can identify which agent owns which number in your dashboard. - Handle expiry: OTP codes typically expire in 5-10 minutes. If your agent is slow to act, request a new code rather than retrying the expired one.
- Monitor via webhooks: Even if you use
waitForOTP(), setting up webhooks gives you an audit trail of all messages for debugging.
Supported Platforms
AgentCall's real SIM numbers have been tested with OTP verification on:
- Stripe, Square, and payment processors
- Google, Microsoft, and Apple accounts
- Uber, Lyft, and ride-sharing platforms
- WhatsApp, Telegram, and messaging apps
- Banks and financial services (Chase, Wells Fargo, etc.)
- Social platforms (Instagram, Twitter/X, LinkedIn)
If a service sends SMS verification to real phone numbers, AgentCall can receive it.
FAQ
What if the OTP comes as a voice call instead of SMS?
Some services offer voice call verification as a fallback. AgentCall supports receiving voice calls on your provisioned numbers. Voice-based OTP extraction is on the roadmap.
Can I reuse a number for multiple signups?
Yes — a single provisioned number can receive unlimited OTPs. However, some services limit how many accounts can be tied to one phone number, so for high-volume signups you may want to provision multiple numbers.