umami-ruby 0.1.3 → 0.3.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.
data/lib/umami/client.rb CHANGED
@@ -47,10 +47,10 @@ module Umami
47
47
 
48
48
  # Verify the authentication token
49
49
  #
50
- # @return [Hash] Token verification result
50
+ # @return [Hash] Token verification result containing user information
51
51
  # @see https://umami.is/docs/api/authentication#post-/api/auth/verify
52
52
  def verify_token
53
- get("/api/auth/verify")
53
+ post("/api/auth/verify")
54
54
  end
55
55
 
56
56
  # Authentication endpoints
@@ -72,36 +72,132 @@ module Umami
72
72
 
73
73
  data = JSON.parse(response.body)
74
74
  @access_token = data["token"]
75
+
76
+ # Umami answers a successful login with { "token": ..., "user": ... }
77
+ # (https://umami.is/docs/api/authentication#post-/api/auth/login).
78
+ # A 200 without a token would otherwise produce a client that fails
79
+ # every request with an opaque 401 — fail loudly at the source.
80
+ if @access_token.nil? || @access_token.empty?
81
+ raise Umami::AuthenticationError, "Authentication succeeded but the response carried no token"
82
+ end
83
+
84
+ # ⚠️ Load-bearing reset. The login POST above just memoized
85
+ # `@connection` — necessarily WITHOUT an Authorization header, since
86
+ # `@access_token` was still nil when the connection was built, and
87
+ # Faraday bakes headers into the connection at build time. Dropping
88
+ # the memo forces the next request to rebuild the connection, this
89
+ # time with the Bearer token (see #connection). Without this reset,
90
+ # every request after a username/password login fails with 401 —
91
+ # the exact bug shipped in <= 0.2.0 (why token-based auth was the
92
+ # only flow that worked against self-hosted instances).
93
+ @connection = nil
75
94
  rescue Faraday::Error, JSON::ParserError => e
76
95
  raise Umami::AuthenticationError, "Authentication failed: #{e.message}"
77
96
  end
78
97
 
98
+ # -------- Me endpoints --------
99
+
100
+ # Get information about the current authenticated user
101
+ #
102
+ # @return [Hash] Current user information including token, authKey, shareToken, and user details
103
+ # @see https://umami.is/docs/api/me#get-/api/me
104
+ def me
105
+ get("/api/me")
106
+ end
107
+
108
+ # Get all teams for the current authenticated user
109
+ #
110
+ # @param params [Hash] Query parameters
111
+ # @option params [Integer] :page Page number (default: 1)
112
+ # @option params [Integer] :pageSize Number of results per page
113
+ # @return [Hash] Paginated list of teams with members
114
+ # @see https://umami.is/docs/api/me#get-/api/me/teams
115
+ def my_teams(params = {})
116
+ get("/api/me/teams", params)
117
+ end
118
+
119
+ # Get all websites for the current authenticated user
120
+ #
121
+ # @param params [Hash] Query parameters
122
+ # @option params [Boolean] :includeTeams Include websites where user is team owner
123
+ # @return [Hash] Paginated list of websites
124
+ # @see https://umami.is/docs/api/me#get-/api/me/websites
125
+ def my_websites(params = {})
126
+ get("/api/me/websites", params)
127
+ end
128
+
129
+ # -------- Admin endpoints --------
130
+
131
+ # Get all users (admin access required, self-hosted only)
132
+ #
133
+ # @param params [Hash] Query parameters
134
+ # @option params [String] :search Search text
135
+ # @option params [Integer] :page Page number (default: 1)
136
+ # @option params [Integer] :pageSize Number of results per page (default: 20)
137
+ # @return [Hash] Paginated list of all users
138
+ # @see https://umami.is/docs/api/admin#get-/api/admin/users
139
+ def admin_users(params = {})
140
+ get("/api/admin/users", params)
141
+ end
142
+
143
+ # Get all websites (admin access required, self-hosted only)
144
+ #
145
+ # @param params [Hash] Query parameters
146
+ # @option params [String] :search Search text
147
+ # @option params [Integer] :page Page number (default: 1)
148
+ # @option params [Integer] :pageSize Number of results per page (default: 20)
149
+ # @return [Hash] Paginated list of all websites
150
+ # @see https://umami.is/docs/api/admin#get-/api/admin/websites
151
+ def admin_websites(params = {})
152
+ get("/api/admin/websites", params)
153
+ end
154
+
155
+ # Get all teams (admin access required, self-hosted only)
156
+ #
157
+ # @param params [Hash] Query parameters
158
+ # @option params [String] :search Search text
159
+ # @option params [Integer] :page Page number (default: 1)
160
+ # @option params [Integer] :pageSize Number of results per page (default: 20)
161
+ # @return [Hash] Paginated list of all teams
162
+ # @see https://umami.is/docs/api/admin#get-/api/admin/teams
163
+ def admin_teams(params = {})
164
+ get("/api/admin/teams", params)
165
+ end
166
+
79
167
  # -------- Users endpoints --------
80
168
 
81
169
  # Create a new user
82
170
  #
83
171
  # @param username [String] The user's username
84
172
  # @param password [String] The user's password
85
- # @param role [String] The user's role ('admin' or 'user')
173
+ # @param role [String] The user's role ('admin', 'user', or 'view-only')
174
+ # @param id [String, nil] Optional UUID to assign to the user
86
175
  # @return [Hash] Created user details
87
- # @see https://umami.is/docs/api/users-api#post-/api/users
88
- def create_user(username, password, role)
89
- post("/api/users", { username: username, password: password, role: role })
176
+ # @see https://umami.is/docs/api/users#post-/api/users
177
+ def create_user(username, password, role, id: nil)
178
+ params = { username: username, password: password, role: role }
179
+ params[:id] = id if id
180
+ post("/api/users", params)
90
181
  end
91
182
 
92
183
  # Get all users (admin access required)
93
184
  #
94
- # @return [Array<Hash>] List of all users
95
- # @see https://umami.is/docs/api/users-api#get-/api/admin/users
96
- def users
97
- get("/api/admin/users")
185
+ # @param params [Hash] Query parameters
186
+ # @option params [String] :search Search text
187
+ # @option params [Integer] :page Page number (default: 1)
188
+ # @option params [Integer] :pageSize Number of results per page (default: 20)
189
+ # @return [Hash] Paginated list of all users
190
+ # @see https://umami.is/docs/api/admin#get-/api/admin/users
191
+ # @deprecated Use {#admin_users} instead
192
+ def users(params = {})
193
+ admin_users(params)
98
194
  end
99
195
 
100
196
  # Get a user by ID
101
197
  #
102
198
  # @param user_id [String] The user's ID
103
199
  # @return [Hash] User details
104
- # @see https://umami.is/docs/api/users-api#get-/api/users/:userid
200
+ # @see https://umami.is/docs/api/users#get-/api/users/:userid
105
201
  def user(user_id)
106
202
  get("/api/users/#{user_id}")
107
203
  end
@@ -112,9 +208,9 @@ module Umami
112
208
  # @param params [Hash] User parameters to update
113
209
  # @option params [String] :username The user's new username
114
210
  # @option params [String] :password The user's new password
115
- # @option params [String] :role The user's new role
211
+ # @option params [String] :role The user's new role ('admin', 'user', or 'view-only')
116
212
  # @return [Hash] Updated user details
117
- # @see https://umami.is/docs/api/users-api#post-/api/users/:userid
213
+ # @see https://umami.is/docs/api/users#post-/api/users/:userid
118
214
  def update_user(user_id, params = {})
119
215
  post("/api/users/#{user_id}", params)
120
216
  end
@@ -122,8 +218,8 @@ module Umami
122
218
  # Delete a user
123
219
  #
124
220
  # @param user_id [String] The user's ID
125
- # @return [String] Confirmation message
126
- # @see https://umami.is/docs/api/users-api#delete-/api/users/:userid
221
+ # @return [Hash] Confirmation message
222
+ # @see https://umami.is/docs/api/users#delete-/api/users/:userid
127
223
  def delete_user(user_id)
128
224
  delete("/api/users/#{user_id}")
129
225
  end
@@ -132,12 +228,12 @@ module Umami
132
228
  #
133
229
  # @param user_id [String] The user's ID
134
230
  # @param params [Hash] Query parameters
135
- # @option params [String] :query Search text
136
- # @option params [Integer] :page Page number
231
+ # @option params [Boolean] :includeTeams Include team websites
232
+ # @option params [String] :search Search text
233
+ # @option params [Integer] :page Page number (default: 1)
137
234
  # @option params [Integer] :pageSize Number of results per page
138
- # @option params [String] :orderBy Column to order by
139
- # @return [Array<Hash>] List of user's websites
140
- # @see https://umami.is/docs/api/users-api#get-/api/users/:userid/websites
235
+ # @return [Hash] Paginated list of user's websites
236
+ # @see https://umami.is/docs/api/users#get-/api/users/:userid/websites
141
237
  def user_websites(user_id, params = {})
142
238
  get("/api/users/#{user_id}/websites", params)
143
239
  end
@@ -146,12 +242,10 @@ module Umami
146
242
  #
147
243
  # @param user_id [String] The user's ID
148
244
  # @param params [Hash] Query parameters
149
- # @option params [String] :query Search text
150
- # @option params [Integer] :page Page number
245
+ # @option params [Integer] :page Page number (default: 1)
151
246
  # @option params [Integer] :pageSize Number of results per page
152
- # @option params [String] :orderBy Column to order by
153
- # @return [Array<Hash>] List of user's teams
154
- # @see https://umami.is/docs/api/users-api#get-/api/users/:userid/teams
247
+ # @return [Hash] Paginated list of user's teams
248
+ # @see https://umami.is/docs/api/users#get-/api/users/:userid/teams
155
249
  def user_teams(user_id, params = {})
156
250
  get("/api/users/#{user_id}/teams", params)
157
251
  end
@@ -162,7 +256,7 @@ module Umami
162
256
  #
163
257
  # @param name [String] The team's name
164
258
  # @return [Hash] Created team details
165
- # @see https://umami.is/docs/api/teams-api#post-/api/teams
259
+ # @see https://umami.is/docs/api/teams#post-/api/teams
166
260
  def create_team(name)
167
261
  post("/api/teams", { name: name })
168
262
  end
@@ -170,12 +264,10 @@ module Umami
170
264
  # Get all teams
171
265
  #
172
266
  # @param params [Hash] Query parameters
173
- # @option params [String] :query Search text
174
- # @option params [Integer] :page Page number
267
+ # @option params [Integer] :page Page number (default: 1)
175
268
  # @option params [Integer] :pageSize Number of results per page
176
- # @option params [String] :orderBy Column to order by
177
- # @return [Array<Hash>] List of teams
178
- # @see https://umami.is/docs/api/teams-api#get-/api/teams
269
+ # @return [Hash] Paginated list of teams
270
+ # @see https://umami.is/docs/api/teams#get-/api/teams
179
271
  def teams(params = {})
180
272
  get("/api/teams", params)
181
273
  end
@@ -184,7 +276,7 @@ module Umami
184
276
  #
185
277
  # @param access_code [String] The team's access code
186
278
  # @return [Hash] Joined team details
187
- # @see https://umami.is/docs/api/teams-api#post-/api/teams/join
279
+ # @see https://umami.is/docs/api/teams#post-/api/teams/join
188
280
  def join_team(access_code)
189
281
  post("/api/teams/join", { accessCode: access_code })
190
282
  end
@@ -193,7 +285,7 @@ module Umami
193
285
  #
194
286
  # @param team_id [String] The team's ID
195
287
  # @return [Hash] Team details
196
- # @see https://umami.is/docs/api/teams-api#get-/api/teams/:teamid
288
+ # @see https://umami.is/docs/api/teams#get-/api/teams/:teamid
197
289
  def team(team_id)
198
290
  get("/api/teams/#{team_id}")
199
291
  end
@@ -205,7 +297,7 @@ module Umami
205
297
  # @option params [String] :name The team's new name
206
298
  # @option params [String] :accessCode The team's new access code
207
299
  # @return [Hash] Updated team details
208
- # @see https://umami.is/docs/api/teams-api#post-/api/teams/:teamid
300
+ # @see https://umami.is/docs/api/teams#post-/api/teams/:teamid
209
301
  def update_team(team_id, params = {})
210
302
  post("/api/teams/#{team_id}", params)
211
303
  end
@@ -213,8 +305,8 @@ module Umami
213
305
  # Delete a team
214
306
  #
215
307
  # @param team_id [String] The team's ID
216
- # @return [String] Confirmation message
217
- # @see https://umami.is/docs/api/teams-api#delete-/api/teams/:teamid
308
+ # @return [Hash] Confirmation message
309
+ # @see https://umami.is/docs/api/teams#delete-/api/teams/:teamid
218
310
  def delete_team(team_id)
219
311
  delete("/api/teams/#{team_id}")
220
312
  end
@@ -223,12 +315,11 @@ module Umami
223
315
  #
224
316
  # @param team_id [String] The team's ID
225
317
  # @param params [Hash] Query parameters
226
- # @option params [String] :query Search text
227
- # @option params [Integer] :page Page number
318
+ # @option params [String] :search Search text
319
+ # @option params [Integer] :page Page number (default: 1)
228
320
  # @option params [Integer] :pageSize Number of results per page
229
- # @option params [String] :orderBy Column to order by
230
- # @return [Array<Hash>] List of team users
231
- # @see https://umami.is/docs/api/teams-api#get-/api/teams/:teamid/users
321
+ # @return [Hash] Paginated list of team users
322
+ # @see https://umami.is/docs/api/teams#get-/api/teams/:teamid/users
232
323
  def team_users(team_id, params = {})
233
324
  get("/api/teams/#{team_id}/users", params)
234
325
  end
@@ -237,9 +328,9 @@ module Umami
237
328
  #
238
329
  # @param team_id [String] The team's ID
239
330
  # @param user_id [String] The user's ID
240
- # @param role [String] The user's role in the team
331
+ # @param role [String] The user's role in the team ('team-manager', 'team-member', or 'team-view-only')
241
332
  # @return [Hash] Added team user details
242
- # @see https://umami.is/docs/api/teams-api#post-/api/teams/:teamid/users
333
+ # @see https://umami.is/docs/api/teams#post-/api/teams/:teamid/users
243
334
  def add_team_user(team_id, user_id, role)
244
335
  post("/api/teams/#{team_id}/users", { userId: user_id, role: role })
245
336
  end
@@ -249,7 +340,7 @@ module Umami
249
340
  # @param team_id [String] The team's ID
250
341
  # @param user_id [String] The user's ID
251
342
  # @return [Hash] Team user details
252
- # @see https://umami.is/docs/api/teams-api#get-/api/teams/:teamid/users/:userid
343
+ # @see https://umami.is/docs/api/teams#get-/api/teams/:teamid/users/:userid
253
344
  def team_user(team_id, user_id)
254
345
  get("/api/teams/#{team_id}/users/#{user_id}")
255
346
  end
@@ -258,9 +349,9 @@ module Umami
258
349
  #
259
350
  # @param team_id [String] The team's ID
260
351
  # @param user_id [String] The user's ID
261
- # @param role [String] The user's new role
262
- # @return [String] Confirmation message
263
- # @see https://umami.is/docs/api/teams-api#post-/api/teams/:teamid/users/:userid
352
+ # @param role [String] The user's new role ('team-manager', 'team-member', or 'team-view-only')
353
+ # @return [Hash] Confirmation message
354
+ # @see https://umami.is/docs/api/teams#post-/api/teams/:teamid/users/:userid
264
355
  def update_team_user(team_id, user_id, role)
265
356
  post("/api/teams/#{team_id}/users/#{user_id}", { role: role })
266
357
  end
@@ -269,8 +360,8 @@ module Umami
269
360
  #
270
361
  # @param team_id [String] The team's ID
271
362
  # @param user_id [String] The user's ID
272
- # @return [String] Confirmation message
273
- # @see https://umami.is/docs/api/teams-api#delete-/api/teams/:teamid/users/:userid
363
+ # @return [Hash] Confirmation message
364
+ # @see https://umami.is/docs/api/teams#delete-/api/teams/:teamid/users/:userid
274
365
  def delete_team_user(team_id, user_id)
275
366
  delete("/api/teams/#{team_id}/users/#{user_id}")
276
367
  end
@@ -279,12 +370,11 @@ module Umami
279
370
  #
280
371
  # @param team_id [String] The team's ID
281
372
  # @param params [Hash] Query parameters
282
- # @option params [String] :query Search text
283
- # @option params [Integer] :page Page number
373
+ # @option params [String] :search Search text
374
+ # @option params [Integer] :page Page number (default: 1)
284
375
  # @option params [Integer] :pageSize Number of results per page
285
- # @option params [String] :orderBy Column to order by
286
- # @return [Array<Hash>] List of team websites
287
- # @see https://umami.is/docs/api/teams-api#get-/api/teams/:teamid/websites
376
+ # @return [Hash] Paginated list of team websites
377
+ # @see https://umami.is/docs/api/teams#get-/api/teams/:teamid/websites
288
378
  def team_websites(team_id, params = {})
289
379
  get("/api/teams/#{team_id}/websites", params)
290
380
  end
@@ -294,12 +384,12 @@ module Umami
294
384
  # Get all websites
295
385
  #
296
386
  # @param params [Hash] Query parameters
297
- # @option params [String] :query Search text
298
- # @option params [Integer] :page Page number
387
+ # @option params [Boolean] :includeTeams Include websites where user is team owner
388
+ # @option params [String] :search Search text
389
+ # @option params [Integer] :page Page number (default: 1)
299
390
  # @option params [Integer] :pageSize Number of results per page
300
- # @option params [String] :orderBy Column to order by
301
- # @return [Array<Hash>] List of websites
302
- # @see https://umami.is/docs/api/websites-api#get-/api/websites
391
+ # @return [Hash] Paginated list of websites
392
+ # @see https://umami.is/docs/api/websites#get-/api/websites
303
393
  def websites(params = {})
304
394
  get("/api/websites", params)
305
395
  end
@@ -307,34 +397,35 @@ module Umami
307
397
  # Create a new website
308
398
  #
309
399
  # @param params [Hash] Website parameters
310
- # @option params [String] :domain The full domain of the tracked website
311
- # @option params [String] :name The name of the website in Umami
400
+ # @option params [String] :name The name of the website in Umami (required)
401
+ # @option params [String] :domain The full domain of the tracked website (required)
312
402
  # @option params [String] :shareId A unique string to enable a share url (optional)
313
403
  # @option params [String] :teamId The ID of the team the website will be created under (optional)
404
+ # @option params [String] :id Force a specific UUID for the website (optional)
314
405
  # @return [Hash] Created website details
315
- # @see https://umami.is/docs/api/websites-api#post-/api/websites
406
+ # @see https://umami.is/docs/api/websites#post-/api/websites
316
407
  def create_website(params = {})
317
408
  post("/api/websites", params)
318
409
  end
319
410
 
320
411
  # Get a website by ID
321
412
  #
322
- # @param id [String] The website's ID
413
+ # @param website_id [String] The website's ID
323
414
  # @return [Hash] Website details
324
- # @see https://umami.is/docs/api/websites-api#get-/api/websites/:websiteid
325
- def website(id)
326
- get("/api/websites/#{id}")
415
+ # @see https://umami.is/docs/api/websites#get-/api/websites/:websiteid
416
+ def website(website_id)
417
+ get("/api/websites/#{website_id}")
327
418
  end
328
419
 
329
420
  # Update a website
330
421
  #
331
422
  # @param website_id [String] The website's ID
332
423
  # @param params [Hash] Website parameters to update
333
- # @option params [String] :name The name of the website in Umami
334
- # @option params [String] :domain The full domain of the tracked website
424
+ # @option params [String] :name The name of the website in Umami (required)
425
+ # @option params [String] :domain The full domain of the tracked website (required)
335
426
  # @option params [String] :shareId A unique string to enable a share url
336
427
  # @return [Hash] Updated website details
337
- # @see https://umami.is/docs/api/websites-api#post-/api/websites/:websiteid
428
+ # @see https://umami.is/docs/api/websites#post-/api/websites/:websiteid
338
429
  def update_website(website_id, params = {})
339
430
  post("/api/websites/#{website_id}", params)
340
431
  end
@@ -342,8 +433,8 @@ module Umami
342
433
  # Delete a website
343
434
  #
344
435
  # @param website_id [String] The website's ID
345
- # @return [String] Confirmation message
346
- # @see https://umami.is/docs/api/websites-api#delete-/api/websites/:websiteid
436
+ # @return [Hash] Confirmation message
437
+ # @see https://umami.is/docs/api/websites#delete-/api/websites/:websiteid
347
438
  def delete_website(website_id)
348
439
  delete("/api/websites/#{website_id}")
349
440
  end
@@ -351,8 +442,8 @@ module Umami
351
442
  # Reset a website's data
352
443
  #
353
444
  # @param website_id [String] The website's ID
354
- # @return [String] Confirmation message
355
- # @see https://umami.is/docs/api/websites-api#post-/api/websites/:websiteid/reset
445
+ # @return [Hash] Confirmation message
446
+ # @see https://umami.is/docs/api/websites#post-/api/websites/:websiteid/reset
356
447
  def reset_website(website_id)
357
448
  post("/api/websites/#{website_id}/reset")
358
449
  end
@@ -361,176 +452,850 @@ module Umami
361
452
 
362
453
  # Get website statistics
363
454
  #
364
- # @param id [String] The website's ID
365
- # @param params [Hash] Query parameters
366
- # @option params [Integer] :startAt Timestamp (in ms) of starting date
367
- # @option params [Integer] :endAt Timestamp (in ms) of end date
368
- # @option params [String] :url Name of URL
369
- # @option params [String] :referrer Name of referrer
370
- # @option params [String] :title Name of page title
371
- # @option params [String] :query Name of query
372
- # @option params [String] :event Name of event
373
- # @option params [String] :os Name of operating system
374
- # @option params [String] :browser Name of browser
375
- # @option params [String] :device Name of device
376
- # @option params [String] :country Name of country
377
- # @option params [String] :region Name of region/state/province
378
- # @option params [String] :city Name of city
379
- # @return [Hash] Website statistics
455
+ # @param website_id [String] The website's ID
456
+ # @param params [Hash] Query parameters
457
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
458
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
459
+ # @option params [String] :path Filter by URL path
460
+ # @option params [String] :referrer Filter by referrer
461
+ # @option params [String] :title Filter by page title
462
+ # @option params [String] :query Filter by query string
463
+ # @option params [String] :os Filter by operating system
464
+ # @option params [String] :browser Filter by browser
465
+ # @option params [String] :device Filter by device type
466
+ # @option params [String] :country Filter by country
467
+ # @option params [String] :region Filter by region/state/province
468
+ # @option params [String] :city Filter by city
469
+ # @option params [String] :hostname Filter by hostname
470
+ # @option params [String] :tag Filter by tag
471
+ # @option params [String] :segment Filter by segment UUID
472
+ # @option params [String] :cohort Filter by cohort UUID
473
+ # @return [Hash] Website statistics including pageviews, visitors, visits, bounces, totaltime
380
474
  # @see https://umami.is/docs/api/website-stats#get-/api/websites/:websiteid/stats
381
- def website_stats(id, params = {})
382
- get("/api/websites/#{id}/stats", params)
475
+ def website_stats(website_id, params = {})
476
+ get("/api/websites/#{website_id}/stats", params)
383
477
  end
384
478
 
385
- # Get active visitors for a website
479
+ # Get active visitors for a website (last 5 minutes)
386
480
  #
387
- # @param id [String] The website's ID
481
+ # @param website_id [String] The website's ID
388
482
  # @return [Hash] Number of active visitors
389
483
  # @see https://umami.is/docs/api/website-stats#get-/api/websites/:websiteid/active
390
- def website_active_visitors(id)
391
- get("/api/websites/#{id}/active")
484
+ def website_active_visitors(website_id)
485
+ get("/api/websites/#{website_id}/active")
392
486
  end
393
487
 
394
- # Get website events
488
+ # Get website pageviews within a time range
395
489
  #
396
- # @param id [String] The website's ID
490
+ # @param website_id [String] The website's ID
397
491
  # @param params [Hash] Query parameters
398
- # @option params [Integer] :startAt Timestamp (in ms) of starting date
399
- # @option params [Integer] :endAt Timestamp (in ms) of end date
400
- # @option params [String] :unit Time unit (year | month | hour | day)
401
- # @option params [String] :timezone Timezone (ex. America/Los_Angeles)
402
- # @option params [String] :url Name of URL
492
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
493
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
494
+ # @option params [String] :unit Time unit for grouping ('minute', 'hour', 'day', 'month', 'year') (required)
495
+ # @option params [String] :timezone Timezone (e.g., 'America/Los_Angeles')
496
+ # @option params [String] :compare Comparison mode ('prev' or 'yoy')
497
+ # @option params [String] :path Filter by URL path
498
+ # @option params [String] :referrer Filter by referrer
499
+ # @option params [String] :title Filter by page title
500
+ # @option params [String] :os Filter by operating system
501
+ # @option params [String] :browser Filter by browser
502
+ # @option params [String] :device Filter by device type
503
+ # @option params [String] :country Filter by country
504
+ # @option params [String] :region Filter by region/state/province
505
+ # @option params [String] :city Filter by city
506
+ # @option params [String] :hostname Filter by hostname
507
+ # @option params [String] :tag Filter by tag
508
+ # @option params [String] :segment Filter by segment UUID
509
+ # @option params [String] :cohort Filter by cohort UUID
510
+ # @return [Hash] Pageviews and sessions arrays with timestamp and count
511
+ # @see https://umami.is/docs/api/website-stats#get-/api/websites/:websiteid/pageviews
512
+ def website_pageviews(website_id, params = {})
513
+ get("/api/websites/#{website_id}/pageviews", params)
514
+ end
515
+
516
+ # Get website events within a time range
517
+ #
518
+ # This method returns event data with optional time-series grouping.
519
+ # For paginated event lists with search, use {#website_events_list} instead.
520
+ #
521
+ # @param website_id [String] The website's ID
522
+ # @param params [Hash] Query parameters
523
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
524
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
525
+ # @option params [String] :unit Time unit for grouping ('minute', 'hour', 'day', 'month', 'year')
526
+ # @option params [String] :timezone Timezone (e.g., 'America/Los_Angeles')
403
527
  # @return [Array<Hash>] Website events
528
+ # @see #website_events_list For paginated event list with search
404
529
  # @see https://umami.is/docs/api/website-stats#get-/api/websites/:websiteid/events
405
- def website_events(id, params = {})
406
- get("/api/websites/#{id}/events", params)
407
- end
408
-
409
- # Get website pageviews
410
- #
411
- # @param id [String] The website's ID
412
- # @param params [Hash] Query parameters
413
- # @option params [Integer] :startAt Timestamp (in ms) of starting date
414
- # @option params [Integer] :endAt Timestamp (in ms) of end date
415
- # @option params [String] :unit Time unit (year | month | hour | day)
416
- # @option params [String] :timezone Timezone (ex. America/Los_Angeles)
417
- # @option params [String] :url Name of URL
418
- # @option params [String] :referrer Name of referrer
419
- # @option params [String] :title Name of page title
420
- # @option params [String] :os Name of operating system
421
- # @option params [String] :browser Name of browser
422
- # @option params [String] :device Name of device
423
- # @option params [String] :country Name of country
424
- # @option params [String] :region Name of region/state/province
425
- # @option params [String] :city Name of city
426
- # @return [Hash] Website pageviews and sessions
427
- # @see https://umami.is/docs/api/website-stats#get-/api/websites/:websiteid/pageviews
428
- def website_pageviews(id, params = {})
429
- get("/api/websites/#{id}/pageviews", params)
530
+ def website_events(website_id, params = {})
531
+ get("/api/websites/#{website_id}/events", params)
532
+ end
533
+
534
+ # Get website events series within a time range
535
+ #
536
+ # @param website_id [String] The website's ID
537
+ # @param params [Hash] Query parameters
538
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
539
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
540
+ # @option params [String] :unit Time unit for grouping ('minute', 'hour', 'day', 'month', 'year') (required)
541
+ # @option params [String] :timezone Timezone (e.g., 'America/Los_Angeles')
542
+ # @option params [String] :path Filter by URL path
543
+ # @option params [String] :referrer Filter by referrer
544
+ # @option params [String] :title Filter by page title
545
+ # @option params [String] :os Filter by operating system
546
+ # @option params [String] :browser Filter by browser
547
+ # @option params [String] :device Filter by device type
548
+ # @option params [String] :country Filter by country
549
+ # @option params [String] :region Filter by region/state/province
550
+ # @option params [String] :city Filter by city
551
+ # @option params [String] :hostname Filter by hostname
552
+ # @option params [String] :tag Filter by tag
553
+ # @option params [String] :segment Filter by segment UUID
554
+ # @option params [String] :cohort Filter by cohort UUID
555
+ # @return [Array<Hash>] Event series with x (event name), t (timestamp), y (count)
556
+ # @see https://umami.is/docs/api/website-stats#get-/api/websites/:websiteid/events/series
557
+ def website_events_series(website_id, params = {})
558
+ get("/api/websites/#{website_id}/events/series", params)
430
559
  end
431
560
 
432
561
  # Get website metrics
433
562
  #
434
- # @param id [String] The website's ID
435
- # @param params [Hash] Query parameters
436
- # @option params [Integer] :startAt Timestamp (in ms) of starting date
437
- # @option params [Integer] :endAt Timestamp (in ms) of end date
438
- # @option params [String] :type Metrics type (url | referrer | browser | os | device | country | event)
439
- # @option params [String] :url Name of URL
440
- # @option params [String] :referrer Name of referrer
441
- # @option params [String] :title Name of page title
442
- # @option params [String] :query Name of query
443
- # @option params [String] :event Name of event
444
- # @option params [String] :os Name of operating system
445
- # @option params [String] :browser Name of browser
446
- # @option params [String] :device Name of device
447
- # @option params [String] :country Name of country
448
- # @option params [String] :region Name of region/state/province
449
- # @option params [String] :city Name of city
450
- # @option params [String] :language Name of language
563
+ # @param website_id [String] The website's ID
564
+ # @param params [Hash] Query parameters
565
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
566
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
567
+ # @option params [String] :type Metrics type (required): 'path', 'entry', 'exit', 'title', 'query', 'referrer', 'channel', 'domain', 'country', 'region', 'city', 'browser', 'os', 'device', 'language', 'screen', 'event', 'hostname', 'tag'
451
568
  # @option params [Integer] :limit Number of results to return (default: 500)
452
- # @return [Array<Hash>] Website metrics
569
+ # @option params [Integer] :offset Number of results to skip (default: 0)
570
+ # @option params [String] :path Filter by URL path
571
+ # @option params [String] :referrer Filter by referrer
572
+ # @option params [String] :title Filter by page title
573
+ # @option params [String] :query Filter by query string
574
+ # @option params [String] :os Filter by operating system
575
+ # @option params [String] :browser Filter by browser
576
+ # @option params [String] :device Filter by device type
577
+ # @option params [String] :country Filter by country
578
+ # @option params [String] :region Filter by region/state/province
579
+ # @option params [String] :city Filter by city
580
+ # @option params [String] :language Filter by language
581
+ # @option params [String] :tag Filter by tag
582
+ # @option params [String] :segment Filter by segment UUID
583
+ # @option params [String] :cohort Filter by cohort UUID
584
+ # @return [Array<Hash>] Website metrics with x (value) and y (visitor count)
453
585
  # @see https://umami.is/docs/api/website-stats#get-/api/websites/:websiteid/metrics
454
- def website_metrics(id, params = {})
455
- get("/api/websites/#{id}/metrics", params)
586
+ def website_metrics(website_id, params = {})
587
+ get("/api/websites/#{website_id}/metrics", params)
456
588
  end
457
589
 
458
- # Get event data events
590
+ # Get expanded website metrics with detailed engagement data
459
591
  #
460
592
  # @param website_id [String] The website's ID
461
593
  # @param params [Hash] Query parameters
462
- # @option params [Integer] :startAt Timestamp (in ms) of starting date
463
- # @option params [Integer] :endAt Timestamp (in ms) of end date
464
- # @option params [String] :event Event Name filter
465
- # @return [Array<Hash>] Event data events
466
- # @see https://umami.is/docs/api/event-data#get-/api/event-data/events
467
- def event_data_events(website_id, params = {})
468
- get("/api/event-data/events", params.merge(websiteId: website_id))
594
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
595
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
596
+ # @option params [String] :type Metrics type (required): 'path', 'entry', 'exit', 'title', 'query', 'referrer', 'channel', 'domain', 'country', 'region', 'city', 'browser', 'os', 'device', 'language', 'screen', 'event', 'hostname', 'tag'
597
+ # @option params [Integer] :limit Number of results to return (default: 500)
598
+ # @option params [Integer] :offset Number of results to skip (default: 0)
599
+ # @option params [String] :path Filter by URL path
600
+ # @option params [String] :referrer Filter by referrer
601
+ # @option params [String] :title Filter by page title
602
+ # @option params [String] :query Filter by query string
603
+ # @option params [String] :os Filter by operating system
604
+ # @option params [String] :browser Filter by browser
605
+ # @option params [String] :device Filter by device type
606
+ # @option params [String] :country Filter by country
607
+ # @option params [String] :region Filter by region/state/province
608
+ # @option params [String] :city Filter by city
609
+ # @option params [String] :language Filter by language
610
+ # @option params [String] :tag Filter by tag
611
+ # @option params [String] :segment Filter by segment UUID
612
+ # @option params [String] :cohort Filter by cohort UUID
613
+ # @return [Array<Hash>] Expanded metrics with name, pageviews, visitors, visits, bounces, totaltime
614
+ # @see https://umami.is/docs/api/website-stats#get-/api/websites/:websiteid/metrics/expanded
615
+ def website_metrics_expanded(website_id, params = {})
616
+ get("/api/websites/#{website_id}/metrics/expanded", params)
469
617
  end
470
618
 
619
+ # -------- Sessions endpoints --------
471
620
 
472
- # -------- Event data endpoints --------
621
+ # Get website sessions within a time range
622
+ #
623
+ # @param website_id [String] The website's ID
624
+ # @param params [Hash] Query parameters
625
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
626
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
627
+ # @option params [String] :search Search text
628
+ # @option params [Integer] :page Page number (default: 1)
629
+ # @option params [Integer] :pageSize Number of results per page (default: 20)
630
+ # @option params [String] :path Filter by URL path
631
+ # @option params [String] :referrer Filter by referrer
632
+ # @option params [String] :title Filter by page title
633
+ # @option params [String] :query Filter by query string
634
+ # @option params [String] :os Filter by operating system
635
+ # @option params [String] :browser Filter by browser
636
+ # @option params [String] :device Filter by device type
637
+ # @option params [String] :country Filter by country
638
+ # @option params [String] :region Filter by region/state/province
639
+ # @option params [String] :city Filter by city
640
+ # @option params [String] :hostname Filter by hostname
641
+ # @option params [String] :tag Filter by tag
642
+ # @option params [String] :segment Filter by segment UUID
643
+ # @option params [String] :cohort Filter by cohort UUID
644
+ # @return [Hash] Paginated list of sessions
645
+ # @see https://umami.is/docs/api/sessions#get-/api/websites/:websiteid/sessions
646
+ def website_sessions(website_id, params = {})
647
+ get("/api/websites/#{website_id}/sessions", params)
648
+ end
473
649
 
474
- # Get event data fields
650
+ # Get summarized session statistics
475
651
  #
476
652
  # @param website_id [String] The website's ID
477
653
  # @param params [Hash] Query parameters
478
- # @option params [Integer] :startAt Timestamp (in ms) of starting date
479
- # @option params [Integer] :endAt Timestamp (in ms) of end date
480
- # @return [Array<Hash>] Event data fields
481
- # @see https://umami.is/docs/api/event-data#get-/api/event-data/fields
482
- def event_data_fields(website_id, params = {})
483
- get("/api/event-data/fields", params.merge(websiteId: website_id))
654
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
655
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
656
+ # @option params [String] :path Filter by URL path
657
+ # @option params [String] :referrer Filter by referrer
658
+ # @option params [String] :title Filter by page title
659
+ # @option params [String] :query Filter by query string
660
+ # @option params [String] :os Filter by operating system
661
+ # @option params [String] :browser Filter by browser
662
+ # @option params [String] :device Filter by device type
663
+ # @option params [String] :country Filter by country
664
+ # @option params [String] :region Filter by region/state/province
665
+ # @option params [String] :city Filter by city
666
+ # @option params [String] :hostname Filter by hostname
667
+ # @option params [String] :tag Filter by tag
668
+ # @option params [String] :segment Filter by segment UUID
669
+ # @option params [String] :cohort Filter by cohort UUID
670
+ # @return [Hash] Session statistics including pageviews, visitors, visits, countries, events
671
+ # @see https://umami.is/docs/api/sessions#get-/api/websites/:websiteid/sessions/stats
672
+ def website_sessions_stats(website_id, params = {})
673
+ get("/api/websites/#{website_id}/sessions/stats", params)
674
+ end
675
+
676
+ # Get session counts by hour of weekday
677
+ #
678
+ # @param website_id [String] The website's ID
679
+ # @param params [Hash] Query parameters
680
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
681
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
682
+ # @option params [String] :timezone Timezone (e.g., 'America/Los_Angeles') (required)
683
+ # @option params [String] :path Filter by URL path
684
+ # @option params [String] :referrer Filter by referrer
685
+ # @option params [String] :title Filter by page title
686
+ # @option params [String] :query Filter by query string
687
+ # @option params [String] :os Filter by operating system
688
+ # @option params [String] :browser Filter by browser
689
+ # @option params [String] :device Filter by device type
690
+ # @option params [String] :country Filter by country
691
+ # @option params [String] :region Filter by region/state/province
692
+ # @option params [String] :city Filter by city
693
+ # @option params [String] :hostname Filter by hostname
694
+ # @option params [String] :tag Filter by tag
695
+ # @option params [String] :segment Filter by segment UUID
696
+ # @option params [String] :cohort Filter by cohort UUID
697
+ # @return [Array<Array>] 7x24 matrix of session counts by weekday and hour
698
+ # @see https://umami.is/docs/api/sessions#get-/api/websites/:websiteid/sessions/weekly
699
+ def website_sessions_weekly(website_id, params = {})
700
+ get("/api/websites/#{website_id}/sessions/weekly", params)
701
+ end
702
+
703
+ # Get details for an individual session
704
+ #
705
+ # @param website_id [String] The website's ID
706
+ # @param session_id [String] The session's ID
707
+ # @return [Hash] Session details including browser, os, device, visits, views, events, totaltime
708
+ # @see https://umami.is/docs/api/sessions#get-/api/websites/:websiteid/sessions/:sessionid
709
+ def website_session(website_id, session_id)
710
+ get("/api/websites/#{website_id}/sessions/#{session_id}")
711
+ end
712
+
713
+ # Get activity for an individual session
714
+ #
715
+ # @param website_id [String] The website's ID
716
+ # @param session_id [String] The session's ID
717
+ # @param params [Hash] Query parameters
718
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
719
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
720
+ # @return [Array<Hash>] Session activity records
721
+ # @see https://umami.is/docs/api/sessions#get-/api/websites/:websiteid/sessions/:sessionid/activity
722
+ def website_session_activity(website_id, session_id, params = {})
723
+ get("/api/websites/#{website_id}/sessions/#{session_id}/activity", params)
724
+ end
725
+
726
+ # Get properties for an individual session
727
+ #
728
+ # @param website_id [String] The website's ID
729
+ # @param session_id [String] The session's ID
730
+ # @return [Array<Hash>] Session properties
731
+ # @see https://umami.is/docs/api/sessions#get-/api/websites/:websiteid/sessions/:sessionid/properties
732
+ def website_session_properties(website_id, session_id)
733
+ get("/api/websites/#{website_id}/sessions/#{session_id}/properties")
734
+ end
735
+
736
+ # Get session data property counts
737
+ #
738
+ # @param website_id [String] The website's ID
739
+ # @param params [Hash] Query parameters
740
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
741
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
742
+ # @option params [String] :path Filter by URL path
743
+ # @option params [String] :referrer Filter by referrer
744
+ # @option params [String] :title Filter by page title
745
+ # @option params [String] :query Filter by query string
746
+ # @option params [String] :os Filter by operating system
747
+ # @option params [String] :browser Filter by browser
748
+ # @option params [String] :device Filter by device type
749
+ # @option params [String] :country Filter by country
750
+ # @option params [String] :region Filter by region/state/province
751
+ # @option params [String] :city Filter by city
752
+ # @option params [String] :hostname Filter by hostname
753
+ # @option params [String] :tag Filter by tag
754
+ # @option params [String] :segment Filter by segment UUID
755
+ # @option params [String] :cohort Filter by cohort UUID
756
+ # @return [Array<Hash>] Property aggregations with propertyName and total
757
+ # @see https://umami.is/docs/api/sessions#get-/api/websites/:websiteid/session-data/properties
758
+ def website_session_data_properties(website_id, params = {})
759
+ get("/api/websites/#{website_id}/session-data/properties", params)
760
+ end
761
+
762
+ # Get session data value counts for a property
763
+ #
764
+ # @param website_id [String] The website's ID
765
+ # @param params [Hash] Query parameters
766
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
767
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
768
+ # @option params [String] :propertyName Property name to query (required)
769
+ # @option params [String] :path Filter by URL path
770
+ # @option params [String] :referrer Filter by referrer
771
+ # @option params [String] :title Filter by page title
772
+ # @option params [String] :query Filter by query string
773
+ # @option params [String] :os Filter by operating system
774
+ # @option params [String] :browser Filter by browser
775
+ # @option params [String] :device Filter by device type
776
+ # @option params [String] :country Filter by country
777
+ # @option params [String] :region Filter by region/state/province
778
+ # @option params [String] :city Filter by city
779
+ # @option params [String] :hostname Filter by hostname
780
+ # @option params [String] :tag Filter by tag
781
+ # @option params [String] :segment Filter by segment UUID
782
+ # @option params [String] :cohort Filter by cohort UUID
783
+ # @return [Array<Hash>] Value aggregations with value and total
784
+ # @see https://umami.is/docs/api/sessions#get-/api/websites/:websiteid/session-data/values
785
+ def website_session_data_values(website_id, params = {})
786
+ get("/api/websites/#{website_id}/session-data/values", params)
787
+ end
788
+
789
+ # -------- Events endpoints --------
790
+
791
+ # Get website event details within a time range (paginated list)
792
+ #
793
+ # This method returns a paginated list of individual events with full details
794
+ # and supports search and filtering. For time-series grouped event data,
795
+ # use {#website_events} or {#website_events_series} instead.
796
+ #
797
+ # @param website_id [String] The website's ID
798
+ # @param params [Hash] Query parameters
799
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
800
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
801
+ # @option params [String] :search Search text
802
+ # @option params [Integer] :page Page number (default: 1)
803
+ # @option params [Integer] :pageSize Number of results per page (default: 20)
804
+ # @option params [String] :path Filter by URL path
805
+ # @option params [String] :referrer Filter by referrer
806
+ # @option params [String] :title Filter by page title
807
+ # @option params [String] :query Filter by query string
808
+ # @option params [String] :os Filter by operating system
809
+ # @option params [String] :browser Filter by browser
810
+ # @option params [String] :device Filter by device type
811
+ # @option params [String] :country Filter by country
812
+ # @option params [String] :region Filter by region/state/province
813
+ # @option params [String] :city Filter by city
814
+ # @option params [String] :hostname Filter by hostname
815
+ # @option params [String] :tag Filter by tag
816
+ # @option params [String] :segment Filter by segment UUID
817
+ # @option params [String] :cohort Filter by cohort UUID
818
+ # @return [Hash] Paginated list of events with full event details
819
+ # @see #website_events For time-series grouped event data
820
+ # @see #website_events_series For event series with x/t/y format
821
+ # @see https://umami.is/docs/api/events#get-/api/websites/:websiteid/events
822
+ def website_events_list(website_id, params = {})
823
+ get("/api/websites/#{website_id}/events", params)
824
+ end
825
+
826
+ # Get event data for an individual event
827
+ #
828
+ # @param website_id [String] The website's ID
829
+ # @param event_id [String] The event's ID
830
+ # @return [Array<Hash>] Event data properties
831
+ # @see https://umami.is/docs/api/events#get-/api/websites/:websiteid/event-data/:eventid
832
+ def website_event_data(website_id, event_id)
833
+ get("/api/websites/#{website_id}/event-data/#{event_id}")
834
+ end
835
+
836
+ # Get event data names, properties, and counts
837
+ #
838
+ # @param website_id [String] The website's ID
839
+ # @param params [Hash] Query parameters
840
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
841
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
842
+ # @option params [String] :event Event name filter
843
+ # @option params [String] :path Filter by URL path
844
+ # @option params [String] :referrer Filter by referrer
845
+ # @option params [String] :title Filter by page title
846
+ # @option params [String] :query Filter by query string
847
+ # @option params [String] :os Filter by operating system
848
+ # @option params [String] :browser Filter by browser
849
+ # @option params [String] :device Filter by device type
850
+ # @option params [String] :country Filter by country
851
+ # @option params [String] :region Filter by region/state/province
852
+ # @option params [String] :city Filter by city
853
+ # @option params [String] :hostname Filter by hostname
854
+ # @option params [String] :tag Filter by tag
855
+ # @option params [String] :segment Filter by segment UUID
856
+ # @option params [String] :cohort Filter by cohort UUID
857
+ # @return [Array<Hash>] Event data with eventName, propertyName, dataType, total
858
+ # @see https://umami.is/docs/api/events#get-/api/websites/:websiteid/event-data/events
859
+ def website_event_data_events(website_id, params = {})
860
+ get("/api/websites/#{website_id}/event-data/events", params)
861
+ end
862
+
863
+ # Get event data fields within a time range
864
+ #
865
+ # @param website_id [String] The website's ID
866
+ # @param params [Hash] Query parameters
867
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
868
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
869
+ # @option params [String] :path Filter by URL path
870
+ # @option params [String] :referrer Filter by referrer
871
+ # @option params [String] :title Filter by page title
872
+ # @option params [String] :query Filter by query string
873
+ # @option params [String] :os Filter by operating system
874
+ # @option params [String] :browser Filter by browser
875
+ # @option params [String] :device Filter by device type
876
+ # @option params [String] :country Filter by country
877
+ # @option params [String] :region Filter by region/state/province
878
+ # @option params [String] :city Filter by city
879
+ # @option params [String] :hostname Filter by hostname
880
+ # @option params [String] :tag Filter by tag
881
+ # @option params [String] :segment Filter by segment UUID
882
+ # @option params [String] :cohort Filter by cohort UUID
883
+ # @return [Array<Hash>] Event data fields with propertyName, dataType, value, total
884
+ # @see https://umami.is/docs/api/events#get-/api/websites/:websiteid/event-data/fields
885
+ def website_event_data_fields(website_id, params = {})
886
+ get("/api/websites/#{website_id}/event-data/fields", params)
887
+ end
888
+
889
+ # Get event name and property counts
890
+ #
891
+ # @param website_id [String] The website's ID
892
+ # @param params [Hash] Query parameters
893
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
894
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
895
+ # @option params [String] :path Filter by URL path
896
+ # @option params [String] :referrer Filter by referrer
897
+ # @option params [String] :title Filter by page title
898
+ # @option params [String] :query Filter by query string
899
+ # @option params [String] :os Filter by operating system
900
+ # @option params [String] :browser Filter by browser
901
+ # @option params [String] :device Filter by device type
902
+ # @option params [String] :country Filter by country
903
+ # @option params [String] :region Filter by region/state/province
904
+ # @option params [String] :city Filter by city
905
+ # @option params [String] :hostname Filter by hostname
906
+ # @option params [String] :tag Filter by tag
907
+ # @option params [String] :segment Filter by segment UUID
908
+ # @option params [String] :cohort Filter by cohort UUID
909
+ # @return [Array<Hash>] Event properties with eventName, propertyName, total
910
+ # @see https://umami.is/docs/api/events#get-/api/websites/:websiteid/event-data/properties
911
+ def website_event_data_properties(website_id, params = {})
912
+ get("/api/websites/#{website_id}/event-data/properties", params)
484
913
  end
485
914
 
486
- # Get event data stats
915
+ # Get event data value counts for a given event and property
487
916
  #
488
917
  # @param website_id [String] The website's ID
489
918
  # @param params [Hash] Query parameters
490
- # @option params [Integer] :startAt Timestamp (in ms) of starting date
491
- # @option params [Integer] :endAt Timestamp (in ms) of end date
492
- # @return [Array<Hash>] Event data stats
493
- # @see https://umami.is/docs/api/event-data#get-/api/event-data/stats
919
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
920
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
921
+ # @option params [String] :event Event name (required)
922
+ # @option params [String] :propertyName Property name (required)
923
+ # @option params [String] :path Filter by URL path
924
+ # @option params [String] :referrer Filter by referrer
925
+ # @option params [String] :title Filter by page title
926
+ # @option params [String] :query Filter by query string
927
+ # @option params [String] :os Filter by operating system
928
+ # @option params [String] :browser Filter by browser
929
+ # @option params [String] :device Filter by device type
930
+ # @option params [String] :country Filter by country
931
+ # @option params [String] :region Filter by region/state/province
932
+ # @option params [String] :city Filter by city
933
+ # @option params [String] :hostname Filter by hostname
934
+ # @option params [String] :tag Filter by tag
935
+ # @option params [String] :segment Filter by segment UUID
936
+ # @option params [String] :cohort Filter by cohort UUID
937
+ # @return [Array<Hash>] Value counts with value and total
938
+ # @see https://umami.is/docs/api/events#get-/api/websites/:websiteid/event-data/values
939
+ def website_event_data_values(website_id, params = {})
940
+ get("/api/websites/#{website_id}/event-data/values", params)
941
+ end
942
+
943
+ # Get aggregated event statistics
944
+ #
945
+ # @param website_id [String] The website's ID
946
+ # @param params [Hash] Query parameters
947
+ # @option params [Integer] :startAt Timestamp (in ms) of starting date (required)
948
+ # @option params [Integer] :endAt Timestamp (in ms) of end date (required)
949
+ # @option params [String] :path Filter by URL path
950
+ # @option params [String] :referrer Filter by referrer
951
+ # @option params [String] :title Filter by page title
952
+ # @option params [String] :query Filter by query string
953
+ # @option params [String] :os Filter by operating system
954
+ # @option params [String] :browser Filter by browser
955
+ # @option params [String] :device Filter by device type
956
+ # @option params [String] :country Filter by country
957
+ # @option params [String] :region Filter by region/state/province
958
+ # @option params [String] :city Filter by city
959
+ # @option params [String] :hostname Filter by hostname
960
+ # @option params [String] :tag Filter by tag
961
+ # @option params [String] :segment Filter by segment UUID
962
+ # @option params [String] :cohort Filter by cohort UUID
963
+ # @return [Array<Hash>] Event stats with events, properties, records counts
964
+ # @see https://umami.is/docs/api/events#get-/api/websites/:websiteid/event-data/stats
965
+ def website_event_data_stats(website_id, params = {})
966
+ get("/api/websites/#{website_id}/event-data/stats", params)
967
+ end
968
+
969
+ # -------- Deprecated event data methods --------
970
+
971
+ # @deprecated Use {#website_event_data_events} instead
972
+ def event_data_events(website_id, params = {})
973
+ warn "[DEPRECATION] `event_data_events` is deprecated. Use `website_event_data_events` instead."
974
+ website_event_data_events(website_id, params)
975
+ end
976
+
977
+ # @deprecated Use {#website_event_data_fields} instead
978
+ def event_data_fields(website_id, params = {})
979
+ warn "[DEPRECATION] `event_data_fields` is deprecated. Use `website_event_data_fields` instead."
980
+ website_event_data_fields(website_id, params)
981
+ end
982
+
983
+ # @deprecated Use {#website_event_data_stats} instead
494
984
  def event_data_stats(website_id, params = {})
495
- get("/api/event-data/stats", params.merge(websiteId: website_id))
985
+ warn "[DEPRECATION] `event_data_stats` is deprecated. Use `website_event_data_stats` instead."
986
+ website_event_data_stats(website_id, params)
987
+ end
988
+
989
+ # -------- Realtime endpoints --------
990
+
991
+ # Get realtime stats for a website (last 30 minutes)
992
+ #
993
+ # @param website_id [String] The website's ID
994
+ # @return [Hash] Realtime data including countries, urls, referrers, events, series, totals
995
+ # @see https://umami.is/docs/api/realtime#get-/api/realtime/:websiteid
996
+ def realtime(website_id)
997
+ get("/api/realtime/#{website_id}")
998
+ end
999
+
1000
+ # -------- Links endpoints --------
1001
+
1002
+ # Get all links
1003
+ #
1004
+ # @param params [Hash] Query parameters
1005
+ # @option params [String] :search Search text
1006
+ # @option params [Integer] :page Page number (default: 1)
1007
+ # @option params [Integer] :pageSize Number of results per page
1008
+ # @return [Hash] Paginated list of links
1009
+ # @see https://umami.is/docs/api/links#get-/api/links
1010
+ def links(params = {})
1011
+ get("/api/links", params)
1012
+ end
1013
+
1014
+ # Get a link by ID
1015
+ #
1016
+ # @param link_id [String] The link's ID
1017
+ # @return [Hash] Link details
1018
+ # @see https://umami.is/docs/api/links#get-/api/links/:linkid
1019
+ def link(link_id)
1020
+ get("/api/links/#{link_id}")
1021
+ end
1022
+
1023
+ # Update a link
1024
+ #
1025
+ # @param link_id [String] The link's ID
1026
+ # @param params [Hash] Link parameters to update
1027
+ # @option params [String] :name Link name
1028
+ # @option params [String] :url Destination URL
1029
+ # @option params [String] :slug URL slug (minimum 8 characters)
1030
+ # @return [Hash] Updated link details
1031
+ # @see https://umami.is/docs/api/links#post-/api/links/:linkid
1032
+ def update_link(link_id, params = {})
1033
+ post("/api/links/#{link_id}", params)
1034
+ end
1035
+
1036
+ # Delete a link
1037
+ #
1038
+ # @param link_id [String] The link's ID
1039
+ # @return [Hash] Confirmation message
1040
+ # @see https://umami.is/docs/api/links#delete-/api/links/:linkid
1041
+ def delete_link(link_id)
1042
+ delete("/api/links/#{link_id}")
1043
+ end
1044
+
1045
+ # -------- Pixels endpoints --------
1046
+
1047
+ # Get all pixels
1048
+ #
1049
+ # @param params [Hash] Query parameters
1050
+ # @option params [String] :search Search text
1051
+ # @option params [Integer] :page Page number (default: 1)
1052
+ # @option params [Integer] :pageSize Number of results per page
1053
+ # @return [Hash] Paginated list of pixels
1054
+ # @see https://umami.is/docs/api/pixels#get-/api/pixels
1055
+ def pixels(params = {})
1056
+ get("/api/pixels", params)
1057
+ end
1058
+
1059
+ # Get a pixel by ID
1060
+ #
1061
+ # @param pixel_id [String] The pixel's ID
1062
+ # @return [Hash] Pixel details
1063
+ # @see https://umami.is/docs/api/pixels#get-/api/pixels/:pixelid
1064
+ def pixel(pixel_id)
1065
+ get("/api/pixels/#{pixel_id}")
1066
+ end
1067
+
1068
+ # Update a pixel
1069
+ #
1070
+ # @param pixel_id [String] The pixel's ID
1071
+ # @param params [Hash] Pixel parameters to update
1072
+ # @option params [String] :name Pixel name
1073
+ # @option params [String] :slug URL slug (minimum 8 characters)
1074
+ # @return [Hash] Updated pixel details
1075
+ # @see https://umami.is/docs/api/pixels#post-/api/pixels/:pixelid
1076
+ def update_pixel(pixel_id, params = {})
1077
+ post("/api/pixels/#{pixel_id}", params)
1078
+ end
1079
+
1080
+ # Delete a pixel
1081
+ #
1082
+ # @param pixel_id [String] The pixel's ID
1083
+ # @return [Hash] Confirmation message
1084
+ # @see https://umami.is/docs/api/pixels#delete-/api/pixels/:pixelid
1085
+ def delete_pixel(pixel_id)
1086
+ delete("/api/pixels/#{pixel_id}")
1087
+ end
1088
+
1089
+ # -------- Reports endpoints --------
1090
+
1091
+ # Get all reports
1092
+ #
1093
+ # @param params [Hash] Query parameters
1094
+ # @option params [String] :websiteId Website ID to filter by
1095
+ # @option params [String] :type Report type to filter by ('attribution', 'breakdown', 'funnel', 'goal', 'journey', 'retention', 'revenue', 'utm')
1096
+ # @option params [Integer] :page Page number (default: 1)
1097
+ # @option params [Integer] :pageSize Number of results per page
1098
+ # @return [Hash] Paginated list of reports
1099
+ # @see https://umami.is/docs/api/reports#get-/api/reports
1100
+ def reports(params = {})
1101
+ get("/api/reports", params)
1102
+ end
1103
+
1104
+ # Create a new report
1105
+ #
1106
+ # @param params [Hash] Report parameters
1107
+ # @option params [String] :websiteId Website ID (required)
1108
+ # @option params [String] :type Report type (required)
1109
+ # @option params [String] :name Report name (required)
1110
+ # @option params [String] :description Report description
1111
+ # @option params [Hash] :parameters Report-specific parameters
1112
+ # @return [Hash] Created report details
1113
+ # @see https://umami.is/docs/api/reports#post-/api/reports
1114
+ def create_report(params = {})
1115
+ post("/api/reports", params)
1116
+ end
1117
+
1118
+ # Get a report by ID
1119
+ #
1120
+ # @param report_id [String] The report's ID
1121
+ # @return [Hash] Report details
1122
+ # @see https://umami.is/docs/api/reports#get-/api/reports/:reportid
1123
+ def report(report_id)
1124
+ get("/api/reports/#{report_id}")
1125
+ end
1126
+
1127
+ # Update a report
1128
+ #
1129
+ # @param report_id [String] The report's ID
1130
+ # @param params [Hash] Report parameters to update
1131
+ # @option params [String] :name Report name
1132
+ # @option params [String] :description Report description
1133
+ # @option params [Hash] :parameters Report-specific parameters
1134
+ # @return [Hash] Updated report details
1135
+ # @see https://umami.is/docs/api/reports#post-/api/reports/:reportid
1136
+ def update_report(report_id, params = {})
1137
+ post("/api/reports/#{report_id}", params)
1138
+ end
1139
+
1140
+ # Delete a report
1141
+ #
1142
+ # @param report_id [String] The report's ID
1143
+ # @return [Hash] Confirmation message
1144
+ # @see https://umami.is/docs/api/reports#delete-/api/reports/:reportid
1145
+ def delete_report(report_id)
1146
+ delete("/api/reports/#{report_id}")
1147
+ end
1148
+
1149
+ # Run an attribution report
1150
+ #
1151
+ # @param params [Hash] Report parameters
1152
+ # @option params [String] :websiteId Website ID (required)
1153
+ # @option params [String] :startDate Start date in ISO 8601 format (required)
1154
+ # @option params [String] :endDate End date in ISO 8601 format (required)
1155
+ # @option params [String] :model Attribution model ('firstClick' or 'lastClick')
1156
+ # @option params [String] :type Attribution type ('path' or 'event')
1157
+ # @option params [Integer] :step Step number
1158
+ # @option params [Hash] :filters Filter criteria (path, referrer, title, query, browser, os, device, country, region, city, hostname, tag, segment, cohort)
1159
+ # @return [Hash] Attribution report data
1160
+ # @see https://umami.is/docs/api/reports#post-/api/reports/attribution
1161
+ def report_attribution(params = {})
1162
+ post("/api/reports/attribution", params)
1163
+ end
1164
+
1165
+ # Run a breakdown report
1166
+ #
1167
+ # @param params [Hash] Report parameters
1168
+ # @option params [String] :websiteId Website ID (required)
1169
+ # @option params [String] :startDate Start date in ISO 8601 format (required)
1170
+ # @option params [String] :endDate End date in ISO 8601 format (required)
1171
+ # @option params [Array<String>] :fields Fields to break down by (path, title, query, referrer, browser, os, device, country, region, city, hostname, tag, event)
1172
+ # @option params [Hash] :filters Filter criteria (path, referrer, title, query, browser, os, device, country, region, city, hostname, tag, segment, cohort)
1173
+ # @return [Hash] Breakdown report data
1174
+ # @see https://umami.is/docs/api/reports#post-/api/reports/breakdown
1175
+ def report_breakdown(params = {})
1176
+ post("/api/reports/breakdown", params)
1177
+ end
1178
+
1179
+ # Run a funnel report
1180
+ #
1181
+ # @param params [Hash] Report parameters
1182
+ # @option params [String] :websiteId Website ID (required)
1183
+ # @option params [String] :startDate Start date in ISO 8601 format (required)
1184
+ # @option params [String] :endDate End date in ISO 8601 format (required)
1185
+ # @option params [Array<Hash>] :steps Funnel steps (minimum 2, each with type and value)
1186
+ # @option params [Integer] :window Number of days between steps
1187
+ # @option params [Hash] :filters Filter criteria (path, referrer, title, query, browser, os, device, country, region, city, hostname, tag, segment, cohort)
1188
+ # @return [Hash] Funnel report data with conversion and drop-off rates
1189
+ # @see https://umami.is/docs/api/reports#post-/api/reports/funnel
1190
+ def report_funnel(params = {})
1191
+ post("/api/reports/funnel", params)
1192
+ end
1193
+
1194
+ # Run a goals report
1195
+ #
1196
+ # @param params [Hash] Report parameters
1197
+ # @option params [String] :websiteId Website ID (required)
1198
+ # @option params [String] :startDate Start date in ISO 8601 format (required)
1199
+ # @option params [String] :endDate End date in ISO 8601 format (required)
1200
+ # @option params [String] :type Goal type ('path' or 'event')
1201
+ # @option params [String] :value Goal value
1202
+ # @option params [Hash] :filters Filter criteria (path, referrer, title, query, browser, os, device, country, region, city, hostname, tag, segment, cohort)
1203
+ # @return [Hash] Goals report data
1204
+ # @see https://umami.is/docs/api/reports#post-/api/reports/goals
1205
+ def report_goals(params = {})
1206
+ post("/api/reports/goals", params)
1207
+ end
1208
+
1209
+ # Run a journey report
1210
+ #
1211
+ # @param params [Hash] Report parameters
1212
+ # @option params [String] :websiteId Website ID (required)
1213
+ # @option params [String] :startDate Start date in ISO 8601 format (required)
1214
+ # @option params [String] :endDate End date in ISO 8601 format (required)
1215
+ # @option params [Integer] :steps Number of steps (3-7)
1216
+ # @option params [String] :startStep Starting step path
1217
+ # @option params [String] :endStep Ending step path
1218
+ # @option params [Hash] :filters Filter criteria (path, referrer, title, query, browser, os, device, country, region, city, hostname, tag, segment, cohort)
1219
+ # @return [Hash] Journey report data showing user navigation paths
1220
+ # @see https://umami.is/docs/api/reports#post-/api/reports/journey
1221
+ def report_journey(params = {})
1222
+ post("/api/reports/journey", params)
1223
+ end
1224
+
1225
+ # Run a retention report
1226
+ #
1227
+ # @param params [Hash] Report parameters
1228
+ # @option params [String] :websiteId Website ID (required)
1229
+ # @option params [String] :startDate Start date in ISO 8601 format (required)
1230
+ # @option params [String] :endDate End date in ISO 8601 format (required)
1231
+ # @option params [String] :timezone Timezone (e.g., 'America/Los_Angeles') (required)
1232
+ # @option params [Hash] :filters Filter criteria (path, referrer, title, query, browser, os, device, country, region, city, hostname, tag, segment, cohort)
1233
+ # @return [Hash] Retention report data with day-based return rates
1234
+ # @see https://umami.is/docs/api/reports#post-/api/reports/retention
1235
+ def report_retention(params = {})
1236
+ post("/api/reports/retention", params)
1237
+ end
1238
+
1239
+ # Run a revenue report
1240
+ #
1241
+ # @param params [Hash] Report parameters
1242
+ # @option params [String] :websiteId Website ID (required)
1243
+ # @option params [String] :startDate Start date in ISO 8601 format (required)
1244
+ # @option params [String] :endDate End date in ISO 8601 format (required)
1245
+ # @option params [String] :timezone Timezone (e.g., 'America/Los_Angeles') (required)
1246
+ # @option params [String] :currency ISO 4217 currency code
1247
+ # @option params [Hash] :filters Filter criteria (path, referrer, title, query, browser, os, device, country, region, city, hostname, tag, segment, cohort)
1248
+ # @return [Hash] Revenue report data
1249
+ # @see https://umami.is/docs/api/reports#post-/api/reports/revenue
1250
+ def report_revenue(params = {})
1251
+ post("/api/reports/revenue", params)
1252
+ end
1253
+
1254
+ # Run a UTM report
1255
+ #
1256
+ # @param params [Hash] Report parameters
1257
+ # @option params [String] :websiteId Website ID (required)
1258
+ # @option params [String] :startDate Start date in ISO 8601 format (required)
1259
+ # @option params [String] :endDate End date in ISO 8601 format (required)
1260
+ # @option params [Hash] :filters Filter criteria (path, referrer, title, query, browser, os, device, country, region, city, hostname, tag, segment, cohort)
1261
+ # @return [Hash] UTM report data with campaign parameter breakdown
1262
+ # @see https://umami.is/docs/api/reports#post-/api/reports/utm
1263
+ def report_utm(params = {})
1264
+ post("/api/reports/utm", params)
496
1265
  end
497
1266
 
498
1267
  # -------- Sending stats endpoint --------
499
1268
 
500
- # Send an event
1269
+ # Send an event to Umami
1270
+ #
1271
+ # This method uses a separate connection that:
1272
+ # - Does NOT include Authorization header (not required for /api/send)
1273
+ # - Uses https://cloud.umami.is for Umami Cloud (different from the main API URL)
1274
+ # - Includes a User-Agent header (mandatory per API docs)
501
1275
  #
502
1276
  # @param payload [Hash] Event payload
503
- # @option payload [String] :hostname Name of host
504
- # @option payload [String] :language Language of visitor (ex. "en-US")
1277
+ # @option payload [String] :hostname Name of host (required)
1278
+ # @option payload [String] :language Language of visitor (e.g., "en-US")
505
1279
  # @option payload [String] :referrer Referrer URL
506
- # @option payload [String] :screen Screen resolution (ex. "1920x1080")
1280
+ # @option payload [String] :screen Screen resolution (e.g., "1920x1080")
507
1281
  # @option payload [String] :title Page title
508
- # @option payload [String] :url Page URL
509
- # @option payload [String] :website Website ID
1282
+ # @option payload [String] :url Page URL (required)
1283
+ # @option payload [String] :website Website ID (required)
510
1284
  # @option payload [String] :name Name of the event
1285
+ # @option payload [String] :tag Additional tag description
1286
+ # @option payload [String] :id Session identifier
511
1287
  # @option payload [Hash] :data Additional data for the event
512
- # @return [Hash] Response from the server
1288
+ # @param user_agent [String] Custom User-Agent header (defaults to "umami-ruby/VERSION")
1289
+ # @return [Hash] Response with cache, sessionId, and visitId
1290
+ # @note No authentication required. Uses https://cloud.umami.is for Umami Cloud.
513
1291
  # @see https://umami.is/docs/api/sending-stats
514
- def send_event(payload)
515
- post("/api/send", { type: "event", payload: payload })
1292
+ def send_event(payload, user_agent: default_user_agent)
1293
+ send_post("/api/send", { type: "event", payload: payload }, user_agent: user_agent)
516
1294
  end
517
1295
 
518
1296
 
519
1297
  private
520
1298
 
521
- def authenticate
522
- raise Umami::AuthenticationError, "Username and password are required for authentication" if @username.nil? || @password.nil?
523
-
524
- response = connection.post("/api/auth/login") do |req|
525
- req.body = { username: @username, password: @password }.to_json
526
- end
527
-
528
- data = JSON.parse(response.body)
529
- @access_token = data["token"]
530
- rescue Faraday::Error, JSON::ParserError => e
531
- raise Umami::AuthenticationError, "Authentication failed: #{e.message}"
532
- end
533
-
534
1299
  def get(path, params = {})
535
1300
  response = connection.get(path, params)
536
1301
  JSON.parse(response.body)
@@ -547,11 +1312,17 @@ module Umami
547
1312
 
548
1313
  def delete(path)
549
1314
  response = connection.delete(path)
550
- response.body == "ok" ? "ok" : JSON.parse(response.body)
1315
+ response.body == "ok" ? { "ok" => true } : JSON.parse(response.body)
551
1316
  rescue Faraday::Error => e
552
1317
  handle_error(e)
553
1318
  end
554
1319
 
1320
+ # Memoized so keep-alive and middleware setup are paid once, BUT the
1321
+ # Authorization header is baked in at build time — Faraday connections
1322
+ # don't re-read `@access_token` afterwards. Anything that changes the
1323
+ # token MUST set `@connection = nil` so the next request rebuilds with
1324
+ # the fresh header (see #authenticate, where forgetting exactly that
1325
+ # was the <= 0.2.0 username/password bug).
555
1326
  def connection
556
1327
  @connection ||= Faraday.new(url: uri_base) do |faraday|
557
1328
  faraday.request :json
@@ -562,8 +1333,17 @@ module Umami
562
1333
  end
563
1334
  end
564
1335
 
1336
+ # Order matters: Faraday::UnauthorizedError (401) and ForbiddenError
1337
+ # (403) are SUBCLASSES of Faraday::ClientError
1338
+ # (https://lostisland.github.io/faraday/#/middleware/included/raising-errors),
1339
+ # so they must be matched before the generic 4xx case or they'd
1340
+ # surface as an undifferentiated ClientError. Raising
1341
+ # AuthenticationError instead gives callers a re-authentication signal
1342
+ # (e.g. an expired or revoked token on a long-lived client).
565
1343
  def handle_error(error)
566
1344
  case error
1345
+ when Faraday::UnauthorizedError, Faraday::ForbiddenError
1346
+ raise Umami::AuthenticationError, "Authentication failed: #{error.message}"
567
1347
  when Faraday::ResourceNotFound
568
1348
  raise Umami::NotFoundError, "Resource not found: #{error.message}"
569
1349
  when Faraday::ClientError
@@ -598,5 +1378,56 @@ module Umami
598
1378
  end
599
1379
  end
600
1380
 
1381
+ # -------- Send event helpers --------
1382
+
1383
+ # Default User-Agent for send requests
1384
+ #
1385
+ # @return [String] User-Agent string identifying this gem
1386
+ def default_user_agent
1387
+ "umami-ruby/#{Umami::VERSION}"
1388
+ end
1389
+
1390
+ # Determine the base URL for send requests
1391
+ #
1392
+ # For Umami Cloud, this returns https://cloud.umami.is (different from main API)
1393
+ # For self-hosted, this returns the configured uri_base
1394
+ #
1395
+ # @return [String] Base URL for send endpoint
1396
+ def send_uri_base
1397
+ cloud? ? Umami::Configuration::UMAMI_CLOUD_SEND_URL : @uri_base
1398
+ end
1399
+
1400
+ # Separate connection for send endpoint
1401
+ #
1402
+ # This connection:
1403
+ # - Does NOT include Authorization header (not required for /api/send)
1404
+ # - Includes User-Agent header (mandatory per API docs)
1405
+ # - Not memoized because user_agent can vary per call
1406
+ #
1407
+ # @param user_agent [String] User-Agent header value
1408
+ # @return [Faraday::Connection] Connection for send requests
1409
+ def send_connection(user_agent:)
1410
+ Faraday.new(url: send_uri_base) do |faraday|
1411
+ faraday.request :json
1412
+ faraday.response :raise_error
1413
+ faraday.adapter Faraday.default_adapter
1414
+ faraday.headers["User-Agent"] = user_agent
1415
+ faraday.options.timeout = request_timeout
1416
+ end
1417
+ end
1418
+
1419
+ # POST specifically for send endpoint (unauthenticated)
1420
+ #
1421
+ # @param path [String] API path
1422
+ # @param body [Hash] Request body
1423
+ # @param user_agent [String] User-Agent header value
1424
+ # @return [Hash] Parsed JSON response
1425
+ def send_post(path, body, user_agent:)
1426
+ response = send_connection(user_agent: user_agent).post(path, body.to_json)
1427
+ JSON.parse(response.body)
1428
+ rescue Faraday::Error => e
1429
+ handle_error(e)
1430
+ end
1431
+
601
1432
  end
602
1433
  end