DocsWhatsApp OTP API

WhatsApp OTP API

Send and verify one-time passwords (OTPs) via WhatsApp using OutreachAgent's Meta BSP direct connection. 98%+ delivery, ~1.5s average latency, with automatic SMS fallback via Twilio.

Meta BSP DirectREST APISMS FallbackWebhook Events

Overview

The OutreachAgent WhatsApp OTP API lets you authenticate users via WhatsApp instead of SMS. Your server makes a single API call; the user receives a WhatsApp message with a code; your server verifies it. No WABA setup required on your end — we handle all Meta infrastructure.

How it works

1Your server calls POST /v1/whatsapp/otp/send with the user's phone number
2OutreachAgent generates a secure OTP and delivers it via Meta's Cloud API
3User receives a WhatsApp message with the OTP code (via your approved template)
4User enters code → your server calls POST /v1/whatsapp/otp/verify → get { valid: true/false }

Prerequisites

  • • Active OutreachAgent workspace with the WhatsApp module (m2_whatsapp) enabled
  • • At least one approved Meta OTP template (we create a default one for you on signup)
  • • An API key from Settings → WhatsApp OTP
  • • Sufficient credit balance (1 credit per OTP send)

Authentication

All API requests use Bearer token authentication. Include your API key in the Authorization header:

Request Header
HTTP
Authorization: Bearer oat_YOUR_API_KEY
Get your API key: Navigate to Settings → WhatsApp OTP in your dashboard. API keys start with oat_ and are scoped to your workspace. Never expose your API key in client-side code.

Send OTP

POST/v1/whatsapp/otp/send

Generates a cryptographically secure OTP and delivers it via WhatsApp to the specified phone number. Returns an otp_id used to verify the code later.

Request Body Parameters

ParameterTypeRequiredDescription
phonestringYesPhone number in E.164 format (+919876543210)
templatestringNoMeta-approved OTP template name. Defaults to otp_verification
lengthintegerNoOTP length: 4, 6, or 8 digits. Defaults to 6
expires_inintegerNoExpiry in seconds (60–900). Defaults to 300 (5 min)
fallback_smsbooleanNoIf true and WA delivery fails, falls back to SMS (requires m3_sms module). Defaults to false
metadataobjectNoCustom key-value pairs stored with the OTP (e.g., user_id, session_id)
Send OTP — Request
curl
curl -X POST https://api.outreachagent.com/v1/whatsapp/otp/send \
  -H "Authorization: Bearer oat_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "template": "otp_verification",
    "length": 6,
    "expires_in": 300,
    "fallback_sms": true
  }'
Send OTP — Response (200 OK)
json
{
  "success": true,
  "otp_id": "otp_01HXK7QZRN8V4M2P9D3Y5F6G7H",
  "channel": "whatsapp",
  "phone": "+919876543210",
  "expires_at": "2026-06-02T19:17:32Z",
  "expires_in": 300,
  "message_id": "wamid.HBgMOTE5ODc2NTQz..."
}

Verify OTP

POST/v1/whatsapp/otp/verify

Verifies a submitted OTP code against an existing otp_id. Each OTP can be verified at most 3 times before it is permanently invalidated.

Request Body Parameters

otp_idstringYesThe otp_id returned from the /send call
codestringYesThe code submitted by the user
Verify OTP — Request
curl
curl -X POST https://api.outreachagent.com/v1/whatsapp/otp/verify \
  -H "Authorization: Bearer oat_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "otp_id": "otp_01HXK7QZRN8V4M2P9D3Y5F6G7H",
    "code": "482915"
  }'
Verify OTP — Response (200 OK, valid)
json
{
  "valid": true,
  "otp_id": "otp_01HXK7QZRN8V4M2P9D3Y5F6G7H",
  "phone": "+919876543210",
  "verified_at": "2026-06-02T19:14:18Z",
  "channel": "whatsapp"
}

Check OTP Status

GET/v1/whatsapp/otp/:otp_id

Retrieves the current status of an OTP. Useful for async verification flows or auditing. Status values: pending | delivered | verified | expired | failed

Check Status — Request
curl
curl https://api.outreachagent.com/v1/whatsapp/otp/otp_01HXK7QZRN8V4M2P9D3Y5F6G7H \
  -H "Authorization: Bearer oat_YOUR_API_KEY"
Check Status — Response
json
{
  "otp_id": "otp_01HXK7QZRN8V4M2P9D3Y5F6G7H",
  "status": "verified",
  "phone": "+919876543210",
  "channel": "whatsapp",
  "created_at": "2026-06-02T19:12:00Z",
  "expires_at": "2026-06-02T19:17:00Z",
  "verified_at": "2026-06-02T19:14:18Z",
  "attempts": 1,
  "fallback_used": false
}

SDK Examples

Node.js / TypeScript

Node.js SDK
typescript
import OutreachAgent from '@outreachagent/sdk';

const client = new OutreachAgent({ apiKey: process.env.OA_API_KEY });

// Send OTP
const { otp_id, channel } = await client.otp.send({
  phone: '+919876543210',
  template: 'otp_verification',
  length: 6,
  expiresIn: 300,
  fallbackSms: true,
});

console.log(`OTP sent via ${channel} — ID: ${otp_id}`);

// Verify OTP (when user submits the code)
const { valid } = await client.otp.verify({
  otp_id,
  code: userSubmittedCode,
});

if (valid) {
  // ✅ User is verified — proceed
} else {
  // ❌ Invalid code — show error
}

Python

Python SDK
python
import outreachagent

client = outreachagent.Client(api_key=os.environ['OA_API_KEY'])

# Send OTP
result = client.otp.send(
    phone='+919876543210',
    template='otp_verification',
    length=6,
    expires_in=300,
    fallback_sms=True
)

print(f"OTP sent via {result.channel} — ID: {result.otp_id}")

# Verify OTP
verification = client.otp.verify(
    otp_id=result.otp_id,
    code=user_submitted_code
)

if verification.valid:
    # ✅ User is verified
    pass

SDKs available for: Node.js, Python, PHP, Go, Ruby, Java. Install via npm i @outreachagent/sdk or pip install outreachagent. All SDKs are open-source on GitHub.

Webhooks

OutreachAgent sends webhook events to your endpoint for real-time OTP status updates. Configure your webhook URL in Settings → WhatsApp OTP.

Event Types

otp.sent

OTP successfully sent to WhatsApp

otp.delivered

WhatsApp confirmed the message was delivered to device

otp.verified

User submitted the correct OTP code

otp.expired

OTP expired without being verified

otp.failed

OTP delivery failed (and SMS fallback was not configured)

otp.sms_fallback

WhatsApp delivery failed — OTP was delivered via SMS fallback

Webhook Payload — otp.verified
json
{
  "event": "otp.verified",
  "timestamp": "2026-06-02T19:14:18Z",
  "data": {
    "otp_id": "otp_01HXK7QZRN8V4M2P9D3Y5F6G7H",
    "phone": "+919876543210",
    "channel": "whatsapp",
    "verified_at": "2026-06-02T19:14:18Z"
  }
}

Error Codes

HTTPError CodeDescription
400invalid_phonePhone number is not in E.164 format
400template_not_foundOTP template not found or not approved by Meta
401invalid_api_keyAPI key is missing, invalid, or expired
402insufficient_creditsWorkspace does not have enough credits to send OTP
403module_inactiveWhatsApp module (m2_whatsapp) is not active for this workspace
404otp_not_foundOTP ID does not exist or belongs to a different workspace
410otp_expiredOTP has expired (past expires_at timestamp)
422otp_already_verifiedOTP was already successfully verified
429rate_limit_exceededToo many OTP requests — see rate limits section
503meta_api_unavailableMeta WhatsApp API is temporarily unavailable (SMS fallback attempted if configured)

Rate Limits

10/s

OTP sends per second

Global per workspace

5

OTP sends per phone/hour

Anti-abuse limit

3

Verification attempts per OTP

Then OTP invalidated

Rate limit headers are returned on every response: X-RateLimit-Remaining, X-RateLimit-Reset. Enterprise plans have higher limits — contact sales.

FAQ

Do I need my own WhatsApp Business Account?

No. OutreachAgent is a Meta BSP — we provide the WABA infrastructure. Your customers receive messages from your branded sender name (configured in Settings).

How does SMS fallback work?

If WhatsApp delivery fails (user doesn't have WhatsApp, or Meta API timeout), and you have fallback_sms: true + the SMS module active, OutreachAgent automatically sends the same OTP via Twilio SMS. The API response will include channel: "sms" if fallback was used.

Is the OTP code generated on my server or OutreachAgent's?

OutreachAgent generates and stores the OTP securely. Your server only receives the otp_id. This is intentional — it prevents your server from needing to store sensitive codes.

What WhatsApp template is used?

OutreachAgent creates a default otp_verification template on your WABA during setup. It's pre-approved by Meta. You can create custom templates in Settings → WhatsApp OTP → Templates.

How much does each OTP cost?

Each OTP send deducts 1 credit from your workspace balance. Credits are included in your module plan. Check Settings → Billing for your current balance and per-credit price.

Can I use this for 2FA in my web/mobile app?

Yes — that's the primary use case. Your backend calls /send when a user triggers 2FA, and /verify when they submit the code. Never make these calls from client-side code.

Ready to integrate?

Get your API key and send your first WhatsApp OTP in under 5 minutes.