Testing OTP and SMS sign-up flows in staging
Quick answer
To test that your own app's SMS codes really arrive, buy a temporary number from the Noir SMS API inside your end-to-end test, type it into your staging sign-up form, and read the code back with GET /api/v1/numbers/{id}. Run these tests before releases rather than on every commit, and use your SMS provider's test numbers for unit tests. Numbers that never receive an SMS are refunded automatically.
Unit tests with mocked SMS prove your code calls the provider. They don't prove a user in another country gets the text. A few real-number tests close that gap.
A Playwright example
This test uses the "Any other" service. Look up its code with GET /services for your country.
// Playwright end-to-end test for your own sign-up page
import { test, expect } from '@playwright/test';
const API = 'https://noirsms.com/api/v1';
const H = { Authorization: `Bearer ${process.env.NOIRSMS_KEY}`, 'Content-Type': 'application/json' };
test('sign-up sends a working SMS code', async ({ page }) => {
const n = await (await fetch(`${API}/numbers`, {
method: 'POST', headers: H, body: JSON.stringify({ service: 'ot', country: 'us' }),
})).json();
await page.goto(process.env.STAGING_URL + '/signup');
await page.fill('#phone', '+' + n.phone);
await page.click('text=Send code');
let code;
await expect.poll(async () => {
const s = await (await fetch(`${API}/numbers/${n.id}`, { headers: H })).json();
code = s.sms[0]?.code;
return code;
}, { timeout: 180_000, intervals: [4000] }).toBeTruthy();
await page.fill('#code', code);
await page.click('text=Verify');
await expect(page.locator('text=Welcome')).toBeVisible();
});What to cover
- Each country you launch in.
- Resend and expiry: request a second code with POST /numbers/{id}/resend.
- Message text, sender ID and length.
Keep it cheap and stable
- Run real-number tests nightly or before releases.
- Set a timeout and cancel the number after 2 minutes if your app never sent a message.
- Respect the 120 requests per minute limit when tests run in parallel.
Scope
Use this only to test apps you own or are authorized to test.
Frequently asked questions
Is there a test mode?
No separate sandbox. GET endpoints are free to call, and purchases without an SMS are refunded.
Can I test voice OTP?
No. Noir SMS numbers receive SMS only.
Services in this guide
Keep reading
Using virtual numbers to test SMS flows
How QA teams use real virtual numbers to test SMS sign-up and OTP flows end to end, when to use them vs test numbers, and how to automate with an API.
Read the guide →DevelopersAutomate receiving SMS codes: polling or webhooks
Two ways to receive SMS verification codes automatically with the Noir SMS API: polling GET /numbers/{id} or a signed sms.received webhook. Code included.
Read the guide →DevelopersReceive SMS verification codes with Node.js
Buy a temporary number and read SMS verification codes from Node.js with fetch and the Noir SMS REST API. Complete example with error handling.
Read the guide →DevelopersReceive SMS verification codes with Python
Buy a temporary number and read the SMS verification code from Python with the Noir SMS REST API. Full example with requests, polling and errors.
Read the guide →DevelopersReceive SMS verification codes with PHP
Use PHP and cURL to buy a temporary number and read the SMS verification code with the Noir SMS API. Copy-paste example for panels and scripts.
Read the guide →DevelopersCommon Noir SMS API errors and how to handle them
Every Noir SMS API error code explained: invalid_api_key, insufficient_balance, no_numbers, too_early, rate_limited and more, with a retry pattern.
Read the guide →