dub 0.27.1__py3-none-any.whl → 0.27.2__py3-none-any.whl

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.
@@ -0,0 +1,516 @@
1
+ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
2
+
3
+ from __future__ import annotations
4
+ from dub.types import BaseModel, Nullable, OptionalNullable, UNSET, UNSET_SENTINEL
5
+ from dub.utils import FieldMetadata, QueryParamMetadata
6
+ from enum import Enum
7
+ import pydantic
8
+ from pydantic import model_serializer
9
+ from typing import List, Optional
10
+ from typing_extensions import Annotated, NotRequired, TypedDict
11
+
12
+
13
+ class ListPartnersQueryParamStatus(str, Enum):
14
+ r"""A filter on the list based on the partner's `status` field."""
15
+
16
+ PENDING = "pending"
17
+ APPROVED = "approved"
18
+ REJECTED = "rejected"
19
+ INVITED = "invited"
20
+ DECLINED = "declined"
21
+ BANNED = "banned"
22
+ ARCHIVED = "archived"
23
+
24
+
25
+ class ListPartnersQueryParamSortBy(str, Enum):
26
+ r"""The field to sort the partners by. The default is `saleAmount`."""
27
+
28
+ CREATED_AT = "createdAt"
29
+ CLICKS = "clicks"
30
+ LEADS = "leads"
31
+ SALES = "sales"
32
+ SALE_AMOUNT = "saleAmount"
33
+ COMMISSIONS = "commissions"
34
+ NET_REVENUE = "netRevenue"
35
+
36
+
37
+ class ListPartnersQueryParamSortOrder(str, Enum):
38
+ r"""The sort order. The default is `desc`."""
39
+
40
+ ASC = "asc"
41
+ DESC = "desc"
42
+
43
+
44
+ class ListPartnersRequestTypedDict(TypedDict):
45
+ status: NotRequired[ListPartnersQueryParamStatus]
46
+ r"""A filter on the list based on the partner's `status` field."""
47
+ country: NotRequired[str]
48
+ r"""A filter on the list based on the partner's `country` field."""
49
+ sort_by: NotRequired[ListPartnersQueryParamSortBy]
50
+ r"""The field to sort the partners by. The default is `saleAmount`."""
51
+ sort_order: NotRequired[ListPartnersQueryParamSortOrder]
52
+ r"""The sort order. The default is `desc`."""
53
+ tenant_id: NotRequired[str]
54
+ r"""A case-sensitive filter on the list based on the partner's `tenantId` field. The value must be a string. Takes precedence over `search`."""
55
+ include_expanded_fields: NotRequired[bool]
56
+ r"""Whether to include stats fields on the partner (`clicks`, `leads`, `sales`, `saleAmount`, `commissions`, `netRevenue`). If false, those fields will be returned as 0."""
57
+ search: NotRequired[str]
58
+ r"""A search query to filter partners by name, email, or tenantId."""
59
+ page: NotRequired[float]
60
+ r"""The page number for pagination."""
61
+ page_size: NotRequired[float]
62
+ r"""The number of items per page."""
63
+
64
+
65
+ class ListPartnersRequest(BaseModel):
66
+ status: Annotated[
67
+ Optional[ListPartnersQueryParamStatus],
68
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
69
+ ] = None
70
+ r"""A filter on the list based on the partner's `status` field."""
71
+
72
+ country: Annotated[
73
+ Optional[str],
74
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
75
+ ] = None
76
+ r"""A filter on the list based on the partner's `country` field."""
77
+
78
+ sort_by: Annotated[
79
+ Optional[ListPartnersQueryParamSortBy],
80
+ pydantic.Field(alias="sortBy"),
81
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
82
+ ] = ListPartnersQueryParamSortBy.SALE_AMOUNT
83
+ r"""The field to sort the partners by. The default is `saleAmount`."""
84
+
85
+ sort_order: Annotated[
86
+ Optional[ListPartnersQueryParamSortOrder],
87
+ pydantic.Field(alias="sortOrder"),
88
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
89
+ ] = ListPartnersQueryParamSortOrder.DESC
90
+ r"""The sort order. The default is `desc`."""
91
+
92
+ tenant_id: Annotated[
93
+ Optional[str],
94
+ pydantic.Field(alias="tenantId"),
95
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
96
+ ] = None
97
+ r"""A case-sensitive filter on the list based on the partner's `tenantId` field. The value must be a string. Takes precedence over `search`."""
98
+
99
+ include_expanded_fields: Annotated[
100
+ Optional[bool],
101
+ pydantic.Field(alias="includeExpandedFields"),
102
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
103
+ ] = None
104
+ r"""Whether to include stats fields on the partner (`clicks`, `leads`, `sales`, `saleAmount`, `commissions`, `netRevenue`). If false, those fields will be returned as 0."""
105
+
106
+ search: Annotated[
107
+ Optional[str],
108
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
109
+ ] = None
110
+ r"""A search query to filter partners by name, email, or tenantId."""
111
+
112
+ page: Annotated[
113
+ Optional[float],
114
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
115
+ ] = 1
116
+ r"""The page number for pagination."""
117
+
118
+ page_size: Annotated[
119
+ Optional[float],
120
+ pydantic.Field(alias="pageSize"),
121
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
122
+ ] = 100
123
+ r"""The number of items per page."""
124
+
125
+
126
+ class ListPartnersStatus(str, Enum):
127
+ r"""The status of the partner's enrollment in the program."""
128
+
129
+ PENDING = "pending"
130
+ APPROVED = "approved"
131
+ REJECTED = "rejected"
132
+ INVITED = "invited"
133
+ DECLINED = "declined"
134
+ BANNED = "banned"
135
+ ARCHIVED = "archived"
136
+
137
+
138
+ class ListPartnersLinkTypedDict(TypedDict):
139
+ id: str
140
+ r"""The unique ID of the short link."""
141
+ domain: str
142
+ r"""The domain of the short link. If not provided, the primary domain for the workspace will be used (or `dub.sh` if the workspace has no domains)."""
143
+ key: str
144
+ r"""The short link slug. If not provided, a random 7-character slug will be generated."""
145
+ short_link: str
146
+ r"""The full URL of the short link, including the https protocol (e.g. `https://dub.sh/try`)."""
147
+ url: str
148
+ r"""The destination URL of the short link."""
149
+ clicks: NotRequired[float]
150
+ r"""The number of clicks on the short link."""
151
+ leads: NotRequired[float]
152
+ r"""The number of leads the short links has generated."""
153
+ sales: NotRequired[float]
154
+ r"""The number of sales the short links has generated."""
155
+ sale_amount: NotRequired[float]
156
+ r"""The total dollar amount of sales the short links has generated (in cents)."""
157
+
158
+
159
+ class ListPartnersLink(BaseModel):
160
+ id: str
161
+ r"""The unique ID of the short link."""
162
+
163
+ domain: str
164
+ r"""The domain of the short link. If not provided, the primary domain for the workspace will be used (or `dub.sh` if the workspace has no domains)."""
165
+
166
+ key: str
167
+ r"""The short link slug. If not provided, a random 7-character slug will be generated."""
168
+
169
+ short_link: Annotated[str, pydantic.Field(alias="shortLink")]
170
+ r"""The full URL of the short link, including the https protocol (e.g. `https://dub.sh/try`)."""
171
+
172
+ url: str
173
+ r"""The destination URL of the short link."""
174
+
175
+ clicks: Optional[float] = 0
176
+ r"""The number of clicks on the short link."""
177
+
178
+ leads: Optional[float] = 0
179
+ r"""The number of leads the short links has generated."""
180
+
181
+ sales: Optional[float] = 0
182
+ r"""The number of sales the short links has generated."""
183
+
184
+ sale_amount: Annotated[Optional[float], pydantic.Field(alias="saleAmount")] = 0
185
+ r"""The total dollar amount of sales the short links has generated (in cents)."""
186
+
187
+
188
+ class ListPartnersBannedReason(str, Enum):
189
+ r"""If the partner was banned from the program, this is the reason for the ban."""
190
+
191
+ TOS_VIOLATION = "tos_violation"
192
+ INAPPROPRIATE_CONTENT = "inappropriate_content"
193
+ FAKE_TRAFFIC = "fake_traffic"
194
+ FRAUD = "fraud"
195
+ SPAM = "spam"
196
+ BRAND_ABUSE = "brand_abuse"
197
+
198
+
199
+ class ListPartnersResponseBodyTypedDict(TypedDict):
200
+ id: str
201
+ r"""The partner's unique ID on Dub."""
202
+ name: str
203
+ r"""The partner's full legal name."""
204
+ email: Nullable[str]
205
+ r"""The partner's email address. Should be a unique value across Dub."""
206
+ image: Nullable[str]
207
+ r"""The partner's avatar image."""
208
+ country: Nullable[str]
209
+ r"""The partner's country (required for tax purposes)."""
210
+ paypal_email: Nullable[str]
211
+ r"""The partner's PayPal email (for receiving payouts via PayPal)."""
212
+ stripe_connect_id: Nullable[str]
213
+ r"""The partner's Stripe Connect ID (for receiving payouts via Stripe)."""
214
+ payouts_enabled_at: Nullable[str]
215
+ r"""The date when the partner enabled payouts."""
216
+ partner_id: str
217
+ r"""The partner's unique ID on Dub."""
218
+ tenant_id: Nullable[str]
219
+ r"""The partner's unique ID within your database. Can be useful for associating the partner with a user in your database and retrieving/update their data in the future."""
220
+ program_id: str
221
+ r"""The program's unique ID on Dub."""
222
+ created_at: str
223
+ status: ListPartnersStatus
224
+ r"""The status of the partner's enrollment in the program."""
225
+ links: Nullable[List[ListPartnersLinkTypedDict]]
226
+ r"""The partner's referral links in this program."""
227
+ description: NotRequired[Nullable[str]]
228
+ r"""A brief description of the partner and their background."""
229
+ total_commissions: NotRequired[float]
230
+ r"""The total commissions paid to the partner for their referrals. Defaults to 0 if `includeExpandedFields` is false."""
231
+ click_reward_id: NotRequired[Nullable[str]]
232
+ lead_reward_id: NotRequired[Nullable[str]]
233
+ sale_reward_id: NotRequired[Nullable[str]]
234
+ discount_id: NotRequired[Nullable[str]]
235
+ application_id: NotRequired[Nullable[str]]
236
+ r"""If the partner submitted an application to join the program, this is the ID of the application."""
237
+ banned_at: NotRequired[Nullable[str]]
238
+ r"""If the partner was banned from the program, this is the date of the ban."""
239
+ banned_reason: NotRequired[Nullable[ListPartnersBannedReason]]
240
+ r"""If the partner was banned from the program, this is the reason for the ban."""
241
+ clicks: NotRequired[float]
242
+ r"""The total number of clicks on the partner's links. Defaults to 0 if `includeExpandedFields` is false."""
243
+ leads: NotRequired[float]
244
+ r"""The total number of leads generated by the partner's links. Defaults to 0 if `includeExpandedFields` is false."""
245
+ sales: NotRequired[float]
246
+ r"""The total number of sales generated by the partner's links. Defaults to 0 if `includeExpandedFields` is false."""
247
+ sale_amount: NotRequired[float]
248
+ r"""The total amount of sales (in cents) generated by the partner's links. Defaults to 0 if `includeExpandedFields` is false."""
249
+ net_revenue: NotRequired[float]
250
+ r"""The total net revenue generated by the partner. Defaults to 0 if `includeExpandedFields` is false."""
251
+ website: NotRequired[Nullable[str]]
252
+ r"""The partner's website URL (including the https protocol)."""
253
+ website_txt_record: NotRequired[Nullable[str]]
254
+ website_verified_at: NotRequired[Nullable[str]]
255
+ youtube: NotRequired[Nullable[str]]
256
+ r"""The partner's YouTube channel username (e.g. `johndoe`)."""
257
+ youtube_verified_at: NotRequired[Nullable[str]]
258
+ youtube_subscriber_count: NotRequired[Nullable[float]]
259
+ youtube_view_count: NotRequired[Nullable[float]]
260
+ twitter: NotRequired[Nullable[str]]
261
+ r"""The partner's Twitter username (e.g. `johndoe`)."""
262
+ twitter_verified_at: NotRequired[Nullable[str]]
263
+ linkedin: NotRequired[Nullable[str]]
264
+ r"""The partner's LinkedIn username (e.g. `johndoe`)."""
265
+ linkedin_verified_at: NotRequired[Nullable[str]]
266
+ instagram: NotRequired[Nullable[str]]
267
+ r"""The partner's Instagram username (e.g. `johndoe`)."""
268
+ instagram_verified_at: NotRequired[Nullable[str]]
269
+ tiktok: NotRequired[Nullable[str]]
270
+ r"""The partner's TikTok username (e.g. `johndoe`)."""
271
+ tiktok_verified_at: NotRequired[Nullable[str]]
272
+
273
+
274
+ class ListPartnersResponseBody(BaseModel):
275
+ id: str
276
+ r"""The partner's unique ID on Dub."""
277
+
278
+ name: str
279
+ r"""The partner's full legal name."""
280
+
281
+ email: Nullable[str]
282
+ r"""The partner's email address. Should be a unique value across Dub."""
283
+
284
+ image: Nullable[str]
285
+ r"""The partner's avatar image."""
286
+
287
+ country: Nullable[str]
288
+ r"""The partner's country (required for tax purposes)."""
289
+
290
+ paypal_email: Annotated[Nullable[str], pydantic.Field(alias="paypalEmail")]
291
+ r"""The partner's PayPal email (for receiving payouts via PayPal)."""
292
+
293
+ stripe_connect_id: Annotated[Nullable[str], pydantic.Field(alias="stripeConnectId")]
294
+ r"""The partner's Stripe Connect ID (for receiving payouts via Stripe)."""
295
+
296
+ payouts_enabled_at: Annotated[
297
+ Nullable[str], pydantic.Field(alias="payoutsEnabledAt")
298
+ ]
299
+ r"""The date when the partner enabled payouts."""
300
+
301
+ partner_id: Annotated[str, pydantic.Field(alias="partnerId")]
302
+ r"""The partner's unique ID on Dub."""
303
+
304
+ tenant_id: Annotated[Nullable[str], pydantic.Field(alias="tenantId")]
305
+ r"""The partner's unique ID within your database. Can be useful for associating the partner with a user in your database and retrieving/update their data in the future."""
306
+
307
+ program_id: Annotated[str, pydantic.Field(alias="programId")]
308
+ r"""The program's unique ID on Dub."""
309
+
310
+ created_at: Annotated[str, pydantic.Field(alias="createdAt")]
311
+
312
+ status: ListPartnersStatus
313
+ r"""The status of the partner's enrollment in the program."""
314
+
315
+ links: Nullable[List[ListPartnersLink]]
316
+ r"""The partner's referral links in this program."""
317
+
318
+ description: OptionalNullable[str] = UNSET
319
+ r"""A brief description of the partner and their background."""
320
+
321
+ total_commissions: Annotated[
322
+ Optional[float], pydantic.Field(alias="totalCommissions")
323
+ ] = 0
324
+ r"""The total commissions paid to the partner for their referrals. Defaults to 0 if `includeExpandedFields` is false."""
325
+
326
+ click_reward_id: Annotated[
327
+ OptionalNullable[str], pydantic.Field(alias="clickRewardId")
328
+ ] = UNSET
329
+
330
+ lead_reward_id: Annotated[
331
+ OptionalNullable[str], pydantic.Field(alias="leadRewardId")
332
+ ] = UNSET
333
+
334
+ sale_reward_id: Annotated[
335
+ OptionalNullable[str], pydantic.Field(alias="saleRewardId")
336
+ ] = UNSET
337
+
338
+ discount_id: Annotated[
339
+ OptionalNullable[str], pydantic.Field(alias="discountId")
340
+ ] = UNSET
341
+
342
+ application_id: Annotated[
343
+ OptionalNullable[str], pydantic.Field(alias="applicationId")
344
+ ] = UNSET
345
+ r"""If the partner submitted an application to join the program, this is the ID of the application."""
346
+
347
+ banned_at: Annotated[OptionalNullable[str], pydantic.Field(alias="bannedAt")] = (
348
+ UNSET
349
+ )
350
+ r"""If the partner was banned from the program, this is the date of the ban."""
351
+
352
+ banned_reason: Annotated[
353
+ OptionalNullable[ListPartnersBannedReason], pydantic.Field(alias="bannedReason")
354
+ ] = UNSET
355
+ r"""If the partner was banned from the program, this is the reason for the ban."""
356
+
357
+ clicks: Optional[float] = 0
358
+ r"""The total number of clicks on the partner's links. Defaults to 0 if `includeExpandedFields` is false."""
359
+
360
+ leads: Optional[float] = 0
361
+ r"""The total number of leads generated by the partner's links. Defaults to 0 if `includeExpandedFields` is false."""
362
+
363
+ sales: Optional[float] = 0
364
+ r"""The total number of sales generated by the partner's links. Defaults to 0 if `includeExpandedFields` is false."""
365
+
366
+ sale_amount: Annotated[Optional[float], pydantic.Field(alias="saleAmount")] = 0
367
+ r"""The total amount of sales (in cents) generated by the partner's links. Defaults to 0 if `includeExpandedFields` is false."""
368
+
369
+ net_revenue: Annotated[Optional[float], pydantic.Field(alias="netRevenue")] = 0
370
+ r"""The total net revenue generated by the partner. Defaults to 0 if `includeExpandedFields` is false."""
371
+
372
+ website: OptionalNullable[str] = UNSET
373
+ r"""The partner's website URL (including the https protocol)."""
374
+
375
+ website_txt_record: Annotated[
376
+ OptionalNullable[str], pydantic.Field(alias="websiteTxtRecord")
377
+ ] = UNSET
378
+
379
+ website_verified_at: Annotated[
380
+ OptionalNullable[str], pydantic.Field(alias="websiteVerifiedAt")
381
+ ] = UNSET
382
+
383
+ youtube: OptionalNullable[str] = UNSET
384
+ r"""The partner's YouTube channel username (e.g. `johndoe`)."""
385
+
386
+ youtube_verified_at: Annotated[
387
+ OptionalNullable[str], pydantic.Field(alias="youtubeVerifiedAt")
388
+ ] = UNSET
389
+
390
+ youtube_subscriber_count: Annotated[
391
+ OptionalNullable[float], pydantic.Field(alias="youtubeSubscriberCount")
392
+ ] = UNSET
393
+
394
+ youtube_view_count: Annotated[
395
+ OptionalNullable[float], pydantic.Field(alias="youtubeViewCount")
396
+ ] = UNSET
397
+
398
+ twitter: OptionalNullable[str] = UNSET
399
+ r"""The partner's Twitter username (e.g. `johndoe`)."""
400
+
401
+ twitter_verified_at: Annotated[
402
+ OptionalNullable[str], pydantic.Field(alias="twitterVerifiedAt")
403
+ ] = UNSET
404
+
405
+ linkedin: OptionalNullable[str] = UNSET
406
+ r"""The partner's LinkedIn username (e.g. `johndoe`)."""
407
+
408
+ linkedin_verified_at: Annotated[
409
+ OptionalNullable[str], pydantic.Field(alias="linkedinVerifiedAt")
410
+ ] = UNSET
411
+
412
+ instagram: OptionalNullable[str] = UNSET
413
+ r"""The partner's Instagram username (e.g. `johndoe`)."""
414
+
415
+ instagram_verified_at: Annotated[
416
+ OptionalNullable[str], pydantic.Field(alias="instagramVerifiedAt")
417
+ ] = UNSET
418
+
419
+ tiktok: OptionalNullable[str] = UNSET
420
+ r"""The partner's TikTok username (e.g. `johndoe`)."""
421
+
422
+ tiktok_verified_at: Annotated[
423
+ OptionalNullable[str], pydantic.Field(alias="tiktokVerifiedAt")
424
+ ] = UNSET
425
+
426
+ @model_serializer(mode="wrap")
427
+ def serialize_model(self, handler):
428
+ optional_fields = [
429
+ "description",
430
+ "totalCommissions",
431
+ "clickRewardId",
432
+ "leadRewardId",
433
+ "saleRewardId",
434
+ "discountId",
435
+ "applicationId",
436
+ "bannedAt",
437
+ "bannedReason",
438
+ "clicks",
439
+ "leads",
440
+ "sales",
441
+ "saleAmount",
442
+ "netRevenue",
443
+ "website",
444
+ "websiteTxtRecord",
445
+ "websiteVerifiedAt",
446
+ "youtube",
447
+ "youtubeVerifiedAt",
448
+ "youtubeSubscriberCount",
449
+ "youtubeViewCount",
450
+ "twitter",
451
+ "twitterVerifiedAt",
452
+ "linkedin",
453
+ "linkedinVerifiedAt",
454
+ "instagram",
455
+ "instagramVerifiedAt",
456
+ "tiktok",
457
+ "tiktokVerifiedAt",
458
+ ]
459
+ nullable_fields = [
460
+ "email",
461
+ "image",
462
+ "description",
463
+ "country",
464
+ "paypalEmail",
465
+ "stripeConnectId",
466
+ "payoutsEnabledAt",
467
+ "tenantId",
468
+ "links",
469
+ "clickRewardId",
470
+ "leadRewardId",
471
+ "saleRewardId",
472
+ "discountId",
473
+ "applicationId",
474
+ "bannedAt",
475
+ "bannedReason",
476
+ "website",
477
+ "websiteTxtRecord",
478
+ "websiteVerifiedAt",
479
+ "youtube",
480
+ "youtubeVerifiedAt",
481
+ "youtubeSubscriberCount",
482
+ "youtubeViewCount",
483
+ "twitter",
484
+ "twitterVerifiedAt",
485
+ "linkedin",
486
+ "linkedinVerifiedAt",
487
+ "instagram",
488
+ "instagramVerifiedAt",
489
+ "tiktok",
490
+ "tiktokVerifiedAt",
491
+ ]
492
+ null_default_fields = []
493
+
494
+ serialized = handler(self)
495
+
496
+ m = {}
497
+
498
+ for n, f in type(self).model_fields.items():
499
+ k = f.alias or n
500
+ val = serialized.get(k)
501
+ serialized.pop(k, None)
502
+
503
+ optional_nullable = k in optional_fields and k in nullable_fields
504
+ is_set = (
505
+ self.__pydantic_fields_set__.intersection({n})
506
+ or k in null_default_fields
507
+ ) # pylint: disable=no-member
508
+
509
+ if val is not None and val != UNSET_SENTINEL:
510
+ m[k] = val
511
+ elif val != UNSET_SENTINEL and (
512
+ not k in optional_fields or (optional_nullable and is_set)
513
+ ):
514
+ m[k] = val
515
+
516
+ return m
@@ -82,6 +82,8 @@ class Trigger(str, Enum):
82
82
 
83
83
  QR = "qr"
84
84
  LINK = "link"
85
+ PAGEVIEW = "pageview"
86
+ DEEPLINK = "deeplink"
85
87
 
86
88
 
87
89
  RetrieveAnalyticsQueryParamTagIdsTypedDict = TypeAliasType(
@@ -96,6 +98,13 @@ RetrieveAnalyticsQueryParamTagIds = TypeAliasType(
96
98
  r"""The tag IDs to retrieve analytics for."""
97
99
 
98
100
 
101
+ class SaleType(str, Enum):
102
+ r"""Filter sales by type: 'new' for first-time purchases, 'recurring' for repeat purchases. If undefined, returns both."""
103
+
104
+ NEW = "new"
105
+ RECURRING = "recurring"
106
+
107
+
99
108
  class RetrieveAnalyticsRequestTypedDict(TypedDict):
100
109
  event: NotRequired[Event]
101
110
  r"""The type of event to retrieve analytics for. Defaults to `clicks`."""
@@ -157,6 +166,8 @@ class RetrieveAnalyticsRequestTypedDict(TypedDict):
157
166
  r"""Deprecated. Use the `trigger` field instead. Filter for QR code scans. If true, filter for QR codes only. If false, filter for links only. If undefined, return both."""
158
167
  root: NotRequired[bool]
159
168
  r"""Filter for root domains. If true, filter for domains only. If false, filter for links only. If undefined, return both."""
169
+ sale_type: NotRequired[SaleType]
170
+ r"""Filter sales by type: 'new' for first-time purchases, 'recurring' for repeat purchases. If undefined, returns both."""
160
171
  utm_source: NotRequired[Nullable[str]]
161
172
  r"""The UTM source of the short link."""
162
173
  utm_medium: NotRequired[Nullable[str]]
@@ -361,6 +372,13 @@ class RetrieveAnalyticsRequest(BaseModel):
361
372
  ] = None
362
373
  r"""Filter for root domains. If true, filter for domains only. If false, filter for links only. If undefined, return both."""
363
374
 
375
+ sale_type: Annotated[
376
+ Optional[SaleType],
377
+ pydantic.Field(alias="saleType"),
378
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
379
+ ] = None
380
+ r"""Filter sales by type: 'new' for first-time purchases, 'recurring' for repeat purchases. If undefined, returns both."""
381
+
364
382
  utm_source: Annotated[
365
383
  OptionalNullable[str],
366
384
  FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
@@ -424,6 +442,7 @@ class RetrieveAnalyticsRequest(BaseModel):
424
442
  "folderId",
425
443
  "qr",
426
444
  "root",
445
+ "saleType",
427
446
  "utm_source",
428
447
  "utm_medium",
429
448
  "utm_campaign",
@@ -16,6 +16,7 @@ class PaymentProcessor(str, Enum):
16
16
  SHOPIFY = "shopify"
17
17
  POLAR = "polar"
18
18
  PADDLE = "paddle"
19
+ REVENUECAT = "revenuecat"
19
20
  CUSTOM = "custom"
20
21
 
21
22