OTP Verification API in Node.js: Order a Number and Read the Code
For teams that build on JavaScript, an OTP verification API in Node.js script is the quickest way to receive test codes inside a CI job or a bot. This example uses the built-in fetch available in current Node versions.
Short answer: request a number with action=getNumber, split the plain-text reply, poll getStatus until it returns STATUS_OK, then complete the order with setStatus. Cancel it if the time runs out.
Setup
- An API key from your dashboard.
- Service and country IDs from
getServicesandgetCountries. - Node 18 or newer for global fetch.
Example
const API_KEY = process.env.OTPGET_API_KEY;
const BASE = "https://otpget.com/stubs/handler_api.php";
async function call(action, params = {}) {
const query = new URLSearchParams({ api_key: API_KEY, action, ...params });
const res = await fetch(BASE + "?" + query.toString());
return (await res.text()).trim();
}
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function getCode(service, country, waitMs = 120000) {
const reply = await call("getNumber", { service, country, type: 1 });
if (!reply.startsWith("ACCESS_NUMBER")) throw new Error("Order failed: " + reply);
const [, orderId, number] = reply.split(":");
console.log("Use this number:", number);
const end = Date.now() + waitMs;
while (Date.now() < end) {
const status = await call("getStatus", { id: orderId });
if (status.startsWith("STATUS_OK")) {
await call("setStatus", { id: orderId, status: 6 });
return status.split(":")[1];
}
if (status === "STATUS_CANCEL") return null;
await sleep(5000);
}
await call("setStatus", { id: orderId, status: 8 });
return null;
}
getCode("SERVICE_ID", "COUNTRY_ID").then(console.log);What to watch
- Parse the plain-text replies exactly as the documentation shows.
- Treat BAD_KEY, NO_BALANCE and BAD_SERVICE as stop signals.
- Cancel only after the minimum wait the docs describe.
Reference: API documentation.
Using it in tests
In CI, wrap getCode in a timeout, run it against a staging environment you own and fail the build cleanly when no code arrives. Our guide on testing OTP flows in staging covers the strategy.
Using async code safely
Node makes it easy to start many requests at once, which is exactly why a small bug can drain a balance. Put a limit on concurrent orders, wrap the loop in a try and catch, and always reach a final state: completed, cancelled or timed out. If your process restarts, read the list of open order IDs from storage and resume polling instead of ordering new numbers.
Ideas for real projects
- A Telegram or Discord bot that returns codes to your own customers.
- A command-line tool for QA teams that prints a number and waits for the code.
- A CI job step that fetches a code for an end-to-end test on a system you own.
In each case, add logging, a timeout and a spending limit before you add features.
Quick troubleshooting table
If something goes wrong, match the reply to the likely cause: BAD_KEY means the key is missing or wrong; NO_BALANCE means you need to top up; BAD_SERVICE or BAD_COUNTRY means an ID is wrong or unavailable; an empty reply usually means a network problem or a timeout. For each case, log the exact text and stop the loop instead of retrying blindly. When in doubt, check the API documentation for that action's list of replies, because the SMS endpoint and the JSON endpoints use different formats.
Frequently Asked Questions
Can I use axios instead of fetch?
Yes. The API is a plain HTTPS GET.
How do I keep the key out of my repository?
Use an environment variable or your CI secret store.
Does the API support other currencies?
Yes, add a currency parameter to receive amounts in another currency.
Is it for production use?
Yes, with limits, logging and a spending alert in your own code.
Conclusion
Keep the loop simple and the key private. Create a free account to get a key, and see the API overview.