API for developers

The Noir SMS API for developers: buy a number, read the SMS code, from your own code

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.

Português →

  • Same prices as the dashboard
  • Refund if no SMS
  • Signed webhooks

Quick answer

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/.

Highlights

01

Plain REST and JSON

Seven endpoints under https://noirsms.com/api/v1: balance, countries, services, numbers, and cancel, resend and finish for a number.

02

One key, your balance

Generate a key on the API page of your dashboard. Purchases use your normal balance at the same prices, with no API fee.

03

Poll or get pushed

Poll GET /numbers/{id} every 3 to 5 seconds, or set an HTTPS webhook and receive sms.received, signed with HMAC-SHA256.

04

Refunds built in

No SMS in 20 minutes means status expired and an automatic refund. You can also cancel 2 minutes after buying.

Authentication and base URL

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.

The purchase flow, step by step

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:

  • waiting: the number is reserved for you until expires_at, 20 minutes after purchase. Enter phone in the app.
  • received: at least one SMS arrived. The code is in sms[].code and the full text in sms[].text.
  • canceled: you called POST /numbers/{id}/cancel after cancelable_at (2 minutes after buying) and the price went back to your balance.
  • expired: no SMS in 20 minutes; the price was refunded automatically.
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 or webhook: which one to use

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 you should handle

Errors come with an HTTP status and a JSON body like {"error": {"code": "...", "message": "..."}}. Switch on code, not on the message text.

  • 401 invalid_api_key: missing, wrong or revoked key.
  • 402 insufficient_balance: top up; needed holds the price.
  • 409 price_above_max: the current price is above your max_price.
  • 400 no_numbers: no stock for that service and country right now; you were not charged.
  • 400 too_early or already_closed: cancel came before cancelable_at, or the number is already closed.
  • 429 rate_limited: more than 120 requests in a minute; wait a few seconds and retry.
  • 502 or 503 provider_error or restocking: temporary; you were not charged.

A complete minimal example in Node.js

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));

Step by step

  1. Create a keyOpen the API page of your dashboard, generate an API key, store it on your server and add funds to your balance.
  2. Buy and waitCall POST /numbers with a service and a country, then poll GET /numbers/{id} or listen for the sms.received webhook.
  3. Use and closeRead sms[].code, enter it in the app, then call finish. Numbers without an SMS are refunded automatically.

Frequently asked questions

Is there a sandbox or test mode?

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.

Does the API cost more than the dashboard?

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.

Can I choose an area code?

No. You choose the service and the country; the number within that country is assigned from available stock.

Which languages are supported?

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.

What can I use the API for?

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.

Related services

Related guides

More solutions

Start building with the Noir SMS API

Create a free account, add funds and generate your API key on the API page of your dashboard.