One-time codes
Esemes Gateway makes, sends, stores (hashed) and checks the code. You never handle it.
1. Send a code
curl https://sms.bizmakers.app/v1/otp -H "Authorization: Bearer $ESEMES_KEY" -H "Content-Type: application/json" \
-d '{"to": "5123 4567", "purpose": "login"}'
{"otp_id": "8c1e…", "message_id": "…", "to": "+23051234567", "expires_at": "…"}
Optional: length (4-10, default 6), ttl_seconds (60-1800, default 300), template + params (your template
gets {{.code}} and {{.minutes}}), idempotency_key. Default text:
"123456 is your verification code. It expires in 5 minutes. Do not share it."
2. Check what the person typed
curl https://sms.bizmakers.app/v1/otp/verify -H "Authorization: Bearer $ESEMES_KEY" -H "Content-Type: application/json" \
-d '{"otp_id": "8c1e…", "code": "123456"}'
{"valid": true}
or {"valid": false, "reason": "incorrect", "attempts_left": 4}. Reasons: incorrect, expired_or_used,
too_many_attempts, not_found. You can also verify by {"to": "...", "purpose": "login", "code": "..."} (the latest
live code for that number).
Rules
- 5 attempts per code, single use, expires after
ttl_seconds. - 30 seconds between sends to the same number and purpose (
429 otp_cooldown), 5 per hour (429 recipient_rate_limited). - Codes still go to people who opted out, so they can always log in.
- With a test key the answer also contains
test_code, so automated tests can verify without a phone.
Do it on your server
Call both endpoints from your backend. A typical flow: the user enters a phone number → your server calls /v1/otp
and keeps otp_id in the session → the user types the code → your server calls /v1/otp/verify and only then
marks the number verified or logs them in.