whatsapp_sdk 1.1.0 → 1.2.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 +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +7 -6
- data/README.md +48 -0
- data/lib/whatsapp_sdk/api/client.rb +12 -6
- data/lib/whatsapp_sdk/api/medias.rb +27 -0
- data/lib/whatsapp_sdk/api/messages.rb +56 -13
- data/lib/whatsapp_sdk/api/responses/generic_error_response.rb +4 -0
- data/lib/whatsapp_sdk/api/responses/message_data_response.rb +3 -1
- data/lib/whatsapp_sdk/resource/contact_response.rb +3 -2
- data/lib/whatsapp_sdk/version.rb +1 -1
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6e1bc509c72a21009421ece7489cc79d178abec74db4445d84cf579fe374d5d3
|
|
4
|
+
data.tar.gz: b547704f8654b49e389547d27014089fdf1583583e57c6f567bf1193dbfc72aa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f302ce6f5126585be265c8a0bdcc7c7681cd27e6838ce6c961a0b196eb66ba0cc3522c87407cbc69af7d95f8adeca02f7dbcf76ee646fddff49e3e50ba6c62b3
|
|
7
|
+
data.tar.gz: d7a97fa6bc6de65711c1d1698cd38863650dfc7f2dd0ef5ec743d2c938e15bca6511f6481c5fd72ee2972ec258466c9066817a9a3ea378f98c0d2db26a05e186
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Unreleased
|
|
2
2
|
|
|
3
|
+
# v 1.2.0
|
|
4
|
+
- Expose Graph media upload sessions through the configured client @oitedi [199](https://github.com/ignacio-chiazzo/ruby_whatsapp_sdk/pull/199)
|
|
5
|
+
- Support BSUID recipients and preserve user IDs in message responses @oitedi [198](https://github.com/ignacio-chiazzo/ruby_whatsapp_sdk/pull/198)
|
|
6
|
+
- Add voice message support to audio sends @oitedi [197](https://github.com/ignacio-chiazzo/ruby_whatsapp_sdk/pull/197)
|
|
7
|
+
- Guard `GenericErrorResponse.build_from_response` against non-Hash input @afonso-aguas [195](https://github.com/ignacio-chiazzo/ruby_whatsapp_sdk/pull/195)
|
|
8
|
+
- Fix false-positive `HttpResponseError` on bodies containing "error" substring @afonso-aguas [194](https://github.com/ignacio-chiazzo/ruby_whatsapp_sdk/pull/194)
|
|
9
|
+
|
|
3
10
|
# v 1.1.0
|
|
4
11
|
- Add support for pagination in template_analytics with 'after' cursor @osvaldo-santos [190](https://github.com/ignacio-chiazzo/ruby_whatsapp_sdk/pull/190)
|
|
5
12
|
- Add template_analytics feature @osvaldo-santos [189](https://github.com/ignacio-chiazzo/ruby_whatsapp_sdk/pull/189)
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
whatsapp_sdk (1.
|
|
4
|
+
whatsapp_sdk (1.2.0)
|
|
5
5
|
faraday (~> 2.0, > 2.0.1)
|
|
6
6
|
faraday-multipart (~> 1)
|
|
7
7
|
zeitwerk (~> 2)
|
|
@@ -9,8 +9,8 @@ PATH
|
|
|
9
9
|
GEM
|
|
10
10
|
remote: https://rubygems.org/
|
|
11
11
|
specs:
|
|
12
|
-
addressable (2.
|
|
13
|
-
public_suffix (>= 2.0.2, <
|
|
12
|
+
addressable (2.9.0)
|
|
13
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
14
14
|
ast (2.4.2)
|
|
15
15
|
base64 (0.2.0)
|
|
16
16
|
coderay (1.1.3)
|
|
@@ -25,10 +25,10 @@ GEM
|
|
|
25
25
|
faraday-net_http (3.4.2)
|
|
26
26
|
net-http (~> 0.5)
|
|
27
27
|
hashdiff (1.0.1)
|
|
28
|
-
json (2.
|
|
28
|
+
json (2.19.9)
|
|
29
29
|
logger (1.7.0)
|
|
30
30
|
method_source (1.0.0)
|
|
31
|
-
minitest (5.
|
|
31
|
+
minitest (5.27.0)
|
|
32
32
|
mocha (1.14.0)
|
|
33
33
|
multipart-post (2.4.1)
|
|
34
34
|
net-http (0.9.1)
|
|
@@ -41,7 +41,7 @@ GEM
|
|
|
41
41
|
method_source (~> 1.0)
|
|
42
42
|
pry-nav (1.0.0)
|
|
43
43
|
pry (>= 0.9.10, < 0.15)
|
|
44
|
-
public_suffix (5.
|
|
44
|
+
public_suffix (5.1.1)
|
|
45
45
|
rainbow (3.1.1)
|
|
46
46
|
rake (12.3.3)
|
|
47
47
|
regexp_parser (2.5.0)
|
|
@@ -78,6 +78,7 @@ PLATFORMS
|
|
|
78
78
|
arm64-darwin-22
|
|
79
79
|
arm64-darwin-23
|
|
80
80
|
arm64-darwin-24
|
|
81
|
+
arm64-darwin-25
|
|
81
82
|
x86_64-darwin-19
|
|
82
83
|
x86_64-darwin-21
|
|
83
84
|
x86_64-linux
|
data/README.md
CHANGED
|
@@ -535,6 +535,54 @@ If the API response is still `success`, but the message is not delivered:
|
|
|
535
535
|
|
|
536
536
|
Note: Sometimes the messages are delayed; see [Meta documentation](https://developers.facebook.com/docs/whatsapp/on-premises/guides/send-message-performance#delays).
|
|
537
537
|
|
|
538
|
+
|
|
539
|
+
### Voice messages
|
|
540
|
+
|
|
541
|
+
Pass `voice: true` to `send_audio` with an uploaded `audio_id` or hosted `link`.
|
|
542
|
+
Voice messages require an Ogg file encoded with Opus; the SDK does not transcode media.
|
|
543
|
+
Omitting `voice` (or passing `false`) sends basic audio.
|
|
544
|
+
|
|
545
|
+
```ruby
|
|
546
|
+
client.messages.send_audio(sender_id: sender_id, recipient_number: recipient_number,
|
|
547
|
+
audio_id: media_id, voice: true)
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
See [Meta's audio message documentation](https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/audio-messages/).
|
|
551
|
+
|
|
552
|
+
### Upload handles for templates and profile photos
|
|
553
|
+
|
|
554
|
+
Use Graph upload sessions when an endpoint requires a media handle instead of a WhatsApp media ID:
|
|
555
|
+
|
|
556
|
+
```ruby
|
|
557
|
+
session = client.media.create_upload_session(app_id: app_id, file_path: "header.png", type: "image/png")
|
|
558
|
+
upload = client.media.upload_file_to_session(session_id: session.fetch("id"), file_path: "header.png")
|
|
559
|
+
handle = upload.fetch("h")
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
Both methods use the client's configured API version and token. An optional `access_token:`
|
|
563
|
+
overrides the token for that request only. They return the Graph response hashes and raise
|
|
564
|
+
`WhatsappSdk::Api::Responses::HttpResponseError` on Graph errors, like the other APIs.
|
|
565
|
+
Missing files or directories raise `WhatsappSdk::Api::Medias::FileNotFoundError`.
|
|
566
|
+
The upload reads the entire file into memory and starts at offset zero; automatic retries and
|
|
567
|
+
resuming interrupted uploads are not included.
|
|
568
|
+
See [Meta's upload guide](https://developers.facebook.com/docs/graph-api/guides/upload).
|
|
569
|
+
|
|
570
|
+
### Business-scoped user IDs (BSUIDs)
|
|
571
|
+
|
|
572
|
+
All message sends accept `recipient:` as an alternative to `recipient_number:`.
|
|
573
|
+
Use the complete BSUID (or parent BSUID), including its country prefix:
|
|
574
|
+
|
|
575
|
+
```ruby
|
|
576
|
+
response = client.messages.send_text(sender_id: sender_id, recipient: "US.123abc", message: "Hello")
|
|
577
|
+
response.contacts.first.user_id # => "US.123abc"
|
|
578
|
+
response.contacts.first.wa_id # => nil when Meta omits the phone number
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
Phone numbers take precedence when both destinations are supplied. Missing or blank
|
|
582
|
+
selected destinations raise `WhatsappSdk::Resource::Errors::MissingArgumentError` before sending.
|
|
583
|
+
Authentication templates require a phone number; the SDK does not infer template category from its name or buttons.
|
|
584
|
+
See [Meta's BSUID documentation](https://developers.facebook.com/documentation/business-messaging/whatsapp/business-scoped-user-ids/).
|
|
585
|
+
|
|
538
586
|
## Development
|
|
539
587
|
|
|
540
588
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests.
|
|
@@ -7,7 +7,7 @@ module WhatsappSdk
|
|
|
7
7
|
module Api
|
|
8
8
|
class Client
|
|
9
9
|
API_VERSIONS = [
|
|
10
|
-
'v24.0', 'v23.0', 'v22.0', 'v21.0', 'v20.0', 'v19.0', 'v18.0', 'v17.0', 'v16.0', 'v15.0', 'v14.0',
|
|
10
|
+
'v25.0', 'v24.0', 'v23.0', 'v22.0', 'v21.0', 'v20.0', 'v19.0', 'v18.0', 'v17.0', 'v16.0', 'v15.0', 'v14.0',
|
|
11
11
|
'v13.0', 'v12.0', 'v11.0', 'v10.0', 'v9.0', 'v8.0', 'v7.0', 'v6.0', 'v5.0', 'v4.0',
|
|
12
12
|
'v3.3', 'v3.2', 'v3.1', 'v3.0', 'v2.12', 'v2.11', 'v2.10', 'v2.9', 'v2.8', 'v2.7',
|
|
13
13
|
'v2.6', 'v2.5', 'v2.4', 'v2.3', 'v2.2', 'v2.1'
|
|
@@ -58,13 +58,13 @@ module WhatsappSdk
|
|
|
58
58
|
|
|
59
59
|
response = faraday_request.public_send(http_method, endpoint, request_params(params, headers), headers)
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
raise Api::Responses::HttpResponseError.new(http_status: response.status, body: JSON.parse(response.body))
|
|
63
|
-
end
|
|
61
|
+
parsed_body = parse_response_body(response.body)
|
|
64
62
|
|
|
65
|
-
|
|
63
|
+
if response.status > 499 || Api::Responses::GenericErrorResponse.response_error?(response: parsed_body)
|
|
64
|
+
raise Api::Responses::HttpResponseError.new(http_status: response.status, body: parsed_body)
|
|
65
|
+
end
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
parsed_body
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
def download_file(url:, content_type_header:, file_path: nil)
|
|
@@ -85,6 +85,12 @@ module WhatsappSdk
|
|
|
85
85
|
|
|
86
86
|
private
|
|
87
87
|
|
|
88
|
+
def parse_response_body(body)
|
|
89
|
+
return nil if body.nil? || body.empty?
|
|
90
|
+
|
|
91
|
+
JSON.parse(body)
|
|
92
|
+
end
|
|
93
|
+
|
|
88
94
|
def request_params(params, headers)
|
|
89
95
|
return params.to_json if params.is_a?(Hash) && headers['Content-Type'] == 'application/json'
|
|
90
96
|
|
|
@@ -117,6 +117,33 @@ module WhatsappSdk
|
|
|
117
117
|
Api::Responses::SuccessResponse.success_response?(response: response)
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
+
# Create a Graph upload session for template media or a business profile photo.
|
|
121
|
+
# Returns the raw response containing the upload session "id".
|
|
122
|
+
# Uses the client's API version and token unless access_token is supplied.
|
|
123
|
+
def create_upload_session(app_id:, file_path:, type:, access_token: nil)
|
|
124
|
+
raise FileNotFoundError.new(file_path: file_path) unless File.file?(file_path)
|
|
125
|
+
|
|
126
|
+
headers = { 'Content-Type' => 'application/json' }
|
|
127
|
+
headers['Authorization'] = "Bearer #{access_token}" if access_token
|
|
128
|
+
send_request(
|
|
129
|
+
endpoint: "./#{app_id}/uploads",
|
|
130
|
+
params: { file_name: File.basename(file_path), file_length: File.size(file_path), file_type: type },
|
|
131
|
+
headers: headers
|
|
132
|
+
)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Upload the complete file to a Graph upload session, starting at offset zero.
|
|
136
|
+
# Returns the raw response containing the reusable media handle "h".
|
|
137
|
+
# This does not resume partial uploads or retry failed requests.
|
|
138
|
+
def upload_file_to_session(session_id:, file_path:, access_token: nil)
|
|
139
|
+
raise FileNotFoundError.new(file_path: file_path) unless File.file?(file_path)
|
|
140
|
+
|
|
141
|
+
headers = { 'Content-Type' => 'application/octet-stream', 'file_offset' => '0' }
|
|
142
|
+
headers['Authorization'] = "Bearer #{access_token}" if access_token
|
|
143
|
+
# ponytail: buffers the whole file; stream bytes if large uploads become a requirement.
|
|
144
|
+
send_request(endpoint: "./#{session_id}", params: File.binread(file_path), headers: headers)
|
|
145
|
+
end
|
|
146
|
+
|
|
120
147
|
private
|
|
121
148
|
|
|
122
149
|
def map_media_type_to_content_type_header(media_type)
|
|
@@ -13,8 +13,9 @@ module WhatsappSdk
|
|
|
13
13
|
# @param recipient_number [Integer] Recipient' Phone number.
|
|
14
14
|
# @param message [String] Text to send.
|
|
15
15
|
# @param message_id [String] The id of the message to reply to.
|
|
16
|
+
# @param recipient [String] Recipient' Business-Scoped User ID (BSUID). Optional alternative to recipient_number.
|
|
16
17
|
# @return [MessageDataResponse] Response object.
|
|
17
|
-
def send_text(sender_id:,
|
|
18
|
+
def send_text(sender_id:, message:, recipient_number: nil, message_id: nil, recipient: nil)
|
|
18
19
|
params = {
|
|
19
20
|
messaging_product: "whatsapp",
|
|
20
21
|
to: recipient_number,
|
|
@@ -23,6 +24,7 @@ module WhatsappSdk
|
|
|
23
24
|
text: { body: message }
|
|
24
25
|
}
|
|
25
26
|
params[:context] = { message_id: message_id } if message_id
|
|
27
|
+
apply_recipient!(params, recipient_number, recipient)
|
|
26
28
|
|
|
27
29
|
response = send_request(
|
|
28
30
|
endpoint: endpoint(sender_id),
|
|
@@ -42,9 +44,10 @@ module WhatsappSdk
|
|
|
42
44
|
# @param name [String] Location name.
|
|
43
45
|
# @param address [String] Location address.
|
|
44
46
|
# @param message_id [String] The id of the message to reply to.
|
|
47
|
+
# @param recipient [String] Recipient' Business-Scoped User ID (BSUID). Optional alternative to recipient_number.
|
|
45
48
|
# @return [MessageDataResponse] Response object.
|
|
46
49
|
def send_location(
|
|
47
|
-
sender_id:,
|
|
50
|
+
sender_id:, longitude:, latitude:, name:, address:, recipient_number: nil, message_id: nil, recipient: nil
|
|
48
51
|
)
|
|
49
52
|
params = {
|
|
50
53
|
messaging_product: "whatsapp",
|
|
@@ -59,6 +62,7 @@ module WhatsappSdk
|
|
|
59
62
|
}
|
|
60
63
|
}
|
|
61
64
|
params[:context] = { message_id: message_id } if message_id
|
|
65
|
+
apply_recipient!(params, recipient_number, recipient)
|
|
62
66
|
|
|
63
67
|
response = send_request(
|
|
64
68
|
endpoint: endpoint(sender_id),
|
|
@@ -77,9 +81,10 @@ module WhatsappSdk
|
|
|
77
81
|
# @param link [String] Image link.
|
|
78
82
|
# @param caption [String] Image caption.
|
|
79
83
|
# @param message_id [String] The id of the message to reply to.
|
|
84
|
+
# @param recipient [String] Recipient' Business-Scoped User ID (BSUID). Optional alternative to recipient_number.
|
|
80
85
|
# @return [MessageDataResponse] Response object.
|
|
81
86
|
def send_image(
|
|
82
|
-
sender_id:, recipient_number
|
|
87
|
+
sender_id:, recipient_number: nil, image_id: nil, link: nil, caption: "", message_id: nil, recipient: nil
|
|
83
88
|
)
|
|
84
89
|
raise Resource::Errors::MissingArgumentError, "image_id or link is required" if !image_id && !link
|
|
85
90
|
|
|
@@ -95,6 +100,7 @@ module WhatsappSdk
|
|
|
95
100
|
{ id: image_id, caption: caption }
|
|
96
101
|
end
|
|
97
102
|
params[:context] = { message_id: message_id } if message_id
|
|
103
|
+
apply_recipient!(params, recipient_number, recipient)
|
|
98
104
|
|
|
99
105
|
response = send_request(
|
|
100
106
|
endpoint: endpoint(sender_id),
|
|
@@ -112,8 +118,12 @@ module WhatsappSdk
|
|
|
112
118
|
# @param audio_id [String] Audio ID.
|
|
113
119
|
# @param link [String] Audio link.
|
|
114
120
|
# @param message_id [String] The id of the message to reply to.
|
|
121
|
+
# @param voice [Boolean] Send an Ogg/Opus voice message instead of basic audio. Defaults to false.
|
|
122
|
+
# @param recipient [String] Recipient' Business-Scoped User ID (BSUID). Optional alternative to recipient_number.
|
|
115
123
|
# @return [MessageDataResponse] Response object.
|
|
116
|
-
def send_audio(
|
|
124
|
+
def send_audio(
|
|
125
|
+
sender_id:, recipient_number: nil, audio_id: nil, link: nil, message_id: nil, voice: false, recipient: nil
|
|
126
|
+
)
|
|
117
127
|
raise Resource::Errors::MissingArgumentError, "audio_id or link is required" if !audio_id && !link
|
|
118
128
|
|
|
119
129
|
params = {
|
|
@@ -122,8 +132,9 @@ module WhatsappSdk
|
|
|
122
132
|
recipient_type: "individual",
|
|
123
133
|
type: "audio"
|
|
124
134
|
}
|
|
125
|
-
params[:audio] = link ? { link: link } : { id: audio_id }
|
|
135
|
+
params[:audio] = link ? { link: link, voice: voice } : { id: audio_id, voice: voice }
|
|
126
136
|
params[:context] = { message_id: message_id } if message_id
|
|
137
|
+
apply_recipient!(params, recipient_number, recipient)
|
|
127
138
|
|
|
128
139
|
response = send_request(
|
|
129
140
|
endpoint: endpoint(sender_id),
|
|
@@ -143,9 +154,10 @@ module WhatsappSdk
|
|
|
143
154
|
# @param link [String] Image link.
|
|
144
155
|
# @param caption [String] Image caption.
|
|
145
156
|
# @param message_id [String] The id of the message to reply to.
|
|
157
|
+
# @param recipient [String] Recipient' Business-Scoped User ID (BSUID). Optional alternative to recipient_number.
|
|
146
158
|
# @return [MessageDataResponse] Response object.
|
|
147
159
|
def send_video(
|
|
148
|
-
sender_id:, recipient_number
|
|
160
|
+
sender_id:, recipient_number: nil, video_id: nil, link: nil, caption: "", message_id: nil, recipient: nil
|
|
149
161
|
)
|
|
150
162
|
raise Resource::Errors::MissingArgumentError, "video_id or link is required" if !video_id && !link
|
|
151
163
|
|
|
@@ -161,6 +173,7 @@ module WhatsappSdk
|
|
|
161
173
|
{ id: video_id, caption: caption }
|
|
162
174
|
end
|
|
163
175
|
params[:context] = { message_id: message_id } if message_id
|
|
176
|
+
apply_recipient!(params, recipient_number, recipient)
|
|
164
177
|
|
|
165
178
|
response = send_request(
|
|
166
179
|
endpoint: endpoint(sender_id),
|
|
@@ -179,9 +192,11 @@ module WhatsappSdk
|
|
|
179
192
|
# @param link [String] Image link.
|
|
180
193
|
# @param caption [String] Image caption.
|
|
181
194
|
# @param message_id [String] The id of the message to reply to.
|
|
195
|
+
# @param recipient [String] Recipient' Business-Scoped User ID (BSUID). Optional alternative to recipient_number.
|
|
182
196
|
# @return [MessageDataResponse] Response object.
|
|
183
197
|
def send_document(
|
|
184
|
-
sender_id:, recipient_number
|
|
198
|
+
sender_id:, recipient_number: nil, document_id: nil, link: nil, caption: "", message_id: nil,
|
|
199
|
+
filename: nil, recipient: nil
|
|
185
200
|
)
|
|
186
201
|
if !document_id && !link
|
|
187
202
|
raise Resource::Errors::MissingArgumentError,
|
|
@@ -201,6 +216,7 @@ module WhatsappSdk
|
|
|
201
216
|
end
|
|
202
217
|
params[:document] = params[:document].merge({ filename: filename }) if filename
|
|
203
218
|
params[:context] = { message_id: message_id } if message_id
|
|
219
|
+
apply_recipient!(params, recipient_number, recipient)
|
|
204
220
|
|
|
205
221
|
response = send_request(
|
|
206
222
|
endpoint: endpoint(sender_id),
|
|
@@ -211,15 +227,16 @@ module WhatsappSdk
|
|
|
211
227
|
Api::Responses::MessageDataResponse.build_from_response(response: response)
|
|
212
228
|
end
|
|
213
229
|
|
|
214
|
-
# Send a
|
|
230
|
+
# Send a sticker.
|
|
215
231
|
#
|
|
216
232
|
# @param sender_id [Integer] Sender' phone number.
|
|
217
233
|
# @param recipient_number [Integer] Recipient' Phone number.
|
|
218
234
|
# @param sticker_id [String] The sticker ID.
|
|
219
235
|
# @param link [String] Image link.
|
|
220
236
|
# @param message_id [String] The id of the message to reply to.
|
|
237
|
+
# @param recipient [String] Recipient' Business-Scoped User ID (BSUID). Optional alternative to recipient_number.
|
|
221
238
|
# @return [MessageDataResponse] Response object.
|
|
222
|
-
def send_sticker(sender_id:, recipient_number
|
|
239
|
+
def send_sticker(sender_id:, recipient_number: nil, sticker_id: nil, link: nil, message_id: nil, recipient: nil)
|
|
223
240
|
raise Resource::Errors::MissingArgumentError, "sticker or link is required" if !sticker_id && !link
|
|
224
241
|
|
|
225
242
|
params = {
|
|
@@ -230,6 +247,7 @@ module WhatsappSdk
|
|
|
230
247
|
}
|
|
231
248
|
params[:sticker] = link ? { link: link } : { id: sticker_id }
|
|
232
249
|
params[:context] = { message_id: message_id } if message_id
|
|
250
|
+
apply_recipient!(params, recipient_number, recipient)
|
|
233
251
|
|
|
234
252
|
response = send_request(
|
|
235
253
|
endpoint: endpoint(sender_id),
|
|
@@ -248,9 +266,10 @@ module WhatsappSdk
|
|
|
248
266
|
# @param contacts [Array<Contact>] Contacts.
|
|
249
267
|
# @param contacts_json [Json] Contacts.
|
|
250
268
|
# @param message_id [String] The id of the message to reply to.
|
|
269
|
+
# @param recipient [String] Recipient' Business-Scoped User ID (BSUID). Optional alternative to recipient_number.
|
|
251
270
|
# @return [MessageDataResponse] Response object.
|
|
252
271
|
def send_contacts(
|
|
253
|
-
sender_id:, recipient_number
|
|
272
|
+
sender_id:, recipient_number: nil, contacts: nil, contacts_json: {}, message_id: nil, recipient: nil
|
|
254
273
|
)
|
|
255
274
|
params = {
|
|
256
275
|
messaging_product: "whatsapp",
|
|
@@ -260,6 +279,7 @@ module WhatsappSdk
|
|
|
260
279
|
}
|
|
261
280
|
params[:contacts] = contacts ? contacts.map(&:to_h) : contacts_json
|
|
262
281
|
params[:context] = { message_id: message_id } if message_id
|
|
282
|
+
apply_recipient!(params, recipient_number, recipient)
|
|
263
283
|
|
|
264
284
|
response = send_request(
|
|
265
285
|
endpoint: endpoint(sender_id),
|
|
@@ -284,9 +304,10 @@ module WhatsappSdk
|
|
|
284
304
|
# @param interactive_json [Json] The interactive object as a Json.
|
|
285
305
|
# If you pass interactive_json, you can't pass interactive.
|
|
286
306
|
# @param message_id [String] The id of the message to reply to.
|
|
307
|
+
# @param recipient [String] Recipient' Business-Scoped User ID (BSUID). Optional alternative to recipient_number.
|
|
287
308
|
# @return [MessageDataResponse] Response object.
|
|
288
309
|
def send_interactive_message(
|
|
289
|
-
sender_id:, recipient_number
|
|
310
|
+
sender_id:, recipient_number: nil, interactive: nil, interactive_json: nil, message_id: nil, recipient: nil
|
|
290
311
|
)
|
|
291
312
|
if !interactive && !interactive_json
|
|
292
313
|
raise Resource::Errors::MissingArgumentError,
|
|
@@ -306,6 +327,7 @@ module WhatsappSdk
|
|
|
306
327
|
interactive.to_json
|
|
307
328
|
end
|
|
308
329
|
params[:context] = { message_id: message_id } if message_id
|
|
330
|
+
apply_recipient!(params, recipient_number, recipient)
|
|
309
331
|
|
|
310
332
|
response = send_request(
|
|
311
333
|
endpoint: endpoint(sender_id),
|
|
@@ -348,9 +370,11 @@ module WhatsappSdk
|
|
|
348
370
|
# @param language [String] template language.
|
|
349
371
|
# @param components [Component] Component.
|
|
350
372
|
# @param components_json [Json] The component as a Json. If you pass components_json, you can't pass components.
|
|
373
|
+
# @param recipient [String] Recipient' Business-Scoped User ID (BSUID). Optional alternative to recipient_number.
|
|
374
|
+
# Not allowed for authentication templates.
|
|
351
375
|
# @return [MessageDataResponse] Response object.
|
|
352
376
|
def send_template(
|
|
353
|
-
sender_id:,
|
|
377
|
+
sender_id:, name:, language:, recipient_number: nil, components: nil, components_json: nil, recipient: nil
|
|
354
378
|
)
|
|
355
379
|
if !components && !components_json
|
|
356
380
|
raise Resource::Errors::MissingArgumentError,
|
|
@@ -373,6 +397,7 @@ module WhatsappSdk
|
|
|
373
397
|
else
|
|
374
398
|
components.map(&:to_json)
|
|
375
399
|
end
|
|
400
|
+
apply_recipient!(params, recipient_number, recipient)
|
|
376
401
|
|
|
377
402
|
response = send_request(
|
|
378
403
|
endpoint: endpoint(sender_id),
|
|
@@ -389,8 +414,9 @@ module WhatsappSdk
|
|
|
389
414
|
# @param recipient_number [Integer] Recipient' Phone number.
|
|
390
415
|
# @param message_id [String] the id of the message to reaction.
|
|
391
416
|
# @param emoji [String] unicode of the emoji to send.
|
|
417
|
+
# @param recipient [String] Recipient' Business-Scoped User ID (BSUID). Optional alternative to recipient_number.
|
|
392
418
|
# @return [MessageDataResponse] Response object.
|
|
393
|
-
def send_reaction(sender_id:,
|
|
419
|
+
def send_reaction(sender_id:, message_id:, emoji:, recipient_number: nil, recipient: nil)
|
|
394
420
|
params = {
|
|
395
421
|
messaging_product: "whatsapp",
|
|
396
422
|
recipient_type: "individual",
|
|
@@ -401,6 +427,7 @@ module WhatsappSdk
|
|
|
401
427
|
emoji: emoji
|
|
402
428
|
}
|
|
403
429
|
}
|
|
430
|
+
apply_recipient!(params, recipient_number, recipient)
|
|
404
431
|
|
|
405
432
|
response = send_request(
|
|
406
433
|
endpoint: endpoint(sender_id),
|
|
@@ -441,6 +468,22 @@ module WhatsappSdk
|
|
|
441
468
|
def endpoint(sender_id)
|
|
442
469
|
"#{sender_id}/messages"
|
|
443
470
|
end
|
|
471
|
+
|
|
472
|
+
# Applies the destination to the payload.
|
|
473
|
+
# - Phone send (recipient_number present): keeps `to`, never adds `recipient` — payload is
|
|
474
|
+
# identical to the pre-BSUID behavior.
|
|
475
|
+
# - BSUID send (recipient_number absent, recipient present): drops `to` and sets `recipient`
|
|
476
|
+
# (the field Meta uses to address a Business-Scoped User ID).
|
|
477
|
+
# Requires at least one destination.
|
|
478
|
+
def apply_recipient!(params, recipient_number, recipient)
|
|
479
|
+
if (recipient_number.nil? ? recipient : recipient_number).to_s.strip.empty?
|
|
480
|
+
raise Resource::Errors::MissingArgumentError, "recipient_number or recipient is required"
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
params.delete(:to) if recipient_number.nil?
|
|
484
|
+
params[:recipient] = recipient if recipient_number.nil? && recipient
|
|
485
|
+
params
|
|
486
|
+
end
|
|
444
487
|
end
|
|
445
488
|
end
|
|
446
489
|
end
|
|
@@ -16,10 +16,14 @@ module WhatsappSdk
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def self.response_error?(response:)
|
|
19
|
+
return false unless response.is_a?(Hash)
|
|
20
|
+
|
|
19
21
|
response["error"]
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def self.build_from_response(response:)
|
|
25
|
+
return unless response.is_a?(Hash)
|
|
26
|
+
|
|
23
27
|
error_response = response["error"]
|
|
24
28
|
return unless error_response
|
|
25
29
|
|
|
@@ -27,7 +27,9 @@ module WhatsappSdk
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def parse_contact(contact_json)
|
|
30
|
-
Resource::ContactResponse.new(
|
|
30
|
+
Resource::ContactResponse.new(
|
|
31
|
+
input: contact_json["input"], wa_id: contact_json["wa_id"], user_id: contact_json["user_id"]
|
|
32
|
+
)
|
|
31
33
|
end
|
|
32
34
|
end
|
|
33
35
|
end
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
module WhatsappSdk
|
|
4
4
|
module Resource
|
|
5
5
|
class ContactResponse
|
|
6
|
-
attr_accessor :wa_id, :input
|
|
6
|
+
attr_accessor :wa_id, :input, :user_id
|
|
7
7
|
|
|
8
|
-
def initialize(input:, wa_id:)
|
|
8
|
+
def initialize(input:, wa_id: nil, user_id: nil)
|
|
9
9
|
@input = input
|
|
10
10
|
@wa_id = wa_id
|
|
11
|
+
@user_id = user_id
|
|
11
12
|
end
|
|
12
13
|
end
|
|
13
14
|
end
|
data/lib/whatsapp_sdk/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: whatsapp_sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ignacio-chiazzo
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: bundler
|
|
@@ -196,7 +195,6 @@ metadata:
|
|
|
196
195
|
source_code_uri: https://github.com/ignacio-chiazzo/ruby_whatsapp_sdk
|
|
197
196
|
changelog_uri: https://github.com/ignacio-chiazzo/ruby_whatsapp_sdk/blob/main/CHANGELOG.md
|
|
198
197
|
rubygems_mfa_required: 'true'
|
|
199
|
-
post_install_message:
|
|
200
198
|
rdoc_options: []
|
|
201
199
|
require_paths:
|
|
202
200
|
- lib
|
|
@@ -211,8 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
211
209
|
- !ruby/object:Gem::Version
|
|
212
210
|
version: '0'
|
|
213
211
|
requirements: []
|
|
214
|
-
rubygems_version:
|
|
215
|
-
signing_key:
|
|
212
|
+
rubygems_version: 4.0.20
|
|
216
213
|
specification_version: 4
|
|
217
214
|
summary: Use the Ruby Whatsapp SDK to communicate with Whatsapp API using the Cloud
|
|
218
215
|
API
|