// otp

OTP verification

Two calls handle phone verification. POST /v1/otp generates a 6-digit code and sends it; POST /v1/otp/verify checks what the user typed. You never see or store the code.

Send a code

curl -X POST https://sms-api.ekrasunya.com/v1/otp \
  -H "X-API-Key: eksms_..." \
  -H "Content-Type: application/json" \
  -d '{
    "to": "9818000000",
    "channels": ["device", "sms"],
    "brand": "Acme"
  }'

The response names the first channel tried. Keep to for the verify call.

{
  "status": "success",
  "statusCode": 201,
  "message": "OK",
  "data": {
    "id": "6f1c2a8e-3b4d-4e5f-9a10-2b3c4d5e6f70",
    "to": "9818000000",
    "channel": "device",
    "expiresInMinutes": 10
  }
}

The recipient receives:

Acme: Your verification code is 481920. It expires in 10 minutes. Do not share it with anyone.

Parameters

FieldRequiredDescription
toYesNepali mobile number, 10 digits starting with 9. A +977 or 977 prefix is accepted.
channelsNoChannels to try, in order: sms (the A2P route) and device (your enrolled phones running the EK SMS Gateway app). Default ["sms"].
senderIdNoSender ID for the sms channel, same rule as Send a message.
brandNoYour app or company name, up to 30 characters, shown before the code.

Channel fallback

The code goes out on the first channel in channels. It moves to the next channel when the current one reports the message failed, or when no phone has picked up a device send within 60 seconds.

Each fallback sends a new code, and the earlier one stops working. A user holding an older code sees OTP_INVALID and should use the latest message.

Cheapest first

["device", "sms"] tries your own SIM first and only pays the A2P rate when the phone is offline or the send fails.

Check a code

curl -X POST https://sms-api.ekrasunya.com/v1/otp/verify \
  -H "X-API-Key: eksms_..." \
  -H "Content-Type: application/json" \
  -d '{ "to": "9818000000", "code": "481920" }'

A correct code returns verified: true once. Every failure returns 400 with code OTP_INVALID and a message you can show the user: wrong code, expired, already used, or too many attempts.

Limits

RuleValue
Code length6 digits
Valid for10 minutes
Wrong attempts per code5, then request a new code
Codes per number5 per rolling 24 hours (OTP_RATE_LIMITED, 429)
Codes that countOnly the newest code for a number. A new request replaces the old one.

Billing

Each channel attempt is billed as one ordinary message at that route's rate. A code that falls back from device to sms is charged for both sends; a send that fails is refunded. Verify calls are free.

Sends pass the same checks as POST /v1/messages: API key scope messages:send, KYC, sender ID, balance, daily spend limit and the new-account limits. A request rejected by one of these does not count toward the daily limit.


Next: Error codes · Delivery & webhooks