v1.0.0 ยท REST API ยท Production Ready

PVALines SMS API

Get OTP codes on real phone numbers across 200+ countries. Simple REST API, JWT auth, and webhooks.

200+
Countries
8
Endpoints
250/min
Rate Limit
1 hr
Token TTL
๐Ÿ”‘

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

https://api.pvalines.com

Authentication

Every protected endpoint requires a Bearer JWT in the x-token header. Here's how it works:

๐Ÿ”
Send this header with every request:
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.
bash
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:

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 }
200Everything worked fine
400Bad Request โ€” check your input fields
401Unauthorized โ€” missing or expired token
402Payment Required โ€” top up your balance
404Not Found โ€” order or resource doesn't exist
429Too Many Requests โ€” slow down
500Internal Server Error โ€” something went wrong on our end

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.

POST /oauth/token No auth required
clientId string required Your client ID from the developer dashboard
clientSecret string required Your secret key โ€” never expose this in client-side code
Returns: { "token": "eyJ...", "type": "Bearer", "expiresIn": 3600 }
curl -X POST https://api.pvalines.com/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "usr_9f3a2c1b4d7e",
    "clientSecret": "sk_live_4xT9mKpQ2rNzWvYcL8jHbA"
  }'
200Token generated successfully 400Missing clientId or clientSecret 401Wrong credentials

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.

POST /api/buyNumbers
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
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"
    }]
  }'
200Returns a batch order ID 400Invalid websiteId or missing fields 401Unauthorized 402Insufficient balance

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.

GET /api/getNumber/:id
PENDINGWaiting for SMS to arrive
COMPLETEDSMS received successfully
EXPIREDTime window closed, no SMS came
FLAGGEDReported as broken/non-working
curl https://api.pvalines.com/api/getNumber/ORDER_ID \
  -H "x-token: Bearer YOUR_TOKEN"

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.

GET /api/getNumbers
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
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;
}

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.

POST /api/reuseNumber/:id
curl -X POST https://api.pvalines.com/api/reuseNumber/ORDER_ID \
  -H "x-token: Bearer YOUR_TOKEN"
200Number reused, waiting for new SMS 400Order expired or not eligible 404Order not found

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.

POST /api/flagNumber/:id
curl -X POST https://api.pvalines.com/api/flagNumber/ORDER_ID \
  -H "x-token: Bearer YOUR_TOKEN"
200Number flagged for review 400Already flagged or window expired

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.

PUT /api/renewLTRNumber/:id
curl -X PUT https://api.pvalines.com/api/renewLTRNumber/ORDER_ID \
  -H "x-token: Bearer YOUR_TOKEN"
200Renewal toggled 400Not an LTR order

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.

GET /api/services No auth required
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...
curl "https://api.pvalines.com/api/services?filter=%7B%22country%22%3A%22US%22%7D&limit=20"

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.

GET /api/countries No auth required
curl https://api.pvalines.com/api/countries

โšก PVALines

support@pvalines.com  ยท  API v1.0.0  ยท  pvalines.com

API Playground

Make live API calls. Responses appear below.

Get one from /oauth/token first

Response will appear here...
Select an endpoint above...