dub 0.32.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.
- dub/_version.py +3 -3
- dub/analytics.py +4 -4
- dub/commissions.py +8 -8
- dub/customers.py +16 -313
- dub/domains.py +22 -26
- dub/embed_tokens.py +4 -4
- dub/events.py +4 -4
- dub/folders.py +16 -20
- dub/links.py +38 -54
- dub/models/components/__init__.py +32 -0
- dub/models/components/analyticstopurls.py +2 -2
- dub/models/components/clickevent.py +7 -6
- dub/models/components/leadcreatedevent.py +7 -6
- dub/models/components/leadevent.py +7 -6
- dub/models/components/linkclickedevent.py +7 -6
- dub/models/components/linkschema.py +6 -0
- dub/models/components/linkwebhookevent.py +7 -6
- dub/models/components/partnerapplicationsubmittedevent.py +269 -0
- dub/models/components/partnerenrolledevent.py +64 -4
- dub/models/components/salecreatedevent.py +7 -6
- dub/models/components/saleevent.py +7 -6
- dub/models/components/webhookevent.py +6 -0
- dub/models/components/workspaceschema.py +6 -0
- dub/models/operations/__init__.py +17 -35
- dub/models/operations/banpartner.py +83 -0
- dub/models/operations/createpartner.py +64 -4
- dub/models/operations/listcommissions.py +13 -2
- dub/models/operations/listevents.py +10 -0
- dub/models/operations/listpartners.py +71 -4
- dub/models/operations/retrieveanalytics.py +12 -0
- dub/models/operations/retrievelinks.py +42 -7
- dub/models/operations/retrievepartneranalytics.py +51 -11
- dub/models/operations/updatecommission.py +7 -2
- dub/partners.py +298 -24
- dub/qr_codes.py +2 -2
- dub/tags.py +16 -24
- dub/track.py +8 -16
- dub/utils/retries.py +69 -5
- dub/utils/unmarshal_json_response.py +15 -1
- dub/workspaces.py +8 -16
- {dub-0.32.0.dist-info → dub-0.33.0.dist-info}/METADATA +2 -20
- {dub-0.32.0.dist-info → dub-0.33.0.dist-info}/RECORD +44 -43
- dub/models/operations/createcustomer.py +0 -382
- {dub-0.32.0.dist-info → dub-0.33.0.dist-info}/WHEEL +0 -0
- {dub-0.32.0.dist-info → dub-0.33.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -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."""
|
|
@@ -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
|
|
@@ -529,9 +531,21 @@ class CreatePartnerResponseBodyTypedDict(TypedDict):
|
|
|
529
531
|
total_sales: NotRequired[float]
|
|
530
532
|
r"""The total number of sales generated by the partner's links (includes recurring sales)"""
|
|
531
533
|
total_sale_amount: NotRequired[float]
|
|
532
|
-
r"""
|
|
534
|
+
r"""Total revenue generated by the partner's links"""
|
|
533
535
|
net_revenue: NotRequired[float]
|
|
534
|
-
r"""
|
|
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
|
|
|
@@ -654,10 +671,40 @@ class CreatePartnerResponseBody(BaseModel):
|
|
|
654
671
|
total_sale_amount: Annotated[
|
|
655
672
|
Optional[float], pydantic.Field(alias="totalSaleAmount")
|
|
656
673
|
] = 0
|
|
657
|
-
r"""
|
|
674
|
+
r"""Total revenue generated by the partner's links"""
|
|
658
675
|
|
|
659
676
|
net_revenue: Annotated[Optional[float], pydantic.Field(alias="netRevenue")] = 0
|
|
660
|
-
r"""
|
|
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`)"""
|
|
661
708
|
|
|
662
709
|
website: OptionalNullable[str] = UNSET
|
|
663
710
|
r"""The partner's website URL (including the https protocol)."""
|
|
@@ -696,6 +743,12 @@ class CreatePartnerResponseBody(BaseModel):
|
|
|
696
743
|
"totalSales",
|
|
697
744
|
"totalSaleAmount",
|
|
698
745
|
"netRevenue",
|
|
746
|
+
"earningsPerClick",
|
|
747
|
+
"averageLifetimeValue",
|
|
748
|
+
"clickToLeadRate",
|
|
749
|
+
"clickToConversionRate",
|
|
750
|
+
"leadToConversionRate",
|
|
751
|
+
"returnOnAdSpend",
|
|
699
752
|
"website",
|
|
700
753
|
"youtube",
|
|
701
754
|
"twitter",
|
|
@@ -712,6 +765,7 @@ class CreatePartnerResponseBody(BaseModel):
|
|
|
712
765
|
"paypalEmail",
|
|
713
766
|
"stripeConnectId",
|
|
714
767
|
"payoutsEnabledAt",
|
|
768
|
+
"trustedAt",
|
|
715
769
|
"groupId",
|
|
716
770
|
"tenantId",
|
|
717
771
|
"links",
|
|
@@ -722,6 +776,12 @@ class CreatePartnerResponseBody(BaseModel):
|
|
|
722
776
|
"applicationId",
|
|
723
777
|
"bannedAt",
|
|
724
778
|
"bannedReason",
|
|
779
|
+
"earningsPerClick",
|
|
780
|
+
"averageLifetimeValue",
|
|
781
|
+
"clickToLeadRate",
|
|
782
|
+
"clickToConversionRate",
|
|
783
|
+
"leadToConversionRate",
|
|
784
|
+
"returnOnAdSpend",
|
|
725
785
|
"website",
|
|
726
786
|
"youtube",
|
|
727
787
|
"twitter",
|
|
@@ -83,6 +83,7 @@ class ListCommissionsRequestTypedDict(TypedDict):
|
|
|
83
83
|
r"""The start date of the date range to filter the commissions by."""
|
|
84
84
|
end: NotRequired[str]
|
|
85
85
|
r"""The end date of the date range to filter the commissions by."""
|
|
86
|
+
timezone: NotRequired[str]
|
|
86
87
|
page: NotRequired[float]
|
|
87
88
|
r"""The page number for pagination."""
|
|
88
89
|
page_size: NotRequired[float]
|
|
@@ -175,6 +176,11 @@ class ListCommissionsRequest(BaseModel):
|
|
|
175
176
|
] = None
|
|
176
177
|
r"""The end date of the date range to filter the commissions by."""
|
|
177
178
|
|
|
179
|
+
timezone: Annotated[
|
|
180
|
+
Optional[str],
|
|
181
|
+
FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
|
|
182
|
+
] = None
|
|
183
|
+
|
|
178
184
|
page: Annotated[
|
|
179
185
|
Optional[float],
|
|
180
186
|
FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
|
|
@@ -219,6 +225,8 @@ class ListCommissionsPartnerTypedDict(TypedDict):
|
|
|
219
225
|
r"""The date when the partner enabled payouts."""
|
|
220
226
|
country: Nullable[str]
|
|
221
227
|
r"""The partner's country (required for tax purposes)."""
|
|
228
|
+
group_id: NotRequired[Nullable[str]]
|
|
229
|
+
r"""The partner's group ID on Dub."""
|
|
222
230
|
|
|
223
231
|
|
|
224
232
|
class ListCommissionsPartner(BaseModel):
|
|
@@ -242,10 +250,13 @@ class ListCommissionsPartner(BaseModel):
|
|
|
242
250
|
country: Nullable[str]
|
|
243
251
|
r"""The partner's country (required for tax purposes)."""
|
|
244
252
|
|
|
253
|
+
group_id: Annotated[OptionalNullable[str], pydantic.Field(alias="groupId")] = UNSET
|
|
254
|
+
r"""The partner's group ID on Dub."""
|
|
255
|
+
|
|
245
256
|
@model_serializer(mode="wrap")
|
|
246
257
|
def serialize_model(self, handler):
|
|
247
|
-
optional_fields = []
|
|
248
|
-
nullable_fields = ["email", "image", "payoutsEnabledAt", "country"]
|
|
258
|
+
optional_fields = ["groupId"]
|
|
259
|
+
nullable_fields = ["email", "image", "payoutsEnabledAt", "country", "groupId"]
|
|
249
260
|
null_default_fields = []
|
|
250
261
|
|
|
251
262
|
serialized = handler(self)
|
|
@@ -148,6 +148,8 @@ class ListEventsRequestTypedDict(TypedDict):
|
|
|
148
148
|
r"""The tag IDs to retrieve analytics for."""
|
|
149
149
|
folder_id: NotRequired[str]
|
|
150
150
|
r"""The folder ID to retrieve analytics for. If not provided, return analytics for unsorted links."""
|
|
151
|
+
group_id: NotRequired[str]
|
|
152
|
+
r"""The group ID to retrieve analytics for."""
|
|
151
153
|
root: NotRequired[bool]
|
|
152
154
|
r"""Filter for root domains. If true, filter for domains only. If false, filter for links only. If undefined, return both."""
|
|
153
155
|
sale_type: NotRequired[QueryParamSaleType]
|
|
@@ -346,6 +348,13 @@ class ListEventsRequest(BaseModel):
|
|
|
346
348
|
] = None
|
|
347
349
|
r"""The folder ID to retrieve analytics for. If not provided, return analytics for unsorted links."""
|
|
348
350
|
|
|
351
|
+
group_id: Annotated[
|
|
352
|
+
Optional[str],
|
|
353
|
+
pydantic.Field(alias="groupId"),
|
|
354
|
+
FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
|
|
355
|
+
] = None
|
|
356
|
+
r"""The group ID to retrieve analytics for."""
|
|
357
|
+
|
|
349
358
|
root: Annotated[
|
|
350
359
|
Optional[bool],
|
|
351
360
|
FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
|
|
@@ -473,6 +482,7 @@ class ListEventsRequest(BaseModel):
|
|
|
473
482
|
"url",
|
|
474
483
|
"tagIds",
|
|
475
484
|
"folderId",
|
|
485
|
+
"groupId",
|
|
476
486
|
"root",
|
|
477
487
|
"saleType",
|
|
478
488
|
"query",
|
|
@@ -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):
|
|
@@ -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
|
|
@@ -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"""
|
|
268
|
+
r"""Total revenue generated by the partner's links"""
|
|
260
269
|
net_revenue: NotRequired[float]
|
|
261
|
-
r"""
|
|
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
|
|
|
@@ -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"""
|
|
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"""
|
|
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",
|
|
@@ -57,7 +57,9 @@ class QueryParamGroupBy(str, Enum):
|
|
|
57
57
|
TOP_DOMAINS = "top_domains"
|
|
58
58
|
TOP_LINKS = "top_links"
|
|
59
59
|
TOP_URLS = "top_urls"
|
|
60
|
+
TOP_BASE_URLS = "top_base_urls"
|
|
60
61
|
TOP_PARTNERS = "top_partners"
|
|
62
|
+
TOP_GROUPS = "top_groups"
|
|
61
63
|
UTM_SOURCES = "utm_sources"
|
|
62
64
|
UTM_MEDIUMS = "utm_mediums"
|
|
63
65
|
UTM_CAMPAIGNS = "utm_campaigns"
|
|
@@ -162,6 +164,8 @@ class RetrieveAnalyticsRequestTypedDict(TypedDict):
|
|
|
162
164
|
r"""The tag IDs to retrieve analytics for."""
|
|
163
165
|
folder_id: NotRequired[str]
|
|
164
166
|
r"""The folder ID to retrieve analytics for. If not provided, return analytics for unsorted links."""
|
|
167
|
+
group_id: NotRequired[str]
|
|
168
|
+
r"""The group ID to retrieve analytics for."""
|
|
165
169
|
root: NotRequired[bool]
|
|
166
170
|
r"""Filter for root domains. If true, filter for domains only. If false, filter for links only. If undefined, return both."""
|
|
167
171
|
sale_type: NotRequired[SaleType]
|
|
@@ -359,6 +363,13 @@ class RetrieveAnalyticsRequest(BaseModel):
|
|
|
359
363
|
] = None
|
|
360
364
|
r"""The folder ID to retrieve analytics for. If not provided, return analytics for unsorted links."""
|
|
361
365
|
|
|
366
|
+
group_id: Annotated[
|
|
367
|
+
Optional[str],
|
|
368
|
+
pydantic.Field(alias="groupId"),
|
|
369
|
+
FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
|
|
370
|
+
] = None
|
|
371
|
+
r"""The group ID to retrieve analytics for."""
|
|
372
|
+
|
|
362
373
|
root: Annotated[
|
|
363
374
|
Optional[bool],
|
|
364
375
|
FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
|
|
@@ -457,6 +468,7 @@ class RetrieveAnalyticsRequest(BaseModel):
|
|
|
457
468
|
"url",
|
|
458
469
|
"tagIds",
|
|
459
470
|
"folderId",
|
|
471
|
+
"groupId",
|
|
460
472
|
"root",
|
|
461
473
|
"saleType",
|
|
462
474
|
"query",
|
|
@@ -1,30 +1,65 @@
|
|
|
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
|
-
|
|
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
|
-
|
|
21
|
+
OptionalNullable[str],
|
|
19
22
|
pydantic.Field(alias="partnerId"),
|
|
20
23
|
FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
|
|
21
|
-
] =
|
|
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
|
-
|
|
28
|
+
OptionalNullable[str],
|
|
25
29
|
pydantic.Field(alias="tenantId"),
|
|
26
30
|
FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
|
|
27
|
-
] =
|
|
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."""
|
|
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 = []
|
|
39
|
+
|
|
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
|
|
28
63
|
|
|
29
64
|
|
|
30
65
|
class LinkTypedDict(TypedDict):
|
|
@@ -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
|
|
42
|
-
tenant_id: NotRequired[str]
|
|
43
|
-
r"""The ID of the
|
|
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
|
-
|
|
61
|
+
OptionalNullable[str],
|
|
61
62
|
pydantic.Field(alias="partnerId"),
|
|
62
63
|
FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
|
|
63
|
-
] =
|
|
64
|
-
r"""The ID of the partner to
|
|
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
|
-
|
|
68
|
+
OptionalNullable[str],
|
|
68
69
|
pydantic.Field(alias="tenantId"),
|
|
69
70
|
FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
|
|
70
|
-
] =
|
|
71
|
-
r"""The ID of the
|
|
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",
|
|
@@ -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)
|