API Reference
Merchant API v1
Programmatically purchase SMS verification numbers, poll OTP status, manage cancellations, renew eligible numbers, and receive webhook events — using the same API keys from your dashboard.
https://realnonvoipusnumber.com/api/v1
Authentication
All protected endpoints require an API key created in the API Dashboard.
X-Api-Key: YOUR_API_KEY
Alternatively:
Authorization: Bearer YOUR_API_KEY
Production keys use the nvl_live_ prefix. Test keys use nvl_test_.
Quick Start
- Create an API key in the dashboard and copy it once.
GET /balanceto confirm authentication.GET /catalogto find aproductServiceId.POST /verificationswith that id and anIdempotency-Key.GET /verifications/{id}untilmessagescontains your OTP (or receive a webhook).
Errors
Every RealNonVoIPUSNumber API response is branded and includes a machine-readable error code:
{
"success": false,
"brand": "RealNonVoIPUSNumber",
"request_id": "rnvs_req_8f29c1a2b3c4",
"error": {
"code": "RNVS_INVALID_API_KEY",
"message": "The API key is invalid or missing.",
"retryable": false,
"request_id": "rnvs_req_8f29c1a2b3c4"
}
}
Use error.code in your client (do not parse message text). Common codes:
RNVS_INVALID_API_KEY,RNVS_API_KEY_DISABLEDRNVS_INSUFFICIENT_BALANCERNVS_INVALID_SERVICE,RNVS_SERVER_NOT_AVAILABLE,RNVS_NUMBER_NOT_AVAILABLERNVS_PROVIDER_UNAVAILABLE,RNVS_PROVIDER_TIMEOUT,RNVS_PROVIDER_ERRORRNVS_ORDER_NOT_FOUND,RNVS_CANCEL_FAILED,RNVS_ORDER_ALREADY_COMPLETEDRNVS_RATE_LIMITED,RNVS_INTERNAL_ERROR
Provider raw errors are never returned. Responses also include header X-Request-Id.
Rate Limits
Default limit: 60 requests per minute per API key.
Headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. Exceeded calls return 429 with Retry-After.
Test Mode
Pass ?test=true or use a nvl_test_ key. Test mode never charges balance and never calls SMS providers. Catalog and create responses are deterministic mock data marked with "test": true.
Webhooks
Configure endpoints in the dashboard. Events include verification.created, verification.otp_received, verification.completed, verification.cancelled, verification.renewed.
Each delivery includes:
X-Webhook-Signature— HMAC-SHA256 hex digest of the raw body using your signing secretX-Webhook-Delivery— unique delivery idX-Webhook-Event— event name
import hmac, hashlib
sig = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
Idempotency
Send Idempotency-Key: UNIQUE_REQUEST_ID on POST /verifications and POST /renew. Retries with the same key return the original result and do not create duplicate charges.
/api/v1/balanceReturns the authenticated account balance.
curl https://realnonvoipusnumber.com/api/v1/balance \
-H "X-Api-Key: YOUR_API_KEY"
{
"success": true,
"brand": "RealNonVoIPUSNumber",
"request_id": "rnvs_req_…",
"data": { "balance": 25.5, "currency": "USD" },
"meta": { "test": false }
}
/api/v1/catalogPurchasable offers from synchronized inventory. Each item’s productServiceId (RNVS-P-…) is used to create a verification.
Query: service, country, page, limit, scope=all (full multi-country catalog), test
Default scope is USA-focused for payload size. Use scope=all for every synced service/country/server combination (paginated).
curl "https://realnonvoipusnumber.com/api/v1/catalog?service=whatsapp&country=187" \
-H "X-Api-Key: YOUR_API_KEY"
/api/v1/verificationsPaginated history for the authenticated account. Query: page, limit, status, from, to.
/api/v1/verificationsCreate a number order through the RealNonVoIPUSNumber stack. Selling price is always calculated server-side.
curl -X POST https://realnonvoipusnumber.com/api/v1/verifications \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Idempotency-Key: UNIQUE_REQUEST_ID" \
-H "Content-Type: application/json" \
-d '{"productServiceId":"RNVS-P-…"}'
{
"success": true,
"brand": "RealNonVoIPUSNumber",
"request_id": "rnvs_req_…",
"data": {
"verificationId": "154785",
"orderId": "#24890552",
"numberId": "RNVS-N-000154785",
"phoneNumber": "+19703453333",
"status": "pending",
"lifecycle": "WAITING_FOR_SMS",
"productServiceId": "RNVS-P-…",
"service": "WhatsApp",
"server": "Server 2",
"price": 0.30,
"messages": []
},
"order": {
"order_id": "#24890552",
"number_id": "RNVS-N-000154785",
"service": "WhatsApp",
"country": "United States",
"phone_number": "+19703453333",
"server": "Server 2",
"price": "0.30",
"status": "WAITING_FOR_SMS"
}
}
JavaScript
const res = await fetch("https://realnonvoipusnumber.com/api/v1/verifications", {
method: "POST",
headers: {
"X-Api-Key": process.env.RNV_API_KEY,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json"
},
body: JSON.stringify({ productServiceId: "RNVS-P-…" })
});
Python
import os, requests, uuid
r = requests.post(
"https://realnonvoipusnumber.com/api/v1/verifications",
headers={
"X-Api-Key": os.environ["RNV_API_KEY"],
"Idempotency-Key": str(uuid.uuid4()),
},
json={"productServiceId": "RNVS-P-…"},
)
print(r.json())
/api/v1/verifications/{id}Poll status and OTP. When a code arrives, data.otp / data.messages and order.status=COMPLETED are populated.
{
"success": true,
"brand": "RealNonVoIPUSNumber",
"order": {
"order_id": "#24890552",
"status": "COMPLETED",
"phone_number": "+19703453333",
"otp": "193680"
}
}
/api/v1/verifications/{id}/cancelCancels when platform rules allow (no OTP yet, cancel lock elapsed). Failures return RNVS_CANCEL_FAILED or RNVS_ORDER_ALREADY_COMPLETED.
/api/v1/verifications/{id}/reuseWhen the original offer supports reuse/reorder, creates a new verification. Otherwise returns RNVS_INVALID_REQUEST.
/api/v1/renewRenew an existing verification when the provider and order state allow it. Uses the same renewal service, pricing engine, and wallet hold/capture as the dashboard Renew button. Provider renewal success is confirmed before any balance charge.
Eligibility: Renew is available only when the order is renewable (for example NonVoIP reuse / HeroSMS reactivation windows). Grizzly and VerifySMS orders are not renewable via API. If renew is unavailable, the API returns RENEW_UNSUPPORTED or RENEW_FAILED and does not charge.
Headers
X-Api-Key: YOUR_API_KEY
Idempotency-Key: unique-renewal-request-id
Body
{
"order_id": 248928997
}
order_id is the numeric verification / order id returned by create/list/get (same integer as in the dashboard). Do not send price, provider, or cost — the backend calculates sell price with the existing markup engine.
cURL
curl -X POST https://realnonvoipusnumber.com/api/v1/renew \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Idempotency-Key: renew-$(date +%s)-$RANDOM" \
-H "Content-Type: application/json" \
-d '{"order_id": 248928997}'
JavaScript
const res = await fetch("https://realnonvoipusnumber.com/api/v1/renew", {
method: "POST",
headers: {
"X-Api-Key": "YOUR_API_KEY",
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json"
},
body: JSON.stringify({ order_id: 248928997 })
});
const json = await res.json();
Python
import uuid, requests
r = requests.post(
"https://realnonvoipusnumber.com/api/v1/renew",
headers={
"X-Api-Key": "YOUR_API_KEY",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"order_id": 248928997},
timeout=60,
)
print(r.json())
Success response
{
"success": true,
"brand": "RealNonVoIPUSNumber",
"request_id": "rnvs_req_…",
"data": { /* verification object */ },
"order": {
"order_id": "#248928997",
"status": "PENDING",
"phone_number": "+1…",
"otp": null
},
"meta": {
"renewed": true,
"renewal_price": "0.24",
"idempotent": false,
"expires_at": "2026-10-01T12:34:56+00:00"
}
}
Errors
VERIFICATION_NOT_FOUND— unknown id or not owned by the API key userINSUFFICIENT_BALANCE(402) — provider is not called when balance is too lowRENEW_UNSUPPORTED— provider/order cannot be renewedRENEW_FAILED— provider unavailable or renew rejected; balance not chargedINVALID_REQUEST— missing/invalidorder_id
Safe retries: send the same Idempotency-Key. A successful renew returns meta.idempotent: true without a second charge.
/api/v1/verifications/statisticsAggregated counts: total, completed, pending, cancelled, failed, expired.
Need a key? Open the API Dashboard. Explore interactively via Swagger.