dub 0.27.1__py3-none-any.whl → 0.27.3__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.
Files changed (38) hide show
  1. dub/_version.py +3 -3
  2. dub/models/components/__init__.py +41 -2
  3. dub/models/components/analyticstriggers.py +2 -0
  4. dub/models/components/clickevent.py +92 -47
  5. dub/models/components/commissioncreatedevent.py +281 -0
  6. dub/models/components/leadcreatedevent.py +66 -21
  7. dub/models/components/leadevent.py +126 -48
  8. dub/models/components/linkclickedevent.py +66 -21
  9. dub/models/components/linkschema.py +26 -20
  10. dub/models/components/linkwebhookevent.py +33 -21
  11. dub/models/components/partnerenrolledevent.py +207 -80
  12. dub/models/components/salecreatedevent.py +66 -21
  13. dub/models/components/saleevent.py +206 -122
  14. dub/models/components/webhookevent.py +6 -0
  15. dub/models/errors/__init__.py +3 -2
  16. dub/models/operations/__init__.py +71 -2
  17. dub/models/operations/bulkcreatelinks.py +25 -25
  18. dub/models/operations/bulkupdatelinks.py +25 -25
  19. dub/models/operations/createlink.py +25 -25
  20. dub/models/operations/createpartner.py +207 -80
  21. dub/models/operations/getlinks.py +2 -2
  22. dub/models/operations/getlinkscount.py +2 -2
  23. dub/models/operations/listcommissions.py +169 -8
  24. dub/models/operations/listevents.py +48 -20
  25. dub/models/operations/listpartners.py +516 -0
  26. dub/models/operations/retrieveanalytics.py +48 -20
  27. dub/models/operations/retrievelinks.py +6 -6
  28. dub/models/operations/tracksale.py +1 -0
  29. dub/models/operations/updatecommission.py +169 -8
  30. dub/models/operations/updatelink.py +25 -25
  31. dub/models/operations/upsertlink.py +25 -25
  32. dub/partners.py +262 -0
  33. dub/sdk.py +1 -1
  34. dub/utils/__init__.py +3 -2
  35. {dub-0.27.1.dist-info → dub-0.27.3.dist-info}/METADATA +3 -2
  36. {dub-0.27.1.dist-info → dub-0.27.3.dist-info}/RECORD +38 -36
  37. {dub-0.27.1.dist-info → dub-0.27.3.dist-info}/LICENSE +0 -0
  38. {dub-0.27.1.dist-info → dub-0.27.3.dist-info}/WHEEL +0 -0
@@ -46,10 +46,12 @@ class QueryParamInterval(str, Enum):
46
46
 
47
47
 
48
48
  class QueryParamTrigger(str, Enum):
49
- r"""The trigger to retrieve analytics for. If undefined, return both QR and link clicks."""
49
+ r"""The trigger to retrieve analytics for. If undefined, returns all trigger types."""
50
50
 
51
51
  QR = "qr"
52
52
  LINK = "link"
53
+ PAGEVIEW = "pageview"
54
+ DEEPLINK = "deeplink"
53
55
 
54
56
 
55
57
  ListEventsQueryParamTagIdsTypedDict = TypeAliasType(
@@ -64,6 +66,13 @@ ListEventsQueryParamTagIds = TypeAliasType(
64
66
  r"""The tag IDs to retrieve analytics for."""
65
67
 
66
68
 
69
+ class QueryParamSaleType(str, Enum):
70
+ r"""Filter sales by type: 'new' for first-time purchases, 'recurring' for repeat purchases. If undefined, returns both."""
71
+
72
+ NEW = "new"
73
+ RECURRING = "recurring"
74
+
75
+
67
76
  class QueryParamSortOrder(str, Enum):
68
77
  r"""The sort order. The default is `desc`."""
69
78
 
@@ -129,23 +138,27 @@ class ListEventsRequestTypedDict(TypedDict):
129
138
  os: NotRequired[str]
130
139
  r"""The OS to retrieve analytics for."""
131
140
  trigger: NotRequired[QueryParamTrigger]
132
- r"""The trigger to retrieve analytics for. If undefined, return both QR and link clicks."""
141
+ r"""The trigger to retrieve analytics for. If undefined, returns all trigger types."""
133
142
  referer: NotRequired[str]
134
143
  r"""The referer to retrieve analytics for."""
135
144
  referer_url: NotRequired[str]
136
145
  r"""The full referer URL to retrieve analytics for."""
137
146
  url: NotRequired[str]
138
147
  r"""The URL to retrieve analytics for."""
139
- tag_id: NotRequired[str]
140
- r"""Deprecated. Use `tagIds` instead. The tag ID to retrieve analytics for."""
141
148
  tag_ids: NotRequired[ListEventsQueryParamTagIdsTypedDict]
142
149
  r"""The tag IDs to retrieve analytics for."""
143
150
  folder_id: NotRequired[str]
144
151
  r"""The folder ID to retrieve analytics for. If not provided, return analytics for unsorted links."""
145
- qr: NotRequired[bool]
146
- 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."""
147
152
  root: NotRequired[bool]
148
153
  r"""Filter for root domains. If true, filter for domains only. If false, filter for links only. If undefined, return both."""
154
+ sale_type: NotRequired[QueryParamSaleType]
155
+ r"""Filter sales by type: 'new' for first-time purchases, 'recurring' for repeat purchases. If undefined, returns both."""
156
+ query: NotRequired[str]
157
+ r"""Search the events by a custom metadata value. Only available for lead and sale events."""
158
+ tag_id: NotRequired[str]
159
+ r"""Deprecated: Use `tagIds` instead. The tag ID to retrieve analytics for."""
160
+ qr: NotRequired[bool]
161
+ 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."""
149
162
  utm_source: NotRequired[Nullable[str]]
150
163
  r"""The UTM source of the short link."""
151
164
  utm_medium: NotRequired[Nullable[str]]
@@ -297,7 +310,7 @@ class ListEventsRequest(BaseModel):
297
310
  Optional[QueryParamTrigger],
298
311
  FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
299
312
  ] = None
300
- r"""The trigger to retrieve analytics for. If undefined, return both QR and link clicks."""
313
+ r"""The trigger to retrieve analytics for. If undefined, returns all trigger types."""
301
314
 
302
315
  referer: Annotated[
303
316
  Optional[str],
@@ -318,13 +331,6 @@ class ListEventsRequest(BaseModel):
318
331
  ] = None
319
332
  r"""The URL to retrieve analytics for."""
320
333
 
321
- tag_id: Annotated[
322
- Optional[str],
323
- pydantic.Field(alias="tagId"),
324
- FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
325
- ] = None
326
- r"""Deprecated. Use `tagIds` instead. The tag ID to retrieve analytics for."""
327
-
328
334
  tag_ids: Annotated[
329
335
  Optional[ListEventsQueryParamTagIds],
330
336
  pydantic.Field(alias="tagIds"),
@@ -339,17 +345,37 @@ class ListEventsRequest(BaseModel):
339
345
  ] = None
340
346
  r"""The folder ID to retrieve analytics for. If not provided, return analytics for unsorted links."""
341
347
 
342
- qr: Annotated[
348
+ root: Annotated[
343
349
  Optional[bool],
344
350
  FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
345
351
  ] = None
346
- 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."""
352
+ r"""Filter for root domains. If true, filter for domains only. If false, filter for links only. If undefined, return both."""
347
353
 
348
- root: Annotated[
354
+ sale_type: Annotated[
355
+ Optional[QueryParamSaleType],
356
+ pydantic.Field(alias="saleType"),
357
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
358
+ ] = None
359
+ r"""Filter sales by type: 'new' for first-time purchases, 'recurring' for repeat purchases. If undefined, returns both."""
360
+
361
+ query: Annotated[
362
+ Optional[str],
363
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
364
+ ] = None
365
+ r"""Search the events by a custom metadata value. Only available for lead and sale events."""
366
+
367
+ tag_id: Annotated[
368
+ Optional[str],
369
+ pydantic.Field(alias="tagId"),
370
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
371
+ ] = None
372
+ r"""Deprecated: Use `tagIds` instead. The tag ID to retrieve analytics for."""
373
+
374
+ qr: Annotated[
349
375
  Optional[bool],
350
376
  FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
351
377
  ] = None
352
- r"""Filter for root domains. If true, filter for domains only. If false, filter for links only. If undefined, return both."""
378
+ 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."""
353
379
 
354
380
  utm_source: Annotated[
355
381
  OptionalNullable[str],
@@ -438,11 +464,13 @@ class ListEventsRequest(BaseModel):
438
464
  "referer",
439
465
  "refererUrl",
440
466
  "url",
441
- "tagId",
442
467
  "tagIds",
443
468
  "folderId",
444
- "qr",
445
469
  "root",
470
+ "saleType",
471
+ "query",
472
+ "tagId",
473
+ "qr",
446
474
  "utm_source",
447
475
  "utm_medium",
448
476
  "utm_campaign",
@@ -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 link has generated."""
153
+ sales: NotRequired[float]
154
+ r"""The total number of sales (includes recurring sales) generated by the short link."""
155
+ sale_amount: NotRequired[float]
156
+ r"""The total dollar value of sales (in cents) generated by the short link."""
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 link has generated."""
180
+
181
+ sales: Optional[float] = 0
182
+ r"""The total number of sales (includes recurring sales) generated by the short link."""
183
+
184
+ sale_amount: Annotated[Optional[float], pydantic.Field(alias="saleAmount")] = 0
185
+ r"""The total dollar value of sales (in cents) generated by the short link."""
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