Public & Account API
Integrate virtual phone numbers for SMS reception directly into your software. For the reseller-specific API (sub-users, markup, payouts), see the Reseller API Reference.
1Authentication
Endpoints that act on your account (buying a number, checking usage) require an API key from Developer → API Keys, passed as a Bearer token:
Authorization: Bearer notp_1234567890abcdef
/v1/public/* endpoints (prices, services, countries) need no authentication at all.
https://api.numberotp.com/v1 or https://numberotp.com/v1 — both work identically, the api. subdomain just skips the marketing site.2Public Endpoints (No Auth)
/v1/public/servicesList all available services (WhatsApp, Telegram, etc). Optional ?country= to filter.
/v1/public/countriesList all available countries. Optional ?service= to only show countries supporting a specific service.
/v1/public/pricesReal-time pricing and availability for all services and countries. Optional ?service= and ?country= filters. Cached ~5 minutes.
3Activations & Rentals
/v1/activationsProvision a virtual phone number for SMS reception. Body: { service, country, pool?, max_price? } — pool 'auto' (default) picks the pool with the best measured delivery rate and switches automatically if it can't supply a number; max_price caps what you'll pay. Returns the phone number and activation id. Balance is deducted instantly.
/v1/activations/{id}Poll the status of an activation and its OTP, once received.
/v1/activations/{id}/waitLong-polling — this connection hangs open (up to 55s) and returns the instant the OTP arrives, instead of you polling in a loop.
/v1/rentalsRent a number for longer-term use (hours/days) rather than a single OTP.
Every response includes X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Reset headers where a limit applies. A 429 means you've hit it.
4Zero-Latency Webhooks
For the fastest possible OTP delivery, set a Global Webhook. When an SMS arrives for your active number, it's POSTed to your URL instantly — no polling needed.
Setup
Set your webhook URL and secret in Developer → Global Webhook.
Payload
{
"id": "act_8f7d98x",
"phone_number": "14155552671",
"service": "wa",
"country": "67",
"otp": "482910",
"full_sms": "Your WhatsApp code is 482910.",
"status": "received"
}Signature verification (HMAC-SHA256)
Every request includes a signature over the raw JSON body, keyed with your webhook secret:
x-numberotp-signature: sha256=10f4be...
const crypto = require('crypto');
function verifyWebhook(reqBody, signatureHeader, secret) {
const hash = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(reqBody))
.digest('hex');
const expectedSignature = `sha256=${hash}`;
return crypto.timingSafeEqual(
Buffer.from(signatureHeader),
Buffer.from(expectedSignature)
);
}