PVALines SMS API
Get OTP codes on real phone numbers across 200+ countries. Simple REST API, JWT auth, and webhooks.
1. Get Token
POST your credentials to /oauth/token to get a JWT
2. Find Service
Browse /api/services and pick one with stock > 0
3. Buy Number
POST to /api/buyNumbers with your service ID
4. Receive OTP
Poll /getNumber/:id or set a webhook for push
Base URL
https://api.pvalines.com
Authentication
Every protected endpoint requires a Bearer JWT in the x-token header. Here's how it works:
x-token: Bearer <your_token>
Tokens are valid for 1 hour (3600s). When you request a new token, the old one is immediately invalidated โ so only one token is active per account at a time.
curl -X POST https://api.pvalines.com/oauth/token \
-H "Content-Type: application/json" \
-d '{"clientId":"usr_xxx","clientSecret":"sk_live_xxx"}'
# โ { "token": "eyJ...", "type": "Bearer", "expiresIn": 3600 }
# Use the token in all subsequent requests:
curl https://api.pvalines.com/api/services \
-H "x-token: Bearer eyJ..."
Rate Limiting
You can make up to 250 requests per 60 seconds per account (sliding window). If you exceed this, you'll get a 429 Too Many Requests response. The response headers tell you exactly where you stand:
| Response Header | What it means |
|---|---|
| X-RateLimit-Limit | Max requests per window (250) |
| X-RateLimit-Remaining | How many requests you have left right now |
| X-RateLimit-Reset | Unix timestamp when your limit resets |
| Retry-After | Seconds to wait before retrying (only sent on 429) |
Error Codes
All errors return a consistent JSON shape โ no surprises:
{ "success": false, "message": "Human-readable description of the error", "status": 400 }
OAuth
Get an Access Token
Exchange your credentials for a signed JWT. You'll need this token for every other API call. The token expires after 1 hour, and getting a new one invalidates the previous one.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| clientId | string | required | Your client ID from the developer dashboard |
| clientSecret | string | required | Your secret key โ never expose this in client-side code |
Code Examples
curl -X POST https://api.pvalines.com/oauth/token \
-H "Content-Type: application/json" \
-d '{
"clientId": "usr_9f3a2c1b4d7e",
"clientSecret": "sk_live_4xT9mKpQ2rNzWvYcL8jHbA"
}'
Orders
Buy SMS Numbers
Purchase one or more Non VoIP numbers in a single request. Numbers are activated immediately. Call GET /api/services first to get a valid websiteId โ make sure stock > 0 before buying.
Request Body โ services[ ] array
| Field | Type | Required | Description |
|---|---|---|---|
| websiteId | string | required | The service ID from GET /api/services |
| quantity | integer | required | How many numbers to buy (min: 1) |
| biddingPercentage | number | optional | Bid % above base price for auction-based services |
| webhookUrl | string | optional | We'll POST the SMS here instead of you polling |
| number | string | optional | Request a specific phone number |
| regionInfo | object | optional | Filter by region/country |
Code Examples
curl -X POST https://api.pvalines.com/api/buyNumbers \
-H "Content-Type: application/json" \
-H "x-token: Bearer YOUR_TOKEN" \
-d '{
"services": [{
"websiteId": "69a13a4ef133cd20b4a7c082",
"quantity": 1,
"webhookUrl": "https://yourapp.com/webhook/sms"
}]
}'
Orders
Get Order Details
Check the status of a specific order and retrieve the SMS/OTP once it arrives. Poll every 5โ10 seconds until status === "COMPLETED", or skip polling entirely by setting a webhookUrl when buying.
Order Statuses
Code Examples
curl https://api.pvalines.com/api/getNumber/ORDER_ID \
-H "x-token: Bearer YOUR_TOKEN"
Orders
List All Purchased Numbers
Retrieve your full order history with cursor-based pagination. To get the next page, pass the pageInfo.endCursor value as the cursor param. Keep going until hasNextPage is false.
| Query Param | Type | Description |
|---|---|---|
| limit | integer | Results per page. Default: 20, Max: 100 |
| cursor | string | Pagination cursor from previous response's pageInfo.endCursor |
| filter | JSON string | Filter by: country, duration, type, status, number |
| order | JSON string | Sort by createdAt: "1" = oldest first, "-1" = newest first |
Fetch All Pages โ Node.js
async function getAllNumbers(token) {
const all = [];
let cursor = null;
do {
const params = new URLSearchParams({ limit: 100 });
if (cursor) params.set("cursor", cursor);
const { data } = await fetch(
`https://api.pvalines.com/api/getNumbers?${params}`,
{ headers: { "x-token": `Bearer ${token}` } }
).then(r => r.json());
all.push(...data.edges);
cursor = data.pageInfo.hasNextPage ? data.pageInfo.endCursor : null;
} while (cursor);
return all;
}
Orders
Reuse a Number
Request another OTP on the same number โ useful if you need multiple codes from the same service. Only works while the order is still active. Check expireAt first to make sure the window hasn't closed.
curl -X POST https://api.pvalines.com/api/reuseNumber/ORDER_ID \
-H "x-token: Bearer YOUR_TOKEN"
Orders
Flag a Problem Number
Report a number that isn't receiving SMS or was already used before purchase. Our team reviews flags for replacement or refund. Each number can only be flagged once.
curl -X POST https://api.pvalines.com/api/flagNumber/ORDER_ID \
-H "x-token: Bearer YOUR_TOKEN"
Orders
Toggle Auto-Renewal (LTR)
Enable or disable automatic renewal for a long-term rental number. This is a toggle โ calling it once enables renewal, calling it again disables it. Only works on orders with type: LTR.
curl -X PUT https://api.pvalines.com/api/renewLTRNumber/ORDER_ID \
-H "x-token: Bearer YOUR_TOKEN"
Catalog
Browse Available Services
Search for available SMS verification services โ see what's in stock, pricing, and which countries are available. The websiteId from here is what you pass to /buyNumbers. No auth needed.
| Query Param | Description | Example |
|---|---|---|
| filter | Filter by: country (iso2), duration, type, isFavorite | {"country":"US"} |
| order | Sort by name: "1" AโZ, "-1" ZโA | {"name":"1"} |
| limit | Results per page. Default: 20, Max: 100 | 50 |
| cursor | Pagination cursor from previous pageInfo.endCursor | eyJ... |
Code Examples
curl "https://api.pvalines.com/api/services?filter=%7B%22country%22%3A%22US%22%7D&limit=20"
Catalog
List Supported Countries
Returns up to 200 countries in one call โ no pagination needed. Use the iso2 code from this response as the country filter in /api/services. No auth needed.
curl https://api.pvalines.com/api/countries
โก PVALines
support@pvalines.com ยท API v1.0.0 ยท pvalines.com