Verify
Phone verification in two calls. Delivered generates the code, sends it, enforces expiry and attempt limits, and defends against SMS pumping. You never store a code — and you don't need to own a phone number.
The whole integration
Two calls, no dependency required:
const send = (to) => fetch('https://api.deliveredsms.com/v1/verify', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.DELIVERED_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ to }),
}).then((r) => r.json());
const check = (to, code) => fetch('https://api.deliveredsms.com/v1/verify/check', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.DELIVERED_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ to, code }),
}).then((r) => r.json());Or from the terminal — the CLI ships inside the SDK package, so npx needs
no install at all:
DELIVERED_API_KEY=ghost_sk_test_... npx deliveredsms verify +14155550132
npx deliveredsms verify +14155550132 482193 # check the codeOr with the official SDK, which adds retries, typed errors and automatic idempotency keys:
npm install deliveredsmsimport { Delivered } from 'deliveredsms';
const delivered = new Delivered(process.env.DELIVERED_API_KEY);
await delivered.verify.send({ to: '+14155550132' });
const { verified } = await delivered.verify.check({ to: '+14155550132', code });Send a code
curl -X POST https://api.deliveredsms.com/v1/verify \
-H "Authorization: Bearer dsms_sk_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "phone": "+14155550132" }'{
"id": "ver_a1B2c3D4e5F6g7H8",
"object": "verification",
"phone": "+14155550132",
"status": "pending",
"attempts": 0,
"charged": false,
"expires_at": "2026-08-07T12:10:00.000Z"
}Optional app_name (24 chars max) puts your product's name in the message.
The body is a fixed Delivered template — you can't set the text, which is what
keeps verification traffic out of spam filtering.
You don't need a phone number
Verify sends from Delivered's own verification numbers, registered under our 10DLC campaign. You don't buy a number, you don't provision anything, and you pay no monthly number fee — verification is the whole product.
The same recipient always gets codes from the same sender, so a second code lands in the thread they already have.
If you'd rather codes came from a number you own, pass it as from:
{ "phone": "+14155550132", "from": "+16155550184" }Check the code
curl -X POST https://api.deliveredsms.com/v1/verify/check \
-H "Authorization: Bearer dsms_sk_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "phone": "+14155550132", "code": "482193" }'{ "verified": true, "status": "approved", "attempts": 1, "charged": true }That's the whole integration.
You only pay when it works
A verification is billed only when a code is actually verified. Wrong
codes, expiries, abandoned flows and anything Shield blocks are free —
every response tells you plainly with charged.
Rules Delivered enforces for you
| Code lifetime | 10 minutes |
| Check attempts | 5, then the code is dead |
| Resend cooldown | 60 seconds per number |
| Per number | 5 an hour, 10 a day |
Statuses: pending, approved, expired, max_attempts, blocked.
Shield
SMS pumping is fraud where someone farms revenue-share by triggering verification codes to numbers they control. Delivered blocks it before you're charged:
- US and Canada only. Country code +1 also covers Jamaica, the Dominican Republic and the Bahamas — the classic pumping destinations. We allowlist real US and Canadian area codes and reject the rest.
- Velocity limits per destination, per account and per source.
- No VoIP. Disposable VoIP numbers are rejected.
Blocked attempts return 403 with code verification_blocked, a reason,
and charged: false.
Sandbox
Test keys never send a real message. Any code you send returns a verification
whose code is 111111, and these codes are deterministic:
| Code | Result |
|---|---|
111111 | approved |
000000 | invalid |
222222 | expired |
333333 | max attempts |
Sandbox has no resend cooldown, so you can iterate on a "resend code"
button freely. Live enforces 60 seconds per number. To test that path
deterministically, send to +15005550003 — it always returns the cooldown
429 with retry_after in the body.
Retrieve a verification
GET /v1/verify/{id} returns the object with its current status, attempt
count, and whether it was charged.