WhatsApp API (Beta)
Examples

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!