dub 0.31.0__py3-none-any.whl → 0.33.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 (68) hide show
  1. dub/_version.py +3 -3
  2. dub/analytics.py +6 -6
  3. dub/commissions.py +12 -12
  4. dub/customers.py +24 -321
  5. dub/domains.py +34 -38
  6. dub/embed_tokens.py +6 -6
  7. dub/events.py +6 -6
  8. dub/folders.py +24 -28
  9. dub/links.py +58 -74
  10. dub/models/components/__init__.py +38 -6
  11. dub/models/components/analyticstopurls.py +2 -2
  12. dub/models/components/clickevent.py +10 -9
  13. dub/models/components/commissioncreatedevent.py +5 -2
  14. dub/models/components/folderschema.py +6 -1
  15. dub/models/components/leadcreatedevent.py +15 -11
  16. dub/models/components/leadevent.py +10 -9
  17. dub/models/components/linkclickedevent.py +10 -9
  18. dub/models/components/linkschema.py +9 -3
  19. dub/models/components/{tagschema.py → linktagschema.py} +2 -2
  20. dub/models/components/linkwebhookevent.py +10 -9
  21. dub/models/components/partnerapplicationsubmittedevent.py +269 -0
  22. dub/models/components/partnerenrolledevent.py +93 -29
  23. dub/models/components/salecreatedevent.py +15 -11
  24. dub/models/components/saleevent.py +10 -9
  25. dub/models/components/webhookevent.py +6 -0
  26. dub/models/components/workspaceschema.py +11 -0
  27. dub/models/errors/badrequest.py +1 -1
  28. dub/models/errors/conflict.py +1 -1
  29. dub/models/errors/duberror.py +1 -1
  30. dub/models/errors/forbidden.py +1 -1
  31. dub/models/errors/internalservererror.py +1 -1
  32. dub/models/errors/inviteexpired.py +1 -1
  33. dub/models/errors/no_response_error.py +1 -1
  34. dub/models/errors/notfound.py +1 -1
  35. dub/models/errors/ratelimitexceeded.py +1 -1
  36. dub/models/errors/responsevalidationerror.py +1 -1
  37. dub/models/errors/sdkerror.py +1 -1
  38. dub/models/errors/unauthorized.py +1 -1
  39. dub/models/errors/unprocessableentity.py +1 -1
  40. dub/models/operations/__init__.py +17 -35
  41. dub/models/operations/banpartner.py +83 -0
  42. dub/models/operations/bulkcreatelinks.py +2 -2
  43. dub/models/operations/createfolder.py +8 -3
  44. dub/models/operations/createlink.py +2 -2
  45. dub/models/operations/createpartner.py +93 -29
  46. dub/models/operations/listcommissions.py +13 -2
  47. dub/models/operations/listevents.py +10 -0
  48. dub/models/operations/listpartners.py +107 -47
  49. dub/models/operations/retrieveanalytics.py +16 -1
  50. dub/models/operations/retrievelinks.py +42 -7
  51. dub/models/operations/retrievepartneranalytics.py +51 -11
  52. dub/models/operations/tracklead.py +2 -2
  53. dub/models/operations/updatecommission.py +7 -2
  54. dub/models/operations/updatefolder.py +8 -3
  55. dub/models/operations/updatelink.py +2 -2
  56. dub/models/operations/upsertlink.py +2 -2
  57. dub/partners.py +310 -36
  58. dub/qr_codes.py +4 -4
  59. dub/tags.py +24 -32
  60. dub/track.py +12 -20
  61. dub/utils/retries.py +69 -5
  62. dub/utils/unmarshal_json_response.py +15 -1
  63. dub/workspaces.py +12 -20
  64. {dub-0.31.0.dist-info → dub-0.33.0.dist-info}/METADATA +2 -21
  65. {dub-0.31.0.dist-info → dub-0.33.0.dist-info}/RECORD +67 -66
  66. dub/models/operations/createcustomer.py +0 -382
  67. {dub-0.31.0.dist-info → dub-0.33.0.dist-info}/WHEEL +0 -0
  68. {dub-0.31.0.dist-info → dub-0.33.0.dist-info}/licenses/LICENSE +0 -0
@@ -105,6 +105,8 @@ class WorkspaceSchemaTypedDict(TypedDict):
105
105
  r"""The invite code of the workspace."""
106
106
  plan: Plan
107
107
  r"""The plan of the workspace."""
108
+ plan_tier: Nullable[float]
109
+ r"""The tier of the workspace's plan."""
108
110
  stripe_id: Nullable[str]
109
111
  r"""The Stripe ID of the workspace."""
110
112
  billing_cycle_start: float
@@ -139,6 +141,8 @@ class WorkspaceSchemaTypedDict(TypedDict):
139
141
  r"""The folders limit of the workspace."""
140
142
  groups_limit: float
141
143
  r"""The groups limit of the workspace."""
144
+ network_invites_limit: float
145
+ r"""The weekly network invites limit of the workspace."""
142
146
  users_limit: float
143
147
  r"""The users limit of the workspace."""
144
148
  ai_usage: float
@@ -183,6 +187,9 @@ class WorkspaceSchema(BaseModel):
183
187
  plan: Plan
184
188
  r"""The plan of the workspace."""
185
189
 
190
+ plan_tier: Annotated[Nullable[float], pydantic.Field(alias="planTier")]
191
+ r"""The tier of the workspace's plan."""
192
+
186
193
  stripe_id: Annotated[Nullable[str], pydantic.Field(alias="stripeId")]
187
194
  r"""The Stripe ID of the workspace."""
188
195
 
@@ -234,6 +241,9 @@ class WorkspaceSchema(BaseModel):
234
241
  groups_limit: Annotated[float, pydantic.Field(alias="groupsLimit")]
235
242
  r"""The groups limit of the workspace."""
236
243
 
244
+ network_invites_limit: Annotated[float, pydantic.Field(alias="networkInvitesLimit")]
245
+ r"""The weekly network invites limit of the workspace."""
246
+
237
247
  users_limit: Annotated[float, pydantic.Field(alias="usersLimit")]
238
248
  r"""The users limit of the workspace."""
239
249
 
@@ -282,6 +292,7 @@ class WorkspaceSchema(BaseModel):
282
292
  nullable_fields = [
283
293
  "logo",
284
294
  "inviteCode",
295
+ "planTier",
285
296
  "stripeId",
286
297
  "paymentFailedAt",
287
298
  "stripeConnectId",
@@ -40,7 +40,7 @@ class BadRequestData(BaseModel):
40
40
  error: Error
41
41
 
42
42
 
43
- @dataclass(frozen=True)
43
+ @dataclass(unsafe_hash=True)
44
44
  class BadRequest(DubError):
45
45
  r"""The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing)."""
46
46
 
@@ -40,7 +40,7 @@ class ConflictData(BaseModel):
40
40
  error: ConflictError
41
41
 
42
42
 
43
- @dataclass(frozen=True)
43
+ @dataclass(unsafe_hash=True)
44
44
  class Conflict(DubError):
45
45
  r"""This response is sent when a request conflicts with the current state of the server."""
46
46
 
@@ -5,7 +5,7 @@ from typing import Optional
5
5
  from dataclasses import dataclass, field
6
6
 
7
7
 
8
- @dataclass(frozen=True)
8
+ @dataclass(unsafe_hash=True)
9
9
  class DubError(Exception):
10
10
  """The base class for all HTTP error responses."""
11
11
 
@@ -40,7 +40,7 @@ class ForbiddenData(BaseModel):
40
40
  error: ForbiddenError
41
41
 
42
42
 
43
- @dataclass(frozen=True)
43
+ @dataclass(unsafe_hash=True)
44
44
  class Forbidden(DubError):
45
45
  r"""The client does not have access rights to the content; that is, it is unauthorized, so the server is refusing to give the requested resource. Unlike 401 Unauthorized, the client's identity is known to the server."""
46
46
 
@@ -40,7 +40,7 @@ class InternalServerErrorData(BaseModel):
40
40
  error: InternalServerErrorError
41
41
 
42
42
 
43
- @dataclass(frozen=True)
43
+ @dataclass(unsafe_hash=True)
44
44
  class InternalServerError(DubError):
45
45
  r"""The server has encountered a situation it does not know how to handle."""
46
46
 
@@ -40,7 +40,7 @@ class InviteExpiredData(BaseModel):
40
40
  error: InviteExpiredError
41
41
 
42
42
 
43
- @dataclass(frozen=True)
43
+ @dataclass(unsafe_hash=True)
44
44
  class InviteExpired(DubError):
45
45
  r"""This response is sent when the requested content has been permanently deleted from server, with no forwarding address."""
46
46
 
@@ -3,7 +3,7 @@
3
3
  from dataclasses import dataclass
4
4
 
5
5
 
6
- @dataclass(frozen=True)
6
+ @dataclass(unsafe_hash=True)
7
7
  class NoResponseError(Exception):
8
8
  """Error raised when no HTTP response is received from the server."""
9
9
 
@@ -40,7 +40,7 @@ class NotFoundData(BaseModel):
40
40
  error: NotFoundError
41
41
 
42
42
 
43
- @dataclass(frozen=True)
43
+ @dataclass(unsafe_hash=True)
44
44
  class NotFound(DubError):
45
45
  r"""The server cannot find the requested resource."""
46
46
 
@@ -40,7 +40,7 @@ class RateLimitExceededData(BaseModel):
40
40
  error: RateLimitExceededError
41
41
 
42
42
 
43
- @dataclass(frozen=True)
43
+ @dataclass(unsafe_hash=True)
44
44
  class RateLimitExceeded(DubError):
45
45
  r"""The user has sent too many requests in a given amount of time (\"rate limiting\")"""
46
46
 
@@ -7,7 +7,7 @@ from dataclasses import dataclass
7
7
  from dub.models.errors import DubError
8
8
 
9
9
 
10
- @dataclass(frozen=True)
10
+ @dataclass(unsafe_hash=True)
11
11
  class ResponseValidationError(DubError):
12
12
  """Error raised when there is a type mismatch between the response data and the expected Pydantic model."""
13
13
 
@@ -9,7 +9,7 @@ from dub.models.errors import DubError
9
9
  MAX_MESSAGE_LEN = 10_000
10
10
 
11
11
 
12
- @dataclass(frozen=True)
12
+ @dataclass(unsafe_hash=True)
13
13
  class SDKError(DubError):
14
14
  """The fallback error class if no more specific error class is matched."""
15
15
 
@@ -40,7 +40,7 @@ class UnauthorizedData(BaseModel):
40
40
  error: UnauthorizedError
41
41
 
42
42
 
43
- @dataclass(frozen=True)
43
+ @dataclass(unsafe_hash=True)
44
44
  class Unauthorized(DubError):
45
45
  r"""Although the HTTP standard specifies \"unauthorized\", semantically this response means \"unauthenticated\". That is, the client must authenticate itself to get the requested response."""
46
46
 
@@ -40,7 +40,7 @@ class UnprocessableEntityData(BaseModel):
40
40
  error: UnprocessableEntityError
41
41
 
42
42
 
43
- @dataclass(frozen=True)
43
+ @dataclass(unsafe_hash=True)
44
44
  class UnprocessableEntity(DubError):
45
45
  r"""The request was well-formed but was unable to be followed due to semantic errors."""
46
46
 
@@ -6,6 +6,13 @@ import builtins
6
6
  import sys
7
7
 
8
8
  if TYPE_CHECKING:
9
+ from .banpartner import (
10
+ BanPartnerRequestBody,
11
+ BanPartnerRequestBodyTypedDict,
12
+ BanPartnerResponseBody,
13
+ BanPartnerResponseBodyTypedDict,
14
+ Reason,
15
+ )
9
16
  from .bulkcreatelinks import (
10
17
  BulkCreateLinksTagIds,
11
18
  BulkCreateLinksTagIdsTypedDict,
@@ -44,19 +51,6 @@ if TYPE_CHECKING:
44
51
  Domains,
45
52
  DomainsTypedDict,
46
53
  )
47
- from .createcustomer import (
48
- CreateCustomerDiscount,
49
- CreateCustomerDiscountTypedDict,
50
- CreateCustomerLink,
51
- CreateCustomerLinkTypedDict,
52
- CreateCustomerPartner,
53
- CreateCustomerPartnerTypedDict,
54
- CreateCustomerRequestBody,
55
- CreateCustomerRequestBodyTypedDict,
56
- CreateCustomerResponseBody,
57
- CreateCustomerResponseBodyTypedDict,
58
- CreateCustomerType,
59
- )
60
54
  from .createdomain import CreateDomainRequestBody, CreateDomainRequestBodyTypedDict
61
55
  from .createfolder import (
62
56
  AccessLevel,
@@ -418,6 +412,10 @@ if TYPE_CHECKING:
418
412
 
419
413
  __all__ = [
420
414
  "AccessLevel",
415
+ "BanPartnerRequestBody",
416
+ "BanPartnerRequestBodyTypedDict",
417
+ "BanPartnerResponseBody",
418
+ "BanPartnerResponseBodyTypedDict",
421
419
  "BannedReason",
422
420
  "BulkCreateLinksTagIds",
423
421
  "BulkCreateLinksTagIdsTypedDict",
@@ -444,17 +442,6 @@ __all__ = [
444
442
  "Click",
445
443
  "ClickTypedDict",
446
444
  "Color",
447
- "CreateCustomerDiscount",
448
- "CreateCustomerDiscountTypedDict",
449
- "CreateCustomerLink",
450
- "CreateCustomerLinkTypedDict",
451
- "CreateCustomerPartner",
452
- "CreateCustomerPartnerTypedDict",
453
- "CreateCustomerRequestBody",
454
- "CreateCustomerRequestBodyTypedDict",
455
- "CreateCustomerResponseBody",
456
- "CreateCustomerResponseBodyTypedDict",
457
- "CreateCustomerType",
458
445
  "CreateDomainRequestBody",
459
446
  "CreateDomainRequestBodyTypedDict",
460
447
  "CreateFolderRequestBody",
@@ -634,6 +621,7 @@ __all__ = [
634
621
  "QueryParamTagNames",
635
622
  "QueryParamTagNamesTypedDict",
636
623
  "QueryParamTrigger",
624
+ "Reason",
637
625
  "RegisterDomainRequestBody",
638
626
  "RegisterDomainRequestBodyTypedDict",
639
627
  "RegisterDomainResponseBody",
@@ -759,6 +747,11 @@ __all__ = [
759
747
  ]
760
748
 
761
749
  _dynamic_imports: dict[str, str] = {
750
+ "BanPartnerRequestBody": ".banpartner",
751
+ "BanPartnerRequestBodyTypedDict": ".banpartner",
752
+ "BanPartnerResponseBody": ".banpartner",
753
+ "BanPartnerResponseBodyTypedDict": ".banpartner",
754
+ "Reason": ".banpartner",
762
755
  "BulkCreateLinksTagIds": ".bulkcreatelinks",
763
756
  "BulkCreateLinksTagIdsTypedDict": ".bulkcreatelinks",
764
757
  "BulkCreateLinksTagNames": ".bulkcreatelinks",
@@ -789,17 +782,6 @@ _dynamic_imports: dict[str, str] = {
789
782
  "CheckDomainStatusResponseBodyTypedDict": ".checkdomainstatus",
790
783
  "Domains": ".checkdomainstatus",
791
784
  "DomainsTypedDict": ".checkdomainstatus",
792
- "CreateCustomerDiscount": ".createcustomer",
793
- "CreateCustomerDiscountTypedDict": ".createcustomer",
794
- "CreateCustomerLink": ".createcustomer",
795
- "CreateCustomerLinkTypedDict": ".createcustomer",
796
- "CreateCustomerPartner": ".createcustomer",
797
- "CreateCustomerPartnerTypedDict": ".createcustomer",
798
- "CreateCustomerRequestBody": ".createcustomer",
799
- "CreateCustomerRequestBodyTypedDict": ".createcustomer",
800
- "CreateCustomerResponseBody": ".createcustomer",
801
- "CreateCustomerResponseBodyTypedDict": ".createcustomer",
802
- "CreateCustomerType": ".createcustomer",
803
785
  "CreateDomainRequestBody": ".createdomain",
804
786
  "CreateDomainRequestBodyTypedDict": ".createdomain",
805
787
  "AccessLevel": ".createfolder",
@@ -0,0 +1,83 @@
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 enum import Enum
6
+ import pydantic
7
+ from pydantic import model_serializer
8
+ from typing_extensions import Annotated, NotRequired, TypedDict
9
+
10
+
11
+ class Reason(str, Enum):
12
+ TOS_VIOLATION = "tos_violation"
13
+ INAPPROPRIATE_CONTENT = "inappropriate_content"
14
+ FAKE_TRAFFIC = "fake_traffic"
15
+ FRAUD = "fraud"
16
+ SPAM = "spam"
17
+ BRAND_ABUSE = "brand_abuse"
18
+
19
+
20
+ class BanPartnerRequestBodyTypedDict(TypedDict):
21
+ reason: Reason
22
+ partner_id: NotRequired[Nullable[str]]
23
+ r"""The ID of the partner to create a link for. Will take precedence over `tenantId` if provided."""
24
+ tenant_id: NotRequired[Nullable[str]]
25
+ r"""The ID of the partner in your system. If both `partnerId` and `tenantId` are not provided, an error will be thrown."""
26
+
27
+
28
+ class BanPartnerRequestBody(BaseModel):
29
+ reason: Reason
30
+
31
+ partner_id: Annotated[OptionalNullable[str], pydantic.Field(alias="partnerId")] = (
32
+ UNSET
33
+ )
34
+ r"""The ID of the partner to create a link for. Will take precedence over `tenantId` if provided."""
35
+
36
+ tenant_id: Annotated[OptionalNullable[str], pydantic.Field(alias="tenantId")] = (
37
+ UNSET
38
+ )
39
+ r"""The ID of the partner in your system. If both `partnerId` and `tenantId` are not provided, an error will be thrown."""
40
+
41
+ @model_serializer(mode="wrap")
42
+ def serialize_model(self, handler):
43
+ optional_fields = ["partnerId", "tenantId"]
44
+ nullable_fields = ["partnerId", "tenantId"]
45
+ null_default_fields = []
46
+
47
+ serialized = handler(self)
48
+
49
+ m = {}
50
+
51
+ for n, f in type(self).model_fields.items():
52
+ k = f.alias or n
53
+ val = serialized.get(k)
54
+ serialized.pop(k, None)
55
+
56
+ optional_nullable = k in optional_fields and k in nullable_fields
57
+ is_set = (
58
+ self.__pydantic_fields_set__.intersection({n})
59
+ or k in null_default_fields
60
+ ) # pylint: disable=no-member
61
+
62
+ if val is not None and val != UNSET_SENTINEL:
63
+ m[k] = val
64
+ elif val != UNSET_SENTINEL and (
65
+ not k in optional_fields or (optional_nullable and is_set)
66
+ ):
67
+ m[k] = val
68
+
69
+ return m
70
+
71
+
72
+ class BanPartnerResponseBodyTypedDict(TypedDict):
73
+ r"""The banned partner"""
74
+
75
+ partner_id: str
76
+ r"""The ID of the banned partner."""
77
+
78
+
79
+ class BanPartnerResponseBody(BaseModel):
80
+ r"""The banned partner"""
81
+
82
+ partner_id: Annotated[str, pydantic.Field(alias="partnerId")]
83
+ r"""The ID of the banned partner."""
@@ -49,7 +49,7 @@ class RequestBodyTypedDict(TypedDict):
49
49
  url: str
50
50
  r"""The destination URL of the short link."""
51
51
  domain: NotRequired[str]
52
- 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)."""
52
+ r"""The domain of the short link (without protocol). If not provided, the primary domain for the workspace will be used (or `dub.sh` if the workspace has no domains)."""
53
53
  key: NotRequired[str]
54
54
  r"""The short link slug. If not provided, a random 7-character slug will be generated."""
55
55
  key_length: NotRequired[float]
@@ -133,7 +133,7 @@ class RequestBody(BaseModel):
133
133
  r"""The destination URL of the short link."""
134
134
 
135
135
  domain: Optional[str] = None
136
- 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)."""
136
+ r"""The domain of the short link (without protocol). If not provided, the primary domain for the workspace will be used (or `dub.sh` if the workspace has no domains)."""
137
137
 
138
138
  key: Optional[str] = None
139
139
  r"""The short link slug. If not provided, a random 7-character slug will be generated."""
@@ -1,7 +1,7 @@
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, Nullable, OptionalNullable, UNSET_SENTINEL
4
+ from dub.types import BaseModel, Nullable, OptionalNullable, UNSET, UNSET_SENTINEL
5
5
  from enum import Enum
6
6
  import pydantic
7
7
  from pydantic import model_serializer
@@ -18,6 +18,8 @@ class AccessLevel(str, Enum):
18
18
  class CreateFolderRequestBodyTypedDict(TypedDict):
19
19
  name: str
20
20
  r"""The name of the folder."""
21
+ description: NotRequired[Nullable[str]]
22
+ r"""The description of the folder."""
21
23
  access_level: NotRequired[Nullable[AccessLevel]]
22
24
  r"""The access level of the folder within the workspace."""
23
25
 
@@ -26,6 +28,9 @@ class CreateFolderRequestBody(BaseModel):
26
28
  name: str
27
29
  r"""The name of the folder."""
28
30
 
31
+ description: OptionalNullable[str] = UNSET
32
+ r"""The description of the folder."""
33
+
29
34
  access_level: Annotated[
30
35
  OptionalNullable[AccessLevel], pydantic.Field(alias="accessLevel")
31
36
  ] = None
@@ -33,8 +38,8 @@ class CreateFolderRequestBody(BaseModel):
33
38
 
34
39
  @model_serializer(mode="wrap")
35
40
  def serialize_model(self, handler):
36
- optional_fields = ["accessLevel"]
37
- nullable_fields = ["accessLevel"]
41
+ optional_fields = ["description", "accessLevel"]
42
+ nullable_fields = ["description", "accessLevel"]
38
43
  null_default_fields = ["accessLevel"]
39
44
 
40
45
  serialized = handler(self)
@@ -43,7 +43,7 @@ class CreateLinkRequestBodyTypedDict(TypedDict):
43
43
  url: str
44
44
  r"""The destination URL of the short link."""
45
45
  domain: NotRequired[str]
46
- 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)."""
46
+ r"""The domain of the short link (without protocol). If not provided, the primary domain for the workspace will be used (or `dub.sh` if the workspace has no domains)."""
47
47
  key: NotRequired[str]
48
48
  r"""The short link slug. If not provided, a random 7-character slug will be generated."""
49
49
  key_length: NotRequired[float]
@@ -127,7 +127,7 @@ class CreateLinkRequestBody(BaseModel):
127
127
  r"""The destination URL of the short link."""
128
128
 
129
129
  domain: Optional[str] = None
130
- 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)."""
130
+ r"""The domain of the short link (without protocol). If not provided, the primary domain for the workspace will be used (or `dub.sh` if the workspace has no domains)."""
131
131
 
132
132
  key: Optional[str] = None
133
133
  r"""The short link slug. If not provided, a random 7-character slug will be generated."""
@@ -493,6 +493,8 @@ class CreatePartnerResponseBodyTypedDict(TypedDict):
493
493
  r"""The partner's Stripe Connect ID (for receiving payouts via Stripe)."""
494
494
  payouts_enabled_at: Nullable[str]
495
495
  r"""The date when the partner enabled payouts."""
496
+ trusted_at: Nullable[str]
497
+ r"""The date when the partner received the trusted badge in the partner network."""
496
498
  program_id: str
497
499
  r"""The program's unique ID on Dub."""
498
500
  partner_id: str
@@ -509,7 +511,7 @@ class CreatePartnerResponseBodyTypedDict(TypedDict):
509
511
  group_id: NotRequired[Nullable[str]]
510
512
  r"""The partner's group ID on Dub."""
511
513
  total_commissions: NotRequired[float]
512
- r"""The total commissions paid to the partner for their referrals. Defaults to 0 if `includeExpandedFields` is false."""
514
+ r"""The total commissions paid to the partner for their referrals"""
513
515
  click_reward_id: NotRequired[Nullable[str]]
514
516
  lead_reward_id: NotRequired[Nullable[str]]
515
517
  sale_reward_id: NotRequired[Nullable[str]]
@@ -520,18 +522,30 @@ class CreatePartnerResponseBodyTypedDict(TypedDict):
520
522
  r"""If the partner was banned from the program, this is the date of the ban."""
521
523
  banned_reason: NotRequired[Nullable[BannedReason]]
522
524
  r"""If the partner was banned from the program, this is the reason for the ban."""
523
- clicks: NotRequired[float]
524
- r"""The total number of clicks on the partner's links. Defaults to 0 if `includeExpandedFields` is false."""
525
- leads: NotRequired[float]
526
- r"""The total number of leads generated by the partner's links. Defaults to 0 if `includeExpandedFields` is false."""
527
- conversions: NotRequired[float]
528
- r"""The total number of leads that converted to paying customers. Defaults to 0 if `includeExpandedFields` is false."""
529
- sales: NotRequired[float]
530
- r"""The total number of sales generated by the partner's links (includes recurring sales). Defaults to 0 if `includeExpandedFields` is false."""
531
- sale_amount: NotRequired[float]
532
- r"""The total amount of sales (in cents) generated by the partner's links. Defaults to 0 if `includeExpandedFields` is false."""
525
+ total_clicks: NotRequired[float]
526
+ r"""The total number of clicks on the partner's links"""
527
+ total_leads: NotRequired[float]
528
+ r"""The total number of leads generated by the partner's links"""
529
+ total_conversions: NotRequired[float]
530
+ r"""The total number of leads that converted to paying customers"""
531
+ total_sales: NotRequired[float]
532
+ r"""The total number of sales generated by the partner's links (includes recurring sales)"""
533
+ total_sale_amount: NotRequired[float]
534
+ r"""Total revenue generated by the partner's links"""
533
535
  net_revenue: NotRequired[float]
534
- r"""The total net revenue generated by the partner. Defaults to 0 if `includeExpandedFields` is false."""
536
+ r"""Net revenue after commissions (`Total Revenue - Total Commissions`)"""
537
+ earnings_per_click: NotRequired[Nullable[float]]
538
+ r"""Earnings Per Click (EPC) (`Total Revenue ÷ Total Clicks`)"""
539
+ average_lifetime_value: NotRequired[Nullable[float]]
540
+ r"""Average lifetime value for each paying customer (`Total Revenue ÷ Total Conversions`)"""
541
+ click_to_lead_rate: NotRequired[Nullable[float]]
542
+ r"""Percentage of clicks that become leads (`Total Leads ÷ Total Clicks`)"""
543
+ click_to_conversion_rate: NotRequired[Nullable[float]]
544
+ r"""Percentage of clicks that convert to paying customers (`Total Conversions ÷ Total Clicks`)"""
545
+ lead_to_conversion_rate: NotRequired[Nullable[float]]
546
+ r"""Percentage of leads that convert to paying customers (`Total Conversions ÷ Total Leads`)"""
547
+ return_on_ad_spend: NotRequired[Nullable[float]]
548
+ r"""Return On Ad Spend (ROAS) (`Total Revenue ÷ Total Commissions`)"""
535
549
  website: NotRequired[Nullable[str]]
536
550
  r"""The partner's website URL (including the https protocol)."""
537
551
  youtube: NotRequired[Nullable[str]]
@@ -578,6 +592,9 @@ class CreatePartnerResponseBody(BaseModel):
578
592
  ]
579
593
  r"""The date when the partner enabled payouts."""
580
594
 
595
+ trusted_at: Annotated[Nullable[str], pydantic.Field(alias="trustedAt")]
596
+ r"""The date when the partner received the trusted badge in the partner network."""
597
+
581
598
  program_id: Annotated[str, pydantic.Field(alias="programId")]
582
599
  r"""The program's unique ID on Dub."""
583
600
 
@@ -604,7 +621,7 @@ class CreatePartnerResponseBody(BaseModel):
604
621
  total_commissions: Annotated[
605
622
  Optional[float], pydantic.Field(alias="totalCommissions")
606
623
  ] = 0
607
- r"""The total commissions paid to the partner for their referrals. Defaults to 0 if `includeExpandedFields` is false."""
624
+ r"""The total commissions paid to the partner for their referrals"""
608
625
 
609
626
  click_reward_id: Annotated[
610
627
  OptionalNullable[str], pydantic.Field(alias="clickRewardId")
@@ -637,23 +654,57 @@ class CreatePartnerResponseBody(BaseModel):
637
654
  ] = UNSET
638
655
  r"""If the partner was banned from the program, this is the reason for the ban."""
639
656
 
640
- clicks: Optional[float] = 0
641
- r"""The total number of clicks on the partner's links. Defaults to 0 if `includeExpandedFields` is false."""
657
+ total_clicks: Annotated[Optional[float], pydantic.Field(alias="totalClicks")] = 0
658
+ r"""The total number of clicks on the partner's links"""
642
659
 
643
- leads: Optional[float] = 0
644
- r"""The total number of leads generated by the partner's links. Defaults to 0 if `includeExpandedFields` is false."""
660
+ total_leads: Annotated[Optional[float], pydantic.Field(alias="totalLeads")] = 0
661
+ r"""The total number of leads generated by the partner's links"""
645
662
 
646
- conversions: Optional[float] = 0
647
- r"""The total number of leads that converted to paying customers. Defaults to 0 if `includeExpandedFields` is false."""
663
+ total_conversions: Annotated[
664
+ Optional[float], pydantic.Field(alias="totalConversions")
665
+ ] = 0
666
+ r"""The total number of leads that converted to paying customers"""
648
667
 
649
- sales: Optional[float] = 0
650
- r"""The total number of sales generated by the partner's links (includes recurring sales). Defaults to 0 if `includeExpandedFields` is false."""
668
+ total_sales: Annotated[Optional[float], pydantic.Field(alias="totalSales")] = 0
669
+ r"""The total number of sales generated by the partner's links (includes recurring sales)"""
651
670
 
652
- sale_amount: Annotated[Optional[float], pydantic.Field(alias="saleAmount")] = 0
653
- r"""The total amount of sales (in cents) generated by the partner's links. Defaults to 0 if `includeExpandedFields` is false."""
671
+ total_sale_amount: Annotated[
672
+ Optional[float], pydantic.Field(alias="totalSaleAmount")
673
+ ] = 0
674
+ r"""Total revenue generated by the partner's links"""
654
675
 
655
676
  net_revenue: Annotated[Optional[float], pydantic.Field(alias="netRevenue")] = 0
656
- r"""The total net revenue generated by the partner. Defaults to 0 if `includeExpandedFields` is false."""
677
+ r"""Net revenue after commissions (`Total Revenue - Total Commissions`)"""
678
+
679
+ earnings_per_click: Annotated[
680
+ OptionalNullable[float], pydantic.Field(alias="earningsPerClick")
681
+ ] = UNSET
682
+ r"""Earnings Per Click (EPC) (`Total Revenue ÷ Total Clicks`)"""
683
+
684
+ average_lifetime_value: Annotated[
685
+ OptionalNullable[float], pydantic.Field(alias="averageLifetimeValue")
686
+ ] = UNSET
687
+ r"""Average lifetime value for each paying customer (`Total Revenue ÷ Total Conversions`)"""
688
+
689
+ click_to_lead_rate: Annotated[
690
+ OptionalNullable[float], pydantic.Field(alias="clickToLeadRate")
691
+ ] = UNSET
692
+ r"""Percentage of clicks that become leads (`Total Leads ÷ Total Clicks`)"""
693
+
694
+ click_to_conversion_rate: Annotated[
695
+ OptionalNullable[float], pydantic.Field(alias="clickToConversionRate")
696
+ ] = UNSET
697
+ r"""Percentage of clicks that convert to paying customers (`Total Conversions ÷ Total Clicks`)"""
698
+
699
+ lead_to_conversion_rate: Annotated[
700
+ OptionalNullable[float], pydantic.Field(alias="leadToConversionRate")
701
+ ] = UNSET
702
+ r"""Percentage of leads that convert to paying customers (`Total Conversions ÷ Total Leads`)"""
703
+
704
+ return_on_ad_spend: Annotated[
705
+ OptionalNullable[float], pydantic.Field(alias="returnOnAdSpend")
706
+ ] = UNSET
707
+ r"""Return On Ad Spend (ROAS) (`Total Revenue ÷ Total Commissions`)"""
657
708
 
658
709
  website: OptionalNullable[str] = UNSET
659
710
  r"""The partner's website URL (including the https protocol)."""
@@ -686,12 +737,18 @@ class CreatePartnerResponseBody(BaseModel):
686
737
  "applicationId",
687
738
  "bannedAt",
688
739
  "bannedReason",
689
- "clicks",
690
- "leads",
691
- "conversions",
692
- "sales",
693
- "saleAmount",
740
+ "totalClicks",
741
+ "totalLeads",
742
+ "totalConversions",
743
+ "totalSales",
744
+ "totalSaleAmount",
694
745
  "netRevenue",
746
+ "earningsPerClick",
747
+ "averageLifetimeValue",
748
+ "clickToLeadRate",
749
+ "clickToConversionRate",
750
+ "leadToConversionRate",
751
+ "returnOnAdSpend",
695
752
  "website",
696
753
  "youtube",
697
754
  "twitter",
@@ -708,6 +765,7 @@ class CreatePartnerResponseBody(BaseModel):
708
765
  "paypalEmail",
709
766
  "stripeConnectId",
710
767
  "payoutsEnabledAt",
768
+ "trustedAt",
711
769
  "groupId",
712
770
  "tenantId",
713
771
  "links",
@@ -718,6 +776,12 @@ class CreatePartnerResponseBody(BaseModel):
718
776
  "applicationId",
719
777
  "bannedAt",
720
778
  "bannedReason",
779
+ "earningsPerClick",
780
+ "averageLifetimeValue",
781
+ "clickToLeadRate",
782
+ "clickToConversionRate",
783
+ "leadToConversionRate",
784
+ "returnOnAdSpend",
721
785
  "website",
722
786
  "youtube",
723
787
  "twitter",