sentdm 0.31.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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/README.md +1 -1
  4. data/lib/sentdm/client.rb +6 -0
  5. data/lib/sentdm/models/channel_event.rb +78 -0
  6. data/lib/sentdm/models/channel_event_payload.rb +265 -0
  7. data/lib/sentdm/models/contact_event.rb +77 -0
  8. data/lib/sentdm/models/contact_event_payload.rb +172 -0
  9. data/lib/sentdm/models/conversation_messages_list.rb +125 -4
  10. data/lib/sentdm/models/inbound_message_event.rb +16 -8
  11. data/lib/sentdm/models/message_event.rb +16 -8
  12. data/lib/sentdm/models/message_event_payload.rb +30 -1
  13. data/lib/sentdm/models/message_retrieve_activities_response.rb +20 -5
  14. data/lib/sentdm/models/message_retrieve_status_response.rb +133 -6
  15. data/lib/sentdm/models/message_send_params.rb +67 -3
  16. data/lib/sentdm/models/message_send_response.rb +13 -4
  17. data/lib/sentdm/models/template.rb +36 -5
  18. data/lib/sentdm/models/template_body.rb +102 -12
  19. data/lib/sentdm/models/template_body_content.rb +35 -3
  20. data/lib/sentdm/models/template_button.rb +8 -2
  21. data/lib/sentdm/models/template_button_props.rb +12 -1
  22. data/lib/sentdm/models/template_definition.rb +14 -2
  23. data/lib/sentdm/models/template_event.rb +16 -8
  24. data/lib/sentdm/models/template_event_payload.rb +31 -4
  25. data/lib/sentdm/models/template_header.rb +91 -3
  26. data/lib/sentdm/models/template_variable.rb +35 -4
  27. data/lib/sentdm/models/webhook_list_events_response.rb +332 -9
  28. data/lib/sentdm/models.rb +8 -0
  29. data/lib/sentdm/resources/messages.rb +33 -5
  30. data/lib/sentdm/resources/templates.rb +28 -2
  31. data/lib/sentdm/version.rb +1 -1
  32. data/lib/sentdm.rb +5 -1
  33. data/rbi/sentdm/client.rbi +6 -0
  34. data/rbi/sentdm/models/channel_event.rbi +128 -0
  35. data/rbi/sentdm/models/channel_event_payload.rbi +440 -0
  36. data/rbi/sentdm/models/contact_event.rbi +126 -0
  37. data/rbi/sentdm/models/contact_event_payload.rbi +254 -0
  38. data/rbi/sentdm/models/conversation_messages_list.rbi +202 -7
  39. data/rbi/sentdm/models/inbound_message_event.rbi +18 -10
  40. data/rbi/sentdm/models/message_event.rbi +18 -10
  41. data/rbi/sentdm/models/message_event_payload.rbi +34 -0
  42. data/rbi/sentdm/models/message_retrieve_activities_response.rbi +23 -5
  43. data/rbi/sentdm/models/message_retrieve_status_response.rbi +214 -9
  44. data/rbi/sentdm/models/message_send_params.rbi +100 -2
  45. data/rbi/sentdm/models/message_send_response.rbi +15 -5
  46. data/rbi/sentdm/models/template.rbi +58 -4
  47. data/rbi/sentdm/models/template_body.rbi +155 -13
  48. data/rbi/sentdm/models/template_body_content.rbi +59 -1
  49. data/rbi/sentdm/models/template_button.rbi +14 -2
  50. data/rbi/sentdm/models/template_button_props.rbi +22 -0
  51. data/rbi/sentdm/models/template_definition.rbi +20 -2
  52. data/rbi/sentdm/models/template_event.rbi +18 -10
  53. data/rbi/sentdm/models/template_event_payload.rbi +51 -8
  54. data/rbi/sentdm/models/template_header.rbi +143 -2
  55. data/rbi/sentdm/models/template_variable.rbi +38 -1
  56. data/rbi/sentdm/models/webhook_list_events_response.rbi +484 -12
  57. data/rbi/sentdm/models.rbi +8 -0
  58. data/rbi/sentdm/resources/messages.rbi +58 -3
  59. data/rbi/sentdm/resources/templates.rbi +28 -2
  60. data/sig/sentdm/models/channel_event.rbs +44 -0
  61. data/sig/sentdm/models/channel_event_payload.rbs +120 -0
  62. data/sig/sentdm/models/contact_event.rbs +44 -0
  63. data/sig/sentdm/models/contact_event_payload.rbs +78 -0
  64. data/sig/sentdm/models/conversation_messages_list.rbs +48 -3
  65. data/sig/sentdm/models/inbound_message_event.rbs +5 -0
  66. data/sig/sentdm/models/message_event.rbs +5 -0
  67. data/sig/sentdm/models/message_event_payload.rbs +15 -0
  68. data/sig/sentdm/models/message_retrieve_activities_response.rbs +5 -0
  69. data/sig/sentdm/models/message_retrieve_status_response.rbs +48 -3
  70. data/sig/sentdm/models/message_send_params.rbs +15 -0
  71. data/sig/sentdm/models/template.rbs +5 -0
  72. data/sig/sentdm/models/template_body.rbs +44 -0
  73. data/sig/sentdm/models/template_event.rbs +5 -0
  74. data/sig/sentdm/models/template_event_payload.rbs +9 -6
  75. data/sig/sentdm/models/template_header.rbs +44 -0
  76. data/sig/sentdm/models/webhook_list_events_response.rbs +147 -0
  77. data/sig/sentdm/models.rbs +8 -0
  78. data/sig/sentdm/resources/messages.rbs +3 -0
  79. metadata +14 -2
@@ -0,0 +1,254 @@
1
+ # typed: strong
2
+
3
+ module Sentdm
4
+ module Models
5
+ class ContactEventPayload < Sentdm::Internal::Type::BaseModel
6
+ OrHash =
7
+ T.type_alias do
8
+ T.any(Sentdm::ContactEventPayload, Sentdm::Internal::AnyHash)
9
+ end
10
+
11
+ # Whether the contact is opted out after this signal — the state to write to your
12
+ # own record. Same meaning as opt_out on the contact resource. On contact.help and
13
+ # contact.custom_keyword this reports the contact's existing state, which neither
14
+ # changes.
15
+ #
16
+ # Two signals from the same contact can arrive out of order, because each one is
17
+ # queued on its own rather than against the contact. Compare the envelope's
18
+ # timestamp before you overwrite a newer state with an older one. That timestamp
19
+ # is second-precision, so treat two signals stamped in the same second as
20
+ # unordered and read the contact resource to settle them.
21
+ sig { returns(T::Boolean) }
22
+ attr_accessor :opt_out
23
+
24
+ # How the signal reached us. INBOUND_KEYWORD means the contact sent a message
25
+ # whose text matched one of the keywords; PROVIDER_SIGNAL means the network
26
+ # reported it. A provider signal usually carries no message_id or text, so read
27
+ # both for null rather than inferring them from this field.
28
+ sig { returns(String) }
29
+ attr_accessor :source
30
+
31
+ # The account the contact belongs to. Present so one endpoint can serve several
32
+ # accounts.
33
+ sig { returns(T.nilable(String)) }
34
+ attr_reader :account_id
35
+
36
+ sig { params(account_id: String).void }
37
+ attr_writer :account_id
38
+
39
+ # The RCS agent the signal reached, when it reached one.
40
+ #
41
+ # Omitted entirely on channels that have no agent, rather than sent as null — an
42
+ # SMS or WhatsApp payload does not carry this key at all. On RCS it is the
43
+ # counterpart to To: a contact reaches an agent rather than a number, so exactly
44
+ # one of the two is populated and never both. If you run more than one agent, this
45
+ # is what tells you which of them the contact acted on.
46
+ sig { returns(T.nilable(String)) }
47
+ attr_accessor :agent_id
48
+
49
+ # The channel the signal arrived on, for example sms or whatsapp.
50
+ sig { returns(T.nilable(String)) }
51
+ attr_reader :channel
52
+
53
+ sig { params(channel: String).void }
54
+ attr_writer :channel
55
+
56
+ # The contact who raised the signal. Always populated, including for contact.help
57
+ # or contact.custom_keyword from a number you have not messaged before — the
58
+ # contact is created if it does not exist yet, so this identifier is always
59
+ # resolvable against the contacts API.
60
+ sig { returns(T.nilable(String)) }
61
+ attr_reader :contact_id
62
+
63
+ sig { params(contact_id: String).void }
64
+ attr_writer :contact_id
65
+
66
+ # The contact's number, in E.164 format with the leading + — who raised the
67
+ # signal. The same party message.received publishes as inbound_number.
68
+ sig { returns(T.nilable(String)) }
69
+ attr_reader :from
70
+
71
+ sig { params(from: String).void }
72
+ attr_writer :from
73
+
74
+ # The inbound message that carried the signal, matching message_id on the
75
+ # corresponding message.received event so the two can be joined.
76
+ #
77
+ # Sent as null when the signal did not arrive as a message — for example when a
78
+ # network processed an opt-out on your behalf — and also when the message belongs
79
+ # to a different account than this event, which can happen on a shared WhatsApp
80
+ # number. The field is always present, so read it and check for null rather than
81
+ # checking whether the key exists.
82
+ sig { returns(T.nilable(String)) }
83
+ attr_accessor :message_id
84
+
85
+ # The auto-reply template whose keyword the contact matched, joinable against the
86
+ # templates API.
87
+ #
88
+ # This is what identifies which signal arrived on contact.custom_keyword: every
89
+ # custom template reports the same event name, so the event alone cannot tell your
90
+ # booking keyword from your opening-hours one. One template holds as many keywords
91
+ # as you configured, so this is steadier to switch on than text.
92
+ #
93
+ # Populated on the compliance sub-types too, where it names the template that
94
+ # replied. Sent as null when no template was involved — a network-reported opt-out
95
+ # matches no keyword. The field is always present, so read it and check for null.
96
+ sig { returns(T.nilable(String)) }
97
+ attr_accessor :template_id
98
+
99
+ # The text the contact sent, for example STOP or UNSUBSCRIBE. Sent as null when
100
+ # the signal did not arrive as text. The field is always present, so read it and
101
+ # check for null rather than checking whether the key exists.
102
+ sig { returns(T.nilable(String)) }
103
+ attr_accessor :text
104
+
105
+ # The number of yours that received the signal, in E.164 format with the leading
106
+ # +. Tells a multi-number account which of its senders the contact acted on, which
107
+ # nothing else on this payload answers.
108
+ #
109
+ # This is your number, not the contact's. That is the opposite of what to means on
110
+ # POST /v3/messages, where it is the list of recipients you are sending to. Reply
111
+ # to From, not to this field, or the message goes back to yourself.
112
+ #
113
+ # Sent as null when the signal did not arrive at a number of yours — an RCS signal
114
+ # terminates at an agent rather than a number, and a provider-reported opt-out may
115
+ # name no receiving number at all. The field is always present, so read it and
116
+ # check for null rather than checking whether the key exists.
117
+ sig { returns(T.nilable(String)) }
118
+ attr_accessor :to
119
+
120
+ # Body of a contact.opt_in, contact.opt_out, contact.help or
121
+ # contact.custom_keyword event. Delivered when a contact signals a consent change,
122
+ # asks for help, or sends one of your own auto-reply keywords.
123
+ #
124
+ # These events state the signal outright, so you do not have to recognise keywords
125
+ # in the text of a message.received event. They also cover cases that produce no
126
+ # inbound message at all, such as a network handling an opt-out on your behalf.
127
+ #
128
+ # Two of the four change consent and two do not: contact.help and
129
+ # contact.custom_keyword report the state the contact already had. Read opt_out
130
+ # for the state and the envelope's event for what happened, rather than inferring
131
+ # one from the other.
132
+ #
133
+ # Fields are ordered identity → resulting state → provenance → join keys. The two
134
+ # parties are from and to. Note that the message family has not moved to those
135
+ # names yet — message.received still calls the same two parties inbound_number and
136
+ # outbound_number. Nothing here restates the envelope: which signal occurred is
137
+ # the envelope's event, and when it was emitted is its timestamp. Retries carry
138
+ # the same X-Webhook-Event-ID header, which is what to deduplicate on.
139
+ sig do
140
+ params(
141
+ opt_out: T::Boolean,
142
+ source: String,
143
+ account_id: String,
144
+ agent_id: T.nilable(String),
145
+ channel: String,
146
+ contact_id: String,
147
+ from: String,
148
+ message_id: T.nilable(String),
149
+ template_id: T.nilable(String),
150
+ text: T.nilable(String),
151
+ to: T.nilable(String)
152
+ ).returns(T.attached_class)
153
+ end
154
+ def self.new(
155
+ # Whether the contact is opted out after this signal — the state to write to your
156
+ # own record. Same meaning as opt_out on the contact resource. On contact.help and
157
+ # contact.custom_keyword this reports the contact's existing state, which neither
158
+ # changes.
159
+ #
160
+ # Two signals from the same contact can arrive out of order, because each one is
161
+ # queued on its own rather than against the contact. Compare the envelope's
162
+ # timestamp before you overwrite a newer state with an older one. That timestamp
163
+ # is second-precision, so treat two signals stamped in the same second as
164
+ # unordered and read the contact resource to settle them.
165
+ opt_out:,
166
+ # How the signal reached us. INBOUND_KEYWORD means the contact sent a message
167
+ # whose text matched one of the keywords; PROVIDER_SIGNAL means the network
168
+ # reported it. A provider signal usually carries no message_id or text, so read
169
+ # both for null rather than inferring them from this field.
170
+ source:,
171
+ # The account the contact belongs to. Present so one endpoint can serve several
172
+ # accounts.
173
+ account_id: nil,
174
+ # The RCS agent the signal reached, when it reached one.
175
+ #
176
+ # Omitted entirely on channels that have no agent, rather than sent as null — an
177
+ # SMS or WhatsApp payload does not carry this key at all. On RCS it is the
178
+ # counterpart to To: a contact reaches an agent rather than a number, so exactly
179
+ # one of the two is populated and never both. If you run more than one agent, this
180
+ # is what tells you which of them the contact acted on.
181
+ agent_id: nil,
182
+ # The channel the signal arrived on, for example sms or whatsapp.
183
+ channel: nil,
184
+ # The contact who raised the signal. Always populated, including for contact.help
185
+ # or contact.custom_keyword from a number you have not messaged before — the
186
+ # contact is created if it does not exist yet, so this identifier is always
187
+ # resolvable against the contacts API.
188
+ contact_id: nil,
189
+ # The contact's number, in E.164 format with the leading + — who raised the
190
+ # signal. The same party message.received publishes as inbound_number.
191
+ from: nil,
192
+ # The inbound message that carried the signal, matching message_id on the
193
+ # corresponding message.received event so the two can be joined.
194
+ #
195
+ # Sent as null when the signal did not arrive as a message — for example when a
196
+ # network processed an opt-out on your behalf — and also when the message belongs
197
+ # to a different account than this event, which can happen on a shared WhatsApp
198
+ # number. The field is always present, so read it and check for null rather than
199
+ # checking whether the key exists.
200
+ message_id: nil,
201
+ # The auto-reply template whose keyword the contact matched, joinable against the
202
+ # templates API.
203
+ #
204
+ # This is what identifies which signal arrived on contact.custom_keyword: every
205
+ # custom template reports the same event name, so the event alone cannot tell your
206
+ # booking keyword from your opening-hours one. One template holds as many keywords
207
+ # as you configured, so this is steadier to switch on than text.
208
+ #
209
+ # Populated on the compliance sub-types too, where it names the template that
210
+ # replied. Sent as null when no template was involved — a network-reported opt-out
211
+ # matches no keyword. The field is always present, so read it and check for null.
212
+ template_id: nil,
213
+ # The text the contact sent, for example STOP or UNSUBSCRIBE. Sent as null when
214
+ # the signal did not arrive as text. The field is always present, so read it and
215
+ # check for null rather than checking whether the key exists.
216
+ text: nil,
217
+ # The number of yours that received the signal, in E.164 format with the leading
218
+ # +. Tells a multi-number account which of its senders the contact acted on, which
219
+ # nothing else on this payload answers.
220
+ #
221
+ # This is your number, not the contact's. That is the opposite of what to means on
222
+ # POST /v3/messages, where it is the list of recipients you are sending to. Reply
223
+ # to From, not to this field, or the message goes back to yourself.
224
+ #
225
+ # Sent as null when the signal did not arrive at a number of yours — an RCS signal
226
+ # terminates at an agent rather than a number, and a provider-reported opt-out may
227
+ # name no receiving number at all. The field is always present, so read it and
228
+ # check for null rather than checking whether the key exists.
229
+ to: nil
230
+ )
231
+ end
232
+
233
+ sig do
234
+ override.returns(
235
+ {
236
+ opt_out: T::Boolean,
237
+ source: String,
238
+ account_id: String,
239
+ agent_id: T.nilable(String),
240
+ channel: String,
241
+ contact_id: String,
242
+ from: String,
243
+ message_id: T.nilable(String),
244
+ template_id: T.nilable(String),
245
+ text: T.nilable(String),
246
+ to: T.nilable(String)
247
+ }
248
+ )
249
+ end
250
+ def to_hash
251
+ end
252
+ end
253
+ end
254
+ end
@@ -112,7 +112,14 @@ module Sentdm
112
112
  attr_accessor :events
113
113
 
114
114
  # Structured message body format for database storage. Preserves channel-specific
115
- # components (header, body, footer, buttons).
115
+ # components (header, header media, body, footer, buttons, MMS subject and media).
116
+ #
117
+ # Persisted as the messageBody jsonb column on Messages. Every write path goes
118
+ # through MessageUtils.MessageBodyJsonOptions, which writes nulls, so the envelope
119
+ # shape is stable regardless of channel or status. Anything that rebuilds this
120
+ # object field by field — the four IMessageBodyStrategy implementations and
121
+ # MessageUtils.BuildSegmentBody — has to carry every member, or that member is
122
+ # silently dropped on whichever path forgot it.
116
123
  sig do
117
124
  returns(
118
125
  T.nilable(Sentdm::ConversationMessagesList::Message::MessageBody)
@@ -166,7 +173,12 @@ module Sentdm
166
173
  sig { returns(T.nilable(String)) }
167
174
  attr_accessor :template_name
168
175
 
169
- # Message response for v3 API — same shape as v2 with snake_case JSON conventions
176
+ # Message response for v3 API — same shape as v2 with snake_case JSON conventions.
177
+ #
178
+ # The shape of a message that was sent immediately: it never has a scheduled_at
179
+ # key. A message that is or was held for a later instant is a
180
+ # ScheduledMessageResponse, and the endpoint decides which of the two to answer
181
+ # with. From always returns this type.
170
182
  sig do
171
183
  params(
172
184
  id: String,
@@ -206,7 +218,14 @@ module Sentdm
206
218
  direction: nil,
207
219
  events: nil,
208
220
  # Structured message body format for database storage. Preserves channel-specific
209
- # components (header, body, footer, buttons).
221
+ # components (header, header media, body, footer, buttons, MMS subject and media).
222
+ #
223
+ # Persisted as the messageBody jsonb column on Messages. Every write path goes
224
+ # through MessageUtils.MessageBodyJsonOptions, which writes nulls, so the envelope
225
+ # shape is stable regardless of channel or status. Anything that rebuilds this
226
+ # object field by field — the four IMessageBodyStrategy implementations and
227
+ # MessageUtils.BuildSegmentBody — has to carry every member, or that member is
228
+ # silently dropped on whichever path forgot it.
210
229
  message_body: nil,
211
230
  phone: nil,
212
231
  phone_international: nil,
@@ -325,8 +344,57 @@ module Sentdm
325
344
  sig { returns(T.nilable(String)) }
326
345
  attr_accessor :header
327
346
 
347
+ # The media asset that rode a message's header, recorded as sent.
348
+ sig do
349
+ returns(
350
+ T.nilable(
351
+ Sentdm::ConversationMessagesList::Message::MessageBody::HeaderMedia
352
+ )
353
+ )
354
+ end
355
+ attr_reader :header_media
356
+
357
+ sig do
358
+ params(
359
+ header_media:
360
+ T.nilable(
361
+ Sentdm::ConversationMessagesList::Message::MessageBody::HeaderMedia::OrHash
362
+ )
363
+ ).void
364
+ end
365
+ attr_writer :header_media
366
+
367
+ # MMS attachments, as the publicly fetchable URLs handed to the carrier. Null on
368
+ # every other channel.
369
+ #
370
+ # Persisted rather than derived because a resend and a curfew release rebuild the
371
+ # send from the stored row — MessageReplayCommandBuilder reads templateId and
372
+ # templateVariables and nothing else — so media that lives only on the original
373
+ # request would silently turn a replayed MMS into a text message.
374
+ sig do
375
+ returns(
376
+ T.nilable(
377
+ T::Array[
378
+ Sentdm::ConversationMessagesList::Message::MessageBody::Media
379
+ ]
380
+ )
381
+ )
382
+ end
383
+ attr_accessor :media
384
+
385
+ # MMS subject line. Null on every other channel.
386
+ sig { returns(T.nilable(String)) }
387
+ attr_accessor :subject
388
+
328
389
  # Structured message body format for database storage. Preserves channel-specific
329
- # components (header, body, footer, buttons).
390
+ # components (header, header media, body, footer, buttons, MMS subject and media).
391
+ #
392
+ # Persisted as the messageBody jsonb column on Messages. Every write path goes
393
+ # through MessageUtils.MessageBodyJsonOptions, which writes nulls, so the envelope
394
+ # shape is stable regardless of channel or status. Anything that rebuilds this
395
+ # object field by field — the four IMessageBodyStrategy implementations and
396
+ # MessageUtils.BuildSegmentBody — has to carry every member, or that member is
397
+ # silently dropped on whichever path forgot it.
330
398
  sig do
331
399
  params(
332
400
  buttons:
@@ -337,10 +405,38 @@ module Sentdm
337
405
  ),
338
406
  content: String,
339
407
  footer: T.nilable(String),
340
- header: T.nilable(String)
408
+ header: T.nilable(String),
409
+ header_media:
410
+ T.nilable(
411
+ Sentdm::ConversationMessagesList::Message::MessageBody::HeaderMedia::OrHash
412
+ ),
413
+ media:
414
+ T.nilable(
415
+ T::Array[
416
+ Sentdm::ConversationMessagesList::Message::MessageBody::Media::OrHash
417
+ ]
418
+ ),
419
+ subject: T.nilable(String)
341
420
  ).returns(T.attached_class)
342
421
  end
343
- def self.new(buttons: nil, content: nil, footer: nil, header: nil)
422
+ def self.new(
423
+ buttons: nil,
424
+ content: nil,
425
+ footer: nil,
426
+ header: nil,
427
+ # The media asset that rode a message's header, recorded as sent.
428
+ header_media: nil,
429
+ # MMS attachments, as the publicly fetchable URLs handed to the carrier. Null on
430
+ # every other channel.
431
+ #
432
+ # Persisted rather than derived because a resend and a curfew release rebuild the
433
+ # send from the stored row — MessageReplayCommandBuilder reads templateId and
434
+ # templateVariables and nothing else — so media that lives only on the original
435
+ # request would silently turn a replayed MMS into a text message.
436
+ media: nil,
437
+ # MMS subject line. Null on every other channel.
438
+ subject: nil
439
+ )
344
440
  end
345
441
 
346
442
  sig do
@@ -354,7 +450,18 @@ module Sentdm
354
450
  ),
355
451
  content: String,
356
452
  footer: T.nilable(String),
357
- header: T.nilable(String)
453
+ header: T.nilable(String),
454
+ header_media:
455
+ T.nilable(
456
+ Sentdm::ConversationMessagesList::Message::MessageBody::HeaderMedia
457
+ ),
458
+ media:
459
+ T.nilable(
460
+ T::Array[
461
+ Sentdm::ConversationMessagesList::Message::MessageBody::Media
462
+ ]
463
+ ),
464
+ subject: T.nilable(String)
358
465
  }
359
466
  )
360
467
  end
@@ -412,6 +519,94 @@ module Sentdm
412
519
  def to_hash
413
520
  end
414
521
  end
522
+
523
+ class HeaderMedia < Sentdm::Internal::Type::BaseModel
524
+ OrHash =
525
+ T.type_alias do
526
+ T.any(
527
+ Sentdm::ConversationMessagesList::Message::MessageBody::HeaderMedia,
528
+ Sentdm::Internal::AnyHash
529
+ )
530
+ end
531
+
532
+ # "image", "video" or "document" — taken from the header's media variable.
533
+ sig { returns(T.nilable(String)) }
534
+ attr_reader :type
535
+
536
+ sig { params(type: String).void }
537
+ attr_writer :type
538
+
539
+ # The https URL the caller supplied for this send. Never the template's stored
540
+ # props.sample, which is Meta's expiring header_handle rather than what was
541
+ # delivered.
542
+ sig { returns(T.nilable(String)) }
543
+ attr_reader :url
544
+
545
+ sig { params(url: String).void }
546
+ attr_writer :url
547
+
548
+ # The media asset that rode a message's header, recorded as sent.
549
+ sig { params(type: String, url: String).returns(T.attached_class) }
550
+ def self.new(
551
+ # "image", "video" or "document" — taken from the header's media variable.
552
+ type: nil,
553
+ # The https URL the caller supplied for this send. Never the template's stored
554
+ # props.sample, which is Meta's expiring header_handle rather than what was
555
+ # delivered.
556
+ url: nil
557
+ )
558
+ end
559
+
560
+ sig { override.returns({ type: String, url: String }) }
561
+ def to_hash
562
+ end
563
+ end
564
+
565
+ class Media < Sentdm::Internal::Type::BaseModel
566
+ OrHash =
567
+ T.type_alias do
568
+ T.any(
569
+ Sentdm::ConversationMessagesList::Message::MessageBody::Media,
570
+ Sentdm::Internal::AnyHash
571
+ )
572
+ end
573
+
574
+ # One of Constants.MmsMediaTypes when known. Advisory — the carrier reads the
575
+ # fetched object's Content-Type, not this.
576
+ sig { returns(T.nilable(String)) }
577
+ attr_accessor :media_type
578
+
579
+ sig { returns(T.nilable(String)) }
580
+ attr_reader :url
581
+
582
+ sig { params(url: String).void }
583
+ attr_writer :url
584
+
585
+ # One attachment on a message: a customer-supplied public URL handed to the
586
+ # carrier as-is.
587
+ #
588
+ # A URL and nothing else. sent.dm never takes custody of MMS media — the customer hosts it and we
589
+ # pass the link through at send time — so there is no storage key, size or expiry to record. If we ever
590
+ # do host attachments, that belongs with the change that introduces the hosting, not here.
591
+ sig do
592
+ params(media_type: T.nilable(String), url: String).returns(
593
+ T.attached_class
594
+ )
595
+ end
596
+ def self.new(
597
+ # One of Constants.MmsMediaTypes when known. Advisory — the carrier reads the
598
+ # fetched object's Content-Type, not this.
599
+ media_type: nil,
600
+ url: nil
601
+ )
602
+ end
603
+
604
+ sig do
605
+ override.returns({ media_type: T.nilable(String), url: String })
606
+ end
607
+ def to_hash
608
+ end
609
+ end
415
610
  end
416
611
  end
417
612
  end
@@ -8,14 +8,14 @@ module Sentdm
8
8
  T.any(Sentdm::InboundMessageEvent, Sentdm::Internal::AnyHash)
9
9
  end
10
10
 
11
- # The specific event within the family, for example message.delivered or
12
- # message.received. Absent on events that have no subtype, so treat it as
13
- # optional.
11
+ # The specific event within the family, for example message.delivered,
12
+ # message.received or contact.opt_out. Absent on events that have no subtype, so
13
+ # treat it as optional.
14
14
  sig { returns(T.nilable(String)) }
15
15
  attr_accessor :event
16
16
 
17
- # The event family, for example message or templates. Route on this first, then on
18
- # event for the specific change.
17
+ # The event family, for example message, templates or contact. Route on this
18
+ # first, then on event for the specific change.
19
19
  sig { returns(T.nilable(String)) }
20
20
  attr_reader :field
21
21
 
@@ -34,6 +34,10 @@ module Sentdm
34
34
  end
35
35
  attr_writer :payload
36
36
 
37
+ # The event-specific body.
38
+ sig { returns(T.nilable(String)) }
39
+ attr_accessor :request_id
40
+
37
41
  # When Sent emitted the event, in UTC (yyyy-MM-ddTHH:mm:ssZ). This is the emission
38
42
  # time, not the time the underlying change happened. Use the timestamp inside the
39
43
  # payload for the latter.
@@ -50,20 +54,23 @@ module Sentdm
50
54
  event: T.nilable(String),
51
55
  field: String,
52
56
  payload: T.nilable(Sentdm::InboundMessageEventPayload::OrHash),
57
+ request_id: T.nilable(String),
53
58
  timestamp: String
54
59
  ).returns(T.attached_class)
55
60
  end
56
61
  def self.new(
57
- # The specific event within the family, for example message.delivered or
58
- # message.received. Absent on events that have no subtype, so treat it as
59
- # optional.
62
+ # The specific event within the family, for example message.delivered,
63
+ # message.received or contact.opt_out. Absent on events that have no subtype, so
64
+ # treat it as optional.
60
65
  event: nil,
61
- # The event family, for example message or templates. Route on this first, then on
62
- # event for the specific change.
66
+ # The event family, for example message, templates or contact. Route on this
67
+ # first, then on event for the specific change.
63
68
  field: nil,
64
69
  # Body of a message.received event. Delivered when a contact messages one of your
65
70
  # numbers.
66
71
  payload: nil,
72
+ # The event-specific body.
73
+ request_id: nil,
67
74
  # When Sent emitted the event, in UTC (yyyy-MM-ddTHH:mm:ssZ). This is the emission
68
75
  # time, not the time the underlying change happened. Use the timestamp inside the
69
76
  # payload for the latter.
@@ -77,6 +84,7 @@ module Sentdm
77
84
  event: T.nilable(String),
78
85
  field: String,
79
86
  payload: T.nilable(Sentdm::InboundMessageEventPayload),
87
+ request_id: T.nilable(String),
80
88
  timestamp: String
81
89
  }
82
90
  )
@@ -6,14 +6,14 @@ module Sentdm
6
6
  OrHash =
7
7
  T.type_alias { T.any(Sentdm::MessageEvent, Sentdm::Internal::AnyHash) }
8
8
 
9
- # The specific event within the family, for example message.delivered or
10
- # message.received. Absent on events that have no subtype, so treat it as
11
- # optional.
9
+ # The specific event within the family, for example message.delivered,
10
+ # message.received or contact.opt_out. Absent on events that have no subtype, so
11
+ # treat it as optional.
12
12
  sig { returns(T.nilable(String)) }
13
13
  attr_accessor :event
14
14
 
15
- # The event family, for example message or templates. Route on this first, then on
16
- # event for the specific change.
15
+ # The event family, for example message, templates or contact. Route on this
16
+ # first, then on event for the specific change.
17
17
  sig { returns(T.nilable(String)) }
18
18
  attr_reader :field
19
19
 
@@ -31,6 +31,10 @@ module Sentdm
31
31
  end
32
32
  attr_writer :payload
33
33
 
34
+ # The event-specific body.
35
+ sig { returns(T.nilable(String)) }
36
+ attr_accessor :request_id
37
+
34
38
  # When Sent emitted the event, in UTC (yyyy-MM-ddTHH:mm:ssZ). This is the emission
35
39
  # time, not the time the underlying change happened. Use the timestamp inside the
36
40
  # payload for the latter.
@@ -47,21 +51,24 @@ module Sentdm
47
51
  event: T.nilable(String),
48
52
  field: String,
49
53
  payload: T.nilable(Sentdm::MessageEventPayload::OrHash),
54
+ request_id: T.nilable(String),
50
55
  timestamp: String
51
56
  ).returns(T.attached_class)
52
57
  end
53
58
  def self.new(
54
- # The specific event within the family, for example message.delivered or
55
- # message.received. Absent on events that have no subtype, so treat it as
56
- # optional.
59
+ # The specific event within the family, for example message.delivered,
60
+ # message.received or contact.opt_out. Absent on events that have no subtype, so
61
+ # treat it as optional.
57
62
  event: nil,
58
- # The event family, for example message or templates. Route on this first, then on
59
- # event for the specific change.
63
+ # The event family, for example message, templates or contact. Route on this
64
+ # first, then on event for the specific change.
60
65
  field: nil,
61
66
  # Body of an outbound message lifecycle event. Delivered once per status change,
62
67
  # so a single message produces several of these as it moves toward a terminal
63
68
  # status.
64
69
  payload: nil,
70
+ # The event-specific body.
71
+ request_id: nil,
65
72
  # When Sent emitted the event, in UTC (yyyy-MM-ddTHH:mm:ssZ). This is the emission
66
73
  # time, not the time the underlying change happened. Use the timestamp inside the
67
74
  # payload for the latter.
@@ -75,6 +82,7 @@ module Sentdm
75
82
  event: T.nilable(String),
76
83
  field: String,
77
84
  payload: T.nilable(Sentdm::MessageEventPayload),
85
+ request_id: T.nilable(String),
78
86
  timestamp: String
79
87
  }
80
88
  )