dub 0.32.0__py3-none-any.whl → 0.34.0__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 (70) hide show
  1. dub/_version.py +3 -3
  2. dub/analytics.py +6 -4
  3. dub/basesdk.py +6 -0
  4. dub/commissions.py +12 -8
  5. dub/customers.py +24 -313
  6. dub/domains.py +34 -26
  7. dub/embed_tokens.py +6 -4
  8. dub/events.py +6 -4
  9. dub/folders.py +24 -20
  10. dub/links.py +58 -54
  11. dub/models/components/__init__.py +81 -149
  12. dub/models/components/analyticstopurls.py +2 -2
  13. dub/models/components/leadcreatedevent.py +15 -14
  14. dub/models/components/linkclickedevent.py +19 -18
  15. dub/models/components/linkerrorschema.py +12 -12
  16. dub/models/components/linkschema.py +9 -3
  17. dub/models/components/linktagschema.py +3 -3
  18. dub/models/components/linktagschemaoutput.py +38 -0
  19. dub/models/components/linkwebhookevent.py +15 -16
  20. dub/models/components/partnerapplicationsubmittedevent.py +269 -0
  21. dub/models/components/partnerenrolledevent.py +68 -8
  22. dub/models/components/salecreatedevent.py +15 -14
  23. dub/models/components/webhookevent.py +6 -0
  24. dub/models/components/workspaceschema.py +6 -0
  25. dub/models/operations/__init__.py +147 -57
  26. dub/models/operations/banpartner.py +83 -0
  27. dub/models/operations/createpartner.py +68 -59
  28. dub/models/operations/createpartnerlink.py +0 -51
  29. dub/models/operations/createreferralsembedtoken.py +0 -51
  30. dub/models/operations/getcustomers.py +18 -0
  31. dub/models/operations/getlinkinfo.py +0 -2
  32. dub/models/operations/getlinks.py +2 -2
  33. dub/models/operations/getlinkscount.py +2 -2
  34. dub/models/operations/getqrcode.py +1 -1
  35. dub/models/operations/listcommissions.py +13 -2
  36. dub/models/operations/listdomains.py +1 -1
  37. dub/models/operations/listevents.py +2026 -21
  38. dub/models/operations/listpartners.py +75 -8
  39. dub/models/operations/retrieveanalytics.py +28 -5
  40. dub/models/operations/retrievelinks.py +44 -9
  41. dub/models/operations/retrievepartneranalytics.py +51 -11
  42. dub/models/operations/tracklead.py +4 -4
  43. dub/models/operations/updatecommission.py +7 -2
  44. dub/models/operations/updatecustomer.py +23 -11
  45. dub/models/operations/updatelink.py +0 -2
  46. dub/models/operations/updateworkspace.py +3 -3
  47. dub/models/operations/upsertpartnerlink.py +0 -51
  48. dub/partners.py +316 -24
  49. dub/qr_codes.py +4 -2
  50. dub/tags.py +24 -20
  51. dub/track.py +12 -16
  52. dub/types/basemodel.py +41 -3
  53. dub/utils/__init__.py +0 -3
  54. dub/utils/enums.py +60 -0
  55. dub/utils/forms.py +21 -10
  56. dub/utils/queryparams.py +14 -2
  57. dub/utils/requestbodies.py +3 -3
  58. dub/utils/retries.py +69 -5
  59. dub/utils/serializers.py +0 -20
  60. dub/utils/unmarshal_json_response.py +15 -1
  61. dub/workspaces.py +12 -16
  62. {dub-0.32.0.dist-info → dub-0.34.0.dist-info}/METADATA +15 -33
  63. {dub-0.32.0.dist-info → dub-0.34.0.dist-info}/RECORD +65 -67
  64. dub/models/components/clickevent.py +0 -556
  65. dub/models/components/continentcode.py +0 -16
  66. dub/models/components/leadevent.py +0 -680
  67. dub/models/components/saleevent.py +0 -779
  68. dub/models/operations/createcustomer.py +0 -382
  69. {dub-0.32.0.dist-info → dub-0.34.0.dist-info}/WHEEL +0 -0
  70. {dub-0.32.0.dist-info → dub-0.34.0.dist-info}/licenses/LICENSE +0 -0
@@ -32,6 +32,13 @@ class ListPartnersQueryParamSortBy(str, Enum):
32
32
  TOTAL_CONVERSIONS = "totalConversions"
33
33
  TOTAL_SALE_AMOUNT = "totalSaleAmount"
34
34
  TOTAL_COMMISSIONS = "totalCommissions"
35
+ NET_REVENUE = "netRevenue"
36
+ EARNINGS_PER_CLICK = "earningsPerClick"
37
+ AVERAGE_LIFETIME_VALUE = "averageLifetimeValue"
38
+ CLICK_TO_LEAD_RATE = "clickToLeadRate"
39
+ CLICK_TO_CONVERSION_RATE = "clickToConversionRate"
40
+ LEAD_TO_CONVERSION_RATE = "leadToConversionRate"
41
+ RETURN_ON_AD_SPEND = "returnOnAdSpend"
35
42
 
36
43
 
37
44
  class ListPartnersQueryParamSortOrder(str, Enum):
@@ -135,7 +142,7 @@ class ListPartnersStatus(str, Enum):
135
142
  ARCHIVED = "archived"
136
143
 
137
144
 
138
- class ListPartnersLinkTypedDict(TypedDict):
145
+ class ListPartnersLinksTypedDict(TypedDict):
139
146
  id: str
140
147
  r"""The unique ID of the short link."""
141
148
  domain: str
@@ -158,7 +165,7 @@ class ListPartnersLinkTypedDict(TypedDict):
158
165
  r"""The total dollar value of sales (in cents) generated by the short link."""
159
166
 
160
167
 
161
- class ListPartnersLink(BaseModel):
168
+ class ListPartnersLinks(BaseModel):
162
169
  id: str
163
170
  r"""The unique ID of the short link."""
164
171
 
@@ -220,6 +227,8 @@ class ListPartnersResponseBodyTypedDict(TypedDict):
220
227
  r"""The partner's Stripe Connect ID (for receiving payouts via Stripe)."""
221
228
  payouts_enabled_at: Nullable[str]
222
229
  r"""The date when the partner enabled payouts."""
230
+ trusted_at: Nullable[str]
231
+ r"""The date when the partner received the trusted badge in the partner network."""
223
232
  program_id: str
224
233
  r"""The program's unique ID on Dub."""
225
234
  partner_id: str
@@ -229,7 +238,7 @@ class ListPartnersResponseBodyTypedDict(TypedDict):
229
238
  created_at: str
230
239
  status: ListPartnersStatus
231
240
  r"""The status of the partner's enrollment in the program."""
232
- links: Nullable[List[ListPartnersLinkTypedDict]]
241
+ links: Nullable[List[ListPartnersLinksTypedDict]]
233
242
  r"""The partner's referral links in this program."""
234
243
  description: NotRequired[Nullable[str]]
235
244
  r"""A brief description of the partner and their background."""
@@ -256,9 +265,21 @@ class ListPartnersResponseBodyTypedDict(TypedDict):
256
265
  total_sales: NotRequired[float]
257
266
  r"""The total number of sales generated by the partner's links (includes recurring sales)"""
258
267
  total_sale_amount: NotRequired[float]
259
- r"""The total amount of sales (in cents) generated by the partner's links"""
268
+ r"""Total revenue generated by the partner's links"""
260
269
  net_revenue: NotRequired[float]
261
- r"""The total net revenue generated by the partner"""
270
+ r"""Net revenue after commissions (`Total Revenue - Total Commissions`)"""
271
+ earnings_per_click: NotRequired[Nullable[float]]
272
+ r"""Earnings Per Click (EPC) (`Total Revenue ÷ Total Clicks`)"""
273
+ average_lifetime_value: NotRequired[Nullable[float]]
274
+ r"""Average lifetime value for each paying customer (`Total Revenue ÷ Total Conversions`)"""
275
+ click_to_lead_rate: NotRequired[Nullable[float]]
276
+ r"""Percentage of clicks that become leads (`Total Leads ÷ Total Clicks`)"""
277
+ click_to_conversion_rate: NotRequired[Nullable[float]]
278
+ r"""Percentage of clicks that convert to paying customers (`Total Conversions ÷ Total Clicks`)"""
279
+ lead_to_conversion_rate: NotRequired[Nullable[float]]
280
+ r"""Percentage of leads that convert to paying customers (`Total Conversions ÷ Total Leads`)"""
281
+ return_on_ad_spend: NotRequired[Nullable[float]]
282
+ r"""Return On Ad Spend (ROAS) (`Total Revenue ÷ Total Commissions`)"""
262
283
  website: NotRequired[Nullable[str]]
263
284
  r"""The partner's website URL (including the https protocol)."""
264
285
  youtube: NotRequired[Nullable[str]]
@@ -303,6 +324,9 @@ class ListPartnersResponseBody(BaseModel):
303
324
  ]
304
325
  r"""The date when the partner enabled payouts."""
305
326
 
327
+ trusted_at: Annotated[Nullable[str], pydantic.Field(alias="trustedAt")]
328
+ r"""The date when the partner received the trusted badge in the partner network."""
329
+
306
330
  program_id: Annotated[str, pydantic.Field(alias="programId")]
307
331
  r"""The program's unique ID on Dub."""
308
332
 
@@ -317,7 +341,7 @@ class ListPartnersResponseBody(BaseModel):
317
341
  status: ListPartnersStatus
318
342
  r"""The status of the partner's enrollment in the program."""
319
343
 
320
- links: Nullable[List[ListPartnersLink]]
344
+ links: Nullable[List[ListPartnersLinks]]
321
345
  r"""The partner's referral links in this program."""
322
346
 
323
347
  description: OptionalNullable[str] = UNSET
@@ -379,10 +403,40 @@ class ListPartnersResponseBody(BaseModel):
379
403
  total_sale_amount: Annotated[
380
404
  Optional[float], pydantic.Field(alias="totalSaleAmount")
381
405
  ] = 0
382
- r"""The total amount of sales (in cents) generated by the partner's links"""
406
+ r"""Total revenue generated by the partner's links"""
383
407
 
384
408
  net_revenue: Annotated[Optional[float], pydantic.Field(alias="netRevenue")] = 0
385
- r"""The total net revenue generated by the partner"""
409
+ r"""Net revenue after commissions (`Total Revenue - Total Commissions`)"""
410
+
411
+ earnings_per_click: Annotated[
412
+ OptionalNullable[float], pydantic.Field(alias="earningsPerClick")
413
+ ] = UNSET
414
+ r"""Earnings Per Click (EPC) (`Total Revenue ÷ Total Clicks`)"""
415
+
416
+ average_lifetime_value: Annotated[
417
+ OptionalNullable[float], pydantic.Field(alias="averageLifetimeValue")
418
+ ] = UNSET
419
+ r"""Average lifetime value for each paying customer (`Total Revenue ÷ Total Conversions`)"""
420
+
421
+ click_to_lead_rate: Annotated[
422
+ OptionalNullable[float], pydantic.Field(alias="clickToLeadRate")
423
+ ] = UNSET
424
+ r"""Percentage of clicks that become leads (`Total Leads ÷ Total Clicks`)"""
425
+
426
+ click_to_conversion_rate: Annotated[
427
+ OptionalNullable[float], pydantic.Field(alias="clickToConversionRate")
428
+ ] = UNSET
429
+ r"""Percentage of clicks that convert to paying customers (`Total Conversions ÷ Total Clicks`)"""
430
+
431
+ lead_to_conversion_rate: Annotated[
432
+ OptionalNullable[float], pydantic.Field(alias="leadToConversionRate")
433
+ ] = UNSET
434
+ r"""Percentage of leads that convert to paying customers (`Total Conversions ÷ Total Leads`)"""
435
+
436
+ return_on_ad_spend: Annotated[
437
+ OptionalNullable[float], pydantic.Field(alias="returnOnAdSpend")
438
+ ] = UNSET
439
+ r"""Return On Ad Spend (ROAS) (`Total Revenue ÷ Total Commissions`)"""
386
440
 
387
441
  website: OptionalNullable[str] = UNSET
388
442
  r"""The partner's website URL (including the https protocol)."""
@@ -421,6 +475,12 @@ class ListPartnersResponseBody(BaseModel):
421
475
  "totalSales",
422
476
  "totalSaleAmount",
423
477
  "netRevenue",
478
+ "earningsPerClick",
479
+ "averageLifetimeValue",
480
+ "clickToLeadRate",
481
+ "clickToConversionRate",
482
+ "leadToConversionRate",
483
+ "returnOnAdSpend",
424
484
  "website",
425
485
  "youtube",
426
486
  "twitter",
@@ -437,6 +497,7 @@ class ListPartnersResponseBody(BaseModel):
437
497
  "paypalEmail",
438
498
  "stripeConnectId",
439
499
  "payoutsEnabledAt",
500
+ "trustedAt",
440
501
  "groupId",
441
502
  "tenantId",
442
503
  "links",
@@ -447,6 +508,12 @@ class ListPartnersResponseBody(BaseModel):
447
508
  "applicationId",
448
509
  "bannedAt",
449
510
  "bannedReason",
511
+ "earningsPerClick",
512
+ "averageLifetimeValue",
513
+ "clickToLeadRate",
514
+ "clickToConversionRate",
515
+ "leadToConversionRate",
516
+ "returnOnAdSpend",
450
517
  "website",
451
518
  "youtube",
452
519
  "twitter",
@@ -16,7 +16,6 @@ from dub.models.components import (
16
16
  analyticstoplinks as components_analyticstoplinks,
17
17
  analyticstopurls as components_analyticstopurls,
18
18
  analyticstriggers as components_analyticstriggers,
19
- continentcode as components_continentcode,
20
19
  )
21
20
  from dub.types import BaseModel, Nullable, OptionalNullable, UNSET, UNSET_SENTINEL
22
21
  from dub.utils import FieldMetadata, QueryParamMetadata
@@ -57,7 +56,9 @@ class QueryParamGroupBy(str, Enum):
57
56
  TOP_DOMAINS = "top_domains"
58
57
  TOP_LINKS = "top_links"
59
58
  TOP_URLS = "top_urls"
59
+ TOP_BASE_URLS = "top_base_urls"
60
60
  TOP_PARTNERS = "top_partners"
61
+ TOP_GROUPS = "top_groups"
61
62
  UTM_SOURCES = "utm_sources"
62
63
  UTM_MEDIUMS = "utm_mediums"
63
64
  UTM_CAMPAIGNS = "utm_campaigns"
@@ -79,6 +80,18 @@ class Interval(str, Enum):
79
80
  ALL = "all"
80
81
 
81
82
 
83
+ class Continent(str, Enum):
84
+ r"""The continent to retrieve analytics for."""
85
+
86
+ AF = "AF"
87
+ AN = "AN"
88
+ AS = "AS"
89
+ EU = "EU"
90
+ NA = "NA"
91
+ OC = "OC"
92
+ SA = "SA"
93
+
94
+
82
95
  class Trigger(str, Enum):
83
96
  r"""The trigger to retrieve analytics for. If undefined, returns all trigger types."""
84
97
 
@@ -142,7 +155,7 @@ class RetrieveAnalyticsRequestTypedDict(TypedDict):
142
155
  r"""The city to retrieve analytics for."""
143
156
  region: NotRequired[str]
144
157
  r"""The ISO 3166-2 region code to retrieve analytics for."""
145
- continent: NotRequired[components_continentcode.ContinentCode]
158
+ continent: NotRequired[Continent]
146
159
  r"""The continent to retrieve analytics for."""
147
160
  device: NotRequired[str]
148
161
  r"""The device to retrieve analytics for."""
@@ -153,7 +166,7 @@ class RetrieveAnalyticsRequestTypedDict(TypedDict):
153
166
  trigger: NotRequired[Trigger]
154
167
  r"""The trigger to retrieve analytics for. If undefined, returns all trigger types."""
155
168
  referer: NotRequired[str]
156
- r"""The referer to retrieve analytics for."""
169
+ r"""The referer hostname to retrieve analytics for."""
157
170
  referer_url: NotRequired[str]
158
171
  r"""The full referer URL to retrieve analytics for."""
159
172
  url: NotRequired[str]
@@ -162,6 +175,8 @@ class RetrieveAnalyticsRequestTypedDict(TypedDict):
162
175
  r"""The tag IDs to retrieve analytics for."""
163
176
  folder_id: NotRequired[str]
164
177
  r"""The folder ID to retrieve analytics for. If not provided, return analytics for unsorted links."""
178
+ group_id: NotRequired[str]
179
+ r"""The group ID to retrieve analytics for."""
165
180
  root: NotRequired[bool]
166
181
  r"""Filter for root domains. If true, filter for domains only. If false, filter for links only. If undefined, return both."""
167
182
  sale_type: NotRequired[SaleType]
@@ -297,7 +312,7 @@ class RetrieveAnalyticsRequest(BaseModel):
297
312
  r"""The ISO 3166-2 region code to retrieve analytics for."""
298
313
 
299
314
  continent: Annotated[
300
- Optional[components_continentcode.ContinentCode],
315
+ Optional[Continent],
301
316
  FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
302
317
  ] = None
303
318
  r"""The continent to retrieve analytics for."""
@@ -330,7 +345,7 @@ class RetrieveAnalyticsRequest(BaseModel):
330
345
  Optional[str],
331
346
  FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
332
347
  ] = None
333
- r"""The referer to retrieve analytics for."""
348
+ r"""The referer hostname to retrieve analytics for."""
334
349
 
335
350
  referer_url: Annotated[
336
351
  Optional[str],
@@ -359,6 +374,13 @@ class RetrieveAnalyticsRequest(BaseModel):
359
374
  ] = None
360
375
  r"""The folder ID to retrieve analytics for. If not provided, return analytics for unsorted links."""
361
376
 
377
+ group_id: Annotated[
378
+ Optional[str],
379
+ pydantic.Field(alias="groupId"),
380
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
381
+ ] = None
382
+ r"""The group ID to retrieve analytics for."""
383
+
362
384
  root: Annotated[
363
385
  Optional[bool],
364
386
  FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
@@ -457,6 +479,7 @@ class RetrieveAnalyticsRequest(BaseModel):
457
479
  "url",
458
480
  "tagIds",
459
481
  "folderId",
482
+ "groupId",
460
483
  "root",
461
484
  "saleType",
462
485
  "query",
@@ -1,33 +1,68 @@
1
1
  """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
2
2
 
3
3
  from __future__ import annotations
4
- from dub.types import BaseModel
4
+ from dub.types import BaseModel, Nullable, OptionalNullable, UNSET, UNSET_SENTINEL
5
5
  from dub.utils import FieldMetadata, QueryParamMetadata
6
6
  import pydantic
7
+ from pydantic import model_serializer
7
8
  from typing import Optional
8
9
  from typing_extensions import Annotated, NotRequired, TypedDict
9
10
 
10
11
 
11
12
  class RetrieveLinksRequestTypedDict(TypedDict):
12
- partner_id: NotRequired[str]
13
- tenant_id: NotRequired[str]
13
+ partner_id: NotRequired[Nullable[str]]
14
+ r"""The ID of the partner to create a link for. Will take precedence over `tenantId` if provided."""
15
+ tenant_id: NotRequired[Nullable[str]]
16
+ r"""The ID of the partner in your system. If both `partnerId` and `tenantId` are not provided, an error will be thrown."""
14
17
 
15
18
 
16
19
  class RetrieveLinksRequest(BaseModel):
17
20
  partner_id: Annotated[
18
- Optional[str],
21
+ OptionalNullable[str],
19
22
  pydantic.Field(alias="partnerId"),
20
23
  FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
21
- ] = None
24
+ ] = UNSET
25
+ r"""The ID of the partner to create a link for. Will take precedence over `tenantId` if provided."""
22
26
 
23
27
  tenant_id: Annotated[
24
- Optional[str],
28
+ OptionalNullable[str],
25
29
  pydantic.Field(alias="tenantId"),
26
30
  FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
27
- ] = None
31
+ ] = UNSET
32
+ r"""The ID of the partner in your system. If both `partnerId` and `tenantId` are not provided, an error will be thrown."""
28
33
 
34
+ @model_serializer(mode="wrap")
35
+ def serialize_model(self, handler):
36
+ optional_fields = ["partnerId", "tenantId"]
37
+ nullable_fields = ["partnerId", "tenantId"]
38
+ null_default_fields = []
29
39
 
30
- class LinkTypedDict(TypedDict):
40
+ serialized = handler(self)
41
+
42
+ m = {}
43
+
44
+ for n, f in type(self).model_fields.items():
45
+ k = f.alias or n
46
+ val = serialized.get(k)
47
+ serialized.pop(k, None)
48
+
49
+ optional_nullable = k in optional_fields and k in nullable_fields
50
+ is_set = (
51
+ self.__pydantic_fields_set__.intersection({n})
52
+ or k in null_default_fields
53
+ ) # pylint: disable=no-member
54
+
55
+ if val is not None and val != UNSET_SENTINEL:
56
+ m[k] = val
57
+ elif val != UNSET_SENTINEL and (
58
+ not k in optional_fields or (optional_nullable and is_set)
59
+ ):
60
+ m[k] = val
61
+
62
+ return m
63
+
64
+
65
+ class RetrieveLinksResponseBodyTypedDict(TypedDict):
31
66
  id: str
32
67
  r"""The unique ID of the short link."""
33
68
  domain: str
@@ -50,7 +85,7 @@ class LinkTypedDict(TypedDict):
50
85
  r"""The total dollar value of sales (in cents) generated by the short link."""
51
86
 
52
87
 
53
- class Link(BaseModel):
88
+ class RetrieveLinksResponseBody(BaseModel):
54
89
  id: str
55
90
  r"""The unique ID of the short link."""
56
91
 
@@ -6,10 +6,11 @@ from dub.models.components import (
6
6
  partneranalyticstimeseries as components_partneranalyticstimeseries,
7
7
  partneranalyticstoplinks as components_partneranalyticstoplinks,
8
8
  )
9
- from dub.types import BaseModel
9
+ from dub.types import BaseModel, Nullable, OptionalNullable, UNSET, UNSET_SENTINEL
10
10
  from dub.utils import FieldMetadata, QueryParamMetadata
11
11
  from enum import Enum
12
12
  import pydantic
13
+ from pydantic import model_serializer
13
14
  from typing import List, Optional, Union
14
15
  from typing_extensions import Annotated, NotRequired, TypeAliasType, TypedDict
15
16
 
@@ -37,10 +38,10 @@ class RetrievePartnerAnalyticsQueryParamGroupBy(str, Enum):
37
38
 
38
39
 
39
40
  class RetrievePartnerAnalyticsRequestTypedDict(TypedDict):
40
- partner_id: NotRequired[str]
41
- r"""The ID of the partner to retrieve analytics for."""
42
- tenant_id: NotRequired[str]
43
- r"""The ID of the tenant that created the link inside your system."""
41
+ partner_id: NotRequired[Nullable[str]]
42
+ r"""The ID of the partner to create a link for. Will take precedence over `tenantId` if provided."""
43
+ tenant_id: NotRequired[Nullable[str]]
44
+ r"""The ID of the partner in your system. If both `partnerId` and `tenantId` are not provided, an error will be thrown."""
44
45
  interval: NotRequired[RetrievePartnerAnalyticsQueryParamInterval]
45
46
  r"""The interval to retrieve analytics for. If undefined, defaults to 24h."""
46
47
  start: NotRequired[str]
@@ -57,18 +58,18 @@ class RetrievePartnerAnalyticsRequestTypedDict(TypedDict):
57
58
 
58
59
  class RetrievePartnerAnalyticsRequest(BaseModel):
59
60
  partner_id: Annotated[
60
- Optional[str],
61
+ OptionalNullable[str],
61
62
  pydantic.Field(alias="partnerId"),
62
63
  FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
63
- ] = None
64
- r"""The ID of the partner to retrieve analytics for."""
64
+ ] = UNSET
65
+ r"""The ID of the partner to create a link for. Will take precedence over `tenantId` if provided."""
65
66
 
66
67
  tenant_id: Annotated[
67
- Optional[str],
68
+ OptionalNullable[str],
68
69
  pydantic.Field(alias="tenantId"),
69
70
  FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
70
- ] = None
71
- r"""The ID of the tenant that created the link inside your system."""
71
+ ] = UNSET
72
+ r"""The ID of the partner in your system. If both `partnerId` and `tenantId` are not provided, an error will be thrown."""
72
73
 
73
74
  interval: Annotated[
74
75
  Optional[RetrievePartnerAnalyticsQueryParamInterval],
@@ -107,6 +108,45 @@ class RetrievePartnerAnalyticsRequest(BaseModel):
107
108
  ] = RetrievePartnerAnalyticsQueryParamGroupBy.COUNT
108
109
  r"""The parameter to group the analytics data points by. Defaults to `count` if undefined."""
109
110
 
111
+ @model_serializer(mode="wrap")
112
+ def serialize_model(self, handler):
113
+ optional_fields = [
114
+ "partnerId",
115
+ "tenantId",
116
+ "interval",
117
+ "start",
118
+ "end",
119
+ "timezone",
120
+ "query",
121
+ "groupBy",
122
+ ]
123
+ nullable_fields = ["partnerId", "tenantId"]
124
+ null_default_fields = []
125
+
126
+ serialized = handler(self)
127
+
128
+ m = {}
129
+
130
+ for n, f in type(self).model_fields.items():
131
+ k = f.alias or n
132
+ val = serialized.get(k)
133
+ serialized.pop(k, None)
134
+
135
+ optional_nullable = k in optional_fields and k in nullable_fields
136
+ is_set = (
137
+ self.__pydantic_fields_set__.intersection({n})
138
+ or k in null_default_fields
139
+ ) # pylint: disable=no-member
140
+
141
+ if val is not None and val != UNSET_SENTINEL:
142
+ m[k] = val
143
+ elif val != UNSET_SENTINEL and (
144
+ not k in optional_fields or (optional_nullable and is_set)
145
+ ):
146
+ m[k] = val
147
+
148
+ return m
149
+
110
150
 
111
151
  RetrievePartnerAnalyticsResponseBodyTypedDict = TypeAliasType(
112
152
  "RetrievePartnerAnalyticsResponseBodyTypedDict",
@@ -126,7 +126,7 @@ class Click(BaseModel):
126
126
  id: str
127
127
 
128
128
 
129
- class TrackLeadLinkTypedDict(TypedDict):
129
+ class LinkTypedDict(TypedDict):
130
130
  id: str
131
131
  r"""The unique ID of the short link."""
132
132
  domain: str
@@ -147,7 +147,7 @@ class TrackLeadLinkTypedDict(TypedDict):
147
147
  r"""The ID of the link in your database. If set, it can be used to identify the link in future API requests (must be prefixed with 'ext_' when passed as a query parameter). This key is unique across your workspace."""
148
148
 
149
149
 
150
- class TrackLeadLink(BaseModel):
150
+ class Link(BaseModel):
151
151
  id: str
152
152
  r"""The unique ID of the short link."""
153
153
 
@@ -257,7 +257,7 @@ class TrackLeadResponseBodyTypedDict(TypedDict):
257
257
  r"""A lead was tracked."""
258
258
 
259
259
  click: ClickTypedDict
260
- link: Nullable[TrackLeadLinkTypedDict]
260
+ link: Nullable[LinkTypedDict]
261
261
  customer: CustomerTypedDict
262
262
 
263
263
 
@@ -266,7 +266,7 @@ class TrackLeadResponseBody(BaseModel):
266
266
 
267
267
  click: Click
268
268
 
269
- link: Nullable[TrackLeadLink]
269
+ link: Nullable[Link]
270
270
 
271
271
  customer: Customer
272
272
 
@@ -94,6 +94,8 @@ class UpdateCommissionPartnerTypedDict(TypedDict):
94
94
  r"""The date when the partner enabled payouts."""
95
95
  country: Nullable[str]
96
96
  r"""The partner's country (required for tax purposes)."""
97
+ group_id: NotRequired[Nullable[str]]
98
+ r"""The partner's group ID on Dub."""
97
99
 
98
100
 
99
101
  class UpdateCommissionPartner(BaseModel):
@@ -117,10 +119,13 @@ class UpdateCommissionPartner(BaseModel):
117
119
  country: Nullable[str]
118
120
  r"""The partner's country (required for tax purposes)."""
119
121
 
122
+ group_id: Annotated[OptionalNullable[str], pydantic.Field(alias="groupId")] = UNSET
123
+ r"""The partner's group ID on Dub."""
124
+
120
125
  @model_serializer(mode="wrap")
121
126
  def serialize_model(self, handler):
122
- optional_fields = []
123
- nullable_fields = ["email", "image", "payoutsEnabledAt", "country"]
127
+ optional_fields = ["groupId"]
128
+ nullable_fields = ["email", "image", "payoutsEnabledAt", "country", "groupId"]
124
129
  null_default_fields = []
125
130
 
126
131
  serialized = handler(self)
@@ -17,38 +17,50 @@ from typing_extensions import Annotated, NotRequired, TypedDict
17
17
 
18
18
  class UpdateCustomerRequestBodyTypedDict(TypedDict):
19
19
  email: NotRequired[Nullable[str]]
20
- r"""Email of the customer in the client's app."""
20
+ r"""The customer's email address."""
21
21
  name: NotRequired[Nullable[str]]
22
- r"""Name of the customer in the client's app. If not provided, a random name will be generated."""
22
+ r"""The customer's name. If not provided, the email address will be used, and if email is not provided, a random name will be generated."""
23
23
  avatar: NotRequired[Nullable[str]]
24
- r"""Avatar URL of the customer in the client's app."""
24
+ r"""The customer's avatar URL. If not provided, a random avatar will be generated."""
25
25
  external_id: NotRequired[str]
26
- r"""Unique identifier for the customer in the client's app."""
26
+ r"""The customer's unique identifier your database. This is useful for associating subsequent conversion events from Dub's API to your internal systems."""
27
27
  stripe_customer_id: NotRequired[Nullable[str]]
28
- r"""The customer's Stripe customer ID. Useful for attribution recurring sale events to the partner who referred the customer."""
28
+ r"""The customer's Stripe customer ID. This is useful for attributing recurring sale events to the partner who referred the customer."""
29
+ country: NotRequired[str]
30
+ r"""The customer's country in ISO 3166-1 alpha-2 format. Updating this field will only affect the customer's country in Dub's system (and has no effect on existing conversion events)."""
29
31
 
30
32
 
31
33
  class UpdateCustomerRequestBody(BaseModel):
32
34
  email: OptionalNullable[str] = UNSET
33
- r"""Email of the customer in the client's app."""
35
+ r"""The customer's email address."""
34
36
 
35
37
  name: OptionalNullable[str] = UNSET
36
- r"""Name of the customer in the client's app. If not provided, a random name will be generated."""
38
+ r"""The customer's name. If not provided, the email address will be used, and if email is not provided, a random name will be generated."""
37
39
 
38
40
  avatar: OptionalNullable[str] = UNSET
39
- r"""Avatar URL of the customer in the client's app."""
41
+ r"""The customer's avatar URL. If not provided, a random avatar will be generated."""
40
42
 
41
43
  external_id: Annotated[Optional[str], pydantic.Field(alias="externalId")] = None
42
- r"""Unique identifier for the customer in the client's app."""
44
+ r"""The customer's unique identifier your database. This is useful for associating subsequent conversion events from Dub's API to your internal systems."""
43
45
 
44
46
  stripe_customer_id: Annotated[
45
47
  OptionalNullable[str], pydantic.Field(alias="stripeCustomerId")
46
48
  ] = UNSET
47
- r"""The customer's Stripe customer ID. Useful for attribution recurring sale events to the partner who referred the customer."""
49
+ r"""The customer's Stripe customer ID. This is useful for attributing recurring sale events to the partner who referred the customer."""
50
+
51
+ country: Optional[str] = None
52
+ r"""The customer's country in ISO 3166-1 alpha-2 format. Updating this field will only affect the customer's country in Dub's system (and has no effect on existing conversion events)."""
48
53
 
49
54
  @model_serializer(mode="wrap")
50
55
  def serialize_model(self, handler):
51
- optional_fields = ["email", "name", "avatar", "externalId", "stripeCustomerId"]
56
+ optional_fields = [
57
+ "email",
58
+ "name",
59
+ "avatar",
60
+ "externalId",
61
+ "stripeCustomerId",
62
+ "country",
63
+ ]
52
64
  nullable_fields = ["email", "name", "avatar", "stripeCustomerId"]
53
65
  null_default_fields = []
54
66
 
@@ -89,7 +89,6 @@ class UpdateLinkRequestBodyTypedDict(TypedDict):
89
89
  android: NotRequired[Nullable[str]]
90
90
  r"""The Android destination URL for the short link for Android device targeting."""
91
91
  geo: NotRequired[Nullable[Dict[str, str]]]
92
- r"""Geo targeting information for the short link in JSON format `{[COUNTRY]: https://example.com }`. See https://d.to/geo for more information."""
93
92
  do_index: NotRequired[bool]
94
93
  r"""Allow search engines to index your short link. Defaults to `false` if not provided. Learn more: https://d.to/noindex"""
95
94
  utm_source: NotRequired[Nullable[str]]
@@ -211,7 +210,6 @@ class UpdateLinkRequestBody(BaseModel):
211
210
  r"""The Android destination URL for the short link for Android device targeting."""
212
211
 
213
212
  geo: OptionalNullable[Dict[str, str]] = UNSET
214
- r"""Geo targeting information for the short link in JSON format `{[COUNTRY]: https://example.com }`. See https://d.to/geo for more information."""
215
213
 
216
214
  do_index: Annotated[Optional[bool], pydantic.Field(alias="doIndex")] = None
217
215
  r"""Allow search engines to index your short link. Defaults to `false` if not provided. Learn more: https://d.to/noindex"""
@@ -5,14 +5,14 @@ from dub.types import BaseModel, Nullable, OptionalNullable, UNSET, UNSET_SENTIN
5
5
  from dub.utils import FieldMetadata, PathParamMetadata, RequestMetadata
6
6
  import pydantic
7
7
  from pydantic import model_serializer
8
- from typing import Optional
8
+ from typing import Any, Optional
9
9
  from typing_extensions import Annotated, NotRequired, TypedDict
10
10
 
11
11
 
12
12
  class UpdateWorkspaceRequestBodyTypedDict(TypedDict):
13
13
  name: NotRequired[str]
14
14
  slug: NotRequired[str]
15
- logo: NotRequired[Nullable[str]]
15
+ logo: NotRequired[Nullable[Any]]
16
16
  conversion_enabled: NotRequired[bool]
17
17
 
18
18
 
@@ -21,7 +21,7 @@ class UpdateWorkspaceRequestBody(BaseModel):
21
21
 
22
22
  slug: Optional[str] = None
23
23
 
24
- logo: OptionalNullable[str] = UNSET
24
+ logo: OptionalNullable[Any] = UNSET
25
25
 
26
26
  conversion_enabled: Annotated[
27
27
  Optional[bool], pydantic.Field(alias="conversionEnabled")