If you searched "sms verification api" expecting a page about sending one-time codes to your own users, this isn't quite that — and it's worth saying so before you read another paragraph. Most of what ranks for that phrase (Google's SMS Retriever docs, Twilio, Vonage, Sinch, Telnyx) is built for the sending side: you already have a user with their own phone, and you want to push them a code. VerifyPulse's API does the opposite job. It provisions a real, cellular (non-VoIP) phone number you can receive SMS on — for testing an OTP flow in CI without burning a real SIM, or for completing a verification step on a third-party platform that requires one.
Both are legitimately called "SMS verification APIs." They solve different problems. This guide explains what VerifyPulse's version does, who actually reaches for it, what an integration involves in practice, and how it compares structurally to the CPaaS "Verify" products that dominate the search results. For endpoint-level detail — parameters, response shapes, exact status codes — that lives at the full endpoint reference; this page is the "why and how" that sits in front of it.
What the API actually does, in one flow
Stripped to the mechanics, there are four steps:
- Request a number.
POST /buy-numberwith a country and a service name, and you get back a live number tied to your account. - Wait for the code. Poll
GET /numbers/{number_id}/status. The response cycles throughSTATUS_WAIT_CODEwhile nothing has arrived, toSTATUS_OK:123456once a code lands — the full message text comes back, not just the digits, so you can parse whatever format the sending platform used. - Use the code in whatever flow you're testing or completing.
- Release it.
POST /numbers/{number_id}/cancelfrees the number. If no code ever arrived, canceling early gets your balance back immediately instead of waiting for it to happen automatically.
That's the entire mental model. There's no code to write for the SMS carrier side, no line-type provisioning, no dealing with a telecom directly — you're calling a REST API with one auth header (X-API-Key) and getting a phone number back.
Who actually reaches for this
Three groups show up in the wild, and they want different things from the same four-step flow:
- QA and platform engineers who need to exercise a real OTP path — their own app's signup flow, or a third-party integration their app depends on — without tying up a personal phone or a drawer of burner SIMs. This is a documented, recurring ask in developer communities: engineers specifically looking to test OTP delivery in CI or staging without a live carrier connection tied to a real device.
- People and small teams who need to complete someone else's verification step programmatically — provisioning a number ahead of time for an account they're setting up, rather than doing it by hand through a phone.
- Developers evaluating this against a CPaaS Verify product and realizing partway through that Twilio Verify, Vonage Verify, and similar products assume you already have the end user's number — they don't solve "I need a number to receive on" at all.
If none of those describe you, you may actually want the products in the first search results — a CPaaS Verify API to send codes to numbers your users already own. That's a fine thing to want; it's just not what this page or this API does.
Why teams reach for a third-party API instead of owning this themselves
Provisioning real cellular numbers isn't something you bolt onto a backend over a weekend. You'd need commercial relationships with mobile carriers or aggregators in every country you care about, a way to detect and route around a dead or congested route in real time, and a process for retiring numbers so you're not paying to hold inventory nobody's using.
VerifyPulse's approach is to aggregate three upstream providers behind one API, so a route going down in one country doesn't take your integration down with it — the API abstracts that failover away from you entirely. For the mechanics of why multi-provider routing matters more than it sounds like it should, see why aggregating three upstream providers beats a single carrier relationship. The short version for API users: you get one interface regardless of which upstream actually served a given number, and you don't have to build or maintain that layer yourself.
Testing and staging without burning real numbers
This is the use case the current SERP doesn't address at all, and it's worth walking through concretely, because it's the strongest reason a developer lands on this page rather than a CPaaS competitor's.
Say your product has its own OTP-based signup, and you want CI to actually exercise that path — not mock it — before every deploy. Hardcoding a QA engineer's personal number doesn't scale past one test run at a time, and it puts a real phone number in your test fixtures. The alternative:
- Your test suite calls
POST /buy-numberfor a cheap, low-traffic service and a country you control. - It polls
GET /numbers/{number_id}/statuson an interval (with backoff — don't hammer this every 500ms) until it seesSTATUS_OK:.... - It extracts the code from the message body and feeds it into your own signup flow's verification step.
- It cancels or lets the number expire once the test run is done.
That gives you a real, disposable phone number per test run, provisioned and torn down entirely through the API, with no human in the loop and no shared test-account number that different CI runs might collide on. It's the same four-step flow from the section above — the only thing that changes is who's on the other end of the code.
Polling vs. webhooks: what's actually supported today
Some verification and messaging APIs offer webhook-based push delivery as an alternative to polling — your server registers a URL, and the provider calls it the moment a message arrives, instead of you asking repeatedly. Today, VerifyPulse's published API reference documents a polling pattern only: GET /numbers/{number_id}/status, called on an interval, is the way you find out a code has arrived. There is no webhook-registration endpoint in the API reference, and nothing in that reference indicates one is planned — treat this as polling-only, not "polling for now."
If your integration specifically needs push delivery, don't assume it exists — check the endpoints tab in the API docs for the current, authoritative endpoint list before you design around it. Polling with a reasonable interval and exponential backoff on errors is a well-understood pattern and works fine for the CI/QA and provisioning use cases above; it just means your client is responsible for the check-in loop rather than the server pushing to you.
How this SMS verification API compares to a CPaaS Verify API
This is the comparison worth having explicitly, because "SMS verification API" gets used for both categories and the pricing models, integration surface, and actual job are different enough that picking the wrong one wastes a sprint.
| CPaaS "Verify" APIs (Twilio Verify, Vonage Verify, Sinch, Telnyx) | VerifyPulse's API | |
|---|---|---|
| What you're buying | A managed pipeline that sends a one-time code to a number your user already owns | A real, non-VoIP number you can receive codes on for a period of time |
| The job it does | Add 2FA/OTP to your own product's login or signup flow | Test an OTP flow in CI/staging, or complete a verification step on a platform that requires a working number |
| Who owns the destination number | Your end user, permanently | You, for the rental or one-time period |
| Pricing shape | Per-verification-attempt or per-successful-conversion fee set by the provider — see Twilio's current Verify pricing and Vonage's current Verify pricing for live figures | Per-number, priced by live demand for that country and service, no subscription |
| Integration surface | Broad — many channels (SMS, voice, WhatsApp, push, TOTP), built-in fraud scoring, channel fallback | Narrow — eight endpoints: balance, countries, services, buy, list, status, cancel, repeat |
| Good fit when | You're building the sending side of verification for users who already exist in your system | You need a number to receive on, not send from |
Neither category is "better" in the abstract — they answer different questions. If what you actually need is to add OTP login to your own app, a CPaaS Verify product is the right tool and this page won't talk you out of it. If what you need is a number to receive a code on, that's the gap CPaaS Verify products don't fill, and it's what this API is for.
Rate limits, auth, and reliability at a glance
Authentication is a single X-API-Key header (or the same key as a query parameter, if a header isn't convenient in your setup) — no OAuth dance, no token refresh cycle. The published rate limit is 100 requests per 15 minutes per IP address, with the current usage reported back in response headers so you can back off before you hit it rather than after. Numbers are issued against live pool availability, so a 503 on /buy-number generally means the upstream is temporarily out of stock for that country/service combination, not that something is broken — retry with backoff or try a different country.
None of this replaces the reference. Treat the numbers above as the shape of what to expect, and check the endpoints tab in the API docs for the exact, current values before you hardcode a rate-limit assumption into production retry logic.
What integration actually costs you in engineering time
The four-step flow is genuinely simple, but "simple API" and "zero engineering work" aren't the same claim. A production-grade integration — as opposed to a one-off script — realistically needs:
- Backoff on polling, not a tight loop. Checking status every second across a fleet of concurrent requests is how you find the rate limit the hard way.
- Handling
STATUS_CANCELas a real outcome, not justSTATUS_OK. A number can expire or get canceled without a code ever arriving, and your code needs a path for that. - Parsing free-text message bodies. The status response returns the actual SMS text, not a normalized "here is the code" field — different services format their codes differently, so you're pattern-matching against real message content.
- Balance and pool-exhaustion handling.
GET /balanceand a400/503on/buy-numberfor insufficient funds or no available numbers are both conditions a resilient integration checks for, not edge cases to ignore. - Key rotation and storage discipline — never in client-side code, rotated on a schedule, revoked immediately if one leaks. This is generic API hygiene, but it's the first thing to skip under deadline pressure, and it's the first thing that bites you later. See harden your verification flow for the fuller security checklist.
- A retry/release strategy for numbers that don't work out —
POST /numbers/{number_id}/repeatgets you a fresh number with the same parameters, which is the pattern to reach for instead of writing a bespoke retry loop.
None of this is exotic. It's the same category of work as integrating any third-party REST API with a rate limit and a polling model — a day or two for a first working integration, more if you're building the CI/staging harness described above around it.
One-time or a longer-lived number, through the API
The same POST /buy-number call provisions a number whether you need it for a single code or expect to keep using it. If your use case is closer to a persistent, ongoing inbox rather than a single verification, read the full one-time-vs-rental comparison before you assume the API endpoints work identically for both — rental-specific management may differ from what's documented for one-time provisioning, so confirm the current parameter set against the reference before you build around a long-term assumption.
Pricing follows the same demand-based model either way — a country and service with heavy demand costs more than one that doesn't, and that's true whether you're buying one number or renting one for weeks. How demand-based pricing actually works covers the mechanism in more depth than fits here.
Getting started
The shortest path from nothing to a verified code:
- Create an account and generate an API key from the dashboard's API Keys section — it's shown once, so store it immediately.
- Call
GET /countriesandGET /servicesto see what's available for the country/service pair you need (coverage spans 184 countries; see current pricing for how per-country, per-service demand pricing works). - Call
POST /buy-numberwith your chosen country and service. - Poll
GET /numbers/{number_id}/statusuntil you seeSTATUS_OK:followed by the code. - Use the code, then cancel the number if you're done with it — or let the automatic balance credit handle it if nothing arrived within the window.
From there, the full endpoint reference has every request/response shape, the complete error-code table, and copy-paste examples in cURL, JavaScript, and Python.
Frequently asked questions
Is there a sandbox or test mode?
Not a separate, documented sandbox environment as of this writing — check the current API docs before building CI around that assumption. In practice, a cheap one-time number against a low-traffic service functions as a low-stakes test: you can provision, verify, and release it the same way you would in a real integration, without a dedicated mock endpoint.
How is this different from Twilio Verify or Vonage Verify?
Those products send a one-time code to a number your user already owns — you're the sender. VerifyPulse's API provisions a number for you to receive on. If you're adding OTP login to your own app for your own users, a CPaaS Verify product is the right tool. If you need a working number to receive a code — for testing or to complete someone else's verification — that's this API's job.
Can I use this for CI or staging tests without a real phone?
Yes — that's one of the more common reasons developers reach for it. Provision a number through POST /buy-number inside your test setup, poll for the code, feed it into the flow you're testing, then release the number when the run finishes. No personal device or shared test-account number required.
Does this API support webhooks, or only polling?
Only polling, per the current published reference — GET /numbers/{number_id}/status on an interval. There's no documented webhook-registration endpoint today. If push delivery matters for your architecture, verify the current endpoint list in the API docs rather than assuming it exists.
Do I need a long-term number for API use, or can I request one-time?
The same purchase endpoint provisions numbers for either case. If your integration needs an ongoing inbox rather than a single code, read the full one-time-vs-rental comparison and confirm the current rental-specific parameters against the reference docs before assuming identical behavior to a one-time request.
Get an API key and start integrating
The fastest way to know whether this API fits your integration is to read the reference and try one call. Read the full API docs for every endpoint, parameter, and error code, or go straight to get an API key and provision your first number.