chore: move docs to docs/ folder and remove vendor references from comments
- Move INTERACTIVE_MESSAGES.md to docs/ folder - Remove all third-party name references from code comments - Temporarily remove docs from .gitignore to allow tracking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,506 @@
|
||||
# ⚠️ EXPERIMENTAL: Interactive Messages Guide
|
||||
|
||||
## 🚨 **CRITICAL WARNING**
|
||||
|
||||
**These features MAY NOT WORK and can cause ACCOUNT BANS.**
|
||||
|
||||
- ❌ WhatsApp actively blocks non-business accounts from sending interactive messages
|
||||
- ❌ Can result in temporary or permanent account bans
|
||||
- ❌ Messages may not be delivered
|
||||
- ✅ **Use ONLY for testing with DISPOSABLE accounts in DEV environment**
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
1. [Configuration](#configuration)
|
||||
2. [Simple Text Buttons](#1-simple-text-buttons)
|
||||
3. [Buttons with Image](#2-buttons-with-image)
|
||||
4. [Buttons with Video](#3-buttons-with-video)
|
||||
5. [List Messages](#4-list-messages)
|
||||
6. [Template Buttons (Action Buttons)](#5-template-buttons-action-buttons)
|
||||
7. [Carousel Messages](#6-carousel-messages)
|
||||
8. [Metrics and Monitoring](#metrics-and-monitoring)
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Enable Interactive Messages
|
||||
|
||||
```typescript
|
||||
import makeWASocket from '@whiskeysockets/baileys'
|
||||
|
||||
const sock = makeWASocket({
|
||||
auth: state,
|
||||
// ⚠️ Enable experimental interactive messages
|
||||
// WARNING: Can cause account bans!
|
||||
enableInteractiveMessages: true, // default: true
|
||||
logger: pino({ level: 'warn' })
|
||||
})
|
||||
```
|
||||
|
||||
### Disable in Production
|
||||
|
||||
```typescript
|
||||
const sock = makeWASocket({
|
||||
auth: state,
|
||||
// ✅ Disable for production safety
|
||||
enableInteractiveMessages: false,
|
||||
logger: pino({ level: 'info' })
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. Simple Text Buttons
|
||||
|
||||
Send a message with up to 3 clickable buttons.
|
||||
|
||||
### Example
|
||||
|
||||
```typescript
|
||||
await sock.sendMessage(jid, {
|
||||
text: 'Choose an option:',
|
||||
buttons: [
|
||||
{
|
||||
buttonId: 'btn1',
|
||||
buttonText: { displayText: 'Option 1' }
|
||||
},
|
||||
{
|
||||
buttonId: 'btn2',
|
||||
buttonText: { displayText: 'Option 2' }
|
||||
},
|
||||
{
|
||||
buttonId: 'btn3',
|
||||
buttonText: { displayText: 'Option 3' }
|
||||
}
|
||||
],
|
||||
footerText: 'Optional footer text'
|
||||
})
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `text` | string | ✅ | Main message text |
|
||||
| `buttons` | ButtonInfo[] | ✅ | Array of buttons (max 3) |
|
||||
| `footerText` | string | ❌ | Footer text below buttons |
|
||||
|
||||
---
|
||||
|
||||
## 2. Buttons with Image
|
||||
|
||||
Send an image with interactive buttons.
|
||||
|
||||
### Example
|
||||
|
||||
```typescript
|
||||
await sock.sendMessage(jid, {
|
||||
image: { url: 'https://example.com/image.jpg' },
|
||||
caption: 'Image description',
|
||||
buttons: [
|
||||
{
|
||||
buttonId: 'view_more',
|
||||
buttonText: { displayText: 'View More' }
|
||||
},
|
||||
{
|
||||
buttonId: 'buy_now',
|
||||
buttonText: { displayText: 'Buy Now' }
|
||||
}
|
||||
],
|
||||
footerText: 'Available now'
|
||||
})
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `image` | WAMediaUpload | ✅ | Image URL or Buffer |
|
||||
| `caption` | string | ❌ | Image caption |
|
||||
| `buttons` | ButtonInfo[] | ✅ | Array of buttons (max 3) |
|
||||
| `footerText` | string | ❌ | Footer text |
|
||||
|
||||
---
|
||||
|
||||
## 3. Buttons with Video
|
||||
|
||||
Send a video with interactive buttons.
|
||||
|
||||
### Example
|
||||
|
||||
```typescript
|
||||
await sock.sendMessage(jid, {
|
||||
video: { url: 'https://example.com/video.mp4' },
|
||||
caption: 'Watch this!',
|
||||
buttons: [
|
||||
{
|
||||
buttonId: 'watch',
|
||||
buttonText: { displayText: 'Watch Now' }
|
||||
}
|
||||
],
|
||||
footerText: 'New release'
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. List Messages
|
||||
|
||||
Send a message with a menu of up to 10 options organized in sections.
|
||||
|
||||
### Example
|
||||
|
||||
```typescript
|
||||
await sock.sendMessage(jid, {
|
||||
text: 'Choose a product:',
|
||||
title: 'Product Catalog',
|
||||
buttonText: 'View Options',
|
||||
sections: [
|
||||
{
|
||||
title: 'Electronics',
|
||||
rows: [
|
||||
{
|
||||
rowId: 'laptop_1',
|
||||
title: 'Laptop Pro',
|
||||
description: '$999 - High performance'
|
||||
},
|
||||
{
|
||||
rowId: 'phone_1',
|
||||
title: 'Smartphone X',
|
||||
description: '$699 - Latest model'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Accessories',
|
||||
rows: [
|
||||
{
|
||||
rowId: 'case_1',
|
||||
title: 'Phone Case',
|
||||
description: '$29 - Protective'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
footerText: 'Free shipping'
|
||||
})
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `text` | string | ✅ | Message description |
|
||||
| `title` | string | ❌ | List title |
|
||||
| `buttonText` | string | ✅ | Text on button that opens list |
|
||||
| `sections` | ListSection[] | ✅ | Array of sections (max 10 items total) |
|
||||
| `footerText` | string | ❌ | Footer text |
|
||||
|
||||
### Limits
|
||||
|
||||
- Maximum 10 sections
|
||||
- Maximum 10 rows total across all sections
|
||||
- Row title: 24 characters max
|
||||
- Row description: 72 characters max
|
||||
|
||||
---
|
||||
|
||||
## 5. Template Buttons (Action Buttons)
|
||||
|
||||
Send buttons with actions: Quick Reply, URL, or Call.
|
||||
|
||||
### Example
|
||||
|
||||
```typescript
|
||||
await sock.sendMessage(jid, {
|
||||
text: 'Contact us or visit our website',
|
||||
templateButtons: [
|
||||
// Quick Reply Button
|
||||
{
|
||||
index: 1,
|
||||
quickReplyButton: {
|
||||
displayText: 'Quick Reply',
|
||||
id: 'reply_1'
|
||||
}
|
||||
},
|
||||
// URL Button
|
||||
{
|
||||
index: 2,
|
||||
urlButton: {
|
||||
displayText: 'Visit Website',
|
||||
url: 'https://example.com'
|
||||
}
|
||||
},
|
||||
// Call Button
|
||||
{
|
||||
index: 3,
|
||||
callButton: {
|
||||
displayText: 'Call Us',
|
||||
phoneNumber: '+551199999999'
|
||||
}
|
||||
}
|
||||
],
|
||||
footer: 'We are here to help'
|
||||
})
|
||||
```
|
||||
|
||||
### Button Types
|
||||
|
||||
| Type | Description | Parameters |
|
||||
|------|-------------|------------|
|
||||
| `quickReplyButton` | Quick response button | `displayText`, `id` |
|
||||
| `urlButton` | Opens URL in browser | `displayText`, `url` |
|
||||
| `callButton` | Initiates phone call | `displayText`, `phoneNumber` |
|
||||
|
||||
---
|
||||
|
||||
## 6. Carousel Messages
|
||||
|
||||
Send up to 10 scrollable cards with images/videos and buttons.
|
||||
|
||||
### Example
|
||||
|
||||
```typescript
|
||||
await sock.sendMessage(jid, {
|
||||
text: 'Check out our products',
|
||||
carousel: {
|
||||
cards: [
|
||||
// Card 1
|
||||
{
|
||||
header: {
|
||||
title: 'Product 1',
|
||||
imageMessage: {
|
||||
url: 'https://example.com/product1.jpg',
|
||||
mimetype: 'image/jpeg'
|
||||
},
|
||||
hasMediaAttachment: true
|
||||
},
|
||||
body: { text: 'Amazing product - $99.90' },
|
||||
footer: { text: 'Limited stock' },
|
||||
nativeFlowMessage: {
|
||||
buttons: [
|
||||
{
|
||||
name: 'quick_reply',
|
||||
buttonParamsJson: JSON.stringify({
|
||||
display_text: 'Buy Now',
|
||||
id: 'buy_1'
|
||||
})
|
||||
},
|
||||
{
|
||||
name: 'cta_url',
|
||||
buttonParamsJson: JSON.stringify({
|
||||
display_text: 'More Info',
|
||||
url: 'https://example.com/product1'
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
// Card 2
|
||||
{
|
||||
header: {
|
||||
title: 'Product 2',
|
||||
imageMessage: {
|
||||
url: 'https://example.com/product2.jpg',
|
||||
mimetype: 'image/jpeg'
|
||||
},
|
||||
hasMediaAttachment: true
|
||||
},
|
||||
body: { text: 'Great deal - $149.90' },
|
||||
footer: { text: 'Best seller' },
|
||||
nativeFlowMessage: {
|
||||
buttons: [
|
||||
{
|
||||
name: 'quick_reply',
|
||||
buttonParamsJson: JSON.stringify({
|
||||
display_text: 'Buy Now',
|
||||
id: 'buy_2'
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
messageVersion: 1
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Limits
|
||||
|
||||
- Maximum 10 cards per carousel
|
||||
- Each card requires an image or video
|
||||
- Up to 3 buttons per card
|
||||
- All cards must have same media type (all images or all videos)
|
||||
|
||||
---
|
||||
|
||||
## Metrics and Monitoring
|
||||
|
||||
All interactive messages are tracked with Prometheus metrics:
|
||||
|
||||
### Available Metrics
|
||||
|
||||
```typescript
|
||||
// Messages sent by type
|
||||
metrics.interactiveMessagesSent.inc({ type: 'buttons' })
|
||||
|
||||
// Successful sends
|
||||
metrics.interactiveMessagesSuccess.inc({ type: 'list' })
|
||||
|
||||
// Failures with reason
|
||||
metrics.interactiveMessagesFailures.inc({
|
||||
type: 'template',
|
||||
reason: 'feature_disabled'
|
||||
})
|
||||
|
||||
// Send latency
|
||||
metrics.interactiveMessagesLatency.observe({ type: 'carousel' }, 1234)
|
||||
```
|
||||
|
||||
### Monitoring Dashboard
|
||||
|
||||
Query these metrics in Prometheus/Grafana:
|
||||
|
||||
```promql
|
||||
# Total interactive messages sent
|
||||
sum(interactive_messages_sent_total) by (type)
|
||||
|
||||
# Success rate
|
||||
sum(interactive_messages_success_total) / sum(interactive_messages_sent_total)
|
||||
|
||||
# Failure breakdown
|
||||
sum(interactive_messages_failures_total) by (type, reason)
|
||||
|
||||
# P95 latency
|
||||
histogram_quantile(0.95, interactive_messages_latency_ms)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Handling Responses
|
||||
|
||||
### Button Response
|
||||
|
||||
```typescript
|
||||
sock.ev.on('messages.upsert', async ({ messages }) => {
|
||||
const msg = messages[0]
|
||||
|
||||
// Button response
|
||||
if (msg.message?.buttonsResponseMessage) {
|
||||
const buttonId = msg.message.buttonsResponseMessage.selectedButtonId
|
||||
const displayText = msg.message.buttonsResponseMessage.selectedDisplayText
|
||||
|
||||
console.log(`User clicked: ${buttonId} - "${displayText}"`)
|
||||
}
|
||||
|
||||
// Template button response
|
||||
if (msg.message?.templateButtonReplyMessage) {
|
||||
const selectedId = msg.message.templateButtonReplyMessage.selectedId
|
||||
const selectedText = msg.message.templateButtonReplyMessage.selectedDisplayText
|
||||
|
||||
console.log(`User clicked template: ${selectedId} - "${selectedText}"`)
|
||||
}
|
||||
|
||||
// List response
|
||||
if (msg.message?.listResponseMessage) {
|
||||
const rowId = msg.message.listResponseMessage.singleSelectReply.selectedRowId
|
||||
const title = msg.message.listResponseMessage.title
|
||||
|
||||
console.log(`User selected from list: ${rowId} - "${title}"`)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Message Not Showing
|
||||
|
||||
- ✅ Verify `enableInteractiveMessages` is `true`
|
||||
- ✅ Check logs for `[EXPERIMENTAL]` warnings
|
||||
- ✅ Ensure you're using a test/disposable account
|
||||
- ❌ Interactive messages don't work on production accounts
|
||||
|
||||
### Account Banned/Restricted
|
||||
|
||||
- ⚠️ This is expected behavior
|
||||
- ⚠️ WhatsApp blocks non-business accounts
|
||||
- ✅ Create a new test account
|
||||
- ✅ Use official WhatsApp Business API for production
|
||||
|
||||
### Metrics Not Showing
|
||||
|
||||
Check feature flag:
|
||||
```typescript
|
||||
if (buttonType && !enableInteractiveMessages) {
|
||||
// Metrics will show reason: 'feature_disabled'
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration to WhatsApp Business API
|
||||
|
||||
For production use, migrate to official API:
|
||||
|
||||
### Evolution API (Cloud Mode)
|
||||
|
||||
```typescript
|
||||
// config.ts
|
||||
export const evolutionConfig = {
|
||||
apiUrl: 'https://your-evolution-api.com',
|
||||
apiKey: 'your-api-key',
|
||||
instance: 'your-instance'
|
||||
}
|
||||
|
||||
// Send button via Evolution API
|
||||
await fetch(`${evolutionConfig.apiUrl}/message/sendButton`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': evolutionConfig.apiKey
|
||||
},
|
||||
body: JSON.stringify({
|
||||
number: '5511999999999',
|
||||
options: {
|
||||
delay: 1200,
|
||||
presence: 'composing'
|
||||
},
|
||||
buttonMessage: {
|
||||
text: 'Choose an option',
|
||||
buttons: [
|
||||
{ id: '1', text: 'Option 1' },
|
||||
{ id: '2', text: 'Option 2' }
|
||||
],
|
||||
footer: 'Footer text'
|
||||
}
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- [WhatsApp Official Business API](https://business.whatsapp.com/products/business-platform)
|
||||
- [Evolution API Documentation](https://doc.evolution-api.com/)
|
||||
- [Baileys GitHub Issues #56](https://github.com/WhiskeySockets/Baileys/issues/56)
|
||||
- [Baileys GitHub Issues #25](https://github.com/WhiskeySockets/Baileys/issues/25)
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Final Reminder
|
||||
|
||||
**THESE FEATURES ARE EXPERIMENTAL AND UNRELIABLE**
|
||||
|
||||
- Use only for testing
|
||||
- Expect failures and bans
|
||||
- Not suitable for production
|
||||
- Official WhatsApp Business API is the only supported way
|
||||
|
||||
---
|
||||
|
||||
**Generated by rsalcara/InfiniteAPI**
|
||||
Reference in New Issue
Block a user