Examples
Practical examples showing how to integrate the WhatsApp API into common use cases.
Complete Workflow Example
This example demonstrates the full process from authentication to sending a message. This class will be used in all examples that follow.
class WhatsAppAPI {
constructor(apiKey, apiSecret, baseUrl = "https://whatsapp.smsleopard.com") {
this.credentials = btoa(`${apiKey}:${apiSecret}`);
this.baseUrl = baseUrl;
this.headers = {
Authorization: `Basic ${this.credentials}`,
"Content-Type": "application/json",
};
}
async getPhoneNumbers() {
const response = await fetch(`${this.baseUrl}/v1/phone_number_ids`, {
method: "GET",
headers: this.headers,
});
return await response.json();
}
async getTemplates(phoneNumberId) {
const response = await fetch(
`${this.baseUrl}/v1/phone_number_ids/${phoneNumberId}/templates`,
{
method: "GET",
headers: this.headers,
}
);
return await response.json();
}
async sendMessage({
destination,
templateId,
phoneNumberId,
variables = [],
}) {
const payload = {
destination,
template_id: templateId,
phone_number_id: phoneNumberId,
component_list: {
components: [
{
component_type: "BODY",
fields: variables.map((value, index) => ({
name: (index + 1).toString(),
value: value.toString(),
})),
},
],
},
};
const response = await fetch(`${this.baseUrl}/v1/whatsapp/send`, {
method: "POST",
headers: this.headers,
body: JSON.stringify(payload),
});
return await response.json();
}
}
// Usage
const api = new WhatsAppAPI("your_api_key", "your_api_secret");
// Get available phone numbers
const phoneNumbers = await api.getPhoneNumbers();
const phoneNumberId = phoneNumbers[0].phone_number_id;
// Get templates for the phone number
const templates = await api.getTemplates(phoneNumbers[0].id);
const authTemplate = templates.find((t) => t.type === "AUTHENTICATION");
// Send OTP message
const result = await api.sendMessage({
destination: "254720000000",
templateId: authTemplate.id,
phoneNumberId: phoneNumberId,
variables: ["123456"], // OTP code
});
console.log("Message sent:", result);
Use Case Examples
1. User Authentication System
Send OTP codes for user verification during login or registration.
class AuthService {
constructor(whatsappAPI) {
this.whatsappAPI = whatsappAPI; // defined at the top
this.otpStore = new Map(); // In production, use Redis or database
}
generateOTP() {
return Math.floor(100000 + Math.random() * 900000).toString();
}
async sendOTP(phoneNumber, phoneNumberId, templateId) {
const otp = this.generateOTP();
// Store OTP with expiration (5 minutes)
this.otpStore.set(phoneNumber, {
code: otp,
expires: Date.now() + 5 * 60 * 1000,
});
try {
const result = await this.whatsappAPI.sendMessage({
destination: phoneNumber,
templateId: templateId,
phoneNumberId: phoneNumberId,
variables: [otp],
});
return {
success: true,
messageId: result.recipients[0].id,
cost: result.recipients[0].cost,
};
} catch (error) {
console.error("Failed to send OTP:", error);
return { success: false, error: error.message };
}
}
verifyOTP(phoneNumber, userOTP) {
const stored = this.otpStore.get(phoneNumber);
if (!stored) {
return { valid: false, reason: "OTP not found" };
}
if (Date.now() > stored.expires) {
this.otpStore.delete(phoneNumber);
return { valid: false, reason: "OTP expired" };
}
if (stored.code !== userOTP) {
return { valid: false, reason: "Invalid OTP" };
}
this.otpStore.delete(phoneNumber);
return { valid: true };
}
}
// Usage
const authService = new AuthService(api);
// Send OTP
const otpResult = await authService.sendOTP(
"254720000000",
"phone_number_id",
"auth_template_id"
);
// Later, verify OTP
const verification = authService.verifyOTP("254720000000", "123456");
console.log("OTP valid:", verification.valid);
2. E-commerce Order Notifications
Send order confirmations, shipping updates, and delivery notifications.
class OrderNotificationService {
constructor(whatsappAPI) {
this.whatsappAPI = whatsappAPI; // defined at the top
this.templates = {
ORDER_CONFIRMATION: "order_confirmation_template_id",
SHIPPING_UPDATE: "shipping_update_template_id",
DELIVERY_CONFIRMATION: "delivery_confirmation_template_id",
};
this.phoneNumberId = "your_phone_number_id";
}
async sendOrderConfirmation(order) {
// Template: "Hi {{1}}, your order #{{2}} worth {{3}} has been confirmed. Expected delivery: {{4}}"
return await this.whatsappAPI.sendMessage({
destination: order.customerPhone,
templateId: this.templates.ORDER_CONFIRMATION,
phoneNumberId: this.phoneNumberId,
variables: [
order.customerName,
order.orderNumber,
order.totalAmount,
order.expectedDelivery,
],
});
}
async sendShippingUpdate(order, trackingNumber) {
// Template: "Hi {{1}}, your order #{{2}} has been shipped! Track it with: {{3}}"
return await this.whatsappAPI.sendMessage({
destination: order.customerPhone,
templateId: this.templates.SHIPPING_UPDATE,
phoneNumberId: this.phoneNumberId,
variables: [order.customerName, order.orderNumber, trackingNumber],
});
}
async sendDeliveryConfirmation(order) {
// Template: "Hi {{1}}, your order #{{2}} has been delivered! Thank you for shopping with us."
return await this.whatsappAPI.sendMessage({
destination: order.customerPhone,
templateId: this.templates.DELIVERY_CONFIRMATION,
phoneNumberId: this.phoneNumberId,
variables: [order.customerName, order.orderNumber],
});
}
}
// Usage
const orderService = new OrderNotificationService(api);
const order = {
customerName: "John Doe",
customerPhone: "254720000000",
orderNumber: "ORD-2025-001",
totalAmount: "KES 2,500",
expectedDelivery: "June 30, 2025",
};
// Send order confirmation
await orderService.sendOrderConfirmation(order);
// Later, when shipped
await orderService.sendShippingUpdate(order, "TRK123456789");
// Finally, when delivered
await orderService.sendDeliveryConfirmation(order);
3. Appointment Reminders
Send appointment confirmations and reminders for healthcare, beauty salons, etc.
class AppointmentService {
constructor(whatsappAPI) {
this.whatsappAPI = whatsappAPI; // defined at the top
this.reminderTemplate = "appointment_reminder_template_id";
this.confirmationTemplate = "appointment_confirmation_template_id";
this.phoneNumberId = "your_phone_number_id";
}
async sendAppointmentConfirmation(appointment) {
// Template: "Hi {{1}}, your appointment with Dr. {{2}} is confirmed for {{3}} at {{4}}."
return await this.whatsappAPI.sendMessage({
destination: appointment.patientPhone,
templateId: this.confirmationTemplate,
phoneNumberId: this.phoneNumberId,
variables: [
appointment.patientName,
appointment.doctorName,
appointment.date,
appointment.time,
],
});
}
async sendAppointmentReminder(appointment) {
// Template: "Reminder: Hi {{1}}, you have an appointment tomorrow at {{2}} with Dr. {{3}}."
return await this.whatsappAPI.sendMessage({
destination: appointment.patientPhone,
templateId: this.reminderTemplate,
phoneNumberId: this.phoneNumberId,
variables: [
appointment.patientName,
appointment.time,
appointment.doctorName,
],
});
}
// Schedule reminder to be sent 24 hours before appointment
scheduleReminder(appointment) {
const appointmentTime = new Date(appointment.datetime);
const reminderTime = new Date(appointmentTime - 24 * 60 * 60 * 1000); // 24 hours before
const delay = reminderTime.getTime() - Date.now();
if (delay > 0) {
setTimeout(() => {
this.sendAppointmentReminder(appointment);
}, delay);
}
}
}
// Usage
const appointmentService = new AppointmentService(api);
const appointment = {
patientName: "Alice Johnson",
patientPhone: "254720000000",
doctorName: "Smith",
date: "July 1, 2025",
time: "2:00 PM",
datetime: "2025-07-01T14:00:00",
};
// Send confirmation immediately
await appointmentService.sendAppointmentConfirmation(appointment);
// Schedule reminder for 24 hours before
appointmentService.scheduleReminder(appointment);
4. Banking and Financial Notifications
Send transaction alerts, balance updates, and payment confirmations.
class BankingNotificationService {
constructor(whatsappAPI) {
this.whatsappAPI = whatsappAPI; // defined at the top
this.templates = {
TRANSACTION_ALERT: "transaction_alert_template_id",
BALANCE_INQUIRY: "balance_inquiry_template_id",
PAYMENT_CONFIRMATION: "payment_confirmation_template_id",
};
this.phoneNumberId = "your_phone_number_id";
}
async sendTransactionAlert(transaction) {
// Template: "Transaction Alert: {{1}} {{2}} {{3}} on {{4}}. Balance: {{5}}"
const transactionType = transaction.amount > 0 ? "Credit" : "Debit";
return await this.whatsappAPI.sendMessage({
destination: transaction.customerPhone,
templateId: this.templates.TRANSACTION_ALERT,
phoneNumberId: this.phoneNumberId,
variables: [
transactionType,
Math.abs(transaction.amount).toFixed(2),
transaction.currency,
transaction.date,
transaction.balance.toFixed(2),
],
});
}
async sendBalanceInquiry(customer) {
// Template: "Hi {{1}}, your account balance is {{2}} {{3}} as of {{4}}"
return await this.whatsappAPI.sendMessage({
destination: customer.phone,
templateId: this.templates.BALANCE_INQUIRY,
phoneNumberId: this.phoneNumberId,
variables: [
customer.name,
customer.balance.toFixed(2),
customer.currency,
new Date().toLocaleString(),
],
});
}
async sendPaymentConfirmation(payment) {
// Template: "Payment Confirmed: {{1}} {{2}} paid to {{3}} on {{4}}. Ref: {{5}}"
return await this.whatsappAPI.sendMessage({
destination: payment.payerPhone,
templateId: this.templates.PAYMENT_CONFIRMATION,
phoneNumberId: this.phoneNumberId,
variables: [
payment.currency,
payment.amount.toFixed(2),
payment.recipient,
payment.date,
payment.reference,
],
});
}
}
// Usage
const bankingService = new BankingNotificationService(api);
// Transaction alert
const transaction = {
customerPhone: "254720000000",
amount: -150.0, // Negative for debit
currency: "KES",
date: "2025-06-26 10:30 AM",
balance: 5750.5,
};
await bankingService.sendTransactionAlert(transaction);
Error Handling Examples
Robust Error Handling
class WhatsAppAPIWithErrorHandling extends WhatsAppAPI {
async sendMessageWithRetry(
{ destination, templateId, phoneNumberId, variables = [] },
maxRetries = 3
) {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const result = await this.sendMessage({
destination,
templateId,
phoneNumberId,
variables,
});
// Check if the response indicates success
if (result.recipients && result.recipients[0].status === "Success") {
return {
success: true,
data: result,
attempt,
};
} else {
throw new Error(`Message failed: ${result.recipients[0].status}`);
}
} catch (error) {
lastError = error;
console.log(`Attempt ${attempt} failed:`, error.message);
// Don't retry on certain errors
if (this.isNonRetryableError(error)) {
break;
}
// Wait before retrying (exponential backoff)
if (attempt < maxRetries) {
await this.delay(Math.pow(2, attempt) * 1000);
}
}
}
return {
success: false,
error: lastError.message,
attempts: maxRetries,
};
}
isNonRetryableError(error) {
const nonRetryableMessages = [
"Invalid phone number",
"Template not found",
"Insufficient balance",
"Invalid credentials",
];
return nonRetryableMessages.some((msg) =>
error.message.toLowerCase().includes(msg.toLowerCase())
);
}
delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async validateBeforeSending({
destination,
templateId,
phoneNumberId,
variables,
}) {
const errors = [];
// Validate phone number format
if (!this.isValidPhoneNumber(destination)) {
errors.push("Invalid phone number format");
}
// Validate template ID
if (!templateId || templateId.trim() === "") {
errors.push("Template ID is required");
}
// Validate phone number ID
if (!phoneNumberId || phoneNumberId.trim() === "") {
errors.push("Phone number ID is required");
}
// Validate variables
if (!Array.isArray(variables)) {
errors.push("Variables must be an array");
}
return {
valid: errors.length === 0,
errors,
};
}
isValidPhoneNumber(phone) {
// Basic phone number validation
const phoneRegex = /^[+]?[\d\s\-\(\)]{10,15}$/;
return phoneRegex.test(phone);
}
}
// Usage with error handling
const robustAPI = new WhatsAppAPIWithErrorHandling("api_key", "api_secret");
async function sendNotificationSafely(messageData) {
// Validate before sending
const validation = await robustAPI.validateBeforeSending(messageData);
if (!validation.valid) {
console.error("Validation failed:", validation.errors);
return { success: false, errors: validation.errors };
}
// Send with retry logic
const result = await robustAPI.sendMessageWithRetry(messageData);
if (result.success) {
console.log(`Message sent successfully on attempt ${result.attempt}`);
return result;
} else {
console.error(
`Failed to send message after ${result.attempts} attempts:`,
result.error
);
return result;
}
}
Bulk Messaging Example
class BulkMessagingService {
constructor(whatsappAPI, rateLimit = 10) {
// 10 messages per second
this.whatsappAPI = whatsappAPI; // defined at the top
this.rateLimit = rateLimit;
this.delayBetweenMessages = 1000 / rateLimit; // milliseconds
}
async sendBulkMessages(messages) {
const results = [];
console.log(`Starting bulk send of ${messages.length} messages...`);
for (let i = 0; i < messages.length; i++) {
const message = messages[i];
try {
const result = await this.whatsappAPI.sendMessage(message);
results.push({
index: i,
destination: message.destination,
success: true,
result,
});
console.log(`Message ${i + 1}/${messages.length} sent successfully`);
} catch (error) {
results.push({
index: i,
destination: message.destination,
success: false,
error: error.message,
});
console.error(
`Message ${i + 1}/${messages.length} failed:`,
error.message
);
}
// Rate limiting delay
if (i < messages.length - 1) {
await this.delay(this.delayBetweenMessages);
}
}
return this.generateBulkReport(results);
}
generateBulkReport(results) {
const successful = results.filter((r) => r.success);
const failed = results.filter((r) => !r.success);
const totalCost = successful.reduce(
(sum, r) => sum + (r.result.recipients[0].cost || 0),
0
);
return {
total: results.length,
successful: successful.length,
failed: failed.length,
successRate:
((successful.length / results.length) * 100).toFixed(2) + "%",
totalCost: totalCost.toFixed(2),
failedMessages: failed,
results,
};
}
delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
}
// Usage
const bulkService = new BulkMessagingService(api, 5); // 5 messages per second
const bulkMessages = [
{
destination: "254720000001",
templateId: "marketing_template_id",
phoneNumberId: "phone_number_id",
variables: ["John", "Special Offer"],
},
{
destination: "254720000002",
templateId: "marketing_template_id",
phoneNumberId: "phone_number_id",
variables: ["Jane", "Special Offer"],
},
// ... more messages
];
const report = await bulkService.sendBulkMessages(bulkMessages);
console.log("Bulk messaging report:", report);
Testing Examples
Unit Tests with Jest
// whatsapp-api.test.js
const WhatsAppAPI = require("./whatsapp-api");
// Mock fetch for testing
global.fetch = jest.fn();
describe("WhatsAppAPI", () => {
let api;
beforeEach(() => {
api = new WhatsAppAPI("test_key", "test_secret");
fetch.mockClear();
});
test("should send message successfully", async () => {
const mockResponse = {
recipients: [
{
id: "test-id",
cost: 0.5,
number: "+254720000000",
status: "Success",
},
],
};
fetch.mockResolvedValueOnce({
ok: true,
json: async () => mockResponse,
});
const result = await api.sendMessage({
destination: "254720000000",
templateId: "test_template",
phoneNumberId: "test_phone_id",
variables: ["test_value"],
});
expect(result).toEqual(mockResponse);
expect(fetch).toHaveBeenCalledWith(
"https://whatsapp.smsleopard.com/v1/whatsapp/send",
expect.objectContaining({
method: "POST",
headers: expect.objectContaining({
Authorization: expect.stringContaining("Basic"),
"Content-Type": "application/json",
}),
})
);
});
test("should handle API errors", async () => {
fetch.mockRejectedValueOnce(new Error("Network error"));
await expect(
api.sendMessage({
destination: "254720000000",
templateId: "test_template",
phoneNumberId: "test_phone_id",
variables: [],
})
).rejects.toThrow("Network error");
});
});
These examples provide a comprehensive foundation for integrating the WhatsApp API into various applications and use cases. Remember to always test with sandbox credentials before using production keys!