trycourier 6.1.0 → 6.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62f640ccc5d992cd807b750192ee8ca02b3ffe5fa09537eeadf67ba086c518b3
4
- data.tar.gz: bd638a13b9a78b54e849e76a30614bed55afbcb6e7fb7a1a2edf60a74cb1531b
3
+ metadata.gz: 0f0b22ca9267f965731c89199aa8d49077c5ac53f12c307946893c67a9ee7896
4
+ data.tar.gz: abeea8195ccb031cebe6a83096665851ee7d6bae0e2743e2d7a3504af35b8f47
5
5
  SHA512:
6
- metadata.gz: ed8c416e8431f1a50aa7fff01b939ba42b03acabe3a42a5a9f14da078f9dcf11bfd8cfe6cb88f642d48444aa0131c3eb9a9164fdbd6fec8a6d80d07c2f360403
7
- data.tar.gz: 971c6a9a71bfdbc8faec0796d2b591d3635e55aece1ab1c208c6f68f3943a5fb39214c8a5944815b1f70f6e9912b8c77d8db2971d836116c543660a0951ef4a2
6
+ metadata.gz: 6c81dbe75df19bf95658f341e62e7475db0007be7ead3a8f822e3e8ce9a8c7424dcaefe76ee629c47bc798211e49e574a81d55b62426fd46a0d022ec61122fa3
7
+ data.tar.gz: 14dfa346c595b581a2ebbe8467e5452af68d04a64638b7347139287f79e05417394ae5ae5508634e209d2618bd821b00b688ecdc1320c6146e6e5587599a4e28
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [6.2.0](https://github.com/trycourier/courier-ruby/compare/v6.1.0...v6.2.0) (2026-08-26)
4
+
5
+
6
+ ### Features
7
+
8
+ * **api:** document the template send metrics endpoint ([#134](https://github.com/trycourier/courier-ruby/issues/134)) ([cd882b5](https://github.com/trycourier/courier-ruby/commit/cd882b5a4e1b1dee40c24fd2bec65f07ed10db8a))
9
+
3
10
  ## [6.1.0](https://github.com/trycourier/courier-ruby/compare/v6.0.0...v6.1.0) (2026-08-19)
4
11
 
5
12
 
data/README.md CHANGED
@@ -9,7 +9,7 @@ Add the gem to your `Gemfile`:
9
9
  <!-- x-release-please-start-version -->
10
10
 
11
11
  ```ruby
12
- gem "trycourier", "~> 6.1.0"
12
+ gem "trycourier", "~> 6.2.0"
13
13
  ```
14
14
 
15
15
  <!-- x-release-please-end -->
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Courier
4
+ module Models
5
+ # @see Courier::Resources::Notifications#get_metrics
6
+ class NotificationGetMetricsParams < Courier::Internal::Type::BaseModel
7
+ extend Courier::Internal::Type::RequestParameters::Converter
8
+ include Courier::Internal::Type::RequestParameters
9
+
10
+ # @!attribute id
11
+ #
12
+ # @return [String]
13
+ required :id, String
14
+
15
+ # @!attribute end_
16
+ # The end of the window, as an ISO 8601 timestamp with an offset. Must be supplied
17
+ # together with `start`. An `end` in the future is accepted and not clamped — the
18
+ # trailing buckets come back empty.
19
+ #
20
+ # @return [Time, nil]
21
+ optional :end_, Time
22
+
23
+ # @!attribute granularity
24
+ # The size of each bucket in the series. Defaults to `DAY`. `WEEK` buckets start
25
+ # on Sunday. A fine granularity caps the window it can cover: `HOUR` spans at most
26
+ # 7 days and `DAY` at most 90 days, and a wider window returns `400` — request a
27
+ # coarser granularity instead. `WEEK` and `MONTH` are uncapped, subject to the
28
+ # 1000-bucket limit on a single response.
29
+ #
30
+ # @return [Symbol, Courier::Models::NotificationGetMetricsParams::Granularity, nil]
31
+ optional :granularity, enum: -> { Courier::NotificationGetMetricsParams::Granularity }
32
+
33
+ # @!attribute lookback
34
+ # The length of the window, counted back from now, as an ISO 8601 duration
35
+ # (`P30D`, `P12W`, `PT12H`). Defaults to `P30D`, and is ignored when `start` and
36
+ # `end` are supplied. A malformed or non-positive duration returns `400`.
37
+ #
38
+ # @return [String, nil]
39
+ optional :lookback, String
40
+
41
+ # @!attribute start
42
+ # The inclusive start of the window, as an ISO 8601 timestamp with an offset
43
+ # (`2026-04-01T00:00:00Z`). Must be supplied together with `end` and be earlier
44
+ # than it; either one alone returns `400`.
45
+ #
46
+ # @return [Time, nil]
47
+ optional :start, Time
48
+
49
+ # @!method initialize(id:, end_: nil, granularity: nil, lookback: nil, start: nil, request_options: {})
50
+ # Some parameter documentations has been truncated, see
51
+ # {Courier::Models::NotificationGetMetricsParams} for more details.
52
+ #
53
+ # @param id [String]
54
+ #
55
+ # @param end_ [Time] The end of the window, as an ISO 8601 timestamp with an offset. Must be supplied
56
+ #
57
+ # @param granularity [Symbol, Courier::Models::NotificationGetMetricsParams::Granularity] The size of each bucket in the series. Defaults to `DAY`. `WEEK` buckets start o
58
+ #
59
+ # @param lookback [String] The length of the window, counted back from now, as an ISO 8601 duration (`P30D`
60
+ #
61
+ # @param start [Time] The inclusive start of the window, as an ISO 8601 timestamp with an offset (`202
62
+ #
63
+ # @param request_options [Courier::RequestOptions, Hash{Symbol=>Object}]
64
+
65
+ # The size of each bucket in the series. Defaults to `DAY`. `WEEK` buckets start
66
+ # on Sunday. A fine granularity caps the window it can cover: `HOUR` spans at most
67
+ # 7 days and `DAY` at most 90 days, and a wider window returns `400` — request a
68
+ # coarser granularity instead. `WEEK` and `MONTH` are uncapped, subject to the
69
+ # 1000-bucket limit on a single response.
70
+ module Granularity
71
+ extend Courier::Internal::Type::Enum
72
+
73
+ HOUR = :HOUR
74
+ DAY = :DAY
75
+ WEEK = :WEEK
76
+ MONTH = :MONTH
77
+
78
+ # @!method self.values
79
+ # @return [Array<Symbol>]
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Courier
4
+ module Models
5
+ # @see Courier::Resources::Notifications#get_metrics
6
+ class NotificationMetricsResponse < Courier::Internal::Type::BaseModel
7
+ # @!attribute end_
8
+ # End of the window actually queried, ceiled onto the granularity grid.
9
+ # Second-precision UTC.
10
+ #
11
+ # @return [Time]
12
+ required :end_, Time, api_name: :end
13
+
14
+ # @!attribute granularity
15
+ # Bucket size the series was built at.
16
+ #
17
+ # @return [Symbol, Courier::Models::NotificationMetricsResponse::Granularity]
18
+ required :granularity, enum: -> { Courier::NotificationMetricsResponse::Granularity }
19
+
20
+ # @!attribute notification_id
21
+ # The template the series describes, echoed from the request.
22
+ #
23
+ # @return [String]
24
+ required :notification_id, String, api_name: :notificationId
25
+
26
+ # @!attribute series
27
+ # One entry per bucket between `start` and `end`, oldest first, including buckets
28
+ # with no activity.
29
+ #
30
+ # @return [Array<Courier::Models::NotificationMetricsResponse::Series>]
31
+ required :series, -> { Courier::Internal::Type::ArrayOf[Courier::NotificationMetricsResponse::Series] }
32
+
33
+ # @!attribute start
34
+ # Inclusive start of the window actually queried, floored onto the granularity
35
+ # grid. Second-precision UTC.
36
+ #
37
+ # @return [Time]
38
+ required :start, Time
39
+
40
+ # @!method initialize(end_:, granularity:, notification_id:, series:, start:)
41
+ # Some parameter documentations has been truncated, see
42
+ # {Courier::Models::NotificationMetricsResponse} for more details.
43
+ #
44
+ # @param end_ [Time] End of the window actually queried, ceiled onto the granularity grid. Second-pre
45
+ #
46
+ # @param granularity [Symbol, Courier::Models::NotificationMetricsResponse::Granularity] Bucket size the series was built at.
47
+ #
48
+ # @param notification_id [String] The template the series describes, echoed from the request.
49
+ #
50
+ # @param series [Array<Courier::Models::NotificationMetricsResponse::Series>] One entry per bucket between `start` and `end`, oldest first, including buckets
51
+ #
52
+ # @param start [Time] Inclusive start of the window actually queried, floored onto the granularity gri
53
+
54
+ # Bucket size the series was built at.
55
+ #
56
+ # @see Courier::Models::NotificationMetricsResponse#granularity
57
+ module Granularity
58
+ extend Courier::Internal::Type::Enum
59
+
60
+ HOUR = :HOUR
61
+ DAY = :DAY
62
+ WEEK = :WEEK
63
+ MONTH = :MONTH
64
+
65
+ # @!method self.values
66
+ # @return [Array<Symbol>]
67
+ end
68
+
69
+ class Series < Courier::Internal::Type::BaseModel
70
+ # @!attribute data
71
+ # One entry per provider and channel that handled a message in this bucket. Empty
72
+ # when nothing was sent.
73
+ #
74
+ # @return [Array<Courier::Models::NotificationMetricsResponse::Series::Data>]
75
+ required :data,
76
+ -> { Courier::Internal::Type::ArrayOf[Courier::NotificationMetricsResponse::Series::Data] }
77
+
78
+ # @!attribute period
79
+ # Start of the bucket, second-precision UTC.
80
+ #
81
+ # @return [Time]
82
+ required :period, Time
83
+
84
+ # @!method initialize(data:, period:)
85
+ # Some parameter documentations has been truncated, see
86
+ # {Courier::Models::NotificationMetricsResponse::Series} for more details.
87
+ #
88
+ # @param data [Array<Courier::Models::NotificationMetricsResponse::Series::Data>] One entry per provider and channel that handled a message in this bucket. Empty
89
+ #
90
+ # @param period [Time] Start of the bucket, second-precision UTC.
91
+
92
+ class Data < Courier::Internal::Type::BaseModel
93
+ # @!attribute channel
94
+ # Channel the provider delivered on, e.g. `email`.
95
+ #
96
+ # @return [String]
97
+ required :channel, String
98
+
99
+ # @!attribute clicked
100
+ # Messages with at least one tracked link click.
101
+ #
102
+ # @return [Integer]
103
+ required :clicked, Integer
104
+
105
+ # @!attribute delivered
106
+ # Messages the provider confirmed as delivered.
107
+ #
108
+ # @return [Integer]
109
+ required :delivered, Integer
110
+
111
+ # @!attribute errors
112
+ # Messages the provider rejected or failed on, including ones a later provider
113
+ # then delivered.
114
+ #
115
+ # @return [Integer]
116
+ required :errors, Integer
117
+
118
+ # @!attribute opened
119
+ # Messages opened at least once. Always `0` on channels with no open tracking.
120
+ #
121
+ # @return [Integer]
122
+ required :opened, Integer
123
+
124
+ # @!attribute provider
125
+ # Provider that handled the messages, e.g. `sendgrid`.
126
+ #
127
+ # @return [String]
128
+ required :provider, String
129
+
130
+ # @!attribute sent
131
+ # Messages handed to the provider.
132
+ #
133
+ # @return [Integer]
134
+ required :sent, Integer
135
+
136
+ # @!attribute undeliverable
137
+ # Messages Courier could not deliver on any provider for the channel.
138
+ #
139
+ # @return [Integer]
140
+ required :undeliverable, Integer
141
+
142
+ # @!method initialize(channel:, clicked:, delivered:, errors:, opened:, provider:, sent:, undeliverable:)
143
+ # Some parameter documentations has been truncated, see
144
+ # {Courier::Models::NotificationMetricsResponse::Series::Data} for more details.
145
+ #
146
+ # @param channel [String] Channel the provider delivered on, e.g. `email`.
147
+ #
148
+ # @param clicked [Integer] Messages with at least one tracked link click.
149
+ #
150
+ # @param delivered [Integer] Messages the provider confirmed as delivered.
151
+ #
152
+ # @param errors [Integer] Messages the provider rejected or failed on, including ones a later provider the
153
+ #
154
+ # @param opened [Integer] Messages opened at least once. Always `0` on channels with no open tracking.
155
+ #
156
+ # @param provider [String] Provider that handled the messages, e.g. `sendgrid`.
157
+ #
158
+ # @param sent [Integer] Messages handed to the provider.
159
+ #
160
+ # @param undeliverable [Integer] Messages Courier could not deliver on any provider for the channel.
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
@@ -422,12 +422,16 @@ module Courier
422
422
 
423
423
  NotificationGetContent = Courier::Models::NotificationGetContent
424
424
 
425
+ NotificationGetMetricsParams = Courier::Models::NotificationGetMetricsParams
426
+
425
427
  NotificationListParams = Courier::Models::NotificationListParams
426
428
 
427
429
  NotificationListVersionsParams = Courier::Models::NotificationListVersionsParams
428
430
 
429
431
  NotificationLocalePutRequest = Courier::Models::NotificationLocalePutRequest
430
432
 
433
+ NotificationMetricsResponse = Courier::Models::NotificationMetricsResponse
434
+
431
435
  NotificationPreferenceDetails = Courier::Models::NotificationPreferenceDetails
432
436
 
433
437
  NotificationPublishParams = Courier::Models::NotificationPublishParams
@@ -123,6 +123,59 @@ module Courier
123
123
  )
124
124
  end
125
125
 
126
+ # Some parameter documentations has been truncated, see
127
+ # {Courier::Models::NotificationGetMetricsParams} for more details.
128
+ #
129
+ # Fetch the delivery funnel for one Notification Template as a time series — sent,
130
+ # delivered, opened, clicked, errors, and undeliverable — broken out per provider
131
+ # and channel inside each bucket. Sum the entries in a bucket for its totals;
132
+ # there is no bucket-level total.
133
+ #
134
+ # Choose the window absolutely with `start` and `end`, or relatively with
135
+ # `lookback` (an ISO 8601 duration). `start` and `end` take precedence when both
136
+ # are supplied, and a request carrying neither defaults to `lookback=P30D`. The
137
+ # window is snapped outwards onto the `granularity` grid so every bucket it
138
+ # overlaps is returned whole, and the snapped boundaries come back as `start` and
139
+ # `end` — align a chart on those rather than on what was requested. Every boundary
140
+ # is UTC; there is no timezone support.
141
+ #
142
+ # Every bucket in the window is returned, including the quiet ones, whose `data`
143
+ # array is empty, so a series is directly plottable with no gap filling
144
+ # client-side. An unknown template id returns `200` with an all-empty series
145
+ # rather than `404`, and messages sent without a Notification Template never
146
+ # appear here.
147
+ #
148
+ # Available in the US region only.
149
+ #
150
+ # @overload get_metrics(id, end_: nil, granularity: nil, lookback: nil, start: nil, request_options: {})
151
+ #
152
+ # @param id [String] The Notification Template to report on — its ID (`nt_` prefix) or an alias. Must
153
+ #
154
+ # @param end_ [Time] The end of the window, as an ISO 8601 timestamp with an offset. Must be supplied
155
+ #
156
+ # @param granularity [Symbol, Courier::Models::NotificationGetMetricsParams::Granularity] The size of each bucket in the series. Defaults to `DAY`. `WEEK` buckets start o
157
+ #
158
+ # @param lookback [String] The length of the window, counted back from now, as an ISO 8601 duration (`P30D`
159
+ #
160
+ # @param start [Time] The inclusive start of the window, as an ISO 8601 timestamp with an offset (`202
161
+ #
162
+ # @param request_options [Courier::RequestOptions, Hash{Symbol=>Object}, nil]
163
+ #
164
+ # @return [Courier::Models::NotificationMetricsResponse]
165
+ #
166
+ # @see Courier::Models::NotificationGetMetricsParams
167
+ def get_metrics(id, params = {})
168
+ parsed, options = Courier::NotificationGetMetricsParams.dump_request(params)
169
+ query = Courier::Internal::Util.encode_query_params(parsed)
170
+ @client.request(
171
+ method: :get,
172
+ path: ["notifications/%1$s/metrics", id],
173
+ query: query.transform_keys(end_: "end"),
174
+ model: Courier::NotificationMetricsResponse,
175
+ options: options
176
+ )
177
+ end
178
+
126
179
  # Returns a notification template's published versions, most recent first, for
127
180
  # comparison or rollback. Paged.
128
181
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Courier
4
- VERSION = "6.1.0"
4
+ VERSION = "6.2.0"
5
5
  end
data/lib/courier.rb CHANGED
@@ -298,9 +298,11 @@ require_relative "courier/models/notification_content_get_response"
298
298
  require_relative "courier/models/notification_content_mutation_response"
299
299
  require_relative "courier/models/notification_create_params"
300
300
  require_relative "courier/models/notification_get_content"
301
+ require_relative "courier/models/notification_get_metrics_params"
301
302
  require_relative "courier/models/notification_list_params"
302
303
  require_relative "courier/models/notification_list_response"
303
304
  require_relative "courier/models/notification_list_versions_params"
305
+ require_relative "courier/models/notification_metrics_response"
304
306
  require_relative "courier/models/notification_preference_details"
305
307
  require_relative "courier/models/notification_publish_params"
306
308
  require_relative "courier/models/notification_put_content_params"
@@ -0,0 +1,167 @@
1
+ # typed: strong
2
+
3
+ module Courier
4
+ module Models
5
+ class NotificationGetMetricsParams < Courier::Internal::Type::BaseModel
6
+ extend Courier::Internal::Type::RequestParameters::Converter
7
+ include Courier::Internal::Type::RequestParameters
8
+
9
+ OrHash =
10
+ T.type_alias do
11
+ T.any(
12
+ Courier::NotificationGetMetricsParams,
13
+ Courier::Internal::AnyHash
14
+ )
15
+ end
16
+
17
+ sig { returns(String) }
18
+ attr_accessor :id
19
+
20
+ # The end of the window, as an ISO 8601 timestamp with an offset. Must be supplied
21
+ # together with `start`. An `end` in the future is accepted and not clamped — the
22
+ # trailing buckets come back empty.
23
+ sig { returns(T.nilable(Time)) }
24
+ attr_reader :end_
25
+
26
+ sig { params(end_: Time).void }
27
+ attr_writer :end_
28
+
29
+ # The size of each bucket in the series. Defaults to `DAY`. `WEEK` buckets start
30
+ # on Sunday. A fine granularity caps the window it can cover: `HOUR` spans at most
31
+ # 7 days and `DAY` at most 90 days, and a wider window returns `400` — request a
32
+ # coarser granularity instead. `WEEK` and `MONTH` are uncapped, subject to the
33
+ # 1000-bucket limit on a single response.
34
+ sig do
35
+ returns(
36
+ T.nilable(
37
+ Courier::NotificationGetMetricsParams::Granularity::OrSymbol
38
+ )
39
+ )
40
+ end
41
+ attr_reader :granularity
42
+
43
+ sig do
44
+ params(
45
+ granularity:
46
+ Courier::NotificationGetMetricsParams::Granularity::OrSymbol
47
+ ).void
48
+ end
49
+ attr_writer :granularity
50
+
51
+ # The length of the window, counted back from now, as an ISO 8601 duration
52
+ # (`P30D`, `P12W`, `PT12H`). Defaults to `P30D`, and is ignored when `start` and
53
+ # `end` are supplied. A malformed or non-positive duration returns `400`.
54
+ sig { returns(T.nilable(String)) }
55
+ attr_reader :lookback
56
+
57
+ sig { params(lookback: String).void }
58
+ attr_writer :lookback
59
+
60
+ # The inclusive start of the window, as an ISO 8601 timestamp with an offset
61
+ # (`2026-04-01T00:00:00Z`). Must be supplied together with `end` and be earlier
62
+ # than it; either one alone returns `400`.
63
+ sig { returns(T.nilable(Time)) }
64
+ attr_reader :start
65
+
66
+ sig { params(start: Time).void }
67
+ attr_writer :start
68
+
69
+ sig do
70
+ params(
71
+ id: String,
72
+ end_: Time,
73
+ granularity:
74
+ Courier::NotificationGetMetricsParams::Granularity::OrSymbol,
75
+ lookback: String,
76
+ start: Time,
77
+ request_options: Courier::RequestOptions::OrHash
78
+ ).returns(T.attached_class)
79
+ end
80
+ def self.new(
81
+ id:,
82
+ # The end of the window, as an ISO 8601 timestamp with an offset. Must be supplied
83
+ # together with `start`. An `end` in the future is accepted and not clamped — the
84
+ # trailing buckets come back empty.
85
+ end_: nil,
86
+ # The size of each bucket in the series. Defaults to `DAY`. `WEEK` buckets start
87
+ # on Sunday. A fine granularity caps the window it can cover: `HOUR` spans at most
88
+ # 7 days and `DAY` at most 90 days, and a wider window returns `400` — request a
89
+ # coarser granularity instead. `WEEK` and `MONTH` are uncapped, subject to the
90
+ # 1000-bucket limit on a single response.
91
+ granularity: nil,
92
+ # The length of the window, counted back from now, as an ISO 8601 duration
93
+ # (`P30D`, `P12W`, `PT12H`). Defaults to `P30D`, and is ignored when `start` and
94
+ # `end` are supplied. A malformed or non-positive duration returns `400`.
95
+ lookback: nil,
96
+ # The inclusive start of the window, as an ISO 8601 timestamp with an offset
97
+ # (`2026-04-01T00:00:00Z`). Must be supplied together with `end` and be earlier
98
+ # than it; either one alone returns `400`.
99
+ start: nil,
100
+ request_options: {}
101
+ )
102
+ end
103
+
104
+ sig do
105
+ override.returns(
106
+ {
107
+ id: String,
108
+ end_: Time,
109
+ granularity:
110
+ Courier::NotificationGetMetricsParams::Granularity::OrSymbol,
111
+ lookback: String,
112
+ start: Time,
113
+ request_options: Courier::RequestOptions
114
+ }
115
+ )
116
+ end
117
+ def to_hash
118
+ end
119
+
120
+ # The size of each bucket in the series. Defaults to `DAY`. `WEEK` buckets start
121
+ # on Sunday. A fine granularity caps the window it can cover: `HOUR` spans at most
122
+ # 7 days and `DAY` at most 90 days, and a wider window returns `400` — request a
123
+ # coarser granularity instead. `WEEK` and `MONTH` are uncapped, subject to the
124
+ # 1000-bucket limit on a single response.
125
+ module Granularity
126
+ extend Courier::Internal::Type::Enum
127
+
128
+ TaggedSymbol =
129
+ T.type_alias do
130
+ T.all(Symbol, Courier::NotificationGetMetricsParams::Granularity)
131
+ end
132
+ OrSymbol = T.type_alias { T.any(Symbol, String) }
133
+
134
+ HOUR =
135
+ T.let(
136
+ :HOUR,
137
+ Courier::NotificationGetMetricsParams::Granularity::TaggedSymbol
138
+ )
139
+ DAY =
140
+ T.let(
141
+ :DAY,
142
+ Courier::NotificationGetMetricsParams::Granularity::TaggedSymbol
143
+ )
144
+ WEEK =
145
+ T.let(
146
+ :WEEK,
147
+ Courier::NotificationGetMetricsParams::Granularity::TaggedSymbol
148
+ )
149
+ MONTH =
150
+ T.let(
151
+ :MONTH,
152
+ Courier::NotificationGetMetricsParams::Granularity::TaggedSymbol
153
+ )
154
+
155
+ sig do
156
+ override.returns(
157
+ T::Array[
158
+ Courier::NotificationGetMetricsParams::Granularity::TaggedSymbol
159
+ ]
160
+ )
161
+ end
162
+ def self.values
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,269 @@
1
+ # typed: strong
2
+
3
+ module Courier
4
+ module Models
5
+ class NotificationMetricsResponse < Courier::Internal::Type::BaseModel
6
+ OrHash =
7
+ T.type_alias do
8
+ T.any(
9
+ Courier::NotificationMetricsResponse,
10
+ Courier::Internal::AnyHash
11
+ )
12
+ end
13
+
14
+ # End of the window actually queried, ceiled onto the granularity grid.
15
+ # Second-precision UTC.
16
+ sig { returns(Time) }
17
+ attr_accessor :end_
18
+
19
+ # Bucket size the series was built at.
20
+ sig do
21
+ returns(Courier::NotificationMetricsResponse::Granularity::TaggedSymbol)
22
+ end
23
+ attr_accessor :granularity
24
+
25
+ # The template the series describes, echoed from the request.
26
+ sig { returns(String) }
27
+ attr_accessor :notification_id
28
+
29
+ # One entry per bucket between `start` and `end`, oldest first, including buckets
30
+ # with no activity.
31
+ sig { returns(T::Array[Courier::NotificationMetricsResponse::Series]) }
32
+ attr_accessor :series
33
+
34
+ # Inclusive start of the window actually queried, floored onto the granularity
35
+ # grid. Second-precision UTC.
36
+ sig { returns(Time) }
37
+ attr_accessor :start
38
+
39
+ sig do
40
+ params(
41
+ end_: Time,
42
+ granularity:
43
+ Courier::NotificationMetricsResponse::Granularity::OrSymbol,
44
+ notification_id: String,
45
+ series:
46
+ T::Array[Courier::NotificationMetricsResponse::Series::OrHash],
47
+ start: Time
48
+ ).returns(T.attached_class)
49
+ end
50
+ def self.new(
51
+ # End of the window actually queried, ceiled onto the granularity grid.
52
+ # Second-precision UTC.
53
+ end_:,
54
+ # Bucket size the series was built at.
55
+ granularity:,
56
+ # The template the series describes, echoed from the request.
57
+ notification_id:,
58
+ # One entry per bucket between `start` and `end`, oldest first, including buckets
59
+ # with no activity.
60
+ series:,
61
+ # Inclusive start of the window actually queried, floored onto the granularity
62
+ # grid. Second-precision UTC.
63
+ start:
64
+ )
65
+ end
66
+
67
+ sig do
68
+ override.returns(
69
+ {
70
+ end_: Time,
71
+ granularity:
72
+ Courier::NotificationMetricsResponse::Granularity::TaggedSymbol,
73
+ notification_id: String,
74
+ series: T::Array[Courier::NotificationMetricsResponse::Series],
75
+ start: Time
76
+ }
77
+ )
78
+ end
79
+ def to_hash
80
+ end
81
+
82
+ # Bucket size the series was built at.
83
+ module Granularity
84
+ extend Courier::Internal::Type::Enum
85
+
86
+ TaggedSymbol =
87
+ T.type_alias do
88
+ T.all(Symbol, Courier::NotificationMetricsResponse::Granularity)
89
+ end
90
+ OrSymbol = T.type_alias { T.any(Symbol, String) }
91
+
92
+ HOUR =
93
+ T.let(
94
+ :HOUR,
95
+ Courier::NotificationMetricsResponse::Granularity::TaggedSymbol
96
+ )
97
+ DAY =
98
+ T.let(
99
+ :DAY,
100
+ Courier::NotificationMetricsResponse::Granularity::TaggedSymbol
101
+ )
102
+ WEEK =
103
+ T.let(
104
+ :WEEK,
105
+ Courier::NotificationMetricsResponse::Granularity::TaggedSymbol
106
+ )
107
+ MONTH =
108
+ T.let(
109
+ :MONTH,
110
+ Courier::NotificationMetricsResponse::Granularity::TaggedSymbol
111
+ )
112
+
113
+ sig do
114
+ override.returns(
115
+ T::Array[
116
+ Courier::NotificationMetricsResponse::Granularity::TaggedSymbol
117
+ ]
118
+ )
119
+ end
120
+ def self.values
121
+ end
122
+ end
123
+
124
+ class Series < Courier::Internal::Type::BaseModel
125
+ OrHash =
126
+ T.type_alias do
127
+ T.any(
128
+ Courier::NotificationMetricsResponse::Series,
129
+ Courier::Internal::AnyHash
130
+ )
131
+ end
132
+
133
+ # One entry per provider and channel that handled a message in this bucket. Empty
134
+ # when nothing was sent.
135
+ sig do
136
+ returns(T::Array[Courier::NotificationMetricsResponse::Series::Data])
137
+ end
138
+ attr_accessor :data
139
+
140
+ # Start of the bucket, second-precision UTC.
141
+ sig { returns(Time) }
142
+ attr_accessor :period
143
+
144
+ sig do
145
+ params(
146
+ data:
147
+ T::Array[
148
+ Courier::NotificationMetricsResponse::Series::Data::OrHash
149
+ ],
150
+ period: Time
151
+ ).returns(T.attached_class)
152
+ end
153
+ def self.new(
154
+ # One entry per provider and channel that handled a message in this bucket. Empty
155
+ # when nothing was sent.
156
+ data:,
157
+ # Start of the bucket, second-precision UTC.
158
+ period:
159
+ )
160
+ end
161
+
162
+ sig do
163
+ override.returns(
164
+ {
165
+ data:
166
+ T::Array[Courier::NotificationMetricsResponse::Series::Data],
167
+ period: Time
168
+ }
169
+ )
170
+ end
171
+ def to_hash
172
+ end
173
+
174
+ class Data < Courier::Internal::Type::BaseModel
175
+ OrHash =
176
+ T.type_alias do
177
+ T.any(
178
+ Courier::NotificationMetricsResponse::Series::Data,
179
+ Courier::Internal::AnyHash
180
+ )
181
+ end
182
+
183
+ # Channel the provider delivered on, e.g. `email`.
184
+ sig { returns(String) }
185
+ attr_accessor :channel
186
+
187
+ # Messages with at least one tracked link click.
188
+ sig { returns(Integer) }
189
+ attr_accessor :clicked
190
+
191
+ # Messages the provider confirmed as delivered.
192
+ sig { returns(Integer) }
193
+ attr_accessor :delivered
194
+
195
+ # Messages the provider rejected or failed on, including ones a later provider
196
+ # then delivered.
197
+ sig { returns(Integer) }
198
+ attr_accessor :errors
199
+
200
+ # Messages opened at least once. Always `0` on channels with no open tracking.
201
+ sig { returns(Integer) }
202
+ attr_accessor :opened
203
+
204
+ # Provider that handled the messages, e.g. `sendgrid`.
205
+ sig { returns(String) }
206
+ attr_accessor :provider
207
+
208
+ # Messages handed to the provider.
209
+ sig { returns(Integer) }
210
+ attr_accessor :sent
211
+
212
+ # Messages Courier could not deliver on any provider for the channel.
213
+ sig { returns(Integer) }
214
+ attr_accessor :undeliverable
215
+
216
+ sig do
217
+ params(
218
+ channel: String,
219
+ clicked: Integer,
220
+ delivered: Integer,
221
+ errors: Integer,
222
+ opened: Integer,
223
+ provider: String,
224
+ sent: Integer,
225
+ undeliverable: Integer
226
+ ).returns(T.attached_class)
227
+ end
228
+ def self.new(
229
+ # Channel the provider delivered on, e.g. `email`.
230
+ channel:,
231
+ # Messages with at least one tracked link click.
232
+ clicked:,
233
+ # Messages the provider confirmed as delivered.
234
+ delivered:,
235
+ # Messages the provider rejected or failed on, including ones a later provider
236
+ # then delivered.
237
+ errors:,
238
+ # Messages opened at least once. Always `0` on channels with no open tracking.
239
+ opened:,
240
+ # Provider that handled the messages, e.g. `sendgrid`.
241
+ provider:,
242
+ # Messages handed to the provider.
243
+ sent:,
244
+ # Messages Courier could not deliver on any provider for the channel.
245
+ undeliverable:
246
+ )
247
+ end
248
+
249
+ sig do
250
+ override.returns(
251
+ {
252
+ channel: String,
253
+ clicked: Integer,
254
+ delivered: Integer,
255
+ errors: Integer,
256
+ opened: Integer,
257
+ provider: String,
258
+ sent: Integer,
259
+ undeliverable: Integer
260
+ }
261
+ )
262
+ end
263
+ def to_hash
264
+ end
265
+ end
266
+ end
267
+ end
268
+ end
269
+ end
@@ -392,6 +392,8 @@ module Courier
392
392
 
393
393
  NotificationGetContent = Courier::Models::NotificationGetContent
394
394
 
395
+ NotificationGetMetricsParams = Courier::Models::NotificationGetMetricsParams
396
+
395
397
  NotificationListParams = Courier::Models::NotificationListParams
396
398
 
397
399
  NotificationListVersionsParams =
@@ -399,6 +401,8 @@ module Courier
399
401
 
400
402
  NotificationLocalePutRequest = Courier::Models::NotificationLocalePutRequest
401
403
 
404
+ NotificationMetricsResponse = Courier::Models::NotificationMetricsResponse
405
+
402
406
  NotificationPreferenceDetails = Courier::Models::NotificationPreferenceDetails
403
407
 
404
408
  NotificationPublishParams = Courier::Models::NotificationPublishParams
@@ -99,6 +99,63 @@ module Courier
99
99
  )
100
100
  end
101
101
 
102
+ # Fetch the delivery funnel for one Notification Template as a time series — sent,
103
+ # delivered, opened, clicked, errors, and undeliverable — broken out per provider
104
+ # and channel inside each bucket. Sum the entries in a bucket for its totals;
105
+ # there is no bucket-level total.
106
+ #
107
+ # Choose the window absolutely with `start` and `end`, or relatively with
108
+ # `lookback` (an ISO 8601 duration). `start` and `end` take precedence when both
109
+ # are supplied, and a request carrying neither defaults to `lookback=P30D`. The
110
+ # window is snapped outwards onto the `granularity` grid so every bucket it
111
+ # overlaps is returned whole, and the snapped boundaries come back as `start` and
112
+ # `end` — align a chart on those rather than on what was requested. Every boundary
113
+ # is UTC; there is no timezone support.
114
+ #
115
+ # Every bucket in the window is returned, including the quiet ones, whose `data`
116
+ # array is empty, so a series is directly plottable with no gap filling
117
+ # client-side. An unknown template id returns `200` with an all-empty series
118
+ # rather than `404`, and messages sent without a Notification Template never
119
+ # appear here.
120
+ #
121
+ # Available in the US region only.
122
+ sig do
123
+ params(
124
+ id: String,
125
+ end_: Time,
126
+ granularity:
127
+ Courier::NotificationGetMetricsParams::Granularity::OrSymbol,
128
+ lookback: String,
129
+ start: Time,
130
+ request_options: Courier::RequestOptions::OrHash
131
+ ).returns(Courier::NotificationMetricsResponse)
132
+ end
133
+ def get_metrics(
134
+ # The Notification Template to report on — its ID (`nt_` prefix) or an alias. Must
135
+ # not contain commas or whitespace.
136
+ id,
137
+ # The end of the window, as an ISO 8601 timestamp with an offset. Must be supplied
138
+ # together with `start`. An `end` in the future is accepted and not clamped — the
139
+ # trailing buckets come back empty.
140
+ end_: nil,
141
+ # The size of each bucket in the series. Defaults to `DAY`. `WEEK` buckets start
142
+ # on Sunday. A fine granularity caps the window it can cover: `HOUR` spans at most
143
+ # 7 days and `DAY` at most 90 days, and a wider window returns `400` — request a
144
+ # coarser granularity instead. `WEEK` and `MONTH` are uncapped, subject to the
145
+ # 1000-bucket limit on a single response.
146
+ granularity: nil,
147
+ # The length of the window, counted back from now, as an ISO 8601 duration
148
+ # (`P30D`, `P12W`, `PT12H`). Defaults to `P30D`, and is ignored when `start` and
149
+ # `end` are supplied. A malformed or non-positive duration returns `400`.
150
+ lookback: nil,
151
+ # The inclusive start of the window, as an ISO 8601 timestamp with an offset
152
+ # (`2026-04-01T00:00:00Z`). Must be supplied together with `end` and be earlier
153
+ # than it; either one alone returns `400`.
154
+ start: nil,
155
+ request_options: {}
156
+ )
157
+ end
158
+
102
159
  # Returns a notification template's published versions, most recent first, for
103
160
  # comparison or rollback. Paged.
104
161
  sig do
@@ -0,0 +1,69 @@
1
+ module Courier
2
+ module Models
3
+ type notification_get_metrics_params =
4
+ {
5
+ id: String,
6
+ end_: Time,
7
+ granularity: Courier::Models::NotificationGetMetricsParams::granularity,
8
+ lookback: String,
9
+ start: Time
10
+ }
11
+ & Courier::Internal::Type::request_parameters
12
+
13
+ class NotificationGetMetricsParams < Courier::Internal::Type::BaseModel
14
+ extend Courier::Internal::Type::RequestParameters::Converter
15
+ include Courier::Internal::Type::RequestParameters
16
+
17
+ attr_accessor id: String
18
+
19
+ attr_reader end_: Time?
20
+
21
+ def end_=: (Time) -> Time
22
+
23
+ attr_reader granularity: Courier::Models::NotificationGetMetricsParams::granularity?
24
+
25
+ def granularity=: (
26
+ Courier::Models::NotificationGetMetricsParams::granularity
27
+ ) -> Courier::Models::NotificationGetMetricsParams::granularity
28
+
29
+ attr_reader lookback: String?
30
+
31
+ def lookback=: (String) -> String
32
+
33
+ attr_reader start: Time?
34
+
35
+ def start=: (Time) -> Time
36
+
37
+ def initialize: (
38
+ id: String,
39
+ ?end_: Time,
40
+ ?granularity: Courier::Models::NotificationGetMetricsParams::granularity,
41
+ ?lookback: String,
42
+ ?start: Time,
43
+ ?request_options: Courier::request_opts
44
+ ) -> void
45
+
46
+ def to_hash: -> {
47
+ id: String,
48
+ end_: Time,
49
+ granularity: Courier::Models::NotificationGetMetricsParams::granularity,
50
+ lookback: String,
51
+ start: Time,
52
+ request_options: Courier::RequestOptions
53
+ }
54
+
55
+ type granularity = :HOUR | :DAY | :WEEK | :MONTH
56
+
57
+ module Granularity
58
+ extend Courier::Internal::Type::Enum
59
+
60
+ HOUR: :HOUR
61
+ DAY: :DAY
62
+ WEEK: :WEEK
63
+ MONTH: :MONTH
64
+
65
+ def self?.values: -> ::Array[Courier::Models::NotificationGetMetricsParams::granularity]
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,127 @@
1
+ module Courier
2
+ module Models
3
+ type notification_metrics_response =
4
+ {
5
+ end_: Time,
6
+ granularity: Courier::Models::NotificationMetricsResponse::granularity,
7
+ notification_id: String,
8
+ series: ::Array[Courier::NotificationMetricsResponse::Series],
9
+ start: Time
10
+ }
11
+
12
+ class NotificationMetricsResponse < Courier::Internal::Type::BaseModel
13
+ attr_accessor end_: Time
14
+
15
+ attr_accessor granularity: Courier::Models::NotificationMetricsResponse::granularity
16
+
17
+ attr_accessor notification_id: String
18
+
19
+ attr_accessor series: ::Array[Courier::NotificationMetricsResponse::Series]
20
+
21
+ attr_accessor start: Time
22
+
23
+ def initialize: (
24
+ end_: Time,
25
+ granularity: Courier::Models::NotificationMetricsResponse::granularity,
26
+ notification_id: String,
27
+ series: ::Array[Courier::NotificationMetricsResponse::Series],
28
+ start: Time
29
+ ) -> void
30
+
31
+ def to_hash: -> {
32
+ end_: Time,
33
+ granularity: Courier::Models::NotificationMetricsResponse::granularity,
34
+ notification_id: String,
35
+ series: ::Array[Courier::NotificationMetricsResponse::Series],
36
+ start: Time
37
+ }
38
+
39
+ type granularity = :HOUR | :DAY | :WEEK | :MONTH
40
+
41
+ module Granularity
42
+ extend Courier::Internal::Type::Enum
43
+
44
+ HOUR: :HOUR
45
+ DAY: :DAY
46
+ WEEK: :WEEK
47
+ MONTH: :MONTH
48
+
49
+ def self?.values: -> ::Array[Courier::Models::NotificationMetricsResponse::granularity]
50
+ end
51
+
52
+ type series =
53
+ {
54
+ data: ::Array[Courier::NotificationMetricsResponse::Series::Data],
55
+ period: Time
56
+ }
57
+
58
+ class Series < Courier::Internal::Type::BaseModel
59
+ attr_accessor data: ::Array[Courier::NotificationMetricsResponse::Series::Data]
60
+
61
+ attr_accessor period: Time
62
+
63
+ def initialize: (
64
+ data: ::Array[Courier::NotificationMetricsResponse::Series::Data],
65
+ period: Time
66
+ ) -> void
67
+
68
+ def to_hash: -> {
69
+ data: ::Array[Courier::NotificationMetricsResponse::Series::Data],
70
+ period: Time
71
+ }
72
+
73
+ type data =
74
+ {
75
+ channel: String,
76
+ clicked: Integer,
77
+ delivered: Integer,
78
+ errors: Integer,
79
+ opened: Integer,
80
+ provider: String,
81
+ sent: Integer,
82
+ undeliverable: Integer
83
+ }
84
+
85
+ class Data < Courier::Internal::Type::BaseModel
86
+ attr_accessor channel: String
87
+
88
+ attr_accessor clicked: Integer
89
+
90
+ attr_accessor delivered: Integer
91
+
92
+ attr_accessor errors: Integer
93
+
94
+ attr_accessor opened: Integer
95
+
96
+ attr_accessor provider: String
97
+
98
+ attr_accessor sent: Integer
99
+
100
+ attr_accessor undeliverable: Integer
101
+
102
+ def initialize: (
103
+ channel: String,
104
+ clicked: Integer,
105
+ delivered: Integer,
106
+ errors: Integer,
107
+ opened: Integer,
108
+ provider: String,
109
+ sent: Integer,
110
+ undeliverable: Integer
111
+ ) -> void
112
+
113
+ def to_hash: -> {
114
+ channel: String,
115
+ clicked: Integer,
116
+ delivered: Integer,
117
+ errors: Integer,
118
+ opened: Integer,
119
+ provider: String,
120
+ sent: Integer,
121
+ undeliverable: Integer
122
+ }
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -379,12 +379,16 @@ module Courier
379
379
 
380
380
  class NotificationGetContent = Courier::Models::NotificationGetContent
381
381
 
382
+ class NotificationGetMetricsParams = Courier::Models::NotificationGetMetricsParams
383
+
382
384
  class NotificationListParams = Courier::Models::NotificationListParams
383
385
 
384
386
  class NotificationListVersionsParams = Courier::Models::NotificationListVersionsParams
385
387
 
386
388
  class NotificationLocalePutRequest = Courier::Models::NotificationLocalePutRequest
387
389
 
390
+ class NotificationMetricsResponse = Courier::Models::NotificationMetricsResponse
391
+
388
392
  class NotificationPreferenceDetails = Courier::Models::NotificationPreferenceDetails
389
393
 
390
394
  class NotificationPublishParams = Courier::Models::NotificationPublishParams
@@ -26,6 +26,15 @@ module Courier
26
26
 
27
27
  def archive: (String id, ?request_options: Courier::request_opts) -> nil
28
28
 
29
+ def get_metrics: (
30
+ String id,
31
+ ?end_: Time,
32
+ ?granularity: Courier::Models::NotificationGetMetricsParams::granularity,
33
+ ?lookback: String,
34
+ ?start: Time,
35
+ ?request_options: Courier::request_opts
36
+ ) -> Courier::NotificationMetricsResponse
37
+
29
38
  def list_versions: (
30
39
  String id,
31
40
  ?cursor: String,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trycourier
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.1.0
4
+ version: 6.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Courier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-19 00:00:00.000000000 Z
11
+ date: 2026-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cgi
@@ -296,10 +296,12 @@ files:
296
296
  - lib/courier/models/notification_create_params.rb
297
297
  - lib/courier/models/notification_element_put_request.rb
298
298
  - lib/courier/models/notification_get_content.rb
299
+ - lib/courier/models/notification_get_metrics_params.rb
299
300
  - lib/courier/models/notification_list_params.rb
300
301
  - lib/courier/models/notification_list_response.rb
301
302
  - lib/courier/models/notification_list_versions_params.rb
302
303
  - lib/courier/models/notification_locale_put_request.rb
304
+ - lib/courier/models/notification_metrics_response.rb
303
305
  - lib/courier/models/notification_preference_details.rb
304
306
  - lib/courier/models/notification_publish_params.rb
305
307
  - lib/courier/models/notification_put_content_params.rb
@@ -767,10 +769,12 @@ files:
767
769
  - rbi/courier/models/notification_create_params.rbi
768
770
  - rbi/courier/models/notification_element_put_request.rbi
769
771
  - rbi/courier/models/notification_get_content.rbi
772
+ - rbi/courier/models/notification_get_metrics_params.rbi
770
773
  - rbi/courier/models/notification_list_params.rbi
771
774
  - rbi/courier/models/notification_list_response.rbi
772
775
  - rbi/courier/models/notification_list_versions_params.rbi
773
776
  - rbi/courier/models/notification_locale_put_request.rbi
777
+ - rbi/courier/models/notification_metrics_response.rbi
774
778
  - rbi/courier/models/notification_preference_details.rbi
775
779
  - rbi/courier/models/notification_publish_params.rbi
776
780
  - rbi/courier/models/notification_put_content_params.rbi
@@ -1237,10 +1241,12 @@ files:
1237
1241
  - sig/courier/models/notification_create_params.rbs
1238
1242
  - sig/courier/models/notification_element_put_request.rbs
1239
1243
  - sig/courier/models/notification_get_content.rbs
1244
+ - sig/courier/models/notification_get_metrics_params.rbs
1240
1245
  - sig/courier/models/notification_list_params.rbs
1241
1246
  - sig/courier/models/notification_list_response.rbs
1242
1247
  - sig/courier/models/notification_list_versions_params.rbs
1243
1248
  - sig/courier/models/notification_locale_put_request.rbs
1249
+ - sig/courier/models/notification_metrics_response.rbs
1244
1250
  - sig/courier/models/notification_preference_details.rbs
1245
1251
  - sig/courier/models/notification_publish_params.rbs
1246
1252
  - sig/courier/models/notification_put_content_params.rbs