Plain REST and JSON
Seven endpoints under https://noirsms.com/api/v1: balance, countries, services, numbers, and cancel, resend and finish for a number.
If you already use Noir SMS in the browser, the API is the same service without the clicking: one API key, the balance you already have, and JSON back with the number, its status and every SMS it received. This page is the developer overview; the field-by-field reference lives at /api/docs/. As with the dashboard, the API is for verifying your own legitimate accounts, or your customers' accounts if you resell under the same rules.
The Noir SMS API is a REST API (v1) at https://noirsms.com/api/v1 that does from code what the dashboard does by hand: you call POST /numbers with a service and a country, put the returned phone number into the app you are verifying, then read the code with GET /numbers/{id} or receive it through a signed sms.received webhook. It uses the same prices and balance as the dashboard with no extra fee, allows 120 requests per minute per key, and refunds the number automatically if no SMS arrives within 20 minutes. Full reference: https://noirsms.com/api/docs/.
Seven endpoints under https://noirsms.com/api/v1: balance, countries, services, numbers, and cancel, resend and finish for a number.
Generate a key on the API page of your dashboard. Purchases use your normal balance at the same prices, with no API fee.
Poll GET /numbers/{id} every 3 to 5 seconds, or set an HTTPS webhook and receive sms.received, signed with HMAC-SHA256.
No SMS in 20 minutes means status expired and an automatic refund. You can also cancel 2 minutes after buying.
Log in, open the API page of your dashboard and generate a key. Keys start with nsk_live_ and are shown only once, so store yours in a secret manager or environment variable. Each account has one key; regenerating it disables the old one immediately, which is how you rotate a leaked key.
Send the key on every request, either as Authorization: Bearer nsk_live_YOUR_KEY or in an X-API-Key header. Request and response bodies are JSON, prices are in US dollars and times are ISO 8601 in UTC. Call the API from your server only: a key in a web page or mobile app can be extracted and spend your balance.
First, look up what you can buy. GET /countries lists countries with numbers in stock right now, and GET /services?country=us returns each service code (wa for WhatsApp, tg for Telegram, go for Google, and so on) with the price you pay and the stock. Prices can change during the day, so read them at runtime.
Then buy with POST /numbers, sending service, country and optionally max_price. If the current price is above max_price, the purchase is refused with HTTP 409 and nothing is charged. A successful purchase answers 201 with the number object:
curl -X POST https://noirsms.com/api/v1/numbers \
-H "Authorization: Bearer nsk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"service": "wa", "country": "us", "max_price": 1.50}'Polling is the simplest option: call GET /numbers/{id} every 3 to 5 seconds until the status changes. Mind the limit of 120 requests per minute per key: at one request every 4 seconds, each open number uses about 15 requests a minute.
A webhook scales better. Set an HTTPS URL on the API page of your dashboard and Noir SMS sends a POST with type sms.received as soon as it detects an SMS on a number bought through the API. Every delivery carries an X-NoirSMS-Signature header with a timestamp t and a v1 signature, the hex HMAC-SHA256 of the timestamp, a dot and the raw body, keyed with your webhook secret. Verify it, reject timestamps older than 5 minutes, and answer with any 2xx status. Many integrations use the webhook for speed and an occasional poll as a safety net.
Errors come with an HTTP status and a JSON body like {"error": {"code": "...", "message": "..."}}. Switch on code, not on the message text.
This script buys a US number for WhatsApp, prints it, polls until the code arrives, marks the number as finished and returns the code. If the number expires or is canceled, it returns null and the balance has already been refunded. POST /numbers/{id}/finish is optional, but it releases the number sooner. POST /numbers/{id}/resend asks for a second code on an open number at no cost.
// Node.js 18+ (built-in fetch). Run it on your server, never in a browser.
const BASE = 'https://noirsms.com/api/v1';
const headers = { Authorization: 'Bearer nsk_live_YOUR_KEY', 'Content-Type': 'application/json' };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function getCode(service, country) {
const res = await fetch(BASE + '/numbers', { method: 'POST', headers, body: JSON.stringify({ service, country }) });
const num = await res.json();
if (!res.ok) throw new Error(num.error.code); // e.g. insufficient_balance, no_numbers
console.log('Enter this number in the app:', num.phone);
while (true) {
await sleep(4000); // poll every 3 to 5 seconds
const n = await (await fetch(BASE + '/numbers/' + num.id, { headers })).json();
if (n.status === 'received') {
await fetch(BASE + '/numbers/' + num.id + '/finish', { method: 'POST', headers });
return n.sms[0].code;
}
if (n.status === 'expired' || n.status === 'canceled') return null; // refunded
}
}
getCode('wa', 'us').then((code) => console.log('Code:', code));
No. GET endpoints such as /balance, /countries and /services are free to call. A purchase uses real balance, but it is refunded automatically if no SMS arrives, and you can cancel it 2 minutes after buying.
No. Each number costs the same as in the dashboard and is paid from the same balance. There is no subscription and no API fee.
No. You choose the service and the country; the number within that country is assigned from available stock.
Any language that can send HTTPS requests with JSON. The docs at /api/docs/ show curl, and Node.js and Python examples for webhook signatures.
Verifying your own legitimate accounts, testing your own app's SMS flows, and reselling to customers who follow the same Acceptable Use Policy. Bulk account creation, spam, ban evasion and bypassing bank or KYC checks are prohibited.
What an OTP code is, how one-time passwords are generated and sent, how long they last, and why you should never share one with anyone.
Read the guide →Getting startedHow Noir SMS refunds work: automatic refund after 20 minutes with no SMS, manual cancel after 2 minutes, and credit back to your balance.
Read the guide →Getting startedNeed a second code on the same number? How resend works, Noir SMS's free extra SMS while the number is active, and the time window to use it.
Read the guide →TroubleshootingMost SMS codes arrive in seconds. Learn normal delivery times, when to resend, how long to wait before giving up, and what slows codes down.
Read the guide →Offer SMS verification in your own panel, app or bot at your own prices. One balance, signed webhooks, and clear rules for your customers.
Read more →API for your own systemUse the Noir SMS API in internal tools, QA of your OTP sign-up flow, CI pipelines and delivery monitoring, in the US, Canada, UK and more.
Read more →What you can buildLegitimate things to build with the Noir SMS API: verification bots, team number tools, OTP localization tests, privacy layers, and what is not allowed.
Read more →WhatsApp bulk messaging, the allowed wayUnsolicited WhatsApp bulk messages get numbers banned. Learn the allowed options: broadcast lists to opted-in contacts and Meta's official Cloud API.
Read more →Create a free account, add funds and generate your API key on the API page of your dashboard.
Use the Noir SMS API only for your own legitimate accounts or, as a reseller, for customers who follow the same Acceptable Use Policy. Bulk or automated account creation, spam, ban evasion and bypassing bank, fintech or identity checks are prohibited and lead to account closure.