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.
@@ -0,0 +1,18 @@
1
+ # Kapso Proxy API
2
+ KAPSO_API_KEY=your_kapso_api_key_here
3
+ PHONE_NUMBER_ID=your_phone_number_id_here
4
+ WHATSAPP_BASE_URL=https://app.kapso.ai/api/meta
5
+
6
+ # Business Account ID (required for template management)
7
+ # Find this in your Kapso dashboard under WhatsApp Business section
8
+ BUSINESS_ACCOUNT_ID=your_business_account_id_here
9
+
10
+ # Optional: Set API version
11
+ # WHATSAPP_API_VERSION=v24.0
12
+
13
+ # Optional: Enable debug mode
14
+ # WHATSAPP_DEBUG=true
15
+
16
+ # Optional: Set timeouts (in seconds)
17
+ # WHATSAPP_TIMEOUT=30
18
+ # WHATSAPP_OPEN_TIMEOUT=10
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'dotenv/load' rescue nil
5
+ require_relative '../lib/whatsapp_cloud_api'
6
+
7
+ puts "๐Ÿ” Kapso Template Finder"
8
+ puts "=" * 30
9
+
10
+ kapso_api_key = ENV['KAPSO_API_KEY']
11
+ phone_number_id = ENV['PHONE_NUMBER_ID']
12
+ business_account_id = ENV['BUSINESS_ACCOUNT_ID']
13
+
14
+ unless kapso_api_key && phone_number_id
15
+ puts "โŒ Missing credentials. Run: ruby sdk_test.rb"
16
+ exit 1
17
+ end
18
+
19
+ client = WhatsAppCloudApi::Client.new(
20
+ kapso_api_key: kapso_api_key,
21
+ base_url: ENV['WHATSAPP_BASE_URL'] || 'https://app.kapso.ai/api/meta'
22
+ )
23
+
24
+ puts "Phone: #{phone_number_id}"
25
+ puts "Business Account: #{business_account_id || 'Not set'}"
26
+
27
+ print "Destination (+56912345678): "
28
+ to_number = gets.chomp
29
+ to_number = "+56912345678" if to_number.empty?
30
+
31
+ puts "\n๐Ÿ“‹ Finding Templates..."
32
+ found_templates = []
33
+
34
+ # Try Business Account if available
35
+ if business_account_id
36
+ puts "Checking Business Account..."
37
+ begin
38
+ response = client.templates.list(business_account_id: business_account_id)
39
+ if response.data && response.data.any?
40
+ response.data.each do |template|
41
+ found_templates << {
42
+ name: template.name,
43
+ language: template.language,
44
+ status: template.status
45
+ }
46
+ puts "โœ… #{template.name} (#{template.language}) - #{template.status}"
47
+ end
48
+ end
49
+ rescue => e
50
+ puts "โŒ Error: #{e.message}"
51
+ end
52
+ end
53
+
54
+ # Test common names if none found
55
+ if found_templates.empty?
56
+ puts "Testing common template names..."
57
+ ["hello_world", "welcome_message"].each do |name|
58
+ print "Testing #{name}... "
59
+ begin
60
+ client.messages.send_template(
61
+ phone_number_id: phone_number_id,
62
+ to: to_number,
63
+ name: name,
64
+ language: "en_US"
65
+ )
66
+ puts "โœ… WORKS"
67
+ found_templates << { name: name, language: "en_US", status: "APPROVED" }
68
+ rescue => e
69
+ puts "โŒ Not found" if e.message.include?("does not exist")
70
+ end
71
+ end
72
+ end
73
+
74
+ puts "\n=" * 30
75
+ puts "๐Ÿ“Š RESULTS"
76
+
77
+ if found_templates.any?
78
+ puts "Found #{found_templates.length} template(s):"
79
+ found_templates.each do |t|
80
+ puts "\nโ€ข #{t[:name]} (#{t[:language]})"
81
+ puts " Status: #{t[:status]}"
82
+ end
83
+ puts "\n๐ŸŽฏ Templates work 24/7 - no time limits!"
84
+ else
85
+ puts "No templates found"
86
+ puts "\nNext steps:"
87
+ puts "1. Add BUSINESS_ACCOUNT_ID to .env"
88
+ puts "2. Create templates in Kapso dashboard"
89
+ end
90
+
91
+ puts "\n๐Ÿ’ก Templates solve the 24-hour problem!"
@@ -0,0 +1,405 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/whatsapp_cloud_api'
5
+
6
+ puts "=== Kapso.ai and WhatsApp Cloud API Ruby SDK Setup ==="
7
+ puts
8
+
9
+ # Helper method for safe input
10
+ def get_input(prompt, required: false, mask: false)
11
+ loop do
12
+ print prompt
13
+ if mask
14
+ # For sensitive input, use a simple masking approach
15
+ begin
16
+ system "stty -echo" if STDIN.tty?
17
+ input = gets.chomp
18
+ ensure
19
+ system "stty echo" if STDIN.tty?
20
+ puts # New line after hidden input
21
+ end
22
+ else
23
+ input = gets.chomp
24
+ end
25
+
26
+ if required && input.strip.empty?
27
+ puts "โŒ This field is required. Please try again."
28
+ next
29
+ end
30
+
31
+ return input.strip
32
+ end
33
+ end
34
+
35
+ # Interactive Environment Setup
36
+ puts "๐Ÿ”ง WhatsApp Cloud API Configuration"
37
+ puts "-" * 40
38
+ puts "Please provide your API credentials (leave empty for test mode):"
39
+ puts
40
+
41
+ # Get Phone Number ID first (common to all)
42
+ phone_number_id = get_input("๐Ÿ“ฑ Phone Number ID (or press Enter for test mode): ")
43
+
44
+ if phone_number_id.empty?
45
+ # Test mode
46
+ puts "\n๐Ÿงช Test Mode - Using mock credentials"
47
+ ENV['WHATSAPP_ACCESS_TOKEN'] = 'test_token_12345'
48
+ ENV['PHONE_NUMBER_ID'] = 'test_phone_id_12345'
49
+ test_mode = true
50
+ puts "โœ… Test credentials configured"
51
+ else
52
+ # Real credentials
53
+ ENV['PHONE_NUMBER_ID'] = phone_number_id
54
+ test_mode = false
55
+
56
+ puts "\nChoose your API provider:"
57
+ puts "๐Ÿ“ฑ Meta WhatsApp Business API (get token from: https://developers.facebook.com/apps)"
58
+ puts "๐Ÿš€ Kapso Proxy API (get key from: https://app.kapso.ai)"
59
+ puts
60
+
61
+ # Try to get access token first
62
+ access_token = get_input("๐Ÿ”‘ WhatsApp Access Token (or press Enter to use Kapso): ", mask: true)
63
+
64
+ if access_token.empty?
65
+ # Use Kapso API
66
+ kapso_api_key = get_input("๐Ÿ”‘ Kapso API Key: ", required: true, mask: true)
67
+ ENV['KAPSO_API_KEY'] = kapso_api_key
68
+ puts "โœ… Kapso API credentials configured"
69
+ else
70
+ # Use Meta API
71
+ ENV['WHATSAPP_ACCESS_TOKEN'] = access_token
72
+ puts "โœ… Meta API credentials configured"
73
+ end
74
+ end
75
+
76
+ puts
77
+ puts "Current Configuration:"
78
+ if ENV['WHATSAPP_ACCESS_TOKEN']
79
+ puts " Access Token: ***#{ENV['WHATSAPP_ACCESS_TOKEN'][-4..-1]}"
80
+ elsif ENV['KAPSO_API_KEY']
81
+ puts " Kapso API Key: ***#{ENV['KAPSO_API_KEY'][-4..-1]}"
82
+ else
83
+ puts " Kapso API Key: Not set"
84
+ end
85
+ puts " Phone Number ID: #{ENV['PHONE_NUMBER_ID']}"
86
+ puts
87
+
88
+ test_real_api = false
89
+ if !test_mode # Only ask for real API test if not in test mode
90
+ puts "โš ๏ธ Real API Test Warning:"
91
+ puts " This will make actual API calls and may incur charges"
92
+ puts " Make sure your credentials are valid and you have proper permissions"
93
+
94
+ confirmation = get_input("Do you want to test with real API calls? (y/N): ")
95
+ test_real_api = confirmation.downcase == 'y' || confirmation.downcase == 'yes'
96
+ else
97
+ puts "โ„น๏ธ Test mode selected - skipping real API calls"
98
+ end
99
+
100
+ puts
101
+
102
+ # Test 1: Configuration and Client Initialization
103
+ puts "1. Testing Client Initialization"
104
+ puts "-" * 40
105
+
106
+ begin
107
+ # Initialize client based on configured environment
108
+ if ENV['KAPSO_API_KEY']
109
+ client = WhatsAppCloudApi::Client.new(
110
+ kapso_api_key: ENV['KAPSO_API_KEY'],
111
+ base_url: 'https://app.kapso.ai/api/meta',
112
+ debug: true
113
+ )
114
+ puts "โœ… Kapso client initialized"
115
+ puts " Kapso proxy: #{client.kapso_proxy?}"
116
+ else
117
+ client = WhatsAppCloudApi::Client.new(
118
+ access_token: ENV['WHATSAPP_ACCESS_TOKEN'],
119
+ debug: true
120
+ )
121
+ puts "โœ… Meta API client initialized"
122
+ puts " Kapso proxy: #{client.kapso_proxy?}"
123
+ end
124
+
125
+ puts " Debug mode: #{client.debug}"
126
+
127
+ rescue => e
128
+ puts "โŒ Client initialization failed: #{e.message}"
129
+ end
130
+
131
+ puts
132
+
133
+ # Test 2: Resource Access
134
+ puts "2. Testing Resource Access"
135
+ puts "-" * 40
136
+
137
+ begin
138
+ client = WhatsAppCloudApi::Client.new(access_token: 'test_token')
139
+
140
+ # Test all resource accessors
141
+ resources = {
142
+ 'Messages' => client.messages,
143
+ 'Media' => client.media,
144
+ 'Templates' => client.templates,
145
+ 'Phone Numbers' => client.phone_numbers,
146
+ 'Calls' => client.calls,
147
+ 'Conversations' => client.conversations,
148
+ 'Contacts' => client.contacts
149
+ }
150
+
151
+ resources.each do |name, resource|
152
+ if resource
153
+ puts "โœ… #{name} resource: #{resource.class}"
154
+ else
155
+ puts "โŒ #{name} resource: nil"
156
+ end
157
+ end
158
+
159
+ rescue => e
160
+ puts "โŒ Resource access failed: #{e.message}"
161
+ end
162
+
163
+ puts
164
+
165
+ # Test 3: Configuration System
166
+ puts "3. Testing Configuration System"
167
+ puts "-" * 40
168
+
169
+ begin
170
+ # Test global configuration
171
+ WhatsAppCloudApi.configure do |config|
172
+ config.debug = true
173
+ config.timeout = 45
174
+ config.access_token = 'global_test_token'
175
+ end
176
+
177
+ puts "โœ… Global configuration set"
178
+ puts " Debug: #{WhatsAppCloudApi.configuration.debug}"
179
+ puts " Timeout: #{WhatsAppCloudApi.configuration.timeout}"
180
+ puts " Access token present: #{!WhatsAppCloudApi.configuration.access_token.nil?}"
181
+
182
+ rescue => e
183
+ puts "โŒ Configuration failed: #{e.message}"
184
+ end
185
+
186
+ puts
187
+
188
+ # Test 4: Error Handling System
189
+ puts "4. Testing Error Handling System"
190
+ puts "-" * 40
191
+
192
+ begin
193
+ # Test creating different error types
194
+ rate_limit_error = WhatsAppCloudApi::Errors::GraphApiError.new(
195
+ message: 'Rate limit exceeded',
196
+ code: 4,
197
+ http_status: 429,
198
+ retry_after: 30
199
+ )
200
+
201
+ puts "โœ… Rate limit error created"
202
+ puts " Category: #{rate_limit_error.category}"
203
+ puts " Rate limited?: #{rate_limit_error.rate_limit?}"
204
+ puts " Retry after: #{rate_limit_error.retry_after}s"
205
+ puts " Retry hint: #{rate_limit_error.retry_hint}"
206
+
207
+ auth_error = WhatsAppCloudApi::Errors::GraphApiError.new(
208
+ message: 'Invalid access token',
209
+ code: 190,
210
+ http_status: 401
211
+ )
212
+
213
+ puts "โœ… Auth error created"
214
+ puts " Category: #{auth_error.category}"
215
+ puts " Temporary?: #{auth_error.temporary?}"
216
+ puts " Retry hint: #{auth_error.retry_hint}"
217
+
218
+ rescue => e
219
+ puts "โŒ Error handling test failed: #{e.message}"
220
+ end
221
+
222
+ puts
223
+
224
+ # Test 5: Payload Building (without API calls)
225
+ puts "5. Testing Message Payload Building"
226
+ puts "-" * 40
227
+
228
+ begin
229
+ # Use the configured client
230
+ messages = client.messages
231
+
232
+ # Test payload building (this is internal, so we'll simulate)
233
+ puts "โœ… Messages resource ready"
234
+ puts " Available methods: send_text, send_image, send_template, etc."
235
+
236
+ # Test media types validation
237
+ media_types = WhatsAppCloudApi::Types::MEDIA_TYPES
238
+ puts "โœ… Media types supported: #{media_types.join(', ')}"
239
+
240
+ # Test template statuses
241
+ template_statuses = WhatsAppCloudApi::Types::TEMPLATE_STATUSES
242
+ puts "โœ… Template statuses: #{template_statuses.join(', ')}"
243
+
244
+ rescue => e
245
+ puts "โŒ Payload building test failed: #{e.message}"
246
+ end
247
+
248
+ puts
249
+
250
+ # Test 6: Logger System
251
+ puts "6. Testing Logger System"
252
+ puts "-" * 40
253
+
254
+ begin
255
+ logger = WhatsAppCloudApi.logger
256
+ puts "โœ… Logger accessible"
257
+ puts " Logger class: #{logger.class}"
258
+
259
+ # Test logging (will show in console if debug enabled)
260
+ WhatsAppCloudApi.logger.info("SDK test completed successfully!")
261
+
262
+ rescue => e
263
+ puts "โŒ Logger test failed: #{e.message}"
264
+ end
265
+
266
+ puts
267
+
268
+ # Test 7: Real API Test (if requested)
269
+ if test_real_api
270
+ puts "7. Testing Real API Calls"
271
+ puts "-" * 40
272
+
273
+ begin
274
+ # Use the configured client from Test 1
275
+ phone_number_id = ENV['PHONE_NUMBER_ID']
276
+
277
+ if phone_number_id.nil? || phone_number_id.empty?
278
+ puts "โŒ Phone Number ID not configured"
279
+ else
280
+ puts "๐Ÿ“ฑ Enter the destination WhatsApp number:"
281
+ puts " โ€ข Must include country code (e.g., +1234567890)"
282
+ puts " โ€ข No spaces or special characters except +"
283
+ puts " โ€ข Example: +56912345678"
284
+ puts
285
+
286
+ to_number = nil
287
+ loop do
288
+ to_number = get_input("Destination phone number: ", required: true)
289
+
290
+ # Basic phone number validation
291
+ if to_number.match(/^\+\d{10,15}$/)
292
+ break
293
+ else
294
+ puts "โŒ Invalid format. Please use format: +[country_code][number] (10-15 digits total)"
295
+ puts " Example: +56912345678"
296
+ end
297
+ end
298
+
299
+ puts "\n๐Ÿ“ฑ Sending test message to #{to_number}..."
300
+
301
+ response = client.messages.send_text(
302
+ phone_number_id: phone_number_id,
303
+ to: to_number,
304
+ body: "๐ŸŽ‰ Test message from WhatsApp Cloud API Ruby SDK! Time: #{Time.now}"
305
+ )
306
+
307
+ puts "โœ… Message sent successfully!"
308
+ puts " Message ID: #{response.messages.first.id}"
309
+ puts " Contact WA ID: #{response.contacts.first.wa_id}"
310
+ puts " Message Status: #{response.messages.first.message_status}"
311
+ end
312
+
313
+ rescue WhatsAppCloudApi::Errors::GraphApiError => e
314
+ puts "โŒ API Error: #{e.message}"
315
+ puts " Category: #{e.category}"
316
+ puts " HTTP Status: #{e.http_status}"
317
+ puts " Error Code: #{e.code}"
318
+ puts " Retry Action: #{e.retry_hint}"
319
+
320
+ if e.rate_limit?
321
+ puts " โณ Rate limited! Retry after: #{e.retry_after}s"
322
+ end
323
+
324
+ rescue => e
325
+ puts "โŒ Unexpected error: #{e.message}"
326
+ puts " Class: #{e.class}"
327
+ end
328
+
329
+ puts
330
+ end
331
+
332
+ puts "=== Test Summary ==="
333
+ puts "โœ… WhatsApp Cloud API Ruby SDK is working correctly!"
334
+
335
+ if test_real_api
336
+ puts "๐ŸŒ Real API test completed"
337
+ else
338
+ puts "๐Ÿงช Mock tests completed successfully"
339
+ puts
340
+ puts "๐Ÿ’ก To test real API calls:"
341
+ puts " - Run this script again and choose option 1 or 2"
342
+ puts " - Provide your real WhatsApp Business API credentials"
343
+ puts " - Answer 'y' when asked to test real API calls"
344
+ end
345
+
346
+ puts
347
+ puts "๐Ÿ”ง Configuration used:"
348
+ if ENV['WHATSAPP_ACCESS_TOKEN']
349
+ puts " Access Token: Configured"
350
+ elsif ENV['KAPSO_API_KEY']
351
+ puts " Kapso API Key: Configured"
352
+ else
353
+ puts " Kapso API Key: Not set"
354
+ end
355
+ puts " Phone Number ID: #{ENV['PHONE_NUMBER_ID'] || 'Not set'}"
356
+ puts
357
+
358
+ # Create .env file with configured credentials
359
+ if !test_mode && (ENV['WHATSAPP_ACCESS_TOKEN'] || ENV['KAPSO_API_KEY'])
360
+ puts "๐Ÿ’พ Creating .env file for production use..."
361
+
362
+ env_content = []
363
+ env_content << "# WhatsApp Cloud API Configuration"
364
+ env_content << "# Generated by WhatsApp Cloud API Ruby SDK Test"
365
+ env_content << "# #{Time.now}"
366
+ env_content << ""
367
+
368
+ if ENV['WHATSAPP_ACCESS_TOKEN']
369
+ env_content << "# Meta WhatsApp Business API"
370
+ env_content << "WHATSAPP_ACCESS_TOKEN=#{ENV['WHATSAPP_ACCESS_TOKEN']}"
371
+ env_content << "PHONE_NUMBER_ID=#{ENV['PHONE_NUMBER_ID']}"
372
+ env_content << ""
373
+ env_content << "# Optional: Set base URL for custom endpoints"
374
+ env_content << "# WHATSAPP_BASE_URL=https://graph.facebook.com"
375
+ env_content << "# WHATSAPP_API_VERSION=v24.0"
376
+ end
377
+
378
+ if ENV['KAPSO_API_KEY']
379
+ env_content << "# Kapso Proxy API"
380
+ env_content << "KAPSO_API_KEY=#{ENV['KAPSO_API_KEY']}"
381
+ env_content << "PHONE_NUMBER_ID=#{ENV['PHONE_NUMBER_ID']}"
382
+ env_content << "WHATSAPP_BASE_URL=https://app.kapso.ai/api/meta"
383
+ env_content << ""
384
+ env_content << "# Optional: Set API version"
385
+ env_content << "# WHATSAPP_API_VERSION=v24.0"
386
+ end
387
+
388
+ env_content << ""
389
+ env_content << "# Optional: Enable debug mode"
390
+ env_content << "# WHATSAPP_DEBUG=true"
391
+ env_content << ""
392
+ env_content << "# Optional: Set timeouts (in seconds)"
393
+ env_content << "# WHATSAPP_TIMEOUT=30"
394
+ env_content << "# WHATSAPP_OPEN_TIMEOUT=10"
395
+
396
+ File.write('.env', env_content.join("\n"))
397
+
398
+ puts "โœ… .env file created successfully!"
399
+ puts " You can now use: require 'dotenv/load' in your Ruby applications"
400
+ puts " Or set these environment variables in your deployment environment"
401
+ puts
402
+ end
403
+
404
+ puts "๐Ÿ“š See examples/ directory for more usage examples"
405
+ puts "๐Ÿ“– See README.md for full documentation"
data/scripts/test.rb ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'dotenv/load' rescue nil
5
+ require_relative '../lib/whatsapp_cloud_api'
6
+
7
+ puts "๐Ÿš€ Kapso API Quick Test"
8
+
9
+ # Get credentials
10
+ kapso_api_key = ENV['KAPSO_API_KEY']
11
+ phone_number_id = ENV['PHONE_NUMBER_ID']
12
+
13
+ unless kapso_api_key && phone_number_id
14
+ puts "โŒ Missing credentials. Run: ruby sdk_test.rb"
15
+ exit 1
16
+ end
17
+
18
+ client = WhatsAppCloudApi::Client.new(
19
+ kapso_api_key: kapso_api_key,
20
+ base_url: ENV['WHATSAPP_BASE_URL'] || 'https://app.kapso.ai/api/meta',
21
+ debug: true
22
+ )
23
+
24
+ puts "API Key: ***#{kapso_api_key[-4..-1]} | Phone: #{phone_number_id}"
25
+
26
+ print "Destination (+56912345678): "
27
+ to_number = gets.chomp
28
+
29
+ puts "๐Ÿ“ฑ Sending..."
30
+
31
+ begin
32
+ response = client.messages.send_text(
33
+ phone_number_id: phone_number_id,
34
+ to: to_number,
35
+ body: "Test from Ruby SDK - #{Time.now.strftime('%H:%M')}"
36
+ )
37
+
38
+ puts "โœ… SUCCESS! Message ID: #{response.messages.first.id}"
39
+
40
+ rescue WhatsAppCloudApi::Errors::GraphApiError => e
41
+ puts "โŒ ERROR #{e.http_status}: #{e.message}"
42
+
43
+ # Check for specific 24-hour window error
44
+ if e.message.include?("24 hours") || e.message.include?("Re-engagement")
45
+ puts "โฐ 24-HOUR WINDOW EXPIRED!"
46
+ puts "๐Ÿ’ก Solutions via Kapso.ai:"
47
+ puts " โ€ข Check Kapso dashboard for approved templates"
48
+ puts " โ€ข Run: ruby kapso_template_finder.rb (discover templates)"
49
+ puts " โ€ข Run: ruby template_test.rb (test template sending)"
50
+ else
51
+ case e.http_status
52
+ when 401
53
+ puts "๐Ÿ’ก Check Kapso API key in dashboard"
54
+ when 400
55
+ puts "๐Ÿ’ก Check phone number ID or destination format"
56
+ else
57
+ puts "๐Ÿ’ก Contact Kapso support"
58
+ end
59
+ end
60
+ end