sentdm 0.36.0 → 0.38.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 +16 -0
- data/README.md +1 -1
- data/lib/sentdm/models/inbound_message_event_payload.rb +17 -1
- data/lib/sentdm/models/message_send_params.rb +68 -1
- data/lib/sentdm/resources/messages.rb +24 -8
- data/lib/sentdm/resources/profiles.rb +7 -0
- data/lib/sentdm/version.rb +1 -1
- data/rbi/sentdm/models/inbound_message_event_payload.rbi +24 -0
- data/rbi/sentdm/models/message_send_params.rbi +117 -0
- data/rbi/sentdm/resources/messages.rbi +47 -7
- data/rbi/sentdm/resources/profiles.rbi +7 -0
- data/sig/sentdm/models/inbound_message_event_payload.rbs +5 -0
- data/sig/sentdm/models/message_send_params.rbs +28 -0
- data/sig/sentdm/resources/messages.rbs +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b87a8f99b83286055bbd617ca7e428d48734be02c56c328493de78fbc3676c20
|
|
4
|
+
data.tar.gz: 277e30bdcb461b6d6a124caf606810d09b295ee097b12795d309a705f82cd28e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f5a4a889a1c15fb5962a15e1468106d3eac930c0fd2b9bbe1f2246696c27c504809fbaff257bf06a97c732f877ce04fe02daa1c15eead19d16e7754d53dc4354
|
|
7
|
+
data.tar.gz: 8e0df11e0a4367ee7a2eb5e44798e980ca2e49619d77faa7042c1829ae9f0c8c3e3f46dfb9e43d91c20e566105f06fe0897272096b463d5207e19028244dd78d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.38.0](https://github.com/sentdm/sent-dm-ruby/compare/v0.37.0...v0.38.0) (2026-10-20)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **api:** sync generated SDKs from the committed spec ([0f635d5](https://github.com/sentdm/sent-dm-ruby/commit/0f635d57fa2ee924000ff7c6683ca505d00dc3e2))
|
|
9
|
+
* **api:** sync OpenAPI spec from production ([dbd2131](https://github.com/sentdm/sent-dm-ruby/commit/dbd2131083dda1ff7b2cd11e41db535364881d65))
|
|
10
|
+
|
|
11
|
+
## [0.37.0](https://github.com/sentdm/sent-dm-ruby/compare/v0.36.0...v0.37.0) (2026-10-09)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* **api:** sync generated SDKs from the committed spec ([c38a90b](https://github.com/sentdm/sent-dm-ruby/commit/c38a90bc1459c97d364720a4d37db3a30f5ea396))
|
|
17
|
+
* **api:** sync OpenAPI spec from production ([6697158](https://github.com/sentdm/sent-dm-ruby/commit/66971588cd75f6b148a1e63e9c43f6d54abb0680))
|
|
18
|
+
|
|
3
19
|
## [0.36.0](https://github.com/sentdm/sent-dm-ruby/compare/v0.35.0...v0.36.0) (2026-10-06)
|
|
4
20
|
|
|
5
21
|
|
data/README.md
CHANGED
|
@@ -56,6 +56,20 @@ module Sentdm
|
|
|
56
56
|
# @return [String, nil]
|
|
57
57
|
optional :outbound_number, String
|
|
58
58
|
|
|
59
|
+
# @!attribute referral
|
|
60
|
+
# The ad the contact tapped to start the conversation, present only on whatsapp
|
|
61
|
+
# messages sent from a Click to WhatsApp ad and omitted entirely otherwise.
|
|
62
|
+
#
|
|
63
|
+
# This is Meta's referral object passed through unchanged, with Meta's field names
|
|
64
|
+
# and nesting: source_url, source_id, source_type, headline, body, media_type,
|
|
65
|
+
# image_url (image ads), video_url and thumbnail_url (video ads), ctwa_clid and
|
|
66
|
+
# welcome_message.text. Which fields appear is Meta's decision: ctwa_clid in
|
|
67
|
+
# particular is not sent for ads shown in WhatsApp Status, so treat every field as
|
|
68
|
+
# optional.
|
|
69
|
+
#
|
|
70
|
+
# @return [Object, nil]
|
|
71
|
+
optional :referral, Sentdm::Internal::Type::Unknown, nil?: true
|
|
72
|
+
|
|
59
73
|
# @!attribute text
|
|
60
74
|
# The message body. Sent as null when the inbound message carried no text, for
|
|
61
75
|
# example a media-only message. The field is always present, so read it and check
|
|
@@ -71,7 +85,7 @@ module Sentdm
|
|
|
71
85
|
# @return [String, nil]
|
|
72
86
|
optional :updated_at, String
|
|
73
87
|
|
|
74
|
-
# @!method initialize(inbound_number:, received_at:, account_id: nil, channel: nil, media: nil, message_id: nil, outbound_number: nil, text: nil, updated_at: nil)
|
|
88
|
+
# @!method initialize(inbound_number:, received_at:, account_id: nil, channel: nil, media: nil, message_id: nil, outbound_number: nil, referral: nil, text: nil, updated_at: nil)
|
|
75
89
|
# Some parameter documentations has been truncated, see
|
|
76
90
|
# {Sentdm::Models::InboundMessageEventPayload} for more details.
|
|
77
91
|
#
|
|
@@ -92,6 +106,8 @@ module Sentdm
|
|
|
92
106
|
#
|
|
93
107
|
# @param outbound_number [String] Your number in E.164 format, meaning the number the message was addressed to.
|
|
94
108
|
#
|
|
109
|
+
# @param referral [Object, nil] The ad the contact tapped to start the conversation, present only on whatsapp
|
|
110
|
+
#
|
|
95
111
|
# @param text [String, nil] The message body. Sent as null when the inbound message carried no text, for
|
|
96
112
|
#
|
|
97
113
|
# @param updated_at [String] When the message was received, in UTC (yyyy-MM-ddTHH:mm:ssZ). Same value as
|
|
@@ -15,6 +15,33 @@ module Sentdm
|
|
|
15
15
|
# @return [Array<String>, nil]
|
|
16
16
|
optional :channel, Sentdm::Internal::Type::ArrayOf[String], nil?: true
|
|
17
17
|
|
|
18
|
+
# @!attribute channels
|
|
19
|
+
# Which of your own numbers to send from, keyed by channel, each channel holding a
|
|
20
|
+
# list of entries: {"sms": [{"country": "US", "from": ["+12125550000",
|
|
21
|
+
# "+14155550000"]}, {"from": ["+447700800001"]}]}. Any real channel may be a key;
|
|
22
|
+
# sent, which is auto-detect rather than a channel, is rejected. country and
|
|
23
|
+
# strategy are accepted and stored but not acted on yet: every entry's numbers
|
|
24
|
+
# apply to every recipient on that channel.
|
|
25
|
+
#
|
|
26
|
+
# This does not choose channels — Channel does, and the two combine: "channel":
|
|
27
|
+
# ["sms"] with an sms list sends on SMS from those numbers. Each list only narrows
|
|
28
|
+
# which of its own channel's routes may win, so with Channel left at auto-detect a
|
|
29
|
+
# recipient best served by a channel with no list still goes out on it. Routing
|
|
30
|
+
# itself is unchanged: the same rules are scored and ranked the same way, with
|
|
31
|
+
# routes pinned to numbers you did not list removed from the running.
|
|
32
|
+
#
|
|
33
|
+
# Every number must be an active sender on your account. The request itself is
|
|
34
|
+
# still accepted (202) if one is not — like every other send-time rule, that is
|
|
35
|
+
# decided per message, so each affected message is recorded BLOCKED with error
|
|
36
|
+
# code BUSINESS_029 and reported on GET /v3/messages and the status webhook.
|
|
37
|
+
#
|
|
38
|
+
# @return [Hash{Symbol=>Array<Sentdm::Models::MessageSendParams::Channel>}, nil]
|
|
39
|
+
optional :channels,
|
|
40
|
+
-> {
|
|
41
|
+
Sentdm::Internal::Type::HashOf[Sentdm::Internal::Type::ArrayOf[Sentdm::MessageSendParams::Channel]]
|
|
42
|
+
},
|
|
43
|
+
nil?: true
|
|
44
|
+
|
|
18
45
|
# @!attribute media_urls
|
|
19
46
|
# Attachments for this send, as publicly fetchable https URLs. Used by the MMS
|
|
20
47
|
# channel and ignored by every other one.
|
|
@@ -93,12 +120,14 @@ module Sentdm
|
|
|
93
120
|
# @return [String, nil]
|
|
94
121
|
optional :x_profile_id, String
|
|
95
122
|
|
|
96
|
-
# @!method initialize(channel: nil, media_urls: nil, sandbox: nil, scheduled_at: nil, subject: nil, template: nil, text: nil, to: nil, idempotency_key: nil, x_profile_id: nil, request_options: {})
|
|
123
|
+
# @!method initialize(channel: nil, channels: nil, media_urls: nil, sandbox: nil, scheduled_at: nil, subject: nil, template: nil, text: nil, to: nil, idempotency_key: nil, x_profile_id: nil, request_options: {})
|
|
97
124
|
# Some parameter documentations has been truncated, see
|
|
98
125
|
# {Sentdm::Models::MessageSendParams} for more details.
|
|
99
126
|
#
|
|
100
127
|
# @param channel [Array<String>, nil] Channels to broadcast on, e.g. ["whatsapp", "sms"].
|
|
101
128
|
#
|
|
129
|
+
# @param channels [Hash{Symbol=>Array<Sentdm::Models::MessageSendParams::Channel>}, nil] Which of your own numbers to send from, keyed by channel, each channel holding a
|
|
130
|
+
#
|
|
102
131
|
# @param media_urls [Array<String>, nil] Attachments for this send, as publicly fetchable https URLs. Used by the MMS cha
|
|
103
132
|
#
|
|
104
133
|
# @param sandbox [Boolean] Sandbox flag - when true, the operation is simulated without side effects
|
|
@@ -119,6 +148,44 @@ module Sentdm
|
|
|
119
148
|
#
|
|
120
149
|
# @param request_options [Sentdm::RequestOptions, Hash{Symbol=>Object}]
|
|
121
150
|
|
|
151
|
+
class Channel < Sentdm::Internal::Type::BaseModel
|
|
152
|
+
# @!attribute country
|
|
153
|
+
# Recipient country this entry is meant for (ISO 3166-1 alpha-2, e.g. US).
|
|
154
|
+
# Optional. Accepted and stored, not acted on yet.
|
|
155
|
+
#
|
|
156
|
+
# @return [String, nil]
|
|
157
|
+
optional :country, String, nil?: true
|
|
158
|
+
|
|
159
|
+
# @!attribute from
|
|
160
|
+
# Sender numbers in E.164. Each must be an active sender on your account for this
|
|
161
|
+
# channel. That is account state rather than request shape, so it is decided per
|
|
162
|
+
# message: the request is accepted with 202 and a message naming an unusable
|
|
163
|
+
# number is recorded BLOCKED with error code BUSINESS_029.
|
|
164
|
+
#
|
|
165
|
+
# @return [Array<String>, nil]
|
|
166
|
+
optional :from, Sentdm::Internal::Type::ArrayOf[String], nil?: true
|
|
167
|
+
|
|
168
|
+
# @!attribute strategy
|
|
169
|
+
# How to pick a number from From, e.g. sticky or geo. Optional. Accepted and
|
|
170
|
+
# stored, not acted on yet.
|
|
171
|
+
#
|
|
172
|
+
# @return [String, nil]
|
|
173
|
+
optional :strategy, String, nil?: true
|
|
174
|
+
|
|
175
|
+
# @!method initialize(country: nil, from: nil, strategy: nil)
|
|
176
|
+
# Some parameter documentations has been truncated, see
|
|
177
|
+
# {Sentdm::Models::MessageSendParams::Channel} for more details.
|
|
178
|
+
#
|
|
179
|
+
# One entry of a channel's list in Channels, e.g. {"country": "US", "from":
|
|
180
|
+
# ["+15559990002", "+15559990003"], "strategy": "sticky"}.
|
|
181
|
+
#
|
|
182
|
+
# @param country [String, nil] Recipient country this entry is meant for (ISO 3166-1 alpha-2, e.g. US). Optiona
|
|
183
|
+
#
|
|
184
|
+
# @param from [Array<String>, nil] Sender numbers in E.164. Each must be an active sender on your account for this
|
|
185
|
+
#
|
|
186
|
+
# @param strategy [String, nil] How to pick a number from From, e.g. sticky or geo. Optional. Accepted
|
|
187
|
+
end
|
|
188
|
+
|
|
122
189
|
class Template < Sentdm::Internal::Type::BaseModel
|
|
123
190
|
# @!attribute id
|
|
124
191
|
# Template ID (mutually exclusive with name)
|
|
@@ -94,13 +94,27 @@ module Sentdm
|
|
|
94
94
|
# Sends a message to one or more recipients using a template. Supports
|
|
95
95
|
# multi-channel broadcast — when multiple channels are specified (e.g. ["sms",
|
|
96
96
|
# "whatsapp"]), a separate message is created for each (recipient, channel) pair.
|
|
97
|
-
#
|
|
98
|
-
#
|
|
99
|
-
#
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
#
|
|
103
|
-
# message
|
|
97
|
+
# To choose which of your own numbers a send goes out from, use 'channels':
|
|
98
|
+
# {"sms": [{"from": ["+12125550000", "+14155550000"]}]}. Each channel holds a list
|
|
99
|
+
# of entries, each with 'from' and optionally 'country' and 'strategy'; 'country'
|
|
100
|
+
# and 'strategy' are stored but not acted on yet, so every entry's numbers apply
|
|
101
|
+
# to every recipient on that channel. Every number listed must be an active sender
|
|
102
|
+
# on your account. Like the other account-level preconditions below, that is
|
|
103
|
+
# checked per message rather than when the request is received: the request is
|
|
104
|
+
# still accepted with 202, and each affected message is reported as BLOCKED with
|
|
105
|
+
# error code BUSINESS_029 on GET /messages/{id} and the message.blocked webhook.
|
|
106
|
+
# Each channel's numbers restrict which numbers that channel may use; it does not
|
|
107
|
+
# choose channels — 'channel' does, and the two can be combined. With 'channel'
|
|
108
|
+
# left at auto-detect, a recipient best served by a channel you listed no numbers
|
|
109
|
+
# for still goes out on it. Where several of the listed numbers could serve a
|
|
110
|
+
# recipient, routing prefers the one whose area code matches theirs. Keys: sms,
|
|
111
|
+
# whatsapp, rcs, mms. Returns immediately with per-recipient message IDs for async
|
|
112
|
+
# tracking via webhooks or the GET /messages/{id} endpoint. Sends gated before any
|
|
113
|
+
# delivery attempt do not reject the request — an account-level precondition such
|
|
114
|
+
# as insufficient balance, a template not approved for sending, or free-form
|
|
115
|
+
# content with no open conversation with the contact. The send is accepted with
|
|
116
|
+
# 202 and the affected messages are reported as BLOCKED on GET /messages/{id} and
|
|
117
|
+
# the message.blocked webhook. To send later, set scheduled_at (ISO-8601 with an
|
|
104
118
|
# explicit UTC offset; a value without one is rejected) between 1 minute and 30
|
|
105
119
|
# days ahead: the response is a ScheduledSendMessageResponse (the same fields plus
|
|
106
120
|
# scheduled_at; status is still QUEUED), each message then moves to SCHEDULED, is
|
|
@@ -112,10 +126,12 @@ module Sentdm
|
|
|
112
126
|
# second message.scheduled webhook reports the new scheduled_at. An account may
|
|
113
127
|
# hold at most 1,000,000 scheduled messages at once (429 LIMIT_001).
|
|
114
128
|
#
|
|
115
|
-
# @overload send_(channel: nil, media_urls: nil, sandbox: nil, scheduled_at: nil, subject: nil, template: nil, text: nil, to: nil, idempotency_key: nil, x_profile_id: nil, request_options: {})
|
|
129
|
+
# @overload send_(channel: nil, channels: nil, media_urls: nil, sandbox: nil, scheduled_at: nil, subject: nil, template: nil, text: nil, to: nil, idempotency_key: nil, x_profile_id: nil, request_options: {})
|
|
116
130
|
#
|
|
117
131
|
# @param channel [Array<String>, nil] Body param: Channels to broadcast on, e.g. ["whatsapp", "sms"].
|
|
118
132
|
#
|
|
133
|
+
# @param channels [Hash{Symbol=>Array<Sentdm::Models::MessageSendParams::Channel>}, nil] Body param: Which of your own numbers to send from, keyed by channel, each chann
|
|
134
|
+
#
|
|
119
135
|
# @param media_urls [Array<String>, nil] Body param: Attachments for this send, as publicly fetchable https URLs. Used by
|
|
120
136
|
#
|
|
121
137
|
# @param sandbox [Boolean] Body param: Sandbox flag - when true, the operation is simulated without side ef
|
|
@@ -316,6 +316,13 @@ module Sentdm
|
|
|
316
316
|
# deregistered, and its routing rules stop being used. Requires admin role in the
|
|
317
317
|
# organization.
|
|
318
318
|
#
|
|
319
|
+
# A number it holds that your WhatsApp Business Account still carries refuses the
|
|
320
|
+
# delete with a `409 CONFLICT_012`, and nothing is deleted: the number would
|
|
321
|
+
# return to our shared inventory while Meta still routes WhatsApp to it, and only
|
|
322
|
+
# you can take it off the account — deregister **and** delete it in WhatsApp
|
|
323
|
+
# Manager, then try again. A `409 CONFLICT_013` means the account could not be
|
|
324
|
+
# read, so we cannot tell.
|
|
325
|
+
#
|
|
319
326
|
# @overload delete(profile_id, sandbox: nil, x_profile_id: nil, request_options: {})
|
|
320
327
|
#
|
|
321
328
|
# @param profile_id [String] Path param: Profile ID from route parameter
|
data/lib/sentdm/version.rb
CHANGED
|
@@ -59,6 +59,18 @@ module Sentdm
|
|
|
59
59
|
sig { params(outbound_number: String).void }
|
|
60
60
|
attr_writer :outbound_number
|
|
61
61
|
|
|
62
|
+
# The ad the contact tapped to start the conversation, present only on whatsapp
|
|
63
|
+
# messages sent from a Click to WhatsApp ad and omitted entirely otherwise.
|
|
64
|
+
#
|
|
65
|
+
# This is Meta's referral object passed through unchanged, with Meta's field names
|
|
66
|
+
# and nesting: source_url, source_id, source_type, headline, body, media_type,
|
|
67
|
+
# image_url (image ads), video_url and thumbnail_url (video ads), ctwa_clid and
|
|
68
|
+
# welcome_message.text. Which fields appear is Meta's decision: ctwa_clid in
|
|
69
|
+
# particular is not sent for ads shown in WhatsApp Status, so treat every field as
|
|
70
|
+
# optional.
|
|
71
|
+
sig { returns(T.nilable(T.anything)) }
|
|
72
|
+
attr_accessor :referral
|
|
73
|
+
|
|
62
74
|
# The message body. Sent as null when the inbound message carried no text, for
|
|
63
75
|
# example a media-only message. The field is always present, so read it and check
|
|
64
76
|
# for null rather than checking whether the key exists.
|
|
@@ -87,6 +99,7 @@ module Sentdm
|
|
|
87
99
|
),
|
|
88
100
|
message_id: String,
|
|
89
101
|
outbound_number: String,
|
|
102
|
+
referral: T.nilable(T.anything),
|
|
90
103
|
text: T.nilable(String),
|
|
91
104
|
updated_at: String
|
|
92
105
|
).returns(T.attached_class)
|
|
@@ -115,6 +128,16 @@ module Sentdm
|
|
|
115
128
|
message_id: nil,
|
|
116
129
|
# Your number in E.164 format, meaning the number the message was addressed to.
|
|
117
130
|
outbound_number: nil,
|
|
131
|
+
# The ad the contact tapped to start the conversation, present only on whatsapp
|
|
132
|
+
# messages sent from a Click to WhatsApp ad and omitted entirely otherwise.
|
|
133
|
+
#
|
|
134
|
+
# This is Meta's referral object passed through unchanged, with Meta's field names
|
|
135
|
+
# and nesting: source_url, source_id, source_type, headline, body, media_type,
|
|
136
|
+
# image_url (image ads), video_url and thumbnail_url (video ads), ctwa_clid and
|
|
137
|
+
# welcome_message.text. Which fields appear is Meta's decision: ctwa_clid in
|
|
138
|
+
# particular is not sent for ads shown in WhatsApp Status, so treat every field as
|
|
139
|
+
# optional.
|
|
140
|
+
referral: nil,
|
|
118
141
|
# The message body. Sent as null when the inbound message carried no text, for
|
|
119
142
|
# example a media-only message. The field is always present, so read it and check
|
|
120
143
|
# for null rather than checking whether the key exists.
|
|
@@ -136,6 +159,7 @@ module Sentdm
|
|
|
136
159
|
T.nilable(T::Array[Sentdm::InboundMessageEventPayload::Media]),
|
|
137
160
|
message_id: String,
|
|
138
161
|
outbound_number: String,
|
|
162
|
+
referral: T.nilable(T.anything),
|
|
139
163
|
text: T.nilable(String),
|
|
140
164
|
updated_at: String
|
|
141
165
|
}
|
|
@@ -17,6 +17,33 @@ module Sentdm
|
|
|
17
17
|
sig { returns(T.nilable(T::Array[String])) }
|
|
18
18
|
attr_accessor :channel
|
|
19
19
|
|
|
20
|
+
# Which of your own numbers to send from, keyed by channel, each channel holding a
|
|
21
|
+
# list of entries: {"sms": [{"country": "US", "from": ["+12125550000",
|
|
22
|
+
# "+14155550000"]}, {"from": ["+447700800001"]}]}. Any real channel may be a key;
|
|
23
|
+
# sent, which is auto-detect rather than a channel, is rejected. country and
|
|
24
|
+
# strategy are accepted and stored but not acted on yet: every entry's numbers
|
|
25
|
+
# apply to every recipient on that channel.
|
|
26
|
+
#
|
|
27
|
+
# This does not choose channels — Channel does, and the two combine: "channel":
|
|
28
|
+
# ["sms"] with an sms list sends on SMS from those numbers. Each list only narrows
|
|
29
|
+
# which of its own channel's routes may win, so with Channel left at auto-detect a
|
|
30
|
+
# recipient best served by a channel with no list still goes out on it. Routing
|
|
31
|
+
# itself is unchanged: the same rules are scored and ranked the same way, with
|
|
32
|
+
# routes pinned to numbers you did not list removed from the running.
|
|
33
|
+
#
|
|
34
|
+
# Every number must be an active sender on your account. The request itself is
|
|
35
|
+
# still accepted (202) if one is not — like every other send-time rule, that is
|
|
36
|
+
# decided per message, so each affected message is recorded BLOCKED with error
|
|
37
|
+
# code BUSINESS_029 and reported on GET /v3/messages and the status webhook.
|
|
38
|
+
sig do
|
|
39
|
+
returns(
|
|
40
|
+
T.nilable(
|
|
41
|
+
T::Hash[Symbol, T::Array[Sentdm::MessageSendParams::Channel]]
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
attr_accessor :channels
|
|
46
|
+
|
|
20
47
|
# Attachments for this send, as publicly fetchable https URLs. Used by the MMS
|
|
21
48
|
# channel and ignored by every other one.
|
|
22
49
|
#
|
|
@@ -99,6 +126,13 @@ module Sentdm
|
|
|
99
126
|
sig do
|
|
100
127
|
params(
|
|
101
128
|
channel: T.nilable(T::Array[String]),
|
|
129
|
+
channels:
|
|
130
|
+
T.nilable(
|
|
131
|
+
T::Hash[
|
|
132
|
+
Symbol,
|
|
133
|
+
T::Array[Sentdm::MessageSendParams::Channel::OrHash]
|
|
134
|
+
]
|
|
135
|
+
),
|
|
102
136
|
media_urls: T.nilable(T::Array[String]),
|
|
103
137
|
sandbox: T::Boolean,
|
|
104
138
|
scheduled_at: T.nilable(Time),
|
|
@@ -116,6 +150,25 @@ module Sentdm
|
|
|
116
150
|
# separate message per recipient. "sent" = auto-detect. Defaults to ["sent"]
|
|
117
151
|
# (auto-detect) if omitted.
|
|
118
152
|
channel: nil,
|
|
153
|
+
# Which of your own numbers to send from, keyed by channel, each channel holding a
|
|
154
|
+
# list of entries: {"sms": [{"country": "US", "from": ["+12125550000",
|
|
155
|
+
# "+14155550000"]}, {"from": ["+447700800001"]}]}. Any real channel may be a key;
|
|
156
|
+
# sent, which is auto-detect rather than a channel, is rejected. country and
|
|
157
|
+
# strategy are accepted and stored but not acted on yet: every entry's numbers
|
|
158
|
+
# apply to every recipient on that channel.
|
|
159
|
+
#
|
|
160
|
+
# This does not choose channels — Channel does, and the two combine: "channel":
|
|
161
|
+
# ["sms"] with an sms list sends on SMS from those numbers. Each list only narrows
|
|
162
|
+
# which of its own channel's routes may win, so with Channel left at auto-detect a
|
|
163
|
+
# recipient best served by a channel with no list still goes out on it. Routing
|
|
164
|
+
# itself is unchanged: the same rules are scored and ranked the same way, with
|
|
165
|
+
# routes pinned to numbers you did not list removed from the running.
|
|
166
|
+
#
|
|
167
|
+
# Every number must be an active sender on your account. The request itself is
|
|
168
|
+
# still accepted (202) if one is not — like every other send-time rule, that is
|
|
169
|
+
# decided per message, so each affected message is recorded BLOCKED with error
|
|
170
|
+
# code BUSINESS_029 and reported on GET /v3/messages and the status webhook.
|
|
171
|
+
channels: nil,
|
|
119
172
|
# Attachments for this send, as publicly fetchable https URLs. Used by the MMS
|
|
120
173
|
# channel and ignored by every other one.
|
|
121
174
|
#
|
|
@@ -166,6 +219,10 @@ module Sentdm
|
|
|
166
219
|
override.returns(
|
|
167
220
|
{
|
|
168
221
|
channel: T.nilable(T::Array[String]),
|
|
222
|
+
channels:
|
|
223
|
+
T.nilable(
|
|
224
|
+
T::Hash[Symbol, T::Array[Sentdm::MessageSendParams::Channel]]
|
|
225
|
+
),
|
|
169
226
|
media_urls: T.nilable(T::Array[String]),
|
|
170
227
|
sandbox: T::Boolean,
|
|
171
228
|
scheduled_at: T.nilable(Time),
|
|
@@ -182,6 +239,66 @@ module Sentdm
|
|
|
182
239
|
def to_hash
|
|
183
240
|
end
|
|
184
241
|
|
|
242
|
+
class Channel < Sentdm::Internal::Type::BaseModel
|
|
243
|
+
OrHash =
|
|
244
|
+
T.type_alias do
|
|
245
|
+
T.any(Sentdm::MessageSendParams::Channel, Sentdm::Internal::AnyHash)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# Recipient country this entry is meant for (ISO 3166-1 alpha-2, e.g. US).
|
|
249
|
+
# Optional. Accepted and stored, not acted on yet.
|
|
250
|
+
sig { returns(T.nilable(String)) }
|
|
251
|
+
attr_accessor :country
|
|
252
|
+
|
|
253
|
+
# Sender numbers in E.164. Each must be an active sender on your account for this
|
|
254
|
+
# channel. That is account state rather than request shape, so it is decided per
|
|
255
|
+
# message: the request is accepted with 202 and a message naming an unusable
|
|
256
|
+
# number is recorded BLOCKED with error code BUSINESS_029.
|
|
257
|
+
sig { returns(T.nilable(T::Array[String])) }
|
|
258
|
+
attr_accessor :from
|
|
259
|
+
|
|
260
|
+
# How to pick a number from From, e.g. sticky or geo. Optional. Accepted and
|
|
261
|
+
# stored, not acted on yet.
|
|
262
|
+
sig { returns(T.nilable(String)) }
|
|
263
|
+
attr_accessor :strategy
|
|
264
|
+
|
|
265
|
+
# One entry of a channel's list in Channels, e.g. {"country": "US", "from":
|
|
266
|
+
# ["+15559990002", "+15559990003"], "strategy": "sticky"}.
|
|
267
|
+
sig do
|
|
268
|
+
params(
|
|
269
|
+
country: T.nilable(String),
|
|
270
|
+
from: T.nilable(T::Array[String]),
|
|
271
|
+
strategy: T.nilable(String)
|
|
272
|
+
).returns(T.attached_class)
|
|
273
|
+
end
|
|
274
|
+
def self.new(
|
|
275
|
+
# Recipient country this entry is meant for (ISO 3166-1 alpha-2, e.g. US).
|
|
276
|
+
# Optional. Accepted and stored, not acted on yet.
|
|
277
|
+
country: nil,
|
|
278
|
+
# Sender numbers in E.164. Each must be an active sender on your account for this
|
|
279
|
+
# channel. That is account state rather than request shape, so it is decided per
|
|
280
|
+
# message: the request is accepted with 202 and a message naming an unusable
|
|
281
|
+
# number is recorded BLOCKED with error code BUSINESS_029.
|
|
282
|
+
from: nil,
|
|
283
|
+
# How to pick a number from From, e.g. sticky or geo. Optional. Accepted and
|
|
284
|
+
# stored, not acted on yet.
|
|
285
|
+
strategy: nil
|
|
286
|
+
)
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
sig do
|
|
290
|
+
override.returns(
|
|
291
|
+
{
|
|
292
|
+
country: T.nilable(String),
|
|
293
|
+
from: T.nilable(T::Array[String]),
|
|
294
|
+
strategy: T.nilable(String)
|
|
295
|
+
}
|
|
296
|
+
)
|
|
297
|
+
end
|
|
298
|
+
def to_hash
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
185
302
|
class Template < Sentdm::Internal::Type::BaseModel
|
|
186
303
|
OrHash =
|
|
187
304
|
T.type_alias do
|
|
@@ -73,13 +73,27 @@ module Sentdm
|
|
|
73
73
|
# Sends a message to one or more recipients using a template. Supports
|
|
74
74
|
# multi-channel broadcast — when multiple channels are specified (e.g. ["sms",
|
|
75
75
|
# "whatsapp"]), a separate message is created for each (recipient, channel) pair.
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
#
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
# message
|
|
76
|
+
# To choose which of your own numbers a send goes out from, use 'channels':
|
|
77
|
+
# {"sms": [{"from": ["+12125550000", "+14155550000"]}]}. Each channel holds a list
|
|
78
|
+
# of entries, each with 'from' and optionally 'country' and 'strategy'; 'country'
|
|
79
|
+
# and 'strategy' are stored but not acted on yet, so every entry's numbers apply
|
|
80
|
+
# to every recipient on that channel. Every number listed must be an active sender
|
|
81
|
+
# on your account. Like the other account-level preconditions below, that is
|
|
82
|
+
# checked per message rather than when the request is received: the request is
|
|
83
|
+
# still accepted with 202, and each affected message is reported as BLOCKED with
|
|
84
|
+
# error code BUSINESS_029 on GET /messages/{id} and the message.blocked webhook.
|
|
85
|
+
# Each channel's numbers restrict which numbers that channel may use; it does not
|
|
86
|
+
# choose channels — 'channel' does, and the two can be combined. With 'channel'
|
|
87
|
+
# left at auto-detect, a recipient best served by a channel you listed no numbers
|
|
88
|
+
# for still goes out on it. Where several of the listed numbers could serve a
|
|
89
|
+
# recipient, routing prefers the one whose area code matches theirs. Keys: sms,
|
|
90
|
+
# whatsapp, rcs, mms. Returns immediately with per-recipient message IDs for async
|
|
91
|
+
# tracking via webhooks or the GET /messages/{id} endpoint. Sends gated before any
|
|
92
|
+
# delivery attempt do not reject the request — an account-level precondition such
|
|
93
|
+
# as insufficient balance, a template not approved for sending, or free-form
|
|
94
|
+
# content with no open conversation with the contact. The send is accepted with
|
|
95
|
+
# 202 and the affected messages are reported as BLOCKED on GET /messages/{id} and
|
|
96
|
+
# the message.blocked webhook. To send later, set scheduled_at (ISO-8601 with an
|
|
83
97
|
# explicit UTC offset; a value without one is rejected) between 1 minute and 30
|
|
84
98
|
# days ahead: the response is a ScheduledSendMessageResponse (the same fields plus
|
|
85
99
|
# scheduled_at; status is still QUEUED), each message then moves to SCHEDULED, is
|
|
@@ -93,6 +107,13 @@ module Sentdm
|
|
|
93
107
|
sig do
|
|
94
108
|
params(
|
|
95
109
|
channel: T.nilable(T::Array[String]),
|
|
110
|
+
channels:
|
|
111
|
+
T.nilable(
|
|
112
|
+
T::Hash[
|
|
113
|
+
Symbol,
|
|
114
|
+
T::Array[Sentdm::MessageSendParams::Channel::OrHash]
|
|
115
|
+
]
|
|
116
|
+
),
|
|
96
117
|
media_urls: T.nilable(T::Array[String]),
|
|
97
118
|
sandbox: T::Boolean,
|
|
98
119
|
scheduled_at: T.nilable(Time),
|
|
@@ -110,6 +131,25 @@ module Sentdm
|
|
|
110
131
|
# produces a separate message per recipient. "sent" = auto-detect. Defaults to
|
|
111
132
|
# ["sent"] (auto-detect) if omitted.
|
|
112
133
|
channel: nil,
|
|
134
|
+
# Body param: Which of your own numbers to send from, keyed by channel, each
|
|
135
|
+
# channel holding a list of entries: {"sms": [{"country": "US", "from":
|
|
136
|
+
# ["+12125550000", "+14155550000"]}, {"from": ["+447700800001"]}]}. Any real
|
|
137
|
+
# channel may be a key; sent, which is auto-detect rather than a channel, is
|
|
138
|
+
# rejected. country and strategy are accepted and stored but not acted on yet:
|
|
139
|
+
# every entry's numbers apply to every recipient on that channel.
|
|
140
|
+
#
|
|
141
|
+
# This does not choose channels — Channel does, and the two combine: "channel":
|
|
142
|
+
# ["sms"] with an sms list sends on SMS from those numbers. Each list only narrows
|
|
143
|
+
# which of its own channel's routes may win, so with Channel left at auto-detect a
|
|
144
|
+
# recipient best served by a channel with no list still goes out on it. Routing
|
|
145
|
+
# itself is unchanged: the same rules are scored and ranked the same way, with
|
|
146
|
+
# routes pinned to numbers you did not list removed from the running.
|
|
147
|
+
#
|
|
148
|
+
# Every number must be an active sender on your account. The request itself is
|
|
149
|
+
# still accepted (202) if one is not — like every other send-time rule, that is
|
|
150
|
+
# decided per message, so each affected message is recorded BLOCKED with error
|
|
151
|
+
# code BUSINESS_029 and reported on GET /v3/messages and the status webhook.
|
|
152
|
+
channels: nil,
|
|
113
153
|
# Body param: Attachments for this send, as publicly fetchable https URLs. Used by
|
|
114
154
|
# the MMS channel and ignored by every other one.
|
|
115
155
|
#
|
|
@@ -385,6 +385,13 @@ module Sentdm
|
|
|
385
385
|
# inventory and can go to whoever asks next, its own WhatsApp account is
|
|
386
386
|
# deregistered, and its routing rules stop being used. Requires admin role in the
|
|
387
387
|
# organization.
|
|
388
|
+
#
|
|
389
|
+
# A number it holds that your WhatsApp Business Account still carries refuses the
|
|
390
|
+
# delete with a `409 CONFLICT_012`, and nothing is deleted: the number would
|
|
391
|
+
# return to our shared inventory while Meta still routes WhatsApp to it, and only
|
|
392
|
+
# you can take it off the account — deregister **and** delete it in WhatsApp
|
|
393
|
+
# Manager, then try again. A `409 CONFLICT_013` means the account could not be
|
|
394
|
+
# read, so we cannot tell.
|
|
388
395
|
sig do
|
|
389
396
|
params(
|
|
390
397
|
profile_id: String,
|
|
@@ -9,6 +9,7 @@ module Sentdm
|
|
|
9
9
|
media: ::Array[Sentdm::InboundMessageEventPayload::Media]?,
|
|
10
10
|
message_id: String,
|
|
11
11
|
outbound_number: String,
|
|
12
|
+
referral: top?,
|
|
12
13
|
text: String?,
|
|
13
14
|
updated_at: String
|
|
14
15
|
}
|
|
@@ -36,6 +37,8 @@ module Sentdm
|
|
|
36
37
|
|
|
37
38
|
def outbound_number=: (String) -> String
|
|
38
39
|
|
|
40
|
+
attr_accessor referral: top?
|
|
41
|
+
|
|
39
42
|
attr_accessor text: String?
|
|
40
43
|
|
|
41
44
|
attr_reader updated_at: String?
|
|
@@ -50,6 +53,7 @@ module Sentdm
|
|
|
50
53
|
?media: ::Array[Sentdm::InboundMessageEventPayload::Media]?,
|
|
51
54
|
?message_id: String,
|
|
52
55
|
?outbound_number: String,
|
|
56
|
+
?referral: top?,
|
|
53
57
|
?text: String?,
|
|
54
58
|
?updated_at: String
|
|
55
59
|
) -> void
|
|
@@ -62,6 +66,7 @@ module Sentdm
|
|
|
62
66
|
media: ::Array[Sentdm::InboundMessageEventPayload::Media]?,
|
|
63
67
|
message_id: String,
|
|
64
68
|
outbound_number: String,
|
|
69
|
+
referral: top?,
|
|
65
70
|
text: String?,
|
|
66
71
|
updated_at: String
|
|
67
72
|
}
|
|
@@ -3,6 +3,7 @@ module Sentdm
|
|
|
3
3
|
type message_send_params =
|
|
4
4
|
{
|
|
5
5
|
channel: ::Array[String]?,
|
|
6
|
+
channels: ::Hash[Symbol, ::Array[Sentdm::MessageSendParams::Channel]]?,
|
|
6
7
|
media_urls: ::Array[String]?,
|
|
7
8
|
sandbox: bool,
|
|
8
9
|
scheduled_at: Time?,
|
|
@@ -21,6 +22,8 @@ module Sentdm
|
|
|
21
22
|
|
|
22
23
|
attr_accessor channel: ::Array[String]?
|
|
23
24
|
|
|
25
|
+
attr_accessor channels: ::Hash[Symbol, ::Array[Sentdm::MessageSendParams::Channel]]?
|
|
26
|
+
|
|
24
27
|
attr_accessor media_urls: ::Array[String]?
|
|
25
28
|
|
|
26
29
|
attr_reader sandbox: bool?
|
|
@@ -49,6 +52,7 @@ module Sentdm
|
|
|
49
52
|
|
|
50
53
|
def initialize: (
|
|
51
54
|
?channel: ::Array[String]?,
|
|
55
|
+
?channels: ::Hash[Symbol, ::Array[Sentdm::MessageSendParams::Channel]]?,
|
|
52
56
|
?media_urls: ::Array[String]?,
|
|
53
57
|
?sandbox: bool,
|
|
54
58
|
?scheduled_at: Time?,
|
|
@@ -63,6 +67,7 @@ module Sentdm
|
|
|
63
67
|
|
|
64
68
|
def to_hash: -> {
|
|
65
69
|
channel: ::Array[String]?,
|
|
70
|
+
channels: ::Hash[Symbol, ::Array[Sentdm::MessageSendParams::Channel]]?,
|
|
66
71
|
media_urls: ::Array[String]?,
|
|
67
72
|
sandbox: bool,
|
|
68
73
|
scheduled_at: Time?,
|
|
@@ -75,6 +80,29 @@ module Sentdm
|
|
|
75
80
|
request_options: Sentdm::RequestOptions
|
|
76
81
|
}
|
|
77
82
|
|
|
83
|
+
type channel =
|
|
84
|
+
{ country: String?, from: ::Array[String]?, strategy: String? }
|
|
85
|
+
|
|
86
|
+
class Channel < Sentdm::Internal::Type::BaseModel
|
|
87
|
+
attr_accessor country: String?
|
|
88
|
+
|
|
89
|
+
attr_accessor from: ::Array[String]?
|
|
90
|
+
|
|
91
|
+
attr_accessor strategy: String?
|
|
92
|
+
|
|
93
|
+
def initialize: (
|
|
94
|
+
?country: String?,
|
|
95
|
+
?from: ::Array[String]?,
|
|
96
|
+
?strategy: String?
|
|
97
|
+
) -> void
|
|
98
|
+
|
|
99
|
+
def to_hash: -> {
|
|
100
|
+
country: String?,
|
|
101
|
+
from: ::Array[String]?,
|
|
102
|
+
strategy: String?
|
|
103
|
+
}
|
|
104
|
+
end
|
|
105
|
+
|
|
78
106
|
type template =
|
|
79
107
|
{ id: String?, name: String?, parameters: ::Hash[Symbol, String]? }
|
|
80
108
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sentdm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.38.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sent
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: cgi
|