PVADeals API Docs

PVADeals API

Build powerful SMS verification solutions with our non-VoIP phone number API. Get access to real carrier phone numbers for account verification across hundreds of services.

Base URL https://prod-v3.pvadeals.com

v3.3 · Last updated: May 31, 2026 (UTC+00:00)

Introduction

The PVADeals API provides programmatic access to our SMS verification service. Use it to purchase phone numbers, receive SMS codes, and manage your verification workflow.

📱

Non-VoIP Numbers

Real carrier phone numbers that work with services that block VoIP.

Instant Delivery

SMS codes typically arrive within seconds of being sent.

📥

Postman Collection

Download our ready-to-use API collection to get started quickly.

Download JSON

Authentication

All API requests require authentication using your API key. Include it in the Authorization header with the Bearer prefix.

Request Header
Authorization: Bearer API-xxxxx...

🔑 Getting Your API Key

2 Go to Settings → API Keys
3 Create your API key

Example Request with Authentication

cURL
curl -X GET "https://prod-v3.pvadeals.com/v3/api/balance" \
  -H "Authorization: Bearer API-xxxxx..."

Quick Start

Follow this typical integration flow to purchase a number and receive an SMS verification code.

1
Get Services
2
Purchase Number
3
Use Number
4
Receive Webhook
5
Complete

Step 1: Get Available Services

cURL
curl -X GET "https://prod-v3.pvadeals.com/v3/api/services/all" \
  -H "Authorization: Bearer API-xxxxx..."

Step 2: Purchase a Number

cURL
curl -X POST "https://prod-v3.pvadeals.com/v3/api/purchase" \
  -H "Authorization: Bearer API-xxxxx..." \
  -H "Content-Type: application/json" \
  -d '{"services": [{"serviceId": "697139f7fe5460ddc2f27214"}]}'

Step 3: Receive SMS via Webhook

Configure your webhook URL in the dashboard. When an SMS arrives, you'll receive a POST request with the verification code.

Rate Limits

The API enforces two layers of rate limiting: a per-IP token bucket that protects the platform from any one source, and a per-API-key bucket that applies a separate cap on each endpoint.

Per-IP limits (apply to every caller from the same IP)

ScopeLimitWindowNotes
All /v3/api/*300 requests60s rollingToken bucket. Refills continuously.
Purchase paths (/v3/api/purchase, /v3/api/purchase-ltr)60 requests60s rollingExtra bucket on top of the all-/v3/api/* bucket.

Per-API-key limits (apply per endpoint)

EndpointLimitWindow
GET /v3/api/services/all1060s
GET /v3/api/service/:id6060s
GET /v3/api/balance6060s
GET /v3/api/requests6060s
GET /v3/api/request/:id12060s
POST /v3/api/purchase5060s
POST /v3/api/purchase-ltr3060s
POST /v3/api/flag/:id, POST /v3/api/reuse/:id, POST /v3/api/renew-ltr/:id3060s
Any other endpoint (default)12060s

Purchase safety brake

If 15 purchase calls fail within 60 seconds for the same API key, the purchase endpoints pause for that key for 5 minutes. Successful calls don't count toward this. Returns 429 with a Retry-After header.

Rate Limit Response

429 Response (per-API-key)
{
  "message": "API rate limit exceeded. Maximum 60 requests per 60 seconds for GET /v3/api/balance.",
  "status": 429,
  "retryAfter": 60
}
💡

Public probes share the per-IP bucket

/v3/api/health and /v3/api/version count against the 300/min per-IP limit. A 30s polling interval (12 req/min) leaves 96% of the bucket free for your real API calls.

Error Handling

The API uses standard HTTP status codes to indicate success or failure of requests.

Status CodeMeaningCommon Causes
200 OKSuccessRequest completed successfully
400 Bad RequestInvalid RequestMissing required fields, invalid JSON
401 UnauthorizedAuthentication FailedMissing or invalid API key
403 ForbiddenAccount Blocked / Action DisallowedAccount suspended, purchase block active, or insufficient privileges
404 Not FoundResource Not FoundRequest ID or Service ID doesn't exist
422 UnprocessableBusiness Rule ViolationFlag/Reuse not allowed for this request
429 Too Many RequestsRate Limit ExceededToo many requests, wait and retry
503 Service UnavailableMaintenance or Backend UnavailableMaintenance window is active, or a critical dependency is down. Also the response for /v3/api/health when status is maintenance or unavailable.

Error Response Format

Error Response
{"success": false, "message": "Unauthorized Access! Invalid API key", "status": 401}

Health Check

Public, unauthenticated liveness probe for customer-side monitoring tools (Pingdom, UptimeRobot, BetterStack, Datadog HTTP checks, custom dashboards). No API key required.

GET/v3/api/health

Response is NOT wrapped in the standard envelope

Unlike every other endpoint, the body below is the entire response — no {success, data, message} wrapper. Customers who write a generic envelope unwrapper need a separate code path for this endpoint.

Example Request

cURL
curl -i "https://prod-v3.pvadeals.com/v3/api/health"

Response: operational

200 OK
{
  "status": "operational",
  "version": "1.6.0",
  "timestamp": "2026-05-31T14:22:01.123Z"
}

Response: maintenance window

503 Service Unavailable
{
  "status": "maintenance",
  "version": "1.6.0",
  "timestamp": "2026-05-31T14:22:01.123Z"
}

Response: backend unavailable

503 Service Unavailable
{
  "status": "unavailable",
  "version": "1.6.0",
  "timestamp": "2026-05-31T14:22:01.123Z"
}

Status Values

StatusHTTP CodeMeaning
operational200 OKAll checks passing. Safe to call other endpoints.
maintenance503Operator-set maintenance window. Every authenticated endpoint will also return 503 right now. Wait and retry.
unavailable503Backend cannot service requests right now. Retry with backoff.

Response Fields

statusstringEnum: operational | maintenance | unavailable
versionstringDeployed backend version (semver, e.g. 1.6.0)
timestampstringISO-8601 UTC timestamp at the moment of response
💡

Integration tips

Key your monitoring off the HTTP status code (200 = up, 503 = down), not the body string — that is what every standard monitoring tool checks. We deliberately do not return 200 with a "down" body. Subsystem detail is intentionally not exposed in the body. Recommended polling interval: 30 seconds (the endpoint is cached server-side for 5 seconds, so polling faster does not get fresher data).

Version

Public, unauthenticated. Returns the deployed backend version — useful for detecting when a new release has rolled out without making an authenticated call (CI/CD smoke checks, incident-response timelines).

GET/v3/api/version

Response is NOT wrapped in the standard envelope

Same convention as /v3/api/health: the body below is the entire response, no {success, data, message} wrapper.

Example Request

cURL
curl "https://prod-v3.pvadeals.com/v3/api/version"

Response

200 OK
{
  "status": "ok",
  "version": "1.6.0"
}

Response Fields

statusstringAlways "ok" for a 200 response
versionstringDeployed backend version (semver)

Get Balance

Retrieve your current account balance and credit information.

GET/v3/api/balance

Example Request

cURL
curl -X GET "https://prod-v3.pvadeals.com/v3/api/balance" \
  -H "Authorization: Bearer API-xxxxx..."

Response

200 OK
{"success": true, "data": {"credits": 100.00}, "message": "Balance retrieved successfully"}

Get All Services

Retrieve a list of all available services for SMS verification.

GET/v3/api/services/all

Example Request

cURL
curl -X GET "https://prod-v3.pvadeals.com/v3/api/services/all" \
  -H "Authorization: Bearer API-xxxxx..."

Response

200 OK
{
  "success": true,
  "data": {
    "services": [
      {
        "_id": "697139f7fe5460ddc2f27214",
        "name": "Airbnb",
        "country": "USA",
        "STRprice": 0.09,
        "LTR3price": 0.7,
        "LTR7price": 1.25,
        "LTR14price": 1.75,
        "LTR30price": 2.25,
        "STRstock": 142,
        "LTRstock": 28
      }
    ]
  }
}

Response Fields

_idstringService ID (use this for purchase)
namestringService/website name
countrystringCountry (USA)
STRpricenumberShort-term rental price in USD
LTR3pricenumber3-day LTR price in USD
LTR7pricenumber7-day LTR price in USD
LTR14pricenumber14-day LTR price in USD
LTR30pricenumber30-day LTR price in USD
STRstockintegerCurrent STR pool inventory available for purchase. Omitted on the "All Services" entry - it's a wildcard with no per-pool stock.
LTRstockintegerCurrent LTR pool inventory available for purchase. Same "All Services" exception as STRstock.

Get Service

Retrieve a single service by its ID. Useful for resolving the serviceId from a request response back to its display name / pricing without paging through the full catalog.

GET/v3/api/service/{id}

Path Parameters

ParameterTypeDescription
id*stringThe service _id (from Get All Services)

Example Request

cURL
curl -X GET "https://prod-v3.pvadeals.com/v3/api/service/697139f7fe5460ddc2f27214" \
  -H "Authorization: Bearer API-xxxxx..."

Response

200 OK
{
  "success": true,
  "data": {
    "_id": "697139f7fe5460ddc2f27214",
    "name": "Airbnb",
    "country": "USA",
    "price": 0.09,
    "LTR3price": 0.7,
    "LTR7price": 1.25,
    "LTR14price": 1.75,
    "LTR30price": 2.25,
    "STRstock": 142,
    "LTRstock": 28
  },
  "message": "Service retrieved successfully"
}

Response Fields

_idstringService ID
namestringService/website name
countrystringCountry (USA)
pricenumberSTR (20-min) price in USD.
LTR3pricenumber3-day LTR price in USD. 0 if the service is not LTR-available.
LTR7pricenumber7-day LTR price in USD. 0 if the service is not LTR-available.
LTR14pricenumber14-day LTR price in USD. 0 if the service is not LTR-available.
LTR30pricenumber30-day LTR price in USD. 0 if the service is not LTR-available.
STRstockintegerHow many numbers we currently have in stock for short-term (20 min) use.
LTRstockintegerHow many numbers we currently have in stock for long-term rental. The same number is used for all duration choices (3 / 7 / 14 / 30 days) because they all draw from the same pool.
💡

Caching

The response is cached for 5 minutes per API key, so repeated lookups of the same service are nearly free.

STR - Purchase Number

Purchase one or more phone numbers for SMS verification. Numbers are available for 20 minutes.

POST/v3/api/purchase

Request Body

📦 Request Body
services*arrayArray of service objects to purchase
↳ serviceId*stringService ID from /services/all endpoint
↳ areaCodestringOptional US area code for specific region (e.g., "215" for Philadelphia)

Example Request

cURL
curl -X POST "https://prod-v3.pvadeals.com/v3/api/purchase" \
  -H "Authorization: Bearer API-xxxxx..." \
  -H "Content-Type: application/json" \
  -d '{"services": [{"serviceId": "697139f7fe5460ddc2f27214", "areaCode": "215"}]}'

Response

200 OK
{
  "success": true,
  "data": {
    "requests": [{
      "_id": "697a90d25ef1873ef44f48bc",
      "serviceName": "Airbnb",
      "serviceId": "697139f7fe5460ddc2f27214",
      "number": "+13130001234",
      "status": "RESERVED",
      "country": "US",
      "amount": 0.2,
      "numberType": "STR",
      "allowFlag": true,
      "allowReuse": false,
      "reuseCounter": 0,
      "endTime": "2026-01-28T23:02:26.292Z",
      "createdAt": "2026-01-28T22:42:26.452Z"
    }]
  },
  "message": "Numbers purchased successfully"
}
📩

Webhook Notification

A number_purchased webhook event will be sent to your configured webhook URL after a successful purchase.

STR - Flag Number

Flag a number to cancel it and receive a refund (if eligible). Only available when allowFlag: true.

POST/v3/api/flag/{id}

Path Parameters

ParameterTypeDescription
id*stringThe service request ID to flag

Example Request

cURL
curl -X POST "https://prod-v3.pvadeals.com/v3/api/flag/697a90d25ef1873ef44f48bc" \
  -H "Authorization: Bearer API-xxxxx..."

Response

200 OK
{"success": true, "data": true, "message": "Number flagged successfully"}

Flag Availability

Check the allowFlag field before attempting to flag. If allowFlag: false, the request will return a 422 error.

STR - Reuse Number

Reuse a previously purchased number to receive additional SMS codes. Only available when allowReuse: true.

POST/v3/api/reuse/{id}

Path Parameters

ParameterTypeDescription
id*stringThe service request ID to reuse

Example Request

cURL
curl -X POST "https://prod-v3.pvadeals.com/v3/api/reuse/697a90d25ef1873ef44f48bc" \
  -H "Authorization: Bearer API-xxxxx..."

Response

200 OK
{
  "success": true,
  "data": {
    "_id": "697a90d25ef1873ef44f48bc",
    "serviceName": "Airbnb",
    "serviceId": "697139f7fe5460ddc2f27214",
    "number": "+13130001234",
    "status": "RESERVED",
    "country": "US",
    "amount": 0,
    "numberType": "STR",
    "allowFlag": false,
    "allowReuse": true,
    "reuseCounter": 2,
    "endTime": "2026-01-28T23:07:17.000Z"
  },
  "message": "Number reused successfully"
}

Reuse

Reuse is time-limited and not guaranteed for all numbers. In some cases, additional charges may apply.

LTR - Purchase Number

Purchase a long-term rental phone number for extended verification needs.

POST/v3/api/purchase-ltr

Request Body

📦 Request Body
duration*numberRental duration in days (3, 7, 14, or 30)
serviceId*stringService ID from /services/all endpoint
areaCodestringOptional US area code for specific region (e.g., "619" for San Diego)

Example Request

cURL
curl -X POST "https://prod-v3.pvadeals.com/v3/api/purchase-ltr" \
  -H "Authorization: Bearer API-xxxxx..." \
  -H "Content-Type: application/json" \
  -d '{"duration": 30, "serviceId": "697139f4fe5460ddc2f271db", "areaCode": "619"}'

Response

200 OK
{
  "success": true,
  "data": {
    "_id": "6985cc7b9ecd8f1260b47a39",
    "serviceName": "2RedBeans",
    "serviceId": "697139f4fe5460ddc2f271db",
    "number": "+13130001234",
    "status": "RESERVED",
    "country": "US",
    "amount": 0.7,
    "endTime": "2026-02-09T11:11:55.324Z",
    "allowFlag": true,
    "autoRenewEnable": false,
    "numberType": "LTR",
    "createdAt": "2026-02-06T11:11:55.354Z",
    "updatedAt": "2026-02-06T11:11:55.384Z"
  },
  "message": "LTR number purchased successfully"
}

Duration Options

DurationPriceDescription
3$0.703-day rental
7$1.257-day rental
14$1.7514-day rental
30$2.2530-day rental

LTR - Flag Number

Flag a LTR number to cancel it and receive a refund (if eligible). Only available when allowFlag: true.

POST/v3/api/flag/{id}

Path Parameters

ParameterTypeDescription
id*stringThe LTR request ID to flag

Example Request

cURL
curl -X POST "https://prod-v3.pvadeals.com/v3/api/flag/6985cc7b9ecd8f1260b47a39" \
  -H "Authorization: Bearer API-xxxxx..."

Response

200 OK
{"success": true, "data": true, "message": "Number flagged successfully"}

Flag Availability

Check the allowFlag field before attempting to flag. If allowFlag: false, the request will return a 422 error.

LTR - Renew Number

Toggle auto-renew for a LTR number. The same endpoint enables or disables auto-renewal.

POST/v3/api/renew-ltr/{id}

Path Parameters

ParameterTypeDescription
id*stringThe LTR request ID to toggle auto-renew

Example Request

cURL
curl -X POST "https://prod-v3.pvadeals.com/v3/api/renew-ltr/6985ce2e9ecd8f1260b47a7e" \
  -H "Authorization: Bearer API-xxxxx..."

Response

200 OK
{
  "success": true,
  "data": {
    "_id": "6985ce2e9ecd8f1260b47a7e",
    "serviceName": "2RedBeans",
    "serviceId": "697139f4fe5460ddc2f271db",
    "number": "+13130001234",
    "status": "RESERVED",
    "country": "US",
    "amount": 0.7,
    "endTime": "2026-02-09T11:19:10.769Z",
    "allowFlag": true,
    "autoRenewEnable": true,
    "numberType": "LTR",
    "createdAt": "2026-02-06T11:19:10.795Z",
    "updatedAt": "2026-02-06T11:19:16.699Z"
  },
  "message": "Auto-renew enabled successfully"
}
🔄

Auto-Renew Toggle

Call this endpoint again to disable auto-renew. Response message will change to "Auto-renew disabled successfully".

LTR - Reuse Number

Reuse a previously purchased LTR number to receive additional SMS codes. Only available when allowReuse: true.

POST/v3/api/reuse/{id}

Path Parameters

ParameterTypeDescription
id*stringThe LTR request ID to reuse

Example Request

cURL
curl -X POST "https://prod-v3.pvadeals.com/v3/api/reuse/6985cc7b9ecd8f1260b47a39" \
  -H "Authorization: Bearer API-xxxxx..."

Response

200 OK
{
  "success": true,
  "data": {
    "_id": "6985cc7b9ecd8f1260b47a39",
    "serviceName": "2RedBeans",
    "serviceId": "697139f4fe5460ddc2f271db",
    "number": "+13130001234",
    "status": "RESERVED",
    "country": "US",
    "amount": 0,
    "numberType": "LTR",
    "allowFlag": false,
    "allowReuse": true,
    "reuseCounter": 2,
    "endTime": "2026-02-09T11:11:55.324Z"
  },
  "message": "Number reused successfully"
}

Reuse Availability

Check the allowReuse field before attempting to reuse. If allowReuse: false, the request will return a 422 error.

LTR - Purchase All Service Number

Purchase a 28-day LTR number that can receive SMS from any service - not restricted to a single website.

POST/v3/api/purchase-ltr

Request Body

📦 Request Body
duration*number28 (fixed for all service)
serviceId*stringALL_SERVICES

Example Request

cURL
curl -X POST "https://prod-v3.pvadeals.com/v3/api/purchase-ltr" \
  -H "Authorization: Bearer API-xxxxx..." \
  -H "Content-Type: application/json" \
  -d '{"duration": 28, "serviceId": "ALL_SERVICES"}'

Response

200 OK
{
  "success": true,
  "data": {
    "_id": "6985d496e49f9312f4cc934e",
    "serviceName": "ALL_SERVICES",
    "serviceId": "ALL_SERVICES",
    "number": "+13130001234",
    "status": "RESERVED",
    "country": "US",
    "amount": 12.99,
    "endTime": "2026-03-06T11:11:55.324Z",
    "allowFlag": false,
    "autoRenewEnable": false,
    "numberType": "LTR",
    "createdAt": "2026-02-06T11:11:55.354Z",
    "updatedAt": "2026-02-06T11:11:55.384Z"
  },
  "message": "LTR number purchased successfully"
}

List Service Requests

Get a paginated list of your service requests (purchased numbers) using cursor-based pagination. Returns both STR and LTR requests.

GET/v3/api/requests

Query Parameters

ParameterTypeDefaultDescription
firstnumber20Number of items to fetch
afterstring-Cursor for forward pagination
beforestring-Cursor for backward pagination
orderFieldstring_idField to sort by
orderBystringdescSort order: asc or desc

Example Request

cURL
curl -X GET "https://prod-v3.pvadeals.com/v3/api/requests?first=20&orderBy=desc" \
  -H "Authorization: Bearer API-xxxxx..."

Response

200 OK
{
  "success": true,
  "data": {
    "data": {
      "edges": [{
        "cursor": "Njk3YTkwZDI1ZWYxODczZWY0NGY0OGJj",
        "node": {
          "_id": "697a90d25ef1873ef44f48bc",
          "serviceName": "Airbnb",
          "serviceId": "697139f7fe5460ddc2f27214",
          "number": "+13130001234",
          "status": "COMPLETED",
          "country": "US",
          "amount": 0.2,
          "numberType": "STR",
          "allowFlag": false,
          "allowReuse": true,
          "reuseCounter": 0,
          "endTime": "2026-01-28T23:02:26.292Z",
          "createdAt": "2026-01-28T22:42:26.452Z"
        }
      }]
    }
  }
}

Get Service Request

Get detailed information about a specific service request by its ID. Works for both STR and LTR requests.

GET/v3/api/request/{id}

Path Parameters

ParameterTypeDescription
id*stringThe service request ID

Example Request

cURL
curl -X GET "https://prod-v3.pvadeals.com/v3/api/request/697a90d25ef1873ef44f48bc" \
  -H "Authorization: Bearer API-xxxxx..."

Response

200 OK
{
  "success": true,
  "data": {
    "_id": "697a90d25ef1873ef44f48bc",
    "serviceName": "Airbnb",
    "serviceId": "697139f7fe5460ddc2f27214",
    "number": "+13130001234",
    "status": "COMPLETED",
    "country": "US",
    "amount": 0.2,
    "numberType": "STR",
    "allowFlag": false,
    "allowReuse": true,
    "reuseCounter": 0,
    "messageCounter": 15,
    "endTime": "2026-01-28T23:02:26.292Z",
    "createdAt": "2026-01-28T22:42:26.452Z",
    "updatedAt": "2026-01-28T22:57:35.016Z"
  },
  "message": "Service request retrieved successfully"
}

Status Values

StatusDescription
RESERVEDNumber purchased, waiting for SMS
COMPLETEDSMS received successfully
FLAGGEDNumber was flagged/cancelled
TIMEOUTNumber expired without receiving SMS

Webhooks

Configure a webhook URL in your dashboard to receive real-time notifications about events.

🔄

Webhook Retry Policy

Webhooks are retried up to 5 times with a 5-second delay between each attempt if delivery fails.

sms_received

Triggered when an SMS is received on a purchased number.

Webhook Payload
{"event": "sms_received", "timestamp": "2026-01-28T22:57:35.001Z", "requestId": "697a90d25ef1873ef44f48bc", "serviceId": "697139f7fe5460ddc2f27214", "number": "+13130001234", "message": "Your Airbnb verification code is 2200."}

number_purchased

Triggered when a number is successfully purchased.

Webhook Payload
{"event": "number_purchased", "timestamp": "2026-01-28T22:42:26.452Z", "requestId": "697a90d25ef1873ef44f48bc", "serviceId": "697139f7fe5460ddc2f27214", "number": "+13130001234", "message": ""}

number_flagged

Triggered when a number is flagged/cancelled.

Webhook Payload
{"event": "number_flagged", "timestamp": "2026-01-28T22:42:25.673Z", "requestId": "697a8d4f8130528198e0c0eb", "serviceId": "697a8d4f8130528198e0c0f4", "number": "+13130001234", "message": ""}

number_reused

Triggered when a number is reused.

Webhook Payload
{"event": "number_reused", "timestamp": "2026-01-28T21:50:36.765Z", "requestId": "697a82bf27787d2db20a29a0", "serviceId": "697a82c127787d2db20a29a6", "number": "+13130001234", "message": ""}

number_renewed

Triggered when an LTR number is automatically renewed. Contains the new request ID which must be used for future API calls.

Webhook Payload
{"event": "number_renewed", "timestamp": "2026-03-09T21:39:19.195Z", "requestId": "69af3e07d317de1936d907fa", "serviceId": "697139f4fe5460ddc2f271b2", "number": "+13130001234", "message": "", "oldRequestId": "69af3a8246b1683d46342bcc", "serviceName": "Chalkboard", "amount": 0.7, "newExpiresAt": "2026-03-12T21:38:42.212Z"}

sms_blocked

Triggered when an inbound SMS arrives on one of your rented numbers but does not match the service the number was rented for. The SMS is not credited to your request and not delivered to you; this event tells you it happened so you can adjust your matching / detection logic.

Webhook Payload
{"event": "sms_blocked", "timestamp": "2026-05-12T18:04:01.211Z", "requestId": "6a1f3e4c4a8f9d1b2c7f0e23", "serviceId": "697139f7fe5460ddc2f27214", "number": "+13130001234", "blockedService": "Discord", "matchType": "keyword", "matchedValue": "discord", "message": ""}

Webhook Payload Fields

eventstringEvent type (sms_received, number_purchased, etc.)
timestampstringISO 8601 timestamp of the event
requestIdstringOrdered number's request ID (new ID for renewals)
serviceIdstringWebsite name's service ID
numberstringThe phone number
messagestringSMS content (only for sms_received)
oldRequestIdstringPrevious request ID (only for number_renewed)
serviceNamestringService name (only for number_renewed)
amountnumberAmount charged (only for number_renewed)
newExpiresAtstringNew expiration date (only for number_renewed)
blockedServicestringService the SMS was for (only for sms_blocked)
matchTypestringHow the block was detected: "keyword" or "exact_pattern" (only for sms_blocked)
matchedValuestringThe keyword or pattern that matched (only for sms_blocked)