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
@@ -13,12 +13,20 @@ module Sentdm
13
13
  # **A message needs a sender.** What you can send, where, and at what cost is
14
14
  # decided by the markets under **Channels** — so a recipient in a country you hold
15
15
  # no sender for is refused here rather than queued.
16
+ #
17
+ # **A message can be resent on its id.** `POST /v3/messages/{id}/resend` puts a
18
+ # finished message — typically one BLOCKED for insufficient balance — back through
19
+ # the send pipeline. It is a new attempt, not a free retry: every policy runs
20
+ # again, the message is billed again, and its status webhooks fire again. A
21
+ # FILTERED message is never resendable.
16
22
  class Messages
17
23
  # Some parameter documentations has been truncated, see
18
24
  # {Sentdm::Models::MessageRetrieveActivitiesParams} for more details.
19
25
  #
20
26
  # Retrieves the activity log for a specific message. Activities track the message
21
- # lifecycle including acceptance, processing, sending, delivery, and any errors.
27
+ # lifecycle including acceptance, processing, sending, delivery, and any errors. A
28
+ # SCHEDULED entry carries scheduled_at, the release instant in UTC as it stood at
29
+ # that moment. Other entries have no scheduled_at key.
22
30
  #
23
31
  # @overload retrieve_activities(id, x_profile_id: nil, request_options: {})
24
32
  #
@@ -46,7 +54,11 @@ module Sentdm
46
54
  # {Sentdm::Models::MessageRetrieveStatusParams} for more details.
47
55
  #
48
56
  # Retrieves the current status and details of a message by ID. Includes delivery
49
- # status, timestamps, and error information if applicable.
57
+ # status, timestamps, and error information if applicable. A message that is or
58
+ # was held for a later time (a send you scheduled with scheduled_at, or a
59
+ # quiet-hours hold) is returned as a ScheduledMessageResponse: the same fields
60
+ # plus scheduled_at, the release instant in UTC. A message sent immediately has no
61
+ # scheduled_at key.
50
62
  #
51
63
  # @overload retrieve_status(id, x_profile_id: nil, request_options: {})
52
64
  #
@@ -82,14 +94,30 @@ module Sentdm
82
94
  # insufficient balance, a template not approved for sending, or free-form content
83
95
  # with no open conversation with the contact. The send is accepted with 202 and
84
96
  # the affected messages are reported as BLOCKED on GET /messages/{id} and the
85
- # message.blocked webhook.
86
- #
87
- # @overload send_(channel: nil, sandbox: nil, template: nil, text: nil, to: nil, idempotency_key: nil, x_profile_id: nil, request_options: {})
97
+ # message.blocked webhook. To send later, set scheduled_at (ISO-8601 with an
98
+ # explicit UTC offset; a value without one is rejected) between 1 minute and 30
99
+ # days ahead: the response is a ScheduledSendMessageResponse (the same fields plus
100
+ # scheduled_at; status is still QUEUED), each message then moves to SCHEDULED, is
101
+ # held and released at that time (within a few minutes), and a message.scheduled
102
+ # webhook fires once it is held. Balance and template approval are evaluated at
103
+ # release, not at acceptance. Quiet hours are not checked when the request is
104
+ # accepted: if the time falls inside a legally protected quiet-hours window for a
105
+ # recipient, that message is moved to the next allowed time at release and a
106
+ # second message.scheduled webhook reports the new scheduled_at. An account may
107
+ # hold at most 1,000,000 scheduled messages at once (429 LIMIT_001).
108
+ #
109
+ # @overload send_(channel: nil, media_urls: nil, sandbox: nil, scheduled_at: nil, subject: nil, template: nil, text: nil, to: nil, idempotency_key: nil, x_profile_id: nil, request_options: {})
88
110
  #
89
111
  # @param channel [Array<String>, nil] Body param: Channels to broadcast on, e.g. ["whatsapp", "sms"].
90
112
  #
113
+ # @param media_urls [Array<String>, nil] Body param: Attachments for this send, as publicly fetchable https URLs. Used by
114
+ #
91
115
  # @param sandbox [Boolean] Body param: Sandbox flag - when true, the operation is simulated without side ef
92
116
  #
117
+ # @param scheduled_at [Time, nil] Body param: Optional future send time as an ISO-8601 timestamp with an explicit
118
+ #
119
+ # @param subject [String, nil] Body param: Subject line for this send, overriding the template's. MMS only; ign
120
+ #
93
121
  # @param template [Sentdm::Models::MessageSendParams::Template, nil] Body param: SDK-style template reference: resolve by ID or by name, with optiona
94
122
  #
95
123
  # @param text [String, nil] Body param: Plain-text (free-form) message body. Provide either Template or this
@@ -15,7 +15,9 @@ module Sentdm
15
15
  #
16
16
  # Creates a new message template with header, body, footer, and buttons. The
17
17
  # template can be submitted for review immediately or saved as draft for later
18
- # submission.
18
+ # submission. There is no `name` field on create — the display name is derived
19
+ # from the template's content and can be changed afterwards with
20
+ # `PUT /v3/templates/{id}`.
19
21
  #
20
22
  # @overload create(category: nil, creation_source: nil, definition: nil, language: nil, sandbox: nil, submit_for_review: nil, idempotency_key: nil, x_profile_id: nil, request_options: {})
21
23
  #
@@ -85,7 +87,31 @@ module Sentdm
85
87
  # {Sentdm::Models::TemplateUpdateParams} for more details.
86
88
  #
87
89
  # Updates an existing template's name, category, language, definition, or submits
88
- # it for review.
90
+ # it for review. While the template is in review (status PENDING, or any channel
91
+ # awaiting a verdict) its definition, category and language are frozen and a
92
+ # resubmission is refused — those requests answer 409 CONFLICT_006. The display
93
+ # name stays editable throughout.
94
+ #
95
+ # `definition`, `category` and `language` are editable only from status DRAFT,
96
+ # REJECTED or APPROVED. An edit to any of them on a template in another state
97
+ # (PAUSED, DISABLED or REVOKED) is refused with 400 VALIDATION_001 and the detail
98
+ # "Template (except display name) cannot be updated unless it is in draft or
99
+ # rejected status"; `name` stays editable in every state. `submit_for_review` on a
100
+ # PAUSED, DISABLED or REVOKED template is accepted and answers 200, but opens no
101
+ # review and does not move the status — only the reviewer can reinstate it.
102
+ #
103
+ # Editing an APPROVED template is a live edit: the new content is stored
104
+ # immediately, and sending `submit_for_review: true` re-opens review, which
105
+ # returns the affected channels to PENDING so they stop sending until they are
106
+ # approved again. The previously approved content is never sent during re-review.
107
+ # Watch the per-channel `templates` webhook events rather than assuming the
108
+ # template-level status.
109
+ #
110
+ # Templates provisioned by Sent (light-onboarding templates, whose names carry the
111
+ # reserved `sent_` prefix) are read-only: every field is refused with 400
112
+ # VALIDATION*001 and the detail "This template is read-only. Only 'submit for
113
+ # review' is allowed.", and only `submit_for_review` is accepted. A `name`
114
+ # starting with `sent*` is refused for the same reason — the prefix is reserved.
89
115
  #
90
116
  # @overload update(id, category: nil, definition: nil, language: nil, name: nil, sandbox: nil, submit_for_review: nil, idempotency_key: nil, x_profile_id: nil, request_options: {})
91
117
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sentdm
4
- VERSION = "0.31.0"
4
+ VERSION = "0.33.0"
5
5
  end
data/lib/sentdm.rb CHANGED
@@ -58,6 +58,7 @@ require_relative "sentdm/internal/templates_page"
58
58
  require_relative "sentdm/internal/webhook_events_page"
59
59
  require_relative "sentdm/internal/webhooks_page"
60
60
  require_relative "sentdm/models/mutation_request"
61
+ require_relative "sentdm/models/template_body_content"
61
62
  require_relative "sentdm/models/api_meta"
62
63
  require_relative "sentdm/models/api_response_of_contact"
63
64
  require_relative "sentdm/models/api_response_of_contact_message_summary"
@@ -72,8 +73,12 @@ require_relative "sentdm/models/brand_business_info"
72
73
  require_relative "sentdm/models/brand_compliance_info"
73
74
  require_relative "sentdm/models/brand_contact_info"
74
75
  require_relative "sentdm/models/brands_brand_data"
76
+ require_relative "sentdm/models/channel_event"
77
+ require_relative "sentdm/models/channel_event_payload"
75
78
  require_relative "sentdm/models/contact_create_params"
76
79
  require_relative "sentdm/models/contact_delete_params"
80
+ require_relative "sentdm/models/contact_event"
81
+ require_relative "sentdm/models/contact_event_payload"
77
82
  require_relative "sentdm/models/contact_list_params"
78
83
  require_relative "sentdm/models/contact_message_summary"
79
84
  require_relative "sentdm/models/contact_response"
@@ -126,7 +131,6 @@ require_relative "sentdm/models/tcr_brand_relationship"
126
131
  require_relative "sentdm/models/tcr_vertical"
127
132
  require_relative "sentdm/models/template"
128
133
  require_relative "sentdm/models/template_body"
129
- require_relative "sentdm/models/template_body_content"
130
134
  require_relative "sentdm/models/template_button"
131
135
  require_relative "sentdm/models/template_button_props"
132
136
  require_relative "sentdm/models/template_create_params"
@@ -78,6 +78,12 @@ module Sentdm
78
78
  # **A message needs a sender.** What you can send, where, and at what cost is
79
79
  # decided by the markets under **Channels** — so a recipient in a country you hold
80
80
  # no sender for is refused here rather than queued.
81
+ #
82
+ # **A message can be resent on its id.** `POST /v3/messages/{id}/resend` puts a
83
+ # finished message — typically one BLOCKED for insufficient balance — back through
84
+ # the send pipeline. It is a new attempt, not a free retry: every policy runs
85
+ # again, the message is billed again, and its status webhooks fire again. A
86
+ # FILTERED message is never resendable.
81
87
  sig { returns(Sentdm::Resources::Messages) }
82
88
  attr_reader :messages
83
89
 
@@ -0,0 +1,128 @@
1
+ # typed: strong
2
+
3
+ module Sentdm
4
+ module Models
5
+ class ChannelEvent < Sentdm::Internal::Type::BaseModel
6
+ OrHash =
7
+ T.type_alias { T.any(Sentdm::ChannelEvent, Sentdm::Internal::AnyHash) }
8
+
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
+ sig { returns(T.nilable(String)) }
13
+ attr_accessor :event
14
+
15
+ # The event family, for example message, templates or contact. Route on this
16
+ # first, then on event for the specific change.
17
+ sig { returns(T.nilable(String)) }
18
+ attr_reader :field
19
+
20
+ sig { params(field: String).void }
21
+ attr_writer :field
22
+
23
+ # Body of a channel event: where one of the customer's channels stands in
24
+ # provisioning and compliance. Delivered when a milestone moves — a registration
25
+ # filed, a verdict returned, a resubmission asked for, a sender gone live — so a
26
+ # customer's own onboarding UI does not have to poll GET /v3/channels.
27
+ #
28
+ # The subject is one item, never the account. A customer's "SMS channel" has no
29
+ # status; a market does. Country, NumberType and SenderValue name which one, so a
30
+ # customer terminating only to Kosovo never receives an event about US 10DLC.
31
+ #
32
+ # Status is the stable half of the contract. It is the same four-value set GET
33
+ # /v3/channels publishes, computed through the same code, so an event and a read
34
+ # of the same market cannot disagree. A subscriber that reads nothing but the
35
+ # status and the subject fields is a correct subscriber. The sub-type on the
36
+ # envelope names the specific milestone and is additive — that vocabulary comes
37
+ # from registries and carriers, which are parties Sent does not control.
38
+ #
39
+ # Status means provisioning and compliance are complete, not that a send will
40
+ # succeed right now. An account can be suspended, or a destination blocked by a
41
+ # routing rule, without either showing up here. Those are separate surfaces and
42
+ # deliberately not modelled on this payload.
43
+ sig { returns(T.nilable(Sentdm::ChannelEventPayload)) }
44
+ attr_reader :payload
45
+
46
+ sig do
47
+ params(payload: T.nilable(Sentdm::ChannelEventPayload::OrHash)).void
48
+ end
49
+ attr_writer :payload
50
+
51
+ # The event-specific body.
52
+ sig { returns(T.nilable(String)) }
53
+ attr_accessor :request_id
54
+
55
+ # When Sent emitted the event, in UTC (yyyy-MM-ddTHH:mm:ssZ). This is the emission
56
+ # time, not the time the underlying change happened. Use the timestamp inside the
57
+ # payload for the latter.
58
+ sig { returns(T.nilable(String)) }
59
+ attr_reader :timestamp
60
+
61
+ sig { params(timestamp: String).void }
62
+ attr_writer :timestamp
63
+
64
+ # The envelope Sent POSTs to a subscribed webhook endpoint. Every event shares
65
+ # this shape and varies only in Payload.
66
+ sig do
67
+ params(
68
+ event: T.nilable(String),
69
+ field: String,
70
+ payload: T.nilable(Sentdm::ChannelEventPayload::OrHash),
71
+ request_id: T.nilable(String),
72
+ timestamp: String
73
+ ).returns(T.attached_class)
74
+ end
75
+ def self.new(
76
+ # The specific event within the family, for example message.delivered,
77
+ # message.received or contact.opt_out. Absent on events that have no subtype, so
78
+ # treat it as optional.
79
+ event: nil,
80
+ # The event family, for example message, templates or contact. Route on this
81
+ # first, then on event for the specific change.
82
+ field: nil,
83
+ # Body of a channel event: where one of the customer's channels stands in
84
+ # provisioning and compliance. Delivered when a milestone moves — a registration
85
+ # filed, a verdict returned, a resubmission asked for, a sender gone live — so a
86
+ # customer's own onboarding UI does not have to poll GET /v3/channels.
87
+ #
88
+ # The subject is one item, never the account. A customer's "SMS channel" has no
89
+ # status; a market does. Country, NumberType and SenderValue name which one, so a
90
+ # customer terminating only to Kosovo never receives an event about US 10DLC.
91
+ #
92
+ # Status is the stable half of the contract. It is the same four-value set GET
93
+ # /v3/channels publishes, computed through the same code, so an event and a read
94
+ # of the same market cannot disagree. A subscriber that reads nothing but the
95
+ # status and the subject fields is a correct subscriber. The sub-type on the
96
+ # envelope names the specific milestone and is additive — that vocabulary comes
97
+ # from registries and carriers, which are parties Sent does not control.
98
+ #
99
+ # Status means provisioning and compliance are complete, not that a send will
100
+ # succeed right now. An account can be suspended, or a destination blocked by a
101
+ # routing rule, without either showing up here. Those are separate surfaces and
102
+ # deliberately not modelled on this payload.
103
+ payload: nil,
104
+ # The event-specific body.
105
+ request_id: nil,
106
+ # When Sent emitted the event, in UTC (yyyy-MM-ddTHH:mm:ssZ). This is the emission
107
+ # time, not the time the underlying change happened. Use the timestamp inside the
108
+ # payload for the latter.
109
+ timestamp: nil
110
+ )
111
+ end
112
+
113
+ sig do
114
+ override.returns(
115
+ {
116
+ event: T.nilable(String),
117
+ field: String,
118
+ payload: T.nilable(Sentdm::ChannelEventPayload),
119
+ request_id: T.nilable(String),
120
+ timestamp: String
121
+ }
122
+ )
123
+ end
124
+ def to_hash
125
+ end
126
+ end
127
+ end
128
+ end