WhatsApp Business SDK

repository·main·Indexed 41 days ago

https://github.com/marcosnicolau/whatsapp-business-sdk

A Node.js connector for the WhatsApp Business Cloud API with full TypeScript support. Version 1.14.3 provides a typed interface for sending messages (text, media, interactive, templates, and reactions), managing business profiles and phone numbers, handling webhooks, and monitoring account health status.

Tokens
11K
Snippets
34
Records
42
Agent score
51%

What's inside WhatsApp Business SDK

  1. Set up Webhooks with WebhookClient

    main

    The WebhookClient handles the subscription and setup for incoming WhatsApp webhooks. You must have an HTTPS connection and have configured your server URL in the Meta application management.

    Default Server Setup

    If you do not provide an existing Express app, the client will create a default one. You can specify a port and a path (which must match your application management settings).

    Using an existing Express app

    You can provide your own Express application via the expressApp option. If you set shouldStartListening: false, you are responsible for calling app.listen() yourself.

    Handling Events

    Use initWebhook to define event handlers. Common handlers include onTextMessageReceived, which provides the message payload and the contact object.

    import { WebhookClient, WABAClient } from "./index";
    
    const webhookClient = new WebhookClient({
    	token: "<YOUR_VALIDATION_TOKEN>",
    	path: "/whatsapp/webhook",
    	port: 8080,
    });
    
    const wabaClient = new WABAClient({
    	accountId: "<ACCOUNT_ID>",
    	phoneId: "<PHONE_ID>",
    	apiToken: "<API_TOKEN>",
    });
    
    webhookClient.initWebhook({
    	onStartListening: () => {
    		console.log("Server started listening");
    	},
    	onTextMessageReceived: async (payload, contact) => {
    		try {
    			const messageId = payload.id.toString();
    			const contactNumber = contact.wa_id;
    
    			// Mark message as read
    			await wabaClient.markMessageAsRead(messageId);
    
    			// React to message
    			await wabaClient.sendMessage({
    				to: contactNumber,
    				type: "reaction",
    				reaction: { message_id: messageId, emoji: "😄" },
    			});
    
    			// Respond to message
    			await wabaClient.sendMessage({
    				type: "text",
    				to: contactNumber,
    				text: { body: "Ok!" },
    				// Optional: enables reply-to feature
    				context: {
    					message_id: messageId,
    				},
    			});
    		} catch (err) {
    			console.log(err);
    		}
    	},
    });
  2. Understand WhatsApp Business API health status and message availability

    main

    The SDK provides types to interpret the health status of your WhatsApp Business account. This status determines if you can send messages and provides context if limitations or blocks occur.

    Message Availability States (CanSendMessage)

    • AVAILABLE: You can send messages normally.
    • LIMITED: You can send messages, but there are restrictions. When in this state, the additional_info field in the entity will contain context about the limitation.
    • BLOCKED: You cannot send messages. When in this state, the errors field in the entity will describe the reason and a possible solution.

    Health Status Hierarchy

    The overall health_status.can_send_message property is a rollup of all entities:

    • BLOCKED: If one or more entities (e.g., a specific phone number or WABA) are blocked.
    • LIMITED: If no entities are blocked, but one or more are limited.
    • AVAILABLE: If all entities are available.
  3. Configure WebhookClient with an existing Express app

    main

    If you are integrating the SDK into an existing Express application, pass your app instance into the expressApp configuration object. Set shouldStartListening: false if you want to manage the server lifecycle (e.g., calling app.listen()) manually.

    import { WebhookClient } from "./index";
    import express from "express";
    
    const myApp = express();
    
    const webhookClient = new WebhookClient({
    	token: "<YOUR_VALIDATION_TOKEN>",
    	path: "/whatsapp/webhook",
    	expressApp: {
    		// Set to false if you want to initialize the server yourself
    		// Otherwise, it will start listening when firing initWebhook()
    		shouldStartListening: false,
    		app: myApp,
    	},
    });
    
    myApp.listen(8080, () => {
    	console.log("My server nows listens to whatsapp webhooks");
    });
  4. Initialize the WABAClient

    main

    To interact with the WhatsApp Business Cloud API, instantiate the WABAClient class. You must provide your account ID, API token, and business phone ID. Note that the accountId is obtained from the Meta developer app administration, not directly from the developer app itself.

    Errors thrown by the client can be caught and cast to the WABAErrorAPI type to access the error message.

    import { WABAClient, WABAErrorAPI } from "whatsapp-business";
    
    const client = new WABAClient({
    	accountId: "<YOUR_ACCOUNT_ID>",
    	apiToken: "<YOUR_API_TOKEN>",
    	phoneId: "<YOUR_BUSINESS_PHONE_ID>",
    });
    
    const foo = async () => {
    	try {
    		const res = await client.getBusinessPhoneNumbers();
    		console.log(res);
    	} catch (err) {
    		const error: WABAErrorAPI = err;
    		console.error(error.message);
    	}
    };
    
    foo();
  5. Send text and image messages

    main

    Use the sendMessage method to send different types of media. The method accepts an object specifying the recipient (to), the message type, and the content payload.

    • Text Messages: Set type: "text" and provide a text object with a body string.
    • Image Messages: Set type: "image" and provide an image object containing a link (URL) and an optional caption.
    // Sending a text message
    const sendTextMessage = async (body: string, to: string) => {
    	try {
    		const res = await client.sendMessage({ to, type: "text", text: { body } });
    		console.log(res);
    	} catch (err) {
    		const error: WABAErrorAPI = err;
    		console.error(error.message);
    	}
    };
    
    // Sending an image message
    const sendPictureMessage = async ({ link, caption }: MediaObject, to: string) => {
    	try {
    		const res = await client.sendMessage({ to, type: "image", image: { link, caption } });
    		console.log(res);
    	} catch (err) {
    		const error: WABAErrorAPI = err;
    		console.error(error.message);
    	}
    };
  6. Integrate WebhookClient into an existing Express application

    main

    If you already have an Express server running, you can mount the WebhookClient router onto it instead of letting the client create a new application. This prevents port conflicts and allows you to use your existing middleware stack.

    To do this, pass your application instance and set shouldStartListening: false.

    import express from 'express';
    import { WebhookClient } from 'whatsapp-business';
    
    const app = express();
    
    const client = new WebhookClient({
      token: 'MY_SECRET_TOKEN',
      path: '/whatsapp',
      expressApp: {
        app: app,
        shouldStartListening: false
      }
    });
    
    // This mounts the webhook router to the app at the specified path
    client.initWebhook();
    
    app.listen(3000, () => {
      console.log('Server running on port 3000');
    });
  7. Parse WebhookMessage payloads

    main

    The WebhookMessage type represents the core data received when a customer sends a message. Because the payload structure changes based on the type field, you should use type guards or check the type property before accessing specific fields.

    Supported type values include:

    • text: Access content via text.body.
    • image, video, document, audio: Access media metadata via image, video, document, or audio objects (containing id, mime_type, and optionally caption or filename).
    • interactive: Contains user interactions like button_reply, list_reply, or nfm_reply (Native Flow Messages).
    • location: Access via location object (latitude, longitude, address).
    • contact: Access via contacts array.
    • sticker: Access via sticker object.
    • reaction: Access via reaction object.
    • system: Triggered by profile or number updates.
    • button, order, unknown, request_welcome.
  8. Import the WhatsApp Business SDK

    main

    The SDK is exported from a single entrypoint. You can import the main client, all types, and webhook utilities directly from the package root. This includes WABA_client for interacting with the WhatsApp Business API and webhook-related classes for handling incoming events.

    import { WABA_client, types, WebhookClient } from 'whatsapp-business-sdk';
  9. Send Media messages using MediaObject

    main

    When sending audio, document, image, sticker, or video messages, you use a MediaObject. You can provide media in two ways:

    1. Via Link: Provide an https:// URL in the link field. You can optionally provide a provider string if the link requires additional configuration (like a bearer token).
    2. Via ID: Provide a WhatsApp media ID in the id field (obtained after uploading media to WhatsApp servers).

    Common MediaObject fields:

    • caption: Description for images, documents, or videos (not for audio/stickers).
    • filename: Filename for documents (the extension determines the displayed format).
    • link: The HTTP/HTTPS URL of the asset.
    • id: The WhatsApp media ID.
    • provider: Optional path/config for non-direct links.
    const imageMessage: Message = {
      to: '1234567890',
      type: 'image',
      image: {
        link: 'https://example.com/image.jpg',
        caption: 'Check this out!'
      }
    };
  10. Handle incoming Webhook events with WebhookEvents

    main

    When setting up a webhook listener, use the WebhookEvents interface to define callbacks for different types of incoming data. The most common events are:

    • onMessageReceived: Fired for any incoming message. You must check the payload.type to differentiate between text, image, interactive, etc.
    • onTextMessageReceived: A specialized callback that fires only when the message type is text.
    • onStatusReceived: Fired when the status of a message you sent changes (e.g., sent, delivered, read, or failed).
    • onError: Fired when a webhook error occurs.
    • onStartListening: Fired when the server successfully starts listening for webhooks.
    const events: WebhookEvents = {
      onMessageReceived: (payload, contact, metadata) => {
        console.log(`New message from ${contact.wa_id}:`, payload.text?.body);
      },
      onStatusReceived: (status) => {
        console.log(`Message ${status.id} status: ${status.status}`);
      },
      onError: (error) => {
        console.error(`Webhook error: ${error.message}`);
      }
    };
  11. Define a Message to send via WhatsApp

    main

    The Message type is the primary interface for sending various content types through the SDK. You must specify the to field (WhatsApp ID or phone number) and the type of message. Depending on the type, you must provide the corresponding payload object (e.g., text, image, template, interactive).

    Supported MessageType values:

    • audio, contacts, document, image, interactive, location, sticker, template, text, video, reaction.

    Additional useful fields:

    • biz_opaque_callback_data: An arbitrary string (max 512 chars) used for tracking (e.g., template IDs). It is returned in webhook status updates.
    • context: Used for the reply-to feature, requiring a message_id from a received webhook.
    • recipient_type: Defaults to individual.
    import { Message } from 'whatsapp-business-sdk';
    
    const message: Message = {
      to: '1234567890',
      type: 'text',
      text: {
        body: 'Hello, world!',
        preview_url: true
      },
      biz_opaque_callback_data: 'my_custom_tracking_id'
    };