Skip to main content
The Verify API sends a one-time code to a phone number and checks the code your user enters.
Base URL
Verify endpoints are also available under /v1/*.

Supported countries

Numbers are routed automatically to the right carrier in each country:

How codes are protected

  • Secure generation: codes are generated from cryptographically secure random bytes.
  • No plaintext storage: codes are hashed server-side with HMAC-SHA256 and a per-session salt. Plaintext codes are never stored in the database.
  • Constant-time checks: submitted codes are compared in constant time (crypto.timingSafeEqual) to prevent timing attacks.
  • Automatic refunds: wallet units are reserved before the OTP is sent. If the carrier fails to deliver it (SMS_DELIVERY_FAILED), the reserved units are refunded automatically.

Authentication

All /verify/* endpoints accept any of these authentication methods: See Authentication for how to get your credentials.

Verify a phone number

1

Start a verification

POST /verify/start sends an OTP to the phone number.
Response (200 OK)
Save the returned verification_id. You need it to check the code.
2

Check the code

POST /verify/check checks the code your user entered.

Resends and rate limits

Resend a code

To resend an OTP, call POST /verify/start again with the same phone_number after the resend_after time has passed. The default cooldown is 60 seconds. If you call it before resend_after, the API returns 429 COOLDOWN_ACTIVE, and error.retry_after_seconds tells you how many seconds remain.

Anti-abuse limits

Sandbox testing

Test the full flow for free, without spending SMS balance. Send POST /verify/start to one of these sandbox numbers: You can also use a test mode Verify Service (is_test_mode: true) or a test API key. In sandbox and test mode:
  • cost_units is 0.
  • No real SMS is sent.
  • Submitting "code": "123456" to POST /verify/check always returns "status": "approved".

Verify Services

A Verify Service controls the message template, Sender ID, code length, expiry, and limits for your OTPs. Use separate services for different flows, such as login and password reset.

Create a service

POST /verify/services (or POST /verify/apps) creates a Verify Service.

Manage services, sessions, and analytics

PUT /verify/services/{id} accepts template, senderId, codeLength, expirySeconds, resendCooldownSeconds, maxAttempts, isActive, and isTestMode. GET /verify/sessions supports these query filters: GET /verify/analytics returns totalRequests, successfulVerifications, successRate, incorrectAttempts, expiredSessions, lockedSessions, and deliveryFailures.

Verify errors