REST API / VERSION 1

Build verification
into your product.

01 / OVERVIEW

Rent numbers, check live pricing and retrieve SMS codes through a compact JSON API.

JSONHTTPSREST
02

GETTING STARTED

Authentication

Include your API key in the X-API-KEY header on every authenticated request. Keep keys server-side and never expose them in browser code.

BASE URLhttps://rentnumber.net/api/v1
curl -H "X-API-KEY: rn_your_key_here" \
  https://rentnumber.net/api/v1/balance

Endpoints marked no authentication required can be called without a key.

03

WALLET

GET /balance

Return the current wallet balance. Authentication is required.

{
  "success": true,
  "balance": 5000,
  "currency": "NGN"
}

balance is a JSON number, so a whole amount has no decimal part. Do not rely on two decimal places being present.

04

DIRECTORY

GET /services

List all available services. No authentication required.

{
  "success": true,
  "data": [{
    "id": 1,
    "slug": "whatsapp",
    "name": "WhatsApp",
    "icon": "assets/img/services/whatsapp.svg",
    "provider_count": 3,
    "min_price": "241.96"
  }]
}

icon is a path relative to the site root, or null. min_price is the lowest price across providers, returned as a decimal string — see number formats.

05

DIRECTORY

GET /countries

List supported countries and their identifiers. No authentication required.

{
  "success": true,
  "data": [
    { "id": 1, "iso_code": "NG", "name": "Nigeria", "flag": "🇳🇬" }
  ]
}
06

LIVE AVAILABILITY

GET /services/{slug}/prices

Get live pricing options for a service. Filter by country using the optional ?country_id= query.

GET /api/v1/services/whatsapp/prices?country_id=1
PARAMETERTYPEDESCRIPTION
slugstringService slug, such as whatsapp
country_idintegerOptional country filter
{
  "success": true,
  "service": { "id": 1, "slug": "whatsapp", "name": "WhatsApp" },
  "data": [{
    "id": 42,
    "final_price": "450.00",
    "stock": 120,
    "rental_type": "short",
    "provider_id": 3,
    "provider_name": "Premium",
    "country_id": 1,
    "country_name": "Nigeria",
    "iso_code": "NG",
    "flag": "🇳🇬"
  }]
}

Pass data[].id as pricing_id to POST /rent. stock may be null when a provider does not report inventory, and rental_type is short, long or both.

07

CREATE RENTAL

POST /rent

Rent a number using a pricing option returned by the prices endpoint. Authentication is required.

PARAMETERTYPEDESCRIPTION
pricing_idintegerID from data[].id in the prices response
curl -X POST -H "X-API-KEY: rn_your_key" \
  -d "pricing_id=42" \
  https://rentnumber.net/api/v1/rent
{
  "success": true,
  "rental_id": 101,
  "phone": "+2348012345678",
  "cost": 450,
  "status": "waiting",
  "expires_at": "2026-04-12T15:30:00Z"
}
08

RETRIEVE SMS

GET /rental/{id}

Check rental status and retrieve the SMS code. This endpoint polls the provider, so call it while you wait rather than re-renting.

{
  "success": true,
  "rental_id": 101,
  "phone": "+2348012345678",
  "status": "received",
  "code": "123456",
  "sms": "Your verification code is 123456",
  "cost": 450,
  "expires_at": "2026-04-12T15:30:00Z"
}

code and sms are null until a message arrives.

STATUS VALUESpendingwaitingreceivedcompletedcancelledexpiredrefunded
09

HISTORY

GET /rentals

List your most recent short-term rentals, newest first. Authentication is required.

{
  "success": true,
  "data": [{
    "rental_id": 101,
    "service": "WhatsApp",
    "country": "Nigeria",
    "provider": "Premium",
    "phone": "+2348012345678",
    "status": "completed",
    "cost": 450,
    "created_at": "2026-04-12 15:10:00"
  }]
}
10

END RENTAL

POST /rental/{id}/cancel

Cancel a rental that has not received an SMS. Eligible rentals are refunded to your wallet automatically.

curl -X POST -H "X-API-KEY: rn_your_key" \
  https://rentnumber.net/api/v1/rental/101/cancel
{
  "success": true,
  "status": "refunded",
  "refunded": true,
  "amount": 450
}
11

RELIABILITY

Errors & rate limits

HTTP status codes communicate the request result. Error responses include a JSON message suitable for logging.

200Success
400Bad request
401Unauthorized
404Not found
502Provider error

Every failure returns the same envelope, so one error path handles them all:

{
  "success": false,
  "error": "Invalid API key."
}

Check success rather than the message text — messages are meant for your logs and may change. Provider failures are sanitised before they reach you, so upstream vendor names never appear in an error.

Number formats
FIELDJSON TYPENOTE
balance, cost, amountnumberTrailing zeros are dropped — 450, not 450.00
final_price, min_pricestringDecimal string such as "450.00". Cast before doing arithmetic.
stockinteger or nullnull when the provider reports no inventory figure
12

ACCOUNTS

Account endpoints

These four need no API key — they are how a client obtains one. All accept either a JSON body or form-encoded fields.

POST /auth/register

PARAMETERTYPEDESCRIPTION
emailstringRequired, must be unique
usernamestringRequired, must be unique
passwordstringRequired
phonestringOptional
agree_termsbooleanRequired — must be true
{
  "success": true,
  "api_key": "rn_live_...",
  "user": {
    "id": 793,
    "username": "yourname",
    "email": "you@example.com",
    "phone": "08011112222",
    "wallet_balance": 0
  }
}

An API key is issued at registration — store it; this is the only response that returns a freshly generated one.

POST /auth/login

Takes email and password and returns the same envelope as register, including the account's existing api_key.

POST /auth/forgot-password

Takes email. Emails a 6-digit code valid for 15 minutes, rate-limited to one request every two minutes.

{
  "success": true,
  "message": "A 6-digit reset code has been sent to your email."
}

POST /auth/reset-password

Takes email, code and the new password. Returns { "success": true, "message": "Password updated successfully." }.

13

WALLET

Transactions & deposits

Both list endpoints page with ?limit= (1–100, default 50) and ?offset=, and report has_more so you know when to stop.

GET /transactions

{
  "success": true,
  "data": [{
    "id": 5001,
    "type": "debit",
    "amount": "450.00",
    "balance_after": "4550.00",
    "source": "rental",
    "description": "WhatsApp — Nigeria",
    "created_at": "2026-04-12 15:10:00"
  }],
  "limit": 50,
  "offset": 0,
  "has_more": false
}

GET /deposits

Same envelope plus the current wallet balance. Rows carry id, gateway, order_id, amount_ngn, amount_usd, status, paid_at and created_at.

GET /deposits/methods

Available funding gateways, plus the accepted range and the USD conversion rate. Authenticated like every other endpoint.

{
  "success": true,
  "data": [
    { "gateway": "cryptomus", "label": "Cryptocurrency",
      "description": "BTC, ETH, USDT, LTC and more", "currency": "USD" },
    { "gateway": "paymentpoint", "label": "Virtual bank account",
      "description": "Permanent NGN account \u2014 transfer to top up any time", "currency": "NGN" },
    { "gateway": "monnify", "label": "Monnify (card or bank)",
      "description": "Alternative NGN card or bank transfer", "currency": "NGN" }
  ],
  "min_ngn": 500,
  "max_ngn": 1000000,
  "usd_ngn_rate": 1450
}

Starting a deposit

Each gateway has its own endpoint, all authenticated and all taking amount_ngn: POST /deposits/cryptomus and POST /deposits/monnify create a pending deposit and return the gateway's checkout URL and reference. POST /deposits/paymentpoint/account takes no amount — it returns a permanent virtual bank account for the user, reusing the existing one when there is one ("reused": true).

14

LONG-TERM RENTALS

Keeping a number

A long-term rental holds the same number for days or months and receives unlimited incoming messages, rather than expiring after one code.

GET /long-term/services

Services available for long-term rental. No authentication required.

{
  "success": true,
  "data": [{
    "id": 1, "slug": "whatsapp", "name": "WhatsApp",
    "icon": "assets/img/services/whatsapp.svg",
    "option_count": 12, "from_price": "12000.00"
  }]
}

GET /long-term/services/{slug}/tiers

Durations and prices, grouped by provider and country. Each group's tiers[].id is the provider_service_id you rent with.

{
  "success": true,
  "service": { "id": 1, "slug": "whatsapp", "name": "WhatsApp" },
  "data": [{
    "provider_id": 3, "provider_name": "Premium",
    "country_id": 1, "country_name": "Nigeria",
    "iso_code": "NG", "flag": "🇳🇬",
    "tiers": [
      { "id": 9001, "duration_days": 30, "final_price": 12000 }
    ]
  }]
}

POST /long-term/rent

Takes provider_service_id (a tier id from above). Authentication required.

GET /long-term/rentals

Your long-term rentals: rental_id, service, country, provider, phone, status, cost, created_at and expires_at.

GET /long-term/rentals/{id}/poll

Fetch messages received on a long-term number. Returns the rental plus a messages array; poll this rather than re-renting.

POST /long-term/rentals/{id}/extend

Takes days. Charges the wallet for the extra period and pushes expires_at out.

15

EMAIL VERIFICATION

Temporary email addresses

Order a disposable email address scoped to a website, then poll it for the verification code or the full message it receives. You pass the website you are signing up to (a link is fine — the host is extracted for you) and pick one of the domains offered for it.

GET /email/domains

List the email domains available for a website, with live pricing and availability. Pass the site as a bare host or a full link in ?site=. Authentication is required.

GET /api/v1/email/domains?site=https://example.com/signup
{
  "success": true,
  "site": "example.com",
  "data": [
    { "domain": "gmail.com", "price": 120, "available": 253701 },
    { "domain": "outlook.com", "price": 95, "available": null }
  ]
}

price is the final price in NGN (a JSON number — see number formats). available is the provider's inventory count for that domain, or null when it does not report one; domains are ordered most-used first.

POST /email/order

Order a temporary address for a site and domain. The wallet is charged up front, and the order auto-expires and refunds if no message arrives within ~20 minutes. Requires a verified email account.

PARAMETERTYPEDESCRIPTION
sitestringThe website you are verifying against — a host or full link
domainstringA domain from the domains response, such as gmail.com
curl -X POST -H "X-API-KEY: rn_your_key" \
  -H "Content-Type: application/json" \
  -d '{"site":"example.com","domain":"gmail.com"}' \
  https://rentnumber.net/api/v1/email/order
{
  "success": true,
  "order_id": 501,
  "email": "quiet.harbor@gmail.com",
  "site": "example.com",
  "domain": "gmail.com",
  "status": "waiting",
  "cost": 120,
  "expires_at": "2026-04-12T15:30:00Z"
}

GET /email/orders/{id}

Poll one order for its status and, once received, the extracted code and the full message body. Call this while you wait rather than re-ordering.

{
  "success": true,
  "order_id": 501,
  "email": "quiet.harbor@gmail.com",
  "site": "example.com",
  "domain": "gmail.com",
  "status": "received",
  "code": "123456",
  "message": "Your verification code is 123456",
  "cost": 120,
  "created_at": "2026-04-12 15:10:00",
  "expires_at": "2026-04-12T15:30:00Z"
}

code and message are null until a message arrives.

STATUS VALUESwaitingreceivedcancelledexpiredrefunded

POST /email/orders/{id}/cancel

Cancel an order that has not received a message. The refund happens only when the provider actually accepts the cancellation — cancellation is refused in the first ~2 minutes, so an early call leaves the order live and unrefunded.

{
  "success": true,
  "refunded": true,
  "status": "refunded",
  "message": "Order cancelled and refunded.",
  "amount": 120
}

When the provider refuses, refunded is false, amount is 0 and status keeps the order's current value.

GET /email/orders

List your email orders, newest first. Authentication is required.

{
  "success": true,
  "data": [{
    "order_id": 501,
    "email": "quiet.harbor@gmail.com",
    "site": "example.com",
    "domain": "gmail.com",
    "status": "received",
    "code": "123456",
    "cost": 120,
    "created_at": "2026-04-12 15:10:00"
  }]
}
16

QUICK START

Code examples

const API_KEY = 'rn_your_key';
const BASE = 'https://rentnumber.net/api/v1';

const response = await fetch(`${BASE}/balance`, {
  headers: { 'X-API-KEY': API_KEY }
});
const data = await response.json();
console.log(data.balance);
import requests

API_KEY = "rn_your_key"
BASE = "https://rentnumber.net/api/v1"
headers = {"X-API-KEY": API_KEY}

response = requests.get(f"{BASE}/balance", headers=headers)
print(response.json())
$apiKey = 'rn_your_key';
$base = 'https://rentnumber.net/api/v1';

$ch = curl_init("$base/balance");
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ["X-API-KEY: $apiKey"]
]);
echo curl_exec($ch);
READY TO BUILD?

One key.
Every endpoint.

Get your API key