OTP Authentication
Send verification codes via WhatsApp Authentication templates
WhatsApp Authentication templates provide a secure, high-delivery-rate channel for sending one-time passwords (OTP) and verification codes. This guide covers creating, submitting, and sending OTP messages.
Overview
Authentication templates are purpose-built for verification codes:
- High delivery rates - WhatsApp messages have 98%+ open rates
- Instant delivery - Codes arrive in seconds
- User-friendly - Copy button or auto-fill on Android
- Cost-effective - Lowest messaging rates of all template categories
- Secure - End-to-end encrypted delivery
Prerequisites
Before creating OTP templates, ensure you have:
Your Meta Business account must be verified
A sender with WhatsApp Business Account configured
Valid payment method configured in Meta Business Manager
A Zavu API key for your project
Step 1: Create OTP Template
Via Dashboard
- Navigate to Senders in your dashboard
- Select the sender with WhatsApp connected
- Go to the Templates tab
- Click Create Template
- Configure the template:
- Name: Use a descriptive name like
otp_verification - Channel: Select WhatsApp only
- Category: Select AUTHENTICATION
- Language: Choose your language (e.g.,
en)
- Name: Use a descriptive name like
- Configure the OTP button:
- Button Type: Choose
Copy CodeorOne-Tap(Android only)
- Button Type: Choose
- Optional settings:
- Enable Security Recommendation to add "Do not share this code"
- Set Code Expiration (1-90 minutes)
- Click Create
Via API
import Zavudev from '@zavudev/sdk';
const zavu = new Zavudev({
apiKey: process.env["ZAVUDEV_API_KEY"],
});
const template = await zavu.templates.create({
name: 'otp_verification',
language: 'en',
body: '{{1}} is your verification code.',
category: 'AUTHENTICATION',
buttons: [{
type: 'otp',
text: 'Copy code',
otpType: 'COPY_CODE'
}],
addSecurityRecommendation: true,
codeExpirationMinutes: 10
});
console.log('Template ID:', template.id);
console.log('Status:', template.status); // "draft"
Step 2: Submit for Meta Approval
Authentication templates typically receive fast approval (within hours).
Via Dashboard
- Go to Senders > Select sender > Templates tab
- Find your template with "Draft" status
- Click the ... menu and select Submit for Approval
Via API
await zavu.templates.submit({
templateId: template.id,
senderId: 'sender_abc123'
});
// Check status
const updated = await zavu.templates.retrieve({
templateId: template.id
});
console.log('Status:', updated.status); // "pending" -> "approved"
Expected Approval Time
| Template Type | Typical Approval Time |
|---|---|
| AUTHENTICATION | 1-4 hours |
| UTILITY | 24-48 hours |
| MARKETING | 24-72 hours |
Step 3: Send OTP Messages
Once approved, send verification codes to users:
import Zavudev from '@zavudev/sdk';
const zavu = new Zavudev({
apiKey: process.env["ZAVUDEV_API_KEY"],
});
// Generate your OTP code
const otpCode = '123456';
const message = await zavu.messages.send({
to: '+14155551234',
messageType: 'template',
content: {
templateId: 'tmpl_abc123',
templateVariables: {
'1': otpCode // The OTP code
}
}
});
console.log('Message ID:', message.id);
console.log('Status:', message.status);
What the User Sees
The user receives a message like:
Code123456 is your verification code. For your security, do not share this code. This code expires in 10 minutes. [Copy code]
OTP Button Types
COPY_CODE (Recommended)
The Copy Code button allows users to tap and copy the code to their clipboard.
TypeScriptbuttons: [{ type: 'otp', text: 'Copy code', otpType: 'COPY_CODE' }]
Benefits:
- Works on all platforms (iOS, Android, Web)
- Simple user experience
- No additional configuration required
ONE_TAP (Android Only)
The One-Tap button enables automatic code filling in your Android app.
TypeScriptbuttons: [{ type: 'otp', text: 'Copy code', otpType: 'ONE_TAP', packageName: 'com.yourcompany.app', signatureHash: 'K8a+W1234...' }]
Requirements:
- Android app only
- Must provide
packageName(Android package name) - Must provide
signatureHash(Android app signature hash)
How to get your signature hash:
- In your Android app, use the SMS Retriever API helper:
JAVAAppSignatureHelper helper = new AppSignatureHelper(context); ArrayList<String> signatures = helper.getAppSignatures(); // Use the first signature String signatureHash = signatures.get(0);
- The hash is an 11-character string like
K8a+W1234ab
Template Options
Security Recommendation
Add a security disclaimer to your OTP message:
TypeScriptaddSecurityRecommendation: true
This adds: "For your security, do not share this code."
Code Expiration
Display when the code expires:
TypeScriptcodeExpirationMinutes: 10 // 1-90 minutes
This adds: "This code expires in 10 minutes."
Best Practices
Set expiration to 5-10 minutes for security. Shorter is better.
Always enable addSecurityRecommendation to protect users from phishing.
Use cryptographically secure random number generators for OTP codes.
Limit OTP requests per user to prevent abuse (e.g., 5 per hour).
OTP Code Guidelines
- Use 6-digit numeric codes for balance of security and usability
- Generate codes using secure random functions
- Store codes with expiration timestamps
- Invalidate codes after successful verification
- Limit verification attempts (e.g., 3 tries per code)
TypeScript// Example: Generate secure OTP import crypto from 'crypto'; function generateOTP(): string { return crypto.randomInt(100000, 999999).toString(); }
Common Issues
| Issue | Solution |
|---|---|
| Template rejected | Ensure category is AUTHENTICATION and content is purely verification-related |
| Code not displaying | Check that variable {{1}} is provided in templateVariables |
| One-Tap not working | Verify packageName and signatureHash are correct for your Android app |
| Slow delivery | Check recipient's WhatsApp status and your sender's quality rating |
| Button not showing | Ensure the template has buttons configured with OTP type |
Webhook Events
Track OTP delivery status via webhooks:
JSON{ "id": "evt_1702000000000_abc123", "type": "message.delivered", "timestamp": 1702000000000, "data": { "messageId": "msg_xyz789", "to": "+14155551234", "channel": "whatsapp", "status": "delivered" } }
Configure webhooks to receive:
message.sent- OTP accepted by WhatsAppmessage.delivered- OTP delivered to devicemessage.failed- Delivery failed
See Webhooks Guide for setup instructions.