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.

Base URL 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

  1. Create an API key in the dashboard and copy it once.
  2. GET /balance to confirm authentication.
  3. GET /catalog to find a productServiceId.
  4. POST /verifications with that id and an Idempotency-Key.
  5. GET /verifications/{id} until messages contains 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_DISABLED
  • RNVS_INSUFFICIENT_BALANCE
  • RNVS_INVALID_SERVICE, RNVS_SERVER_NOT_AVAILABLE, RNVS_NUMBER_NOT_AVAILABLE
  • RNVS_PROVIDER_UNAVAILABLE, RNVS_PROVIDER_TIMEOUT, RNVS_PROVIDER_ERROR
  • RNVS_ORDER_NOT_FOUND, RNVS_CANCEL_FAILED, RNVS_ORDER_ALREADY_COMPLETED
  • RNVS_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 secret
  • X-Webhook-Delivery — unique delivery id
  • X-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.

GET/api/v1/balance

Returns 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 }
}
GET/api/v1/catalog

Purchasable 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"
GET/api/v1/verifications

Paginated history for the authenticated account. Query: page, limit, status, from, to.

POST/api/v1/verifications

Create 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())
GET/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"
  }
}
PATCH/api/v1/verifications/{id}/cancel

Cancels when platform rules allow (no OTP yet, cancel lock elapsed). Failures return RNVS_CANCEL_FAILED or RNVS_ORDER_ALREADY_COMPLETED.

PATCH/api/v1/verifications/{id}/reuse

When the original offer supports reuse/reorder, creates a new verification. Otherwise returns RNVS_INVALID_REQUEST.

POST/api/v1/renew

Renew 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 user
  • INSUFFICIENT_BALANCE (402) — provider is not called when balance is too low
  • RENEW_UNSUPPORTED — provider/order cannot be renewed
  • RENEW_FAILED — provider unavailable or renew rejected; balance not charged
  • INVALID_REQUEST — missing/invalid order_id

Safe retries: send the same Idempotency-Key. A successful renew returns meta.idempotent: true without a second charge.

GET/api/v1/verifications/statistics

Aggregated counts: total, completed, pending, cancelled, failed, expired.

Need a key? Open the API Dashboard. Explore interactively via Swagger.