# How to test an OTP flow without real phone numbers

Source: https://tempsmsverify.com/blog/sms-verification-for-qa-testing · Last updated: 2026-10-25

Every product with phone sign-up eventually hits the same QA problem: the test suite needs a number that receives a code, and nobody wants to hand over their personal phone to a CI pipeline. The answer is layered. Most of your tests should never send an SMS at all; a smaller set should exercise your provider's sandbox; and a thin end-to-end layer should prove that a real message reaches a real carrier line. This guide covers each layer, where temporary numbers from TempSMSVerify fit, how to drive them through our API, and the lines you should not cross.

## How do you test an OTP flow without real phone numbers?

Use three layers. Mock the SMS provider in unit tests. Use your provider's test numbers, such as Firebase fictional numbers or Twilio magic numbers, for integration tests, since no SMS is sent. For end-to-end checks of real delivery, buy temporary numbers through an API like TempSMSVerify's, paid only when the code arrives, for apps you own or may test.

## Steps

1. **Mock the provider in unit tests.** Wrap your SMS provider behind an interface and inject a fake that records the code. Test code generation, expiry, attempt limits and lockouts here, with no network.
2. **Configure sandbox test numbers.** Add fictional numbers in your auth provider (Firebase allows up to 10) or use test credentials with magic numbers (Twilio) for integration tests that exercise the real API shape.
3. **Get a TempSMSVerify API key.** Top up at least $5, open the API section of the dashboard and generate a key. Store it as a CI secret; it can spend your balance.
4. **Buy a number for your own service.** Call POST /api/v1/orders with the product and country. The price is frozen and the number is reserved for up to 20 minutes.
5. **Trigger the SMS and poll for the code.** Have your test enter the number in your sign-up flow, then poll GET /api/v1/orders/{id} every 3 to 5 seconds until the code appears.
6. **Finish or cancel.** Submit the code, assert the result, then finish the order. If no SMS arrived, cancel after about 2 minutes; the frozen amount returns automatically.

## Which tests actually need a real SMS?

Fewer than you think. What breaks most often, code length, expiry, retry timers, attempt caps, lockout after too many wrong codes, normalization of the number to E.164, lives entirely in your own code and can be tested with a fake provider. Real SMS adds cost, flakiness and minutes of wall time, so it belongs only where the question is 'does the message really arrive?'.

That question is still worth asking. Sender registration, carrier filtering, short-code reach, international routing and template changes all fail silently, and none of them show up in a mocked test. A few real-delivery checks per release catch them before users do.

| Layer | What it proves | Tooling | Real SMS sent? |
| --- | --- | --- | --- |
| Unit | Code generation, expiry, attempt limits, lockout, number formatting | Fake provider injected in your code | No |
| Integration (sandbox) | Your calls match the provider's API, errors are handled | Firebase fictional numbers; Twilio test credentials and magic numbers | No |
| End-to-end (real delivery) | The message leaves your provider and reaches a carrier line in a given country | Temporary numbers bought through the TempSMSVerify API | Yes |
| Monitoring (canary) | Delivery still works today in your key countries | A scheduled end-to-end job per country | Yes |

## What do provider sandboxes give you?

Firebase Authentication lets you register fictional test numbers with fixed codes. Its documentation (checked October 2026) says 'you can add up to 10 phone numbers for development', that they let you test 'without sending an actual SMS message' and 'without consuming your usage quota', and that you can 'run consecutive tests with the same phone number without getting throttled'. Firebase also insists the numbers be fictional; it does not allow existing numbers used by real users as test numbers, and recommends 555-style examples.

Twilio offers test credentials. Per its docs, when you authenticate with them 'Twilio doesn't charge your account, update the state of your account, or connect to real phone numbers'. Magic numbers simulate outcomes: +15005550006 passes validation, +15005550001 returns 'phone number is invalid' (error 21212) and +15005550002 returns 'Twilio can't route to this number' (error 21612). That is ideal for testing your error handling, and useless for testing delivery, because nothing is delivered.

App review has the same need. Apple's Review Guideline 2.1 asks for 'demo account info' when an app has a login, and Google Play's sign-in form asks about logins 'using a one-time password, multi-factor authentication'. Give reviewers a demo account on a fixed test number; a temporary number will not receive their code a week later.

## How do you automate real delivery with the TempSMSVerify API?

The REST API lives at https://tempsmsverify.com/api/v1 and takes an API key in the X-Api-Key header. A test run is four calls. POST /api/v1/orders with a body such as {"product": "telegram", "country": "usa"} buys a number and returns the order with the phone number. Your test enters it in the sign-up flow under test. GET /api/v1/orders/{id}, polled every 3 to 5 seconds, returns the SMS when it reaches the line. Then POST /api/v1/orders/{id}/finish closes the order, or /cancel releases it if nothing arrived.

If your test needs a second code, for example to check that your resend path invalidates the first one, POST /api/v1/orders/{id}/resend asks for another SMS on the same number at no extra cost, accepted only after the first code has arrived. SMS-Activate-style tools can use /api/stubs/handler_api.php instead. The full reference, including error codes, is on /api-docs.

Billing works in your favor for flaky tests: the price is frozen on purchase and charged only when an SMS arrives. A run where your sender failed costs nothing, and the balance never expires, so a small top-up covers a long series of canaries.

| Call | Purpose | Notes |
| --- | --- | --- |
| GET /api/v1/services/{product}/countries | Find countries with stock for a service | Returns price, stock and dial code per country |
| POST /api/v1/orders | Buy a number | 402 no balance, 409 no numbers, 429 over 500 purchases per minute |
| GET /api/v1/orders/{id} | Poll for the SMS | Poll every 3 to 5 seconds |
| POST /api/v1/orders/{id}/resend | Second code on the same number | Only after the first code; no extra charge |
| POST /api/v1/orders/{id}/finish or /cancel | Close the order | Cancel unlocks after about 2 minutes; refund is automatic |

## Which rate limits matter in testing?

Two sets: ours and yours. Our purchases are capped at 500 per minute per account, and per IP on REST; the API answers 429 when you exceed it, and the SMS-Activate endpoint answers NO_NUMBERS. Resend requests are limited to 30 per minute. Parallel CI jobs sharing one key can hit it, so back off on 429.

The limits that bite more often are in the app under test. If your own anti-abuse rules cap codes per number, per device or per IP, your end-to-end tests will trip them; whitelist the CI runner's IP in a staging environment rather than disabling protection in production. And remember that the defenses Twilio recommends against SMS pumping, rate limits, bot detection, geographic permissions and carrier lookups that send 'only to mobile numbers', may refuse the temporary number itself. That is a useful test result: it tells you what your real users with unusual numbers experience.

## What are the ethical and legal limits?

Test what you own or are authorized to test. Running a real-delivery check against your company's own sign-up flow, or a client's flow under a testing agreement, is exactly the use our /acceptable-use policy lists as allowed. Pointing the same script at a third-party app to create accounts, probe its verification, or measure its defenses without permission is not testing; it can break that app's terms and, depending on what the script does, the law.

- Never put real people's numbers, colleagues' included, in test fixtures; fixtures leak.
- Label test accounts, delete them afterwards and keep them out of metrics and promotions.
- Do not use temporary numbers to farm sign-up bonuses or referral credit in your own product's production environment.
- Treat the API key like a password: store it as a secret, rotate it if a log leaks it, and never share it between teams.

## FAQ

### Can I test SMS verification without sending real messages?

Yes, for most tests. Mock the SMS provider in unit tests and use your provider's sandbox for integration tests: Firebase fictional phone numbers send no SMS and consume no quota, and Twilio test credentials with magic numbers simulate success and failure without connecting to real phones. Real messages are only needed to prove delivery.

### How many test phone numbers does Firebase allow?

Firebase Authentication's documentation says you can add up to 10 phone numbers for development, each with a fixed verification code. They must be fictional; Firebase does not allow existing numbers used by real users. Test numbers skip SMS delivery and quota, so they suit integration tests but not delivery checks.

### What are Twilio magic numbers?

Special numbers that work only with Twilio test credentials and return a fixed result. Per Twilio's docs, +15005550006 passes validation, +15005550001 returns an invalid-number error (21212) and +15005550002 a cannot-route error (21612). Nothing is sent and nothing is charged, which makes them good for testing your error handling.

### How do I get an API key for TempSMSVerify?

Top up at least $5 with Card via Stripe (Visa, Mastercard, Amex, Apple Pay, Google Pay); Crypto (USDC or SOL on Solana), then open the API section of your dashboard and generate a key. The full key is shown once; we store only a hash. Send it in the X-Api-Key header. Each account has one active key, and generating a new one revokes the old key immediately.

### Do I pay for test runs where the SMS never arrives?

No. Buying a number freezes its price, and the charge happens only when an SMS reaches the line. If your sender fails, cancel after about 2 minutes or let the number expire after up to 20 minutes, and the full amount returns to your balance automatically. That means a failed canary run costs nothing.

### Can I use temporary numbers in a CI pipeline?

Yes, for a thin real-delivery layer. Store the API key as a CI secret, buy one number per run, poll the order every 3 to 5 seconds, and finish or cancel it at the end. Serialize purchases across parallel jobs or back off on HTTP 429, since purchases are capped at 500 per minute per account.

### Is it legal to test another company's OTP flow?

Only with permission. Testing your own product, or a client's under a written agreement, is normal QA. Automating sign-ups or probing verification on a third-party service without authorization can breach its terms and, depending on what you do, the law. Our /acceptable-use policy prohibits probing or creating accounts in bulk on services you do not own.

---
TempSMSVerify · https://tempsmsverify.com
