Activation workflow
Choose a number, retrieve its result, and manage the order.
1. Choose country, service and message type
Use country and service codes. For a chosen country, fetch operators, number counts and prices. Check message type settings: voice=0 is SMS, 1 is caller-ID, 2 is voice calls.
Prices and stock can change before you order; checking them does not reserve a number. For donor operators, a count of 9999 means the exact quantity is unknown.
2. Get a number
Use Get number to request a number, or Get number by operator if you need a specific operator.
Save data.orderId — you’ll need it to receive messages and manage the order. The response also includes data.orderExpireIn, the number of seconds remaining before the order expires. Use it to calculate the expiry time once:
const expiresAt = Date.now() + numberResult.data.orderExpireIn * 1000;Keep this expiry time when checking for messages. Each check uses the same deadline; use the lifetime returned by the API rather than assuming a fixed ten minutes.
If the request times out, check Current orders before requesting another number: the first order may already have been created. There is no documented idempotency key to prevent a duplicate request.
3. Wait for the result
Call Receive SMS with the returned orderId. It also retrieves voice and caller-ID results, without another voice parameter.
| Response | What to do |
|---|---|
| 200 | Use data.sms and stop this polling loop |
| 202 + SMS_NOT_YET_RECEIVED | Wait, then poll again before the saved deadline |
| 410 + ORDER_CLOSED | Stop; the order is closed |
| Other error | Handle the documented error; do not keep polling blindly |
A waiting response includes error, so check for SMS_NOT_YET_RECEIVED before treating it as a failure. Reading a newly received SMS can trigger payment; keep that in mind when calling this method.
The example checks every five seconds and stops when the order expires. Five seconds is a choice for this example, not an API rate limit. Also handle any limit response from the server. A connection failure or non-JSON response stops the loop so you can decide what to do next.
// Node.js 22.16+. No automatic retries after transport errors or terminal responses.
export async function waitForSms({ apiKey, orderId, expiresAt, intervalMs = 5000 }, {
fetchImpl = fetch,
now = Date.now,
sleep = ms => new Promise(resolve => setTimeout(resolve, ms)),
baseUrl = 'https://api.smspva.com',
} = {}) {
if (!apiKey || !/^\d+$/.test(String(orderId))) throw new Error('Set your API key and order ID');
if (!Number.isFinite(expiresAt) || expiresAt <= now()) throw new Error('Order deadline has passed');
if (!Number.isFinite(intervalMs) || intervalMs < 5000) throw new Error('Use a polling interval of at least 5000 ms in this example');
while (now() < expiresAt) {
const remaining = expiresAt - now();
const response = await fetchImpl(`${baseUrl}/activation/sms/${encodeURIComponent(orderId)}`, {
headers: { apikey: apiKey },
signal: AbortSignal.timeout(Math.max(1, Math.floor(Math.min(30_000, remaining)))),
});
const result = await response.json();
if (response.status === 202 && result.statusCode === 202 && result.error?.type === 'SMS_NOT_YET_RECEIVED') {
const delay = Math.min(intervalMs, expiresAt - now());
if (delay <= 0) break;
await sleep(delay);
continue;
}
if (response.status !== 200 || result.error || result.statusCode !== 200) {
throw new Error(`HTTP ${response.status}: ${JSON.stringify(result)}`);
}
return result.data;
}
throw new Error('No result before the order deadline');
}Save the function in poll-sms.mjs, then call it with the deadline calculated when the number was received:
import { waitForSms } from './poll-sms.mjs';
const data = await waitForSms({ apiKey, orderId, expiresAt });
console.log(data.sms);4. Manage the order
- Clear SMS: clear the current SMS to receive another. Preserve the returned
orderExpireIn. HTTP 404 / NO_SMS_TO_CLEAN has the documented meaning; do not assume a clear succeeded. - Stop SMS: stop receiving SMS.
- Cancel order: cancel an order.
- Block number: mark a number as nonworking.
- Number status: check a number previously used for the same service.
Choose the action that matches what you want to do with the order, then check its response. The examples leave this decision to you and do not cancel, stop or block an order automatically after a timeout.