whatsapp-cloud-api-ruby 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rubocop.yml +82 -0
- data/CHANGELOG.md +92 -0
- data/Gemfile +21 -0
- data/README.md +735 -0
- data/Rakefile +41 -0
- data/TEMPLATE_TOOLS_GUIDE.md +121 -0
- data/WHATSAPP_24_HOUR_GUIDE.md +134 -0
- data/examples/advanced_features.rb +350 -0
- data/examples/basic_messaging.rb +137 -0
- data/examples/media_management.rb +254 -0
- data/examples/template_management.rb +391 -0
- data/lib/whatsapp_cloud_api/client.rb +317 -0
- data/lib/whatsapp_cloud_api/errors.rb +330 -0
- data/lib/whatsapp_cloud_api/resources/calls.rb +173 -0
- data/lib/whatsapp_cloud_api/resources/contacts.rb +191 -0
- data/lib/whatsapp_cloud_api/resources/conversations.rb +104 -0
- data/lib/whatsapp_cloud_api/resources/media.rb +206 -0
- data/lib/whatsapp_cloud_api/resources/messages.rb +381 -0
- data/lib/whatsapp_cloud_api/resources/phone_numbers.rb +86 -0
- data/lib/whatsapp_cloud_api/resources/templates.rb +284 -0
- data/lib/whatsapp_cloud_api/types.rb +263 -0
- data/lib/whatsapp_cloud_api/version.rb +5 -0
- data/lib/whatsapp_cloud_api.rb +69 -0
- data/scripts/.env.example +18 -0
- data/scripts/kapso_template_finder.rb +91 -0
- data/scripts/sdk_setup.rb +405 -0
- data/scripts/test.rb +60 -0
- metadata +254 -0
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
desc 'Run RSpec tests'
|
4
|
+
task :spec do
|
5
|
+
sh 'bundle exec rspec'
|
6
|
+
end
|
7
|
+
|
8
|
+
desc 'Run RuboCop'
|
9
|
+
task :rubocop do
|
10
|
+
sh 'bundle exec rubocop'
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'Run all linting and tests'
|
14
|
+
task test: [:rubocop, :spec]
|
15
|
+
|
16
|
+
desc 'Generate YARD documentation'
|
17
|
+
task :docs do
|
18
|
+
sh 'bundle exec yard doc'
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Clean up generated files'
|
22
|
+
task :clean do
|
23
|
+
sh 'rm -rf coverage/ doc/ .yardoc/'
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'Build the gem'
|
27
|
+
task :build do
|
28
|
+
sh 'gem build whatsapp-cloud-api-ruby.gemspec'
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'Install the gem locally'
|
32
|
+
task install: :build do
|
33
|
+
sh 'gem install whatsapp-cloud-api-ruby-*.gem'
|
34
|
+
end
|
35
|
+
|
36
|
+
desc 'Release the gem'
|
37
|
+
task release: [:clean, :test, :build] do
|
38
|
+
puts 'Run `gem push whatsapp-cloud-api-ruby-*.gem` to release'
|
39
|
+
end
|
40
|
+
|
41
|
+
task default: :test
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# 📋 Kapso Template Management Tools
|
2
|
+
|
3
|
+
## The 24-Hour Problem & Solution
|
4
|
+
|
5
|
+
**Problem**: You're getting "24 hours have passed" errors when sending messages.
|
6
|
+
**Solution**: Use template messages - they work anytime, no 24-hour limit!
|
7
|
+
|
8
|
+
## 🛠️ Template Tools (Simplified)
|
9
|
+
|
10
|
+
### 1. `scripts/kapso_template_finder.rb` - **MAIN TOOL** ⭐
|
11
|
+
```bash
|
12
|
+
ruby scripts/kapso_template_finder.rb
|
13
|
+
```
|
14
|
+
**Purpose**: Complete template discovery and testing
|
15
|
+
**Features**:
|
16
|
+
- Fetches your actual created templates from Kapso
|
17
|
+
|
18
|
+
### 2. `scripts/test.rb` - Basic Message Testing
|
19
|
+
```bash
|
20
|
+
ruby scripts/test.rb
|
21
|
+
```
|
22
|
+
**Purpose**: Test regular message sending
|
23
|
+
**Use when**: Testing within 24-hour window
|
24
|
+
**Features**:
|
25
|
+
- Test regular messages
|
26
|
+
- Shows 24h error if outside window
|
27
|
+
|
28
|
+
## 📋 Setup Instructions
|
29
|
+
|
30
|
+
### Step 1: Find Your Business Account ID
|
31
|
+
|
32
|
+
1. **Login to Kapso Dashboard**: https://app.kapso.ai/
|
33
|
+
2. **Navigate to WhatsApp Business section**
|
34
|
+
3. **Look for**:
|
35
|
+
- "Business Account ID"
|
36
|
+
- "WABA ID"
|
37
|
+
- Long number (15+ digits)
|
38
|
+
4. **Add to `.env` file**:
|
39
|
+
```properties
|
40
|
+
BUSINESS_ACCOUNT_ID=your_business_account_id_here
|
41
|
+
```
|
42
|
+
|
43
|
+
### Step 2: Discover Your Templates
|
44
|
+
|
45
|
+
```bash
|
46
|
+
ruby scripts/kapso_template_finder.rb
|
47
|
+
```
|
48
|
+
|
49
|
+
✅ **Current Status**: Found 1 template `reply_message (es_MX) - PENDING`
|
50
|
+
⏳ **Waiting for approval** - Template will work once Meta approves it
|
51
|
+
|
52
|
+
### Step 3: Test Templates
|
53
|
+
|
54
|
+
```bash
|
55
|
+
ruby test_specific_template.rb
|
56
|
+
# Enter template name when prompted
|
57
|
+
```
|
58
|
+
|
59
|
+
## 🎯 Creating Templates in Kapso
|
60
|
+
|
61
|
+
### Via Kapso Dashboard:
|
62
|
+
1. Login to https://app.kapso.ai/
|
63
|
+
2. Find "WhatsApp Templates" or "Template Builder"
|
64
|
+
3. Create simple text template:
|
65
|
+
- **Name**: `hello_world` or `welcome_message`
|
66
|
+
- **Language**: `en_US`
|
67
|
+
- **Category**: `UTILITY` (usually fastest approval)
|
68
|
+
- **Content**: "Hello {{1}}, welcome to our service!"
|
69
|
+
|
70
|
+
### Template Approval:
|
71
|
+
- **Pending**: Template submitted, waiting for Meta approval
|
72
|
+
- **Approved**: Ready to use anytime
|
73
|
+
- **Rejected**: Need to fix and resubmit
|
74
|
+
- **Time**: Usually 24-48 hours for approval
|
75
|
+
|
76
|
+
## 🚀 Using Templates in Code
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
# Once your template is approved:
|
80
|
+
response = client.messages.send_template(
|
81
|
+
phone_number_id: "your_phone_number",
|
82
|
+
to: "+56912345678",
|
83
|
+
name: "reply_message", # Your actual template name
|
84
|
+
language: "es_MX" # Your template language
|
85
|
+
)
|
86
|
+
|
87
|
+
# Templates work 24/7 - no time restrictions!
|
88
|
+
```
|
89
|
+
|
90
|
+
## 🔄 Workflow Summary
|
91
|
+
|
92
|
+
1. **Check templates**: `ruby scripts/kapso_template_finder.rb`
|
93
|
+
2. ✅ **Template found**: `reply_message (es_MX) - PENDING`
|
94
|
+
3. ⏳ **Wait for approval**: Meta is reviewing your template
|
95
|
+
4. **Once approved**: Use `reply_message` template for 24/7 messaging
|
96
|
+
|
97
|
+
## ❓ Troubleshooting
|
98
|
+
|
99
|
+
### "Template not found"
|
100
|
+
- Template name is wrong
|
101
|
+
- Template not approved yet
|
102
|
+
- Language code incorrect
|
103
|
+
|
104
|
+
### "24 hours error" (with templates)
|
105
|
+
- This shouldn't happen with templates
|
106
|
+
- Contact Kapso support
|
107
|
+
|
108
|
+
### "Business Account ID not found"
|
109
|
+
- Check Kapso dashboard for WABA ID
|
110
|
+
- Add to .env file
|
111
|
+
- Contact Kapso support if unclear
|
112
|
+
|
113
|
+
## 📞 Support Resources
|
114
|
+
|
115
|
+
- **Kapso Dashboard**: https://app.kapso.ai/
|
116
|
+
- **Kapso Support**: Contact through dashboard
|
117
|
+
- **WhatsApp Template Policies**: Check Meta Business documentation
|
118
|
+
|
119
|
+
---
|
120
|
+
|
121
|
+
**Remember**: Templates solve the 24-hour limitation permanently! Regular messages work within 24h of customer reply, templates work anytime. 🎯
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# WhatsApp 24-Hour Window Policy - Solutions Guide
|
2
|
+
|
3
|
+
## The Problem You're Experiencing
|
4
|
+
|
5
|
+
**Error Message**: "Meta reported a deli### Long-term**: Design your messaging strategy around the 24h rule
|
6
|
+
|
7
|
+
## Kapso.ai Specific Features
|
8
|
+
|
9
|
+
Since you're using Kapso.ai, you may have access to:
|
10
|
+
|
11
|
+
- **Template Library**: Pre-built approved templates
|
12
|
+
- **Template Builder**: Easy template creation interface
|
13
|
+
- **Auto-Approval**: Faster template approval process
|
14
|
+
- **Template Analytics**: Usage statistics and delivery rates
|
15
|
+
- **Bulk Template Management**: Manage multiple templates
|
16
|
+
|
17
|
+
Check your Kapso dashboard for:
|
18
|
+
1. **Available Templates** - Already approved and ready to use
|
19
|
+
2. **Template Status** - Pending, approved, or rejected templates
|
20
|
+
3. **Template Builder** - Create new templates without Meta Business Manager
|
21
|
+
|
22
|
+
## Why This Existsy error. Re-engagement message Message failed to send because more than 24 hours have passed since the customer last replied to this number."
|
23
|
+
|
24
|
+
This is **NOT** a bug in your Ruby SDK - it's a WhatsApp Business API policy.
|
25
|
+
|
26
|
+
## Understanding the 24-Hour Rule
|
27
|
+
|
28
|
+
WhatsApp Business API has a **conversation window** policy:
|
29
|
+
|
30
|
+
### ✅ Within 24 Hours (Free Messaging Window)
|
31
|
+
- **Trigger**: Customer sends you a message
|
32
|
+
- **Duration**: 24 hours from their last message
|
33
|
+
- **Allowed**: ANY message type (text, images, audio, video, documents)
|
34
|
+
- **No restrictions**: Send as many messages as you want
|
35
|
+
|
36
|
+
### ❌ After 24 Hours (Template-Only Window)
|
37
|
+
- **Trigger**: 24+ hours since customer's last message
|
38
|
+
- **Restriction**: ONLY pre-approved template messages allowed
|
39
|
+
- **Regular messages**: Will be rejected with your error
|
40
|
+
|
41
|
+
## Solutions
|
42
|
+
|
43
|
+
### Option 1: Use Template Messages (Recommended)
|
44
|
+
|
45
|
+
Template messages work anytime and are designed for business communications:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
# Send a template message (works 24/7)
|
49
|
+
response = client.messages.send_template(
|
50
|
+
phone_number_id: phone_number_id,
|
51
|
+
to: "+56912345678",
|
52
|
+
template_name: "hello_world", # Must be pre-approved
|
53
|
+
template_language: "en_US"
|
54
|
+
)
|
55
|
+
```
|
56
|
+
|
57
|
+
### Option 2: Wait for Customer Reply
|
58
|
+
|
59
|
+
- Customer sends any message → Opens 24-hour window
|
60
|
+
- You can then send regular messages for 24 hours
|
61
|
+
|
62
|
+
### Option 3: Create Templates via Kapso.ai
|
63
|
+
|
64
|
+
✅ **Current Status**: You already have templates in progress!
|
65
|
+
|
66
|
+
1. **Kapso Dashboard**: ✅ Connected (Business Account: `your_business_id_account`)
|
67
|
+
2. **Template Found**: `reply_message (es_MX) - PENDING`
|
68
|
+
3. **Status**: Waiting for Meta approval (usually 24-48 hours)
|
69
|
+
4. **Once Approved**: Use `your_template` template for 24/7 messaging
|
70
|
+
5. **Test Tool**: `ruby scripts/kapso_template_finder.rb`
|
71
|
+
|
72
|
+
## Prevention Strategies
|
73
|
+
|
74
|
+
### For Customer Service
|
75
|
+
- Respond within 24 hours of customer messages
|
76
|
+
- Use templates for follow-ups after 24h
|
77
|
+
- Set up auto-responses within the window
|
78
|
+
|
79
|
+
### For Marketing
|
80
|
+
- Always use approved template messages
|
81
|
+
- Create templates for different campaigns
|
82
|
+
- Schedule template sends anytime
|
83
|
+
|
84
|
+
### For Notifications
|
85
|
+
- Use templates for order updates, reminders, etc.
|
86
|
+
- Create templates for common notifications
|
87
|
+
- Test templates before going live
|
88
|
+
|
89
|
+
## Template Message Examples
|
90
|
+
|
91
|
+
### Basic Template (No Variables)
|
92
|
+
```ruby
|
93
|
+
client.messages.send_template(
|
94
|
+
phone_number_id: phone_number_id,
|
95
|
+
to: phone_number,
|
96
|
+
template_name: "hello_world",
|
97
|
+
template_language: "en_US"
|
98
|
+
)
|
99
|
+
```
|
100
|
+
|
101
|
+
### Template with Variables
|
102
|
+
```ruby
|
103
|
+
client.messages.send_template(
|
104
|
+
phone_number_id: phone_number_id,
|
105
|
+
to: phone_number,
|
106
|
+
template_name: "order_confirmation",
|
107
|
+
template_language: "en_US",
|
108
|
+
components: [
|
109
|
+
{
|
110
|
+
type: "body",
|
111
|
+
parameters: [
|
112
|
+
{ type: "text", text: "John" }, # Customer name
|
113
|
+
{ type: "text", text: "12345" } # Order number
|
114
|
+
]
|
115
|
+
}
|
116
|
+
]
|
117
|
+
)
|
118
|
+
```
|
119
|
+
|
120
|
+
## Next Steps
|
121
|
+
|
122
|
+
1. **Immediate**: Use `ruby template_test.rb` to test template messages
|
123
|
+
2. **Short-term**: Create templates in Meta Business Manager
|
124
|
+
3. **Long-term**: Design your messaging strategy around the 24h rule
|
125
|
+
|
126
|
+
## Why This Exists
|
127
|
+
|
128
|
+
WhatsApp enforces this to:
|
129
|
+
- Prevent spam
|
130
|
+
- Ensure quality business communications
|
131
|
+
- Protect user experience
|
132
|
+
- Maintain platform integrity
|
133
|
+
|
134
|
+
The Ruby SDK is working perfectly - this is just how WhatsApp Business API works! 🚀
|
@@ -0,0 +1,350 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'whatsapp_cloud_api'
|
4
|
+
|
5
|
+
puts "=== Advanced Features with Kapso Proxy ==="
|
6
|
+
|
7
|
+
# Initialize Kapso client
|
8
|
+
kapso_client = WhatsAppCloudApi::Client.new(
|
9
|
+
kapso_api_key: ENV['KAPSO_API_KEY'],
|
10
|
+
base_url: 'https://app.kapso.ai/api/meta',
|
11
|
+
debug: true
|
12
|
+
)
|
13
|
+
|
14
|
+
phone_number_id = ENV['PHONE_NUMBER_ID']
|
15
|
+
|
16
|
+
# Example 1: Message History and Analytics
|
17
|
+
puts "\n--- Message History ---"
|
18
|
+
|
19
|
+
begin
|
20
|
+
# Query message history
|
21
|
+
messages = kapso_client.messages.query(
|
22
|
+
phone_number_id: phone_number_id,
|
23
|
+
direction: 'inbound',
|
24
|
+
since: '2024-01-01T00:00:00Z',
|
25
|
+
limit: 10
|
26
|
+
)
|
27
|
+
|
28
|
+
puts "Found #{messages.data.length} messages:"
|
29
|
+
messages.data.each do |message|
|
30
|
+
puts "- #{message['id']}: #{message['type']} from #{message['from']}"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get messages by conversation
|
34
|
+
if messages.data.any? && messages.data.first['conversation_id']
|
35
|
+
conv_messages = kapso_client.messages.list_by_conversation(
|
36
|
+
phone_number_id: phone_number_id,
|
37
|
+
conversation_id: messages.data.first['conversation_id'],
|
38
|
+
limit: 5
|
39
|
+
)
|
40
|
+
|
41
|
+
puts "\nConversation messages: #{conv_messages.data.length}"
|
42
|
+
end
|
43
|
+
|
44
|
+
rescue WhatsAppCloudApi::Errors::KapsoProxyRequiredError => e
|
45
|
+
puts "Kapso Proxy required: #{e.message}"
|
46
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
47
|
+
puts "Message history error: #{e.message}"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Example 2: Conversation Management
|
51
|
+
puts "\n--- Conversation Management ---"
|
52
|
+
|
53
|
+
begin
|
54
|
+
# List active conversations
|
55
|
+
conversations = kapso_client.conversations.list(
|
56
|
+
phone_number_id: phone_number_id,
|
57
|
+
status: 'active',
|
58
|
+
limit: 10
|
59
|
+
)
|
60
|
+
|
61
|
+
puts "Active conversations: #{conversations.data.length}"
|
62
|
+
|
63
|
+
conversations.data.each do |conv|
|
64
|
+
puts "Conversation #{conv.id}:"
|
65
|
+
puts " Phone: #{conv.phone_number}"
|
66
|
+
puts " Status: #{conv.status}"
|
67
|
+
puts " Last Active: #{conv.last_active_at}"
|
68
|
+
|
69
|
+
if conv.kapso
|
70
|
+
puts " Contact Name: #{conv.kapso['contact_name']}"
|
71
|
+
puts " Messages Count: #{conv.kapso['messages_count']}"
|
72
|
+
puts " Last Message: #{conv.kapso['last_message_text']}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Get specific conversation details
|
77
|
+
if conversations.data.any?
|
78
|
+
conversation_id = conversations.data.first.id
|
79
|
+
|
80
|
+
conv_details = kapso_client.conversations.get(
|
81
|
+
conversation_id: conversation_id
|
82
|
+
)
|
83
|
+
|
84
|
+
puts "\nDetailed conversation info:"
|
85
|
+
puts "ID: #{conv_details.id}"
|
86
|
+
puts "Status: #{conv_details.status}"
|
87
|
+
puts "Metadata: #{conv_details.metadata}"
|
88
|
+
|
89
|
+
# Update conversation status
|
90
|
+
kapso_client.conversations.update_status(
|
91
|
+
conversation_id: conversation_id,
|
92
|
+
status: 'archived'
|
93
|
+
)
|
94
|
+
|
95
|
+
puts "Conversation archived successfully"
|
96
|
+
|
97
|
+
# Unarchive it
|
98
|
+
kapso_client.conversations.unarchive(conversation_id: conversation_id)
|
99
|
+
puts "Conversation unarchived"
|
100
|
+
end
|
101
|
+
|
102
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
103
|
+
puts "Conversation management error: #{e.message}"
|
104
|
+
end
|
105
|
+
|
106
|
+
# Example 3: Contact Management
|
107
|
+
puts "\n--- Contact Management ---"
|
108
|
+
|
109
|
+
begin
|
110
|
+
# List contacts
|
111
|
+
contacts = kapso_client.contacts.list(
|
112
|
+
phone_number_id: phone_number_id,
|
113
|
+
limit: 10
|
114
|
+
)
|
115
|
+
|
116
|
+
puts "Found #{contacts.data.length} contacts:"
|
117
|
+
|
118
|
+
contacts.data.each do |contact|
|
119
|
+
puts "Contact #{contact.wa_id}:"
|
120
|
+
puts " Phone: #{contact.phone_number}"
|
121
|
+
puts " Profile Name: #{contact.profile_name}"
|
122
|
+
puts " Metadata: #{contact.metadata}"
|
123
|
+
end
|
124
|
+
|
125
|
+
# Get specific contact
|
126
|
+
if contacts.data.any?
|
127
|
+
wa_id = contacts.data.first.wa_id
|
128
|
+
|
129
|
+
contact_details = kapso_client.contacts.get(
|
130
|
+
phone_number_id: phone_number_id,
|
131
|
+
wa_id: wa_id
|
132
|
+
)
|
133
|
+
|
134
|
+
puts "\nContact details for #{wa_id}:"
|
135
|
+
puts "Profile Name: #{contact_details.profile_name}"
|
136
|
+
|
137
|
+
# Update contact metadata
|
138
|
+
kapso_client.contacts.update(
|
139
|
+
phone_number_id: phone_number_id,
|
140
|
+
wa_id: wa_id,
|
141
|
+
metadata: {
|
142
|
+
tags: ['ruby_sdk', 'test_contact'],
|
143
|
+
source: 'api_example',
|
144
|
+
notes: 'Updated via Ruby SDK'
|
145
|
+
}
|
146
|
+
)
|
147
|
+
|
148
|
+
puts "Contact metadata updated"
|
149
|
+
|
150
|
+
# Add tags
|
151
|
+
kapso_client.contacts.add_tags(
|
152
|
+
phone_number_id: phone_number_id,
|
153
|
+
wa_id: wa_id,
|
154
|
+
tags: ['premium_customer']
|
155
|
+
)
|
156
|
+
|
157
|
+
puts "Tags added to contact"
|
158
|
+
|
159
|
+
# Search contacts
|
160
|
+
search_results = kapso_client.contacts.search(
|
161
|
+
phone_number_id: phone_number_id,
|
162
|
+
query: 'john',
|
163
|
+
search_in: ['profile_name', 'phone_number']
|
164
|
+
)
|
165
|
+
|
166
|
+
puts "Search results: #{search_results.data.length} contacts"
|
167
|
+
end
|
168
|
+
|
169
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
170
|
+
puts "Contact management error: #{e.message}"
|
171
|
+
end
|
172
|
+
|
173
|
+
# Example 4: Call Management
|
174
|
+
puts "\n--- Call Management ---"
|
175
|
+
|
176
|
+
begin
|
177
|
+
# List recent calls
|
178
|
+
calls = kapso_client.calls.list(
|
179
|
+
phone_number_id: phone_number_id,
|
180
|
+
direction: 'INBOUND',
|
181
|
+
limit: 5
|
182
|
+
)
|
183
|
+
|
184
|
+
puts "Recent calls: #{calls.data.length}"
|
185
|
+
|
186
|
+
calls.data.each do |call|
|
187
|
+
puts "Call #{call.id}:"
|
188
|
+
puts " Direction: #{call.direction}"
|
189
|
+
puts " Status: #{call.status}"
|
190
|
+
puts " Duration: #{call.duration_seconds} seconds"
|
191
|
+
puts " Started: #{call.started_at}"
|
192
|
+
end
|
193
|
+
|
194
|
+
# Initiate a call (example - requires proper setup)
|
195
|
+
begin
|
196
|
+
call_response = kapso_client.calls.connect(
|
197
|
+
phone_number_id: phone_number_id,
|
198
|
+
to: '+1234567890',
|
199
|
+
session: {
|
200
|
+
sdp_type: 'offer',
|
201
|
+
sdp: 'v=0\r\no=- 123456789 123456789 IN IP4 127.0.0.1\r\n...'
|
202
|
+
}
|
203
|
+
)
|
204
|
+
|
205
|
+
puts "Call initiated: #{call_response.calls.first['id']}"
|
206
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
207
|
+
puts "Call initiation error (expected in example): #{e.message}"
|
208
|
+
end
|
209
|
+
|
210
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
211
|
+
puts "Call management error: #{e.message}"
|
212
|
+
end
|
213
|
+
|
214
|
+
# Example 5: Advanced Error Handling and Monitoring
|
215
|
+
puts "\n--- Advanced Error Handling ---"
|
216
|
+
|
217
|
+
class WhatsAppMonitor
|
218
|
+
def initialize(client)
|
219
|
+
@client = client
|
220
|
+
@error_counts = Hash.new(0)
|
221
|
+
@last_errors = []
|
222
|
+
end
|
223
|
+
|
224
|
+
def send_with_monitoring(method, *args, **kwargs)
|
225
|
+
start_time = Time.now
|
226
|
+
|
227
|
+
begin
|
228
|
+
result = @client.messages.public_send(method, **kwargs)
|
229
|
+
|
230
|
+
duration = Time.now - start_time
|
231
|
+
puts "✓ #{method} succeeded in #{duration.round(2)}s"
|
232
|
+
|
233
|
+
result
|
234
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
235
|
+
duration = Time.now - start_time
|
236
|
+
@error_counts[e.category] += 1
|
237
|
+
@last_errors << {
|
238
|
+
timestamp: Time.now,
|
239
|
+
method: method,
|
240
|
+
error: e,
|
241
|
+
duration: duration
|
242
|
+
}
|
243
|
+
|
244
|
+
puts "✗ #{method} failed in #{duration.round(2)}s"
|
245
|
+
puts " Category: #{e.category}"
|
246
|
+
puts " Message: #{e.message}"
|
247
|
+
puts " Retry: #{e.retry_hint[:action]}"
|
248
|
+
|
249
|
+
# Automatic retry logic
|
250
|
+
case e.retry_hint[:action]
|
251
|
+
when :retry
|
252
|
+
if kwargs[:_retry_count].to_i < 3
|
253
|
+
retry_count = kwargs[:_retry_count].to_i + 1
|
254
|
+
puts " Auto-retrying (#{retry_count}/3)..."
|
255
|
+
sleep(retry_count)
|
256
|
+
return send_with_monitoring(method, **kwargs.merge(_retry_count: retry_count))
|
257
|
+
end
|
258
|
+
when :retry_after
|
259
|
+
if e.retry_hint[:retry_after_ms] && e.retry_hint[:retry_after_ms] < 30000
|
260
|
+
delay = e.retry_hint[:retry_after_ms] / 1000.0
|
261
|
+
puts " Waiting #{delay}s for rate limit..."
|
262
|
+
sleep(delay)
|
263
|
+
return send_with_monitoring(method, **kwargs)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
raise
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def print_statistics
|
272
|
+
puts "\n--- Error Statistics ---"
|
273
|
+
puts "Total error categories: #{@error_counts.keys.length}"
|
274
|
+
@error_counts.each do |category, count|
|
275
|
+
puts " #{category}: #{count} errors"
|
276
|
+
end
|
277
|
+
|
278
|
+
if @last_errors.any?
|
279
|
+
puts "\nRecent errors:"
|
280
|
+
@last_errors.last(3).each do |error_info|
|
281
|
+
puts " #{error_info[:timestamp]}: #{error_info[:method]} -> #{error_info[:error].category}"
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
# Test the monitoring system
|
288
|
+
monitor = WhatsAppMonitor.new(kapso_client)
|
289
|
+
|
290
|
+
# Test various operations with monitoring
|
291
|
+
test_operations = [
|
292
|
+
[:send_text, {
|
293
|
+
phone_number_id: phone_number_id,
|
294
|
+
to: '+1234567890',
|
295
|
+
body: 'Test message from monitoring system'
|
296
|
+
}],
|
297
|
+
[:send_template, {
|
298
|
+
phone_number_id: phone_number_id,
|
299
|
+
to: '+1234567890',
|
300
|
+
name: 'nonexistent_template',
|
301
|
+
language: 'en_US'
|
302
|
+
}],
|
303
|
+
[:send_image, {
|
304
|
+
phone_number_id: phone_number_id,
|
305
|
+
to: '+1234567890',
|
306
|
+
image: { link: 'https://invalid-url.example/image.jpg' }
|
307
|
+
}]
|
308
|
+
]
|
309
|
+
|
310
|
+
test_operations.each do |method, kwargs|
|
311
|
+
begin
|
312
|
+
monitor.send_with_monitoring(method, **kwargs)
|
313
|
+
rescue => e
|
314
|
+
puts "Final error for #{method}: #{e.message}"
|
315
|
+
end
|
316
|
+
|
317
|
+
sleep(1) # Rate limiting prevention
|
318
|
+
end
|
319
|
+
|
320
|
+
monitor.print_statistics
|
321
|
+
|
322
|
+
# Example 6: Webhook Signature Verification (helper function)
|
323
|
+
puts "\n--- Webhook Signature Verification ---"
|
324
|
+
|
325
|
+
def verify_webhook_signature(payload, signature, app_secret)
|
326
|
+
require 'openssl'
|
327
|
+
|
328
|
+
# Extract signature from header (format: "sha256=...")
|
329
|
+
sig_hash = signature.sub('sha256=', '')
|
330
|
+
|
331
|
+
# Calculate expected signature
|
332
|
+
expected_sig = OpenSSL::HMAC.hexdigest('sha256', app_secret, payload)
|
333
|
+
|
334
|
+
# Secure comparison
|
335
|
+
sig_hash == expected_sig
|
336
|
+
end
|
337
|
+
|
338
|
+
# Example webhook payload verification
|
339
|
+
webhook_payload = '{"object":"whatsapp_business_account","entry":[...]}'
|
340
|
+
webhook_signature = 'sha256=abcdef123456...' # From X-Hub-Signature-256 header
|
341
|
+
app_secret = ENV['WHATSAPP_APP_SECRET']
|
342
|
+
|
343
|
+
if app_secret
|
344
|
+
is_valid = verify_webhook_signature(webhook_payload, webhook_signature, app_secret)
|
345
|
+
puts "Webhook signature valid: #{is_valid}"
|
346
|
+
else
|
347
|
+
puts "Set WHATSAPP_APP_SECRET to test webhook verification"
|
348
|
+
end
|
349
|
+
|
350
|
+
puts "\n=== Advanced Features Examples Completed ==="
|