◈OTPProvider
Sign in

API Docs

Create an API key in your dashboard and send it as a Bearer token. Keys are shown once.

Authentication

Authorization: Bearer otp_live_<48 hex characters>

Send an email OTP

curl -X POST https://otpprovider.com/api/v1/email-otp/send \
  -H "Authorization: Bearer $OTP_KEY" -H "Content-Type: application/json" \
  -d '{"to":"user@example.com","idempotency_key":"signup-8841"}'
// Node.js
const r = await fetch('https://otpprovider.com/api/v1/email-otp/send', {
  method: 'POST',
  headers: { Authorization: 'Bearer ' + process.env.OTP_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({ to: 'user@example.com' }),
});
const { data } = await r.json();   // data.id is the request_id used to verify
# Python
import os, requests
r = requests.post("https://otpprovider.com/api/v1/email-otp/send",
    headers={"Authorization": "Bearer " + os.environ["OTP_KEY"]},
    json={"to": "user@example.com"})
print(r.json()["data"]["id"])

Endpoints

POST/api/v1/email-otp/sendBody: { "to": "user@example.com", "idempotency_key"?: string }
POST/api/v1/email-otp/verifyBody: { "request_id": "<id from send>", "code": "123456" }
POST/api/v1/whatsapp-otp/sendBody: { "to": "+201234567890", "idempotency_key"?: string }. Returns 202 (queued).
POST/api/v1/whatsapp-otp/verifyBody: { "request_id": "<id>", "code": "123456" }
POST/api/v1/email-validation/checkBody: { "email": "user@example.com" }
POST/api/v1/email-validation/batchBody: { "emails": [ ... up to the configured batch limit ] }
GET/api/v1/accountAccount summary.
GET/api/v1/account/balanceWallet balance.
GET/api/v1/account/usageUsage counts per service.
GET/api/v1/account/transactionsLedger entries.
GET/api/v1/account/messagesMessage history. Query: id, limit (max 200).

Responses

// success
{ "success": true, "request_id": "req_…", "data": { … } }
// error
{ "success": false, "request_id": "req_…", "error": { "code": "INSUFFICIENT_BALANCE", "message": "…" } }
401UNAUTHENTICATED / INVALID_API_KEY
402INSUFFICIENT_BALANCE
403ACCOUNT_NOT_ACTIVE / SERVICE_NOT_ALLOWED / KEY_SCOPE
422VALIDATION_ERROR / INVALID_PHONE
429RATE_LIMITED
502Provider rejected or the outcome is uncertain: check status before retrying
503SERVICE_DISABLED / MAINTENANCE / NO_PROVIDER

Statuses

QUEUED, PROCESSING, SUBMITTED, SENT, DELIVERED, READ, REJECTED, FAILED, EXPIRED, UNKNOWN_OUTCOME. SUBMITTED means the provider accepted the request, not that it reached the inbox. Only states actually reported by the provider or device are shown.

Use idempotency_key so a retried request never sends or charges twice. If a request ends in UNKNOWN_OUTCOME, check GET /account/messages before sending again.