OTP Flow

API documentation

The OTP Flow API has two core endpoints: POST /send-otp delivers a code by SMS and returns an otp_id; POST /verify-otp checks the code your user typed. Base URL: https://otpflow.in. A machine-readable OpenAPI 3.1 spec is available.

Authentication

Create an API key in your dashboard and send it as a Bearer token. Never expose keys in browsers or mobile apps — call the API from your server.

http
Authorization: Bearer otpf_xxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

Send OTP

POST https://otpflow.in/send-otp

FieldTypeDescription
numberstringrequired10 digit Indian mobile number starting with 6–9. No country code.
purposestringrequired3–40 characters describing why the OTP is sent (e.g. login, registration). Shown in the SMS template.
ttlintegeroptionalTime-to-live in minutes, 5–120. Default 10.
otpstringoptionalYour own numeric OTP, 3–40 digits. Send as a string to preserve leading zeros. If omitted we generate one.
otp_lengthintegeroptionalLength of the generated OTP (3–40). Used only when otp is not provided. Default 6.
cURL
curl -X POST https://otpflow.in/send-otp \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"number":"9876543210","purpose":"login","ttl":10,"otp_length":6}'

Response 200

json
{
  "success": true,
  "message": "OTP sent successfully",
  "otp_id": "otp_k3J9xQ2mP0aZ7Vb1",
  "number": "9876543210",
  "purpose": "login",
  "ttl": 10,
  "expires_at": "2026-01-01T10:10:00.000Z",
  "cost": 0.4,
  "balance": 99.6
}

Store the otp_id — you need it to verify. The OTP value itself is never returned by the API.

Verify OTP

POST https://otpflow.in/verify-otp

FieldTypeDescription
otp_idstringrequiredThe id returned by /send-otp.
otpstringrequiredThe code entered by your user.
cURL
curl -X POST https://otpflow.in/verify-otp \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"otp_id":"otp_k3J9xQ2mP0aZ7Vb1","otp":"123456"}'

Success 200

json
{ "success": true, "message": "OTP verified", "otp_id": "otp_k3J9xQ2mP0aZ7Vb1", "verified": true }

Wrong code 400

json
{ "success": false, "error": "invalid_otp", "message": "Incorrect OTP. 4 attempt(s) left." }

Each OTP can be verified once and allows up to 5 attempts before it is locked.

Check balance

GET https://otpflow.in/balance

json
{ "success": true, "balance": 250.5, "currency": "INR", "rate_per_otp": 0.6 }

Errors

Errors return a non-2xx status and a JSON body with success: false, a stable error code and a human readable message.

HTTPerrorMeaning
401unauthorizedMissing or invalid API key
402insufficient_balanceWallet balance is lower than your per-OTP rate
403forbiddenAccount suspended
404otp_not_foundUnknown otp_id
409otp_already_usedOTP was already verified
410otp_expiredTTL elapsed; request a new OTP
422validation_errorInvalid or missing fields
429rate_limited / too_many_attemptsSlow down or request a new OTP
502sms_failedCarrier rejected the SMS. You were not charged

Limits & security

  • Max 5 OTPs per destination number per 10 minutes, 120 requests/min per account.
  • OTPs are encrypted at rest (AES-256-GCM) and compared in constant time.
  • Maximum 5 verification attempts per OTP; OTPs are single-use.

Billing

Your wallet is debited your per-OTP rate when an OTP is sent. If the SMS fails to be accepted by the carrier, the amount is refunded immediately. See pricing for volume tiers.