sentdm 0.32.0 → 0.34.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/client.rb +6 -0
- data/lib/sentdm/models/channel_event_payload.rb +154 -7
- 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 +214 -6
- data/lib/sentdm/models/inbound_message_event_payload.rb +70 -3
- data/lib/sentdm/models/me_retrieve_response.rb +21 -1
- data/lib/sentdm/models/message_event_payload.rb +42 -1
- data/lib/sentdm/models/message_retrieve_activities_response.rb +42 -5
- data/lib/sentdm/models/message_retrieve_status_response.rb +222 -8
- 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_create_params.rb +11 -1
- data/lib/sentdm/models/template_header.rb +91 -3
- data/lib/sentdm/models/template_variable.rb +15 -1
- data/lib/sentdm/models/webhook_create_params.rb +31 -1
- data/lib/sentdm/models/webhook_list_events_response.rb +497 -9
- data/lib/sentdm/models/webhook_update_params.rb +31 -1
- data/lib/sentdm/resources/me.rb +5 -0
- data/lib/sentdm/resources/messages.rb +33 -5
- data/lib/sentdm/resources/templates.rb +3 -1
- data/lib/sentdm/resources/webhooks.rb +9 -3
- 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 +273 -10
- 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 +308 -10
- data/rbi/sentdm/models/inbound_message_event_payload.rbi +110 -2
- data/rbi/sentdm/models/me_retrieve_response.rbi +35 -0
- data/rbi/sentdm/models/message_event_payload.rbi +50 -0
- data/rbi/sentdm/models/message_retrieve_activities_response.rbi +49 -5
- data/rbi/sentdm/models/message_retrieve_status_response.rbi +320 -12
- 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_create_params.rbi +15 -0
- data/rbi/sentdm/models/template_header.rbi +143 -2
- data/rbi/sentdm/models/template_variable.rbi +10 -0
- data/rbi/sentdm/models/webhook_create_params.rbi +61 -0
- data/rbi/sentdm/models/webhook_list_events_response.rbi +747 -12
- data/rbi/sentdm/models/webhook_update_params.rbi +61 -0
- data/rbi/sentdm/resources/me.rbi +5 -0
- data/rbi/sentdm/resources/messages.rbi +58 -3
- data/rbi/sentdm/resources/templates.rbi +6 -0
- data/rbi/sentdm/resources/webhooks.rbi +15 -1
- data/sig/sentdm/models/channel_event_payload.rbs +62 -0
- data/sig/sentdm/models/contact_event_payload.rbs +24 -9
- data/sig/sentdm/models/conversation_messages_list.rbs +99 -6
- data/sig/sentdm/models/inbound_message_event_payload.rbs +37 -0
- data/sig/sentdm/models/me_retrieve_response.rbs +7 -0
- data/sig/sentdm/models/message_event_payload.rbs +20 -0
- data/sig/sentdm/models/message_retrieve_activities_response.rbs +15 -0
- data/sig/sentdm/models/message_retrieve_status_response.rbs +99 -6
- data/sig/sentdm/models/message_send_params.rbs +15 -0
- data/sig/sentdm/models/template_body.rbs +44 -0
- data/sig/sentdm/models/template_create_params.rbs +7 -0
- data/sig/sentdm/models/template_header.rbs +44 -0
- data/sig/sentdm/models/webhook_create_params.rbs +29 -0
- data/sig/sentdm/models/webhook_list_events_response.rbs +252 -0
- data/sig/sentdm/models/webhook_update_params.rbs +29 -0
- data/sig/sentdm/resources/messages.rbs +3 -0
- data/sig/sentdm/resources/templates.rbs +1 -0
- data/sig/sentdm/resources/webhooks.rbs +2 -0
- metadata +2 -2
|
@@ -11,7 +11,12 @@ module Sentdm
|
|
|
11
11
|
)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
# Message response for v3 API — same shape as v2 with snake_case JSON conventions
|
|
14
|
+
# Message response for v3 API — same shape as v2 with snake_case JSON conventions.
|
|
15
|
+
#
|
|
16
|
+
# The shape of a message that was sent immediately: it never has a scheduled_at
|
|
17
|
+
# key. A message that is or was held for a later instant is a
|
|
18
|
+
# ScheduledMessageResponse, and the endpoint decides which of the two to answer
|
|
19
|
+
# with. From always returns this type.
|
|
15
20
|
sig do
|
|
16
21
|
returns(T.nilable(Sentdm::Models::MessageRetrieveStatusResponse::Data))
|
|
17
22
|
end
|
|
@@ -61,7 +66,12 @@ module Sentdm
|
|
|
61
66
|
).returns(T.attached_class)
|
|
62
67
|
end
|
|
63
68
|
def self.new(
|
|
64
|
-
# Message response for v3 API — same shape as v2 with snake_case JSON conventions
|
|
69
|
+
# Message response for v3 API — same shape as v2 with snake_case JSON conventions.
|
|
70
|
+
#
|
|
71
|
+
# The shape of a message that was sent immediately: it never has a scheduled_at
|
|
72
|
+
# key. A message that is or was held for a later instant is a
|
|
73
|
+
# ScheduledMessageResponse, and the endpoint decides which of the two to answer
|
|
74
|
+
# with. From always returns this type.
|
|
65
75
|
data: nil,
|
|
66
76
|
# Error information
|
|
67
77
|
error: nil,
|
|
@@ -146,7 +156,14 @@ module Sentdm
|
|
|
146
156
|
attr_accessor :events
|
|
147
157
|
|
|
148
158
|
# Structured message body format for database storage. Preserves channel-specific
|
|
149
|
-
# components (header, body, footer, buttons).
|
|
159
|
+
# components (header, header media, body, footer, buttons, MMS subject and media).
|
|
160
|
+
#
|
|
161
|
+
# Persisted as the messageBody jsonb column on Messages. Every write path goes
|
|
162
|
+
# through MessageUtils.MessageBodyJsonOptions, which writes nulls, so the envelope
|
|
163
|
+
# shape is stable regardless of channel or status. Anything that rebuilds this
|
|
164
|
+
# object field by field — the four IMessageBodyStrategy implementations and
|
|
165
|
+
# MessageUtils.BuildSegmentBody — has to carry every member, or that member is
|
|
166
|
+
# silently dropped on whichever path forgot it.
|
|
150
167
|
sig do
|
|
151
168
|
returns(
|
|
152
169
|
T.nilable(
|
|
@@ -181,6 +198,20 @@ module Sentdm
|
|
|
181
198
|
sig { returns(T.nilable(Float)) }
|
|
182
199
|
attr_accessor :price
|
|
183
200
|
|
|
201
|
+
# A human-readable sentence for reason_code, for example "Insufficient balance".
|
|
202
|
+
# Omitted whenever reason_code is.
|
|
203
|
+
sig { returns(T.nilable(String)) }
|
|
204
|
+
attr_accessor :reason
|
|
205
|
+
|
|
206
|
+
# Why the message is at its current status, as a stable platform code such as
|
|
207
|
+
# DELIVERY_007, BUSINESS_003 or DELIVERY_003. Present when the current status is
|
|
208
|
+
# FAILED, FILTERED or BLOCKED and the lifecycle was loaded; omitted otherwise.
|
|
209
|
+
# Switch on this rather than on reason: the code is stable, the wording may be
|
|
210
|
+
# improved. It is the platform's classification of the outcome, never a carrier or
|
|
211
|
+
# vendor code.
|
|
212
|
+
sig { returns(T.nilable(String)) }
|
|
213
|
+
attr_accessor :reason_code
|
|
214
|
+
|
|
184
215
|
sig { returns(T.nilable(String)) }
|
|
185
216
|
attr_reader :region_code
|
|
186
217
|
|
|
@@ -202,7 +233,12 @@ module Sentdm
|
|
|
202
233
|
sig { returns(T.nilable(String)) }
|
|
203
234
|
attr_accessor :template_name
|
|
204
235
|
|
|
205
|
-
# Message response for v3 API — same shape as v2 with snake_case JSON conventions
|
|
236
|
+
# Message response for v3 API — same shape as v2 with snake_case JSON conventions.
|
|
237
|
+
#
|
|
238
|
+
# The shape of a message that was sent immediately: it never has a scheduled_at
|
|
239
|
+
# key. A message that is or was held for a later instant is a
|
|
240
|
+
# ScheduledMessageResponse, and the endpoint decides which of the two to answer
|
|
241
|
+
# with. From always returns this type.
|
|
206
242
|
sig do
|
|
207
243
|
params(
|
|
208
244
|
id: String,
|
|
@@ -225,6 +261,8 @@ module Sentdm
|
|
|
225
261
|
phone: String,
|
|
226
262
|
phone_international: String,
|
|
227
263
|
price: T.nilable(Float),
|
|
264
|
+
reason: T.nilable(String),
|
|
265
|
+
reason_code: T.nilable(String),
|
|
228
266
|
region_code: String,
|
|
229
267
|
status: String,
|
|
230
268
|
template_category: T.nilable(String),
|
|
@@ -242,11 +280,28 @@ module Sentdm
|
|
|
242
280
|
direction: nil,
|
|
243
281
|
events: nil,
|
|
244
282
|
# Structured message body format for database storage. Preserves channel-specific
|
|
245
|
-
# components (header, body, footer, buttons).
|
|
283
|
+
# components (header, header media, body, footer, buttons, MMS subject and media).
|
|
284
|
+
#
|
|
285
|
+
# Persisted as the messageBody jsonb column on Messages. Every write path goes
|
|
286
|
+
# through MessageUtils.MessageBodyJsonOptions, which writes nulls, so the envelope
|
|
287
|
+
# shape is stable regardless of channel or status. Anything that rebuilds this
|
|
288
|
+
# object field by field — the four IMessageBodyStrategy implementations and
|
|
289
|
+
# MessageUtils.BuildSegmentBody — has to carry every member, or that member is
|
|
290
|
+
# silently dropped on whichever path forgot it.
|
|
246
291
|
message_body: nil,
|
|
247
292
|
phone: nil,
|
|
248
293
|
phone_international: nil,
|
|
249
294
|
price: nil,
|
|
295
|
+
# A human-readable sentence for reason_code, for example "Insufficient balance".
|
|
296
|
+
# Omitted whenever reason_code is.
|
|
297
|
+
reason: nil,
|
|
298
|
+
# Why the message is at its current status, as a stable platform code such as
|
|
299
|
+
# DELIVERY_007, BUSINESS_003 or DELIVERY_003. Present when the current status is
|
|
300
|
+
# FAILED, FILTERED or BLOCKED and the lifecycle was loaded; omitted otherwise.
|
|
301
|
+
# Switch on this rather than on reason: the code is stable, the wording may be
|
|
302
|
+
# improved. It is the platform's classification of the outcome, never a carrier or
|
|
303
|
+
# vendor code.
|
|
304
|
+
reason_code: nil,
|
|
250
305
|
region_code: nil,
|
|
251
306
|
status: nil,
|
|
252
307
|
template_category: nil,
|
|
@@ -278,6 +333,8 @@ module Sentdm
|
|
|
278
333
|
phone: String,
|
|
279
334
|
phone_international: String,
|
|
280
335
|
price: T.nilable(Float),
|
|
336
|
+
reason: T.nilable(String),
|
|
337
|
+
reason_code: T.nilable(String),
|
|
281
338
|
region_code: String,
|
|
282
339
|
status: String,
|
|
283
340
|
template_category: T.nilable(String),
|
|
@@ -307,15 +364,39 @@ module Sentdm
|
|
|
307
364
|
sig { returns(T.nilable(String)) }
|
|
308
365
|
attr_accessor :description
|
|
309
366
|
|
|
367
|
+
# A human-readable sentence for reason_code. Omitted whenever reason_code is.
|
|
368
|
+
sig { returns(T.nilable(String)) }
|
|
369
|
+
attr_accessor :reason
|
|
370
|
+
|
|
371
|
+
# Why the message reached this status, as a stable platform code such as
|
|
372
|
+
# DELIVERY_007. Present on FAILED, FILTERED and BLOCKED events; omitted on every
|
|
373
|
+
# status that needs no explanation. Same wire name and vocabulary as on the
|
|
374
|
+
# activities list and the webhook.
|
|
375
|
+
sig { returns(T.nilable(String)) }
|
|
376
|
+
attr_accessor :reason_code
|
|
377
|
+
|
|
310
378
|
# Represents a status change event in a message's lifecycle (v3)
|
|
311
379
|
sig do
|
|
312
380
|
params(
|
|
313
381
|
status: String,
|
|
314
382
|
timestamp: Time,
|
|
315
|
-
description: T.nilable(String)
|
|
383
|
+
description: T.nilable(String),
|
|
384
|
+
reason: T.nilable(String),
|
|
385
|
+
reason_code: T.nilable(String)
|
|
316
386
|
).returns(T.attached_class)
|
|
317
387
|
end
|
|
318
|
-
def self.new(
|
|
388
|
+
def self.new(
|
|
389
|
+
status:,
|
|
390
|
+
timestamp:,
|
|
391
|
+
description: nil,
|
|
392
|
+
# A human-readable sentence for reason_code. Omitted whenever reason_code is.
|
|
393
|
+
reason: nil,
|
|
394
|
+
# Why the message reached this status, as a stable platform code such as
|
|
395
|
+
# DELIVERY_007. Present on FAILED, FILTERED and BLOCKED events; omitted on every
|
|
396
|
+
# status that needs no explanation. Same wire name and vocabulary as on the
|
|
397
|
+
# activities list and the webhook.
|
|
398
|
+
reason_code: nil
|
|
399
|
+
)
|
|
319
400
|
end
|
|
320
401
|
|
|
321
402
|
sig do
|
|
@@ -323,7 +404,9 @@ module Sentdm
|
|
|
323
404
|
{
|
|
324
405
|
status: String,
|
|
325
406
|
timestamp: Time,
|
|
326
|
-
description: T.nilable(String)
|
|
407
|
+
description: T.nilable(String),
|
|
408
|
+
reason: T.nilable(String),
|
|
409
|
+
reason_code: T.nilable(String)
|
|
327
410
|
}
|
|
328
411
|
)
|
|
329
412
|
end
|
|
@@ -363,8 +446,57 @@ module Sentdm
|
|
|
363
446
|
sig { returns(T.nilable(String)) }
|
|
364
447
|
attr_accessor :header
|
|
365
448
|
|
|
449
|
+
# The media asset that rode a message's header, recorded as sent.
|
|
450
|
+
sig do
|
|
451
|
+
returns(
|
|
452
|
+
T.nilable(
|
|
453
|
+
Sentdm::Models::MessageRetrieveStatusResponse::Data::MessageBody::HeaderMedia
|
|
454
|
+
)
|
|
455
|
+
)
|
|
456
|
+
end
|
|
457
|
+
attr_reader :header_media
|
|
458
|
+
|
|
459
|
+
sig do
|
|
460
|
+
params(
|
|
461
|
+
header_media:
|
|
462
|
+
T.nilable(
|
|
463
|
+
Sentdm::Models::MessageRetrieveStatusResponse::Data::MessageBody::HeaderMedia::OrHash
|
|
464
|
+
)
|
|
465
|
+
).void
|
|
466
|
+
end
|
|
467
|
+
attr_writer :header_media
|
|
468
|
+
|
|
469
|
+
# MMS attachments, as the publicly fetchable URLs handed to the carrier. Null on
|
|
470
|
+
# every other channel.
|
|
471
|
+
#
|
|
472
|
+
# Persisted rather than derived because a resend and a curfew release rebuild the
|
|
473
|
+
# send from the stored row — MessageReplayCommandBuilder reads templateId and
|
|
474
|
+
# templateVariables and nothing else — so media that lives only on the original
|
|
475
|
+
# request would silently turn a replayed MMS into a text message.
|
|
476
|
+
sig do
|
|
477
|
+
returns(
|
|
478
|
+
T.nilable(
|
|
479
|
+
T::Array[
|
|
480
|
+
Sentdm::Models::MessageRetrieveStatusResponse::Data::MessageBody::Media
|
|
481
|
+
]
|
|
482
|
+
)
|
|
483
|
+
)
|
|
484
|
+
end
|
|
485
|
+
attr_accessor :media
|
|
486
|
+
|
|
487
|
+
# MMS subject line. Null on every other channel.
|
|
488
|
+
sig { returns(T.nilable(String)) }
|
|
489
|
+
attr_accessor :subject
|
|
490
|
+
|
|
366
491
|
# Structured message body format for database storage. Preserves channel-specific
|
|
367
|
-
# components (header, body, footer, buttons).
|
|
492
|
+
# components (header, header media, body, footer, buttons, MMS subject and media).
|
|
493
|
+
#
|
|
494
|
+
# Persisted as the messageBody jsonb column on Messages. Every write path goes
|
|
495
|
+
# through MessageUtils.MessageBodyJsonOptions, which writes nulls, so the envelope
|
|
496
|
+
# shape is stable regardless of channel or status. Anything that rebuilds this
|
|
497
|
+
# object field by field — the four IMessageBodyStrategy implementations and
|
|
498
|
+
# MessageUtils.BuildSegmentBody — has to carry every member, or that member is
|
|
499
|
+
# silently dropped on whichever path forgot it.
|
|
368
500
|
sig do
|
|
369
501
|
params(
|
|
370
502
|
buttons:
|
|
@@ -375,10 +507,38 @@ module Sentdm
|
|
|
375
507
|
),
|
|
376
508
|
content: String,
|
|
377
509
|
footer: T.nilable(String),
|
|
378
|
-
header: T.nilable(String)
|
|
510
|
+
header: T.nilable(String),
|
|
511
|
+
header_media:
|
|
512
|
+
T.nilable(
|
|
513
|
+
Sentdm::Models::MessageRetrieveStatusResponse::Data::MessageBody::HeaderMedia::OrHash
|
|
514
|
+
),
|
|
515
|
+
media:
|
|
516
|
+
T.nilable(
|
|
517
|
+
T::Array[
|
|
518
|
+
Sentdm::Models::MessageRetrieveStatusResponse::Data::MessageBody::Media::OrHash
|
|
519
|
+
]
|
|
520
|
+
),
|
|
521
|
+
subject: T.nilable(String)
|
|
379
522
|
).returns(T.attached_class)
|
|
380
523
|
end
|
|
381
|
-
def self.new(
|
|
524
|
+
def self.new(
|
|
525
|
+
buttons: nil,
|
|
526
|
+
content: nil,
|
|
527
|
+
footer: nil,
|
|
528
|
+
header: nil,
|
|
529
|
+
# The media asset that rode a message's header, recorded as sent.
|
|
530
|
+
header_media: nil,
|
|
531
|
+
# MMS attachments, as the publicly fetchable URLs handed to the carrier. Null on
|
|
532
|
+
# every other channel.
|
|
533
|
+
#
|
|
534
|
+
# Persisted rather than derived because a resend and a curfew release rebuild the
|
|
535
|
+
# send from the stored row — MessageReplayCommandBuilder reads templateId and
|
|
536
|
+
# templateVariables and nothing else — so media that lives only on the original
|
|
537
|
+
# request would silently turn a replayed MMS into a text message.
|
|
538
|
+
media: nil,
|
|
539
|
+
# MMS subject line. Null on every other channel.
|
|
540
|
+
subject: nil
|
|
541
|
+
)
|
|
382
542
|
end
|
|
383
543
|
|
|
384
544
|
sig do
|
|
@@ -392,7 +552,18 @@ module Sentdm
|
|
|
392
552
|
),
|
|
393
553
|
content: String,
|
|
394
554
|
footer: T.nilable(String),
|
|
395
|
-
header: T.nilable(String)
|
|
555
|
+
header: T.nilable(String),
|
|
556
|
+
header_media:
|
|
557
|
+
T.nilable(
|
|
558
|
+
Sentdm::Models::MessageRetrieveStatusResponse::Data::MessageBody::HeaderMedia
|
|
559
|
+
),
|
|
560
|
+
media:
|
|
561
|
+
T.nilable(
|
|
562
|
+
T::Array[
|
|
563
|
+
Sentdm::Models::MessageRetrieveStatusResponse::Data::MessageBody::Media
|
|
564
|
+
]
|
|
565
|
+
),
|
|
566
|
+
subject: T.nilable(String)
|
|
396
567
|
}
|
|
397
568
|
)
|
|
398
569
|
end
|
|
@@ -450,6 +621,143 @@ module Sentdm
|
|
|
450
621
|
def to_hash
|
|
451
622
|
end
|
|
452
623
|
end
|
|
624
|
+
|
|
625
|
+
class HeaderMedia < Sentdm::Internal::Type::BaseModel
|
|
626
|
+
OrHash =
|
|
627
|
+
T.type_alias do
|
|
628
|
+
T.any(
|
|
629
|
+
Sentdm::Models::MessageRetrieveStatusResponse::Data::MessageBody::HeaderMedia,
|
|
630
|
+
Sentdm::Internal::AnyHash
|
|
631
|
+
)
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
# "image", "video" or "document" — taken from the header's media variable.
|
|
635
|
+
sig { returns(T.nilable(String)) }
|
|
636
|
+
attr_reader :type
|
|
637
|
+
|
|
638
|
+
sig { params(type: String).void }
|
|
639
|
+
attr_writer :type
|
|
640
|
+
|
|
641
|
+
# The https URL the caller supplied for this send. Never the template's stored
|
|
642
|
+
# props.sample, which is Meta's expiring header_handle rather than what was
|
|
643
|
+
# delivered.
|
|
644
|
+
sig { returns(T.nilable(String)) }
|
|
645
|
+
attr_reader :url
|
|
646
|
+
|
|
647
|
+
sig { params(url: String).void }
|
|
648
|
+
attr_writer :url
|
|
649
|
+
|
|
650
|
+
# The media asset that rode a message's header, recorded as sent.
|
|
651
|
+
sig { params(type: String, url: String).returns(T.attached_class) }
|
|
652
|
+
def self.new(
|
|
653
|
+
# "image", "video" or "document" — taken from the header's media variable.
|
|
654
|
+
type: nil,
|
|
655
|
+
# The https URL the caller supplied for this send. Never the template's stored
|
|
656
|
+
# props.sample, which is Meta's expiring header_handle rather than what was
|
|
657
|
+
# delivered.
|
|
658
|
+
url: nil
|
|
659
|
+
)
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
sig { override.returns({ type: String, url: String }) }
|
|
663
|
+
def to_hash
|
|
664
|
+
end
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
class Media < Sentdm::Internal::Type::BaseModel
|
|
668
|
+
OrHash =
|
|
669
|
+
T.type_alias do
|
|
670
|
+
T.any(
|
|
671
|
+
Sentdm::Models::MessageRetrieveStatusResponse::Data::MessageBody::Media,
|
|
672
|
+
Sentdm::Internal::AnyHash
|
|
673
|
+
)
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
# One of MmsMediaTypes when the content type is known. Advisory — a reader should
|
|
677
|
+
# trust the fetched object's own Content-Type.
|
|
678
|
+
sig { returns(T.nilable(String)) }
|
|
679
|
+
attr_accessor :media_type
|
|
680
|
+
|
|
681
|
+
# Content type as the provider declared it. Null when it declared none.
|
|
682
|
+
sig { returns(T.nilable(String)) }
|
|
683
|
+
attr_accessor :mime_type
|
|
684
|
+
|
|
685
|
+
# Size as the provider declared it. Never measured here — nothing downloads the
|
|
686
|
+
# file.
|
|
687
|
+
sig { returns(T.nilable(Integer)) }
|
|
688
|
+
attr_accessor :size_bytes
|
|
689
|
+
|
|
690
|
+
# Inbound only: the SHA-256 the provider declared alongside the attachment, when
|
|
691
|
+
# it declared one. Relayed to the customer so they can verify what they fetch
|
|
692
|
+
# matches what the carrier said it sent. It is the only integrity signal available
|
|
693
|
+
# on an attachment nobody here has read.
|
|
694
|
+
sig { returns(T.nilable(String)) }
|
|
695
|
+
attr_accessor :source_hash_sha256
|
|
696
|
+
|
|
697
|
+
# Where the file lives. Outbound: the URL the customer gave us and the carrier
|
|
698
|
+
# fetched. Inbound: the URL the carrier hosts it at, relayed unchanged.
|
|
699
|
+
sig { returns(T.nilable(String)) }
|
|
700
|
+
attr_accessor :url
|
|
701
|
+
|
|
702
|
+
# One attachment on a message, in either direction — and in both, a URL somebody
|
|
703
|
+
# else hosts.
|
|
704
|
+
#
|
|
705
|
+
# Outbound: the customer supplied a public URL and we handed it to the carrier.
|
|
706
|
+
# Inbound: the carrier hosts the file and we record where. sent.dm never holds the
|
|
707
|
+
# bytes, so there is no key, no expiry bookkeeping and nothing minted per read —
|
|
708
|
+
# what is stored is what is served.
|
|
709
|
+
#
|
|
710
|
+
# An inbound link expires on the carrier's own schedule and is unauthenticated.
|
|
711
|
+
# That is the customer's to manage, and it is documented where they will see it
|
|
712
|
+
# rather than only here — a recipient who needs an attachment to outlive that
|
|
713
|
+
# window copies it on receipt.
|
|
714
|
+
#
|
|
715
|
+
# Storing a presigned URL is the specific mistake this shape still avoids:
|
|
716
|
+
# M260826130000 and M260826140000 exist because RCS assets were stored as signed
|
|
717
|
+
# URLs and went stale. Nothing here is signed.
|
|
718
|
+
sig do
|
|
719
|
+
params(
|
|
720
|
+
media_type: T.nilable(String),
|
|
721
|
+
mime_type: T.nilable(String),
|
|
722
|
+
size_bytes: T.nilable(Integer),
|
|
723
|
+
source_hash_sha256: T.nilable(String),
|
|
724
|
+
url: T.nilable(String)
|
|
725
|
+
).returns(T.attached_class)
|
|
726
|
+
end
|
|
727
|
+
def self.new(
|
|
728
|
+
# One of MmsMediaTypes when the content type is known. Advisory — a reader should
|
|
729
|
+
# trust the fetched object's own Content-Type.
|
|
730
|
+
media_type: nil,
|
|
731
|
+
# Content type as the provider declared it. Null when it declared none.
|
|
732
|
+
mime_type: nil,
|
|
733
|
+
# Size as the provider declared it. Never measured here — nothing downloads the
|
|
734
|
+
# file.
|
|
735
|
+
size_bytes: nil,
|
|
736
|
+
# Inbound only: the SHA-256 the provider declared alongside the attachment, when
|
|
737
|
+
# it declared one. Relayed to the customer so they can verify what they fetch
|
|
738
|
+
# matches what the carrier said it sent. It is the only integrity signal available
|
|
739
|
+
# on an attachment nobody here has read.
|
|
740
|
+
source_hash_sha256: nil,
|
|
741
|
+
# Where the file lives. Outbound: the URL the customer gave us and the carrier
|
|
742
|
+
# fetched. Inbound: the URL the carrier hosts it at, relayed unchanged.
|
|
743
|
+
url: nil
|
|
744
|
+
)
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
sig do
|
|
748
|
+
override.returns(
|
|
749
|
+
{
|
|
750
|
+
media_type: T.nilable(String),
|
|
751
|
+
mime_type: T.nilable(String),
|
|
752
|
+
size_bytes: T.nilable(Integer),
|
|
753
|
+
source_hash_sha256: T.nilable(String),
|
|
754
|
+
url: T.nilable(String)
|
|
755
|
+
}
|
|
756
|
+
)
|
|
757
|
+
end
|
|
758
|
+
def to_hash
|
|
759
|
+
end
|
|
760
|
+
end
|
|
453
761
|
end
|
|
454
762
|
end
|
|
455
763
|
end
|
|
@@ -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
|