SMS Mock inbox for end-to-end tests

The text never leaves.
Your test gets the code anyway.

otpmock speaks the API of the SMS provider you already use: Twilio, Vonage, AWS SNS, Infobip, Sinch, Plivo, Netgsm or İleti Merkezi. Your app sends verification codes the same way it does in production. We catch every message before it gets anywhere near a carrier, and hand the code to Playwright, Cypress, or whoever is clicking through staging.

Free for 100 messages a month. No card required.

Last code caught
+1555 0142Vonage Verify

Arrivals

SMS inbox · demo--:--:--

This board is a demo. Nothing on it ever reached a phone, and nothing your tests send will either.

Real SMS sent
0
SMS provider APIs
8Twilio, Vonage, AWS SNS…
Message retention
10minutes
Free every month
100messages

Works with Playwright / Cypress / Appium / Jest / GitHub Actions / GitLab CI / any HTTP client

1 The problem

Every signup test hits the same wall.

The flow works. The suite doesn't, because step four is waiting for a text message. Every common workaround costs you something.

  1. 01

    Send real SMS

    You pay for every message on every CI run. Delivery takes as long as the carrier decides, so tests time out at random. And you still need a phone, or a paid inbox, to read the code back.

  2. 02

    Hard-code a test code

    if (phone === TEST_PHONE) code = "000000" works fine until one config mistake ships it to production. Then it's a key to every account on that number.

  3. 03

    Write your own fake

    Fine for plain SMS. Useless with Verify APIs (Twilio Verify, Vonage Verify), where the provider generates the code and your fake never sees it. Then you build it again for the next project.

2 How it works

Change one option. Keep the rest of your stack.

otpmock answers in your SMS provider's own API format, so your application code can't tell the difference. Only the test environment's configuration changes.

  1. Your app

    Sends as usual

    Calls your provider's SDK: messages.create, sms.send, a Verify request. Same SDK, same code path as production.

  2. otpmock

    Catches the message

    Answers in your provider's exact response format, keeps the message for 10 minutes and pulls the code out of the text.

    Carrier network never contacted

  3. Your test

    Reads the code

    Asks the inbox over HTTPS and types the code in. Verify checks pass with the right code, exactly like the real provider.

Example: the whole integration for the Twilio Node.js SDK. Every provider is a similar one-option change (Vonage's restHost, the AWS SDK's endpoint, Infobip's baseUrl…). Production keeps talking to your provider; anything with OTPMOCK_URL set talks to us.

src/sms.ts+2 lines
  import twilio from "twilio";
import { OtpMockHttpClient } from "./twilio-node-client.mjs";
  export const sms = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN, {
  httpClient: process.env.OTPMOCK_URL ? new OtpMockHttpClient(process.env.OTPMOCK_URL) : undefined,
  });

3 Providers

Keep your SMS provider. Swap the host in tests.

Each emulation follows the provider's real paths, payloads, responses and errors, and is tested end to end with the provider's official Node.js SDK.

Using something else? Send to the generic HTTP API from a test-only branch. All providers

4 In your tests

Read the code from wherever your tests run.

Give every test its own number so parallel workers never read each other's codes. Then wait for the code and type it in.

signup.spec.ts
test("sign up with a phone number", async ({ page }) => {
  const phone = otp.randomPhone();            // unique per test

  await page.getByLabel("Phone").fill(phone);
  await page.getByRole("button", { name: "Send code" }).click();

  const { code } = await otp.waitForCode(phone);
  await page.getByLabel("Verification code").fill(code);

  await expect(page.getByText("Welcome")).toBeVisible();
});

The otp helper is a single dependency-free file. Get it from the docs. Using an AI coding assistant? Point it at otpmock.com/llms-full.txt and it can do the whole integration.

5 Dashboard

One inbox for the whole team. Developers, QA and CI.

Manual testers watch codes land in the browser and click to copy. Engineers manage keys per environment. Everyone sees how much of the month is left.

Plan2026-10
Team
12,480 / 25,000 messagesResets Nov 1
API keys3 / 10
  • om_live_9f2c…CIused just now
  • om_live_41ab…stagingused 12 min ago
  • om_live_c07e…localused 2 h ago
ArrivalsLive
  • +1555 0142vonage-verify · 14:02:41

    Your Acme verification code is: 482913

  • +1555 3307aws-sns · 14:02:38

    Acme: 7731 is your login code. Don't share it.

  • +1555 8816twilio · 14:02:19

    Your Acme code: 905126

  • +1555 0279netgsm · 14:01:57

    Use 3388 to confirm your phone number.

6 Spec sheet

The fine print, up front.

Compatible with
Twilio (Messaging, Verify v2), Vonage (SMS, Messages, Verify v2), AWS SNS, Infobip, Sinch, Plivo, Netgsm and İleti Merkezi. Each is tested against the provider's official Node.js SDK, error formats included. Anything else can use the generic HTTP API.
Code extraction
Looks for a 4 to 8 digit number next to words like code, OTP or PIN, then falls back to the first one in the message.
Parallel tests
Every test can use its own virtual number. Workers never share an inbox.
Stale codes
A since timestamp ignores anything left over from the previous run.
Consistency
A code is readable the moment your app's send call returns. No eventual consistency, no sleeps.
Isolation
Each account gets its own isolated storage, shared by its API keys. No other customer can see your messages.
Retention
Messages and verifications are deleted after 10 minutes.
Infrastructure
Cloudflare Workers and Durable Objects.
Real SMS sent
Never.

7 Pricing

Cheaper than the texts you're not sending.

A message is one SMS your app sends, or one Verify verification it starts. Reading codes is always free.

Free

Try it

App → otpmock → Test

  • 100 messages a month
  • 1 API key
  • All 8 SMS provider APIs
  • Live inbox
$0
forever
Get a free key

Solo

One project

App → otpmock → Test

  • 5,000 messages a month
  • 3 API keys
  • All 8 SMS provider APIs
  • Email support
$19
per month
Choose Solo

Enterprise

Big suites

App → otpmock → Test

  • Unlimited messages (fair use)
  • Unlimited API keys
  • All 8 SMS provider APIs
  • Priority email support
$129
per month
Choose Enterprise

Prices in USD, billed monthly. Payments are processed by Creem, our merchant of record, which also handles sales tax and VAT. Cancel any time. See the refund policy.

8 Questions

Before you ask support.

Does otpmock send real SMS?

No, and that's the point. Messages never leave our API: no carrier fees, no delivery delays, no phones involved. Use otpmock in test and staging environments only.

Do I have to change my application code?

Barely. You point your provider's SDK at otpmock when an environment variable is set, usually one option such as Twilio's httpClient, Vonage's restHost or the AWS SDK's endpoint. Your production configuration stays exactly as it is.

What about Verify APIs, where the provider generates the code?

Supported for Twilio Verify v2 and Vonage Verify v2. otpmock generates the code, your test reads it from the inbox, and the verification check approves it the same way the provider would, including wrong-code and too-many-attempts errors.

Which SMS providers are supported?

Twilio, Vonage, AWS SNS, Infobip, Sinch, Plivo, Netgsm and İleti Merkezi. For anything else, such as MessageBird or an in-house gateway, send to otpmock's generic HTTP API from a test-only branch, and email support@otpmock.com: requests decide what we build next.

Can I use real phone numbers in tests?

You can, but please don't. Test environments should use made-up numbers like the ones randomPhone() generates. Either way, every message is deleted after 10 minutes.

What happens when I run out of messages?

Sending returns HTTP 429 until your allowance resets on the 1st of next month (UTC), or until you upgrade. Reading codes keeps working.

Can I cancel?

Any time, from your account. You keep access until the end of the period you've paid for. New subscriptions can be refunded within 7 days; see the refund policy.

Ship the signup flow with a green build.

Get a key in under a minute. The free plan covers a small suite for good.

Get a free API key