diff --git a/src/18-appendix-external-services/channels.md b/src/18-appendix-external-services/channels.md
index e12e4984..7b53ac5d 100644
--- a/src/18-appendix-external-services/channels.md
+++ b/src/18-appendix-external-services/channels.md
@@ -1 +1,275 @@
# Channel Integrations
+
+This guide covers integrating messaging channels with General Bots, focusing on WhatsApp Business API integration using Twilio-purchased phone numbers.
+
+## Overview
+
+General Bots supports multiple messaging channels through a unified API. This section focuses on WhatsApp Business API, the most widely used business messaging platform globally.
+
+## Supported Channels
+
+| Channel | Status | Config Keys |
+|---------|--------|-------------|
+| WhatsApp | β
Production Ready | `whatsapp-api-key`, `whatsapp-phone-number-id` |
+| Twilio SMS | β
Production Ready | `twilio-account-sid`, `twilio-auth-token` |
+| Instagram | β
Production Ready | `instagram-access-token`, `instagram-page-id` |
+| Microsoft Teams | β
Production Ready | `teams-app-id`, `teams-app-password` |
+
+## WhatsApp Business Integration
+
+The most popular channel for business messaging. Complete integration guide: [WhatsApp Quick Start](./whatsapp-quick-start.md)
+
+### Quick Setup (5 minutes)
+
+1. **Purchase a phone number from Twilio**
+ ```bash
+ # Twilio Console > Phone Numbers > Buy a Number
+ # Select: Voice capability (required for verification)
+ # Example: +553322980098
+ ```
+
+2. **Create Meta App with WhatsApp**
+ ```bash
+ # https://developers.facebook.com/apps/
+ # Create App > Business > Add WhatsApp product
+ ```
+
+3. **Configure credentials in `config.csv`**
+ ```csv
+ whatsapp-enabled,true
+ whatsapp-api-key,EAAQdlso6aM8BOwlhc3yM6bbJkGyibQPGJd87zFDHtfaFoJDJPohMl2c5nXs4yYuuHwoXJWx0rQKo0VXgTwThPYzqLEZArOZBhCWPBUpq7YlkEJXFAgB6ZAb3eoUzZAMgNZCZA1sg11rT2G8e1ZAgzpRVRffU4jmMChc7ybcyIwbtGOPKZAXKcNoMRfUwssoLhDWr
+ whatsapp-phone-number-id,1158433381968079
+ whatsapp-business-account-id,390727550789228
+ whatsapp-webhook-verify-token,4qIogZadggQ.BEoMeciXIdl_MlkV_1DTx8Z_i0bYPxtSJwKSbH0FKlY
+ whatsapp-application-id,323250907549153
+ ```
+
+### BASIC Keywords for WhatsApp
+
+```basic
+REM Send a message
+SEND WHATSAPP TO "+5511999999999" WITH "Hello from General Bots!"
+
+REM Handle incoming messages
+ON WHATSAPP MESSAGE RECEIVED
+ LET SENDER$ = GET WHATSAPP SENDER NUMBER
+ LET MESSAGE$ = GET WHATSAPP MESSAGE BODY
+
+ REM Echo message back
+ SEND WHATSAPP TO SENDER$ WITH "You said: " + MESSAGE$
+END ON
+```
+
+### Credential Reference
+
+| Credential | Format | Example | Purpose |
+|------------|--------|---------|---------|
+| Access Token | `EAAQ...` | `EAAQdlso6aM8BOwl...` | API authentication |
+| Phone Number ID | 16 digits | `1158433381968079` | Message sending endpoint |
+| WABA ID | 15 digits | `390727550789228` | Business account identifier |
+| Verify Token | Custom string | `4qIogZadggQ.BEoMeci...` | Webhook security |
+| Application ID | 15 digits | `323250907549153` | App identifier |
+
+### Phone Number Verification
+
+Twilio numbers require **voice call verification** (not SMS):
+
+1. **Configure Twilio webhook** to capture verification calls
+ ```xml
+
+
+
+
+ Please enter your verification code.
+
+
+ ```
+
+2. **In Meta Business Suite**: Select "Phone Call" verification method
+3. **Enter the 6-digit code** received via email
+4. **Verification complete** - number ready for WhatsApp
+
+See: [Webhook Configuration Guide](./whatsapp-webhooks.md)
+
+## Advanced Configuration
+
+### Message Templates
+
+For business-initiated messages outside the 24-hour window:
+
+```javascript
+// Send template message
+POST https://graph.facebook.com/v18.0/1158433381968079/messages
+{
+ "messaging_product": "whatsapp",
+ "to": "5511999999999",
+ "type": "template",
+ "template": {
+ "name": "hello_world",
+ "language": { "code": "pt_BR" }
+ }
+}
+```
+
+### Rate Limiting
+
+WhatsApp enforces rate limits per tier:
+
+| Tier | Messages/Day | Messages/Second |
+|------|--------------|-----------------|
+| Tier 1 | 1,000 | 1 |
+| Tier 2 | 10,000 | 5 |
+| Tier 3 | 100,000 | 50 |
+| Tier 4 | Unlimited | 1,000 |
+
+Implement rate limiting in your bot:
+
+```basic
+REM Simple rate limiting
+LET LAST_SENT = 0
+SUB SEND WHATSAPP WITH LIMIT TO NUMBER$, MESSAGE$
+ LET NOW = TIMER
+ IF NOW - LAST_SENT < 1 THEN
+ WAIT 1 - (NOW - LAST_SENT)
+ END IF
+ SEND WHATSAPP TO NUMBER$ WITH MESSAGE$
+ LAST_SENT = TIMER
+END SUB
+```
+
+### Webhook Security
+
+Always verify webhook signatures:
+
+```javascript
+// Node.js signature verification
+const crypto = require('crypto');
+
+function verifySignature(payload, signature, appSecret) {
+ const expected = 'sha256=' +
+ crypto.createHmac('sha256', appSecret)
+ .update(payload)
+ .digest('hex');
+ return crypto.timingSafeEqual(
+ Buffer.from(signature),
+ Buffer.from(expected)
+ );
+}
+```
+
+## Complete Documentation
+
+For detailed guides and examples:
+
+- **[WhatsApp Quick Start Guide](./whatsapp-quick-start.md)** - 30-minute setup walkthrough
+- **[Webhook Configuration](./whatsapp-webhooks.md)** - Detailed webhook setup for Twilio and Meta
+- **[Code Examples](./whatsapp-examples.md)** - Examples in BASIC, Node.js, and Python
+- **[Troubleshooting Guide](./whatsapp-troubleshooting.md)** - Common issues and solutions
+- **[Quick Reference](./whatsapp-quick-reference.md)** - Commands, configs, and snippets
+
+## Other Channels
+
+### Twilio SMS
+
+Simple SMS integration using Twilio:
+
+```csv
+# config.csv
+twilio-account-sid,ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+twilio-auth-token,your_auth_token_here
+twilio-from-number,+15551234567
+```
+
+```basic
+REM Send SMS
+SEND SMS TO "+5511999999999" WITH "Hello via SMS!"
+```
+
+### Instagram Direct Messages
+
+Connect Instagram messaging:
+
+```csv
+# config.csv
+instagram-access-token,EAAxxxx...
+instagram-page-id,123456789012345
+```
+
+```basic
+REM Send Instagram DM
+SEND INSTAGRAM TO "1234567890" WITH "Hello via Instagram!"
+```
+
+## Configuration Template
+
+Complete channel configuration example:
+
+```csv
+# config.csv
+
+# WhatsApp Business (Primary channel)
+whatsapp-enabled,true
+whatsapp-api-key,EAAQdlso6aM8BOwlhc3yM6bbJkGyibQPGJd87zFDHtfaFoJDJPohMl2c5nXs4yYuuHwoXJWx0rQKo0VXgTwThPYzqLEZArOZBhCWPBUpq7YlkEJXFAgB6ZAb3eoUzZAMgNZCZA1sg11rT2G8e1ZAgzpRVRffU4jmMChc7ybcyIwbtGOPKZAXKcNoMRfUwssoLhDWr
+whatsapp-phone-number-id,1158433381968079
+whatsapp-business-account-id,390727550789228
+whatsapp-webhook-verify-token,4qIogZadggQ.BEoMeciXIdl_MlkV_1DTx8Z_i0bYPxtSJwKSbH0FKlY
+
+# Twilio SMS (Backup channel)
+twilio-enabled,false
+twilio-account-sid,ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+twilio-auth-token,your_auth_token_here
+twilio-from-number,+15551234567
+
+# Instagram (Social channel)
+instagram-enabled,false
+instagram-access-token,EAAxxxx...
+instagram-page-id,123456789012345
+```
+
+## Troubleshooting
+
+### Common Issues
+
+**Issue: Phone number verification fails**
+- **Solution**: Ensure "Phone Call" verification is selected (not SMS)
+- **Solution**: Verify Twilio webhook is configured correctly
+- See: [Troubleshooting Guide](./whatsapp-troubleshooting.md)
+
+**Issue: Messages not sending**
+- **Solution**: Check access token validity
+- **Solution**: Verify phone number format: `5511999999999` (no +, no spaces)
+- **Solution**: Ensure webhook is subscribed to "messages" field
+
+**Issue: Rate limit errors**
+- **Solution**: Implement rate limiting in your bot
+- **Solution**: Use message queues for bulk sending
+- See: [Code Examples](./whatsapp-examples.md)
+
+## Best Practices
+
+1. **Never hardcode credentials** - Always use `config.csv`
+2. **Implement retry logic** - Handle API failures gracefully
+3. **Monitor rate limits** - Respect platform limits
+4. **Secure webhooks** - Verify all incoming requests
+5. **Test thoroughly** - Use ngrok for local testing
+6. **Log everything** - Track message delivery and errors
+7. **Use templates** - Pre-approved templates for business-initiated messages
+8. **Handle errors** - Provide user-friendly error messages
+
+## Support
+
+- **Documentation**: [Full guide](./whatsapp-quick-start.md)
+- **Examples**: [Code samples](./whatsapp-examples.md)
+- **Community**: [General Bots Discord](https://discord.gg/general-bots)
+- **Meta Docs**: [WhatsApp Business API](https://developers.facebook.com/docs/whatsapp/)
+- **Twilio Docs**: [Twilio WhatsApp](https://www.twilio.com/docs/whatsapp)
+
+## Next Steps
+
+1. Complete the [Quick Start Guide](./whatsapp-quick-start.md)
+2. Set up webhooks using [Webhook Configuration](./whatsapp-webhooks.md)
+3. Explore [Code Examples](./whatsapp-examples.md) for your use case
+4. Configure monitoring and error handling
+5. Test with your team before launching to users
+
+For configuration of other services (LLM providers, databases, etc.), see [Appendix B: External Services](./README.md).
\ No newline at end of file
diff --git a/src/18-appendix-external-services/whatsapp-examples.md b/src/18-appendix-external-services/whatsapp-examples.md
new file mode 100644
index 00000000..261f51ed
--- /dev/null
+++ b/src/18-appendix-external-services/whatsapp-examples.md
@@ -0,0 +1,1410 @@
+# Code Examples for WhatsApp Integration
+
+This page provides practical code examples for integrating WhatsApp Business API with General Bots, covering common use cases and implementations in multiple languages.
+
+## Table of Contents
+
+- [BASIC Examples](#basic-examples)
+- [Node.js Examples](#nodejs-examples)
+- [Python Examples](#python-examples)
+- [Common Use Cases](#common-use-cases)
+- [Advanced Scenarios](#advanced-scenarios)
+
+## BASIC Examples
+
+### Simple Message Sender
+
+```basic
+REM Send a simple text message via WhatsApp
+SEND WHATSAPP TO "+5511999999999" WITH "Hello from General Bots!"
+```
+
+### Interactive Bot Response
+
+```basic
+REM Handle incoming WhatsApp messages
+ON WHATSAPP MESSAGE RECEIVED
+ REM Get message details
+ LET SENDER$ = GET WHATSAPP SENDER NUMBER
+ LET MESSAGE$ = GET WHATSAPP MESSAGE BODY
+ LET MESSAGE_ID$ = GET WHATSAPP MESSAGE ID
+
+ REM Log the incoming message
+ LOG "Received from " + SENDER$ + ": " + MESSAGE$
+
+ REM Process based on message content
+ IF INSTR(UCASE$(MESSAGE$), "HELP") > 0 THEN
+ SEND HELP MENU TO SENDER$
+ ELSEIF INSTR(UCASE$(MESSAGE$), "STATUS") > 0 THEN
+ SEND STATUS UPDATE TO SENDER$
+ ELSE
+ SEND DEFAULT RESPONSE TO SENDER$
+ END IF
+END ON
+
+SUB SEND HELP MENU TO NUMBER$
+ LET MENU$ = "π€ *Bot Menu*" + CHR$(10)
+ MENU$ = MENU$ + CHR$(10) + "1. π Status - Check system status"
+ MENU$ = MENU$ + CHR$(10) + "2. π Weather - Get weather info"
+ MENU$ = MENU$ + CHR$(10) + "3. π§ Contact - Get support contact"
+ MENU$ = MENU$ + CHR$(10) + CHR$(10) + "Reply with a number or keyword"
+
+ SEND WHATSAPP TO NUMBER$ WITH MENU$
+END SUB
+
+SUB SEND STATUS UPDATE TO NUMBER$
+ LET STATUS$ = "β
*System Status*" + CHR$(10)
+ STATUS$ = STATUS$ + CHR$(10) + "πΉ Bot: Online"
+ STATUS$ = STATUS$ + CHR$(10) + "πΉ Uptime: " + GET SYSTEM UPTIME$()
+ STATUS$ = STATUS$ + CHR$(10) + "πΉ Memory: " + GET MEMORY USAGE$()
+
+ SEND WHATSAPP TO NUMBER$ WITH STATUS$
+END SUB
+
+SUB SEND DEFAULT RESPONSE TO NUMBER$
+ LET RESPONSE$ = "π Hello! I'm your General Bot assistant."
+ RESPONSE$ = RESPONSE$ + CHR$(10) + CHR$(10) + "Type *help* to see available commands."
+
+ SEND WHATSAPP TO NUMBER$ WITH RESPONSE$
+END SUB
+```
+
+### Message with Formatting
+
+```basic
+REM Send message with rich text formatting
+SEND WHATSAPP TO "+5511999999999" WITH "*Bold text* and _italics_ and ~strikethrough~"
+```
+
+### Send Location
+
+```basic
+REM Send a location message
+SEND WHATSAPP TO "+5511999999999" WITH LOCATION AT "-23.5505,-46.6333" NAMED "SΓ£o Paulo" WITH ADDRESS "SΓ£o Paulo, Brazil"
+```
+
+### Send Media (Image)
+
+```basic
+REM Send an image from URL
+SEND WHATSAPP TO "+5511999999999" WITH IMAGE FROM "https://example.com/image.jpg" AND CAPTION "Check this out!"
+```
+
+### Interactive Menu with Button Response
+
+```basic
+REM Create an interactive menu
+REM Note: Interactive templates must be pre-approved by Meta
+
+REM Send a list message
+SEND WHATSAPP TO "+5511999999999" WITH LIST "Choose an option" WITH HEADER "Main Menu" AND ITEMS "Status,Help,Contact,About"
+```
+
+## Node.js Examples
+
+### Configuration Setup
+
+```javascript
+// config.js
+module.exports = {
+ whatsapp: {
+ apiKey: process.env.WHATSAPP_API_KEY || 'EAAQdlso6aM8BOwlhc3yM6bbJkGyibQPGJd87zFDHtfaFoJDJPohMl2c5nXs4yYuuHwoXJWx0rQKo0VXgTwThPYzqLEZArOZBhCWPBUpq7YlkEJXFAgB6ZAb3eoUzZAMgNZCZA1sg11rT2G8e1ZAgzpRVRffU4jmMChc7ybcyIwbtGOPKZAXKcNoMRfUwssoLhDWr',
+ phoneNumberId: process.env.WHATSAPP_PHONE_NUMBER_ID || '1158433381968079',
+ wabaId: process.env.WHATSAPP_WABA_ID || '390727550789228',
+ verifyToken: process.env.WHATSAPP_VERIFY_TOKEN || '4qIogZadggQ.BEoMeciXIdl_MlkV_1DTx8Z_i0bYPxtSJwKSbH0FKlY',
+ apiVersion: 'v18.0'
+ }
+};
+```
+
+### Send Text Message
+
+```javascript
+// whatsapp-client.js
+const axios = require('axios');
+const config = require('./config');
+
+class WhatsAppClient {
+ constructor() {
+ this.baseURL = `https://graph.facebook.com/${config.whatsapp.apiVersion}`;
+ this.phoneNumberId = config.whatsapp.phoneNumberId;
+ this.accessToken = config.whatsapp.apiKey;
+ }
+
+ async sendText(to, message) {
+ try {
+ const response = await axios.post(
+ `${this.baseURL}/${this.phoneNumberId}/messages`,
+ {
+ messaging_product: 'whatsapp',
+ to: to.replace(/[^\d]/g, ''), // Remove non-digits
+ type: 'text',
+ text: {
+ body: message
+ }
+ },
+ {
+ headers: {
+ 'Authorization': `Bearer ${this.accessToken}`,
+ 'Content-Type': 'application/json'
+ }
+ }
+ );
+
+ return response.data;
+ } catch (error) {
+ console.error('Error sending message:', error.response?.data || error.message);
+ throw error;
+ }
+ }
+
+ async sendFormattedText(to, message) {
+ // WhatsApp formatting: *bold*, _italics_, ~strikethrough~, ```monospace```
+ return await this.sendText(to, message);
+ }
+}
+
+module.exports = WhatsAppClient;
+```
+
+### Send Media Message
+
+```javascript
+// Extend WhatsAppClient with media methods
+class WhatsAppClientWithMedia extends WhatsAppClient {
+ async sendImage(to, imageUrl, caption = '') {
+ try {
+ const response = await axios.post(
+ `${this.baseURL}/${this.phoneNumberId}/messages`,
+ {
+ messaging_product: 'whatsapp',
+ to: to.replace(/[^\d]/g, ''),
+ type: 'image',
+ image: {
+ link: imageUrl,
+ caption: caption
+ }
+ },
+ {
+ headers: {
+ 'Authorization': `Bearer ${this.accessToken}`,
+ 'Content-Type': 'application/json'
+ }
+ }
+ );
+
+ return response.data;
+ } catch (error) {
+ console.error('Error sending image:', error.response?.data || error.message);
+ throw error;
+ }
+ }
+
+ async sendDocument(to, documentUrl, filename, caption = '') {
+ try {
+ const response = await axios.post(
+ `${this.baseURL}/${this.phoneNumberId}/messages`,
+ {
+ messaging_product: 'whatsapp',
+ to: to.replace(/[^\d]/g, ''),
+ type: 'document',
+ document: {
+ link: documentUrl,
+ filename: filename,
+ caption: caption
+ }
+ },
+ {
+ headers: {
+ 'Authorization': `Bearer ${this.accessToken}`,
+ 'Content-Type': 'application/json'
+ }
+ }
+ );
+
+ return response.data;
+ } catch (error) {
+ console.error('Error sending document:', error.response?.data || error.message);
+ throw error;
+ }
+ }
+
+ async sendLocation(to, latitude, longitude, name, address) {
+ try {
+ const response = await axios.post(
+ `${this.baseURL}/${this.phoneNumberId}/messages`,
+ {
+ messaging_product: 'whatsapp',
+ to: to.replace(/[^\d]/g, ''),
+ type: 'location',
+ location: {
+ latitude: latitude,
+ longitude: longitude,
+ name: name,
+ address: address
+ }
+ },
+ {
+ headers: {
+ 'Authorization': `Bearer ${this.accessToken}`,
+ 'Content-Type': 'application/json'
+ }
+ }
+ );
+
+ return response.data;
+ } catch (error) {
+ console.error('Error sending location:', error.response?.data || error.message);
+ throw error;
+ }
+ }
+}
+
+module.exports = WhatsAppClientWithMedia;
+```
+
+### Webhook Handler (Express)
+
+```javascript
+// webhook-handler.js
+const express = require('express');
+const WhatsAppClient = require('./whatsapp-client');
+
+const app = express();
+app.use(express.json());
+
+const whatsapp = new WhatsAppClient();
+
+// Webhook verification (GET request)
+app.get('/webhooks/whatsapp', (req, res) => {
+ const mode = req.query['hub.mode'];
+ const token = req.query['hub.verify_token'];
+ const challenge = req.query['hub.challenge'];
+
+ const VERIFY_TOKEN = '4qIogZadggQ.BEoMeciXIdl_MlkV_1DTx8Z_i0bYPxtSJwKSbH0FKlY';
+
+ if (mode === 'subscribe' && token === VERIFY_TOKEN) {
+ console.log('β
Webhook verified');
+ res.status(200).send(challenge);
+ } else {
+ console.log('β Webhook verification failed');
+ res.sendStatus(403);
+ }
+});
+
+// Webhook message handler (POST request)
+app.post('/webhooks/whatsapp', async (req, res) => {
+ try {
+ const data = req.body;
+
+ if (data.object === 'whatsapp_business_account') {
+ for (const entry of data.entry) {
+ for (const change of entry.changes) {
+ if (change.field === 'messages') {
+ const message = change.value.messages[0];
+ await handleMessage(message);
+ }
+ }
+ }
+ }
+
+ res.status(200).send('OK');
+ } catch (error) {
+ console.error('β Webhook error:', error);
+ res.status(500).send('Error');
+ }
+});
+
+async function handleMessage(message) {
+ const from = message.from;
+ const body = message.text.body;
+ const messageId = message.id;
+ const timestamp = message.timestamp;
+
+ console.log(`π© Message from ${from}: ${body}`);
+
+ // Process the message
+ const response = await generateResponse(body);
+
+ // Send reply
+ await whatsapp.sendText(from, response);
+
+ // Mark as read (optional)
+ await markAsRead(messageId);
+}
+
+async function generateResponse(userMessage) {
+ const lowerMessage = userMessage.toLowerCase();
+
+ if (lowerMessage.includes('help') || lowerMessage === '1') {
+ return `π€ *Bot Menu*
+
+1. π Status - Check system status
+2. π Weather - Get weather info
+3. π§ Contact - Get support contact
+
+Reply with a number or keyword`;
+ } else if (lowerMessage.includes('status') || lowerMessage === '2') {
+ return `β
*System Status*
+
+πΉ Bot: Online
+πΉ Uptime: ${process.uptime().toFixed(2)}s
+πΉ Memory: ${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)}MB
+
+Type *help* for more options.`;
+ } else {
+ return `π Hello! I'm your General Bot assistant.
+
+Type *help* to see available commands.
+
+You said: ${userMessage}`;
+ }
+}
+
+async function markAsRead(messageId) {
+ try {
+ await axios.post(
+ `https://graph.facebook.com/${config.whatsapp.apiVersion}/${messageId}`,
+ {
+ messaging_product: 'whatsapp',
+ status: 'read'
+ },
+ {
+ headers: {
+ 'Authorization': `Bearer ${config.whatsapp.apiKey}`,
+ 'Content-Type': 'application/json'
+ }
+ }
+ );
+ } catch (error) {
+ console.error('Error marking as read:', error.message);
+ }
+}
+
+const PORT = process.env.PORT || 3000;
+app.listen(PORT, () => {
+ console.log(`π WhatsApp webhook server running on port ${PORT}`);
+});
+```
+
+### Interactive Bot with Conversation State
+
+```javascript
+// conversation-bot.js
+const WhatsAppClient = require('./whatsapp-client');
+
+class ConversationBot {
+ constructor() {
+ this.whatsapp = new WhatsAppClient();
+ this.conversations = new Map(); // Store conversation state per user
+ }
+
+ async handleMessage(from, message) {
+ // Get or create conversation state
+ let state = this.conversations.get(from) || {
+ step: 'initial',
+ data: {}
+ };
+
+ // Process based on current step
+ const response = await this.processStep(state, message);
+
+ // Update state
+ this.conversations.set(from, state);
+
+ // Send response
+ await this.whatsapp.sendText(from, response);
+ }
+
+ async processStep(state, message) {
+ const lowerMessage = message.toLowerCase();
+
+ switch (state.step) {
+ case 'initial':
+ if (lowerMessage.includes('order')) {
+ state.step = 'awaiting_product';
+ return 'π *Order Process*\n\nWhat product would you like to order?';
+ } else if (lowerMessage.includes('support')) {
+ state.step = 'awaiting_issue';
+ return 'π« *Support*\n\nPlease describe your issue:';
+ } else {
+ return 'π Welcome!\n\nReply with:\nβ’ "order" to place an order\nβ’ "support" for help';
+ }
+
+ case 'awaiting_product':
+ state.data.product = message;
+ state.step = 'awaiting_quantity';
+ return `π¦ Product: *${message}*\n\nHow many would you like?`;
+
+ case 'awaiting_quantity':
+ const quantity = parseInt(message);
+ if (isNaN(quantity) || quantity <= 0) {
+ return 'β Please enter a valid number.';
+ }
+ state.data.quantity = quantity;
+ state.step = 'confirm_order';
+ return `π *Order Summary*\n\nProduct: ${state.data.product}\nQuantity: ${quantity}\n\nReply "confirm" to place order or "cancel" to start over.`;
+
+ case 'confirm_order':
+ if (lowerMessage === 'confirm') {
+ // Process order
+ const orderId = await this.placeOrder(state.data);
+ state.step = 'initial';
+ state.data = {};
+ return `β
Order placed successfully!\n\nOrder ID: ${orderId}\n\nThank you for your business!`;
+ } else if (lowerMessage === 'cancel') {
+ state.step = 'initial';
+ state.data = {};
+ return 'β Order cancelled.\n\nReply with "order" to start over.';
+ } else {
+ return 'Please reply "confirm" or "cancel".';
+ }
+
+ case 'awaiting_issue':
+ state.data.issue = message;
+ state.step = 'confirm_ticket';
+ return `π *Issue Description*\n\n${message}\n\nReply "confirm" to submit ticket or "cancel" to discard.`;
+
+ case 'confirm_ticket':
+ if (lowerMessage === 'confirm') {
+ const ticketId = await this.createTicket(state.data);
+ state.step = 'initial';
+ state.data = {};
+ return `β
Support ticket created!\n\nTicket ID: ${ticketId}\n\nOur team will review your issue shortly.`;
+ } else if (lowerMessage === 'cancel') {
+ state.step = 'initial';
+ state.data = {};
+ return 'β Ticket cancelled.\n\nReply with "support" to start over.';
+ } else {
+ return 'Please reply "confirm" or "cancel".';
+ }
+
+ default:
+ state.step = 'initial';
+ return 'π Welcome!\n\nReply with:\nβ’ "order" to place an order\nβ’ "support" for help';
+ }
+ }
+
+ async placeOrder(data) {
+ // Implement order placement logic
+ return 'ORD-' + Date.now();
+ }
+
+ async createTicket(data) {
+ // Implement ticket creation logic
+ return 'TKT-' + Date.now();
+ }
+}
+
+module.exports = ConversationBot;
+```
+
+## Python Examples
+
+### Configuration Setup
+
+```python
+# config.py
+import os
+from dataclasses import dataclass
+
+@dataclass
+class WhatsAppConfig:
+ api_key: str = os.getenv('WHATSAPP_API_KEY', 'EAAQdlso6aM8BOwlhc3yM6bbJkGyibQPGJd87zFDHtfaFoJDJPohMl2c5nXs4yYuuHwoXJWx0rQKo0VXgTwThPYzqLEZArOZBhCWPBUpq7YlkEJXFAgB6ZAb3eoUzZAMgNZCZA1sg11rT2G8e1ZAgzpRVRffU4jmMChc7ybcyIwbtGOPKZAXKcNoMRfUwssoLhDWr')
+ phone_number_id: str = os.getenv('WHATSAPP_PHONE_NUMBER_ID', '1158433381968079')
+ waba_id: str = os.getenv('WHATSAPP_WABA_ID', '390727550789228')
+ verify_token: str = os.getenv('WHATSAPP_VERIFY_TOKEN', '4qIogZadggQ.BEoMeciXIdl_MlkV_1DTx8Z_i0bYPxtSJwKSbH0FKlY')
+ api_version: str = 'v18.0'
+
+config = WhatsAppConfig()
+```
+
+### WhatsApp Client
+
+```python
+# whatsapp_client.py
+import requests
+from typing import Dict, Optional
+from config import config
+
+class WhatsAppClient:
+ def __init__(self):
+ self.base_url = f"https://graph.facebook.com/{config.api_version}"
+ self.phone_number_id = config.phone_number_id
+ self.access_token = config.api_key
+ self.headers = {
+ 'Authorization': f'Bearer {self.access_token}',
+ 'Content-Type': 'application/json'
+ }
+
+ def send_text(self, to: str, message: str) -> Dict:
+ """Send a text message via WhatsApp"""
+ url = f"{self.base_url}/{self.phone_number_id}/messages"
+
+ # Clean phone number (remove non-digits)
+ to = ''.join(filter(str.isdigit, to))
+
+ payload = {
+ 'messaging_product': 'whatsapp',
+ 'to': to,
+ 'type': 'text',
+ 'text': {
+ 'body': message
+ }
+ }
+
+ response = requests.post(url, json=payload, headers=self.headers)
+ response.raise_for_status()
+ return response.json()
+
+ def send_image(self, to: str, image_url: str, caption: str = '') -> Dict:
+ """Send an image message"""
+ url = f"{self.base_url}/{self.phone_number_id}/messages"
+
+ to = ''.join(filter(str.isdigit, to))
+
+ payload = {
+ 'messaging_product': 'whatsapp',
+ 'to': to,
+ 'type': 'image',
+ 'image': {
+ 'link': image_url,
+ 'caption': caption
+ }
+ }
+
+ response = requests.post(url, json=payload, headers=self.headers)
+ response.raise_for_status()
+ return response.json()
+
+ def send_location(self, to: str, latitude: float, longitude: float,
+ name: str, address: str) -> Dict:
+ """Send a location message"""
+ url = f"{self.base_url}/{self.phone_number_id}/messages"
+
+ to = ''.join(filter(str.isdigit, to))
+
+ payload = {
+ 'messaging_product': 'whatsapp',
+ 'to': to,
+ 'type': 'location',
+ 'location': {
+ 'latitude': latitude,
+ 'longitude': longitude,
+ 'name': name,
+ 'address': address
+ }
+ }
+
+ response = requests.post(url, json=payload, headers=self.headers)
+ response.raise_for_status()
+ return response.json()
+
+ def mark_as_read(self, message_id: str) -> Dict:
+ """Mark a message as read"""
+ url = f"{self.base_url}/{message_id}"
+
+ payload = {
+ 'messaging_product': 'whatsapp',
+ 'status': 'read'
+ }
+
+ response = requests.post(url, json=payload, headers=self.headers)
+ response.raise_for_status()
+ return response.json()
+```
+
+### Flask Webhook Handler
+
+```python
+# webhook_handler.py
+from flask import Flask, request, jsonify
+import logging
+from whatsapp_client import WhatsAppClient
+from config import config
+
+app = Flask(__name__)
+whatsapp = WhatsAppClient()
+logging.basicConfig(level=logging.INFO)
+
+@app.route('/webhooks/whatsapp', methods=['GET'])
+def verify_webhook():
+ """Verify webhook with Meta"""
+ mode = request.args.get('hub.mode')
+ token = request.args.get('hub.verify_token')
+ challenge = request.args.get('hub.challenge')
+
+ VERIFY_TOKEN = config.verify_token
+
+ if mode == 'subscribe' and token == VERIFY_TOKEN:
+ logging.info("β
Webhook verified")
+ return challenge, 200
+ else:
+ logging.error("β Webhook verification failed")
+ return 'Forbidden', 403
+
+@app.route('/webhooks/whatsapp', methods=['POST'])
+def webhook_handler():
+ """Handle incoming WhatsApp messages"""
+ try:
+ data = request.get_json()
+
+ if data.get('object') == 'whatsapp_business_account':
+ for entry in data.get('entry', []):
+ for change in entry.get('changes', []):
+ if change.get('field') == 'messages':
+ message = change['value']['messages'][0]
+ handle_message(message)
+
+ return 'OK', 200
+ except Exception as e:
+ logging.error(f"β Webhook error: {e}")
+ return 'Error', 500
+
+def handle_message(message):
+ """Process incoming message"""
+ from_number = message['from']
+ body = message['text']['body']
+ message_id = message['id']
+
+ logging.info(f"π© Message from {from_number}: {body}")
+
+ # Generate response
+ response = generate_response(body)
+
+ # Send reply
+ whatsapp.send_text(from_number, response)
+
+ # Mark as read
+ whatsapp.mark_as_read(message_id)
+
+def generate_response(user_message: str) -> str:
+ """Generate bot response based on user input"""
+ lower_message = user_message.lower()
+
+ if 'help' in lower_message or lower_message == '1':
+ return """π€ *Bot Menu*
+
+1. π Status - Check system status
+2. π Weather - Get weather info
+3. π§ Contact - Get support contact
+
+Reply with a number or keyword"""
+
+ elif 'status' in lower_message or lower_message == '2':
+ return f"""β
*System Status*
+
+πΉ Bot: Online
+πΉ Uptime: Active
+πΉ Version: 1.0.0
+
+Type *help* for more options."""
+
+ else:
+ return f"""π Hello! I'm your General Bot assistant.
+
+Type *help* to see available commands.
+
+You said: {user_message}"""
+
+if __name__ == '__main__':
+ app.run(host='0.0.0.0', port=3000, debug=True)
+```
+
+## Common Use Cases
+
+### 1. Order Confirmation Bot
+
+```basic
+REM Order confirmation workflow
+ON WHATSAPP MESSAGE RECEIVED
+ LET SENDER$ = GET WHATSAPP SENDER NUMBER
+ LET MESSAGE$ = GET WHATSAPP MESSAGE BODY
+
+ IF LEFT$(MESSAGE$, 5) = "ORDER" THEN
+ REM Extract order ID (format: ORDER 12345)
+ LET ORDER_ID$ = MID$(MESSAGE$, 7)
+
+ REM Fetch order details from database
+ LET ORDER_DETAILS$ = GET ORDER DETAILS ORDER_ID$
+
+ REM Send confirmation
+ SEND WHATSAPP TO SENDER$ WITH "β
Order " + ORDER_ID$ + " confirmed!" + CHR$(10) + ORDER_DETAILS$
+ ELSE
+ SEND WHATSAPP TO SENDER$ WITH "Send 'ORDER ' to check your order status"
+ END IF
+END ON
+```
+
+### 2. Weather Information Bot
+
+```javascript
+// Node.js weather bot
+async function handleWeatherRequest(location) {
+ try {
+ // Call weather API
+ const weatherData = await fetchWeatherData(location);
+
+ // Format response
+ const response = `π€οΈ *Weather in ${location}*
+
+Temperature: ${weatherData.main.temp}Β°C
+Condition: ${weatherData.weather[0].description}
+Humidity: ${weatherData.main.humidity}%
+Wind: ${weatherData.wind.speed} m/s
+
+Have a great day!`;
+
+ return response;
+ } catch (error) {
+ return 'β Unable to fetch weather data. Please try again.';
+ }
+}
+
+// In webhook handler
+if (lowerMessage.includes('weather')) {
+ const location = lowerMessage.replace('weather', '').trim() || 'SΓ£o Paulo';
+ const response = await handleWeatherRequest(location);
+ await whatsapp.sendText(from, response);
+}
+```
+
+### 3. Support Ticket System
+
+```python
+# Python support ticket bot
+class SupportBot:
+ def __init__(self):
+ self.whatsapp = WhatsAppClient()
+ self.tickets = {}
+
+ def handle_support_request(self, from_number, issue):
+ # Create ticket
+ ticket_id = f"TKT-{int(time.time())}"
+ self.tickets[ticket_id] = {
+ 'from': from_number,
+ 'issue': issue,
+ 'status': 'open',
+ 'created_at': datetime.now()
+ }
+
+ # Send confirmation
+ response = f"""π« *Support Ticket Created*
+
+Ticket ID: {ticket_id}
+Status: Open
+Issue: {issue}
+
+Our team will review your request shortly.
+Reply with 'STATUS {ticket_id}' to check updates."""
+
+ self.whatsapp.send_text(from_number, response)
+
+ def check_ticket_status(self, from_number, ticket_id):
+ if ticket_id in self.tickets:
+ ticket = self.tickets[ticket_id]
+ response = f"""π *Ticket Status*
+
+ID: {ticket_id}
+Status: {ticket['status'].title()}
+Created: {ticket['created_at'].strftime('%Y-%m-%d %H:%M')}
+
+Issue: {ticket['issue']}"""
+ else:
+ response = f"β Ticket {ticket_id} not found."
+
+ self.whatsapp.send_text(from_number, response)
+```
+
+### 4. Appointment Scheduling
+
+```basic
+REM Appointment scheduling bot
+ON WHATSAPP MESSAGE RECEIVED
+ LET SENDER$ = GET WHATSAPP SENDER NUMBER
+ LET MESSAGE$ = GET WHATSAPP MESSAGE BODY
+
+ IF LEFT$(MESSAGE$, 5) = "BOOK " THEN
+ REM Parse date (format: BOOK 2024-01-15 14:00)
+ LET DATE_STR$ = MID$(MESSAGE$, 6)
+
+ REM Check availability
+ IF CHECK AVAILABILITY DATE_STR$ THEN
+ REM Book appointment
+ LET CONFIRMATION$ = BOOK APPOINTMENT SENDER$, DATE_STR$
+
+ REM Send confirmation
+ SEND WHATSAPP TO SENDER$ WITH "π
Appointment Confirmed!" + CHR$(10) + CONFIRMATION$
+ ELSE
+ SEND WHATSAPP TO SENDER$ WITH "β Date not available. Please choose another time."
+ END IF
+ END IF
+END ON
+```
+
+### 5. Poll/Survey Bot
+
+```javascript
+// Node.js survey bot
+class SurveyBot {
+ constructor() {
+ this.surveys = {};
+ this.responses = {};
+ }
+
+ async createSurvey(from, question, options) {
+ const surveyId = `SURV-${Date.now()}`;
+
+ this.surveys[surveyId] = {
+ question,
+ options,
+ responses: []
+ };
+
+ let message = `π *Survey*\n\n${question}\n\n`;
+ options.forEach((opt, i) => {
+ message += `${i + 1}. ${opt}\n`;
+ });
+ message += '\nReply with the option number to vote.';
+
+ await this.whatsapp.sendText(from, message);
+ return surveyId;
+ }
+
+ async handleResponse(from, surveyId, choice) {
+ if (this.surveys[surveyId]) {
+ const survey = this.surveys[surveyId];
+
+ if (choice >= 1 && choice <= survey.options.length) {
+ survey.responses.push({
+ from,
+ choice,
+ timestamp: new Date()
+ });
+
+ const selectedOption = survey.options[choice - 1];
+ await this.whatsapp.sendText(from, `β
You voted for: ${selectedOption}`);
+ } else {
+ await this.whatsapp.sendText(from, 'β Invalid option. Please try again.');
+ }
+ }
+ }
+}
+```
+
+### 6. Broadcast Message Sender
+
+```python
+# Python broadcast sender
+class BroadcastSender:
+ def __init__(self):
+ self.whatsapp = WhatsAppClient()
+
+ def send_broadcast(self, recipients, message):
+ """Send message to multiple recipients"""
+ success_count = 0
+ failed_count = 0
+
+ for recipient in recipients:
+ try:
+ self.whatsapp.send_text(recipient, message)
+ success_count += 1
+ time.sleep(1) # Rate limiting
+ except Exception as e:
+ logging.error(f"Failed to send to {recipient}: {e}")
+ failed_count += 1
+
+ return {
+ 'total': len(recipients),
+ 'success': success_count,
+ 'failed': failed_count
+ }
+
+# Usage
+broadcast = BroadcastSender()
+recipients = ['+5511999999999', '+5511888888888', '+5511777777777']
+message = "π’ *Important Announcement*\n\nThis is a broadcast message to all subscribers."
+
+result = broadcast.send_broadcast(recipients, message)
+print(f"Sent: {result['success']}/{result['total']}")
+```
+
+### 7. File Download Bot
+
+```basic
+REM File download and send bot
+ON WHATSAPP MESSAGE RECEIVED
+ LET SENDER$ = GET WHATSAPP SENDER NUMBER
+ LET MESSAGE$ = GET WHATSAPP MESSAGE BODY
+
+ IF LEFT$(MESSAGE$, 4) = "GET " THEN
+ REM Extract filename
+ LET FILENAME$ = MID$(MESSAGE$, 5)
+
+ REM Check if file exists
+ IF FILE EXISTS("documents/" + FILENAME$) THEN
+ REM Get file URL
+ LET FILE_URL$ = "https://your-domain.com/files/" + FILENAME$
+
+ REM Send document
+ SEND WHATSAPP TO SENDER$ WITH DOCUMENT FROM FILE_URL$ NAMED FILENAME$
+ ELSE
+ SEND WHATSAPP TO SENDER$ WITH "β File not found: " + FILENAME$
+ END IF
+ END IF
+END ON
+```
+
+### 8. E-commerce Product Catalog
+
+```javascript
+// Product catalog bot
+const products = [
+ { id: 1, name: 'Wireless Headphones', price: 299.90, image: 'https://example.com/headphones.jpg' },
+ { id: 2, name: 'Smart Watch', price: 499.90, image: 'https://example.com/watch.jpg' },
+ { id: 3, name: 'Bluetooth Speaker', price: 199.90, image: 'https://example.com/speaker.jpg' }
+];
+
+async function showProductCatalog(to) {
+ let message = 'ποΈ *Product Catalog*\n\n';
+
+ products.forEach(product => {
+ message += `${product.id}. *${product.name}*\n`;
+ message += ` Price: R$ ${product.price.toFixed(2)}\n\n`;
+ });
+
+ message += 'Reply with product number to see details.';
+
+ await whatsapp.sendText(to, message);
+}
+
+async function showProductDetails(to, productId) {
+ const product = products.find(p => p.id === productId);
+
+ if (product) {
+ await whatsapp.sendImage(to, product.image, `π¦ *${product.name}*\n\nPrice: R$ ${product.price.toFixed(2)}\n\nReply 'BUY ${productId}' to purchase.`);
+ } else {
+ await whatsapp.sendText(to, 'β Product not found.');
+ }
+}
+
+// In webhook handler
+if (lowerMessage === 'catalog' || lowerMessage === 'products') {
+ await showProductCatalog(from);
+} else if (lowerMessage.startsWith('product ')) {
+ const productId = parseInt(lowerMessage.split(' ')[1]);
+ await showProductDetails(from, productId);
+}
+```
+
+### 9. Daily Digest/Notification Bot
+
+```python
+# Daily digest scheduler
+import schedule
+import time
+
+class DigestBot:
+ def __init__(self):
+ self.whatsapp = WhatsAppClient()
+ self.subscribers = set()
+
+ def subscribe(self, number):
+ self.subscribers.add(number)
+ return "β
Subscribed to daily digest!"
+
+ def unsubscribe(self, number):
+ self.subscribers.discard(number)
+ return "β Unsubscribed from daily digest."
+
+ def send_daily_digest(self):
+ digest = self.generate_digest()
+
+ for subscriber in self.subscribers:
+ try:
+ self.whatsapp.send_text(subscriber, digest)
+ except Exception as e:
+ logging.error(f"Failed to send digest to {subscriber}: {e}")
+
+ def generate_digest(self):
+ # Generate daily digest content
+ return f"""π° *Daily Digest*
+
+π
{datetime.now().strftime('%Y-%m-%d')}
+
+β’ Weather: Sunny, 25Β°C
+β’ News: 5 new articles
+β’ Events: 2 upcoming
+
+Have a great day! π"""
+
+ def start_scheduler(self):
+ schedule.every().day.at("09:00").do(self.send_daily_digest)
+
+ while True:
+ schedule.run_pending()
+ time.sleep(60)
+```
+
+### 10. Multi-language Support Bot
+
+```basic
+REM Multi-language bot
+ON WHATSAPP MESSAGE RECEIVED
+ LET SENDER$ = GET WHATSAPP SENDER NUMBER
+ LET MESSAGE$ = GET WHATSAPP MESSAGE BODY
+
+ REM Get user's preferred language (default: English)
+ LET LANG$ = GET USER LANGUAGE SENDER$
+
+ REM Check for language change command
+ IF LEFT$(MESSAGE$, 3) = "SET " THEN
+ LET NEW_LANG$ = UPPER$(MID$(MESSAGE$, 5))
+
+ IF NEW_LANG$ = "EN" OR NEW_LANG$ = "ES" OR NEW_LANG$ = "PT" THEN
+ SET USER LANGUAGE SENDER$ TO NEW_LANG$
+ SEND WHATSAPP TO SENDER$ WITH GET TEXT "language_set" IN NEW_LANG$
+ ELSE
+ SEND WHATSAPP TO SENDER$ WITH "β Unsupported language. Use: EN, ES, or PT"
+ END IF
+ ELSE
+ REM Process message in user's language
+ LET RESPONSE$ = PROCESS MESSAGE MESSAGE$ IN LANG$
+ SEND WHATSAPP TO SENDER$ WITH RESPONSE$
+ END IF
+END ON
+
+REM Language text retrieval
+FUNCTION GET TEXT$ KEY$, LANG$
+ IF LANG$ = "EN" THEN
+ IF KEY$ = "language_set" THEN RETURN "Language set to English β
"
+ IF KEY$ = "welcome" THEN RETURN "Welcome! How can I help you today?"
+ ELSEIF LANG$ = "ES" THEN
+ IF KEY$ = "language_set" THEN RETURN "Idioma establecido en EspaΓ±ol β
"
+ IF KEY$ = "welcome" THEN RETURN "Β‘Bienvenido! ΒΏCΓ³mo puedo ayudarte hoy?"
+ ELSEIF LANG$ = "PT" THEN
+ IF KEY$ = "language_set" THEN RETURN "Idioma definido para PortuguΓͺs β
"
+ IF KEY$ = "welcome" THEN RETURN "Bem-vindo! Como posso ajudΓ‘-lo hoje?"
+ END IF
+
+ RETURN "Text not found"
+END FUNCTION
+```
+
+## Advanced Scenarios
+
+### Conversation Flow Management
+
+```javascript
+// Advanced conversation state machine
+class ConversationFlow {
+ constructor() {
+ this.flows = {
+ 'sales': {
+ 'initial': async (from, input, state) => {
+ state.products = await getProducts();
+ return this.formatProductList(state.products);
+ },
+ 'selecting_product': async (from, input, state) => {
+ const product = state.products.find(p => p.id === parseInt(input));
+ if (product) {
+ state.selectedProduct = product;
+ state.step = 'confirming_purchase';
+ return `You selected: ${product.name}\nPrice: $${product.price}\n\nConfirm purchase? (yes/no)`;
+ }
+ return 'Invalid product. Please select a valid number.';
+ },
+ 'confirming_purchase': async (from, input, state) => {
+ if (input.toLowerCase() === 'yes') {
+ const order = await createOrder(from, state.selectedProduct);
+ state.step = 'completed';
+ return `β
Order created!\nOrder ID: ${order.id}\n\nThank you for your purchase!`;
+ } else if (input.toLowerCase() === 'no') {
+ state.step = 'initial';
+ return this.formatProductList(state.products);
+ }
+ return 'Please reply "yes" or "no".';
+ }
+ }
+ };
+ }
+
+ async processFlow(flowName, from, input, state) {
+ const flow = this.flows[flowName];
+ if (!flow) return 'Flow not found';
+
+ const handler = flow[state.step] || flow['initial'];
+ return await handler(from, input, state);
+ }
+
+ formatProductList(products) {
+ let message = 'ποΈ *Products*\n\n';
+ products.forEach((p, i) => {
+ message += `${i + 1}. ${p.name} - $${p.price}\n`;
+ });
+ message += '\nReply with the product number to purchase.';
+ return message;
+ }
+}
+```
+
+### Interactive Buttons and Lists
+
+```python
+# Interactive message templates (must be pre-approved in Meta)
+class InteractiveMessages:
+ @staticmethod
+ def send_list_message(to, header, body, options):
+ """Send an interactive list message"""
+ sections = [{
+ 'title': header,
+ 'rows': [{'id': str(i), 'title': opt, 'description': ''}
+ for i, opt in enumerate(options)]
+ }]
+
+ payload = {
+ 'messaging_product': 'whatsapp',
+ 'to': to,
+ 'type': 'interactive',
+ 'interactive': {
+ 'type': 'list',
+ 'header': {
+ 'type': 'text',
+ 'text': header
+ },
+ 'body': {
+ 'text': body
+ },
+ 'action': {
+ 'button': 'Select',
+ 'sections': sections
+ }
+ }
+ }
+
+ return send_interactive(payload)
+
+ @staticmethod
+ def send_button_message(to, text, buttons):
+ """Send an interactive button message"""
+ payload = {
+ 'messaging_product': 'whatsapp',
+ 'to': to,
+ 'type': 'interactive',
+ 'interactive': {
+ 'type': 'button',
+ 'body': {
+ 'text': text
+ },
+ 'action': {
+ 'buttons': [
+ {
+ 'type': 'reply',
+ 'reply': {'id': f'btn_{i}', 'title': btn}
+ } for i, btn in enumerate(buttons)
+ ]
+ }
+ }
+ }
+
+ return send_interactive(payload)
+```
+
+### Media Upload and Management
+
+```javascript
+// Media management utilities
+class MediaManager {
+ constructor(whatsappClient) {
+ this.whatsapp = whatsappClient;
+ this.mediaCache = new Map();
+ }
+
+ async uploadMedia(url, mediaType = 'image') {
+ // Check cache first
+ if (this.mediaCache.has(url)) {
+ return this.mediaCache.get(url);
+ }
+
+ try {
+ // Upload to Meta servers
+ const response = await axios.post(
+ `${this.baseURL}/${this.phone_number_id}/media`,
+ {
+ file: url,
+ type: mediaType
+ },
+ {
+ headers: {
+ 'Authorization': `Bearer ${this.accessToken}`
+ }
+ }
+ );
+
+ const mediaId = response.data.id;
+ this.mediaCache.set(url, mediaId);
+
+ return mediaId;
+ } catch (error) {
+ console.error('Media upload failed:', error);
+ throw error;
+ }
+ }
+
+ async sendCachedImage(to, imageUrl, caption = '') {
+ const mediaId = await this.uploadMedia(imageUrl);
+
+ return await this.whatsapp.send({
+ to,
+ type: 'image',
+ image: {
+ id: mediaId,
+ caption
+ }
+ });
+ }
+}
+```
+
+### Rate Limiting and Queue Management
+
+```python
+# Rate limiter for WhatsApp API
+from datetime import datetime, timedelta
+import time
+
+class RateLimiter:
+ def __init__(self, max_requests=1000, time_window=60):
+ self.max_requests = max_requests
+ self.time_window = time_window
+ self.requests = []
+ self.queue = []
+
+ def can_make_request(self):
+ now = datetime.now()
+ cutoff = now - timedelta(seconds=self.time_window)
+
+ # Remove old requests
+ self.requests = [r for r in self.requests if r > cutoff]
+
+ return len(self.requests) < self.max_requests
+
+ def record_request(self):
+ self.requests.append(datetime.now())
+
+ async def send_with_limit(self, send_func, *args, **kwargs):
+ if not self.can_make_request():
+ wait_time = self.time_window - (datetime.now() - self.requests[0]).total_seconds()
+ if wait_time > 0:
+ time.sleep(wait_time)
+
+ self.record_request()
+ return await send_func(*args, **kwargs)
+
+# Usage
+rate_limiter = RateLimiter(max_requests=50, time_window=60)
+
+async def send_message_safe(to, message):
+ await rate_limiter.send_with_limit(whatsapp.send_text, to, message)
+```
+
+## Testing Examples
+
+### Unit Tests for WhatsApp Client
+
+```javascript
+// whatsapp-client.test.js
+const WhatsAppClient = require('./whatsapp-client');
+const nock = require('nock');
+
+describe('WhatsAppClient', () => {
+ let client;
+
+ beforeEach(() => {
+ client = new WhatsAppClient();
+ });
+
+ test('sendText should send message successfully', async () => {
+ nock('https://graph.facebook.com')
+ .post('/v18.0/1158433381968079/messages')
+ .reply(200, {
+ messaging_product: 'whatsapp',
+ contacts: [{ input: '5511999999999', wa_id: '5511999999999' }],
+ messages: [{ id: 'wamid.example' }]
+ });
+
+ const result = await client.sendText('+5511999999999', 'Test message');
+
+ expect(result.messaging_product).toBe('whatsapp');
+ expect(result.messages[0].id).toBeDefined();
+ });
+
+ test('sendText should handle errors', async () => {
+ nock('https://graph.facebook.com')
+ .post('/v18.0/1158433381968079/messages')
+ .reply(400, {
+ error: {
+ message: 'Invalid phone number',
+ type: 'WhatsAppApiError'
+ }
+ });
+
+ await expect(
+ client.sendText('invalid', 'Test message')
+ ).rejects.toThrow();
+ });
+});
+```
+
+### Integration Tests with Twilio
+
+```python
+# twilio_integration_test.py
+import pytest
+from twilio_integration import TwilioWebhookHandler
+
+def test_voice_webhook_verification():
+ handler = TwilioWebhookHandler()
+
+ # Mock Twilio request
+ request_data = {
+ 'CallSid': 'CA123',
+ 'From': '+1234567890',
+ 'To': '+553322980098',
+ 'CallStatus': 'ringing'
+ }
+
+ # Process webhook
+ response = handler.handle_voice_call(request_data)
+
+ # Verify TwiML response
+ assert '' in response
+ assert '
+
+
+
+ Please enter your verification code followed by the pound sign.
+
+
+
+ https://twimlets.com/voicemail?Email=your-email@example.com
+
+
+```
+
+### Simple Voicemail
+
+```xml
+
+
+ Please leave your message after the tone.
+
+ Thank you for your message.
+
+```
+
+## Diagnostic Commands
+
+### Test Connectivity
+
+```bash
+# Test webhook endpoint
+curl -X POST https://your-domain.com/webhooks/whatsapp \
+ -H "Content-Type: application/json" \
+ -d '{"test": true}'
+
+# Test Meta API
+curl -X GET "https://graph.facebook.com/v18.0/1158433381968079" \
+ -H "Authorization: Bearer EAAQdlso6aM8BOwl..."
+
+# Test Twilio webhook
+curl -X POST https://your-domain.com/twilio/voice \
+ -d "CallSid=CA123&From=+1234567890&To=+553322980098"
+
+# Check SSL certificate
+openssl s_client -connect your-domain.com:443
+```
+
+### Monitor Logs
+
+```bash
+# General Bots logs
+tail -f .gbot/logs/bot.log
+
+# Webhook server logs (PM2)
+pm2 logs whatsapp-webhook
+
+# System logs
+journalctl -u whatsapp-webhook -f
+
+# Twilio debugger
+# https://console.twilio.com/us1/develop/monitor/debugger
+
+# Meta webhook status
+# https://developers.facebook.com/apps/YOUR_APP_ID/webhooks/
+```
+
+## Rate Limits
+
+### WhatsApp Business API
+
+| Tier | Messages/Day | Messages/Second |
+|------|--------------|-----------------|
+| Tier 1 | 1,000 | 1 |
+| Tier 2 | 10,000 | 5 |
+| Tier 3 | 100,000 | 50 |
+| Tier 4 | Unlimited | 1,000 |
+
+### Rate Limiting Implementation
+
+```javascript
+const rateLimiter = {
+ requests: [],
+ maxRequests: 50,
+ timeWindow: 60000, // 1 minute
+
+ canMakeRequest() {
+ const now = Date.now();
+ this.requests = this.requests.filter(t => now - t < this.timeWindow);
+ return this.requests.length < this.maxRequests;
+ },
+
+ recordRequest() {
+ this.requests.push(Date.now());
+ }
+};
+```
+
+## Formatting Syntax
+
+### Text Formatting
+
+```basic
+REM Bold text
+*bold text*
+
+REM Italics
+_italics_
+
+REM Strikethrough
+~strikethrough~
+
+REM Monospace
+```monospace```
+
+REM Combined
+*_bold and italic_*
+
+REM Line breaks
+Line 1
+Line 2
+```
+
+### Message Examples
+
+```basic
+REM Formatted menu
+SEND WHATSAPP TO "+5511999999999" WITH "π€ *Bot Menu*" + CHR$(10) + CHR$(10) + "1. π Status" + CHR$(10) + "2. π Weather" + CHR$(10) + "3. π§ Contact"
+
+REM Address
+SEND WHATSAPP TO "+5511999999999" WITH "π *Address:*" + CHR$(10) + "123 Main St" + CHR$(10) + "SΓ£o Paulo, SP" + CHR$(10) + "Brazil"
+
+REM Code snippet
+SEND WHATSAPP TO "+5511999999999" WITH "```bash" + CHR$(10) + "npm install" + CHR$(10) + "```"
+```
+
+## URLs
+
+### Meta Platforms
+
+```
+Meta for Developers:
+https://developers.facebook.com/
+
+Meta Business Suite:
+https://business.facebook.com/
+
+WhatsApp Business API:
+https://developers.facebook.com/docs/whatsapp/
+
+Webhook Configuration:
+https://developers.facebook.com/apps/YOUR_APP_ID/webhooks/
+
+Message Templates:
+https://business.facebook.com/latest/wa/manage/message-templates/
+```
+
+### Twilio Platforms
+
+```
+Twilio Console:
+https://console.twilio.com/
+
+Twilio Debugger:
+https://console.twilio.com/us1/develop/monitor/debugger
+
+TwiML Bins:
+https://console.twilio.com/us1/develop/twiml/bins
+
+Phone Numbers:
+https://console.twilio.com/us1/develop/phone-numbers/manage/active
+```
+
+### General Bots
+
+```
+Documentation:
+https://botbook.general-bots.com/
+
+Community Discord:
+https://discord.gg/general-bots
+
+GitHub Repository:
+https://github.com/general-bots/general-bots
+```
+
+## Quick Troubleshooting
+
+### Issue: Verification Code Not Received
+
+```bash
+# Check Twilio webhook is configured
+twilio phone-numerals:info +553322980098
+
+# Test webhook manually
+curl -X POST https://your-domain.com/twilio/voice \
+ -d "CallSid=CA123&From=+1234567890"
+
+# Verify voice capability is enabled
+# In Twilio Console: Phone Numbers > Active Numbers > Your Number
+# Check "Voice" is enabled
+```
+
+### Issue: Messages Not Sending
+
+```bash
+# Verify access token
+curl -X GET "https://graph.facebook.com/v18.0/me" \
+ -H "Authorization: Bearer YOUR_TOKEN"
+
+# Check phone number ID
+curl -X GET "https://graph.facebook.com/v18.0/1158433381968079" \
+ -H "Authorization: Bearer YOUR_TOKEN"
+
+# Test message format
+# Ensure phone number: 5511999999999 (no +, no spaces)
+```
+
+### Issue: Webhook Not Receiving Messages
+
+```bash
+# Verify webhook subscription
+curl -X GET "https://graph.facebook.com/v18.0/YOUR_APP_ID/subscriptions" \
+ -H "Authorization: Bearer YOUR_TOKEN"
+
+# Test webhook endpoint
+curl -X POST https://your-domain.com/webhooks/whatsapp \
+ -H "Content-Type: application/json" \
+ -d '{"object":"whatsapp_business_account","entry":[]}'
+
+# Check webhook is subscribed to "messages" field
+# In Meta Dashboard: WhatsApp > API Setup > Webhook > Manage
+```
+
+## Code Snippets
+
+### Validate Phone Number
+
+```javascript
+function validatePhoneNumber(phone) {
+ // Remove non-digits
+ const cleaned = phone.replace(/\D/g, '');
+
+ // Check length (10-15 digits)
+ if (cleaned.length < 10 || cleaned.length > 15) {
+ return false;
+ }
+
+ // Check if all digits
+ if (!/^\d+$/.test(cleaned)) {
+ return false;
+ }
+
+ return cleaned;
+}
+```
+
+### Format WhatsApp Message
+
+```javascript
+function formatMessage(template, variables) {
+ let message = template;
+
+ for (const [key, value] of Object.entries(variables)) {
+ message = message.replace(new RegExp(`{{${key}}}`, 'g'), value);
+ }
+
+ return message;
+}
+
+// Usage
+const template = 'Hello {{name}}, your order {{orderId}} is confirmed!';
+const variables = { name: 'John', orderId: '12345' };
+const message = formatMessage(template, variables);
+// Result: "Hello John, your order 12345 is confirmed!"
+```
+
+### Retry Logic
+
+```javascript
+async function sendWithRetry(whatsapp, to, message, maxRetries = 3) {
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
+ try {
+ return await whatsapp.sendText(to, message);
+ } catch (error) {
+ if (attempt === maxRetries) {
+ throw error;
+ }
+
+ // Exponential backoff
+ const delay = Math.pow(2, attempt) * 1000;
+ await new Promise(resolve => setTimeout(resolve, delay));
+ }
+ }
+}
+```
+
+## Environment Checklist
+
+### Development
+
+```bash
+# Node.js
+npm install express twilio body-parser axios
+
+# Python
+pip install flask requests twilio
+
+# BASIC
+REM No installation required
+```
+
+### Production
+
+```bash
+# Reverse proxy (nginx)
+apt install nginx
+
+# Process manager (PM2)
+npm install -g pm2
+
+# SSL certificate (Let's Encrypt)
+apt install certbot python3-certbot-nginx
+```
+
+## Meta Console URLs
+
+### Direct Access
+
+Replace with your IDs:
+
+```
+WhatsApp Settings:
+https://business.facebook.com/latest/settings/whatsapp_account/?business_id=312254061496740&selected_asset_id=303621682831134&selected_asset_type=whatsapp-business-account
+
+Webhook Configuration:
+https://developers.facebook.com/apps/323250907549153/webhooks/
+
+Message Templates:
+https://business.facebook.com/latest/wa/manage/message-templates/?waba_id=390727550789228
+
+API Usage:
+https://developers.facebook.com/apps/323250907549153/usage/
+```
+
+---
+
+**For detailed documentation:** See [README.md](./README.md)
+**For troubleshooting:** See [troubleshooting.md](./troubleshooting.md)
+**For code examples:** See [examples.md](./examples.md)
+**For webhook setup:** See [webhooks.md](./webhooks.md)
\ No newline at end of file
diff --git a/src/18-appendix-external-services/whatsapp-quick-start.md b/src/18-appendix-external-services/whatsapp-quick-start.md
new file mode 100644
index 00000000..f0852863
--- /dev/null
+++ b/src/18-appendix-external-services/whatsapp-quick-start.md
@@ -0,0 +1,298 @@
+# Quick Start Guide
+
+Get your WhatsApp Business bot up and running in 30 minutes with this streamlined setup guide.
+
+## Prerequisites Checklist
+
+- [ ] Twilio account with $10+ credit
+- [ ] Meta for Developers account
+- [ ] Meta Business Suite account
+- [ ] Publicly accessible webhook URL (use ngrok for testing)
+- [ ] Basic command line knowledge
+
+## 30-Minute Setup
+
+### Step 1: Buy Twilio Number (5 minutes)
+
+```bash
+# Log into Twilio Console
+# https://console.twilio.com/
+
+# Navigate to: Phone Numbers > Buy a Number
+# Select: Voice capability (required!)
+# Purchase number
+# Example: +553322980098
+```
+
+**Tip:** Choose a number from your target country for easier verification.
+
+### Step 2: Create Meta App (5 minutes)
+
+```bash
+# Go to Meta for Developers
+# https://developers.facebook.com/apps/
+
+# Click: Create App > Business type
+# App name: "My WhatsApp Bot"
+# Add product: WhatsApp
+# Create WhatsApp Business Account (WABA)
+```
+
+**Save these values:**
+```
+WABA ID: 390727550789228
+Application ID: 323250907549153
+Phone Number ID: (after verification)
+```
+
+### Step 3: Configure Twilio Webhook (5 minutes)
+
+**Option A: TwiML Bin (Fastest)**
+
+```xml
+
+
+
+
+ Please enter your verification code.
+
+
+```
+
+**Option B: ngrok + Node.js (Recommended)**
+
+```bash
+# Install dependencies
+npm install express twilio body-parser
+
+# Create server.js
+```
+
+```javascript
+const express = require('express');
+const twilio = require('twilio');
+const app = express();
+
+app.use(require('body-parser').urlencoded({ extended: false }));
+
+app.post('/twilio/voice', (req, res) => {
+ const twiml = new twilio.twiml.VoiceResponse();
+ twiml.redirect('https://twimlets.com/voicemail?Email=your-email@example.com');
+ res.type('text/xml');
+ res.send(twiml.toString());
+});
+
+app.listen(3000);
+```
+
+```bash
+# Start ngrok
+ngrok http 3000
+
+# Update Twilio number webhook to:
+# https://abc123.ngrok.io/twilio/voice
+```
+
+### Step 4: Verify Phone Number (5 minutes)
+
+```bash
+# In Meta Business Suite:
+# 1. WhatsApp Accounts > Add Phone Number
+# 2. Enter: +553322980098
+# 3. Select: "Phone Call" (NOT SMS!)
+# 4. Click: Verify
+
+# Meta will call your Twilio number
+# Check your email for the verification code
+# Enter code in Meta dashboard
+```
+
+**Critical:** Select "Phone Call" verification - Twilio numbers don't support SMS!
+
+### Step 5: Get API Credentials (3 minutes)
+
+```bash
+# In Meta for Developers:
+# 1. Your App > WhatsApp > API Setup
+# 2. Click: "Temporary Access Token"
+# 3. Copy token (starts with EAAQ...)
+# 4. Note Phone Number ID from URL
+```
+
+**Required credentials:**
+```csv
+whatsapp-api-key,EAAQdlso6aM8BOwlhc3yM6bbJkGyibQPGJd87zFDHtfaFoJDJPohMl2c5nXs4yYuuHwoXJWx0rQKo0VXgTwThPYzqLEZArOZBhCWPBUpq7YlkEJXFAgB6ZAb3eoUzZAMgNZCZA1sg11rT2G8e1ZAgzpRVRffU4jmMChc7ybcyIwbtGOPKZAXKcNoMRfUwssoLhDWr
+whatsapp-phone-number-id,1158433381968079
+whatsapp-business-account-id,390727550789228
+whatsapp-webhook-verify-token,4qIogZadggQ.BEoMeciXIdl_MlkV_1DTx8Z_i0bYPxtSJwKSbH0FKlY
+whatsapp-application-id,323250907549153
+whatsapp-enabled,true
+```
+
+### Step 6: Configure Webhook (5 minutes)
+
+```bash
+# Start your webhook server
+node server.js
+
+# In Meta Developers:
+# 1. WhatsApp > API Setup > Webhook > Edit
+# 2. Webhook URL: https://your-domain.com/webhooks/whatsapp
+# 3. Verify Token: 4qIogZadggQ.BEoMeciXIdl_MlkV_1DTx8Z_i0bYPxtSJwKSbH0FKlY
+# 4. Click: Verify and Save
+# 5. Subscribe to: messages
+```
+
+### Step 7: Configure General Bots (2 minutes)
+
+```bash
+# Edit .gbot/config.csv
+```
+
+```csv
+key,value
+whatsapp-enabled,true
+whatsapp-api-key,EAAQdlso6aM8BOwlhc3yM6bbJkGyibQPGJd87zFDHtfaFoJDJPohMl2c5nXs4yYuuHwoXJWx0rQKo0VXgTwThPYzqLEZArOZBhCWPBUpq7YlkEJXFAgB6ZAb3eoUzZAMgNZCZA1sg11rT2G8e1ZAgzpRVRffU4jmMChc7ybcyIwbtGOPKZAXKcNoMRfUwssoLhDWr
+whatsapp-phone-number-id,1158433381968079
+whatsapp-business-account-id,390727550789228
+whatsapp-webhook-verify-token,4qIogZadggQ.BEoMeciXIdl_MlkV_1DTx8Z_i0bYPxtSJwKSbH0FKlY
+whatsapp-application-id,323250907549153
+```
+
+### Step 8: Test Your Bot (5 minutes)
+
+```bash
+# Send test message via API
+curl -X POST \
+ 'https://graph.facebook.com/v18.0/1158433381968079/messages' \
+ -H 'Authorization: Bearer EAAQdlso6aM8BOwl...' \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "messaging_product": "whatsapp",
+ "to": "5511999999999",
+ "type": "text",
+ "text": {"body": "Hello from General Bots!"}
+ }'
+
+# Or use BASIC
+```
+
+```basic
+REM Test your WhatsApp integration
+SEND WHATSAPP TO "+5511999999999" WITH "Hello from General Bots!"
+```
+
+## Your First WhatsApp Bot
+
+Create a simple echo bot:
+
+```basic
+REM Simple WhatsApp Echo Bot
+ON WHATSAPP MESSAGE RECEIVED
+ LET SENDER$ = GET WHATSAPP SENDER NUMBER
+ LET MESSAGE$ = GET WHATSAPP MESSAGE BODY
+
+ LOG "Message from " + SENDER$ + ": " + MESSAGE$
+
+ REM Echo back with acknowledgment
+ SEND WHATSAPP TO SENDER$ WITH "You said: " + MESSAGE$
+END ON
+```
+
+## Common First-Time Mistakes
+
+β **Don't select SMS verification** - Use "Phone Call"
+β **Don't hardcode tokens** - Use config.csv
+β **Don't forget webhook subscriptions** - Subscribe to "messages"
+β **Don't use + in phone numbers** - Format: 5511999999999
+β **Don't ignore rate limits** - Max 1000 messages/second
+
+## Next Steps
+
+1. **Create message templates** for business-initiated conversations
+2. **Set up persistent storage** for conversation history
+3. **Implement retry logic** for failed messages
+4. **Add monitoring** for webhook health
+5. **Review security best practices**
+
+## Need Help?
+
+- π [Full Documentation](./README.md)
+- π§ [Troubleshooting Guide](./troubleshooting.md)
+- π» [Code Examples](./examples.md)
+- π [Webhook Configuration](./webhooks.md)
+- π¬ [Community Discord](https://discord.gg/general-bots)
+
+## Verification Checklist
+
+- [ ] Twilio number purchased with Voice capability
+- [ ] Meta app created with WhatsApp product
+- [ ] Phone number verified via phone call
+- [ ] Access token generated and saved
+- [ ] Webhook configured and verified
+- [ ] Webhook subscribed to "messages"
+- [ ] config.csv updated with all credentials
+- [ ] Test message sent successfully
+- [ ] Incoming webhook received
+- [ ] Bot replied to test message
+
+β
**All checked? Your WhatsApp bot is live!**
+
+## Quick Reference: Essential Commands
+
+```bash
+# Test webhook connectivity
+curl -X POST https://your-webhook.com/webhooks/whatsapp \
+ -H "Content-Type: application/json" \
+ -d '{"test":true}'
+
+# Check Meta API status
+curl https://developers.facebook.com/status/
+
+# View Twilio call logs
+# https://console.twilio.com/us1/develop/monitor/logs/calls
+
+# Test access token
+curl -X GET "https://graph.facebook.com/v18.0/me" \
+ -H "Authorization: Bearer YOUR_TOKEN"
+
+# Monitor bot logs
+tail -f .gbot/logs/bot.log
+```
+
+## Configuration Template
+
+Copy this template and replace with your values:
+
+```csv
+# WhatsApp Business Configuration
+whatsapp-enabled,true
+whatsapp-api-key,YOUR_ACCESS_TOKEN_HERE
+whatsapp-phone-number-id,YOUR_PHONE_NUMBER_ID_HERE
+whatsapp-business-account-id,YOUR_WABA_ID_HERE
+whatsapp-webhook-verify-token,YOUR_VERIFY_TOKEN_HERE
+whatsapp-application-id,YOUR_APP_ID_HERE
+whatsapp-from-number,+553322980098
+
+# Optional: Advanced Settings
+whatsapp-webhook-url,https://your-domain.com/webhooks/whatsapp
+whatsapp-timeout,30000
+whatsapp-retry-attempts,3
+whatsapp-rate-limit,50
+```
+
+## Time-Saving Tips
+
+π‘ **Use ngrok for testing** - No need to deploy to test webhooks
+π‘ **Save all credentials immediately** - Tokens won't be shown again
+π‘ **Test with your own number first** - Verify everything works
+π‘ **Enable debug logging** - Troubleshoot issues faster
+π‘ **Set up monitoring early** - Catch problems before users do
+
+---
+
+**Estimated total time:** 30 minutes
+**Difficulty:** Intermediate
+**Cost:** ~$10/month (Twilio number + usage)
+
+For detailed explanations, advanced configurations, and production deployment, see the [complete documentation](./README.md).
\ No newline at end of file
diff --git a/src/18-appendix-external-services/whatsapp-troubleshooting.md b/src/18-appendix-external-services/whatsapp-troubleshooting.md
new file mode 100644
index 00000000..177e7fe9
--- /dev/null
+++ b/src/18-appendix-external-services/whatsapp-troubleshooting.md
@@ -0,0 +1,1044 @@
+# Troubleshooting Guide
+
+This comprehensive guide helps you diagnose and resolve common issues when integrating WhatsApp Business API with Twilio phone numbers in General Bots.
+
+## Table of Contents
+
+- [Diagnostic Tools](#diagnostic-tools)
+- [Verification Issues](#verification-issues)
+- [Webhook Problems](#webhook-problems)
+- [API Errors](#api-errors)
+- [Message Delivery Failures](#message-delivery-failures)
+- [Twilio-Specific Issues](#twilio-specific-issues)
+- [Meta-Specific Issues](#meta-specific-issues)
+- [Performance Issues](#performance-issues)
+- [Security Issues](#security-issues)
+
+## Diagnostic Tools
+
+### Essential Commands
+
+```bash
+# Test webhook connectivity
+curl -X POST https://your-webhook-url/webhooks/whatsapp \
+ -H "Content-Type: application/json" \
+ -d '{"test": true}'
+
+# Check Meta API status
+curl https://developers.facebook.com/status/
+
+# Verify Twilio number configuration
+twilio phone-numbers:list +553322980098
+
+# Test Meta API connectivity
+curl -X GET "https://graph.facebook.com/v18.0/1158433381968079" \
+ -H "Authorization: Bearer EAAQdlso6aM8BOwl..."
+```
+
+### Log Locations
+
+```bash
+# General Bots logs
+tail -f .gbot/logs/bot.log
+
+# Webhook server logs (Node.js)
+pm2 logs whatsapp-webhook
+
+# Webhook server logs (Python)
+journalctl -u whatsapp-webhook -f
+
+# Twilio debugger
+https://console.twilio.com/us1/develop/monitor/debugger
+
+# Meta webhook debugging
+https://developers.facebook.com/apps/YOUR_APP_ID/webhooks/
+```
+
+## Verification Issues
+
+### Issue: Phone Number Verification Fails
+
+**Symptoms:**
+- Meta cannot verify your Twilio number
+- "Verification failed" error after call completes
+- No verification code received
+
+**Diagnosis:**
+
+```bash
+# Check Twilio number has Voice capability
+twilio phone-numbers:info +553322980098
+
+# Test incoming call handling
+# Call your Twilio number from another phone
+# Check if webhook is triggered
+```
+
+**Solutions:**
+
+1. **Verify Voice Webhook Configuration**
+ ```bash
+ # Check webhook URL is correct
+ curl -X POST https://your-domain.com/twilio/voice \
+ -d "CallSid=CA123&From=+1234567890&To=+553322980098"
+
+ # Expected: TwiML XML response
+ ```
+
+2. **Verify Verification Method**
+ - Ensure "Phone Call" is selected (not SMS)
+ - Twilio numbers don't support SMS for verification
+ - Meta must call your number
+
+3. **Check TwiML Response**
+ ```xml
+
+
+
+
+ Please enter your verification code.
+
+
+ ```
+
+4. **Test Webhook Locally**
+ ```bash
+ # Use ngrok for local testing
+ ngrok http 3000
+
+ # Update Twilio webhook to ngrok URL
+ # Test with actual Meta verification call
+ ```
+
+### Issue: Verification Code Not Captured
+
+**Symptoms:**
+- Call completes but no code received
+- Email not forwarded
+- Code not logged
+
+**Diagnosis:**
+
+```bash
+# Check webhook server logs
+tail -f /var/log/whatsapp-webhook/app.log
+
+# Verify Gather action is configured
+# Test DTMF capture with a test call
+```
+
+**Solutions:**
+
+1. **Implement Email Forwarding**
+ ```javascript
+ // Add to your gather handler
+ app.post('/twilio/gather', (req, res) => {
+ const code = req.body.Digits;
+
+ // Send email
+ sendEmail({
+ to: 'your-email@example.com',
+ subject: 'Verification Code',
+ body: `Code: ${code}`
+ });
+
+ // Also log it
+ console.log('Verification Code:', code);
+
+ res.type('text/xml');
+ res.send('Thank you');
+ });
+ ```
+
+2. **Use Voicemail Fallback**
+ ```xml
+
+ https://twimlets.com/voicemail?Email=your-email@example.com&Transcribe=true
+
+ ```
+
+3. **Add Logging**
+ ```basic
+ REM BASIC logging
+ ON WEBHOOK POST TO "/twilio/gather" DO
+ LET CODE$ = GET FORM VALUE "Digits"
+ LOG "Verification Code: " + CODE$
+ PRINT "Code logged"
+ END ON
+ ```
+
+## Webhook Problems
+
+### Issue: Webhook Verification Fails
+
+**Symptoms:**
+- Meta webhook setup shows "Verification failed"
+- "Challenge mismatch" error
+- 403 Forbidden response
+
+**Diagnosis:**
+
+```bash
+# Test webhook verification endpoint
+curl "https://your-domain.com/webhooks/whatsapp?hub.verify_token=YOUR_TOKEN&hub.challenge=CHALLENGE"
+
+# Expected response: The challenge string
+```
+
+**Solutions:**
+
+1. **Match Verify Token Exactly**
+ ```javascript
+ // In config.csv
+ whatsapp-webhook-verify-token,4qIogZadggQ.BEoMeciXIdl_MlkV_1DTx8Z_i0bYPxtSJwKSbH0FKlY
+
+ // In your code
+ const VERIFY_TOKEN = '4qIogZadggQ.BEoMeciXIdl_MlkV_1DTx8Z_i0bYPxtSJwKSbH0FKlY';
+
+ app.get('/webhooks/whatsapp', (req, res) => {
+ const token = req.query['hub.verify_token'];
+ if (token === VERIFY_TOKEN) {
+ res.send(req.query['hub.challenge']);
+ } else {
+ res.sendStatus(403);
+ }
+ });
+ ```
+
+2. **Return Challenge Correctly**
+ - Must return the challenge as plain text
+ - Must respond with 200 OK status
+ - Must not include HTML or JSON formatting
+
+3. **Check URL Accessibility**
+ ```bash
+ # Ensure URL is publicly accessible
+ curl -v https://your-domain.com/webhooks/whatsapp
+
+ # Check firewall rules
+ sudo ufw status
+
+ # Verify SSL certificate
+ openssl s_client -connect your-domain.com:443
+ ```
+
+### Issue: Webhook Not Receiving Messages
+
+**Symptoms:**
+- Webhook endpoint configured but no messages received
+- Messages appear in Meta inbox but not in bot
+- No webhook logs
+
+**Diagnosis:**
+
+```bash
+# Check webhook subscriptions in Meta dashboard
+# Navigate to: WhatsApp > API Setup > Webhook > Subscriptions
+
+# Verify webhook field subscription
+curl -X GET "https://graph.facebook.com/v18.0/YOUR_APP_ID/subscriptions" \
+ -H "Authorization: Bearer EAAQdlso6aM8BOwl..."
+```
+
+**Solutions:**
+
+1. **Subscribe to Messages Field**
+ ```
+ In Meta Dashboard:
+ 1. Go to WhatsApp > API Setup > Webhook
+ 2. Click "Manage" webhook fields
+ 3. Subscribe to: messages
+ 4. Save changes
+ ```
+
+2. **Check Webhook URL**
+ ```javascript
+ // Ensure correct webhook path
+ app.post('/webhooks/whatsapp', (req, res) => {
+ console.log('Webhook received:', JSON.stringify(req.body, null, 2));
+ res.status(200).send('OK');
+ });
+ ```
+
+3. **Verify Response Time**
+ - Webhook must respond within 3 seconds
+ - Process heavy operations asynchronously
+ - Return 200 OK immediately
+
+ ```javascript
+ app.post('/webhooks/whatsapp', (req, res) => {
+ // Acknowledge immediately
+ res.status(200).send('OK');
+
+ // Process asynchronously
+ setImmediate(() => {
+ processWebhook(req.body);
+ });
+ });
+ ```
+
+## API Errors
+
+### Issue: 401 Unauthorized
+
+**Symptoms:**
+- API calls return 401 status
+- "Invalid access token" error
+- Messages fail to send
+
+**Diagnosis:**
+
+```bash
+# Test access token validity
+curl -X GET "https://graph.facebook.com/v18.0/me" \
+ -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
+
+# Expected: JSON with app ID and name
+# 401 means token is invalid or expired
+```
+
+**Solutions:**
+
+1. **Generate New Access Token**
+ ```
+ In Meta Dashboard:
+ 1. Go to WhatsApp > API Setup
+ 2. Click "Temporary Access Token"
+ 3. Copy and update config.csv
+ 4. Restart bot
+ ```
+
+2. **Check Token Format**
+ ```csv
+ # config.csv
+ # Token must start with EAAQ...
+ whatsapp-api-key,EAAQdlso6aM8BOwlhc3yM6bbJkGyibQPGJd87zFDHtfaFoJDJPohMl2c5nXs4yYuuHwoXJWx0rQKo0VXgTwThPYzqLEZArOZBhCWPBUpq7YlkEJXFAgB6ZAb3eoUzZAMgNZCZA1sg11rT2G8e1ZAgzpRVRffU4jmMChc7ybcyIwbtGOPKZAXKcNoMRfUwssoLhDWr
+ ```
+
+3. **Verify Token Permissions**
+ ```
+ In Meta Dashboard:
+ 1. Go to App Review > Permissions and Features
+ 2. Ensure "WhatsApp" permission is granted
+ 3. Check for any additional required permissions
+ ```
+
+### Issue: 470 Message Rate Limit
+
+**Symptoms:**
+- Messages fail with 470 error
+- "Rate limit exceeded" message
+- Bulk sending stops working
+
+**Diagnosis:**
+
+```bash
+# Check API rate limits
+# WhatsApp Business API: 1000 messages/second per WABA
+
+# Monitor message queue
+tail -f .gbot/logs/message-queue.log
+```
+
+**Solutions:**
+
+1. **Implement Rate Limiting**
+ ```javascript
+ class RateLimiter {
+ constructor(maxRequests = 50, timeWindow = 60) {
+ this.maxRequests = maxRequests;
+ this.timeWindow = timeWindow;
+ this.requests = [];
+ }
+
+ async send(whatsapp, to, message) {
+ while (!this.canMakeRequest()) {
+ await this.sleep(1000);
+ }
+ this.recordRequest();
+ return await whatsapp.sendText(to, message);
+ }
+
+ canMakeRequest() {
+ const now = Date.now();
+ this.requests = this.requests.filter(t => now - t < this.timeWindow * 1000);
+ return this.requests.length < this.maxRequests;
+ }
+
+ recordRequest() {
+ this.requests.push(Date.now());
+ }
+
+ sleep(ms) {
+ return new Promise(resolve => setTimeout(resolve, ms));
+ }
+ }
+
+ const rateLimiter = new RateLimiter(50, 60);
+ await rateLimiter.send(whatsapp, to, message);
+ ```
+
+2. **Use Message Queuing**
+ ```basic
+ REM BASIC message queuing
+ SUB SEND WHATSAPP WITH RATE LIMIT TO NUMBER$, MESSAGE$
+ ADD TO QUEUE "whatsapp-outbound", NUMBER$ + "|" + MESSAGE$
+ END SUB
+ ```
+
+3. **Monitor Usage**
+ ```
+ In Meta Dashboard:
+ 1. Go to WhatsApp > API Usage
+ 2. Monitor message volume
+ 3. Check for rate limit warnings
+ ```
+
+### Issue: Invalid Phone Number Format
+
+**Symptoms:**
+- "Invalid phone number" error
+- Messages not delivered
+- 400 Bad Request
+
+**Diagnosis:**
+
+```bash
+# Test phone number format
+# Correct format: 5511999999999 (no +, no spaces, no dashes)
+```
+
+**Solutions:**
+
+1. **Format Phone Numbers Correctly**
+ ```javascript
+ function formatPhoneNumber(phone) {
+ // Remove all non-digits
+ let cleaned = phone.replace(/\D/g, '');
+
+ // Remove leading + or 00 if present
+ cleaned = cleaned.replace(/^(\+|00)/, '');
+
+ // Ensure country code is present
+ if (!cleaned.startsWith('55') && cleaned.length === 11) {
+ cleaned = '55' + cleaned;
+ }
+
+ return cleaned;
+ }
+
+ const formatted = formatPhoneNumber('+55 (11) 99999-9999');
+ // Result: 5511999999999
+ ```
+
+2. **Validate Before Sending**
+ ```basic
+ REM BASIC validation
+ SUB SEND VALIDATED WHATSAPP NUMBER$, MESSAGE$
+ LET CLEANED$ = ""
+ FOR I = 1 TO LEN(NUMBER$)
+ LET CH$ = MID$(NUMBER$, I, 1)
+ IF CH$ >= "0" AND CH$ <= "9" THEN
+ CLEANED$ = CLEANED$ + CH$
+ END IF
+ NEXT I
+
+ IF LEN(CLEANED$) < 10 OR LEN(CLEANED$) > 15 THEN
+ LOG "Invalid phone number: " + NUMBER$
+ EXIT SUB
+ END IF
+
+ SEND WHATSAPP TO CLEANED$ WITH MESSAGE$
+ END SUB
+ ```
+
+## Message Delivery Failures
+
+### Issue: Messages Not Delivered (24-Hour Window)
+
+**Symptoms:**
+- Messages work when user messages first
+- Fail after 24 hours of inactivity
+- "24-hour window" error
+
+**Diagnosis:**
+
+```bash
+# Check last message timestamp
+# Meta allows business-initiated messages only within 24 hours of last user message
+```
+
+**Solutions:**
+
+1. **Use Message Templates**
+ ```
+ In Meta Dashboard:
+ 1. Go to WhatsApp > Message Templates
+ 2. Create and submit template for approval
+ 3. Use template for business-initiated messages
+ ```
+
+2. **Send Template Message**
+ ```javascript
+ async function sendTemplate(to, templateName, parameters = []) {
+ const response = await axios.post(
+ `${baseURL}/${phoneNumberId}/messages`,
+ {
+ messaging_product: 'whatsapp',
+ to: to,
+ type: 'template',
+ template: {
+ name: templateName,
+ language: { code: 'pt_BR' },
+ components: [{
+ type: 'body',
+ parameters: parameters.map(p => ({
+ type: 'text',
+ text: p
+ }))
+ }]
+ }
+ },
+ { headers: { 'Authorization': `Bearer ${accessToken}` } }
+ );
+ return response.data;
+ }
+ ```
+
+3. **Track Last Interaction**
+ ```javascript
+ // Store last message time
+ const lastInteraction = new Map();
+
+ async function sendMessage(to, message) {
+ const lastTime = lastInteraction.get(to);
+ const now = Date.now();
+ const hoursSince = (now - lastTime) / (1000 * 60 * 60);
+
+ if (hoursSince > 24) {
+ // Use template
+ await sendTemplate(to, 'reengagement_template', []);
+ } else {
+ // Use regular message
+ await sendText(to, message);
+ }
+
+ lastInteraction.set(to, now);
+ }
+ ```
+
+### Issue: Media Messages Fail to Send
+
+**Symptoms:**
+- Text messages work, media fails
+- "Media upload failed" error
+- Images not delivered
+
+**Diagnosis:**
+
+```bash
+# Test media URL accessibility
+curl -I https://your-media-url.com/image.jpg
+
+# Expected: 200 OK with Content-Type: image/jpeg
+```
+
+**Solutions:**
+
+1. **Verify Media URL**
+ - Must be publicly accessible
+ - Must use HTTPS
+ - Must return correct Content-Type
+ - Should be under 5MB for images
+
+2. **Upload Media First**
+ ```javascript
+ async function uploadMedia(mediaUrl) {
+ const response = await axios.post(
+ `${baseURL}/${phoneNumberId}/media`,
+ {
+ file: mediaUrl,
+ type: 'image/jpeg'
+ },
+ { headers: { 'Authorization': `Bearer ${accessToken}` } }
+ );
+ return response.data.id;
+ }
+
+ async function sendImageWithUpload(to, imageUrl, caption) {
+ const mediaId = await uploadMedia(imageUrl);
+ await sendMediaById(to, mediaId, caption);
+ }
+ ```
+
+3. **Use Approved Media Hosts**
+ - Meta's media servers (preferred)
+ - AWS S3 with public access
+ - CloudFront CDN
+ - Avoid self-hosted media for reliability
+
+## Twilio-Specific Issues
+
+### Issue: TwiML Bin Not Working
+
+**Symptoms:**
+- TwiML Bin returns 404
+- Invalid TwiML error
+- Webhook not triggered
+
+**Diagnosis:**
+
+```bash
+# Test TwiML Bin URL
+curl -X POST https://handler.twilio.com/twiml/EH123...
+```
+
+**Solutions:**
+
+1. **Validate TwiML Syntax**
+ ```xml
+
+
+
+
+ Enter your code
+
+
+ ```
+
+2. **Use Custom Webhook Instead**
+ ```javascript
+ // Replace TwiML Bin with custom server
+ app.post('/twilio/voice', (req, res) => {
+ const twiml = new twilio.twiml.VoiceResponse();
+ const gather = twiml.gather({
+ action: '/twilio/gather',
+ method: 'POST'
+ });
+ gather.say('Enter your code');
+ res.type('text/xml');
+ res.send(twiml.toString());
+ });
+ ```
+
+### Issue: Call Not Forwarded to Email
+
+**Symptoms:**
+- Voicemail not received
+- Email not sent
+- Transcription not working
+
+**Diagnosis:**
+
+```bash
+# Check TwiML voicemail URL
+https://twimlets.com/voicemail?Email=your-email@example.com
+```
+
+**Solutions:**
+
+1. **Implement Custom Voicemail**
+ ```javascript
+ app.post('/twilio/gather', (req, res) => {
+ const code = req.body.Digits;
+
+ // Send email with code
+ transporter.sendMail({
+ from: 'bot@example.com',
+ to: 'your-email@example.com',
+ subject: 'WhatsApp Verification Code',
+ text: `Your code is: ${code}`
+ });
+
+ // Also send via SMS as backup
+ client.messages.create({
+ to: '+5511999999999',
+ from: process.env.TWILIO_NUMBER,
+ body: `Code: ${code}`
+ });
+
+ res.type('text/xml');
+ res.send('Code sent to email');
+ });
+ ```
+
+2. **Add Multiple Notification Channels**
+ - Email (primary)
+ - SMS backup
+ - Database logging
+ - Webhook notification
+
+## Meta-Specific Issues
+
+### Issue: Phone Number Not Approved
+
+**Symptoms:**
+- Number shows "Not Verified"
+- Cannot send messages
+- "Number quality" error
+
+**Diagnosis:**
+
+```bash
+# Check number status in Meta Dashboard
+# WhatsApp Accounts > Phone Numbers > Select Number
+```
+
+**Solutions:**
+
+1. **Verify Number Quality**
+ - Number must be from reputable provider
+ - Avoid VOIP numbers
+ - Use local numbers for target country
+
+2. **Complete Business Verification**
+ ```
+ In Meta Dashboard:
+ 1. Go to Business Settings > Business Verification
+ 2. Submit business documents
+ 3. Wait for approval (7-14 days)
+ ```
+
+3. **Request Higher Limits**
+ ```
+ In Meta Dashboard:
+ 1. Go to WhatsApp > API Settings
+ 2. Request increased messaging limits
+ 3. Provide business justification
+ ```
+
+### Issue: Webhook Signature Verification Fails
+
+**Symptoms:**
+- All webhooks rejected
+- "Invalid signature" errors
+- Security check failures
+
+**Diagnosis:**
+
+```bash
+# Check X-Hub-Signature-256 header
+curl -X POST https://your-domain.com/webhooks/whatsapp \
+ -H "X-Hub-Signature-256: sha256=..." \
+ -d '{"test": true}'
+```
+
+**Solutions:**
+
+1. **Implement Signature Verification**
+ ```javascript
+ const crypto = require('crypto');
+
+ function verifySignature(payload, signature, appSecret) {
+ const expectedSignature = 'sha256=' +
+ crypto.createHmac('sha256', appSecret)
+ .update(payload)
+ .digest('hex');
+ return crypto.timingSafeEqual(
+ Buffer.from(signature),
+ Buffer.from(expectedSignature)
+ );
+ }
+
+ app.post('/webhooks/whatsapp', (req, res) => {
+ const signature = req.headers['x-hub-signature-256'];
+ const payload = JSON.stringify(req.body);
+
+ if (!verifySignature(payload, signature, APP_SECRET)) {
+ return res.status(403).send('Invalid signature');
+ }
+
+ // Process webhook
+ processWebhook(req.body);
+ res.status(200).send('OK');
+ });
+ ```
+
+2. **Get App Secret**
+ ```
+ In Meta Dashboard:
+ 1. Go to App Settings > Basic
+ 2. Copy App Secret
+ 3. Store securely in environment variable
+ ```
+
+## Performance Issues
+
+### Issue: Slow Webhook Response
+
+**Symptoms:**
+- Webhooks timeout
+- Meta shows "Webhook slow" warning
+- Messages delayed
+
+**Diagnosis:**
+
+```bash
+# Measure webhook response time
+time curl -X POST https://your-domain.com/webhooks/whatsapp \
+ -H "Content-Type: application/json" \
+ -d '{"object":"whatsapp_business_account","entry":[]}'
+```
+
+**Solutions:**
+
+1. **Optimize Webhook Handler**
+ ```javascript
+ app.post('/webhooks/whatsapp', (req, res) => {
+ // Acknowledge immediately
+ res.status(200).send('OK');
+
+ // Process asynchronously
+ setImmediate(() => {
+ processMessageAsync(req.body);
+ });
+ });
+
+ async function processMessageAsync(data) {
+ // Heavy processing here
+ await handleMessage(data);
+ }
+ ```
+
+2. **Use Worker Queues**
+ ```javascript
+ const { Queue } = require('bull');
+
+ const webhookQueue = new Queue('webhook-processing', {
+ redis: { host: 'localhost', port: 6379 }
+ });
+
+ app.post('/webhooks/whatsapp', async (req, res) => {
+ await webhookQueue.add('process', req.body);
+ res.status(200).send('OK');
+ });
+
+ webhookQueue.process('process', async (job) => {
+ await handleMessage(job.data);
+ });
+ ```
+
+3. **Monitor Response Times**
+ ```javascript
+ const responseTime = require('response-time');
+
+ app.use(responseTime((req, res, time) => {
+ console.log(`${req.method} ${req.path} ${time}ms`);
+ }));
+ ```
+
+### Issue: High Memory Usage
+
+**Symptoms:**
+- Bot crashes with out of memory
+- Slow response times
+- High server load
+
+**Diagnosis:**
+
+```bash
+# Check memory usage
+node --inspect app.js
+# Open chrome://inspect in Chrome
+
+# Monitor process
+pm2 monit
+```
+
+**Solutions:**
+
+1. **Limit Conversation State**
+ ```javascript
+ // Don't store unlimited conversation history
+ const MAX_HISTORY = 50;
+ const conversations = new Map();
+
+ function addToConversation(phone, message) {
+ let history = conversations.get(phone) || [];
+ history.push({ message, time: Date.now() });
+
+ if (history.length > MAX_HISTORY) {
+ history = history.slice(-MAX_HISTORY);
+ }
+
+ conversations.set(phone, history);
+ }
+ ```
+
+2. **Use Redis for State**
+ ```javascript
+ const redis = require('redis');
+ const client = redis.createClient();
+
+ async function setState(phone, key, value) {
+ await client.hset(`conversation:${phone}`, key, JSON.stringify(value));
+ }
+
+ async function getState(phone, key) {
+ const value = await client.hget(`conversation:${phone}`, key);
+ return value ? JSON.parse(value) : null;
+ }
+ ```
+
+3. **Implement Cleanup**
+ ```javascript
+ // Clean up old conversations
+ setInterval(() => {
+ const now = Date.now();
+ const MAX_AGE = 24 * 60 * 60 * 1000; // 24 hours
+
+ for (const [phone, data] of conversations.entries()) {
+ if (now - data.lastActivity > MAX_AGE) {
+ conversations.delete(phone);
+ }
+ }
+ }, 60 * 60 * 1000); // Every hour
+ ```
+
+## Security Issues
+
+### Issue: Access Token Exposed
+
+**Symptoms:**
+- Token found in logs
+- Token in version control
+- Unauthorized API usage
+
+**Solutions:**
+
+1. **Use Environment Variables**
+ ```bash
+ # .env file (add to .gitignore)
+ WHATSAPP_API_KEY=EAAQdlso6aM8BOwl...
+ WHATSAPP_PHONE_NUMBER_ID=1158433381968079
+ ```
+
+ ```javascript
+ // config.js
+ module.exports = {
+ whatsapp: {
+ apiKey: process.env.WHATSAPP_API_KEY,
+ phoneNumberId: process.env.WHATSAPP_PHONE_NUMBER_ID
+ }
+ };
+ ```
+
+2. **Secure Config File**
+ ```bash
+ # Set proper permissions
+ chmod 600 .gbot/config.csv
+ chown bot-user:bot-group .gbot/config.csv
+ ```
+
+3. **Rotate Tokens Regularly**
+ ```
+ In Meta Dashboard:
+ 1. Go to WhatsApp > API Setup
+ 2. Generate new temporary token
+ 3. Update config.csv
+ 4. Restart bot
+ 5. Invalidate old token
+ ```
+
+### Issue: Webhook Abuse
+
+**Symptoms:**
+- Excessive webhook calls
+- Spam messages
+- High server load
+
+**Solutions:**
+
+1. **Rate Limit Webhooks**
+ ```javascript
+ const rateLimit = require('express-rate-limit');
+
+ const webhookLimiter = rateLimit({
+ windowMs: 60 * 1000, // 1 minute
+ max: 100, // 100 requests per minute
+ keyGenerator: (req) => {
+ return req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]?.from || 'unknown';
+ }
+ });
+
+ app.post('/webhooks/whatsapp', webhookLimiter, (req, res) => {
+ // Process webhook
+ });
+ ```
+
+2. **Validate Payload**
+ ```javascript
+ function validateWebhookPayload(data) {
+ if (!data.object === 'whatsapp_business_account') {
+ return false;
+ }
+
+ if (!data.entry || !Array.isArray(data.entry)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ app.post('/webhooks/whatsapp', (req, res) => {
+ if (!validateWebhookPayload(req.body)) {
+ return res.status(400).send('Invalid payload');
+ }
+
+ // Process webhook
+ });
+ ```
+
+3. **Monitor for Anomalies**
+ ```javascript
+ const messageCounts = new Map();
+
+ function checkForAbuse(phoneNumber) {
+ const count = messageCounts.get(phoneNumber) || 0;
+ messageCounts.set(phoneNumber, count + 1);
+
+ if (count > 100) {
+ console.warn(`Potential abuse from ${phoneNumber}`);
+ // Block or throttle
+ }
+ }
+ ```
+
+## Getting Help
+
+If you're still experiencing issues after following this guide:
+
+1. **Check Community Resources**
+ - [General Bots Discord](https://discord.gg/general-bots)
+ - [Meta for Developers Forum](https://developers.facebook.com/community/)
+ - [Twilio Community](https://www.twilio.com/help/faq)
+
+2. **Enable Debug Logging**
+ ```basic
+ REM Enable detailed logging
+ SET DEBUG MODE TO "verbose"
+ LOG ALL WEBHOOK REQUESTS
+ LOG ALL API RESPONSES
+ ```
+
+3. **Collect Diagnostic Information**
+ ```bash
+ # Export logs
+ tar -czf whatsapp-debug-$(date +%Y%m%d).tar.gz \
+ .gbot/logs/ \
+ /var/log/whatsapp-webhook/
+
+ # Include configuration (redact sensitive data)
+ # Include error messages
+ # Include timestamps
+ ```
+
+4. **Create Support Ticket**
+ - Include diagnostic tarball
+ - Describe expected vs actual behavior
+ - List steps to reproduce
+ - Include error messages
+
+For the latest troubleshooting information, see [Webhook Configuration Guide](./webhooks.md) or [Code Examples](./examples.md).
\ No newline at end of file
diff --git a/src/18-appendix-external-services/whatsapp-webhooks.md b/src/18-appendix-external-services/whatsapp-webhooks.md
new file mode 100644
index 00000000..9891cf8c
--- /dev/null
+++ b/src/18-appendix-external-services/whatsapp-webhooks.md
@@ -0,0 +1,632 @@
+# Webhook Configuration Guide
+
+This guide provides detailed instructions for configuring webhooks for both Twilio (voice call handling) and Meta (WhatsApp message handling) in your General Bots integration.
+
+## Overview
+
+The integration requires two separate webhook configurations:
+
+1. **Twilio Voice Webhook** - Handles incoming verification calls and captures verification codes
+2. **Meta WhatsApp Webhook** - Receives incoming WhatsApp messages and status updates
+
+## Twilio Webhook Configuration
+
+### Purpose
+
+The Twilio webhook is critical during the initial phone number verification phase. Since Twilio numbers don't support SMS verification, Meta must call your number and read a 6-digit code. Your webhook must:
+
+1. Answer the incoming call from Meta
+2. Capture the audio or DTMF tones (key presses)
+3. Forward the verification code to your email or logging system
+
+### Webhook URL Structure
+
+```
+POST https://your-domain.com/twilio/voice
+```
+
+### Required HTTP Headers
+
+Twilio sends these headers with every webhook request:
+
+| Header | Description | Example |
+|--------|-------------|---------|
+| `X-Twilio-Signature` | Request signature for security | `RCYmLs...` |
+| `Content-Type` | Always `application/x-www-form-urlencoded` | - |
+
+### Request Body Parameters
+
+When a call comes in, Twilio POSTs these parameters:
+
+| Parameter | Description | Example |
+|-----------|-------------|---------|
+| `CallSid` | Unique call identifier | `CA1234567890ABCDEF1234567890ABCDEF` |
+| `From` | Caller's phone number | `+1234567890` (Meta's verification number) |
+| `To` | Your Twilio number | `+553322980098` |
+| `CallStatus` | Current call status | `ringing` |
+| `Direction` | Call direction | `inbound` |
+
+### TwiML Response Format
+
+Your webhook must respond with TwiML (Twilio Markup Language) XML:
+
+```xml
+
+
+
+
+ Please enter your verification code followed by the pound sign.
+
+
+ https://twimlets.com/voicemail?Email=your-email@example.com
+
+```
+
+### Implementation Examples
+
+#### Node.js/Express
+
+```javascript
+const express = require('express');
+const twilio = require('twilio');
+const app = express();
+
+app.post('/twilio/voice', (req, res) => {
+ const twiml = new twilio.twiml.VoiceResponse();
+
+ const gather = twiml.gather({
+ action: '/twilio/gather',
+ method: 'POST',
+ numDigits: 6,
+ timeout: 10
+ });
+
+ gather.say({
+ voice: 'alice',
+ language: 'pt-BR'
+ }, 'Please enter your verification code followed by the pound key.');
+
+ // Fallback to voicemail if no input
+ twiml.redirect('https://twimlets.com/voicemail?Email=your-email@example.com');
+
+ res.type('text/xml');
+ res.send(twiml.toString());
+});
+
+app.post('/twilio/gather', (req, res) => {
+ const verificationCode = req.body.Digits;
+
+ console.log('WhatsApp Verification Code:', verificationCode);
+
+ // Send email notification
+ sendEmail({
+ to: 'your-email@example.com',
+ subject: 'WhatsApp Verification Code',
+ body: `Your verification code is: ${verificationCode}`
+ });
+
+ const twiml = new twilio.twiml.VoiceResponse();
+ twiml.say('Thank you. Your code has been received.');
+
+ res.type('text/xml');
+ res.send(twiml.toString());
+});
+
+app.listen(3000, () => {
+ console.log('Twilio webhook server running on port 3000');
+});
+```
+
+#### Python/Flask
+
+```python
+from flask import Flask, request, Response
+from twilio.twiml.voice_response import VoiceResponse, Gather
+import smtplib
+
+app = Flask(__name__)
+
+@app.route('/twilio/voice', methods=['POST'])
+def voice_webhook():
+ response = VoiceResponse()
+
+ gather = Gather(
+ action='/twilio/gather',
+ method='POST',
+ num_digits=6,
+ timeout=10
+ )
+ gather.say(
+ 'Please enter your verification code followed by the pound key.',
+ voice='alice',
+ language='pt-BR'
+ )
+ response.append(gather)
+
+ # Fallback to voicemail
+ response.redirect('https://twimlets.com/voicemail?Email=your-email@example.com')
+
+ return Response(str(response), mimetype='text/xml')
+
+@app.route('/twilio/gather', methods=['POST'])
+def gather_webhook():
+ verification_code = request.form.get('Digits')
+
+ print(f'WhatsApp Verification Code: {verification_code}')
+
+ # Send email notification
+ send_email(
+ to='your-email@example.com',
+ subject='WhatsApp Verification Code',
+ body=f'Your verification code is: {verification_code}'
+ )
+
+ response = VoiceResponse()
+ response.say('Thank you. Your code has been received.')
+
+ return Response(str(response), mimetype='text/xml')
+
+def send_email(to, subject, body):
+ # Implement email sending logic
+ pass
+
+if __name__ == '__main__':
+ app.run(port=3000)
+```
+
+#### BASIC (General Bots)
+
+```basic
+REM Twilio Voice Webhook Handler
+ON WEBHOOK POST TO "/twilio/voice" DO
+ REM Create TwiML response
+ LET TWIML$ = ""
+ TWIML$ = TWIML$ + ""
+ TWIML$ = TWIML$ + ""
+ TWIML$ = TWIML$ + ""
+ TWIML$ = TWIML$ + "Please enter your verification code followed by the pound sign."
+ TWIML$ = TWIML$ + ""
+ TWIML$ = TWIML$ + ""
+ TWIML$ = TWIML$ + "https://twimlets.com/voicemail?Email=your-email@example.com"
+ TWIML$ = TWIML$ + ""
+
+ REM Set response content type
+ SET RESPONSE HEADER "Content-Type" TO "text/xml"
+ PRINT TWIML$
+END ON
+
+REM Gather Handler (receives the DTMF input)
+ON WEBHOOK POST TO "/twilio/gather" DO
+ REM Get the digits entered
+ LET CODE$ = GET FORM VALUE "Digits"
+
+ REM Log the verification code
+ LOG "WhatsApp Verification Code: " + CODE$
+
+ REM Send email notification
+ SEND MAIL TO "your-email@example.com" WITH SUBJECT "WhatsApp Verification Code" AND BODY "Your verification code is: " + CODE$
+
+ REM Create confirmation TwiML
+ LET TWIML$ = ""
+ TWIML$ = TWIML$ + ""
+ TWIML$ = TWIML$ + "Thank you. Your code has been received."
+ TWIML$ = TWIML$ + ""
+
+ SET RESPONSE HEADER "Content-Type" TO "text/xml"
+ PRINT TWIML$
+END ON
+```
+
+### Configuring Twilio
+
+1. **Navigate to your phone number**
+ - Go to Twilio Console > Phone Numbers > Active Numbers
+ - Click on your purchased number
+
+2. **Configure Voice Webhook**
+ - Find "Voice & Fax" section
+ - Set "A Call Comes In" to your webhook URL
+ - Select HTTP POST method
+ - Example: `https://your-domain.com/twilio/voice`
+
+3. **Save changes**
+ - Click "Save" to apply the configuration
+
+### Webhook Security
+
+Verify that requests come from Twilio:
+
+```javascript
+const twilio = require('twilio');
+const client = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);
+
+app.post('/twilio/voice', (req, res) => {
+ const url = `https://${req.headers.host}${req.path}`;
+ const signature = req.headers['x-twilio-signature'];
+
+ if (client.validateRequest(url, req.body, signature)) {
+ // Request is from Twilio, process it
+ handleVoiceWebhook(req, res);
+ } else {
+ // Invalid signature
+ res.status(403).send('Invalid signature');
+ }
+});
+```
+
+## Meta WhatsApp Webhook Configuration
+
+### Purpose
+
+The Meta webhook receives:
+- Incoming WhatsApp messages from users
+- Message delivery status updates
+- Message read receipts
+- Webhook verification requests
+
+### Webhook URL Structure
+
+```
+POST https://your-domain.com/webhooks/whatsapp
+```
+
+### Required HTTP Headers
+
+| Header | Description | Example |
+|--------|-------------|---------|
+| `X-Hub-Signature-256` | HMAC SHA-256 signature | `sha256=...` |
+
+### Webhook Verification
+
+When you first configure the webhook, Meta sends a GET request to verify your URL:
+
+```
+GET https://your-domain.com/webhooks/whatsapp?hub.verify_token=YOUR_TOKEN&hub.challenge=CHALLENGE_STRING
+```
+
+Your webhook must respond with the challenge:
+
+```javascript
+app.get('/webhooks/whatsapp', (req, res) => {
+ const mode = req.query['hub.mode'];
+ const token = req.query['hub.verify_token'];
+ const challenge = req.query['hub.challenge'];
+
+ const VERIFY_TOKEN = '4qIogZadggQ.BEoMeciXIdl_MlkV_1DTx8Z_i0bYPxtSJwKSbH0FKlY';
+
+ if (mode === 'subscribe' && token === VERIFY_TOKEN) {
+ console.log('Webhook verified');
+ res.status(200).send(challenge);
+ } else {
+ res.sendStatus(403);
+ }
+});
+```
+
+### Message Payload Structure
+
+Meta sends JSON payloads with message data:
+
+```json
+{
+ "object": "whatsapp_business_account",
+ "entry": [{
+ "id": "390727550789228",
+ "changes": [{
+ "value": {
+ "messaging_product": "whatsapp",
+ "metadata": {
+ "display_phone_number": "+553322980098",
+ "phone_number_id": "1158433381968079"
+ },
+ "contacts": [{
+ "profile": {
+ "name": "John Doe"
+ },
+ "wa_id": "5511999999999"
+ }],
+ "messages": [{
+ "from": "5511999999999",
+ "id": "wamid.HBgLNTE1OTk5OTk5OTk5FQIAERgSMzg1QTlCNkE2RTlFRTdFNDdF",
+ "timestamp": "1704067200",
+ "text": {
+ "body": "Hello, how can I help you?"
+ },
+ "type": "text"
+ }]
+ },
+ "field": "messages"
+ }]
+ }]
+}
+```
+
+### Implementation Examples
+
+#### Node.js/Express
+
+```javascript
+app.post('/webhooks/whatsapp', (req, res) => {
+ try {
+ const data = req.body;
+
+ // Check if this is a WhatsApp message
+ if (data.object === 'whatsapp_business_account') {
+ data.entry.forEach(entry => {
+ entry.changes.forEach(change => {
+ if (change.field === 'messages') {
+ const message = change.value.messages[0];
+ const from = message.from;
+ const body = message.text.body;
+ const messageId = message.id;
+
+ console.log(`Received message from ${from}: ${body}`);
+
+ // Process the message
+ processWhatsAppMessage(from, body, messageId);
+ }
+ });
+ });
+ }
+
+ res.status(200).send('OK');
+ } catch (error) {
+ console.error('Webhook error:', error);
+ res.status(500).send('Error');
+ }
+});
+
+async function processWhatsAppMessage(from, body, messageId) {
+ // Implement your bot logic here
+ const response = await generateResponse(body);
+
+ // Send reply
+ await sendWhatsAppMessage(from, response);
+}
+```
+
+#### Python/Flask
+
+```python
+@app.route('/webhooks/whatsapp', methods=['POST'])
+def whatsapp_webhook():
+ try:
+ data = request.get_json()
+
+ if data.get('object') == 'whatsapp_business_account':
+ for entry in data.get('entry', []):
+ for change in entry.get('changes', []):
+ if change.get('field') == 'messages':
+ message = change['value']['messages'][0]
+ from_number = message['from']
+ body = message['text']['body']
+ message_id = message['id']
+
+ print(f"Received message from {from_number}: {body}")
+
+ # Process the message
+ process_whatsapp_message(from_number, body, message_id)
+
+ return 'OK', 200
+ except Exception as e:
+ print(f'Webhook error: {e}')
+ return 'Error', 500
+
+def process_whatsapp_message(from_number, body, message_id):
+ # Implement your bot logic here
+ response = generate_response(body)
+
+ # Send reply
+ send_whatsapp_message(from_number, response)
+```
+
+#### BASIC (General Bots)
+
+```basic
+REM Meta WhatsApp Webhook Handler
+ON WEBHOOK POST TO "/webhooks/whatsapp" DO
+ REM Get the JSON payload
+ LET PAYLOAD$ = GET REQUEST BODY
+
+ REM Parse the JSON (requires JSON parser library)
+ LET OBJ = PARSE JSON PAYLOAD$
+
+ REM Check if this is a WhatsApp message
+ IF GET JSON PATH OBJ, "object" = "whatsapp_business_account" THEN
+ REM Get the message
+ LET MESSAGE = GET JSON PATH OBJ, "entry[0].changes[0].value.messages[0]"
+
+ REM Extract message details
+ LET FROM$ = GET JSON PATH MESSAGE, "from"
+ LET BODY$ = GET JSON PATH MESSAGE, "text.body"
+ LET ID$ = GET JSON PATH MESSAGE, "id"
+
+ REM Log the message
+ LOG "WhatsApp message from " + FROM$ + ": " + BODY$
+
+ REM Process the message asynchronously
+ SPAWN PROCESS WHATSAPP MESSAGE FROM$, BODY$, ID$
+ END IF
+
+ REM Respond with 200 OK
+ PRINT "OK"
+ SET RESPONSE STATUS TO 200
+END ON
+
+REM Message processor
+SUB PROCESS WHATSAPP MESSAGE FROM$, BODY$, ID$
+ REM Generate a response
+ LET RESPONSE$ = GENERATE RESPONSE BODY$
+
+ REM Send the reply
+ SEND WHATSAPP TO FROM$ WITH RESPONSE$
+END SUB
+```
+
+### Configuring Meta
+
+1. **Navigate to WhatsApp API Setup**
+ - Go to Meta for Developers > Your App > WhatsApp > API Setup
+
+2. **Edit Webhook**
+ - Click "Edit" next to Webhook
+ - Enter your webhook URL: `https://your-domain.com/webhooks/whatsapp`
+ - Enter your Verify Token: `4qIogZadggQ.BEoMeciXIdl_MlkV_1DTx8Z_i0bYPxtSJwKSbH0FKlY`
+ - Click "Verify and Save"
+
+3. **Subscribe to Webhook Fields**
+ - Subscribe to: `messages`
+ - This ensures you receive all incoming messages
+
+### Webhook Security
+
+Implement signature verification:
+
+```javascript
+const crypto = require('crypto');
+
+app.post('/webhooks/whatsapp', (req, res) => {
+ const signature = req.headers['x-hub-signature-256'];
+ const payload = JSON.stringify(req.body);
+ const appSecret = 'YOUR_APP_SECRET'; // From Meta dashboard
+
+ const expectedSignature = 'sha256=' + crypto
+ .createHmac('sha256', appSecret)
+ .update(payload)
+ .digest('hex');
+
+ if (signature !== expectedSignature) {
+ console.error('Invalid webhook signature');
+ return res.status(403).send('Invalid signature');
+ }
+
+ // Process the webhook
+ processWebhook(req.body);
+ res.status(200).send('OK');
+});
+```
+
+## Testing Webhooks
+
+### Using Ngrok for Local Development
+
+1. **Install ngrok**
+ ```bash
+ npm install -g ngrok
+ ```
+
+2. **Start your local server**
+ ```bash
+ node server.js
+ ```
+
+3. **Start ngrok**
+ ```bash
+ ngrok http 3000
+ ```
+
+4. **Use the ngrok URL**
+ - Your webhook URL: `https://abc123.ngrok.io/webhooks/whatsapp`
+
+### Testing Twilio Webhook
+
+Use Twilio's webhook debugger:
+
+```bash
+curl -X POST \
+ 'https://your-domain.com/twilio/voice' \
+ -H 'Content-Type: application/x-www-form-urlencoded' \
+ -d 'CallSid=CA123&From=+1234567890&To=+553322980098&CallStatus=ringing&Direction=inbound'
+```
+
+### Testing Meta Webhook
+
+Use Meta's webhook testing tool:
+
+```bash
+curl -X POST \
+ 'https://your-domain.com/webhooks/whatsapp' \
+ -H 'Content-Type: application/json' \
+ -H 'X-Hub-Signature-256: sha256=...' \
+ -d '{
+ "object": "whatsapp_business_account",
+ "entry": [{
+ "id": "390727550789228",
+ "changes": [{
+ "value": {
+ "messaging_product": "whatsapp",
+ "messages": [{
+ "from": "5511999999999",
+ "text": {"body": "Test message"}
+ }]
+ },
+ "field": "messages"
+ }]
+ }]
+ }'
+```
+
+## Production Considerations
+
+### High Availability
+
+- Deploy webhooks behind a load balancer
+- Implement retry logic for failed deliveries
+- Use a message queue (RabbitMQ, Redis) for async processing
+- Monitor webhook health and set up alerts
+
+### Performance
+
+- Respond to webhooks quickly (< 3 seconds)
+- Process heavy operations asynchronously
+- Use worker queues for message processing
+- Implement rate limiting to prevent abuse
+
+### Monitoring
+
+- Log all webhook requests and responses
+- Track delivery success rates
+- Monitor response times
+- Set up alerts for failures
+- Use tools like Sentry, Datadog, or New Relic
+
+## Troubleshooting
+
+### Common Issues
+
+**Problem: Webhook verification fails**
+- Ensure verify token matches exactly
+- Check that your endpoint returns the challenge
+- Verify your URL is publicly accessible
+
+**Problem: Messages not received**
+- Check webhook logs for errors
+- Verify subscription to `messages` field
+- Ensure your server is online and responding
+
+**Problem: Invalid signature errors**
+- Verify your app secret is correct
+- Check that you're computing the hash correctly
+- Ensure you're using the raw request body
+
+**Problem: Timeout errors**
+- Optimize your webhook handler
+- Move heavy processing to background jobs
+- Increase server capacity if needed
+
+### Debugging Tools
+
+- **Twilio Debugger**: View all Twilio webhook attempts
+- **Meta Webhook Debugging**: Enable in app settings
+- **Ngrok Inspector**: Inspect requests in real-time
+- **Webhook.site**: Test webhooks without a server
+
+## Next Steps
+
+- Set up persistent storage for message history
+- Implement message queue for reliability
+- Add webhook retry logic
+- Configure monitoring and alerting
+- Set up automated testing
+
+For more information on webhook security, see [Security Considerations](./README.md#security-considerations).
\ No newline at end of file
diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 2c5b17ef..ba2db8b3 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -433,6 +433,11 @@
- [LLM Providers](./18-appendix-external-services/llm-providers.md)
- [Weather API](./18-appendix-external-services/weather.md)
- [Channel Integrations](./18-appendix-external-services/channels.md)
+ - [Quick Start Guide](./18-appendix-external-services/whatsapp-quick-start.md)
+ - [Webhook Configuration](./18-appendix-external-services/whatsapp-webhooks.md)
+ - [Code Examples](./18-appendix-external-services/whatsapp-examples.md)
+ - [Troubleshooting](./18-appendix-external-services/whatsapp-troubleshooting.md)
+ - [Quick Reference](./18-appendix-external-services/whatsapp-quick-reference.md)
- [Storage Services](./18-appendix-external-services/storage.md)
- [Directory Services](./18-appendix-external-services/directory.md)
- [Attendance Queue](./18-appendix-external-services/attendance-queue.md)
@@ -452,5 +457,7 @@
- [LXC Migration](./19-maintenance/lxc-migration.md)
+
+
[Glossary](./glossary.md)
[Contact](./contact/README.md)