sentdm 0.32.0 → 0.33.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 +9 -0
- data/README.md +1 -1
- data/lib/sentdm/client.rb +6 -0
- data/lib/sentdm/models/channel_event_payload.rb +139 -2
- data/lib/sentdm/models/contact_event.rb +15 -7
- data/lib/sentdm/models/contact_event_payload.rb +77 -16
- data/lib/sentdm/models/conversation_messages_list.rb +125 -4
- data/lib/sentdm/models/message_event_payload.rb +20 -1
- data/lib/sentdm/models/message_retrieve_activities_response.rb +20 -5
- data/lib/sentdm/models/message_retrieve_status_response.rb +133 -6
- data/lib/sentdm/models/message_send_params.rb +67 -3
- data/lib/sentdm/models/message_send_response.rb +13 -4
- data/lib/sentdm/models/template_body.rb +82 -1
- data/lib/sentdm/models/template_header.rb +91 -3
- data/lib/sentdm/models/template_variable.rb +15 -1
- data/lib/sentdm/models/webhook_list_events_response.rb +324 -9
- data/lib/sentdm/resources/messages.rb +33 -5
- data/lib/sentdm/version.rb +1 -1
- data/lib/sentdm.rb +1 -1
- data/rbi/sentdm/client.rbi +6 -0
- data/rbi/sentdm/models/channel_event_payload.rbi +253 -2
- data/rbi/sentdm/models/contact_event.rbi +28 -12
- data/rbi/sentdm/models/contact_event_payload.rbi +118 -28
- data/rbi/sentdm/models/conversation_messages_list.rbi +202 -7
- data/rbi/sentdm/models/message_event_payload.rbi +22 -0
- data/rbi/sentdm/models/message_retrieve_activities_response.rbi +23 -5
- data/rbi/sentdm/models/message_retrieve_status_response.rbi +214 -9
- data/rbi/sentdm/models/message_send_params.rbi +100 -2
- data/rbi/sentdm/models/message_send_response.rbi +15 -5
- data/rbi/sentdm/models/template_body.rbi +133 -0
- data/rbi/sentdm/models/template_header.rbi +143 -2
- data/rbi/sentdm/models/template_variable.rbi +10 -0
- data/rbi/sentdm/models/webhook_list_events_response.rbi +478 -12
- data/rbi/sentdm/resources/messages.rbi +58 -3
- data/sig/sentdm/models/channel_event_payload.rbs +57 -0
- data/sig/sentdm/models/contact_event_payload.rbs +24 -9
- data/sig/sentdm/models/conversation_messages_list.rbs +48 -3
- data/sig/sentdm/models/message_event_payload.rbs +10 -0
- data/sig/sentdm/models/message_retrieve_activities_response.rbs +5 -0
- data/sig/sentdm/models/message_retrieve_status_response.rbs +48 -3
- data/sig/sentdm/models/message_send_params.rbs +15 -0
- data/sig/sentdm/models/template_body.rbs +44 -0
- data/sig/sentdm/models/template_header.rbs +44 -0
- data/sig/sentdm/models/webhook_list_events_response.rbs +145 -0
- data/sig/sentdm/resources/messages.rbs +3 -0
- metadata +2 -2
|
@@ -17,6 +17,23 @@ module Sentdm
|
|
|
17
17
|
sig { returns(T.nilable(T::Array[String])) }
|
|
18
18
|
attr_accessor :channel
|
|
19
19
|
|
|
20
|
+
# Attachments for this send, as publicly fetchable https URLs. Used by the MMS
|
|
21
|
+
# channel and ignored by every other one.
|
|
22
|
+
#
|
|
23
|
+
# Supplying these replaces the media on the template's mms body rather than adding
|
|
24
|
+
# to it, so a template can hold a default creative while a caller still sends
|
|
25
|
+
# something recipient-specific.
|
|
26
|
+
#
|
|
27
|
+
# Their presence is also what makes a message eligible for MMS on an auto-detect
|
|
28
|
+
# send: a message with nothing attached is delivered as SMS, because an MMS with
|
|
29
|
+
# no media is a more expensive text message.
|
|
30
|
+
#
|
|
31
|
+
# The recipient's carrier fetches each URL after the send is accepted, so it must
|
|
32
|
+
# stay publicly reachable — a link that expires, or one behind auth, arrives as a
|
|
33
|
+
# failed message.
|
|
34
|
+
sig { returns(T.nilable(T::Array[String])) }
|
|
35
|
+
attr_accessor :media_urls
|
|
36
|
+
|
|
20
37
|
# Sandbox flag - when true, the operation is simulated without side effects Useful
|
|
21
38
|
# for testing integrations without actual execution
|
|
22
39
|
sig { returns(T.nilable(T::Boolean)) }
|
|
@@ -25,6 +42,25 @@ module Sentdm
|
|
|
25
42
|
sig { params(sandbox: T::Boolean).void }
|
|
26
43
|
attr_writer :sandbox
|
|
27
44
|
|
|
45
|
+
# Optional future send time as an ISO-8601 timestamp with an explicit UTC offset,
|
|
46
|
+
# e.g. 2026-10-01T09:00:00+02:00 or 2026-10-01T07:00:00Z. A value without an
|
|
47
|
+
# offset is rejected (400) rather than read in the server's zone. The offset only
|
|
48
|
+
# fixes the instant: it is stored and echoed in UTC as scheduled_at. Omit to send
|
|
49
|
+
# now. Must be at least one minute ahead and at most 30 days ahead. Accepted
|
|
50
|
+
# messages report SCHEDULED and are released for delivery at this time. Quiet
|
|
51
|
+
# hours, balance and template approval are evaluated at release, not at
|
|
52
|
+
# acceptance: a message whose time falls inside a recipient's protected
|
|
53
|
+
# quiet-hours window is moved to the next allowed time and a second
|
|
54
|
+
# message.scheduled webhook reports the new scheduled_at.
|
|
55
|
+
sig { returns(T.nilable(Time)) }
|
|
56
|
+
attr_accessor :scheduled_at
|
|
57
|
+
|
|
58
|
+
# Subject line for this send, overriding the template's. MMS only; ignored on
|
|
59
|
+
# every other channel. Most handsets render it above the body, some ignore it
|
|
60
|
+
# entirely.
|
|
61
|
+
sig { returns(T.nilable(String)) }
|
|
62
|
+
attr_accessor :subject
|
|
63
|
+
|
|
28
64
|
# SDK-style template reference: resolve by ID or by name, with optional
|
|
29
65
|
# parameters.
|
|
30
66
|
sig { returns(T.nilable(Sentdm::MessageSendParams::Template)) }
|
|
@@ -63,7 +99,10 @@ module Sentdm
|
|
|
63
99
|
sig do
|
|
64
100
|
params(
|
|
65
101
|
channel: T.nilable(T::Array[String]),
|
|
102
|
+
media_urls: T.nilable(T::Array[String]),
|
|
66
103
|
sandbox: T::Boolean,
|
|
104
|
+
scheduled_at: T.nilable(Time),
|
|
105
|
+
subject: T.nilable(String),
|
|
67
106
|
template: T.nilable(Sentdm::MessageSendParams::Template::OrHash),
|
|
68
107
|
text: T.nilable(String),
|
|
69
108
|
to: T::Array[String],
|
|
@@ -77,9 +116,39 @@ module Sentdm
|
|
|
77
116
|
# separate message per recipient. "sent" = auto-detect. Defaults to ["sent"]
|
|
78
117
|
# (auto-detect) if omitted.
|
|
79
118
|
channel: nil,
|
|
119
|
+
# Attachments for this send, as publicly fetchable https URLs. Used by the MMS
|
|
120
|
+
# channel and ignored by every other one.
|
|
121
|
+
#
|
|
122
|
+
# Supplying these replaces the media on the template's mms body rather than adding
|
|
123
|
+
# to it, so a template can hold a default creative while a caller still sends
|
|
124
|
+
# something recipient-specific.
|
|
125
|
+
#
|
|
126
|
+
# Their presence is also what makes a message eligible for MMS on an auto-detect
|
|
127
|
+
# send: a message with nothing attached is delivered as SMS, because an MMS with
|
|
128
|
+
# no media is a more expensive text message.
|
|
129
|
+
#
|
|
130
|
+
# The recipient's carrier fetches each URL after the send is accepted, so it must
|
|
131
|
+
# stay publicly reachable — a link that expires, or one behind auth, arrives as a
|
|
132
|
+
# failed message.
|
|
133
|
+
media_urls: nil,
|
|
80
134
|
# Sandbox flag - when true, the operation is simulated without side effects Useful
|
|
81
135
|
# for testing integrations without actual execution
|
|
82
136
|
sandbox: nil,
|
|
137
|
+
# Optional future send time as an ISO-8601 timestamp with an explicit UTC offset,
|
|
138
|
+
# e.g. 2026-10-01T09:00:00+02:00 or 2026-10-01T07:00:00Z. A value without an
|
|
139
|
+
# offset is rejected (400) rather than read in the server's zone. The offset only
|
|
140
|
+
# fixes the instant: it is stored and echoed in UTC as scheduled_at. Omit to send
|
|
141
|
+
# now. Must be at least one minute ahead and at most 30 days ahead. Accepted
|
|
142
|
+
# messages report SCHEDULED and are released for delivery at this time. Quiet
|
|
143
|
+
# hours, balance and template approval are evaluated at release, not at
|
|
144
|
+
# acceptance: a message whose time falls inside a recipient's protected
|
|
145
|
+
# quiet-hours window is moved to the next allowed time and a second
|
|
146
|
+
# message.scheduled webhook reports the new scheduled_at.
|
|
147
|
+
scheduled_at: nil,
|
|
148
|
+
# Subject line for this send, overriding the template's. MMS only; ignored on
|
|
149
|
+
# every other channel. Most handsets render it above the body, some ignore it
|
|
150
|
+
# entirely.
|
|
151
|
+
subject: nil,
|
|
83
152
|
# SDK-style template reference: resolve by ID or by name, with optional
|
|
84
153
|
# parameters.
|
|
85
154
|
template: nil,
|
|
@@ -97,7 +166,10 @@ module Sentdm
|
|
|
97
166
|
override.returns(
|
|
98
167
|
{
|
|
99
168
|
channel: T.nilable(T::Array[String]),
|
|
169
|
+
media_urls: T.nilable(T::Array[String]),
|
|
100
170
|
sandbox: T::Boolean,
|
|
171
|
+
scheduled_at: T.nilable(Time),
|
|
172
|
+
subject: T.nilable(String),
|
|
101
173
|
template: T.nilable(Sentdm::MessageSendParams::Template),
|
|
102
174
|
text: T.nilable(String),
|
|
103
175
|
to: T::Array[String],
|
|
@@ -127,7 +199,20 @@ module Sentdm
|
|
|
127
199
|
sig { returns(T.nilable(String)) }
|
|
128
200
|
attr_accessor :name
|
|
129
201
|
|
|
130
|
-
# Template variable parameters for personalization
|
|
202
|
+
# Template variable parameters for personalization, keyed by variable name.
|
|
203
|
+
#
|
|
204
|
+
# Every variable the template declares is required; GET /v3/templates/{id} lists
|
|
205
|
+
# them. Supplying a key the template does not declare is ignored.
|
|
206
|
+
#
|
|
207
|
+
# Media headers. A template whose header is an image (designed in WhatsApp Manager
|
|
208
|
+
# and imported into Sent) declares a reserved header_image key. Its value is a
|
|
209
|
+
# publicly reachable https URL that Meta fetches at send time — Sent does not host
|
|
210
|
+
# the asset, and the sample approved with the template is not reused. The key is
|
|
211
|
+
# derived from the header's media type, so header_video and header_document follow
|
|
212
|
+
# the same shape when those formats ship.
|
|
213
|
+
#
|
|
214
|
+
# "parameters": { "header_image": "https://cdn.example.com/banner.jpg", "name":
|
|
215
|
+
# "John Doe" }
|
|
131
216
|
sig { returns(T.nilable(T::Hash[Symbol, String])) }
|
|
132
217
|
attr_accessor :parameters
|
|
133
218
|
|
|
@@ -145,7 +230,20 @@ module Sentdm
|
|
|
145
230
|
id: nil,
|
|
146
231
|
# Template name (mutually exclusive with id)
|
|
147
232
|
name: nil,
|
|
148
|
-
# Template variable parameters for personalization
|
|
233
|
+
# Template variable parameters for personalization, keyed by variable name.
|
|
234
|
+
#
|
|
235
|
+
# Every variable the template declares is required; GET /v3/templates/{id} lists
|
|
236
|
+
# them. Supplying a key the template does not declare is ignored.
|
|
237
|
+
#
|
|
238
|
+
# Media headers. A template whose header is an image (designed in WhatsApp Manager
|
|
239
|
+
# and imported into Sent) declares a reserved header_image key. Its value is a
|
|
240
|
+
# publicly reachable https URL that Meta fetches at send time — Sent does not host
|
|
241
|
+
# the asset, and the sample approved with the template is not reused. The key is
|
|
242
|
+
# derived from the header's media type, so header_video and header_document follow
|
|
243
|
+
# the same shape when those formats ship.
|
|
244
|
+
#
|
|
245
|
+
# "parameters": { "header_image": "https://cdn.example.com/banner.jpg", "name":
|
|
246
|
+
# "John Doe" }
|
|
149
247
|
parameters: nil
|
|
150
248
|
)
|
|
151
249
|
end
|
|
@@ -17,7 +17,9 @@ module Sentdm
|
|
|
17
17
|
# its result; this is what a caller sees, and the mapping between them is a
|
|
18
18
|
# decision the endpoint makes.
|
|
19
19
|
#
|
|
20
|
-
# The
|
|
20
|
+
# The shape of an immediate send: it never has a scheduled_at key. A send that
|
|
21
|
+
# carried scheduled_at is a ScheduledSendMessageResponse, and the endpoint decides
|
|
22
|
+
# which of the two to answer with. From always returns this type.
|
|
21
23
|
sig { returns(T.nilable(Sentdm::Models::MessageSendResponse::Data)) }
|
|
22
24
|
attr_reader :data
|
|
23
25
|
|
|
@@ -68,7 +70,9 @@ module Sentdm
|
|
|
68
70
|
# its result; this is what a caller sees, and the mapping between them is a
|
|
69
71
|
# decision the endpoint makes.
|
|
70
72
|
#
|
|
71
|
-
# The
|
|
73
|
+
# The shape of an immediate send: it never has a scheduled_at key. A send that
|
|
74
|
+
# carried scheduled_at is a ScheduledSendMessageResponse, and the endpoint decides
|
|
75
|
+
# which of the two to answer with. From always returns this type.
|
|
72
76
|
data: nil,
|
|
73
77
|
# Error information
|
|
74
78
|
error: nil,
|
|
@@ -120,7 +124,9 @@ module Sentdm
|
|
|
120
124
|
end
|
|
121
125
|
attr_writer :recipients
|
|
122
126
|
|
|
123
|
-
#
|
|
127
|
+
# QUEUED: the batch is accepted. A request that carried scheduled_at is QUEUED
|
|
128
|
+
# here too; each message moves to SCHEDULED once it is held, as GET
|
|
129
|
+
# /v3/messages/{id} and the message.scheduled webhook report.
|
|
124
130
|
sig { returns(T.nilable(String)) }
|
|
125
131
|
attr_reader :status
|
|
126
132
|
|
|
@@ -148,7 +154,9 @@ module Sentdm
|
|
|
148
154
|
# its result; this is what a caller sees, and the mapping between them is a
|
|
149
155
|
# decision the endpoint makes.
|
|
150
156
|
#
|
|
151
|
-
# The
|
|
157
|
+
# The shape of an immediate send: it never has a scheduled_at key. A send that
|
|
158
|
+
# carried scheduled_at is a ScheduledSendMessageResponse, and the endpoint decides
|
|
159
|
+
# which of the two to answer with. From always returns this type.
|
|
152
160
|
sig do
|
|
153
161
|
params(
|
|
154
162
|
recipients:
|
|
@@ -162,7 +170,9 @@ module Sentdm
|
|
|
162
170
|
end
|
|
163
171
|
def self.new(
|
|
164
172
|
recipients: nil,
|
|
165
|
-
#
|
|
173
|
+
# QUEUED: the batch is accepted. A request that carried scheduled_at is QUEUED
|
|
174
|
+
# here too; each message moves to SCHEDULED once it is held, as GET
|
|
175
|
+
# /v3/messages/{id} and the message.scheduled webhook report.
|
|
166
176
|
status: nil,
|
|
167
177
|
template_id: nil,
|
|
168
178
|
template_name: nil
|
|
@@ -6,6 +6,19 @@ module Sentdm
|
|
|
6
6
|
OrHash =
|
|
7
7
|
T.type_alias { T.any(Sentdm::TemplateBody, Sentdm::Internal::AnyHash) }
|
|
8
8
|
|
|
9
|
+
# MMS-specific content — subject, text and attachments.
|
|
10
|
+
#
|
|
11
|
+
# Like Rcs, an override that cannot stand on its own: a template still needs a
|
|
12
|
+
# MultiChannel body or the Sms + Whatsapp pair to be deliverable at all. Unlike
|
|
13
|
+
# Rcs, it has no fallback at send time — MMS with no media is a more expensive
|
|
14
|
+
# SMS, so a template without this slot is deliberately not MMS-capable and never
|
|
15
|
+
# produces an MMS route candidate.
|
|
16
|
+
sig { returns(T.nilable(Sentdm::TemplateBody::Mms)) }
|
|
17
|
+
attr_reader :mms
|
|
18
|
+
|
|
19
|
+
sig { params(mms: T.nilable(Sentdm::TemplateBody::Mms::OrHash)).void }
|
|
20
|
+
attr_writer :mms
|
|
21
|
+
|
|
9
22
|
# The shared body, used for every channel. One half of the choice described above.
|
|
10
23
|
sig { returns(T.nilable(Sentdm::TemplateBodyContent)) }
|
|
11
24
|
attr_reader :multi_channel
|
|
@@ -54,6 +67,7 @@ module Sentdm
|
|
|
54
67
|
# the copy, but cannot stand alone.
|
|
55
68
|
sig do
|
|
56
69
|
params(
|
|
70
|
+
mms: T.nilable(Sentdm::TemplateBody::Mms::OrHash),
|
|
57
71
|
multi_channel: T.nilable(Sentdm::TemplateBodyContent::OrHash),
|
|
58
72
|
rcs: T.nilable(Sentdm::TemplateBodyContent::OrHash),
|
|
59
73
|
sms: T.nilable(Sentdm::TemplateBodyContent::OrHash),
|
|
@@ -61,6 +75,14 @@ module Sentdm
|
|
|
61
75
|
).returns(T.attached_class)
|
|
62
76
|
end
|
|
63
77
|
def self.new(
|
|
78
|
+
# MMS-specific content — subject, text and attachments.
|
|
79
|
+
#
|
|
80
|
+
# Like Rcs, an override that cannot stand on its own: a template still needs a
|
|
81
|
+
# MultiChannel body or the Sms + Whatsapp pair to be deliverable at all. Unlike
|
|
82
|
+
# Rcs, it has no fallback at send time — MMS with no media is a more expensive
|
|
83
|
+
# SMS, so a template without this slot is deliberately not MMS-capable and never
|
|
84
|
+
# produces an MMS route candidate.
|
|
85
|
+
mms: nil,
|
|
64
86
|
# The shared body, used for every channel. One half of the choice described above.
|
|
65
87
|
multi_channel: nil,
|
|
66
88
|
# RCS-specific copy that overrides the chosen strategy for RCS only. The one true
|
|
@@ -77,6 +99,7 @@ module Sentdm
|
|
|
77
99
|
sig do
|
|
78
100
|
override.returns(
|
|
79
101
|
{
|
|
102
|
+
mms: T.nilable(Sentdm::TemplateBody::Mms),
|
|
80
103
|
multi_channel: T.nilable(Sentdm::TemplateBodyContent),
|
|
81
104
|
rcs: T.nilable(Sentdm::TemplateBodyContent),
|
|
82
105
|
sms: T.nilable(Sentdm::TemplateBodyContent),
|
|
@@ -86,6 +109,116 @@ module Sentdm
|
|
|
86
109
|
end
|
|
87
110
|
def to_hash
|
|
88
111
|
end
|
|
112
|
+
|
|
113
|
+
class Mms < Sentdm::Models::TemplateBodyContent
|
|
114
|
+
OrHash =
|
|
115
|
+
T.type_alias do
|
|
116
|
+
T.any(Sentdm::TemplateBody::Mms, Sentdm::Internal::AnyHash)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Attachments carried by every send on this template, in order. A per-send
|
|
120
|
+
# media_urls on the request replaces this list rather than adding to it, so a
|
|
121
|
+
# template can hold a default creative and a caller can still send something
|
|
122
|
+
# recipient-specific.
|
|
123
|
+
sig { returns(T.nilable(T::Array[Sentdm::TemplateBody::Mms::Media])) }
|
|
124
|
+
attr_accessor :media
|
|
125
|
+
|
|
126
|
+
# MMS subject line. Optional — most handsets render it above the body, some ignore
|
|
127
|
+
# it entirely. Deliberately its own field rather than riding TemplateHeader: the
|
|
128
|
+
# header is authored once and shared across every channel, and carries Meta's
|
|
129
|
+
# 60-character cap plus its no-newline, no-emoji text rules, none of which
|
|
130
|
+
# describe an MMS subject.
|
|
131
|
+
sig { returns(T.nilable(String)) }
|
|
132
|
+
attr_accessor :subject
|
|
133
|
+
|
|
134
|
+
# MMS-specific content — subject, text and attachments.
|
|
135
|
+
#
|
|
136
|
+
# Like Rcs, an override that cannot stand on its own: a template still needs a
|
|
137
|
+
# MultiChannel body or the Sms + Whatsapp pair to be deliverable at all. Unlike
|
|
138
|
+
# Rcs, it has no fallback at send time — MMS with no media is a more expensive
|
|
139
|
+
# SMS, so a template without this slot is deliberately not MMS-capable and never
|
|
140
|
+
# produces an MMS route candidate.
|
|
141
|
+
sig do
|
|
142
|
+
params(
|
|
143
|
+
media:
|
|
144
|
+
T.nilable(T::Array[Sentdm::TemplateBody::Mms::Media::OrHash]),
|
|
145
|
+
subject: T.nilable(String)
|
|
146
|
+
).returns(T.attached_class)
|
|
147
|
+
end
|
|
148
|
+
def self.new(
|
|
149
|
+
# Attachments carried by every send on this template, in order. A per-send
|
|
150
|
+
# media_urls on the request replaces this list rather than adding to it, so a
|
|
151
|
+
# template can hold a default creative and a caller can still send something
|
|
152
|
+
# recipient-specific.
|
|
153
|
+
media: nil,
|
|
154
|
+
# MMS subject line. Optional — most handsets render it above the body, some ignore
|
|
155
|
+
# it entirely. Deliberately its own field rather than riding TemplateHeader: the
|
|
156
|
+
# header is authored once and shared across every channel, and carries Meta's
|
|
157
|
+
# 60-character cap plus its no-newline, no-emoji text rules, none of which
|
|
158
|
+
# describe an MMS subject.
|
|
159
|
+
subject: nil
|
|
160
|
+
)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
sig do
|
|
164
|
+
override.returns(
|
|
165
|
+
{
|
|
166
|
+
media: T.nilable(T::Array[Sentdm::TemplateBody::Mms::Media]),
|
|
167
|
+
subject: T.nilable(String)
|
|
168
|
+
}
|
|
169
|
+
)
|
|
170
|
+
end
|
|
171
|
+
def to_hash
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
class Media < Sentdm::Internal::Type::BaseModel
|
|
175
|
+
OrHash =
|
|
176
|
+
T.type_alias do
|
|
177
|
+
T.any(Sentdm::TemplateBody::Mms::Media, Sentdm::Internal::AnyHash)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# One of MmsMediaTypes. Advisory: the carrier reads the Content-Type off the
|
|
181
|
+
# fetched object, not this field. It exists so an authoring UI can render the
|
|
182
|
+
# right preview and so a reviewer can see what was intended.
|
|
183
|
+
sig { returns(T.nilable(String)) }
|
|
184
|
+
attr_accessor :media_type
|
|
185
|
+
|
|
186
|
+
# Publicly fetchable https URL. The carrier's MMSC fetches this at send time, so
|
|
187
|
+
# it has to stay reachable and unauthenticated for the life of the send —
|
|
188
|
+
# including retries and a DLQ replay — which is why a presigned URL is not a valid
|
|
189
|
+
# value here.
|
|
190
|
+
sig { returns(T.nilable(String)) }
|
|
191
|
+
attr_reader :url
|
|
192
|
+
|
|
193
|
+
sig { params(url: String).void }
|
|
194
|
+
attr_writer :url
|
|
195
|
+
|
|
196
|
+
# One attachment on an MMS template body.
|
|
197
|
+
sig do
|
|
198
|
+
params(media_type: T.nilable(String), url: String).returns(
|
|
199
|
+
T.attached_class
|
|
200
|
+
)
|
|
201
|
+
end
|
|
202
|
+
def self.new(
|
|
203
|
+
# One of MmsMediaTypes. Advisory: the carrier reads the Content-Type off the
|
|
204
|
+
# fetched object, not this field. It exists so an authoring UI can render the
|
|
205
|
+
# right preview and so a reviewer can see what was intended.
|
|
206
|
+
media_type: nil,
|
|
207
|
+
# Publicly fetchable https URL. The carrier's MMSC fetches this at send time, so
|
|
208
|
+
# it has to stay reachable and unauthenticated for the life of the send —
|
|
209
|
+
# including retries and a DLQ replay — which is why a presigned URL is not a valid
|
|
210
|
+
# value here.
|
|
211
|
+
url: nil
|
|
212
|
+
)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
sig do
|
|
216
|
+
override.returns({ media_type: T.nilable(String), url: String })
|
|
217
|
+
end
|
|
218
|
+
def to_hash
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
89
222
|
end
|
|
90
223
|
end
|
|
91
224
|
end
|
|
@@ -13,7 +13,59 @@ module Sentdm
|
|
|
13
13
|
sig { returns(String) }
|
|
14
14
|
attr_accessor :template
|
|
15
15
|
|
|
16
|
-
# The
|
|
16
|
+
# Request-only. The s.dm URL of the asset Meta's reviewers see —
|
|
17
|
+
# https://s.dm/s/{ID}, eight uppercase characters, uploaded to s.dm out of band.
|
|
18
|
+
# NormalizeRichHeader folds it into the synthesized media variable's Props.Sample
|
|
19
|
+
# and clears it, so it never persists and a stored definition is indistinguishable
|
|
20
|
+
# from an imported one.
|
|
21
|
+
#
|
|
22
|
+
# Stricter than the send path on purpose:
|
|
23
|
+
# TemplateUtils.ValidateMediaVariableValues accepts any absolute https URL for the
|
|
24
|
+
# per-send asset, because that one is the customer's and may live behind a signed
|
|
25
|
+
# CDN link. This one is the review sample, has to outlive every resubmission, and
|
|
26
|
+
# so must be ours. Do not "fix" one to match the other.
|
|
27
|
+
sig { returns(T.nilable(String)) }
|
|
28
|
+
attr_accessor :example_url
|
|
29
|
+
|
|
30
|
+
# The map pin a location header drops. Meta wants none of this at creation — the
|
|
31
|
+
# component is just {"type":"header","format":"location"} — so these values exist
|
|
32
|
+
# for Sent: a preview, and the default a StaticResource header falls back to at
|
|
33
|
+
# send.
|
|
34
|
+
sig { returns(T.nilable(Sentdm::TemplateHeader::Location)) }
|
|
35
|
+
attr_reader :location
|
|
36
|
+
|
|
37
|
+
sig do
|
|
38
|
+
params(
|
|
39
|
+
location: T.nilable(Sentdm::TemplateHeader::Location::OrHash)
|
|
40
|
+
).void
|
|
41
|
+
end
|
|
42
|
+
attr_writer :location
|
|
43
|
+
|
|
44
|
+
# Whether the asset registered at creation is reused when a caller omits the
|
|
45
|
+
# header's variable at send time. Default false — the caller must supply it per
|
|
46
|
+
# message, which is the behaviour every existing template has. Written only when
|
|
47
|
+
# true, so a default-valued header serializes byte-identically to one imported
|
|
48
|
+
# from Meta.
|
|
49
|
+
#
|
|
50
|
+
# Stored and validated but not yet honoured at send: that lands with the Resumable
|
|
51
|
+
# Upload work, alongside the code that lets such a template be approved in the
|
|
52
|
+
# first place.
|
|
53
|
+
sig { returns(T.nilable(T::Boolean)) }
|
|
54
|
+
attr_reader :static_resource
|
|
55
|
+
|
|
56
|
+
sig { params(static_resource: T::Boolean).void }
|
|
57
|
+
attr_writer :static_resource
|
|
58
|
+
|
|
59
|
+
# The kind of header. One of:
|
|
60
|
+
#
|
|
61
|
+
# text — up to 60 characters, at most one variable. image — png, jpg or jpeg.
|
|
62
|
+
# Needs ExampleUrl. video — mp4. Needs ExampleUrl. gif — mp4, max 3.5MB. WhatsApp
|
|
63
|
+
# renders larger files as an ordinary video. Needs ExampleUrl. document — pdf or
|
|
64
|
+
# docx; only the first page is shown as a thumbnail, so pdf is the practical
|
|
65
|
+
# choice. Needs ExampleUrl. location — a map pin, supplied through Location.
|
|
66
|
+
#
|
|
67
|
+
# Kept lowercase because MetaToTemplateConverter writes Meta's format through
|
|
68
|
+
# ToLowerInvariant() into this field on import, and the two are compared directly.
|
|
17
69
|
sig { returns(T.nilable(String)) }
|
|
18
70
|
attr_accessor :type
|
|
19
71
|
|
|
@@ -25,6 +77,9 @@ module Sentdm
|
|
|
25
77
|
sig do
|
|
26
78
|
params(
|
|
27
79
|
template: String,
|
|
80
|
+
example_url: T.nilable(String),
|
|
81
|
+
location: T.nilable(Sentdm::TemplateHeader::Location::OrHash),
|
|
82
|
+
static_resource: T::Boolean,
|
|
28
83
|
type: T.nilable(String),
|
|
29
84
|
variables: T.nilable(T::Array[Sentdm::TemplateVariable::OrHash])
|
|
30
85
|
).returns(T.attached_class)
|
|
@@ -33,7 +88,43 @@ module Sentdm
|
|
|
33
88
|
# The header template text with optional variable placeholders (e.g., "Welcome to
|
|
34
89
|
# {{0:variable}}")
|
|
35
90
|
template:,
|
|
36
|
-
# The
|
|
91
|
+
# Request-only. The s.dm URL of the asset Meta's reviewers see —
|
|
92
|
+
# https://s.dm/s/{ID}, eight uppercase characters, uploaded to s.dm out of band.
|
|
93
|
+
# NormalizeRichHeader folds it into the synthesized media variable's Props.Sample
|
|
94
|
+
# and clears it, so it never persists and a stored definition is indistinguishable
|
|
95
|
+
# from an imported one.
|
|
96
|
+
#
|
|
97
|
+
# Stricter than the send path on purpose:
|
|
98
|
+
# TemplateUtils.ValidateMediaVariableValues accepts any absolute https URL for the
|
|
99
|
+
# per-send asset, because that one is the customer's and may live behind a signed
|
|
100
|
+
# CDN link. This one is the review sample, has to outlive every resubmission, and
|
|
101
|
+
# so must be ours. Do not "fix" one to match the other.
|
|
102
|
+
example_url: nil,
|
|
103
|
+
# The map pin a location header drops. Meta wants none of this at creation — the
|
|
104
|
+
# component is just {"type":"header","format":"location"} — so these values exist
|
|
105
|
+
# for Sent: a preview, and the default a StaticResource header falls back to at
|
|
106
|
+
# send.
|
|
107
|
+
location: nil,
|
|
108
|
+
# Whether the asset registered at creation is reused when a caller omits the
|
|
109
|
+
# header's variable at send time. Default false — the caller must supply it per
|
|
110
|
+
# message, which is the behaviour every existing template has. Written only when
|
|
111
|
+
# true, so a default-valued header serializes byte-identically to one imported
|
|
112
|
+
# from Meta.
|
|
113
|
+
#
|
|
114
|
+
# Stored and validated but not yet honoured at send: that lands with the Resumable
|
|
115
|
+
# Upload work, alongside the code that lets such a template be approved in the
|
|
116
|
+
# first place.
|
|
117
|
+
static_resource: nil,
|
|
118
|
+
# The kind of header. One of:
|
|
119
|
+
#
|
|
120
|
+
# text — up to 60 characters, at most one variable. image — png, jpg or jpeg.
|
|
121
|
+
# Needs ExampleUrl. video — mp4. Needs ExampleUrl. gif — mp4, max 3.5MB. WhatsApp
|
|
122
|
+
# renders larger files as an ordinary video. Needs ExampleUrl. document — pdf or
|
|
123
|
+
# docx; only the first page is shown as a thumbnail, so pdf is the practical
|
|
124
|
+
# choice. Needs ExampleUrl. location — a map pin, supplied through Location.
|
|
125
|
+
#
|
|
126
|
+
# Kept lowercase because MetaToTemplateConverter writes Meta's format through
|
|
127
|
+
# ToLowerInvariant() into this field on import, and the two are compared directly.
|
|
37
128
|
type: nil,
|
|
38
129
|
# List of variables used in the header template
|
|
39
130
|
variables: nil
|
|
@@ -44,6 +135,9 @@ module Sentdm
|
|
|
44
135
|
override.returns(
|
|
45
136
|
{
|
|
46
137
|
template: String,
|
|
138
|
+
example_url: T.nilable(String),
|
|
139
|
+
location: T.nilable(Sentdm::TemplateHeader::Location),
|
|
140
|
+
static_resource: T::Boolean,
|
|
47
141
|
type: T.nilable(String),
|
|
48
142
|
variables: T.nilable(T::Array[Sentdm::TemplateVariable])
|
|
49
143
|
}
|
|
@@ -51,6 +145,53 @@ module Sentdm
|
|
|
51
145
|
end
|
|
52
146
|
def to_hash
|
|
53
147
|
end
|
|
148
|
+
|
|
149
|
+
class Location < Sentdm::Internal::Type::BaseModel
|
|
150
|
+
OrHash =
|
|
151
|
+
T.type_alias do
|
|
152
|
+
T.any(Sentdm::TemplateHeader::Location, Sentdm::Internal::AnyHash)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
sig { returns(String) }
|
|
156
|
+
attr_accessor :address
|
|
157
|
+
|
|
158
|
+
sig { returns(String) }
|
|
159
|
+
attr_accessor :latitude
|
|
160
|
+
|
|
161
|
+
sig { returns(String) }
|
|
162
|
+
attr_accessor :longitude
|
|
163
|
+
|
|
164
|
+
sig { returns(String) }
|
|
165
|
+
attr_accessor :name
|
|
166
|
+
|
|
167
|
+
# The map pin a location header drops. Meta wants none of this at creation — the
|
|
168
|
+
# component is just {"type":"header","format":"location"} — so these values exist
|
|
169
|
+
# for Sent: a preview, and the default a StaticResource header falls back to at
|
|
170
|
+
# send.
|
|
171
|
+
sig do
|
|
172
|
+
params(
|
|
173
|
+
address: String,
|
|
174
|
+
latitude: String,
|
|
175
|
+
longitude: String,
|
|
176
|
+
name: String
|
|
177
|
+
).returns(T.attached_class)
|
|
178
|
+
end
|
|
179
|
+
def self.new(address:, latitude:, longitude:, name:)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
sig do
|
|
183
|
+
override.returns(
|
|
184
|
+
{
|
|
185
|
+
address: String,
|
|
186
|
+
latitude: String,
|
|
187
|
+
longitude: String,
|
|
188
|
+
name: String
|
|
189
|
+
}
|
|
190
|
+
)
|
|
191
|
+
end
|
|
192
|
+
def to_hash
|
|
193
|
+
end
|
|
194
|
+
end
|
|
54
195
|
end
|
|
55
196
|
end
|
|
56
197
|
end
|
|
@@ -86,6 +86,11 @@ module Sentdm
|
|
|
86
86
|
sig { returns(String) }
|
|
87
87
|
attr_accessor :media_type
|
|
88
88
|
|
|
89
|
+
# Example value substituted into the template when previewing it and when
|
|
90
|
+
# submitting it to Meta for review. Free text by nature, so the converter accepts
|
|
91
|
+
# a JSON number or boolean here and normalizes it — see
|
|
92
|
+
# JsonScalarToStringConverter for why — and guarantees it is always serialized
|
|
93
|
+
# back out as a JSON string.
|
|
89
94
|
sig { returns(String) }
|
|
90
95
|
attr_accessor :sample
|
|
91
96
|
|
|
@@ -117,6 +122,11 @@ module Sentdm
|
|
|
117
122
|
end
|
|
118
123
|
def self.new(
|
|
119
124
|
media_type:,
|
|
125
|
+
# Example value substituted into the template when previewing it and when
|
|
126
|
+
# submitting it to Meta for review. Free text by nature, so the converter accepts
|
|
127
|
+
# a JSON number or boolean here and normalizes it — see
|
|
128
|
+
# JsonScalarToStringConverter for why — and guarantees it is always serialized
|
|
129
|
+
# back out as a JSON string.
|
|
120
130
|
sample:,
|
|
121
131
|
url:,
|
|
122
132
|
variable_type:,
|