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:

js
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:

bash
DELIVERED_API_KEY=ghost_sk_test_... npx deliveredsms verify +14155550132
npx deliveredsms verify +14155550132 482193   # check the code

Or with the official SDK, which adds retries, typed errors and automatic idempotency keys:

bash
npm install deliveredsms
js
import { 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

bash
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" }'
json
{
  "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:

json
{ "phone": "+14155550132", "from": "+16155550184" }

Check the code

bash
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" }'
json
{ "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 lifetime10 minutes
Check attempts5, then the code is dead
Resend cooldown60 seconds per number
Per number5 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:

CodeResult
111111approved
000000invalid
222222expired
333333max 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.