dub 0.34.1__py3-none-any.whl → 0.35.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 (93) hide show
  1. dub/_version.py +3 -3
  2. dub/basesdk.py +20 -6
  3. dub/models/components/__init__.py +108 -26
  4. dub/models/components/analyticsbrowsers.py +18 -1
  5. dub/models/components/analyticscities.py +18 -1
  6. dub/models/components/analyticscontinents.py +18 -1
  7. dub/models/components/analyticscount.py +18 -1
  8. dub/models/components/analyticscountries.py +20 -1
  9. dub/models/components/analyticsdevices.py +18 -1
  10. dub/models/components/analyticsos.py +18 -1
  11. dub/models/components/analyticsreferers.py +18 -1
  12. dub/models/components/analyticsrefererurls.py +18 -1
  13. dub/models/components/analyticsregions.py +18 -1
  14. dub/models/components/analyticstimeseries.py +18 -1
  15. dub/models/components/analyticstoplinks.py +16 -26
  16. dub/models/components/analyticstopurls.py +18 -1
  17. dub/models/components/analyticstriggers.py +18 -1
  18. dub/models/components/commissioncreatedevent.py +96 -64
  19. dub/models/components/domainschema.py +31 -50
  20. dub/models/components/folderschema.py +18 -19
  21. dub/models/components/leadcreatedevent.py +151 -134
  22. dub/models/components/linkclickedevent.py +57 -70
  23. dub/models/components/linkschema.py +63 -64
  24. dub/models/components/linkwebhookevent.py +43 -51
  25. dub/models/components/partneranalyticscount.py +18 -1
  26. dub/models/components/partneranalyticstimeseries.py +18 -1
  27. dub/models/components/partneranalyticstoplinks.py +16 -27
  28. dub/models/components/partnerapplicationsubmittedevent.py +42 -75
  29. dub/models/components/partnerenrolledevent.py +477 -83
  30. dub/models/components/salecreatedevent.py +152 -151
  31. dub/models/errors/badrequest.py +18 -1
  32. dub/models/errors/conflict.py +18 -1
  33. dub/models/errors/forbidden.py +18 -1
  34. dub/models/errors/internalservererror.py +18 -1
  35. dub/models/errors/inviteexpired.py +18 -1
  36. dub/models/errors/notfound.py +18 -1
  37. dub/models/errors/ratelimitexceeded.py +18 -1
  38. dub/models/errors/unauthorized.py +18 -1
  39. dub/models/errors/unprocessableentity.py +18 -1
  40. dub/models/operations/__init__.py +230 -19
  41. dub/models/operations/approvebountysubmission.py +71 -45
  42. dub/models/operations/banpartner.py +14 -19
  43. dub/models/operations/bulkcreatelinks.py +86 -87
  44. dub/models/operations/bulkupdatelinks.py +97 -82
  45. dub/models/operations/checkdomainstatus.py +1 -17
  46. dub/models/operations/createdomain.py +33 -34
  47. dub/models/operations/createfolder.py +18 -19
  48. dub/models/operations/createlink.py +86 -87
  49. dub/models/operations/createpartner.py +560 -168
  50. dub/models/operations/createpartnerlink.py +74 -85
  51. dub/models/operations/createreferralsembedtoken.py +99 -87
  52. dub/models/operations/createtag.py +18 -1
  53. dub/models/operations/deactivatepartner.py +65 -0
  54. dub/models/operations/getcustomer.py +106 -105
  55. dub/models/operations/getcustomers.py +123 -105
  56. dub/models/operations/getlinkinfo.py +18 -1
  57. dub/models/operations/getlinks.py +36 -1
  58. dub/models/operations/getlinkscount.py +32 -1
  59. dub/models/operations/getqrcode.py +29 -1
  60. dub/models/operations/gettags.py +20 -1
  61. dub/models/operations/listbountysubmissions.py +63 -26
  62. dub/models/operations/listcommissions.py +129 -64
  63. dub/models/operations/listdomains.py +18 -1
  64. dub/models/operations/listevents.py +414 -389
  65. dub/models/operations/listfolders.py +18 -1
  66. dub/models/operations/listpartners.py +510 -84
  67. dub/models/operations/registerdomain.py +1 -17
  68. dub/models/operations/rejectbountysubmission.py +71 -26
  69. dub/models/operations/retrieveanalytics.py +65 -66
  70. dub/models/operations/retrievelinks.py +30 -19
  71. dub/models/operations/retrievepartneranalytics.py +25 -28
  72. dub/models/operations/tracklead.py +38 -83
  73. dub/models/operations/tracksale.py +52 -95
  74. dub/models/operations/updatecommission.py +126 -64
  75. dub/models/operations/updatecustomer.py +122 -131
  76. dub/models/operations/updatedomain.py +50 -35
  77. dub/models/operations/updatefolder.py +34 -19
  78. dub/models/operations/updatelink.py +101 -86
  79. dub/models/operations/updatetag.py +34 -1
  80. dub/models/operations/upsertlink.py +86 -87
  81. dub/models/operations/upsertpartnerlink.py +72 -78
  82. dub/partners.py +288 -0
  83. dub/sdk.py +0 -3
  84. dub/utils/__init__.py +10 -1
  85. {dub-0.34.1.dist-info → dub-0.35.0.dist-info}/METADATA +4 -8
  86. dub-0.35.0.dist-info/RECORD +143 -0
  87. dub/models/components/workspaceschema.py +0 -328
  88. dub/models/operations/getworkspace.py +0 -21
  89. dub/models/operations/updateworkspace.py +0 -78
  90. dub/workspaces.py +0 -561
  91. dub-0.34.1.dist-info/RECORD +0 -146
  92. {dub-0.34.1.dist-info → dub-0.35.0.dist-info}/WHEEL +0 -0
  93. {dub-0.34.1.dist-info → dub-0.35.0.dist-info}/licenses/LICENSE +0 -0
@@ -17,36 +17,42 @@ class LeadCreatedEventEvent(str, Enum):
17
17
  class CustomerTypedDict(TypedDict):
18
18
  id: str
19
19
  r"""The unique ID of the customer. You may use either the customer's `id` on Dub (obtained via `/customers` endpoint) or their `externalId` (unique ID within your system, prefixed with `ext_`, e.g. `ext_123`)."""
20
- external_id: str
21
- r"""Unique identifier for the customer in the client's app."""
22
20
  name: str
23
21
  r"""Name of the customer."""
22
+ external_id: str
23
+ r"""Unique identifier for the customer in the client's app."""
24
24
  created_at: str
25
- r"""The date the customer was created."""
25
+ r"""The date the customer was created (usually the signup date or trial start date)."""
26
26
  email: NotRequired[Nullable[str]]
27
27
  r"""Email of the customer."""
28
28
  avatar: NotRequired[Nullable[str]]
29
29
  r"""Avatar URL of the customer."""
30
+ stripe_customer_id: NotRequired[Nullable[str]]
31
+ r"""The customer's Stripe customer ID. This is useful for attributing recurring sale events to the partner who referred the customer."""
30
32
  country: NotRequired[Nullable[str]]
31
33
  r"""Country of the customer."""
32
34
  sales: NotRequired[Nullable[float]]
33
35
  r"""Total number of sales for the customer."""
34
36
  sale_amount: NotRequired[Nullable[float]]
35
37
  r"""Total amount of sales for the customer."""
38
+ first_sale_at: NotRequired[Nullable[str]]
39
+ r"""The date the customer made their first sale. Useful for calculating the time to first sale and LTV."""
40
+ subscription_canceled_at: NotRequired[Nullable[str]]
41
+ r"""The date the customer canceled their subscription. Useful for calculating LTV and churn rate."""
36
42
 
37
43
 
38
44
  class Customer(BaseModel):
39
45
  id: str
40
46
  r"""The unique ID of the customer. You may use either the customer's `id` on Dub (obtained via `/customers` endpoint) or their `externalId` (unique ID within your system, prefixed with `ext_`, e.g. `ext_123`)."""
41
47
 
42
- external_id: Annotated[str, pydantic.Field(alias="externalId")]
43
- r"""Unique identifier for the customer in the client's app."""
44
-
45
48
  name: str
46
49
  r"""Name of the customer."""
47
50
 
51
+ external_id: Annotated[str, pydantic.Field(alias="externalId")]
52
+ r"""Unique identifier for the customer in the client's app."""
53
+
48
54
  created_at: Annotated[str, pydantic.Field(alias="createdAt")]
49
- r"""The date the customer was created."""
55
+ r"""The date the customer was created (usually the signup date or trial start date)."""
50
56
 
51
57
  email: OptionalNullable[str] = UNSET
52
58
  r"""Email of the customer."""
@@ -54,6 +60,11 @@ class Customer(BaseModel):
54
60
  avatar: OptionalNullable[str] = UNSET
55
61
  r"""Avatar URL of the customer."""
56
62
 
63
+ stripe_customer_id: Annotated[
64
+ OptionalNullable[str], pydantic.Field(alias="stripeCustomerId")
65
+ ] = UNSET
66
+ r"""The customer's Stripe customer ID. This is useful for attributing recurring sale events to the partner who referred the customer."""
67
+
57
68
  country: OptionalNullable[str] = UNSET
58
69
  r"""Country of the customer."""
59
70
 
@@ -65,33 +76,60 @@ class Customer(BaseModel):
65
76
  ] = UNSET
66
77
  r"""Total amount of sales for the customer."""
67
78
 
79
+ first_sale_at: Annotated[
80
+ OptionalNullable[str], pydantic.Field(alias="firstSaleAt")
81
+ ] = UNSET
82
+ r"""The date the customer made their first sale. Useful for calculating the time to first sale and LTV."""
83
+
84
+ subscription_canceled_at: Annotated[
85
+ OptionalNullable[str], pydantic.Field(alias="subscriptionCanceledAt")
86
+ ] = UNSET
87
+ r"""The date the customer canceled their subscription. Useful for calculating LTV and churn rate."""
88
+
68
89
  @model_serializer(mode="wrap")
69
90
  def serialize_model(self, handler):
70
- optional_fields = ["email", "avatar", "country", "sales", "saleAmount"]
71
- nullable_fields = ["email", "avatar", "country", "sales", "saleAmount"]
72
- null_default_fields = []
73
-
91
+ optional_fields = set(
92
+ [
93
+ "email",
94
+ "avatar",
95
+ "stripeCustomerId",
96
+ "country",
97
+ "sales",
98
+ "saleAmount",
99
+ "firstSaleAt",
100
+ "subscriptionCanceledAt",
101
+ ]
102
+ )
103
+ nullable_fields = set(
104
+ [
105
+ "email",
106
+ "avatar",
107
+ "stripeCustomerId",
108
+ "country",
109
+ "sales",
110
+ "saleAmount",
111
+ "firstSaleAt",
112
+ "subscriptionCanceledAt",
113
+ ]
114
+ )
74
115
  serialized = handler(self)
75
-
76
116
  m = {}
77
117
 
78
118
  for n, f in type(self).model_fields.items():
79
119
  k = f.alias or n
80
120
  val = serialized.get(k)
81
- serialized.pop(k, None)
82
-
83
- optional_nullable = k in optional_fields and k in nullable_fields
84
- is_set = (
85
- self.__pydantic_fields_set__.intersection({n})
86
- or k in null_default_fields
87
- ) # pylint: disable=no-member
88
-
89
- if val is not None and val != UNSET_SENTINEL:
90
- m[k] = val
91
- elif val != UNSET_SENTINEL and (
92
- not k in optional_fields or (optional_nullable and is_set)
93
- ):
94
- m[k] = val
121
+ is_nullable_and_explicitly_set = (
122
+ k in nullable_fields
123
+ and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
124
+ )
125
+
126
+ if val != UNSET_SENTINEL:
127
+ if (
128
+ val is not None
129
+ or k not in optional_fields
130
+ or is_nullable_and_explicitly_set
131
+ ):
132
+ m[k] = val
95
133
 
96
134
  return m
97
135
 
@@ -147,31 +185,26 @@ class LeadCreatedEventClick(BaseModel):
147
185
 
148
186
  @model_serializer(mode="wrap")
149
187
  def serialize_model(self, handler):
150
- optional_fields = ["trigger"]
151
- nullable_fields = ["trigger"]
152
- null_default_fields = []
153
-
188
+ optional_fields = set(["trigger"])
189
+ nullable_fields = set(["trigger"])
154
190
  serialized = handler(self)
155
-
156
191
  m = {}
157
192
 
158
193
  for n, f in type(self).model_fields.items():
159
194
  k = f.alias or n
160
195
  val = serialized.get(k)
161
- serialized.pop(k, None)
162
-
163
- optional_nullable = k in optional_fields and k in nullable_fields
164
- is_set = (
165
- self.__pydantic_fields_set__.intersection({n})
166
- or k in null_default_fields
167
- ) # pylint: disable=no-member
168
-
169
- if val is not None and val != UNSET_SENTINEL:
170
- m[k] = val
171
- elif val != UNSET_SENTINEL and (
172
- not k in optional_fields or (optional_nullable and is_set)
173
- ):
174
- m[k] = val
196
+ is_nullable_and_explicitly_set = (
197
+ k in nullable_fields
198
+ and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
199
+ )
200
+
201
+ if val != UNSET_SENTINEL:
202
+ if (
203
+ val is not None
204
+ or k not in optional_fields
205
+ or is_nullable_and_explicitly_set
206
+ ):
207
+ m[k] = val
175
208
 
176
209
  return m
177
210
 
@@ -431,63 +464,55 @@ class LeadCreatedEventLink(BaseModel):
431
464
 
432
465
  @model_serializer(mode="wrap")
433
466
  def serialize_model(self, handler):
434
- optional_fields = [
435
- "testVariants",
436
- "clicks",
437
- "leads",
438
- "conversions",
439
- "sales",
440
- "saleAmount",
441
- ]
442
- nullable_fields = [
443
- "externalId",
444
- "tenantId",
445
- "programId",
446
- "partnerId",
447
- "expiredUrl",
448
- "password",
449
- "title",
450
- "description",
451
- "image",
452
- "video",
453
- "ios",
454
- "android",
455
- "geo",
456
- "tags",
457
- "folderId",
458
- "comments",
459
- "utm_source",
460
- "utm_medium",
461
- "utm_campaign",
462
- "utm_term",
463
- "utm_content",
464
- "testVariants",
465
- "userId",
466
- "tagId",
467
- ]
468
- null_default_fields = []
469
-
467
+ optional_fields = set(
468
+ ["testVariants", "clicks", "leads", "conversions", "sales", "saleAmount"]
469
+ )
470
+ nullable_fields = set(
471
+ [
472
+ "externalId",
473
+ "tenantId",
474
+ "programId",
475
+ "partnerId",
476
+ "expiredUrl",
477
+ "password",
478
+ "title",
479
+ "description",
480
+ "image",
481
+ "video",
482
+ "ios",
483
+ "android",
484
+ "geo",
485
+ "tags",
486
+ "folderId",
487
+ "comments",
488
+ "utm_source",
489
+ "utm_medium",
490
+ "utm_campaign",
491
+ "utm_term",
492
+ "utm_content",
493
+ "testVariants",
494
+ "userId",
495
+ "tagId",
496
+ ]
497
+ )
470
498
  serialized = handler(self)
471
-
472
499
  m = {}
473
500
 
474
501
  for n, f in type(self).model_fields.items():
475
502
  k = f.alias or n
476
503
  val = serialized.get(k)
477
- serialized.pop(k, None)
478
-
479
- optional_nullable = k in optional_fields and k in nullable_fields
480
- is_set = (
481
- self.__pydantic_fields_set__.intersection({n})
482
- or k in null_default_fields
483
- ) # pylint: disable=no-member
484
-
485
- if val is not None and val != UNSET_SENTINEL:
486
- m[k] = val
487
- elif val != UNSET_SENTINEL and (
488
- not k in optional_fields or (optional_nullable and is_set)
489
- ):
490
- m[k] = val
504
+ is_nullable_and_explicitly_set = (
505
+ k in nullable_fields
506
+ and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
507
+ )
508
+
509
+ if val != UNSET_SENTINEL:
510
+ if (
511
+ val is not None
512
+ or k not in optional_fields
513
+ or is_nullable_and_explicitly_set
514
+ ):
515
+ m[k] = val
491
516
 
492
517
  return m
493
518
 
@@ -551,31 +576,28 @@ class Partner(BaseModel):
551
576
 
552
577
  @model_serializer(mode="wrap")
553
578
  def serialize_model(self, handler):
554
- optional_fields = ["groupId"]
555
- nullable_fields = ["email", "image", "payoutsEnabledAt", "country", "groupId"]
556
- null_default_fields = []
557
-
579
+ optional_fields = set(["groupId"])
580
+ nullable_fields = set(
581
+ ["email", "image", "payoutsEnabledAt", "country", "groupId"]
582
+ )
558
583
  serialized = handler(self)
559
-
560
584
  m = {}
561
585
 
562
586
  for n, f in type(self).model_fields.items():
563
587
  k = f.alias or n
564
588
  val = serialized.get(k)
565
- serialized.pop(k, None)
566
-
567
- optional_nullable = k in optional_fields and k in nullable_fields
568
- is_set = (
569
- self.__pydantic_fields_set__.intersection({n})
570
- or k in null_default_fields
571
- ) # pylint: disable=no-member
572
-
573
- if val is not None and val != UNSET_SENTINEL:
574
- m[k] = val
575
- elif val != UNSET_SENTINEL and (
576
- not k in optional_fields or (optional_nullable and is_set)
577
- ):
578
- m[k] = val
589
+ is_nullable_and_explicitly_set = (
590
+ k in nullable_fields
591
+ and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
592
+ )
593
+
594
+ if val != UNSET_SENTINEL:
595
+ if (
596
+ val is not None
597
+ or k not in optional_fields
598
+ or is_nullable_and_explicitly_set
599
+ ):
600
+ m[k] = val
579
601
 
580
602
  return m
581
603
 
@@ -604,31 +626,26 @@ class LeadCreatedEventData(BaseModel):
604
626
 
605
627
  @model_serializer(mode="wrap")
606
628
  def serialize_model(self, handler):
607
- optional_fields = ["partner", "metadata"]
608
- nullable_fields = ["partner", "metadata"]
609
- null_default_fields = []
610
-
629
+ optional_fields = set(["partner", "metadata"])
630
+ nullable_fields = set(["partner", "metadata"])
611
631
  serialized = handler(self)
612
-
613
632
  m = {}
614
633
 
615
634
  for n, f in type(self).model_fields.items():
616
635
  k = f.alias or n
617
636
  val = serialized.get(k)
618
- serialized.pop(k, None)
619
-
620
- optional_nullable = k in optional_fields and k in nullable_fields
621
- is_set = (
622
- self.__pydantic_fields_set__.intersection({n})
623
- or k in null_default_fields
624
- ) # pylint: disable=no-member
625
-
626
- if val is not None and val != UNSET_SENTINEL:
627
- m[k] = val
628
- elif val != UNSET_SENTINEL and (
629
- not k in optional_fields or (optional_nullable and is_set)
630
- ):
631
- m[k] = val
637
+ is_nullable_and_explicitly_set = (
638
+ k in nullable_fields
639
+ and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
640
+ )
641
+
642
+ if val != UNSET_SENTINEL:
643
+ if (
644
+ val is not None
645
+ or k not in optional_fields
646
+ or is_nullable_and_explicitly_set
647
+ ):
648
+ m[k] = val
632
649
 
633
650
  return m
634
651
 
@@ -65,31 +65,26 @@ class Click(BaseModel):
65
65
 
66
66
  @model_serializer(mode="wrap")
67
67
  def serialize_model(self, handler):
68
- optional_fields = ["trigger"]
69
- nullable_fields = ["trigger"]
70
- null_default_fields = []
71
-
68
+ optional_fields = set(["trigger"])
69
+ nullable_fields = set(["trigger"])
72
70
  serialized = handler(self)
73
-
74
71
  m = {}
75
72
 
76
73
  for n, f in type(self).model_fields.items():
77
74
  k = f.alias or n
78
75
  val = serialized.get(k)
79
- serialized.pop(k, None)
80
-
81
- optional_nullable = k in optional_fields and k in nullable_fields
82
- is_set = (
83
- self.__pydantic_fields_set__.intersection({n})
84
- or k in null_default_fields
85
- ) # pylint: disable=no-member
86
-
87
- if val is not None and val != UNSET_SENTINEL:
88
- m[k] = val
89
- elif val != UNSET_SENTINEL and (
90
- not k in optional_fields or (optional_nullable and is_set)
91
- ):
92
- m[k] = val
76
+ is_nullable_and_explicitly_set = (
77
+ k in nullable_fields
78
+ and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
79
+ )
80
+
81
+ if val != UNSET_SENTINEL:
82
+ if (
83
+ val is not None
84
+ or k not in optional_fields
85
+ or is_nullable_and_explicitly_set
86
+ ):
87
+ m[k] = val
93
88
 
94
89
  return m
95
90
 
@@ -349,63 +344,55 @@ class Link(BaseModel):
349
344
 
350
345
  @model_serializer(mode="wrap")
351
346
  def serialize_model(self, handler):
352
- optional_fields = [
353
- "testVariants",
354
- "clicks",
355
- "leads",
356
- "conversions",
357
- "sales",
358
- "saleAmount",
359
- ]
360
- nullable_fields = [
361
- "externalId",
362
- "tenantId",
363
- "programId",
364
- "partnerId",
365
- "expiredUrl",
366
- "password",
367
- "title",
368
- "description",
369
- "image",
370
- "video",
371
- "ios",
372
- "android",
373
- "geo",
374
- "tags",
375
- "folderId",
376
- "comments",
377
- "utm_source",
378
- "utm_medium",
379
- "utm_campaign",
380
- "utm_term",
381
- "utm_content",
382
- "testVariants",
383
- "userId",
384
- "tagId",
385
- ]
386
- null_default_fields = []
387
-
347
+ optional_fields = set(
348
+ ["testVariants", "clicks", "leads", "conversions", "sales", "saleAmount"]
349
+ )
350
+ nullable_fields = set(
351
+ [
352
+ "externalId",
353
+ "tenantId",
354
+ "programId",
355
+ "partnerId",
356
+ "expiredUrl",
357
+ "password",
358
+ "title",
359
+ "description",
360
+ "image",
361
+ "video",
362
+ "ios",
363
+ "android",
364
+ "geo",
365
+ "tags",
366
+ "folderId",
367
+ "comments",
368
+ "utm_source",
369
+ "utm_medium",
370
+ "utm_campaign",
371
+ "utm_term",
372
+ "utm_content",
373
+ "testVariants",
374
+ "userId",
375
+ "tagId",
376
+ ]
377
+ )
388
378
  serialized = handler(self)
389
-
390
379
  m = {}
391
380
 
392
381
  for n, f in type(self).model_fields.items():
393
382
  k = f.alias or n
394
383
  val = serialized.get(k)
395
- serialized.pop(k, None)
396
-
397
- optional_nullable = k in optional_fields and k in nullable_fields
398
- is_set = (
399
- self.__pydantic_fields_set__.intersection({n})
400
- or k in null_default_fields
401
- ) # pylint: disable=no-member
402
-
403
- if val is not None and val != UNSET_SENTINEL:
404
- m[k] = val
405
- elif val != UNSET_SENTINEL and (
406
- not k in optional_fields or (optional_nullable and is_set)
407
- ):
408
- m[k] = val
384
+ is_nullable_and_explicitly_set = (
385
+ k in nullable_fields
386
+ and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
387
+ )
388
+
389
+ if val != UNSET_SENTINEL:
390
+ if (
391
+ val is not None
392
+ or k not in optional_fields
393
+ or is_nullable_and_explicitly_set
394
+ ):
395
+ m[k] = val
409
396
 
410
397
  return m
411
398