growsurf-python 1.16.0__py3-none-any.whl → 1.18.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 (45) hide show
  1. growsurf/_client.py +1 -38
  2. growsurf/_exceptions.py +91 -0
  3. growsurf/_version.py +1 -1
  4. growsurf/resources/__init__.py +0 -14
  5. growsurf/resources/campaign/__init__.py +14 -0
  6. growsurf/resources/campaign/campaign.py +73 -25
  7. growsurf/resources/campaign/custom_domain.py +450 -0
  8. growsurf/resources/campaign/design.py +12 -6
  9. growsurf/resources/campaign/emails.py +4 -4
  10. growsurf/resources/campaign/installation.py +4 -4
  11. growsurf/resources/campaign/options.py +10 -10
  12. growsurf/resources/campaign/participant.py +52 -32
  13. growsurf/resources/campaign/rewards.py +76 -16
  14. growsurf/resources/campaign/webhooks.py +40 -8
  15. growsurf/resources/team.py +34 -2
  16. growsurf/types/__init__.py +0 -2
  17. growsurf/types/campaign/__init__.py +8 -0
  18. growsurf/types/campaign/campaign_custom_domain.py +49 -0
  19. growsurf/types/campaign/campaign_design.py +16 -12
  20. growsurf/types/campaign/campaign_options.py +1 -1
  21. growsurf/types/campaign/custom_domain_set_params.py +15 -0
  22. growsurf/types/campaign/delete_campaign_custom_domain_response.py +13 -0
  23. growsurf/types/campaign/participant.py +25 -64
  24. growsurf/types/campaign/participant_add_params.py +13 -3
  25. growsurf/types/campaign/participant_email_params.py +11 -8
  26. growsurf/types/campaign/participant_get_payout_destination_response.py +8 -5
  27. growsurf/types/campaign/participant_list_referrals_params.py +1 -1
  28. growsurf/types/campaign/participant_request_payout_destination_confirmation_response.py +1 -1
  29. growsurf/types/campaign/reward_create_params.py +26 -6
  30. growsurf/types/campaign/reward_update_params.py +26 -6
  31. growsurf/types/campaign/webhook_create_params.py +11 -1
  32. growsurf/types/campaign_create_mobile_participant_token_params.py +13 -3
  33. growsurf/types/campaign_create_params.py +10 -5
  34. growsurf/types/campaign_list_referrals_params.py +1 -1
  35. growsurf/types/campaign_update_params.py +3 -2
  36. growsurf/types/commission_structure.py +5 -0
  37. growsurf/types/referral_flow_screenshot.py +8 -7
  38. growsurf/types/referral_list.py +12 -0
  39. {growsurf_python-1.16.0.dist-info → growsurf_python-1.18.0.dist-info}/METADATA +1 -1
  40. {growsurf_python-1.16.0.dist-info → growsurf_python-1.18.0.dist-info}/RECORD +42 -41
  41. growsurf/resources/account.py +0 -219
  42. growsurf/types/account_create_params.py +0 -23
  43. growsurf/types/create_account_response.py +0 -29
  44. {growsurf_python-1.16.0.dist-info → growsurf_python-1.18.0.dist-info}/WHEEL +0 -0
  45. {growsurf_python-1.16.0.dist-info → growsurf_python-1.18.0.dist-info}/licenses/LICENSE +0 -0
growsurf/_client.py CHANGED
@@ -36,9 +36,8 @@ from ._base_client import (
36
36
  )
37
37
 
38
38
  if TYPE_CHECKING:
39
- from .resources import team, account, campaign
39
+ from .resources import team, campaign
40
40
  from .resources.team import TeamResource, AsyncTeamResource
41
- from .resources.account import AccountResource, AsyncAccountResource
42
41
  from .resources.campaign.campaign import CampaignResource, AsyncCampaignResource
43
42
 
44
43
  __all__ = [
@@ -116,12 +115,6 @@ class Growsurf(SyncAPIClient):
116
115
  )
117
116
  self._idempotency_header = "Idempotency-Key"
118
117
 
119
- @cached_property
120
- def account(self) -> AccountResource:
121
- from .resources.account import AccountResource
122
-
123
- return AccountResource(self)
124
-
125
118
  @cached_property
126
119
  def team(self) -> TeamResource:
127
120
  from .resources.team import TeamResource
@@ -319,12 +312,6 @@ class AsyncGrowsurf(AsyncAPIClient):
319
312
  )
320
313
  self._idempotency_header = "Idempotency-Key"
321
314
 
322
- @cached_property
323
- def account(self) -> AsyncAccountResource:
324
- from .resources.account import AsyncAccountResource
325
-
326
- return AsyncAccountResource(self)
327
-
328
315
  @cached_property
329
316
  def team(self) -> AsyncTeamResource:
330
317
  from .resources.team import AsyncTeamResource
@@ -465,12 +452,6 @@ class GrowsurfWithRawResponse:
465
452
  def __init__(self, client: Growsurf) -> None:
466
453
  self._client = client
467
454
 
468
- @cached_property
469
- def account(self) -> account.AccountResourceWithRawResponse:
470
- from .resources.account import AccountResourceWithRawResponse
471
-
472
- return AccountResourceWithRawResponse(self._client.account)
473
-
474
455
  @cached_property
475
456
  def team(self) -> team.TeamResourceWithRawResponse:
476
457
  from .resources.team import TeamResourceWithRawResponse
@@ -490,12 +471,6 @@ class AsyncGrowsurfWithRawResponse:
490
471
  def __init__(self, client: AsyncGrowsurf) -> None:
491
472
  self._client = client
492
473
 
493
- @cached_property
494
- def account(self) -> account.AsyncAccountResourceWithRawResponse:
495
- from .resources.account import AsyncAccountResourceWithRawResponse
496
-
497
- return AsyncAccountResourceWithRawResponse(self._client.account)
498
-
499
474
  @cached_property
500
475
  def team(self) -> team.AsyncTeamResourceWithRawResponse:
501
476
  from .resources.team import AsyncTeamResourceWithRawResponse
@@ -515,12 +490,6 @@ class GrowsurfWithStreamedResponse:
515
490
  def __init__(self, client: Growsurf) -> None:
516
491
  self._client = client
517
492
 
518
- @cached_property
519
- def account(self) -> account.AccountResourceWithStreamingResponse:
520
- from .resources.account import AccountResourceWithStreamingResponse
521
-
522
- return AccountResourceWithStreamingResponse(self._client.account)
523
-
524
493
  @cached_property
525
494
  def team(self) -> team.TeamResourceWithStreamingResponse:
526
495
  from .resources.team import TeamResourceWithStreamingResponse
@@ -540,12 +509,6 @@ class AsyncGrowsurfWithStreamedResponse:
540
509
  def __init__(self, client: AsyncGrowsurf) -> None:
541
510
  self._client = client
542
511
 
543
- @cached_property
544
- def account(self) -> account.AsyncAccountResourceWithStreamingResponse:
545
- from .resources.account import AsyncAccountResourceWithStreamingResponse
546
-
547
- return AsyncAccountResourceWithStreamingResponse(self._client.account)
548
-
549
512
  @cached_property
550
513
  def team(self) -> team.AsyncTeamResourceWithStreamingResponse:
551
514
  from .resources.team import AsyncTeamResourceWithStreamingResponse
growsurf/_exceptions.py CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from typing import Dict, List, cast
5
6
  from typing_extensions import Literal
6
7
 
7
8
  import httpx
@@ -60,11 +61,79 @@ class APIStatusError(APIError):
60
61
  response: httpx.Response
61
62
  status_code: int
62
63
 
64
+ # Documented error-body fields. Each is `None` when the body omits it or sends another
65
+ # type; `body` keeps the complete response body, including fields added later.
66
+ error_name: str | None
67
+ """Error name returned for the failed request."""
68
+
69
+ error_code: str | None
70
+ """Stable machine-readable error code."""
71
+
72
+ error_message: str | None
73
+ """Human-readable error message."""
74
+
75
+ errors: List[Dict[str, object]] | None
76
+ """Optional validation details for specific request fields."""
77
+
78
+ support_url: str | None
79
+ """Support URL related to the error, when available."""
80
+
81
+ policy_name: str | None
82
+ """Rate-limit policy name for `429` errors, when available."""
83
+
84
+ level: str | None
85
+ """Error severity level, when available."""
86
+
87
+ timestamp: str | None
88
+ """When the error response was created."""
89
+
90
+ fraud_risk_level: str | None
91
+ """Fraud risk level assigned to the blocked signup."""
92
+
93
+ fraud_reason_code: str | None
94
+ """Machine-readable reason code for the fraud decision."""
95
+
96
+ matched_participant_ids: List[str] | None
97
+ """Existing participant IDs related to the fraud match."""
98
+
99
+ email: str | None
100
+ """Email address from the blocked signup attempt."""
101
+
102
+ referrer_id: str | None
103
+ """Referrer participant ID supplied with the blocked signup, or `null`."""
104
+
105
+ ip_address: str | None
106
+ """IP address supplied with the blocked signup, or `null`."""
107
+
108
+ fingerprint: str | None
109
+ """Browser fingerprint supplied with the blocked signup, or `null`."""
110
+
111
+ blocked_at: str | None
112
+ """When the signup was blocked."""
113
+
63
114
  def __init__(self, message: str, *, response: httpx.Response, body: object | None) -> None:
64
115
  super().__init__(message, response.request, body=body)
65
116
  self.response = response
66
117
  self.status_code = response.status_code
67
118
 
119
+ fields = cast(Dict[str, object], body) if isinstance(body, dict) else {}
120
+ self.error_name = _str_or_none(fields.get("name"))
121
+ self.error_code = _str_or_none(fields.get("code"))
122
+ self.error_message = _str_or_none(fields.get("message"))
123
+ self.errors = _record_list_or_none(fields.get("errors"))
124
+ self.support_url = _str_or_none(fields.get("supportUrl"))
125
+ self.policy_name = _str_or_none(fields.get("policyName"))
126
+ self.level = _str_or_none(fields.get("level"))
127
+ self.timestamp = _str_or_none(fields.get("timestamp"))
128
+ self.fraud_risk_level = _str_or_none(fields.get("fraudRiskLevel"))
129
+ self.fraud_reason_code = _str_or_none(fields.get("fraudReasonCode"))
130
+ self.matched_participant_ids = _str_list_or_none(fields.get("matchedParticipantIds"))
131
+ self.email = _str_or_none(fields.get("email"))
132
+ self.referrer_id = _str_or_none(fields.get("referrerId"))
133
+ self.ip_address = _str_or_none(fields.get("ipAddress"))
134
+ self.fingerprint = _str_or_none(fields.get("fingerprint"))
135
+ self.blocked_at = _str_or_none(fields.get("blockedAt"))
136
+
68
137
 
69
138
  class APIConnectionError(APIError):
70
139
  def __init__(self, *, message: str = "Connection error.", request: httpx.Request) -> None:
@@ -106,3 +175,25 @@ class RateLimitError(APIStatusError):
106
175
 
107
176
  class InternalServerError(APIStatusError):
108
177
  pass
178
+
179
+
180
+ def _str_or_none(value: object) -> str | None:
181
+ return value if isinstance(value, str) else None
182
+
183
+
184
+ def _str_list_or_none(value: object) -> List[str] | None:
185
+ if not isinstance(value, list):
186
+ return None
187
+ items = cast(List[object], value)
188
+ if not all(isinstance(item, str) for item in items):
189
+ return None
190
+ return cast(List[str], items)
191
+
192
+
193
+ def _record_list_or_none(value: object) -> List[Dict[str, object]] | None:
194
+ if not isinstance(value, list):
195
+ return None
196
+ items = cast(List[object], value)
197
+ if not all(isinstance(item, dict) for item in items):
198
+ return None
199
+ return cast(List[Dict[str, object]], items)
growsurf/_version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
3
  __title__ = "growsurf"
4
- __version__ = "1.16.0" # x-release-please-version
4
+ __version__ = "1.18.0" # x-release-please-version
@@ -8,14 +8,6 @@ from .team import (
8
8
  TeamResourceWithStreamingResponse,
9
9
  AsyncTeamResourceWithStreamingResponse,
10
10
  )
11
- from .account import (
12
- AccountResource,
13
- AsyncAccountResource,
14
- AccountResourceWithRawResponse,
15
- AsyncAccountResourceWithRawResponse,
16
- AccountResourceWithStreamingResponse,
17
- AsyncAccountResourceWithStreamingResponse,
18
- )
19
11
  from .campaign import (
20
12
  CampaignResource,
21
13
  AsyncCampaignResource,
@@ -26,12 +18,6 @@ from .campaign import (
26
18
  )
27
19
 
28
20
  __all__ = [
29
- "AccountResource",
30
- "AsyncAccountResource",
31
- "AccountResourceWithRawResponse",
32
- "AsyncAccountResourceWithRawResponse",
33
- "AccountResourceWithStreamingResponse",
34
- "AsyncAccountResourceWithStreamingResponse",
35
21
  "TeamResource",
36
22
  "AsyncTeamResource",
37
23
  "TeamResourceWithRawResponse",
@@ -88,6 +88,14 @@ from .integrations import (
88
88
  IntegrationsResourceWithStreamingResponse,
89
89
  AsyncIntegrationsResourceWithStreamingResponse,
90
90
  )
91
+ from .custom_domain import (
92
+ CustomDomainResource,
93
+ AsyncCustomDomainResource,
94
+ CustomDomainResourceWithRawResponse,
95
+ AsyncCustomDomainResourceWithRawResponse,
96
+ CustomDomainResourceWithStreamingResponse,
97
+ AsyncCustomDomainResourceWithStreamingResponse,
98
+ )
91
99
  from .program_resources import (
92
100
  ProgramResourcesResource,
93
101
  AsyncProgramResourcesResource,
@@ -158,6 +166,12 @@ __all__ = [
158
166
  "AsyncInstallationResourceWithRawResponse",
159
167
  "InstallationResourceWithStreamingResponse",
160
168
  "AsyncInstallationResourceWithStreamingResponse",
169
+ "CustomDomainResource",
170
+ "AsyncCustomDomainResource",
171
+ "CustomDomainResourceWithRawResponse",
172
+ "AsyncCustomDomainResourceWithRawResponse",
173
+ "CustomDomainResourceWithStreamingResponse",
174
+ "AsyncCustomDomainResourceWithStreamingResponse",
161
175
  "CommissionResource",
162
176
  "AsyncCommissionResource",
163
177
  "CommissionResourceWithRawResponse",
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Dict, Iterable
5
+ from typing import Dict, Iterable, Optional
6
6
  from typing_extensions import Literal
7
7
 
8
8
  import httpx
@@ -113,6 +113,14 @@ from .integrations import (
113
113
  IntegrationsResourceWithStreamingResponse,
114
114
  AsyncIntegrationsResourceWithStreamingResponse,
115
115
  )
116
+ from .custom_domain import (
117
+ CustomDomainResource,
118
+ AsyncCustomDomainResource,
119
+ CustomDomainResourceWithRawResponse,
120
+ AsyncCustomDomainResourceWithRawResponse,
121
+ CustomDomainResourceWithStreamingResponse,
122
+ AsyncCustomDomainResourceWithStreamingResponse,
123
+ )
116
124
  from ..._base_client import make_request_options
117
125
  from ...types.campaign import ReferralStatus, reward_create_params
118
126
  from .program_resources import (
@@ -197,6 +205,11 @@ class CampaignResource(SyncAPIResource):
197
205
  """Campaign installation (`CampaignInstallation`) — the Program Editor's Installation tab."""
198
206
  return InstallationResource(self._client)
199
207
 
208
+ @cached_property
209
+ def custom_domain(self) -> CustomDomainResource:
210
+ """Campaign custom domain (`CampaignCustomDomain`) — the domain that serves a program's landing pages."""
211
+ return CustomDomainResource(self._client)
212
+
200
213
  @cached_property
201
214
  def with_raw_response(self) -> CampaignResourceWithRawResponse:
202
215
  """
@@ -220,8 +233,8 @@ class CampaignResource(SyncAPIResource):
220
233
  self,
221
234
  *,
222
235
  type: Literal["REFERRAL", "AFFILIATE"],
223
- company_logo_image_url: str | Omit = omit,
224
- company_name: str | Omit = omit,
236
+ company_logo_image_url: Optional[str] | Omit = omit,
237
+ company_name: Optional[str] | Omit = omit,
225
238
  currency_iso: str | Omit = omit,
226
239
  goal: Literal[
227
240
  "CUSTOMERS",
@@ -329,8 +342,8 @@ class CampaignResource(SyncAPIResource):
329
342
  self,
330
343
  id: str,
331
344
  *,
332
- company_logo_image_url: str | Omit = omit,
333
- company_name: str | Omit = omit,
345
+ company_logo_image_url: Optional[str] | Omit = omit,
346
+ company_name: Optional[str] | Omit = omit,
334
347
  name: str | Omit = omit,
335
348
  status: Literal["IN_PROGRESS", "COMPLETE"] | Omit = omit,
336
349
  # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -347,8 +360,8 @@ class CampaignResource(SyncAPIResource):
347
360
  dedicated config sub-resources, not here. The program cannot be deleted via this
348
361
  endpoint.
349
362
  Changes to participant email content are checked before saving. Rejected content returns
350
- `400`; if the check is unavailable, `503` asks you to retry. Neither response saves the
351
- change. A concurrent edit can return `409`; reload the program before retrying.
363
+ `400` and is not saved. A concurrent edit can return `409`; reload the program before
364
+ retrying.
352
365
 
353
366
  Args:
354
367
  status: The requested program status. `IN_PROGRESS` publishes or resumes the program;
@@ -449,6 +462,7 @@ class CampaignResource(SyncAPIResource):
449
462
  metadata: Dict[str, object] | Omit = omit,
450
463
  mobile_instance_id: str | Omit = omit,
451
464
  referral_status: Literal["CREDIT_PENDING", "CREDIT_AWARDED"] | Omit = omit,
465
+ referred_at: Optional[int] | Omit = omit,
452
466
  referred_by: str | Omit = omit,
453
467
  # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
454
468
  # The extra values given here take precedence over values defined on the client or passed to this method.
@@ -472,8 +486,14 @@ class CampaignResource(SyncAPIResource):
472
486
 
473
487
  is_affiliate: Affiliate programs only. Controls affiliate enrollment for a new participant.
474
488
 
475
- language: The language of the participant's portal and program emails. Must be one of the
476
- program's languages. Applied only when this request creates the participant.
489
+ language: The language of the participant's portal and program emails. Stored when it is one of
490
+ the program's languages. A regional tag maps to its language (for example, `es-MX` is
491
+ stored as `es`). Any other value is ignored and the program's base language applies.
492
+ Applied only when this request creates the participant.
493
+
494
+ referred_at: When the participant was referred, in Unix milliseconds. Used only with a valid
495
+ `referredBy`. If you omit `referralStatus`, GrowSurf compares this time with the
496
+ program's referral credit window to set it. Defaults to the time of the request.
477
497
 
478
498
  referred_by: Referrer participant ID or email address.
479
499
 
@@ -501,6 +521,7 @@ class CampaignResource(SyncAPIResource):
501
521
  "metadata": metadata,
502
522
  "mobile_instance_id": mobile_instance_id,
503
523
  "referral_status": referral_status,
524
+ "referred_at": referred_at,
504
525
  "referred_by": referred_by,
505
526
  },
506
527
  campaign_create_mobile_participant_token_params.CampaignCreateMobileParticipantTokenParams,
@@ -793,10 +814,7 @@ class CampaignResource(SyncAPIResource):
793
814
  next_id: str | Omit = omit,
794
815
  offset: int | Omit = omit,
795
816
  referral_status: ReferralStatus | Omit = omit,
796
- sort_by: Literal[
797
- "updatedAt", "createdAt", "email", "firstName", "lastName", "referralStatus", "referralTriggeredAt"
798
- ]
799
- | Omit = omit,
817
+ sort_by: Literal["updatedAt", "createdAt", "email", "referralTriggeredAt"] | Omit = omit,
800
818
  # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
801
819
  # The extra values given here take precedence over values defined on the client or passed to this method.
802
820
  extra_headers: Headers | None = None,
@@ -1432,6 +1450,11 @@ class AsyncCampaignResource(AsyncAPIResource):
1432
1450
  """Campaign installation (`CampaignInstallation`) — the Program Editor's Installation tab."""
1433
1451
  return AsyncInstallationResource(self._client)
1434
1452
 
1453
+ @cached_property
1454
+ def custom_domain(self) -> AsyncCustomDomainResource:
1455
+ """Campaign custom domain (`CampaignCustomDomain`) — the domain that serves a program's landing pages."""
1456
+ return AsyncCustomDomainResource(self._client)
1457
+
1435
1458
  @cached_property
1436
1459
  def with_raw_response(self) -> AsyncCampaignResourceWithRawResponse:
1437
1460
  """
@@ -1455,8 +1478,8 @@ class AsyncCampaignResource(AsyncAPIResource):
1455
1478
  self,
1456
1479
  *,
1457
1480
  type: Literal["REFERRAL", "AFFILIATE"],
1458
- company_logo_image_url: str | Omit = omit,
1459
- company_name: str | Omit = omit,
1481
+ company_logo_image_url: Optional[str] | Omit = omit,
1482
+ company_name: Optional[str] | Omit = omit,
1460
1483
  currency_iso: str | Omit = omit,
1461
1484
  goal: Literal[
1462
1485
  "CUSTOMERS",
@@ -1564,8 +1587,8 @@ class AsyncCampaignResource(AsyncAPIResource):
1564
1587
  self,
1565
1588
  id: str,
1566
1589
  *,
1567
- company_logo_image_url: str | Omit = omit,
1568
- company_name: str | Omit = omit,
1590
+ company_logo_image_url: Optional[str] | Omit = omit,
1591
+ company_name: Optional[str] | Omit = omit,
1569
1592
  name: str | Omit = omit,
1570
1593
  status: Literal["IN_PROGRESS", "COMPLETE"] | Omit = omit,
1571
1594
  # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -1582,8 +1605,8 @@ class AsyncCampaignResource(AsyncAPIResource):
1582
1605
  dedicated config sub-resources, not here. The program cannot be deleted via this
1583
1606
  endpoint.
1584
1607
  Changes to participant email content are checked before saving. Rejected content returns
1585
- `400`; if the check is unavailable, `503` asks you to retry. Neither response saves the
1586
- change. A concurrent edit can return `409`; reload the program before retrying.
1608
+ `400` and is not saved. A concurrent edit can return `409`; reload the program before
1609
+ retrying.
1587
1610
 
1588
1611
  Args:
1589
1612
  status: The requested program status. `IN_PROGRESS` publishes or resumes the program;
@@ -1684,6 +1707,7 @@ class AsyncCampaignResource(AsyncAPIResource):
1684
1707
  metadata: Dict[str, object] | Omit = omit,
1685
1708
  mobile_instance_id: str | Omit = omit,
1686
1709
  referral_status: Literal["CREDIT_PENDING", "CREDIT_AWARDED"] | Omit = omit,
1710
+ referred_at: Optional[int] | Omit = omit,
1687
1711
  referred_by: str | Omit = omit,
1688
1712
  # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
1689
1713
  # The extra values given here take precedence over values defined on the client or passed to this method.
@@ -1707,8 +1731,14 @@ class AsyncCampaignResource(AsyncAPIResource):
1707
1731
 
1708
1732
  is_affiliate: Affiliate programs only. Controls affiliate enrollment for a new participant.
1709
1733
 
1710
- language: The language of the participant's portal and program emails. Must be one of the
1711
- program's languages. Applied only when this request creates the participant.
1734
+ language: The language of the participant's portal and program emails. Stored when it is one of
1735
+ the program's languages. A regional tag maps to its language (for example, `es-MX` is
1736
+ stored as `es`). Any other value is ignored and the program's base language applies.
1737
+ Applied only when this request creates the participant.
1738
+
1739
+ referred_at: When the participant was referred, in Unix milliseconds. Used only with a valid
1740
+ `referredBy`. If you omit `referralStatus`, GrowSurf compares this time with the
1741
+ program's referral credit window to set it. Defaults to the time of the request.
1712
1742
 
1713
1743
  referred_by: Referrer participant ID or email address.
1714
1744
 
@@ -1736,6 +1766,7 @@ class AsyncCampaignResource(AsyncAPIResource):
1736
1766
  "metadata": metadata,
1737
1767
  "mobile_instance_id": mobile_instance_id,
1738
1768
  "referral_status": referral_status,
1769
+ "referred_at": referred_at,
1739
1770
  "referred_by": referred_by,
1740
1771
  },
1741
1772
  campaign_create_mobile_participant_token_params.CampaignCreateMobileParticipantTokenParams,
@@ -2028,10 +2059,7 @@ class AsyncCampaignResource(AsyncAPIResource):
2028
2059
  next_id: str | Omit = omit,
2029
2060
  offset: int | Omit = omit,
2030
2061
  referral_status: ReferralStatus | Omit = omit,
2031
- sort_by: Literal[
2032
- "updatedAt", "createdAt", "email", "firstName", "lastName", "referralStatus", "referralTriggeredAt"
2033
- ]
2034
- | Omit = omit,
2062
+ sort_by: Literal["updatedAt", "createdAt", "email", "referralTriggeredAt"] | Omit = omit,
2035
2063
  # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
2036
2064
  # The extra values given here take precedence over values defined on the client or passed to this method.
2037
2065
  extra_headers: Headers | None = None,
@@ -2734,6 +2762,11 @@ class CampaignResourceWithRawResponse:
2734
2762
  """Campaign installation (`CampaignInstallation`) — the Program Editor's Installation tab."""
2735
2763
  return InstallationResourceWithRawResponse(self._campaign.installation)
2736
2764
 
2765
+ @cached_property
2766
+ def custom_domain(self) -> CustomDomainResourceWithRawResponse:
2767
+ """Campaign custom domain (`CampaignCustomDomain`) — the domain that serves a program's landing pages."""
2768
+ return CustomDomainResourceWithRawResponse(self._campaign.custom_domain)
2769
+
2737
2770
 
2738
2771
  class AsyncCampaignResourceWithRawResponse:
2739
2772
  def __init__(self, campaign: AsyncCampaignResource) -> None:
@@ -2856,6 +2889,11 @@ class AsyncCampaignResourceWithRawResponse:
2856
2889
  """Campaign installation (`CampaignInstallation`) — the Program Editor's Installation tab."""
2857
2890
  return AsyncInstallationResourceWithRawResponse(self._campaign.installation)
2858
2891
 
2892
+ @cached_property
2893
+ def custom_domain(self) -> AsyncCustomDomainResourceWithRawResponse:
2894
+ """Campaign custom domain (`CampaignCustomDomain`) — the domain that serves a program's landing pages."""
2895
+ return AsyncCustomDomainResourceWithRawResponse(self._campaign.custom_domain)
2896
+
2859
2897
 
2860
2898
  class CampaignResourceWithStreamingResponse:
2861
2899
  def __init__(self, campaign: CampaignResource) -> None:
@@ -2978,6 +3016,11 @@ class CampaignResourceWithStreamingResponse:
2978
3016
  """Campaign installation (`CampaignInstallation`) — the Program Editor's Installation tab."""
2979
3017
  return InstallationResourceWithStreamingResponse(self._campaign.installation)
2980
3018
 
3019
+ @cached_property
3020
+ def custom_domain(self) -> CustomDomainResourceWithStreamingResponse:
3021
+ """Campaign custom domain (`CampaignCustomDomain`) — the domain that serves a program's landing pages."""
3022
+ return CustomDomainResourceWithStreamingResponse(self._campaign.custom_domain)
3023
+
2981
3024
 
2982
3025
  class AsyncCampaignResourceWithStreamingResponse:
2983
3026
  def __init__(self, campaign: AsyncCampaignResource) -> None:
@@ -3099,3 +3142,8 @@ class AsyncCampaignResourceWithStreamingResponse:
3099
3142
  def installation(self) -> AsyncInstallationResourceWithStreamingResponse:
3100
3143
  """Campaign installation (`CampaignInstallation`) — the Program Editor's Installation tab."""
3101
3144
  return AsyncInstallationResourceWithStreamingResponse(self._campaign.installation)
3145
+
3146
+ @cached_property
3147
+ def custom_domain(self) -> AsyncCustomDomainResourceWithStreamingResponse:
3148
+ """Campaign custom domain (`CampaignCustomDomain`) — the domain that serves a program's landing pages."""
3149
+ return AsyncCustomDomainResourceWithStreamingResponse(self._campaign.custom_domain)