✅ Trusted by 423,454+ users · ⭐ 4.1/5 on Trustpilot · 200+ countries423,454+ users · Trustpilot

Read FAQs →
423,454+ users4.1/5 rating🌍 200+ countries⚡ Quickstart🧪 REST API v1❓ FAQs📚 Full reference
🧩 API integration · copy/paste quickstart

PVAPins API docs for SMS verification

Integrate faster: request numbers, receive OTP SMS, handle errors cleanly, and scale with polling best practices. Two APIs, one key — the JSON REST API at https://api.pvapins.com/api/v1 and the classic API at https://api.pvapins.com/user/api/.

  • REST API v1 — JSON in, JSON out, header auth, OpenAPI spec
  • Quickstart to first OTP — temporary or rent flow
  • Rate limits + errors — stable production integrations

Responsible use: Follow local laws and each platform’s terms. PVAPins is not affiliated with third-party apps.

60–90s quickstart

Minimal steps to your first OTP via API.

🔑 Needs API key
1
Create accountCopy your API key from the dashboard.
2
Load listsCountries → apps → pick service IDs.
3
Get numberRequest a number for country + app.
4
Fetch OTPPoll the SMS endpoint until the code arrives.
SMS verification and API integration
Tip for devsUse retry/backoff to respect rate limits and reduce failed polls.

Why developers use PVAPins API

Predictable responses, clear flows, and practical guidance for production.

Fast integration

From API key → number → OTP with copy/paste requests and expandable reference below.

🧭

Structured flows

Separate temporary and rent logic so your code stays easier to debug.

🛡️

Stability

Rate-limit-friendly polling, error mapping, and retry tips.

Quickstart (temporary flow)

Replace YOUR_API_KEY, COUNTRY_ID, APP_ID, and NUMBER with your values.

1) Load countries (no auth)
curl -s 'https://api.pvapins.com/user/api/load_countries.php'
2) Load apps for a country (no auth)
curl -s 'https://api.pvapins.com/user/api/load_apps.php?country_id=COUNTRY_ID'
3) Request number (auth)
curl -s 'https://api.pvapins.com/user/api/get_number.php?customer=YOUR_API_KEY&app=APP_NAME&country=COUNTRY_NAME'
4) Poll SMS / OTP (auth)
# Poll every 3–6s with backoff
curl -s 'https://api.pvapins.com/user/api/get_sms.php?customer=YOUR_API_KEY&number=NUMBER&country=COUNTRY_NAME&app=APP_NAME'

Combine / operator (optional): For services that use a group name plus an operator suffix on the site, add &operator=OPERATOR_SUFFIX and set app to the group name (not the full internal name). Use the same pairing on get_number, get_sms, and reject endpoints. If you omit operator, app must stay the full app name, unchanged from before.

Optional: same flow with operator
# get_number / get_sms / reject — use the same app + operator pair everywhere
curl -s 'https://api.pvapins.com/user/api/get_number.php?customer=YOUR_API_KEY&app=GROUP_NAME&country=COUNTRY_NAME&operator=OPERATOR_SUFFIX'

Integration tip: Use exponential backoff (e.g. 3s → 5s → 8s) and stop after a timeout.

Authentication & API key

One key works on both APIs. Send it in a header — the ?customer= query form still works for existing integrations, but a key in a URL ends up in access logs, Referer headers and browser history, so don't build new code on it.

Send the key as a header
# preferred
curl -s -H 'X-API-Key: YOUR_API_KEY' 'https://api.pvapins.com/api/v1/account'

# also accepted
curl -s -H 'Authorization: Bearer YOUR_API_KEY' 'https://api.pvapins.com/api/v1/account'
🔑

Get your API key

Register, open your dashboard API page, and copy the key. Use it only on your server.

🧱

Security

Store keys in environment variables, rotate if leaked, and log requests in production. There is no CORS — never call these APIs from a browser.

REST API v1 — JSON endpoints

The modern API: JSON in, JSON out, header authentication, ISO country codes and a machine-readable OpenAPI 3.1 spec you can generate a client from. Base URL https://api.pvapins.com. Everything below is also browsable and runnable in the interactive reference.

🧾

Predictable JSON

Every response is JSON. Errors carry a stable machine code plus a human message.

🎯

Pick your operator

GET /operators lists price and stock per operator, most reliable first. Pin one, or let us auto-pick.

♻️

Safe retries

Send an Idempotency-Key on order creation and a retry returns the original order instead of buying twice.

Endpoints

EndpointWhat it doesNotes
GET /api/v1/accountYour account and spendable balanceBalance already excludes funds held by pending orders
GET /api/v1/countriesSupported countriesKeyed by ISO 3166-1 alpha-2 (US, GB)
GET /api/v1/servicesSupported services and their codesRead codes from here — never guess them
GET /api/v1/operatorsOperators, price and stock for a country + serviceRequires country and service. Most reliable first
GET /api/v1/numbersLive availability and priceprice is filled only when both country and service are given
POST /api/v1/ordersReserve a numberThis is the call that spends money
GET /api/v1/ordersYour 20 most recent ordersNot paginated — don't reconcile on this alone
GET /api/v1/orders/{id}Poll one order for its OTP404 if the order isn't yours

Quickstart — country to OTP in four calls

1) Find the service code
curl -s -H 'X-API-Key: YOUR_API_KEY' 'https://api.pvapins.com/api/v1/services'

# {"services":[{"code":"wa","name":"Whatsapp"},{"code":"course-hero","name":"Course Hero"}, ...]}
2) Check operators, price and stock
curl -s -H 'X-API-Key: YOUR_API_KEY' \
  'https://api.pvapins.com/api/v1/operators?country=US&service=wa'

# {"operators":[{"operator":2,"label":"Operator 2","price":0.15,"count":42}, ...]}
# count: null means "stock unknown", NOT zero — those operators are still buyable.
3) Create the order (this spends balance)
curl -s -X POST 'https://api.pvapins.com/api/v1/orders' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: YOUR_UNIQUE_ID' \
  -d '{"country":"US","service":"wa","operator":2}'

# {"id":"1048576","phoneNumber":"+15551234567","status":"active","price":0.15,"expires_in":1200}
# Omit "operator" to auto-pick the most reliable operator in stock and bill its price.
4) Poll for the code
# Poll every 3-5s until otpCode is filled or status leaves "active".
# There are no customer webhooks — polling is the delivery path.
curl -s -H 'X-API-Key: YOUR_API_KEY' 'https://api.pvapins.com/api/v1/orders/1048576'

# {"id":"1048576","status":"completed","otpCode":"418494","phoneNumber":"+15551234567"}

Service codes are not all two or three letters. Where we have an sms-activate slug we keep it (wa, tg, go = Gmail, ts = PayPal) — those you cannot guess. Everything else gets a slug derived from the name (course-hero, capital-one-shopping), and a service whose name has no Latin characters gets svc-<id>. Read the code from GET /api/v1/services, or pass the service name instead — POST /orders, GET /operators and GET /numbers all accept a name wherever they accept a code.

Order errors

HTTPCodeMeaningWhat to do
400BAD_REQUESTBody was not valid JSONFix the request
401Missing, invalid or revoked keyCheck the header; rotate if leaked
403Key is missing a required scopeIssue a key with that scope
402NO_BALANCENot enough balanceTop up, then retry
404BAD_SERVICE / BAD_COUNTRY / BAD_OPERATORUnknown or inactiveRe-read the inventory endpoints
409NO_NUMBERSOut of stock right nowRetry with backoff, or another operator
409IN_FLIGHTSame Idempotency-Key is still being placedWait and re-poll — do not send a new order
429RATE_LIMITEDToo many requestsHonour Retry-After
502SUPPLIER_ERRORUpstream failureRetryable
503SUPPLIER_DISABLEDSupplier switched offTry another operator or country

Rate limits: per API key, per endpoint, per minute — 60/min on most endpoints, higher on OTP polling, and lower on the calls that consume stock. Over the limit you get 429 with a Retry-After header; the limits are tuned at runtime, so read the header rather than hardcoding a number.

Temporary numbers — core endpoints

One-time verification sessions. See full reference for payloads and errors.

Load countries

GET https://api.pvapins.com/user/api/load_countries.php
No auth
Purpose
Country list and IDs for your UI

Load apps

GET …/load_apps.php?country_id=
No authcountry_id
Required
country_id
Purpose
Apps/services available for that country

Get rates

GET …/get_rates.php
Auth
Params
customer, country (and app per docs)

Get number

GET …/get_number.php
AuthRate limit
Required
customer, app, country
Optional
operator — when set, app is the group/combine name and operator is the suffix (see full reference)

Get SMS (OTP)

GET …/get_sms.php
Auth
Required
customer, number, country, app
Optional
operator — same pairing rules as Get number

Rent numbers API

For repeated OTPs or longer access — keep rent calls separate in your codebase.

🔁

When to rent

Repeat logins, re-verification, or when you may need another code on the same line.

🧩

API difference

Use rent-specific parameters (e.g. is_rent=1) as in the reference below.

Example: rent number request
curl -s 'https://api.pvapins.com/user/api/get_number.php?customer=YOUR_API_KEY&app=APP_NAME&country=COUNTRY_NAME&is_rent=1'

Combine / operator: Optional &operator=… works with rent requests too — same rules as the temporary flow (app = group name when operator is set).

Errors, rate limits & stability

Treat limits as normal — throttle, backoff, and map errors to clear actions.

⏱️

Polling

Start around 3–6s, then backoff; stop after a max wait; log failures.

🚦

Rate limits

Throttle concurrent polls; queue requests under load.

🧾

Error mapping

One internal table: message → meaning → action (retry / new number / balance / key).

ErrorMeaningAction
Customer Not FoundInvalid or missing API keyVerify the key you sent; rotate if leaked
No Number FoundNo inventory for selectionTry another country/app or timing
Not Possible (limit)Rate limitBackoff and retry later

Temporary vs rent

Pick the right model before you wire up automation.

OptionBest forRepeat accessNext step
TemporaryOne-off verification or testingNoRun quickstart →
RentMultiple OTPs / longer windowYesRent options →
RatesPricing by country & appPricing →

FAQs

Quick answers for integrators.

How do I get my PVAPins API key?

Register, log in, and copy your key from the dashboard. Use it server-side only.

Which API should I use — REST v1 or the classic one?

New integrations should use REST API v1 (https://api.pvapins.com/api/v1): JSON responses, header authentication, ISO country codes and a published OpenAPI spec. The classic /user/api/*.php endpoints are unchanged and still supported, so existing code keeps working — you do not need to migrate.

Are there webhooks for incoming OTPs?

No. Poll GET /api/v1/orders/{id} every 3–5 seconds until otpCode is filled or status leaves active.

Can I call the API from a browser?

No — there is no CORS, deliberately. Your API key is a server-side secret; put the calls behind your own backend.

Which endpoints don’t need authentication?

Listing countries/apps is typically public; requesting numbers and fetching SMS requires your key.

Fastest way to get an OTP?

Request a number, then poll get_sms with backoff until the code appears or you time out.

Temporary vs rent?

Temporary is for a short session; rent keeps the same line for repeated codes over a rental period.

“Customer Not Found”?

Check the customer parameter matches your API key exactly.

No SMS arriving?

Wait, poll with backoff, then try another route; avoid hammering the API.

What is the operator parameter?

Optional. For combine-style services, pass the operator suffix and set app to the group name shown on the site. Omit operator if you use the full app name as app (default behavior).

Rate limits?

Yes — design throttling and exponential backoff into your integration.

Automation at scale?

Use monitoring, error mapping, and compliance controls; follow platform terms.

Need help integrating?

Use the quickstart and full reference, then contact us if you want flow validation or troubleshooting.

Full endpoint reference

Expand each block for parameters, examples, and error messages. Switch tabs for temporary vs rent endpoints.

GET Load Countries
Endpoint:
https://api.pvapins.com/user/api/load_countries.php
Example Request:
https://api.pvapins.com/user/api/load_countries.php
Parameters:
• No parameters required - returns all available countries
Response Format:
[ { "id": 58, "full_name": "USA" }, { "id": 62, "full_name": "UK" } ]
Response Fields:
id: Unique country identifier
full_name: Full country name
Notes:
  • This endpoint returns a JSON array of all available countries
  • No authentication required
  • Useful for populating country dropdowns in applications
  • Country names can be used with other API endpoints
GET Load Apps
Endpoint:
https://api.pvapins.com/user/api/load_apps.php?country_id=country_id
Example Request:
https://api.pvapins.com/user/api/load_apps.php?country_id=58
Parameters:
country_id: Country ID to get apps for (required)
Response Format:
[ { "id": 2548, "full_name": "Facebook40", "timestamp": "2025-08-13 10:25:32", "trending": 1, "deduct": "0.91" }, { "id": 2551, "full_name": "Gmail40", "timestamp": "2025-08-14 14:47:36", "trending": 1, "deduct": "0.84" } ]
Response Fields:
id: Unique app identifier
full_name: Full app name
timestamp: Last update timestamp
trending: Trending status (1 = trending, 0 = not trending)
deduct: Cost deduction amount
Notes:
  • This endpoint returns a JSON array of all available apps for a specific country
  • No authentication required
  • Useful for populating app dropdowns in applications
  • App names can be used with other API endpoints
  • Trending apps are marked with trending=1
  • Deduct field shows the cost for using this app
GET Check Rates
Endpoint:
https://api.pvapins.com/user/api/get_rates.php?customer=apikey&country=countryname
Example Request:
https://api.pvapins.com/user/api/get_rates.php?customer=YOUR_API_KEY&country=malaysia
Parameters:
customer: Your API key (required)
country: Country name to check rates for
Error Messages:
  • Customer Not Found
GET Get Number
Endpoint:
https://api.pvapins.com/user/api/get_number.php?customer=apikey&app=appname&country=countryname
Example Request (New Number):
https://api.pvapins.com/user/api/get_number.php?customer=YOUR_API_KEY&app=google&country=malaysia
Example Request (Reuse Number):
https://api.pvapins.com/user/api/get_number.php?customer=YOUR_API_KEY&app=google&country=malaysia&number=112869xxx
Optional — combine / operator (group + suffix):
https://api.pvapins.com/user/api/get_number.php?customer=YOUR_API_KEY&app=GROUP_NAME&country=malaysia&operator=OPERATOR_SUFFIX
When operator is present, app must be the group/combine name (as on the website), and operator is the suffix for that service. Omit operator to keep classic behavior: app = full application name.
Parameters:
customer: Your API key (required)
app: Full application name, or group name when using operator
country: Country name (e.g., malaysia, indonesia, philippines)
operator: Optional — operator suffix for combine-style services
number: Phone number to reuse (optional, for reuse feature only)
Rate Limit: 5 numbers per minute
🔄 Reuse Number Feature:
Free of charge - No deduction when reusing a number
15 minutes limit - Can only reuse numbers within 15 minutes of creation
User history required - Number must exist in your usage history
Usage: Add &number=PHONE_NUMBER parameter to reuse a previously used number
Example:?customer=apikey&app=google&country=malaysia&number=112869xxx
Error Messages:
  • Customer Not Found.
  • App Not Found.
  • Country Not Found.
  • Number not found in your history. (when reusing)
  • Number reuse is only available for supported services.
  • New Numbers registration in progress, please wait or check back later.
  • Error 102, check back later.
GET Get SMS
Endpoint:
https://api.pvapins.com/user/api/get_sms.php?customer=apikey&number=number&country=countryname&app=appname
Example Request:
https://api.pvapins.com/user/api/get_sms.php?customer=YOUR_API_KEY&number=112869xxx&country=malaysia&app=google
Example (with operator):
https://api.pvapins.com/user/api/get_sms.php?customer=YOUR_API_KEY&number=112869xxx&country=malaysia&app=GROUP_NAME&operator=OPERATOR_SUFFIX
Parameters:
customer: Your API key (required)
number: Phone number to check SMS for
country: Country name
app: Full application name, or group name when using operator
operator: Optional — same pairing as Get number
Error Messages:
  • Customer Not Found.
  • Number Not Found.
  • You have not received any code yet.
  • Your balance is expired.
  • Error 102, check back later.
GET Reject Number
Endpoint:
https://api.pvapins.com/user/api/get_reject_number.php?customer=apikey&number=number&country=countryname&app=appname
Example Request:
https://api.pvapins.com/user/api/get_reject_number.php?customer=YOUR_API_KEY&number=112869xxx&country=malaysia&app=google
Example (with operator):
https://api.pvapins.com/user/api/get_reject_number.php?customer=YOUR_API_KEY&number=112869xxx&country=malaysia&app=GROUP_NAME&operator=OPERATOR_SUFFIX
Parameters:
customer: Your API key (required)
number: Phone number to reject
country: Country name
app: Full application name, or group name when using operator
operator: Optional — same pairing as Get number / Get SMS
Time Limit: 3 minutes per number
Note: get_reject.php (alternate URL using n_id) supports the same optional operator parameter.
Error Messages:
  • Customer Not Found.
  • App Not Found.
  • Country Not Found.
  • Number Not Found.
  • Number Rejected.
  • Not able to reject.
  • Error 102, check back later.
  • Limit: 3 MINUTES PER NUMBER
GET Check Balance
Endpoint:
https://api.pvapins.com/user/api/get_balance.php?customer=apikey
Example Request:
https://api.pvapins.com/user/api/get_balance.php?customer=YOUR_API_KEY
Parameters:
customer: Your API key (required)
Error Messages:
  • Customer Not Found
GET Get History
Endpoint:
https://api.pvapins.com/user/api/get_history.php?customer=apikey
Example Request:
https://api.pvapins.com/user/api/get_history.php?customer=YOUR_API_KEY
Parameters:
customer: Your API key (required)
Error Messages:
  • Customer Not Found

Rent Numbers API Endpoints

API endpoints for renting phone numbers for extended periods. These endpoints include the is_rent=1 parameter to distinguish from temporary numbers.

GET Load Countries (Rent)
Endpoint:
https://api.pvapins.com/user/api/load_countries.php?is_rent=1
Example Request:
https://api.pvapins.com/user/api/load_countries.php?is_rent=1
Parameters:
is_rent: Set to 1 to get countries available for rent (required)
Note: This endpoint returns countries that support number rental services
Response Format:
[ { "id": 58, "full_name": "USA" }, { "id": 62, "full_name": "UK" } ]
Response Fields:
id: Unique country identifier
full_name: Full country name
GET Load Apps (Rent)
Endpoint:
https://api.pvapins.com/user/api/load_apps.php?country_id=country_id&is_rent=1
Example Request:
https://api.pvapins.com/user/api/load_apps.php?country_id=58&is_rent=1
Parameters:
country_id: Country ID to get apps for (required)
is_rent: Set to 1 to get apps available for rent (required)
Note: This endpoint returns apps that support number rental services
Response Format:
[ { "id": 2333, "full_name": "Rent Adidas", "timestamp": "2025-06-17 21:04:01", "trending": 0, "deduct": "10.00" }, { "id": 2349, "full_name": "Rent Airbnb", "timestamp": "2025-06-17 21:03:54", "trending": 0, "deduct": "10.00" } ]
Response Fields:
id: Unique app identifier
full_name: Full app name
timestamp: Last update timestamp
trending: Trending status (1 = trending, 0 = not trending)
deduct: Cost deduction amount for rental
Notes:
  • This endpoint returns a JSON array of all available apps for rent in a specific country
  • No authentication required
  • Useful for populating app dropdowns in rental applications
  • App names can be used with other rental API endpoints
  • Trending apps are marked with trending=1
  • Deduct field shows the rental cost for using this app
GET Get Number (Rent)
Endpoint:
https://api.pvapins.com/user/api/rent.php?customer=apikey&app=appname&country=countryname
Example Request:
https://api.pvapins.com/user/api/rent.php?customer=YOUR_API_KEY&app=google&country=malaysia
Parameters:
customer: Your API key (required)
app: Application name (e.g., google, whatsapp, telegram)
country: Country name (e.g., malaysia, indonesia, philippines)
Rate Limit: 5 numbers per minute
Success Response:
{ "data": "112869xxx", "code": 100 }
Error Response:
{ "data": "Currently, The number is unavailable, Try again later", "code": 200 }
Response Fields:
data: Phone number (success) or error message (failure)
code: Response code (100 = success, 200 = error)
Notes:
  • This endpoint is specifically for renting phone numbers for extended periods
  • Authentication required via API key
  • Rate limited to 5 numbers per minute
  • Returns a rented phone number that can be used for longer periods
  • Use the returned number with other rental-specific endpoints
GET Load Rented Numbers
Endpoint:
https://api.pvapins.com/user/api/load_rent.php?customer=apikey
Example Request:
https://api.pvapins.com/user/api/load_rent.php?customer=YOUR_API_KEY
Parameters:
customer: Your API key (required)
Success Response:
[ { "id": 728, "user_id": "80768a26e52ca6156081", "key_id": "840811", "key_id2": null, "app_id": 2327, "number": "12817437990", "deduct": "3.33", "duration": 3, "country_id": "58", "is_released": 0, "auto_renew": 0, "received_message": 0, "api": "1010", "timestamp": "2025-08-17 20:14:13", "app_name": "Rent GPay GPlay GVoice", "country_name": "USA", "timestamp_readable": "17/08/2025 08:14 pm", "days": 2, "expiry": "2025-08-20 20:14:13" } ]
Response Fields:
id: Unique rental ID
user_id: User identifier
key_id: Key identifier
app_id: Application ID
number: Rented phone number
deduct: Cost deduction amount
duration: Rental duration in days
country_id: Country identifier
is_released: Release status (0 = active, 1 = released)
auto_renew: Auto-renewal status (0 = disabled, 1 = enabled)
received_message: Message count received
api: API identifier
timestamp: Rental start timestamp
app_name: Application name
country_name: Country name
timestamp_readable: Human-readable timestamp
days: Days remaining in rental
expiry: Rental expiry date and time
Notes:
  • This endpoint retrieves all currently rented phone numbers for your account
  • Authentication required via API key
  • Returns detailed information about each rented number including expiry dates
  • Use this endpoint to manage and monitor all your rented numbers
  • The days field shows remaining rental days
  • Check is_released to see if a number is still active
  • Response includes country and app information for each rented number
GET Get SMS (Rent)
Endpoint:
https://api.pvapins.com/user/api/load_rent_code.php?customer=apikey&country=countryname&app=appname&number=number
Example Request:
https://api.pvapins.com/user/api/load_rent_code.php?customer=YOUR_API_KEY&country=USA&app=Rent%20GPay%20GPlay%20GVoice&number=12817437990
Parameters:
customer: Your API key (required)
country: Country name (e.g., USA, UK, malaysia)
app: Application name (e.g., Rent GPay GPlay GVoice)
number: Rented phone number to check SMS for (required)
Success Response:
[ { "from": "22000", "message": "If someone requests this code, it is a scam. Use code 418494 only in Google Voice app to sign up. g.co/voice/help", "timestamp": "17/08/2025 08:15 pm" }, { "from": "Billing", "message": "3-day MDN rental started", "timestamp": "17/08/2025 08:14 pm" } ]
Response Fields:
from: Sender of the SMS message
message: Content of the SMS message
timestamp: Date and time when the SMS was received
Notes:
  • This endpoint retrieves SMS messages for rented phone numbers
  • Authentication required via API key
  • Returns an array of SMS messages with sender, content, and timestamp
  • Use this endpoint to check for verification codes and other messages
  • Messages are returned in chronological order (newest first)
  • URL encode app names that contain spaces (e.g., "Rent GPay GPlay GVoice")
GET Reject Number (Rent)
Endpoint:
https://api.pvapins.com/user/api/reject_rent.php?customer=apikey&app=appname&country=countryname&number=number
Example Request:
https://api.pvapins.com/user/api/reject_rent.php?customer=YOUR_API_KEY&app=google&country=malaysia&number=121345698
Parameters:
customer: Your API key (required)
app: Application name (e.g., google, whatsapp, telegram)
country: Country name (e.g., malaysia, indonesia, philippines)
number: Phone number to reject (required)
Success Response:
{ "data": "Rejected", "code": 100 }
Error Response:
{ "data": "Cant Rejected", "code": 200 }
Response Fields:
data: Response message (success or error)
code: Response code (100 = success, 200 = error)
Notes:
  • This endpoint allows you to reject/return a rented phone number
  • Authentication required via API key
  • Use this when you no longer need a rented number
  • Rejecting a number will release it back to the pool
  • Only works with numbers that are currently rented by your account
  • Check the response code to confirm if the rejection was successful
GET Renew Number (Rent)
Endpoint:
https://api.pvapins.com/user/api/rent_renew_number.php?customer=apikey&app=appname&country=countryname&number=number
Example Request:
https://api.pvapins.com/user/api/rent_renew_number.php?customer=YOUR_API_KEY&app=google&country=malaysia&number=121345698
Parameters:
customer: Your API key (required)
app: Application name (e.g., google, whatsapp, telegram)
country: Country name (e.g., malaysia, indonesia, philippines)
number: Phone number to renew (required)
Success Response:
{ "data": "Status Updated", "code": 100 }
Error Response:
{ "data": "Not enough balance", "code": 200 }
Response Fields:
data: Response message (success or error)
code: Response code (100 = success, 200 = error)
Notes:
  • This endpoint allows you to extend the rental period of a phone number
  • Authentication required via API key
  • Use this to keep a rented number for additional time periods
  • Requires sufficient balance in your account
  • Only works with numbers that are currently rented by your account
  • Check the response code to confirm if the renewal was successful
  • Renewal will extend the rental by the original duration period

REST API v1 — JSON endpoints

Base URL https://api.pvapins.com. Authenticate with X-API-Key: YOUR_API_KEY (or Authorization: Bearer YOUR_API_KEY). The same key works here and on the classic endpoints above. Machine-readable spec: OpenAPI 3.1 · runnable interactive reference.

GET Account & balance
Endpoint:
GET https://api.pvapins.com/api/v1/account
Example Request:
curl -s -H 'X-API-Key: YOUR_API_KEY' 'https://api.pvapins.com/api/v1/account'
Response Format:
{ "id": "80768a26e52ca6156081", "email": "[email protected]", "role": "user", "balance": 12.35, "created_at": "2025-08-17T20:14:13.000Z" }
Response Fields:
balance: spendable balance — your total minus anything held by pending orders. This is the figure ordering is gated on.
created_at: snake_case here, camelCase on the order endpoints. Kept that way for compatibility.
GET List countries
Endpoint:
GET https://api.pvapins.com/api/v1/countries
Example Request:
curl -s -H 'X-API-Key: YOUR_API_KEY' 'https://api.pvapins.com/api/v1/countries'
Response Format:
{ "countries": [ { "code": "US", "name": "USA", "flag": "🇺🇸" }, { "code": "GB", "name": "UK", "flag": "🇬🇧" } ] }
Notes:
code is ISO 3166-1 alpha-2 and is what you pass as country everywhere else. The classic endpoints use country names instead — the two are not interchangeable.
• Cached for 5 minutes.
GET List services
Endpoint:
GET https://api.pvapins.com/api/v1/services
Example Request:
curl -s -H 'X-API-Key: YOUR_API_KEY' 'https://api.pvapins.com/api/v1/services'
Response Format:
{ "services": [ { "code": "wa", "name": "Whatsapp" }, { "code": "go", "name": "Gmail" }, { "code": "course-hero", "name": "Course Hero" }, { "code": "svc-1234", "name": "Название" } ] }
Read the code — do not guess it.
• Where we hold an sms-activate slug we keep it: 2–3 lowercase letters (wa, tg, acd). These are not derivable from the name — go is Gmail, ts is PayPal, lf is TikTok.
• Otherwise the code is a slug derived from the name: lowercased, accents stripped, non-alphanumerics collapsed to -, capped at 48 characters — 5ka.ru5ka-ru, Capital One Shoppingcapital-one-shopping. Collisions get a numeric suffix (-2, -3).
• A name with no Latin characters at all has no derivable slug and gets svc-<id>. Address those by namePOST /orders, GET /operators and GET /numbers accept a name wherever they accept a code.
GET Operators, price & stock
Endpoint:
GET https://api.pvapins.com/api/v1/operators?country=COUNTRY&service=SERVICE
Example Request:
curl -s -H 'X-API-Key: YOUR_API_KEY' 'https://api.pvapins.com/api/v1/operators?country=US&service=wa'
Parameters — country and service are each optional, but at least one is required:
country: ISO-2 country code
service: service code from /api/v1/services, or the service name
page: bulk listings only — 1-based, default 1
limit: bulk listings only — default 500, maximum 2000. Out-of-range values are clamped, never rejected.
Which one you supply picks the mode:
Both — every operator for that one route, with live stock. This is the call to make right before buying.
service only — every country that sells it. Each row carries country.
country only — every service available there. Each row carries service.
Neither422. There is no all-routes mode: we publish roughly 6,900 services across 216 countries, so page through one of the two bulk modes instead.
Response Format — one route (both parameters):
{ "operators": [ { "operator": 2, "label": "Operator 2", "price": 0.15, "count": 42 }, { "operator": 4, "label": "Operator 4", "price": 0.19, "count": null } ] }
Response Format — bulk (one parameter):
curl -s -H 'X-API-Key: YOUR_API_KEY' 'https://api.pvapins.com/api/v1/operators?service=wa&limit=500' { "operators": [ { "country": "AE", "operator": 1, "price": 0.42, "count": null }, { "country": "AL", "operator": 1, "price": 0.55, "count": null } ], "page": 1, "limit": 500, "total": 4176, "hasMore": true }
count is always null in the two bulk modes. Live stock costs us one supplier call per operator, so we do not fetch it for a listing thousands of rows long. As everywhere in this API, null means stock unknown — it never means zero or sold out. Ask for the single route you are about to buy if you need a live figure. Bulk rows also carry no label.
Response Fields:
operator: the public displayId you pin on POST /orders
price: per-OTP price in USD — the price we quote is the price we charge
count: numbers in stock. null means unknown, not zero — some suppliers expose no stock figure and those operators are still buyable.
Ordering: most reliable first, ranked on our measured delivery rate for that route, with price deciding between operators of similar reliability.
displayIds are assigned by price rank and stay stable regardless of stock or reliability, so the list can legitimately read 1, 3, 4 (one temporarily empty) and can appear out of numeric order. A displayId always means the same operator, so pinning is unaffected.
Reliability ordering applies to the single-route mode, where it tells you which operator we would auto-pick. The two bulk modes are sorted by country (or service) and then operator ascending instead — a ranking across thousands of unrelated routes would mean nothing, and a listing that size needs to be predictably addressable so paging is repeatable.
A displayId is scoped to its (service, country) pair, so operator: 1 under wa/US and operator: 1 under tg/GB are different operators. Never key a cache or a config on the number alone.
Errors:
  • 404 — unknown country or service
  • 422 — neither country nor service supplied; at least one is required. Note this one error uses a nested shape: {"error":{"code":"VALIDATION_ERROR","message":"…"}}
GET Availability & live price
Endpoint:
GET https://api.pvapins.com/api/v1/numbers?country=COUNTRY&service=SERVICE
Example Request:
curl -s -H 'X-API-Key: YOUR_API_KEY' 'https://api.pvapins.com/api/v1/numbers?country=US&service=wa'
Parameters:
country: ISO-2 country code (optional)
service: service code or name (optional)
Note:price is non-null only when both are supplied, and it is the auto-pick price — exactly what POST /orders bills when you omit operator.
Response Format:
{ "countries": [ { "code": "US", "name": "USA", "flag": "🇺🇸", "heroId": 58, "available": 1240 } ], "price": 0.15 }
POST Create an order
Endpoint:
POST https://api.pvapins.com/api/v1/orders
Example Request:
curl -s -X POST 'https://api.pvapins.com/api/v1/orders' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: YOUR_UNIQUE_ID' \ -d '{"country":"US","service":"wa","operator":2}'
Body (JSON):
country: ISO-2 country code, case-insensitive (required)
service: service code or name (required)
operator: optional displayId from /api/v1/operators. Omit it and we auto-pick the most reliable operator in stock and bill that price.
Header:Idempotency-Key — optional, but recommended. A retry with the same key returns the original order for 30 minutes instead of buying a second number.
Success Response:
{ "id": "1048576", "phoneNumber": "+15551234567", "country": "US", "service": "wa", "operator": 2, "status": "active", "otpCode": null, "price": 0.15, "createdAt": "2026-08-10T12:00:00.000Z", "expiresAt": "2026-08-10T12:20:00.000Z", "expires_in": 1200 }
Response Fields:
status: one of pending, active, completed, cancelled, expired
expires_in: seconds until the order expires — always 1200 (20 minutes)
price: what you were charged, in USD
Errors{"error":"CODE","message":"…"}:
  • 400 BAD_REQUEST — body was not valid JSON
  • 402 NO_BALANCE — insufficient balance
  • 404 BAD_SERVICE / BAD_COUNTRY / BAD_OPERATOR — unknown or inactive
  • 409 NO_NUMBERS — out of stock; retryable with backoff
  • 409 IN_FLIGHT — an order with the same Idempotency-Key is still being placed. Wait and re-poll; do not send a new order.
  • 429 RATE_LIMITED — honour the Retry-After header
  • 502 SUPPLIER_ERROR — upstream failure; retryable
  • 503 SUPPLIER_DISABLED — supplier switched off
GET Poll an order for its OTP
Endpoint:
GET https://api.pvapins.com/api/v1/orders/{id}
Example Request:
curl -s -H 'X-API-Key: YOUR_API_KEY' 'https://api.pvapins.com/api/v1/orders/1048576'
Response Format:
{ "id": "1048576", "phoneNumber": "+15551234567", "status": "completed", "otpCode": "418494", "message": "418494", "price": 0.15, "completedAt": "2026-08-10T12:01:44.000Z" }
Polling: there are no customer webhooks. Poll every 3–5 seconds until otpCode is populated or status leaves active, then stop.
Note:message carries the OTP code, not the full SMS body — our suppliers do not reliably return the full text.
Errors:
  • 404 — no such order, or the order is not yours
GET List recent orders
Endpoint:
GET https://api.pvapins.com/api/v1/orders
Example Request:
curl -s -H 'X-API-Key: YOUR_API_KEY' 'https://api.pvapins.com/api/v1/orders'
Response Format:
{ "orders": [ { "id": "1048576", "phoneNumber": "+15551234567", "country": "US", "service": "wa", "operator": 2, "status": "completed", "otpCode": "418494", "price": 0.15, "createdAt": "2026-08-10T12:00:00.000Z", "expiresAt": "2026-08-10T12:20:00.000Z" } ] }
Notes:
  • Returns the 20 most recent orders, newest first
  • No pagination — don't build financial reconciliation on this endpoint alone; record order ids as you create them
Get API keyQuickstart