UNPKG

@microfox/whatsapp-business

Version:

WhatsApp Business API SDK: A lightweight, type-safe SDK for interacting with the WhatsApp Business API

910 lines (788 loc) 19.8 kB
# @microfox/whatsapp-business A lightweight, type-safe SDK for interacting with the WhatsApp Business API. This SDK provides a simple and intuitive interface to send various types of messages through the WhatsApp Business API. ## Features - 🔒 Type-safe API with TypeScript - 📱 Support for all WhatsApp message types - 🚀 Easy to use and integrate - 🔄 Built-in error handling - 📦 Lightweight and dependency-free - 💬 Conversational Components Support - 📊 Analytics and insights - 🛍️ Commerce settings management - 📱 Phone number management - 📝 Template management - 📸 Media handling - ••• Typing indicator support - 🔄 Message reactions and contextual replies - 📍 Location sharing - 👥 Contact sharing - 🔄 Interactive messages (buttons, lists, flows) - 📱 QR code generation ## Installation ```bash npm install @microfox/whatsapp-business ``` ## Quick Start ```typescript import { WhatsAppBusinessSDK } from '@microfox/whatsapp-business'; // Initialize the SDK const whatsapp = new WhatsAppBusinessSDK({ phoneNumberId: process.env.WHATSAPP_BUSINESS_PHONE_NUMBER_ID, businessAccountId: process.env.WHATSAPP_BUSINESS_ACCOUNT_ID, accessToken: process.env.WHATSAPP_BUSINESS_ACCESS_TOKEN, }); // Optional parameters // version: 'v22.0', // Optional: defaults to v22.0 // baseUrl: 'https://graph.facebook.com/v22.0', // Optional: custom base URL // Send a text message await whatsapp.sendTextMessage( 'RECIPIENT_PHONE_NUMBER', 'Hello from WhatsApp Business API!', ); ``` ## Configuration The SDK requires the following configuration: ```typescript interface WhatsAppSDKConfig { phoneNumberId: string; // Your WhatsApp Business phone number ID businessAccountId: string; // Your WhatsApp Business account ID accessToken: string; // Your WhatsApp Business API access token version?: string; // Optional: API version (defaults to v22.0) baseUrl?: string; // Optional: Custom base URL } ``` ## Conversational Components Conversational components are in-chat features that make it easier for WhatsApp users to interact with your business. They include ice breakers and commands that users can tap or type to interact with your business. > **Important Note**: Make sure `WHATSAPP_WEBHOOK_URL` is set as an environment variable. The Conversational components require whatsapp webhook url. ### Ice Breakers Ice breakers are customizable, tappable text strings that appear in a message thread the first time you chat with a user. You can configure up to 4 ice breakers, each with a maximum of 80 characters. ### Commands Commands are text strings that WhatsApp users can see by typing a forward slash in a message thread. You can define up to 30 commands, each with a maximum of 32 characters for the command name and 256 characters for the description. ### Configure Conversational Components You can configure ice breakers and commands separately or together. Here are examples for each scenario: #### Configure Only Ice Breakers ```typescript await whatsapp.configureConversationalComponents({ enable_welcome_message: true, prompts: ['Book a flight', 'Plan a vacation', 'Find hotels', 'Rent a car'], }); ``` #### Configure Only Commands ```typescript await whatsapp.configureConversationalComponents({ enable_welcome_message: true, commands: [ { command_name: 'tickets', command_description: 'Book flight tickets', }, { command_name: 'hotel', command_description: 'Book hotel', }, ], }); ``` #### Configure Both Ice Breakers and Commands ```typescript await whatsapp.configureConversationalComponents({ enable_welcome_message: true, prompts: ['Book a flight', 'Plan a vacation', 'Find hotels', 'Rent a car'], commands: [ { command_name: 'tickets', command_description: 'Book flight tickets', }, { command_name: 'hotel', command_description: 'Book hotel', }, ], }); ``` > **Important Note**: While Conversational Components can be reconfigured, it's recommended to avoid frequent changes as they can confuse users and disrupt their interaction patterns with your business. It's best to carefully plan your ice breakers and commands before implementation and only update them when absolutely necessary. ### Get Current Configuration ```typescript const config = await whatsapp.getConversationalComponents(); console.log(config); // { // enable_welcome_message: true, // prompts: ["Book a flight", "Plan a vacation"], // commands: [ // { command_name: "tickets", command_description: "Book flight tickets" } // ] // } ``` ## Common Message Options All message types support the following options: ```typescript interface MessageOptions { recipientType?: 'individual' | 'group'; // Default: 'individual' } ``` Text messages have additional options: ```typescript interface TextMessageOptions extends MessageOptions { previewUrl?: boolean; // Whether to show a preview URL, default: true } ``` ## Message Types ### Text Messages ```typescript // Basic text message (URL preview enabled by default) await whatsapp.sendTextMessage( 'RECIPIENT_PHONE_NUMBER', 'Hello from WhatsApp Business API!', { recipientType: 'individual' }, // Optional ); // Text message with preview URL disabled await whatsapp.sendTextMessage( 'RECIPIENT_PHONE_NUMBER', 'Check out our website: https://example.com', { recipientType: 'individual', previewUrl: false, // Explicitly disable URL preview }, ); // Text message with preview URL enabled (explicit) await whatsapp.sendTextMessage( 'RECIPIENT_PHONE_NUMBER', 'Check out our website: https://example.com', { recipientType: 'individual', previewUrl: true, // Explicitly enable URL preview }, ); ``` ### Media Messages #### Image ```typescript // Using Media ID (Recommended) const mediaId = await whatsapp.uploadMedia(file, 'image'); await whatsapp.sendImageMessage( 'RECIPIENT_PHONE_NUMBER', { id: mediaId, caption: 'This is an image caption', }, { recipientType: 'individual' }, // Optional ); // Using Direct Link (Alternative) await whatsapp.sendImageMessage( 'RECIPIENT_PHONE_NUMBER', { link: 'https://example.com/image.jpg', caption: 'This is an image caption', }, { recipientType: 'individual' }, // Optional ); ``` #### Video ```typescript // Using Media ID (Recommended) const mediaId = await whatsapp.uploadMedia(file, 'video'); await whatsapp.sendVideoMessage( 'RECIPIENT_PHONE_NUMBER', { id: mediaId, caption: 'This is a video caption', }, { recipientType: 'individual' }, // Optional ); // Using Direct Link (Alternative) await whatsapp.sendVideoMessage( 'RECIPIENT_PHONE_NUMBER', { link: 'https://example.com/video.mp4', caption: 'This is a video caption', }, { recipientType: 'individual' }, // Optional ); ``` #### Document ```typescript // Using Media ID (Recommended) const mediaId = await whatsapp.uploadMedia(file, 'document'); await whatsapp.sendDocumentMessage( 'RECIPIENT_PHONE_NUMBER', { id: mediaId, filename: 'document.pdf', caption: 'This is a document caption', }, { recipientType: 'individual' }, // Optional ); // Using Direct Link (Alternative) await whatsapp.sendDocumentMessage( 'RECIPIENT_PHONE_NUMBER', { link: 'https://example.com/document.pdf', filename: 'document.pdf', caption: 'This is a document caption', }, { recipientType: 'individual' }, // Optional ); ``` #### Audio ```typescript // Using Media ID (Recommended) const mediaId = await whatsapp.uploadMedia(file, 'audio'); await whatsapp.sendAudioMessage( 'RECIPIENT_PHONE_NUMBER', { id: mediaId, }, { recipientType: 'individual' }, // Optional ); // Using Direct Link (Alternative) await whatsapp.sendAudioMessage( 'RECIPIENT_PHONE_NUMBER', { link: 'https://example.com/audio.mp3', }, { recipientType: 'individual' }, // Optional ); ``` #### Sticker ```typescript // Using Media ID (Recommended) const mediaId = await whatsapp.uploadMedia(file, 'sticker'); await whatsapp.sendStickerMessage( 'RECIPIENT_PHONE_NUMBER', { id: mediaId, }, { recipientType: 'individual' }, // Optional ); // Using Direct Link (Alternative) await whatsapp.sendStickerMessage( 'RECIPIENT_PHONE_NUMBER', { link: 'https://example.com/sticker.webp', }, { recipientType: 'individual' }, // Optional ); ``` ### Location Messages ```typescript // Basic location await whatsapp.sendLocationMessage( 'RECIPIENT_PHONE_NUMBER', { longitude: 123.456, latitude: 78.901, }, { recipientType: 'individual' }, // Optional ); // Location with name and address await whatsapp.sendLocationMessage( 'RECIPIENT_PHONE_NUMBER', { longitude: 123.456, latitude: 78.901, name: 'Business Location', address: '123 Business Street, City, Country', }, { recipientType: 'individual' }, // Optional ); ``` ### Location Request Messages ```typescript // Request user's location await whatsapp.sendLocationRequestMessage( 'RECIPIENT_PHONE_NUMBER', 'Please share your location', 'individual', ); ``` ### Contact Messages ```typescript // Single contact await whatsapp.sendContactMessage( 'RECIPIENT_PHONE_NUMBER', [ { name: { formatted_name: 'John Doe', first_name: 'John', last_name: 'Doe', }, phones: [ { phone: '+1234567890', type: 'WORK', }, ], }, ], { recipientType: 'individual' }, // Optional ); // Multiple contacts await whatsapp.sendContactMessage( 'RECIPIENT_PHONE_NUMBER', [ { name: { formatted_name: 'John Doe', first_name: 'John', last_name: 'Doe', }, phones: [ { phone: '+1234567890', type: 'WORK', }, ], }, { name: { formatted_name: 'Jane Smith', first_name: 'Jane', last_name: 'Smith', }, phones: [ { phone: '+0987654321', type: 'CELL', }, ], }, ], 'individual', ); ``` ### Interactive Messages #### Buttons ```typescript // Simple buttons await whatsapp.sendInteractiveMessage( 'RECIPIENT_PHONE_NUMBER', { type: 'button', body: { text: 'Choose an option', }, action: { buttons: [ { type: 'reply', reply: { id: 'option1', title: 'Option 1', }, }, { type: 'reply', reply: { id: 'option2', title: 'Option 2', }, }, ], }, }, { recipientType: 'individual' }, // Optional ); // Buttons with emojis await whatsapp.sendInteractiveMessage( 'RECIPIENT_PHONE_NUMBER', { type: 'button', body: { text: 'How can we help you?', }, action: { buttons: [ { type: 'reply', reply: { id: 'support', title: '💬 Support', }, }, { type: 'reply', reply: { id: 'sales', title: '💰 Sales', }, }, ], }, }, { recipientType: 'individual' }, // Optional ); ``` #### Lists ```typescript // Simple list await whatsapp.sendInteractiveMessage( 'RECIPIENT_PHONE_NUMBER', { type: 'list', body: { text: 'Choose a category', }, action: { button: 'Select', sections: [ { title: 'Products', rows: [ { id: 'product1', title: 'Product 1', description: 'Description of product 1', }, { id: 'product2', title: 'Product 2', description: 'Description of product 2', }, ], }, ], }, }, { recipientType: 'individual' }, // Optional ); // Multiple sections list await whatsapp.sendInteractiveMessage( 'RECIPIENT_PHONE_NUMBER', { type: 'list', body: { text: 'Select a service', }, action: { button: 'Choose', sections: [ { title: 'Support', rows: [ { id: 'support_chat', title: 'Chat Support', description: '24/7 chat support', }, { id: 'support_email', title: 'Email Support', description: 'Email support team', }, ], }, { title: 'Sales', rows: [ { id: 'sales_contact', title: 'Contact Sales', description: 'Talk to our sales team', }, { id: 'sales_demo', title: 'Request Demo', description: 'Schedule a product demo', }, ], }, ], }, }, { recipientType: 'individual' }, // Optional ); ``` #### Call-to-Action (CTA) ```typescript // CTA message with URL await whatsapp.sendInteractiveCtaMessage( 'RECIPIENT_PHONE_NUMBER', 'Click the button below to visit our website', 'https://example.com', 'individual', ); ``` ### Template Messages ```typescript // Simple template await whatsapp.sendTemplateMessage( 'RECIPIENT_PHONE_NUMBER', 'hello_world', 'en_US', [ { type: 'body', parameters: [ { type: 'text', text: 'John', }, ], }, ], { recipientType: 'individual' }, // Optional ); // Template with multiple components await whatsapp.sendTemplateMessage( 'RECIPIENT_PHONE_NUMBER', 'order_confirmation', 'en_US', [ { type: 'header', parameters: [ { type: 'text', text: 'Order #12345', }, ], }, { type: 'body', parameters: [ { type: 'text', text: 'John', }, { type: 'text', text: '2 items', }, { type: 'text', text: '$99.99', }, ], }, { type: 'footer', text: 'Thank you for your order!', }, ], { recipientType: 'individual' }, // Optional ); ``` ### Flow Messages ```typescript // Simple flow await whatsapp.sendFlowMessage( 'RECIPIENT_PHONE_NUMBER', { token: 'flow_token', parameters: { product_id: '123', user_id: '456', }, }, { recipientType: 'individual' }, // Optional ); // Flow with header and body await whatsapp.sendFlowMessage( 'RECIPIENT_PHONE_NUMBER', { token: 'flow_token', header: { type: 'text', text: 'Welcome to our service!', }, body: { text: 'Please complete the following steps:', }, parameters: { flow_id: '789', step: '1', }, }, { recipientType: 'individual' }, // Optional ); ``` ### Message Reactions ```typescript // Send a reaction to a message await whatsapp.sendReaction( 'RECIPIENT_PHONE_NUMBER', 'message_id', '❤️', // Emoji to react with ); ``` ### Send Typing Indicator The typing indicator shows the user that you are preparing a response. This is a good practice for improving user experience when it will take a few seconds to respond. ```typescript await whatsapp.sendTypingIndicator({ messageId: 'MESSAGE_ID', type: 'text', // Optional, defaults to 'text' }); ``` > **Note**: The typing indicator will be dismissed automatically after 25 seconds or when you send a response, whichever comes first. Only use this feature when you are actually going to respond to the user. ### Message Replies ```typescript // Text reply await whatsapp.sendReply( 'RECIPIENT_PHONE_NUMBER', 'text', 'Thank you for your message!', 'message_id', { recipientType: 'individual' }, // Optional ); // Media reply (image, video, document, audio, sticker) await whatsapp.sendReply( 'RECIPIENT_PHONE_NUMBER', 'image', { id: 'MEDIA_ID', caption: 'Here is the image you requested', }, 'message_id', { recipientType: 'individual' }, // Optional ); // Location reply await whatsapp.sendReply( 'RECIPIENT_PHONE_NUMBER', 'location', { longitude: 123.456, latitude: 78.901, name: 'Business Location', address: '123 Business Street, City, Country', }, 'message_id', 'individual', ); // Contact reply await whatsapp.sendReply( 'RECIPIENT_PHONE_NUMBER', 'contacts', [ { name: { formatted_name: 'John Doe', first_name: 'John', last_name: 'Doe', }, phones: [ { phone: '+1234567890', type: 'WORK', }, ], }, ], 'message_id', 'individual', ); // Interactive reply await whatsapp.sendReply( 'RECIPIENT_PHONE_NUMBER', 'interactive', { type: 'button', body: { text: 'Choose an option', }, action: { buttons: [ { type: 'reply', reply: { id: 'option1', title: 'Option 1', }, }, ], }, }, 'message_id', 'individual', ); ``` ### Message Management ```typescript // Mark single message as read await whatsapp.markMessageAsRead('MESSAGE_ID'); // Mark multiple messages as read await whatsapp.markMessagesAsRead(['MESSAGE_ID_1', 'MESSAGE_ID_2']); ``` ### Media Management ```typescript // Upload media const mediaId = await whatsapp.uploadMedia(file, 'image'); // Download media const mediaData = await whatsapp.downloadMedia('MEDIA_ID'); // Get media URL const mediaUrl = await whatsapp.getMediaUrl('MEDIA_ID'); ``` ### Phone Number Management ```typescript // Register phone await whatsapp.registerPhone('PHONE_NUMBER', 'PIN'); // Deregister phone await whatsapp.deregisterPhone('PHONE_NUMBER'); // Get phone numbers const phoneNumbers = await whatsapp.getPhoneNumbers(); // Get QR code const qrCode = await whatsapp.getQRCode(); ``` ### Business Profile ```typescript // Get business profile const profile = await whatsapp.getBusinessProfile(); // Update business profile const updatedProfile = await whatsapp.updateBusinessProfile({ about: 'We provide excellent customer service', address: '123 Business Street, City, Country', description: 'Leading provider of business solutions', email: 'contact@business.com', website: 'https://business.com', }); ``` ### Analytics ```typescript // Get daily analytics const analytics = await whatsapp.getAnalytics({ start: '2024-01-01', end: '2024-01-31', granularity: 'DAY', }); // Get hourly analytics const hourlyAnalytics = await whatsapp.getAnalytics({ start: '2024-01-01T00:00:00Z', end: '2024-01-01T23:59:59Z', granularity: 'HOUR', }); ``` ### Commerce Settings ```typescript // Get commerce settings const settings = await whatsapp.getCommerceSettings(); // Update commerce settings const updatedSettings = await whatsapp.updateCommerceSettings({ catalog_id: 'CATALOG_ID', is_catalog_visible: true, cart_enabled: true, cart_expiration_time: 3600, }); ``` ## Error Handling The SDK throws a `WhatsAppBusinessSDKError` for API errors with the following properties: ```typescript class WhatsAppBusinessSDKError extends Error { code: number; originalError: any; } ``` Example error handling: ```typescript try { await whatsapp.sendTextMessage('RECIPIENT_PHONE_NUMBER', 'Hello!'); } catch (error) { if (error instanceof WhatsAppBusinessSDKError) { console.error(`Error ${error.code}: ${error.message}`); console.error('Original error:', error.originalError); } } ``` ## Contributing Contributions are welcome! Please feel free to submit a Pull Request. ## License This project is licensed under the MIT License - see the LICENSE file for details.