Reseller API
Rent virtual numbers, receive SMS, and get real-time webhooks — all over a simple REST API. Resell our 100+ country catalog through your own app.
API Features
Instant Rentals
Numbers provisioned in under a second.
100+ Countries
Full catalog across multiple servers.
Signed Webhooks
HMAC-SHA256 signatures on every event.
Real-time Events
sms.received, rental.expired, rental.cancelled.
Quickstart
- Sign in and visit API Keys to generate a key.
- Top up your wallet — every API rental charges your account balance.
- Send requests to
https://rentalnumbers.com/functions/<endpoint>with headerAuthorization: Bearer <your_key>. - Optionally register a webhook to receive real-time SMS events.
// Node.js — full reseller flow
// All endpoints go to /resellerApi with an "endpoint" field in the body.
const API = 'https://rentalnumbers.com/functions/resellerApi';
const KEY = process.env.RENTALNUMBERS_API_KEY;
const headers = { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' };
const call = (endpoint, params = {}) =>
fetch(API, { method: 'POST', headers, body: JSON.stringify({ endpoint, ...params }) })
.then(r => r.json());
// 1. Check balance
const bal = await call('getBalance');
console.log('Balance:', bal.balance);
// 2. Rent a US WhatsApp number
const rental = await call('rentNumber', { country: 'United States', service: 'WhatsApp', server: 1 });
console.log('Number:', rental.phone_number);
// 3. Poll for SMS (or use webhooks — see below)
let sms = null;
for (let i = 0; i < 30 && !sms; i++) {
await new Promise(r => setTimeout(r, 5000));
const res = await call('getSMS', { rental_id: rental.rental_id });
if (res.sms_messages?.length) sms = res.sms_messages[0];
}
console.log('SMS:', sms);Authentication
All endpoints (except apiCreateKey / apiListKeys / apiRevokeKey which use your session) authenticate via a Bearer token in the Authorization header.
Authorization: Bearer rk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Keys are stored as SHA-256 hashes — we cannot recover them. Lost a key? Revoke it and create a new one.
Endpoints
Base URL: https://rentalnumbers.com/functions
Server-14 is available for Walmart in Canada. Use server: 14 with checkPrice or rentNumber.
https://rentalnumbers.com/functions/apiCreateKeyGenerate a new API key. Returns the key once — store it securely.
{
"name": "Production server"
}{
"success": true,
"api_key": "rk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"id": "abc123",
"key_prefix": "rk_live_xxxxxxxx"
}https://rentalnumbers.com/functions/apiGetBalanceReturns the reseller wallet balance in USD.
{
"success": true,
"balance": 42.5,
"currency": "USD",
"email": "reseller@example.com"
}https://rentalnumbers.com/functions/resellerApiCheck live price + availability. Set endpoint="checkPrice".
{
"endpoint": "checkPrice",
"country": "United States",
"service": "WhatsApp",
"server": 1
}{
"success": true,
"country": "United States",
"service": "WhatsApp",
"server": 1,
"price": 0.45,
"stock": 124
}https://rentalnumbers.com/functions/resellerApiRent a virtual number. Set endpoint="rentNumber". Charges your wallet at the displayed price.
{
"endpoint": "rentNumber",
"country": "United States",
"service": "WhatsApp",
"server": 1
}{
"success": true,
"rental_id": "rent_abc123",
"phone_number": "+15551234567",
"service": "WhatsApp",
"country": "United States",
"server": 1,
"expires_at": "2026-05-01T14:00:00Z",
"price": 0.45
}https://rentalnumbers.com/functions/resellerApiFetch SMS messages received on a rented number. Set endpoint="getSMS". Poll every 5–10 seconds, or use webhooks.
{
"endpoint": "getSMS",
"rental_id": "rent_abc123"
}{
"success": true,
"rental_id": "rent_abc123",
"phone_number": "+15551234567",
"status": "active",
"sms_messages": [
{
"from": "WhatsApp",
"text": "Your code is 123-456",
"received_at": "2026-05-01T13:31:00Z"
}
]
}https://rentalnumbers.com/functions/resellerApiCancel an active rental. Set endpoint="cancelRental". Refunds wallet if eligible (no SMS received yet).
{
"endpoint": "cancelRental",
"rental_id": "rent_abc123"
}{
"success": true,
"rental_id": "rent_abc123",
"status": "cancelled",
"refunded": true,
"refund_amount": 0.45
}https://rentalnumbers.com/functions/resellerApiRegister an HTTPS webhook URL. Set endpoint="setWebhook". Returns a signing secret used to verify HMAC-SHA256 signatures.
{
"endpoint": "setWebhook",
"webhook_url": "https://your-server.com/rentalnumbers-webhook",
"events": [
"sms.received",
"rental.expired"
]
}{
"success": true,
"webhook_url": "https://...",
"events": [
"sms.received"
],
"secret": "whsec_xxxxxxxxxxxx"
}https://rentalnumbers.com/functions/resellerApiList all valid country names. Set endpoint="listCountries".
{
"endpoint": "listCountries"
}{
"success": true,
"count": 100,
"countries": [
"Argentina",
"Australia",
"Brazil",
"Canada",
"..."
]
}https://rentalnumbers.com/functions/resellerApiList the popular service names accepted by the API. Set endpoint="listServices". Names are case-insensitive.
{
"endpoint": "listServices"
}{
"success": true,
"count": 90,
"services": [
"WhatsApp",
"Telegram",
"Google",
"Facebook",
"..."
]
}Country & service names
checkPrice and rentNumber accept human-readable names for country and service — no need to memorize any codes. Just use the full name as shown by listServices.
- Use
listCountriesto fetch all valid country names per server. - Use
listServicesto fetch the popular service catalog. - Names are case-insensitive (e.g.
"whatsapp"="WhatsApp"). - Use full country names:
"United States"(not "USA"),"United Kingdom"(not "UK"). - If a service isn't available on a given server/country,
checkPricereturnsavailable: 0— try another server.
⚠️ Always use full service names
Always pass the full human-readable service name (e.g. "Walmart", "WhatsApp"). Short codes or abbreviations like "wr" or "wa" are not accepted and will result in "No numbers available" errors. When in doubt, call listServices first to get the exact accepted strings.
Recommended flow
const API = 'https://rentalnumbers.com/functions/resellerApi';
const call = (endpoint, params = {}) =>
fetch(API, { method: 'POST', headers, body: JSON.stringify({ endpoint, ...params }) })
.then(r => r.json());
// 1. Fetch valid countries for the server you want
const { countries } = await call('listCountries', { server: 3 });
// 2. Fetch service catalog
const { services } = await call('listServices', { server: 3, country: 'United Kingdom' });
// 3. Confirm price + availability before renting
const price = await call('checkPrice', { country: 'United Kingdom', service: 'WhatsApp', server: 3 });
// → { success: true, price: 0.45, available: 124 }Webhooks
Register your HTTPS endpoint via apiSetWebhook. We'll POST signed JSON payloads when these events fire:
sms.received— a new SMS landed on a rented numberrental.expired— a rental's time window endedrental.cancelled— a rental was cancelled (refunded if eligible)
Headers we send
X-RentalNumbers-Event: sms.received X-RentalNumbers-Signature: sha256=<hex> Content-Type: application/json
Verifying signatures
Compute HMAC-SHA256 of the raw request body using your signing secret, then compare against the signature header.
// Node.js — verify incoming webhook
const crypto = require('crypto');
const SECRET = process.env.RENTALNUMBERS_WEBHOOK_SECRET; // whsec_...
app.post('/rentalnumbers-webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.header('X-RentalNumbers-Signature') || '';
const expected = 'sha256=' + crypto.createHmac('sha256', SECRET)
.update(req.body).digest('hex');
if (sig !== expected) return res.status(401).send('bad signature');
const event = JSON.parse(req.body.toString());
// event.event = "sms.received" | "rental.expired" | "rental.cancelled"
// event.data = { rental_id, phone_number, sms?, ... }
console.log('Webhook:', event.event, event.data);
res.sendStatus(200);
});SMS delivery latency
How fast you receive an SMS depends on two things: how the underlying network delivers it to us, and how you fetch it from us.
How we receive SMS
| Server | Latency |
|---|---|
| Server-1 | ~1–3 s |
| Server-2 | ~1–3 s |
| Server-3 | ~1–3 s |
| Server-4 | ~1–3 s |
| Server-5 | ~1–3 s |
| Server-6 | ~1–3 s |
You can call getSMS as often as you want (up to your key rate limit), or register a webhook for push delivery.
Webhooks vs polling — pick one
Webhooks (recommended)
- Fastest: ~1–2 s from delivery to your endpoint
- Zero polling load on your server
- Won't burn your rate limit
- Signed with HMAC-SHA256
Polling getSMS
- Poll every 10–15 s for a good balance
- Do not poll faster than 5 s — wasteful, hits rate limit
- Default rate limit: 60 req/min per key
- Use exponential backoff once you receive the SMS
Bottom line: if you're building production, register a webhook via setWebhook for the lowest latency. Polling is fine for quick scripts and prototypes.
Error responses
| Status | Meaning |
|---|---|
| 400 | Bad request — missing/invalid parameters |
| 401 | Missing, invalid, or revoked API key |
| 403 | Resource doesn't belong to your account |
| 404 | Resource not found |
| 429 | Rate limit exceeded (default: 60 req/min) |
| 500 | Server error — retry with backoff |
All error responses follow the shape { "error": "message" }.
"Did you mean?" suggestions
When you pass a service or country value that doesn't match any known name, the API attempts a fuzzy match and returns a suggestion so you can self-correct:
// You sent: { endpoint: "checkPrice", service: "wr", server: 1, country: "United States" }
// Response (400):
{
"error": "Service 'wr' not found on Server-1.",
"suggestion": "Did you mean 'Walmart'? Use listServices to fetch all accepted names."
}Ready to integrate?
Generate your first key and start reselling our numbers in minutes.