On this page
SMS pumping is fraud in which bots make your app send large numbers of text messages, usually one-time passcodes, to numbers that earn the attacker a share of every delivery fee. You pay for messages nobody reads. The fix is layered: limit who can trigger a text, where it can go, and check the number before you pay.
What is SMS pumping, exactly?
SMS pumping is a scheme to generate paid message traffic that has no real recipient. The telecom industry calls it artificially inflated traffic (AIT). Other names are SMS toll fraud and OTP abuse.
It works because every SMS creates money along its route. You pay your messaging provider. Your provider pays carriers and intermediaries, and the network that delivers the message to the handset collects a termination fee. If an attacker controls a block of numbers, or has a revenue-share deal with someone who does, every message sent to those numbers pays them.
The attacker doesn't need to break into anything. They only need a public form that sends an SMS to any number typed into it: sign-up, login with a code, "send me a download link", password reset. Bots fill that form thousands of times with numbers from the attacker's ranges. The codes are never entered, because nobody is waiting for them. Our glossary entry on SMS pumping has a shorter definition.
Why are OTP forms the favourite target?
A passcode form is built to send an SMS to a stranger, fast, with as little friction as possible. That's exactly what an attacker needs.
- No account required. The SMS is sent before the user has proven anything.
- Any destination accepted. Many forms take any international number, because blocking a real customer abroad feels worse than paying for a few extra texts.
- Resend buttons. "Didn't get the code?" invites repeated sends to the same number.
- Automatic retries. Some verification setups fall back from SMS to a voice call, which can add a second payout on expensive destinations.
The attack also hides well. On a dashboard it looks like growth: more sign-ups started, more codes sent. The problem shows up later, as an invoice.
Large platforms have acted on this publicly. In February 2023 Twitter said it had "seen phone-number based 2FA be used - and abused - by bad actors", and stopped offering SMS two-factor authentication to non-subscribers after 20 March 2023 (Twitter, 2023). Most companies can't simply switch SMS off, so they need controls instead.
What does a pumping attack look like in your data?
Pumping leaves a fingerprint. You'll usually see several of these signals at once:
| Signal | What it looks like | Why it points to pumping |
|---|---|---|
| Conversion collapse | Codes sent rise, codes verified stay flat | Nobody is receiving the codes |
| Country shift | Traffic to a destination you rarely serve | Attackers pick destinations with high fees |
| Range clustering | Many numbers share the first 7–9 digits | The attacker owns a block of numbers |
| Sequential numbers | …101, …102, …103 in minutes | Bots iterate through the block |
| Odd line types | Premium-rate, shared-cost or unallocated ranges | Real users rarely sign up with them |
| Burst timing | Hundreds of requests in a few minutes, often at night in your main market | Automated traffic |
| Rotating clients | Many IP addresses or user agents, few completed sessions | The bot is spreading out to dodge limits |
The single most useful metric is the verification rate per country: codes verified divided by codes sent. Real users verify most of their codes. A pumped destination verifies almost none. Alert on it per country and per hour, not as a global daily average, where a small attack disappears.
How do you stop SMS pumping with a layered checklist?
No single control is enough, because attackers adapt. Stack these layers so that each one catches what the previous one missed.
1. Limit who can trigger a send
- Put bot protection (a challenge or proof-of-work) in front of every endpoint that sends an SMS.
- Require a session that did something human first, such as loading the page and filling other fields.
- Delay the resend button (for example 30–60 seconds) and cap resends per session.
2. Rate-limit on several keys at once
- Per destination number: a few codes per hour, a small daily maximum.
- Per number prefix (the first digits of the national number): catches attacks that rotate through a block.
- Per IP address, device fingerprint and session.
- Per country: a ceiling on codes per hour, set from your normal traffic.
- A global daily spend cap on your SMS account, with an alert well below it.
3. Restrict destinations (geo permissions)
- Allow OTP only to countries where you have customers. Everything else needs a manual exception.
- Use your messaging provider's geographic permissions as a second, independent control.
- Treat a new country as a release decision, not a default.
4. Check the number before you pay
- Normalize to E.164 and reject numbers that can't exist. This is free.
- Look up the line type: don't send SMS codes to premium-rate, shared-cost, toll-free or fixed lines.
- Check whether the number has a messenger account the user can receive codes on, and whether the number is new to you.
5. Watch and respond
- Alert on verification rate per country and per prefix.
- Keep a kill switch per country that support staff can flip at night.
- Review the SMS invoice by destination every week, not every month.
How does a pre-send number check help?
Rate limits slow attackers down. A number check removes whole categories of pumped destinations before a single message is paid for.
The check runs between "user entered a number" and "we send a code". With MobileValidate, one POST /v1/lookup request can return the number's normalized form, its line type and carrier from the carrier lookup, and whether it has an account on a messenger such as WhatsApp. Here is a real test-mode example:
curl https://api.mobilevalidate.com/v1/lookup \
-H "Authorization: Bearer $MOBILEVALIDATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"numbers": ["+447700900001", "+447700900002"], "checks": ["carrier", "whatsapp"], "wait": 5}'Response (excerpt: the checks of both numbers):
[
{"e164": "+447700900001", "number_status": "valid",
"checks": {
"network.carrier": {"status": "completed", "registered": true,
"attributes": {"line_type": "mobile", "carrier": "Test Carrier", "country": "GB"}, "billed": false},
"whatsapp.registered": {"status": "completed", "registered": true, "billed": false}}},
{"e164": "+447700900002", "number_status": "valid",
"checks": {
"network.carrier": {"status": "unknown", "registered": null, "reason": "NO_DATA", "billed": false},
"whatsapp.registered": {"status": "completed", "registered": false, "billed": false}}}
]Your code then applies a rule per result. A premium_rate line type is a hard stop. A mobile number with a messenger account is a normal send. An unknown answer means "no data", so the flow continues with its default rules. It is never a reason to block, and it isn't charged.
Which rules should the pre-send check apply?
Keep the rules simple and explainable, so that support can tell a user why their code didn't arrive.
| Result | Suggested action |
|---|---|
number_status: invalid_number | Ask the user to correct the number; send nothing |
line_type is premium_rate, shared_cost or uan | Block the SMS |
line_type is fixed_line or toll_free | Offer a voice call or another method instead of SMS |
line_type is voip | Send, but with a lower per-number limit; see VoIP detection |
| Country not on your allow-list | Block, or send to manual review |
mobile with a messenger account the user chose | Send the code there or by SMS as usual |
Any check unknown or pending | Fall back to your default rules; don't block on missing data |
Two API behaviours help directly against pumping. First, requests with 20 or more numerically consecutive numbers are refused with 403 suspected_enumeration, which is the pattern a bot walking through a number block produces in batch tools. Second, repeat checks of the same number inside the freshness window come from your account's cache for free, so a bot hammering "resend" on one number doesn't multiply your check costs. You're not charged for inconclusive results (unknown, unsupported country, timeout, invalid, duplicate).
Should you move OTP away from SMS altogether?
Sometimes, partly. Every channel has trade-offs, and removing SMS entirely locks out users without a smartphone app.
NIST's current authentication guidance treats one-time codes sent over the phone network as a restricted authenticator. It says verifiers should consider risk indicators such as device swap, SIM change and number porting before sending a code that way (NIST, 2025). That guidance is about account security rather than cost, but it points the same way: use SMS where it's needed and with checks, not as the only option.
Practical options:
- Offer app-based codes (authenticator apps, passkeys) to returning users and make them the default after the first login.
- Deliver codes on a messenger the user already has, if they chose it. A messenger delivery doesn't create an SMS termination fee. Check that the number has an account first; see our WhatsApp check API guide.
- Keep SMS as a fallback, protected by every layer in the checklist above.
How do you size the problem before and after?
Measure before you change anything, so you can show that the controls worked.
- Baseline. For the last 90 days, export codes sent and codes verified per country and per week. Note the SMS cost per country from your invoice.
- Find the gap. Countries with a verification rate far below your main market's are candidates for pumping. Look for sudden jumps in volume in the same weeks.
- Estimate the waste. Unverified codes × cost per SMS in that country gives an upper bound of what pumping cost you. Some unverified codes are real users who gave up, so treat it as a ceiling.
- Roll out the layers, starting with the country allow-list and rate limits. They are cheap and fast to deploy.
- Compare. After two to four weeks, the verification rate in previously abused countries should rise and total SMS volume should fall, while sign-up completions in your main markets stay the same.
If completions in your main markets drop, a rule is too strict. Loosen it instead of piling on more friction.
What are the key takeaways?
- SMS pumping (artificially inflated traffic) makes you pay termination fees on messages sent to numbers the attacker profits from.
- The clearest signal is a collapsing verification rate in one country or number range. Monitor it per country and per hour.
- Layer the defences: bot protection, rate limits on number, prefix, IP and country, a country allow-list, a spend cap, and a pre-send number check.
- A number check removes impossible numbers and non-mobile line types before any SMS is paid for. Unknown results aren't charged and should never block a user.
- Offer app-based or messenger delivery where users choose it, and keep SMS as a protected fallback.
For a full implementation of the pre-send check, including multi-check requests and timeouts, read OTP fraud prevention: checks to run before sending a code. The OTP and sign-up fraud use case and SMS cost reduction pages show the same checks from a product angle.
Sources
Frequently asked questions
Is SMS pumping the same as artificially inflated traffic (AIT)?
Yes, in practice. Artificially inflated traffic is the industry term for messages generated only to earn termination fees. SMS pumping and SMS toll fraud describe the same scheme from the victim's side: bots trigger texts that nobody reads.
Which countries does SMS pumping target?
It follows the money, so it moves. Attackers favour destinations where terminating an SMS is expensive and where they have a share of the fee. The safest assumption is that any country you don't actively serve can be abused, so allow OTP only to the countries where you have customers.
Will a CAPTCHA alone stop SMS pumping?
It raises the cost of each attempt, but determined attackers solve challenges with humans or services. Combine bot protection with per-number, per-IP and per-country limits, a country allow-list and a check of the number before you send.
Does checking a number cost more than the SMS it prevents?
It depends on your SMS rates and prices. Invalid and duplicate numbers are found for free, and inconclusive checks are not charged. Run the check only on paths where an SMS would be sent, and compare its price with your cost per SMS in the countries you serve.
Related services and guides
More from the blog
All articlesFraud prevention
OTP fraud prevention: the checks to run before you send a code
A practical pre-send pipeline for one-time passcodes: normalize, check line type, messenger presence and reputation in one request, then decide.
8 min read
Fraud prevention
IRSF: international revenue share fraud, explained
How international revenue share fraud turns your calls and texts into someone else's income, how it differs from SMS pumping, and how to cap your exposure.
7 min read
Deliverability
WhatsApp OTP vs SMS OTP: cost per verified user, with a calculator
WhatsApp authentication rates vs SMS prices by country, the October 2026 changes, and a calculator for cost per verified user including SMS fallback.
7 min read


