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.
Files changed (70) 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_payload.rb +154 -7
  6. data/lib/sentdm/models/contact_event.rb +15 -7
  7. data/lib/sentdm/models/contact_event_payload.rb +77 -16
  8. data/lib/sentdm/models/conversation_messages_list.rb +214 -6
  9. data/lib/sentdm/models/inbound_message_event_payload.rb +70 -3
  10. data/lib/sentdm/models/me_retrieve_response.rb +21 -1
  11. data/lib/sentdm/models/message_event_payload.rb +42 -1
  12. data/lib/sentdm/models/message_retrieve_activities_response.rb +42 -5
  13. data/lib/sentdm/models/message_retrieve_status_response.rb +222 -8
  14. data/lib/sentdm/models/message_send_params.rb +67 -3
  15. data/lib/sentdm/models/message_send_response.rb +13 -4
  16. data/lib/sentdm/models/template_body.rb +82 -1
  17. data/lib/sentdm/models/template_create_params.rb +11 -1
  18. data/lib/sentdm/models/template_header.rb +91 -3
  19. data/lib/sentdm/models/template_variable.rb +15 -1
  20. data/lib/sentdm/models/webhook_create_params.rb +31 -1
  21. data/lib/sentdm/models/webhook_list_events_response.rb +497 -9
  22. data/lib/sentdm/models/webhook_update_params.rb +31 -1
  23. data/lib/sentdm/resources/me.rb +5 -0
  24. data/lib/sentdm/resources/messages.rb +33 -5
  25. data/lib/sentdm/resources/templates.rb +3 -1
  26. data/lib/sentdm/resources/webhooks.rb +9 -3
  27. data/lib/sentdm/version.rb +1 -1
  28. data/lib/sentdm.rb +1 -1
  29. data/rbi/sentdm/client.rbi +6 -0
  30. data/rbi/sentdm/models/channel_event_payload.rbi +273 -10
  31. data/rbi/sentdm/models/contact_event.rbi +28 -12
  32. data/rbi/sentdm/models/contact_event_payload.rbi +118 -28
  33. data/rbi/sentdm/models/conversation_messages_list.rbi +308 -10
  34. data/rbi/sentdm/models/inbound_message_event_payload.rbi +110 -2
  35. data/rbi/sentdm/models/me_retrieve_response.rbi +35 -0
  36. data/rbi/sentdm/models/message_event_payload.rbi +50 -0
  37. data/rbi/sentdm/models/message_retrieve_activities_response.rbi +49 -5
  38. data/rbi/sentdm/models/message_retrieve_status_response.rbi +320 -12
  39. data/rbi/sentdm/models/message_send_params.rbi +100 -2
  40. data/rbi/sentdm/models/message_send_response.rbi +15 -5
  41. data/rbi/sentdm/models/template_body.rbi +133 -0
  42. data/rbi/sentdm/models/template_create_params.rbi +15 -0
  43. data/rbi/sentdm/models/template_header.rbi +143 -2
  44. data/rbi/sentdm/models/template_variable.rbi +10 -0
  45. data/rbi/sentdm/models/webhook_create_params.rbi +61 -0
  46. data/rbi/sentdm/models/webhook_list_events_response.rbi +747 -12
  47. data/rbi/sentdm/models/webhook_update_params.rbi +61 -0
  48. data/rbi/sentdm/resources/me.rbi +5 -0
  49. data/rbi/sentdm/resources/messages.rbi +58 -3
  50. data/rbi/sentdm/resources/templates.rbi +6 -0
  51. data/rbi/sentdm/resources/webhooks.rbi +15 -1
  52. data/sig/sentdm/models/channel_event_payload.rbs +62 -0
  53. data/sig/sentdm/models/contact_event_payload.rbs +24 -9
  54. data/sig/sentdm/models/conversation_messages_list.rbs +99 -6
  55. data/sig/sentdm/models/inbound_message_event_payload.rbs +37 -0
  56. data/sig/sentdm/models/me_retrieve_response.rbs +7 -0
  57. data/sig/sentdm/models/message_event_payload.rbs +20 -0
  58. data/sig/sentdm/models/message_retrieve_activities_response.rbs +15 -0
  59. data/sig/sentdm/models/message_retrieve_status_response.rbs +99 -6
  60. data/sig/sentdm/models/message_send_params.rbs +15 -0
  61. data/sig/sentdm/models/template_body.rbs +44 -0
  62. data/sig/sentdm/models/template_create_params.rbs +7 -0
  63. data/sig/sentdm/models/template_header.rbs +44 -0
  64. data/sig/sentdm/models/webhook_create_params.rbs +29 -0
  65. data/sig/sentdm/models/webhook_list_events_response.rbs +252 -0
  66. data/sig/sentdm/models/webhook_update_params.rbs +29 -0
  67. data/sig/sentdm/resources/messages.rbs +3 -0
  68. data/sig/sentdm/resources/templates.rbs +1 -0
  69. data/sig/sentdm/resources/webhooks.rbs +2 -0
  70. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5dab566c65206bbd97b0e29e8660f25932a22d58359db63e20c4d4ba9cbd8dec
4
- data.tar.gz: 5e097f125343b76d26132686ff963dcfba40c316b6e9a8a4b13dc0fd493014aa
3
+ metadata.gz: 8b4444164d11b8913195b89a66ba9d140e5edaca680199f80156774e39f3f893
4
+ data.tar.gz: 38b18a67c9dc58ed79f990686d0363fbab3138b66c9a2e3b20eb76ba0d4d4988
5
5
  SHA512:
6
- metadata.gz: a47bec3101129a85381094c226cf6be44786562b5a882683bcc6c40dbeeb40d6da8ef8dd4a47254a7f6dc09cefea91655170baa7495755a54d922d127f0d6e56
7
- data.tar.gz: a5239a8ae31862ca952d547205f9fd35b909f3bf43320f45afbed14f881110de646b5697a2f247b43bc91861ef5df95f43b5f6353becce01a133086bf844bb6b
6
+ metadata.gz: bd38b5407cb704af0bf1cfecccb4f4bdcc2b5b173ac638d7c3f4c8e5a6039a019637d46114d6c082ebc420f7ad3532cfd128493f56d7bff51c62abc62cf34461
7
+ data.tar.gz: 3a79e6d405c70edc8e4479f28dc4955c0e0a3fbfaa59da458848c831e99650d90e87c672316609514fb9d5bd4d2b61d194d3f54a31d6c7ecac9340b12117e887
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.34.0](https://github.com/sentdm/sent-dm-ruby/compare/v0.33.0...v0.34.0) (2026-09-30)
4
+
5
+
6
+ ### Features
7
+
8
+ * **api:** sync OpenAPI spec from production ([d7d4ecf](https://github.com/sentdm/sent-dm-ruby/commit/d7d4ecf5dd378e69ee6f5148b816554ebbf1a6bf))
9
+
10
+ ## [0.33.0](https://github.com/sentdm/sent-dm-ruby/compare/v0.32.0...v0.33.0) (2026-09-30)
11
+
12
+
13
+ ### Features
14
+
15
+ * **api:** sync generated SDKs from the committed spec ([c68607e](https://github.com/sentdm/sent-dm-ruby/commit/c68607ed78d4a03f1c3c03d36440985cd5eedceb))
16
+ * **api:** sync OpenAPI spec from production ([ceb47d9](https://github.com/sentdm/sent-dm-ruby/commit/ceb47d9ddc2d46144e5f81b0ef4bc7693b1f435f))
17
+ * **api:** sync OpenAPI spec from production ([8c92eb5](https://github.com/sentdm/sent-dm-ruby/commit/8c92eb52bff195424d14d09eff8f131edc640918))
18
+
3
19
  ## [0.32.0](https://github.com/sentdm/sent-dm-ruby/compare/v0.31.0...v0.32.0) (2026-09-18)
4
20
 
5
21
 
data/README.md CHANGED
@@ -17,7 +17,7 @@ To use this gem, install via Bundler by adding the following to your application
17
17
  <!-- x-release-please-start-version -->
18
18
 
19
19
  ```ruby
20
- gem "sentdm", "~> 0.32.0"
20
+ gem "sentdm", "~> 0.34.0"
21
21
  ```
22
22
 
23
23
  <!-- x-release-please-end -->
data/lib/sentdm/client.rb CHANGED
@@ -83,6 +83,12 @@ module Sentdm
83
83
  # **A message needs a sender.** What you can send, where, and at what cost is
84
84
  # decided by the markets under **Channels** — so a recipient in a country you hold
85
85
  # no sender for is refused here rather than queued.
86
+ #
87
+ # **A message can be resent on its id.** `POST /v3/messages/{id}/resend` puts a
88
+ # finished message — typically one BLOCKED for insufficient balance — back through
89
+ # the send pipeline. It is a new attempt, not a free retry: every policy runs
90
+ # again, the message is billed again, and its status webhooks fire again. A
91
+ # FILTERED message is never resendable.
86
92
  # @return [Sentdm::Resources::Messages]
87
93
  attr_reader :messages
88
94
 
@@ -16,7 +16,9 @@ module Sentdm
16
16
  # The account whose market this is, named as on every other family. When an
17
17
  # organization receives an event for one of its sender profiles this is the
18
18
  # profile, so a reseller compares it with its own id and anything different is one
19
- # of its profiles.
19
+ # of its profiles. Matches customer_id on GET /v3/channels and the sender
20
+ # profile's id. Together with channel, country, and number_type, it identifies the
21
+ # market.
20
22
  #
21
23
  # @return [String, nil]
22
24
  optional :account_id, String
@@ -29,6 +31,28 @@ module Sentdm
29
31
  # @return [String, nil]
30
32
  optional :channel, String
31
33
 
34
+ # @!attribute compliance
35
+ # What a market has been given: the identity it registers under, its programme,
36
+ # and any documents attached.
37
+ #
38
+ # What it does not carry is what the market asks for. That is the subject of GET
39
+ # /v3/compliance/requirements, and it is the same answer for every caller — a
40
+ # description of what a compliance regime wants, not a record of one customer's
41
+ # progress through it. It was reported here as well for a while, which put the
42
+ # same array in six response shapes and left a caller deciding which of two
43
+ # sources to believe.
44
+ #
45
+ # Present on a list read for markets that register (carrying brand and campaign),
46
+ # but with documents absent — documents are not fetched for a list, because a
47
+ # catalog lookup and a document read per market would multiply across a page.
48
+ # Absent documents is distinct from an empty list: absent says they were not
49
+ # fetched; empty says the market has been given none. The parent object is null
50
+ # only when the market registers with nobody and compliance was not computed —
51
+ # nothing to show at all.
52
+ #
53
+ # @return [Sentdm::Models::ChannelEventPayload::Compliance, nil]
54
+ optional :compliance, -> { Sentdm::ChannelEventPayload::Compliance }, nil?: true
55
+
32
56
  # @!attribute number_type
33
57
  # The kind of sender the market uses, for example TEN_DLC, LOCAL, or ALPHANUMERIC.
34
58
  # Omitted when the subject has no sender type of its own.
@@ -37,14 +61,22 @@ module Sentdm
37
61
  optional :number_type, String, nil?: true
38
62
 
39
63
  # @!attribute reason
40
- # Why the market reached this state, when a reason was given — a correction
41
- # explained, or a campaign lapse. Free text, passed through from the registry or
42
- # carrier that wrote it, so treat it as a message to show a human rather than a
43
- # value to branch on.
64
+ # Why the market reached this state, as a sentence to show a person: the specific
65
+ # explanation when one was given (a correction explained, a campaign lapse),
66
+ # otherwise what reason_code means for this market. Not a value to branch on.
44
67
  #
45
68
  # @return [String, nil]
46
69
  optional :reason, String, nil?: true
47
70
 
71
+ # @!attribute reason_code
72
+ # Why the market is not ACTIVE, as a stable code: an ErrorCodes CHANNEL_xxx value
73
+ # such as CHANNEL_001 (something you owe) or CHANNEL_002 (a correction was
74
+ # requested). The same code the channels resource reports for the market. Switch
75
+ # on this rather than on reason. Omitted while ACTIVE.
76
+ #
77
+ # @return [String, nil]
78
+ optional :reason_code, String, nil?: true
79
+
48
80
  # @!attribute sender_value
49
81
  # The sender itself — a number in E.164, or an alphanumeric sender ID.
50
82
  #
@@ -83,7 +115,7 @@ module Sentdm
83
115
  # @return [String, nil]
84
116
  optional :updated_at, String
85
117
 
86
- # @!method initialize(country:, account_id: nil, channel: nil, number_type: nil, reason: nil, sender_value: nil, status: nil, updated_at: nil)
118
+ # @!method initialize(country:, account_id: nil, channel: nil, compliance: nil, number_type: nil, reason: nil, reason_code: nil, sender_value: nil, status: nil, updated_at: nil)
87
119
  # Some parameter documentations has been truncated, see
88
120
  # {Sentdm::Models::ChannelEventPayload} for more details.
89
121
  #
@@ -114,15 +146,130 @@ module Sentdm
114
146
  #
115
147
  # @param channel [String] The channel this market belongs to: sms, whatsapp, or rcs. Never
116
148
  #
149
+ # @param compliance [Sentdm::Models::ChannelEventPayload::Compliance, nil] What a market has been given: the identity it registers under, its programme, an
150
+ #
117
151
  # @param number_type [String, nil] The kind of sender the market uses, for example TEN_DLC, LOCAL, or
118
152
  #
119
- # @param reason [String, nil] Why the market reached this state, when a reason was given — a correction explai
153
+ # @param reason [String, nil] Why the market reached this state, as a sentence to show a person: the specific
154
+ #
155
+ # @param reason_code [String, nil] Why the market is not ACTIVE, as a stable code: an ErrorCodes CHANNEL_xxx value
120
156
  #
121
157
  # @param sender_value [String, nil] The sender itself — a number in E.164, or an alphanumeric sender ID.
122
158
  #
123
159
  # @param status [String] Where the market stands: PENDING_REVIEW, ACTION_NEEDED, PROVISIONING,
124
160
  #
125
161
  # @param updated_at [String] When the transition happened, in UTC (yyyy-MM-ddTHH:mm:ssZ).
162
+
163
+ # @see Sentdm::Models::ChannelEventPayload#compliance
164
+ class Compliance < Sentdm::Internal::Type::BaseModel
165
+ # @!attribute brand
166
+ # The identity this market registers under, with inherit saying whose it is.
167
+ #
168
+ # Reported here rather than on the profile because it belongs to the registration
169
+ # this market files, and only one market files one. It was a top-level block for a
170
+ # while, which put a per-registration value beside a list of markets and left a
171
+ # caller to work out which market it belonged to.
172
+ #
173
+ # Absent for a market that registers with nobody — such a market asks for no
174
+ # identity, so there is none to report. Absent and null mean different things:
175
+ # absent says this market does not ask, null would say it asks and nothing was
176
+ # supplied.
177
+ #
178
+ # Untyped, like the request side, because its members are declared by the market's
179
+ # own schema rather than by a C# class. A typed pair here would be a second
180
+ # definition of what a market wants, free to drift from the one that validates.
181
+ #
182
+ # @return [Hash{Symbol=>Object}, nil]
183
+ optional :brand, Sentdm::Internal::Type::HashOf[Sentdm::Internal::Type::Unknown], nil?: true
184
+
185
+ # @!attribute campaign
186
+ # The programme this market registers, with inherit saying whose it is.
187
+ #
188
+ # One, not a list. TcrCampaigns permits several and an account built on the admin
189
+ # side may hold them, but this surface offers one — which is what lets the
190
+ # market's PATCH be an upsert rather than a collection with an addressable create
191
+ # behind it. An account holding several is reported as its first and refused on
192
+ # write, rather than half-edited.
193
+ #
194
+ # Carries no id. Nothing addresses a campaign, and an undeclared key would be
195
+ # refused if the caller sent this object back — which it is meant to be able to
196
+ # do.
197
+ #
198
+ # @return [Hash{Symbol=>Object}, nil]
199
+ optional :campaign, Sentdm::Internal::Type::HashOf[Sentdm::Internal::Type::Unknown], nil?: true
200
+
201
+ # @!attribute documents
202
+ # What has been supplied for this market.
203
+ #
204
+ # Files, not values — the declared halves above carry the values. A document
205
+ # cannot be a JSON value, so it is sent as multipart on the channel call and
206
+ # reported here as a reference.
207
+ #
208
+ # Absent on a list read, which fetches identity but does not compute compliance
209
+ # documents per market. Absent and empty mean different things: absent says the
210
+ # documents were not fetched; empty says the market has been given none.
211
+ #
212
+ # @return [Array<Sentdm::Models::ChannelEventPayload::Compliance::Document>, nil]
213
+ optional :documents,
214
+ -> { Sentdm::Internal::Type::ArrayOf[Sentdm::ChannelEventPayload::Compliance::Document] },
215
+ nil?: true
216
+
217
+ # @!method initialize(brand: nil, campaign: nil, documents: nil)
218
+ # Some parameter documentations has been truncated, see
219
+ # {Sentdm::Models::ChannelEventPayload::Compliance} for more details.
220
+ #
221
+ # What a market has been given: the identity it registers under, its programme,
222
+ # and any documents attached.
223
+ #
224
+ # What it does not carry is what the market asks for. That is the subject of GET
225
+ # /v3/compliance/requirements, and it is the same answer for every caller — a
226
+ # description of what a compliance regime wants, not a record of one customer's
227
+ # progress through it. It was reported here as well for a while, which put the
228
+ # same array in six response shapes and left a caller deciding which of two
229
+ # sources to believe.
230
+ #
231
+ # Present on a list read for markets that register (carrying brand and campaign),
232
+ # but with documents absent — documents are not fetched for a list, because a
233
+ # catalog lookup and a document read per market would multiply across a page.
234
+ # Absent documents is distinct from an empty list: absent says they were not
235
+ # fetched; empty says the market has been given none. The parent object is null
236
+ # only when the market registers with nobody and compliance was not computed —
237
+ # nothing to show at all.
238
+ #
239
+ # @param brand [Hash{Symbol=>Object}, nil] The identity this market registers under, with inherit saying whose it is.
240
+ #
241
+ # @param campaign [Hash{Symbol=>Object}, nil] The programme this market registers, with inherit saying whose it is.
242
+ #
243
+ # @param documents [Array<Sentdm::Models::ChannelEventPayload::Compliance::Document>, nil] What has been supplied for this market.
244
+
245
+ class Document < Sentdm::Internal::Type::BaseModel
246
+ # @!attribute document_id
247
+ # Identifier of the upload, for fetching it back through the documents endpoints.
248
+ #
249
+ # @return [String, nil]
250
+ optional :document_id, String, nil?: true
251
+
252
+ # @!attribute file_name
253
+ #
254
+ # @return [String, nil]
255
+ optional :file_name, String, nil?: true
256
+
257
+ # @!attribute key
258
+ # The catalog's name for this document, matching the requirement it satisfies.
259
+ #
260
+ # @return [String, nil]
261
+ optional :key, String
262
+
263
+ # @!method initialize(document_id: nil, file_name: nil, key: nil)
264
+ # A document a market asked for and has been given.
265
+ #
266
+ # @param document_id [String, nil] Identifier of the upload, for fetching it back through the documents endpoints.
267
+ #
268
+ # @param file_name [String, nil]
269
+ #
270
+ # @param key [String] The catalog's name for this document, matching the requirement it satisfies.
271
+ end
272
+ end
126
273
  end
127
274
  end
128
275
  end
@@ -19,17 +19,25 @@ module Sentdm
19
19
  optional :field, String
20
20
 
21
21
  # @!attribute payload
22
- # Body of a contact.opt_in, contact.opt_out or contact.help event. Delivered when
23
- # a contact signals a consent change or asks for help.
22
+ # Body of a contact.opt_in, contact.opt_out, contact.help or
23
+ # contact.custom_keyword event. Delivered when a contact signals a consent change,
24
+ # asks for help, or sends one of your own auto-reply keywords.
24
25
  #
25
26
  # These events state the signal outright, so you do not have to recognise keywords
26
27
  # in the text of a message.received event. They also cover cases that produce no
27
28
  # inbound message at all, such as a network handling an opt-out on your behalf.
28
29
  #
29
- # Fields are ordered identity → resulting state → provenance → join key. Nothing
30
- # here restates the envelope: which of the three signals occurred is the
31
- # envelope's event, and when it was emitted is its timestamp. Retries carry the
32
- # same X-Webhook-Event-ID header, which is what to deduplicate on.
30
+ # Two of the four change consent and two do not: contact.help and
31
+ # contact.custom_keyword report the state the contact already had. Read opt_out
32
+ # for the state and the envelope's event for what happened, rather than inferring
33
+ # one from the other.
34
+ #
35
+ # Fields are ordered identity → resulting state → provenance → join keys. The two
36
+ # parties are from and to. Note that the message family has not moved to those
37
+ # names yet — message.received still calls the same two parties inbound_number and
38
+ # outbound_number. Nothing here restates the envelope: which signal occurred is
39
+ # the envelope's event, and when it was emitted is its timestamp. Retries carry
40
+ # the same X-Webhook-Event-ID header, which is what to deduplicate on.
33
41
  #
34
42
  # @return [Sentdm::Models::ContactEventPayload, nil]
35
43
  optional :payload, -> { Sentdm::ContactEventPayload }, nil?: true
@@ -59,7 +67,7 @@ module Sentdm
59
67
  #
60
68
  # @param field [String] The event family, for example message, templates or contact. Route on
61
69
  #
62
- # @param payload [Sentdm::Models::ContactEventPayload, nil] Body of a contact.opt_in, contact.opt_out or contact.help event. Delivered
70
+ # @param payload [Sentdm::Models::ContactEventPayload, nil] Body of a contact.opt_in, contact.opt_out, contact.help or
63
71
  #
64
72
  # @param request_id [String, nil] The event-specific body.
65
73
  #
@@ -5,8 +5,9 @@ module Sentdm
5
5
  class ContactEventPayload < Sentdm::Internal::Type::BaseModel
6
6
  # @!attribute opt_out
7
7
  # Whether the contact is opted out after this signal — the state to write to your
8
- # own record. Same meaning as opt_out on the contact resource. On contact.help
9
- # this reports the contact's existing state, which help does not change.
8
+ # own record. Same meaning as opt_out on the contact resource. On contact.help and
9
+ # contact.custom_keyword this reports the contact's existing state, which neither
10
+ # changes.
10
11
  #
11
12
  # Two signals from the same contact can arrive out of order, because each one is
12
13
  # queued on its own rather than against the contact. Compare the envelope's
@@ -33,6 +34,18 @@ module Sentdm
33
34
  # @return [String, nil]
34
35
  optional :account_id, String
35
36
 
37
+ # @!attribute agent_id
38
+ # The RCS agent the signal reached, when it reached one.
39
+ #
40
+ # Omitted entirely on channels that have no agent, rather than sent as null — an
41
+ # SMS or WhatsApp payload does not carry this key at all. On RCS it is the
42
+ # counterpart to To: a contact reaches an agent rather than a number, so exactly
43
+ # one of the two is populated and never both. If you run more than one agent, this
44
+ # is what tells you which of them the contact acted on.
45
+ #
46
+ # @return [String, nil]
47
+ optional :agent_id, String, nil?: true
48
+
36
49
  # @!attribute channel
37
50
  # The channel the signal arrived on, for example sms or whatsapp.
38
51
  #
@@ -41,12 +54,20 @@ module Sentdm
41
54
 
42
55
  # @!attribute contact_id
43
56
  # The contact who raised the signal. Always populated, including for contact.help
44
- # from a number you have not messaged before — the contact is created if it does
45
- # not exist yet, so this identifier is always resolvable against the contacts API.
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.
46
60
  #
47
61
  # @return [String, nil]
48
62
  optional :contact_id, String
49
63
 
64
+ # @!attribute from
65
+ # The contact's number, in E.164 format with the leading + — who raised the
66
+ # signal. The same party message.received publishes as inbound_number.
67
+ #
68
+ # @return [String, nil]
69
+ optional :from, String
70
+
50
71
  # @!attribute message_id
51
72
  # The inbound message that carried the signal, matching message_id on the
52
73
  # corresponding message.received event so the two can be joined.
@@ -60,12 +81,21 @@ module Sentdm
60
81
  # @return [String, nil]
61
82
  optional :message_id, String, nil?: true
62
83
 
63
- # @!attribute phone_number
64
- # The contact's number in E.164 format. Same value as phone_number on the contact
65
- # resource.
84
+ # @!attribute template_id
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.
66
96
  #
67
97
  # @return [String, nil]
68
- optional :phone_number, String
98
+ optional :template_id, String, nil?: true
69
99
 
70
100
  # @!attribute text
71
101
  # The text the contact sent, for example STOP or UNSUBSCRIBE. Sent as null when
@@ -75,21 +105,46 @@ module Sentdm
75
105
  # @return [String, nil]
76
106
  optional :text, String, nil?: true
77
107
 
78
- # @!method initialize(opt_out:, source:, account_id: nil, channel: nil, contact_id: nil, message_id: nil, phone_number: nil, text: nil)
108
+ # @!attribute to
109
+ # The number of yours that received the signal, in E.164 format with the leading
110
+ # +. Tells a multi-number account which of its senders the contact acted on, which
111
+ # nothing else on this payload answers.
112
+ #
113
+ # This is your number, not the contact's. That is the opposite of what to means on
114
+ # POST /v3/messages, where it is the list of recipients you are sending to. Reply
115
+ # to From, not to this field, or the message goes back to yourself.
116
+ #
117
+ # Sent as null when the signal did not arrive at a number of yours — an RCS signal
118
+ # terminates at an agent rather than a number, and a provider-reported opt-out may
119
+ # name no receiving number at all. The field is always present, so read it and
120
+ # check for null rather than checking whether the key exists.
121
+ #
122
+ # @return [String, nil]
123
+ optional :to, String, nil?: true
124
+
125
+ # @!method initialize(opt_out:, source:, account_id: nil, agent_id: nil, channel: nil, contact_id: nil, from: nil, message_id: nil, template_id: nil, text: nil, to: nil)
79
126
  # Some parameter documentations has been truncated, see
80
127
  # {Sentdm::Models::ContactEventPayload} for more details.
81
128
  #
82
- # Body of a contact.opt_in, contact.opt_out or contact.help event. Delivered when
83
- # a contact signals a consent change or asks for help.
129
+ # Body of a contact.opt_in, contact.opt_out, contact.help or
130
+ # contact.custom_keyword event. Delivered when a contact signals a consent change,
131
+ # asks for help, or sends one of your own auto-reply keywords.
84
132
  #
85
133
  # These events state the signal outright, so you do not have to recognise keywords
86
134
  # in the text of a message.received event. They also cover cases that produce no
87
135
  # inbound message at all, such as a network handling an opt-out on your behalf.
88
136
  #
89
- # Fields are ordered identity → resulting state → provenance → join key. Nothing
90
- # here restates the envelope: which of the three signals occurred is the
91
- # envelope's event, and when it was emitted is its timestamp. Retries carry the
92
- # same X-Webhook-Event-ID header, which is what to deduplicate on.
137
+ # Two of the four change consent and two do not: contact.help and
138
+ # contact.custom_keyword report the state the contact already had. Read opt_out
139
+ # for the state and the envelope's event for what happened, rather than inferring
140
+ # one from the other.
141
+ #
142
+ # Fields are ordered identity → resulting state → provenance → join keys. The two
143
+ # parties are from and to. Note that the message family has not moved to those
144
+ # names yet — message.received still calls the same two parties inbound_number and
145
+ # outbound_number. Nothing here restates the envelope: which signal occurred is
146
+ # the envelope's event, and when it was emitted is its timestamp. Retries carry
147
+ # the same X-Webhook-Event-ID header, which is what to deduplicate on.
93
148
  #
94
149
  # @param opt_out [Boolean] Whether the contact is opted out after this signal — the state to write to your
95
150
  #
@@ -97,15 +152,21 @@ module Sentdm
97
152
  #
98
153
  # @param account_id [String] The account the contact belongs to. Present so one endpoint can serve several ac
99
154
  #
155
+ # @param agent_id [String, nil] The RCS agent the signal reached, when it reached one.
156
+ #
100
157
  # @param channel [String] The channel the signal arrived on, for example sms or whatsapp.
101
158
  #
102
159
  # @param contact_id [String] The contact who raised the signal. Always populated, including for contact.help
103
160
  #
161
+ # @param from [String] The contact's number, in E.164 format with the leading + — who raised the signal
162
+ #
104
163
  # @param message_id [String, nil] The inbound message that carried the signal, matching message_id on the
105
164
  #
106
- # @param phone_number [String] The contact's number in E.164 format. Same value as phone_number on the contact
165
+ # @param template_id [String, nil] The auto-reply template whose keyword the contact matched, joinable against the
107
166
  #
108
167
  # @param text [String, nil] The text the contact sent, for example STOP or UNSUBSCRIBE. Sent as
168
+ #
169
+ # @param to [String, nil] The number of yours that received the signal, in E.164 format with the leading +
109
170
  end
110
171
  end
111
172
  end