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.