Send a verification code

POST /v1/verify

Generates a one-time code, sends it, and enforces expiry, attempt limits and anti-pumping controls. You do NOT need to own a phone number; SimpleSMS sends from its own verification pool. Nothing is billed here; a verification is charged only when the code is checked successfully. Supports the Idempotency-Key header, so a retried request does not text a second code.

Send your API key as a bearer token: Authorization: Bearer ssms_sk_.... Test keys run this endpoint against the sandbox; see Authentication for key modes and scopes.

Headers

NameTypeRequiredDescription
Idempotency-KeystringNoMakes retries safe for 24 hours: the same key and body replays the original successful response (with Idempotent-Replayed: true); a different body returns 409. Failed requests release the key. At most 255 characters.

Request body

JSON (Content-Type: application/json).

FieldTypeRequiredDescription
phonestringYesExample: +14155550132.
app_namestringNoYour product name, shown in the message At most 24 characters.
fromstringNoOptional: send from a number you own instead of the SimpleSMS pool
customer_idstringNoOptional: attribute the verification to one of your customers

Responses

StatusMeaningBody
201Verification createdVerification
401Missing, malformed, or revoked API keyError
402Billable live calls only: the prepaid credit balance cannot cover the call (insufficient_credits); nothing was done or chargedError
403Blocked by Shield (charged: false)Error
409Idempotency conflictError
429Rate limit or quota exceededError

201: Verification fields

FieldTypeDescription
idstringExample: ver_a1B2c3D4e5F6g7H8.
objectverification
phonestring
statuspending, approved, expired, max_attempts, blocked
attemptsinteger
testboolean
chargedboolean
created_atstring (date-time)
expires_atstring (date-time)
customer_idstringThe customer this is attributed to. Present only when set.

Errors

StatusWhen
401Missing, malformed, or revoked API key
402Billable live calls only: the prepaid credit balance cannot cover the call (insufficient_credits); nothing was done or charged
403Blocked by Shield (charged: false)
409Idempotency conflict
429Rate limit or quota exceeded

Every error has the same JSON shape, and request_id matches the X-Request-Id response header. Errors lists every code and what to do about it.

json
{
  "error": {
    "code": "invalid_request",
    "message": "What went wrong, in plain words.",
    "param": "the_field",
    "request_id": "req_a1B2c3D4e5F6g7H8"
  }
}

Idempotency

Send an Idempotency-Key header to make retries safe. For 24 hours the same key with the same body replays the original successful response (with Idempotent-Replayed: true); the same key with a different body returns 409. A failed request releases its key.

Examples

curl

bash
curl -X POST "https://api.joinsimplesms.com/v1/verify" \
  -H "Authorization: Bearer $SIMPLESMS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2f0e-order-1042" \
  -d '{
  "phone": "+14155550132"
}'

Node.js

javascript
import { SimpleSMS } from 'joinsimplesms'; // npm install joinsimplesms

const sms = new SimpleSMS(process.env.SIMPLESMS_API_KEY);

const verification = await sms.verify.send({ to: '+14155550132' });

console.log(verification.id, verification.status);

Python

python
import os
from joinsimplesms import SimpleSMS  # pip install joinsimplesms

client = SimpleSMS(os.environ["SIMPLESMS_API_KEY"])

verification = client.verify.send("+14155550132")

print(verification["id"], verification["status"])