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
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'whatsapp_cloud_api'
|
4
|
+
|
5
|
+
# Example 1: Basic Text Message
|
6
|
+
puts "=== Basic Text Message ==="
|
7
|
+
|
8
|
+
begin
|
9
|
+
# Initialize client with access token (direct Meta API)
|
10
|
+
client = WhatsAppCloudApi::Client.new(
|
11
|
+
access_token: ENV['WHATSAPP_ACCESS_TOKEN']
|
12
|
+
)
|
13
|
+
|
14
|
+
# Send a simple text message
|
15
|
+
response = client.messages.send_text(
|
16
|
+
phone_number_id: ENV['PHONE_NUMBER_ID'],
|
17
|
+
to: '+56912345678',
|
18
|
+
body: 'Hello! This is a test message from Ruby SDK.'
|
19
|
+
)
|
20
|
+
|
21
|
+
puts "Message sent successfully!"
|
22
|
+
puts "Message ID: #{response.messages.first.id}"
|
23
|
+
puts "Contact: #{response.contacts.first.wa_id}"
|
24
|
+
|
25
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
26
|
+
puts "API Error: #{e.message}"
|
27
|
+
puts "Category: #{e.category}"
|
28
|
+
puts "HTTP Status: #{e.http_status}"
|
29
|
+
puts "Retry Action: #{e.retry_hint[:action]}"
|
30
|
+
|
31
|
+
if e.rate_limit?
|
32
|
+
puts "Rate limited! Retry after: #{e.retry_hint[:retry_after_ms]}ms"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Example 2: Media Message with Error Handling
|
37
|
+
puts "\n=== Media Message with Error Handling ==="
|
38
|
+
|
39
|
+
begin
|
40
|
+
# Send image message
|
41
|
+
response = client.messages.send_image(
|
42
|
+
phone_number_id: ENV['PHONE_NUMBER_ID'],
|
43
|
+
to: '+1234567890',
|
44
|
+
image: {
|
45
|
+
link: 'https://example.com/image.jpg',
|
46
|
+
caption: 'Check out this image!'
|
47
|
+
}
|
48
|
+
)
|
49
|
+
|
50
|
+
puts "Image message sent: #{response.messages.first.id}"
|
51
|
+
|
52
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
53
|
+
case e.category
|
54
|
+
when :media
|
55
|
+
puts "Media error: #{e.details}"
|
56
|
+
puts "Check your media file URL or format"
|
57
|
+
when :parameter
|
58
|
+
puts "Parameter error: #{e.message}"
|
59
|
+
puts "Check your phone number and recipient format"
|
60
|
+
when :throttling
|
61
|
+
puts "Rate limited - waiting before retry"
|
62
|
+
sleep(e.retry_hint[:retry_after_ms] / 1000.0) if e.retry_hint[:retry_after_ms]
|
63
|
+
else
|
64
|
+
puts "Other error: #{e.message}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Example 3: Template Message
|
69
|
+
puts "\n=== Template Message ==="
|
70
|
+
|
71
|
+
begin
|
72
|
+
response = client.messages.send_template(
|
73
|
+
phone_number_id: ENV['PHONE_NUMBER_ID'],
|
74
|
+
to: '+1234567890',
|
75
|
+
name: 'welcome_template',
|
76
|
+
language: 'en_US',
|
77
|
+
components: [
|
78
|
+
{
|
79
|
+
type: 'body',
|
80
|
+
parameters: [
|
81
|
+
{ type: 'text', text: 'John Doe' }
|
82
|
+
]
|
83
|
+
}
|
84
|
+
]
|
85
|
+
)
|
86
|
+
|
87
|
+
puts "Template message sent: #{response.messages.first.id}"
|
88
|
+
|
89
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
90
|
+
if e.template_error?
|
91
|
+
puts "Template error: #{e.details}"
|
92
|
+
puts "Check template name, language, and parameters"
|
93
|
+
else
|
94
|
+
puts "Error: #{e.message}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Example 4: Interactive Buttons
|
99
|
+
puts "\n=== Interactive Buttons ==="
|
100
|
+
|
101
|
+
begin
|
102
|
+
response = client.messages.send_interactive_buttons(
|
103
|
+
phone_number_id: ENV['PHONE_NUMBER_ID'],
|
104
|
+
to: '+1234567890',
|
105
|
+
body_text: 'Please choose an option:',
|
106
|
+
buttons: [
|
107
|
+
{
|
108
|
+
type: 'reply',
|
109
|
+
reply: {
|
110
|
+
id: 'option_1',
|
111
|
+
title: 'Option 1'
|
112
|
+
}
|
113
|
+
},
|
114
|
+
{
|
115
|
+
type: 'reply',
|
116
|
+
reply: {
|
117
|
+
id: 'option_2',
|
118
|
+
title: 'Option 2'
|
119
|
+
}
|
120
|
+
}
|
121
|
+
],
|
122
|
+
header: {
|
123
|
+
type: 'text',
|
124
|
+
text: 'Choose Your Option'
|
125
|
+
},
|
126
|
+
footer: {
|
127
|
+
text: 'Powered by Ruby SDK'
|
128
|
+
}
|
129
|
+
)
|
130
|
+
|
131
|
+
puts "Interactive message sent: #{response.messages.first.id}"
|
132
|
+
|
133
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
134
|
+
puts "Interactive message error: #{e.message}"
|
135
|
+
end
|
136
|
+
|
137
|
+
puts "\n=== Example completed ==="
|
@@ -0,0 +1,254 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'whatsapp_cloud_api'
|
4
|
+
|
5
|
+
puts "=== Media Management Examples ==="
|
6
|
+
|
7
|
+
# Initialize client
|
8
|
+
client = WhatsAppCloudApi::Client.new(
|
9
|
+
access_token: ENV['WHATSAPP_ACCESS_TOKEN'],
|
10
|
+
debug: true # Enable debug logging
|
11
|
+
)
|
12
|
+
|
13
|
+
# Example 1: Upload Media File
|
14
|
+
puts "\n--- Upload Media File ---"
|
15
|
+
|
16
|
+
begin
|
17
|
+
# Upload an image file
|
18
|
+
upload_response = client.media.upload(
|
19
|
+
phone_number_id: ENV['PHONE_NUMBER_ID'],
|
20
|
+
type: 'image',
|
21
|
+
file: 'path/to/your/image.jpg', # Replace with actual file path
|
22
|
+
filename: 'my_image.jpg'
|
23
|
+
)
|
24
|
+
|
25
|
+
media_id = upload_response.id
|
26
|
+
puts "File uploaded successfully!"
|
27
|
+
puts "Media ID: #{media_id}"
|
28
|
+
|
29
|
+
# Get media metadata
|
30
|
+
metadata = client.media.get(media_id: media_id)
|
31
|
+
puts "\nMedia Metadata:"
|
32
|
+
puts "URL: #{metadata.url}"
|
33
|
+
puts "MIME Type: #{metadata.mime_type}"
|
34
|
+
puts "File Size: #{metadata.file_size} bytes"
|
35
|
+
puts "SHA256: #{metadata.sha256}"
|
36
|
+
|
37
|
+
# Send the uploaded media
|
38
|
+
message_response = client.messages.send_image(
|
39
|
+
phone_number_id: ENV['PHONE_NUMBER_ID'],
|
40
|
+
to: '+1234567890',
|
41
|
+
image: { id: media_id, caption: 'Uploaded via Ruby SDK!' }
|
42
|
+
)
|
43
|
+
|
44
|
+
puts "\nMessage sent with uploaded media: #{message_response.messages.first.id}"
|
45
|
+
|
46
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
47
|
+
puts "Upload error: #{e.message}"
|
48
|
+
puts "Category: #{e.category}"
|
49
|
+
|
50
|
+
case e.category
|
51
|
+
when :media
|
52
|
+
puts "Media-specific error - check file format, size, or type"
|
53
|
+
when :parameter
|
54
|
+
puts "Parameter error - check phone_number_id and file path"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Example 2: Upload Different Media Types
|
59
|
+
puts "\n--- Upload Different Media Types ---"
|
60
|
+
|
61
|
+
media_examples = [
|
62
|
+
{ type: 'image', file: 'examples/sample_image.jpg', message_method: :send_image },
|
63
|
+
{ type: 'audio', file: 'examples/sample_audio.mp3', message_method: :send_audio },
|
64
|
+
{ type: 'video', file: 'examples/sample_video.mp4', message_method: :send_video },
|
65
|
+
{ type: 'document', file: 'examples/sample_document.pdf', message_method: :send_document }
|
66
|
+
]
|
67
|
+
|
68
|
+
media_examples.each do |example|
|
69
|
+
begin
|
70
|
+
next unless File.exist?(example[:file]) # Skip if file doesn't exist
|
71
|
+
|
72
|
+
puts "\nUploading #{example[:type]}: #{example[:file]}"
|
73
|
+
|
74
|
+
upload_response = client.media.upload(
|
75
|
+
phone_number_id: ENV['PHONE_NUMBER_ID'],
|
76
|
+
type: example[:type],
|
77
|
+
file: example[:file]
|
78
|
+
)
|
79
|
+
|
80
|
+
puts "Uploaded #{example[:type]} - Media ID: #{upload_response.id}"
|
81
|
+
|
82
|
+
# Send message with the uploaded media
|
83
|
+
case example[:message_method]
|
84
|
+
when :send_image
|
85
|
+
client.messages.send_image(
|
86
|
+
phone_number_id: ENV['PHONE_NUMBER_ID'],
|
87
|
+
to: '+1234567890',
|
88
|
+
image: { id: upload_response.id, caption: "#{example[:type].capitalize} via Ruby SDK" }
|
89
|
+
)
|
90
|
+
when :send_audio
|
91
|
+
client.messages.send_audio(
|
92
|
+
phone_number_id: ENV['PHONE_NUMBER_ID'],
|
93
|
+
to: '+1234567890',
|
94
|
+
audio: { id: upload_response.id }
|
95
|
+
)
|
96
|
+
when :send_video
|
97
|
+
client.messages.send_video(
|
98
|
+
phone_number_id: ENV['PHONE_NUMBER_ID'],
|
99
|
+
to: '+1234567890',
|
100
|
+
video: { id: upload_response.id, caption: "Video via Ruby SDK" }
|
101
|
+
)
|
102
|
+
when :send_document
|
103
|
+
client.messages.send_document(
|
104
|
+
phone_number_id: ENV['PHONE_NUMBER_ID'],
|
105
|
+
to: '+1234567890',
|
106
|
+
document: {
|
107
|
+
id: upload_response.id,
|
108
|
+
caption: "Document via Ruby SDK",
|
109
|
+
filename: File.basename(example[:file])
|
110
|
+
}
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
puts "Message sent successfully!"
|
115
|
+
|
116
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
117
|
+
puts "Error with #{example[:type]}: #{e.message}"
|
118
|
+
rescue StandardError => e
|
119
|
+
puts "File error with #{example[:file]}: #{e.message}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Example 3: Download Media
|
124
|
+
puts "\n--- Download Media ---"
|
125
|
+
|
126
|
+
begin
|
127
|
+
# First, get a media ID (you would normally get this from webhook or previous upload)
|
128
|
+
sample_media_id = "your_media_id_here" # Replace with actual media ID
|
129
|
+
|
130
|
+
# Download media content
|
131
|
+
puts "Downloading media: #{sample_media_id}"
|
132
|
+
|
133
|
+
# Method 1: Download to memory
|
134
|
+
content = client.media.download(
|
135
|
+
media_id: sample_media_id,
|
136
|
+
phone_number_id: ENV['PHONE_NUMBER_ID'],
|
137
|
+
as: :binary
|
138
|
+
)
|
139
|
+
|
140
|
+
puts "Downloaded #{content.length} bytes"
|
141
|
+
|
142
|
+
# Method 2: Save directly to file
|
143
|
+
saved_path = client.media.save_to_file(
|
144
|
+
media_id: sample_media_id,
|
145
|
+
filepath: "downloaded_media_#{sample_media_id}.jpg",
|
146
|
+
phone_number_id: ENV['PHONE_NUMBER_ID']
|
147
|
+
)
|
148
|
+
|
149
|
+
puts "Media saved to: #{saved_path}"
|
150
|
+
|
151
|
+
# Method 3: Get as base64
|
152
|
+
base64_content = client.media.download(
|
153
|
+
media_id: sample_media_id,
|
154
|
+
phone_number_id: ENV['PHONE_NUMBER_ID'],
|
155
|
+
as: :base64
|
156
|
+
)
|
157
|
+
|
158
|
+
puts "Base64 content (first 100 chars): #{base64_content[0..100]}..."
|
159
|
+
|
160
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
161
|
+
puts "Download error: #{e.message}"
|
162
|
+
|
163
|
+
if e.http_status == 404
|
164
|
+
puts "Media not found - it may have been deleted or expired"
|
165
|
+
elsif e.http_status == 403
|
166
|
+
puts "Access denied - check your permissions"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Example 4: Media Management with Kapso Proxy
|
171
|
+
puts "\n--- Media Management with Kapso Proxy ---"
|
172
|
+
|
173
|
+
begin
|
174
|
+
# Initialize Kapso client
|
175
|
+
kapso_client = WhatsAppCloudApi::Client.new(
|
176
|
+
kapso_api_key: ENV['KAPSO_API_KEY'],
|
177
|
+
base_url: 'https://app.kapso.ai/api/meta'
|
178
|
+
)
|
179
|
+
|
180
|
+
# With Kapso proxy, phone_number_id is required for media operations
|
181
|
+
media_id = "sample_media_id"
|
182
|
+
|
183
|
+
# Get media info (includes enhanced metadata from Kapso)
|
184
|
+
info = kapso_client.media.info(
|
185
|
+
media_id: media_id,
|
186
|
+
phone_number_id: ENV['PHONE_NUMBER_ID']
|
187
|
+
)
|
188
|
+
|
189
|
+
puts "Media Info:"
|
190
|
+
puts "ID: #{info[:id]}"
|
191
|
+
puts "MIME Type: #{info[:mime_type]}"
|
192
|
+
puts "Size: #{info[:file_size]} bytes"
|
193
|
+
puts "URL: #{info[:url]}"
|
194
|
+
|
195
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
196
|
+
puts "Kapso media error: #{e.message}"
|
197
|
+
end
|
198
|
+
|
199
|
+
# Example 5: Error Handling and Retry Logic
|
200
|
+
puts "\n--- Error Handling and Retry Logic ---"
|
201
|
+
|
202
|
+
def upload_with_retry(client, phone_number_id, file_path, max_retries = 3)
|
203
|
+
retries = 0
|
204
|
+
|
205
|
+
begin
|
206
|
+
client.media.upload(
|
207
|
+
phone_number_id: phone_number_id,
|
208
|
+
type: 'image',
|
209
|
+
file: file_path
|
210
|
+
)
|
211
|
+
rescue WhatsAppCloudApi::Errors::GraphApiError => e
|
212
|
+
retries += 1
|
213
|
+
|
214
|
+
case e.retry_hint[:action]
|
215
|
+
when :retry
|
216
|
+
if retries <= max_retries
|
217
|
+
puts "Retrying upload (attempt #{retries}/#{max_retries})..."
|
218
|
+
sleep(1 * retries) # Exponential backoff
|
219
|
+
retry
|
220
|
+
else
|
221
|
+
puts "Max retries exceeded"
|
222
|
+
raise
|
223
|
+
end
|
224
|
+
when :retry_after
|
225
|
+
if retries <= max_retries && e.retry_hint[:retry_after_ms]
|
226
|
+
delay_seconds = e.retry_hint[:retry_after_ms] / 1000.0
|
227
|
+
puts "Rate limited. Waiting #{delay_seconds} seconds..."
|
228
|
+
sleep(delay_seconds)
|
229
|
+
retry
|
230
|
+
else
|
231
|
+
raise
|
232
|
+
end
|
233
|
+
when :do_not_retry
|
234
|
+
puts "Permanent error - do not retry: #{e.message}"
|
235
|
+
raise
|
236
|
+
else
|
237
|
+
puts "Unknown error - manual intervention needed: #{e.message}"
|
238
|
+
raise
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
begin
|
244
|
+
response = upload_with_retry(
|
245
|
+
client,
|
246
|
+
ENV['PHONE_NUMBER_ID'],
|
247
|
+
'examples/sample_image.jpg'
|
248
|
+
)
|
249
|
+
puts "Upload successful with retry logic: #{response.id}"
|
250
|
+
rescue => e
|
251
|
+
puts "Final upload error: #{e.message}"
|
252
|
+
end
|
253
|
+
|
254
|
+
puts "\n=== Media Management Examples Completed ==="
|