OTP
Multi-channel one-time password (OTP) verification with support for email, SMS, and WhatsApp.
Send OTP
Send OTP codes across multiple channels simultaneously:
const result = await sendmator.otp.send({
channels: ['email', 'sms'],
recipients: {
email: 'user@example.com',
sms: '+14155552671'
}
});
console.log('Session ID:', result.data.session_id);
console.log('Expires at:', result.data.expires_at);
console.log('Channels:', result.data.channels);
Sandbox Mode
Enable sandbox mode to receive OTPs in the API response (for testing):
const result = await sendmator.otp.send({
channels: ['email'],
recipients: {
email: 'test@example.com'
},
sandbox_mode: true
});
// In sandbox mode, OTPs are returned in response
console.log('Email OTP:', result.data.otps?.email);
warning
Never use sandbox_mode in production. OTPs should only be sent to users, never returned in API responses.
Multi-Channel OTP
Send OTP through multiple channels for redundancy:
const result = await sendmator.otp.send({
channels: ['email', 'sms', 'whatsapp'],
recipients: {
email: 'user@example.com',
sms: '+14155552671',
whatsapp: '+14155552671'
},
add_contact: true // Automatically add to contacts after verification
});
Verify OTP
Verify the OTP codes provided by the user:
const result = await sendmator.otp.verify({
session_token: 'session-token-from-send-response',
otps: {
email: '123456',
sms: '123456'
}
});
if (result.data.verified) {
console.log('✅ OTP verified successfully');
console.log('Email verified:', result.data.verification_results.email?.success);
console.log('SMS verified:', result.data.verification_results.sms?.success);
} else {
console.log('❌ Verification failed');
}
Verify Single Channel
Verify OTP from a single channel:
const result = await sendmator.otp.verify({
session_token: sessionToken,
otps: {
email: '123456'
}
});
if (result.data.verified) {
// OTP is valid
console.log('Email verified!');
}
Resend OTP
Resend OTP using the same session:
const result = await sendmator.otp.resend({
session_token: 'session-token-from-send-response'
});
console.log('OTP resent to:', result.data.channels);
console.log('New expiry:', result.data.expires_at);
Complete Options
await sendmator.otp.send({
// Channels to send OTP (required)
channels: ['email', 'sms', 'whatsapp'],
// Recipients for each channel (required)
recipients: {
email: 'user@example.com',
sms: '+14155552671',
whatsapp: '+14155552671'
},
// Optional settings
add_contact: true, // Add verified contacts to contacts table
sandbox_mode: false, // Return OTPs in response (testing only)
metadata: { // Custom tracking data
purpose: 'login',
ip_address: '192.168.1.1'
}
});
Examples
Login Verification
async function loginWithOTP(email: string) {
// Step 1: Send OTP
const sendResult = await sendmator.otp.send({
channels: ['email'],
recipients: { email },
metadata: {
action: 'login',
timestamp: new Date().toISOString()
}
});
const sessionToken = sendResult.data.session_id;
// Store session token in session/database
return sessionToken;
}
async function verifyLoginOTP(sessionToken: string, code: string) {
// Step 2: Verify OTP
const verifyResult = await sendmator.otp.verify({
session_token: sessionToken,
otps: { email: code }
});
if (verifyResult.data.verified) {
// Grant access
return { success: true };
} else {
return { success: false, message: 'Invalid OTP' };
}
}
Phone Verification
async function verifyPhoneNumber(phone: string): Promise<string> {
const result = await sendmator.otp.send({
channels: ['sms'],
recipients: { sms: phone },
add_contact: true, // Add to contacts after verification
metadata: {
action: 'phone_verification'
}
});
return result.data.session_id;
}
async function confirmPhone(sessionToken: string, code: string): Promise<boolean> {
const result = await sendmator.otp.verify({
session_token: sessionToken,
otps: { sms: code }
});
return result.data.verified;
}
Multi-Factor Authentication (MFA)
async function sendMFACode(userId: string, userEmail: string, userPhone: string) {
// Send OTP through both email and SMS for added security
const result = await sendmator.otp.send({
channels: ['email', 'sms'],
recipients: {
email: userEmail,
sms: userPhone
},
metadata: {
user_id: userId,
action: 'mfa',
required_channels: 2 // Require both channels
}
});
return result.data.session_id;
}
async function verifyMFA(sessionToken: string, emailCode: string, smsCode: string) {
const result = await sendmator.otp.verify({
session_token: sessionToken,
otps: {
email: emailCode,
sms: smsCode
}
});
// Check if both channels verified
const emailVerified = result.data.verification_results.email?.success;
const smsVerified = result.data.verification_results.sms?.success;
return emailVerified && smsVerified;
}
Password Reset
async function requestPasswordReset(email: string) {
const result = await sendmator.otp.send({
channels: ['email'],
recipients: { email },
metadata: {
action: 'password_reset'
}
});
// Store session token with user record
return {
sessionToken: result.data.session_id,
expiresAt: result.data.expires_at
};
}
async function resetPasswordWithOTP(
sessionToken: string,
code: string,
newPassword: string
) {
// Verify OTP
const verifyResult = await sendmator.otp.verify({
session_token: sessionToken,
otps: { email: code }
});
if (verifyResult.data.verified) {
// OTP is valid, update password
// updateUserPassword(newPassword);
return { success: true };
}
return { success: false, message: 'Invalid or expired code' };
}
Resend with Cooldown
async function resendOTPWithCooldown(sessionToken: string, lastSentAt: Date) {
const cooldownSeconds = 60; // 1 minute cooldown
const now = new Date();
const secondsSinceLastSend = (now.getTime() - lastSentAt.getTime()) / 1000;
if (secondsSinceLastSend < cooldownSeconds) {
const remainingSeconds = Math.ceil(cooldownSeconds - secondsSinceLastSend);
throw new Error(`Please wait ${remainingSeconds} seconds before resending`);
}
const result = await sendmator.otp.resend({
session_token: sessionToken
});
return {
success: true,
expiresAt: result.data.expires_at
};
}
Response Types
Send OTP Response
{
success: true,
data: {
session_id: "uuid-session-token",
expires_at: "2024-01-15T10:35:00.000Z",
channels: ["email", "sms"],
recipients: {
email: "user@example.com",
sms: "+14155552671"
},
otps: { // Only in sandbox_mode
email: "123456",
sms: "123456"
}
}
}
Verify OTP Response
{
success: true,
data: {
verified: true,
verification_results: {
email: {
success: true,
message: "OTP verified successfully"
},
sms: {
success: true,
message: "OTP verified successfully"
}
}
}
}
Best Practices
- Use Multiple Channels - Offer email and SMS for better delivery rates
- Set Expiration - OTPs should expire quickly (5-10 minutes)
- Rate Limiting - Implement cooldown between resend requests
- Attempt Limits - Limit verification attempts (3-5 attempts)
- Secure Storage - Never log or store OTP codes
- Clear Sessions - Invalidate session tokens after successful verification
- Sandbox Testing - Use sandbox_mode only in development/testing
- Add Contacts - Use add_contact flag for verified users
Security Considerations
- ✅ OTPs are automatically generated (secure random)
- ✅ OTPs expire after a short time
- ✅ Session tokens are unique per request
- ✅ Verification invalidates the OTP
- ✅ Rate limiting prevents abuse
- ❌ Never return OTPs in production responses
- ❌ Never log OTP codes
- ❌ Never send OTPs via insecure channels
Channels
| Channel | Use Case | Pros | Cons |
|---|---|---|---|
email | Email verification, password reset | High delivery rate, free | Slower delivery |
sms | Phone verification, MFA | Fast delivery | Costs money |
whatsapp | International users, MFA | Global reach, reliable | Requires template approval |
Next Steps
- Contacts SDK - Manage contacts
- Email SDK - Send emails
- SMS SDK - Send SMS
- WhatsApp SDK - Send WhatsApp messages