diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eefc48e..7234cce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,14 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'stl-preview-head/**' - - 'stl-preview-base/**' + branches: + - '**' + - '!integrated/**' + - '!stl-preview-head/**' + - '!stl-preview-base/**' + - '!generated' + - '!codegen/**' + - 'codegen/stl/**' pull_request: branches-ignore: - 'stl-preview-head/**' diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 09a565d..9682ed8 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.0.34" + ".": "0.0.35" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index d46615a..c2e464b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 181 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/frostedinc%2Fwhopsdk-b6e1387ac58f903f887eae989de30273824663a9a752e7834b82b1036950c3d2.yml -openapi_spec_hash: 0bea29a304f3d57c44cc186478bef054 -config_hash: 7e9d4f2abf58b7918a0e103387d2a2e9 +configured_endpoints: 191 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/frostedinc%2Fwhopsdk-97e920db587b07c064bef1bf31de5e110a3750ddfddc8fca26642e79e6b827f8.yml +openapi_spec_hash: 97ca16cc55271602443a4329d1e02895 +config_hash: 1a836d20bb988f001cc66d1526f71306 diff --git a/CHANGELOG.md b/CHANGELOG.md index 763b2f1..0c02743 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## 0.0.35 (2026-03-18) + +Full Changelog: [v0.0.34...v0.0.35](https://github.com/whopio/whopsdk-python/compare/v0.0.34...v0.0.35) + +### Features + +* **api:** api update ([8a74bd2](https://github.com/whopio/whopsdk-python/commit/8a74bd28a45ae766a17d696a405ec2dcd5f4918a)) +* **api:** api update ([c9dd73f](https://github.com/whopio/whopsdk-python/commit/c9dd73fece709c673b37575a2e1e82ca9643f7d9)) +* **api:** api update ([41811c0](https://github.com/whopio/whopsdk-python/commit/41811c0aec1d7d07b0e7450c810a2b2e5ca03fcb)) +* **api:** manual updates ([9506c84](https://github.com/whopio/whopsdk-python/commit/9506c84dd2836cf9b150e999840b79d82517046f)) + + +### Bug Fixes + +* **deps:** bump minimum typing-extensions version ([52face0](https://github.com/whopio/whopsdk-python/commit/52face04bba526f4c009caa1dcc390d84da60840)) +* **pydantic:** do not pass `by_alias` unless set ([23cb493](https://github.com/whopio/whopsdk-python/commit/23cb4936ab4f00829d98f0a910e26f2ae26e5398)) + + +### Chores + +* **internal:** tweak CI branches ([ca6b4cd](https://github.com/whopio/whopsdk-python/commit/ca6b4cd8b46e7de115b37c833da3c40f87ca779a)) + ## 0.0.34 (2026-03-13) Full Changelog: [v0.0.33...v0.0.34](https://github.com/whopio/whopsdk-python/compare/v0.0.33...v0.0.34) diff --git a/api.md b/api.md index bf78cc0..60f2181 100644 --- a/api.md +++ b/api.md @@ -849,7 +849,7 @@ Methods: Types: ```python -from whop_sdk.types import AIChat, AIChatListResponse, AIChatDeleteResponse +from whop_sdk.types import AIChat, NotificationPreferences, AIChatListResponse, AIChatDeleteResponse ``` Methods: @@ -921,3 +921,52 @@ from whop_sdk.types import PayoutAccountCalculatedStatuses, PayoutAccountRetriev Methods: - client.payout_accounts.retrieve(id) -> PayoutAccountRetrieveResponse + +# Affiliates + +Types: + +```python +from whop_sdk.types import ( + Affiliate, + Status, + AffiliateListResponse, + AffiliateArchiveResponse, + AffiliateUnarchiveResponse, +) +``` + +Methods: + +- client.affiliates.create(\*\*params) -> Affiliate +- client.affiliates.retrieve(id) -> Affiliate +- client.affiliates.list(\*\*params) -> SyncCursorPage[AffiliateListResponse] +- client.affiliates.archive(id) -> AffiliateArchiveResponse +- client.affiliates.unarchive(id) -> AffiliateUnarchiveResponse + +## Overrides + +Types: + +```python +from whop_sdk.types.affiliates import ( + AffiliateAppliesToPayments, + AffiliateAppliesToProducts, + AffiliateOverrideRoles, + AffiliatePayoutTypes, + AffiliateRevenueBases, + OverrideCreateResponse, + OverrideRetrieveResponse, + OverrideUpdateResponse, + OverrideListResponse, + OverrideDeleteResponse, +) +``` + +Methods: + +- client.affiliates.overrides.create(path_id, \*\*params) -> OverrideCreateResponse +- client.affiliates.overrides.retrieve(override_id, \*, id) -> OverrideRetrieveResponse +- client.affiliates.overrides.update(override_id, \*, id, \*\*params) -> OverrideUpdateResponse +- client.affiliates.overrides.list(id, \*\*params) -> SyncCursorPage[OverrideListResponse] +- client.affiliates.overrides.delete(override_id, \*, id) -> OverrideDeleteResponse diff --git a/pyproject.toml b/pyproject.toml index 6d34f6e..062c3d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "whop-sdk" -version = "0.0.34" +version = "0.0.35" description = "The official Python library for the Whop API" dynamic = ["readme"] license = "Apache-2.0" @@ -11,7 +11,7 @@ authors = [ dependencies = [ "httpx>=0.23.0, <1", "pydantic>=1.9.0, <3", - "typing-extensions>=4.10, <5", + "typing-extensions>=4.14, <5", "anyio>=3.5.0, <5", "distro>=1.7.0, <2", "sniffio", diff --git a/src/whop_sdk/_client.py b/src/whop_sdk/_client.py index 0f28664..98fa7ac 100644 --- a/src/whop_sdk/_client.py +++ b/src/whop_sdk/_client.py @@ -55,6 +55,7 @@ reactions, shipments, transfers, + affiliates, app_builds, dm_members, dm_channels, @@ -133,6 +134,7 @@ from .resources.payout_accounts import PayoutAccountsResource, AsyncPayoutAccountsResource from .resources.authorized_users import AuthorizedUsersResource, AsyncAuthorizedUsersResource from .resources.support_channels import SupportChannelsResource, AsyncSupportChannelsResource + from .resources.affiliates.affiliates import AffiliatesResource, AsyncAffiliatesResource from .resources.checkout_configurations import CheckoutConfigurationsResource, AsyncCheckoutConfigurationsResource from .resources.resolution_center_cases import ResolutionCenterCasesResource, AsyncResolutionCenterCasesResource from .resources.company_token_transactions import ( @@ -531,6 +533,13 @@ def payout_accounts(self) -> PayoutAccountsResource: return PayoutAccountsResource(self) + @cached_property + def affiliates(self) -> AffiliatesResource: + """Affiliates""" + from .resources.affiliates import AffiliatesResource + + return AffiliatesResource(self) + @cached_property def with_raw_response(self) -> WhopWithRawResponse: return WhopWithRawResponse(self) @@ -1033,6 +1042,13 @@ def payout_accounts(self) -> AsyncPayoutAccountsResource: return AsyncPayoutAccountsResource(self) + @cached_property + def affiliates(self) -> AsyncAffiliatesResource: + """Affiliates""" + from .resources.affiliates import AsyncAffiliatesResource + + return AsyncAffiliatesResource(self) + @cached_property def with_raw_response(self) -> AsyncWhopWithRawResponse: return AsyncWhopWithRawResponse(self) @@ -1471,6 +1487,13 @@ def payout_accounts(self) -> payout_accounts.PayoutAccountsResourceWithRawRespon return PayoutAccountsResourceWithRawResponse(self._client.payout_accounts) + @cached_property + def affiliates(self) -> affiliates.AffiliatesResourceWithRawResponse: + """Affiliates""" + from .resources.affiliates import AffiliatesResourceWithRawResponse + + return AffiliatesResourceWithRawResponse(self._client.affiliates) + class AsyncWhopWithRawResponse: _client: AsyncWhop @@ -1796,6 +1819,13 @@ def payout_accounts(self) -> payout_accounts.AsyncPayoutAccountsResourceWithRawR return AsyncPayoutAccountsResourceWithRawResponse(self._client.payout_accounts) + @cached_property + def affiliates(self) -> affiliates.AsyncAffiliatesResourceWithRawResponse: + """Affiliates""" + from .resources.affiliates import AsyncAffiliatesResourceWithRawResponse + + return AsyncAffiliatesResourceWithRawResponse(self._client.affiliates) + class WhopWithStreamedResponse: _client: Whop @@ -2121,6 +2151,13 @@ def payout_accounts(self) -> payout_accounts.PayoutAccountsResourceWithStreaming return PayoutAccountsResourceWithStreamingResponse(self._client.payout_accounts) + @cached_property + def affiliates(self) -> affiliates.AffiliatesResourceWithStreamingResponse: + """Affiliates""" + from .resources.affiliates import AffiliatesResourceWithStreamingResponse + + return AffiliatesResourceWithStreamingResponse(self._client.affiliates) + class AsyncWhopWithStreamedResponse: _client: AsyncWhop @@ -2450,6 +2487,13 @@ def payout_accounts(self) -> payout_accounts.AsyncPayoutAccountsResourceWithStre return AsyncPayoutAccountsResourceWithStreamingResponse(self._client.payout_accounts) + @cached_property + def affiliates(self) -> affiliates.AsyncAffiliatesResourceWithStreamingResponse: + """Affiliates""" + from .resources.affiliates import AsyncAffiliatesResourceWithStreamingResponse + + return AsyncAffiliatesResourceWithStreamingResponse(self._client.affiliates) + Client = Whop diff --git a/src/whop_sdk/_compat.py b/src/whop_sdk/_compat.py index 786ff42..e6690a4 100644 --- a/src/whop_sdk/_compat.py +++ b/src/whop_sdk/_compat.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload from datetime import date, datetime -from typing_extensions import Self, Literal +from typing_extensions import Self, Literal, TypedDict import pydantic from pydantic.fields import FieldInfo @@ -131,6 +131,10 @@ def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: return model.model_dump_json(indent=indent) +class _ModelDumpKwargs(TypedDict, total=False): + by_alias: bool + + def model_dump( model: pydantic.BaseModel, *, @@ -142,6 +146,9 @@ def model_dump( by_alias: bool | None = None, ) -> dict[str, Any]: if (not PYDANTIC_V1) or hasattr(model, "model_dump"): + kwargs: _ModelDumpKwargs = {} + if by_alias is not None: + kwargs["by_alias"] = by_alias return model.model_dump( mode=mode, exclude=exclude, @@ -149,7 +156,7 @@ def model_dump( exclude_defaults=exclude_defaults, # warnings are not supported in Pydantic v1 warnings=True if PYDANTIC_V1 else warnings, - by_alias=by_alias, + **kwargs, ) return cast( "dict[str, Any]", diff --git a/src/whop_sdk/_version.py b/src/whop_sdk/_version.py index 75c990c..057036e 100644 --- a/src/whop_sdk/_version.py +++ b/src/whop_sdk/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "whop_sdk" -__version__ = "0.0.34" # x-release-please-version +__version__ = "0.0.35" # x-release-please-version diff --git a/src/whop_sdk/resources/__init__.py b/src/whop_sdk/resources/__init__.py index 9d6f232..e95bf53 100644 --- a/src/whop_sdk/resources/__init__.py +++ b/src/whop_sdk/resources/__init__.py @@ -184,6 +184,14 @@ TransfersResourceWithStreamingResponse, AsyncTransfersResourceWithStreamingResponse, ) +from .affiliates import ( + AffiliatesResource, + AsyncAffiliatesResource, + AffiliatesResourceWithRawResponse, + AsyncAffiliatesResourceWithRawResponse, + AffiliatesResourceWithStreamingResponse, + AsyncAffiliatesResourceWithStreamingResponse, +) from .app_builds import ( AppBuildsResource, AsyncAppBuildsResource, @@ -730,4 +738,10 @@ "AsyncPayoutAccountsResourceWithRawResponse", "PayoutAccountsResourceWithStreamingResponse", "AsyncPayoutAccountsResourceWithStreamingResponse", + "AffiliatesResource", + "AsyncAffiliatesResource", + "AffiliatesResourceWithRawResponse", + "AsyncAffiliatesResourceWithRawResponse", + "AffiliatesResourceWithStreamingResponse", + "AsyncAffiliatesResourceWithStreamingResponse", ] diff --git a/src/whop_sdk/resources/affiliates/__init__.py b/src/whop_sdk/resources/affiliates/__init__.py new file mode 100644 index 0000000..b533807 --- /dev/null +++ b/src/whop_sdk/resources/affiliates/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .overrides import ( + OverridesResource, + AsyncOverridesResource, + OverridesResourceWithRawResponse, + AsyncOverridesResourceWithRawResponse, + OverridesResourceWithStreamingResponse, + AsyncOverridesResourceWithStreamingResponse, +) +from .affiliates import ( + AffiliatesResource, + AsyncAffiliatesResource, + AffiliatesResourceWithRawResponse, + AsyncAffiliatesResourceWithRawResponse, + AffiliatesResourceWithStreamingResponse, + AsyncAffiliatesResourceWithStreamingResponse, +) + +__all__ = [ + "OverridesResource", + "AsyncOverridesResource", + "OverridesResourceWithRawResponse", + "AsyncOverridesResourceWithRawResponse", + "OverridesResourceWithStreamingResponse", + "AsyncOverridesResourceWithStreamingResponse", + "AffiliatesResource", + "AsyncAffiliatesResource", + "AffiliatesResourceWithRawResponse", + "AsyncAffiliatesResourceWithRawResponse", + "AffiliatesResourceWithStreamingResponse", + "AsyncAffiliatesResourceWithStreamingResponse", +] diff --git a/src/whop_sdk/resources/affiliates/affiliates.py b/src/whop_sdk/resources/affiliates/affiliates.py new file mode 100644 index 0000000..2c184de --- /dev/null +++ b/src/whop_sdk/resources/affiliates/affiliates.py @@ -0,0 +1,674 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ...types import Status, affiliate_list_params, affiliate_create_params +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from .overrides import ( + OverridesResource, + AsyncOverridesResource, + OverridesResourceWithRawResponse, + AsyncOverridesResourceWithRawResponse, + OverridesResourceWithStreamingResponse, + AsyncOverridesResourceWithStreamingResponse, +) +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncCursorPage, AsyncCursorPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.status import Status +from ...types.affiliate import Affiliate +from ...types.shared.direction import Direction +from ...types.affiliate_list_response import AffiliateListResponse +from ...types.affiliate_archive_response import AffiliateArchiveResponse +from ...types.affiliate_unarchive_response import AffiliateUnarchiveResponse + +__all__ = ["AffiliatesResource", "AsyncAffiliatesResource"] + + +class AffiliatesResource(SyncAPIResource): + """Affiliates""" + + @cached_property + def overrides(self) -> OverridesResource: + """Affiliates""" + return OverridesResource(self._client) + + @cached_property + def with_raw_response(self) -> AffiliatesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/whopio/whopsdk-python#accessing-raw-response-data-eg-headers + """ + return AffiliatesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AffiliatesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/whopio/whopsdk-python#with_streaming_response + """ + return AffiliatesResourceWithStreamingResponse(self) + + def create( + self, + *, + company_id: str, + user_identifier: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Affiliate: + """ + Creates or finds an affiliate for a company and user. + + Required permissions: + + - `affiliate:create` + + Args: + company_id: The ID of the company to create the affiliate for. + + user_identifier: The user identifier (username, email, user ID, or Discord ID). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/affiliates", + body=maybe_transform( + { + "company_id": company_id, + "user_identifier": user_identifier, + }, + affiliate_create_params.AffiliateCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Affiliate, + ) + + def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Affiliate: + """ + Retrieves the details of an existing affiliate. + + Required permissions: + + - `affiliate:basic:read` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + f"/affiliates/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Affiliate, + ) + + def list( + self, + *, + company_id: str, + after: Optional[str] | Omit = omit, + before: Optional[str] | Omit = omit, + direction: Optional[Direction] | Omit = omit, + first: Optional[int] | Omit = omit, + last: Optional[int] | Omit = omit, + order: Optional[Literal["id", "created_at", "cached_total_referrals", "cached_total_rewards"]] | Omit = omit, + query: Optional[str] | Omit = omit, + status: Optional[Status] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[AffiliateListResponse]: + """ + Returns a paginated list of affiliates for the actor in context, with optional + filtering by status, search, and sorting. + + Required permissions: + + - `affiliate:basic:read` + + Args: + company_id: The unique identifier of the company to list affiliates for. + + after: Returns the elements in the list that come after the specified cursor. + + before: Returns the elements in the list that come before the specified cursor. + + direction: The direction of the sort. + + first: Returns the first _n_ elements from the list. + + last: Returns the last _n_ elements from the list. + + order: Which columns can be used to sort. + + query: Search affiliates by username. + + status: Statuses for resources + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/affiliates", + page=SyncCursorPage[AffiliateListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "company_id": company_id, + "after": after, + "before": before, + "direction": direction, + "first": first, + "last": last, + "order": order, + "query": query, + "status": status, + }, + affiliate_list_params.AffiliateListParams, + ), + ), + model=AffiliateListResponse, + ) + + def archive( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AffiliateArchiveResponse: + """ + Archives an existing Affiliate + + Required permissions: + + - `affiliate:update` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + f"/affiliates/{id}/archive", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AffiliateArchiveResponse, + ) + + def unarchive( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AffiliateUnarchiveResponse: + """ + Unarchives an existing Affiliate + + Required permissions: + + - `affiliate:update` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + f"/affiliates/{id}/unarchive", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AffiliateUnarchiveResponse, + ) + + +class AsyncAffiliatesResource(AsyncAPIResource): + """Affiliates""" + + @cached_property + def overrides(self) -> AsyncOverridesResource: + """Affiliates""" + return AsyncOverridesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncAffiliatesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/whopio/whopsdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncAffiliatesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAffiliatesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/whopio/whopsdk-python#with_streaming_response + """ + return AsyncAffiliatesResourceWithStreamingResponse(self) + + async def create( + self, + *, + company_id: str, + user_identifier: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Affiliate: + """ + Creates or finds an affiliate for a company and user. + + Required permissions: + + - `affiliate:create` + + Args: + company_id: The ID of the company to create the affiliate for. + + user_identifier: The user identifier (username, email, user ID, or Discord ID). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/affiliates", + body=await async_maybe_transform( + { + "company_id": company_id, + "user_identifier": user_identifier, + }, + affiliate_create_params.AffiliateCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Affiliate, + ) + + async def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Affiliate: + """ + Retrieves the details of an existing affiliate. + + Required permissions: + + - `affiliate:basic:read` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + f"/affiliates/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Affiliate, + ) + + def list( + self, + *, + company_id: str, + after: Optional[str] | Omit = omit, + before: Optional[str] | Omit = omit, + direction: Optional[Direction] | Omit = omit, + first: Optional[int] | Omit = omit, + last: Optional[int] | Omit = omit, + order: Optional[Literal["id", "created_at", "cached_total_referrals", "cached_total_rewards"]] | Omit = omit, + query: Optional[str] | Omit = omit, + status: Optional[Status] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[AffiliateListResponse, AsyncCursorPage[AffiliateListResponse]]: + """ + Returns a paginated list of affiliates for the actor in context, with optional + filtering by status, search, and sorting. + + Required permissions: + + - `affiliate:basic:read` + + Args: + company_id: The unique identifier of the company to list affiliates for. + + after: Returns the elements in the list that come after the specified cursor. + + before: Returns the elements in the list that come before the specified cursor. + + direction: The direction of the sort. + + first: Returns the first _n_ elements from the list. + + last: Returns the last _n_ elements from the list. + + order: Which columns can be used to sort. + + query: Search affiliates by username. + + status: Statuses for resources + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/affiliates", + page=AsyncCursorPage[AffiliateListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "company_id": company_id, + "after": after, + "before": before, + "direction": direction, + "first": first, + "last": last, + "order": order, + "query": query, + "status": status, + }, + affiliate_list_params.AffiliateListParams, + ), + ), + model=AffiliateListResponse, + ) + + async def archive( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AffiliateArchiveResponse: + """ + Archives an existing Affiliate + + Required permissions: + + - `affiliate:update` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + f"/affiliates/{id}/archive", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AffiliateArchiveResponse, + ) + + async def unarchive( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AffiliateUnarchiveResponse: + """ + Unarchives an existing Affiliate + + Required permissions: + + - `affiliate:update` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + f"/affiliates/{id}/unarchive", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AffiliateUnarchiveResponse, + ) + + +class AffiliatesResourceWithRawResponse: + def __init__(self, affiliates: AffiliatesResource) -> None: + self._affiliates = affiliates + + self.create = to_raw_response_wrapper( + affiliates.create, + ) + self.retrieve = to_raw_response_wrapper( + affiliates.retrieve, + ) + self.list = to_raw_response_wrapper( + affiliates.list, + ) + self.archive = to_raw_response_wrapper( + affiliates.archive, + ) + self.unarchive = to_raw_response_wrapper( + affiliates.unarchive, + ) + + @cached_property + def overrides(self) -> OverridesResourceWithRawResponse: + """Affiliates""" + return OverridesResourceWithRawResponse(self._affiliates.overrides) + + +class AsyncAffiliatesResourceWithRawResponse: + def __init__(self, affiliates: AsyncAffiliatesResource) -> None: + self._affiliates = affiliates + + self.create = async_to_raw_response_wrapper( + affiliates.create, + ) + self.retrieve = async_to_raw_response_wrapper( + affiliates.retrieve, + ) + self.list = async_to_raw_response_wrapper( + affiliates.list, + ) + self.archive = async_to_raw_response_wrapper( + affiliates.archive, + ) + self.unarchive = async_to_raw_response_wrapper( + affiliates.unarchive, + ) + + @cached_property + def overrides(self) -> AsyncOverridesResourceWithRawResponse: + """Affiliates""" + return AsyncOverridesResourceWithRawResponse(self._affiliates.overrides) + + +class AffiliatesResourceWithStreamingResponse: + def __init__(self, affiliates: AffiliatesResource) -> None: + self._affiliates = affiliates + + self.create = to_streamed_response_wrapper( + affiliates.create, + ) + self.retrieve = to_streamed_response_wrapper( + affiliates.retrieve, + ) + self.list = to_streamed_response_wrapper( + affiliates.list, + ) + self.archive = to_streamed_response_wrapper( + affiliates.archive, + ) + self.unarchive = to_streamed_response_wrapper( + affiliates.unarchive, + ) + + @cached_property + def overrides(self) -> OverridesResourceWithStreamingResponse: + """Affiliates""" + return OverridesResourceWithStreamingResponse(self._affiliates.overrides) + + +class AsyncAffiliatesResourceWithStreamingResponse: + def __init__(self, affiliates: AsyncAffiliatesResource) -> None: + self._affiliates = affiliates + + self.create = async_to_streamed_response_wrapper( + affiliates.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + affiliates.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + affiliates.list, + ) + self.archive = async_to_streamed_response_wrapper( + affiliates.archive, + ) + self.unarchive = async_to_streamed_response_wrapper( + affiliates.unarchive, + ) + + @cached_property + def overrides(self) -> AsyncOverridesResourceWithStreamingResponse: + """Affiliates""" + return AsyncOverridesResourceWithStreamingResponse(self._affiliates.overrides) diff --git a/src/whop_sdk/resources/affiliates/overrides.py b/src/whop_sdk/resources/affiliates/overrides.py new file mode 100644 index 0000000..a3158a1 --- /dev/null +++ b/src/whop_sdk/resources/affiliates/overrides.py @@ -0,0 +1,859 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, overload + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import required_args, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncCursorPage, AsyncCursorPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.affiliates import ( + AffiliatePayoutTypes, + AffiliateRevenueBases, + AffiliateOverrideRoles, + AffiliateAppliesToPayments, + override_list_params, + override_create_params, + override_update_params, +) +from ...types.affiliates.affiliate_payout_types import AffiliatePayoutTypes +from ...types.affiliates.override_list_response import OverrideListResponse +from ...types.affiliates.affiliate_revenue_bases import AffiliateRevenueBases +from ...types.affiliates.affiliate_override_roles import AffiliateOverrideRoles +from ...types.affiliates.override_create_response import OverrideCreateResponse +from ...types.affiliates.override_delete_response import OverrideDeleteResponse +from ...types.affiliates.override_update_response import OverrideUpdateResponse +from ...types.affiliates.override_retrieve_response import OverrideRetrieveResponse +from ...types.affiliates.affiliate_applies_to_payments import AffiliateAppliesToPayments + +__all__ = ["OverridesResource", "AsyncOverridesResource"] + + +class OverridesResource(SyncAPIResource): + """Affiliates""" + + @cached_property + def with_raw_response(self) -> OverridesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/whopio/whopsdk-python#accessing-raw-response-data-eg-headers + """ + return OverridesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> OverridesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/whopio/whopsdk-python#with_streaming_response + """ + return OverridesResourceWithStreamingResponse(self) + + @overload + def create( + self, + path_id: str, + *, + body_id: str, + commission_value: float, + override_type: Literal["standard"], + plan_id: str, + applies_to_payments: Optional[AffiliateAppliesToPayments] | Omit = omit, + commission_type: Optional[AffiliatePayoutTypes] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverrideCreateResponse: + """ + Creates a commission override for an affiliate. + + Required permissions: + + - `affiliate:create` + + Args: + body_id: The affiliate ID. + + commission_value: The commission value (percentage 1-100 or flat fee). + + plan_id: The plan ID (required for standard overrides). + + applies_to_payments: Whether the affiliate commission applies to the first payment or all payments + + commission_type: The types of payouts an affiliate can have + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + path_id: str, + *, + body_id: str, + commission_value: float, + override_type: Literal["rev_share"], + commission_type: Optional[AffiliatePayoutTypes] | Omit = omit, + product_id: Optional[str] | Omit = omit, + revenue_basis: Optional[AffiliateRevenueBases] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverrideCreateResponse: + """ + Creates a commission override for an affiliate. + + Required permissions: + + - `affiliate:create` + + Args: + body_id: The affiliate ID. + + commission_value: The commission value (percentage 1-100 or flat fee). + + commission_type: The types of payouts an affiliate can have + + product_id: The product ID (for rev-share overrides, omit for company-wide). + + revenue_basis: The calculation method for affiliate rev-share percentages + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args( + ["body_id", "commission_value", "override_type", "plan_id"], ["body_id", "commission_value", "override_type"] + ) + def create( + self, + path_id: str, + *, + body_id: str, + commission_value: float, + override_type: Literal["standard"] | Literal["rev_share"], + plan_id: str | Omit = omit, + applies_to_payments: Optional[AffiliateAppliesToPayments] | Omit = omit, + commission_type: Optional[AffiliatePayoutTypes] | Omit = omit, + product_id: Optional[str] | Omit = omit, + revenue_basis: Optional[AffiliateRevenueBases] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverrideCreateResponse: + if not path_id: + raise ValueError(f"Expected a non-empty value for `path_id` but received {path_id!r}") + return self._post( + f"/affiliates/{path_id}/overrides", + body=maybe_transform( + { + "body_id": body_id, + "commission_value": commission_value, + "override_type": override_type, + "plan_id": plan_id, + "applies_to_payments": applies_to_payments, + "commission_type": commission_type, + "product_id": product_id, + "revenue_basis": revenue_basis, + }, + override_create_params.OverrideCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OverrideCreateResponse, + ) + + def retrieve( + self, + override_id: str, + *, + id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverrideRetrieveResponse: + """ + Retrieves the details of a specific affiliate override. + + Required permissions: + + - `affiliate:basic:read` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + if not override_id: + raise ValueError(f"Expected a non-empty value for `override_id` but received {override_id!r}") + return self._get( + f"/affiliates/{id}/overrides/{override_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OverrideRetrieveResponse, + ) + + def update( + self, + override_id: str, + *, + id: str, + applies_to_payments: Optional[AffiliateAppliesToPayments] | Omit = omit, + commission_type: Optional[AffiliatePayoutTypes] | Omit = omit, + commission_value: Optional[float] | Omit = omit, + revenue_basis: Optional[AffiliateRevenueBases] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverrideUpdateResponse: + """ + Updates an existing affiliate override. + + Required permissions: + + - `affiliate:update` + + Args: + applies_to_payments: Whether the affiliate commission applies to the first payment or all payments + + commission_type: The types of payouts an affiliate can have + + commission_value: The commission value (percentage 1-100 or flat fee in dollars). + + revenue_basis: The calculation method for affiliate rev-share percentages + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + if not override_id: + raise ValueError(f"Expected a non-empty value for `override_id` but received {override_id!r}") + return self._patch( + f"/affiliates/{id}/overrides/{override_id}", + body=maybe_transform( + { + "applies_to_payments": applies_to_payments, + "commission_type": commission_type, + "commission_value": commission_value, + "revenue_basis": revenue_basis, + }, + override_update_params.OverrideUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OverrideUpdateResponse, + ) + + def list( + self, + id: str, + *, + after: Optional[str] | Omit = omit, + before: Optional[str] | Omit = omit, + first: Optional[int] | Omit = omit, + last: Optional[int] | Omit = omit, + override_type: Optional[AffiliateOverrideRoles] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[OverrideListResponse]: + """ + Returns a paginated list of overrides for an affiliate. + + Required permissions: + + - `affiliate:basic:read` + + Args: + after: Returns the elements in the list that come after the specified cursor. + + before: Returns the elements in the list that come before the specified cursor. + + first: Returns the first _n_ elements from the list. + + last: Returns the last _n_ elements from the list. + + override_type: The role of an affiliate override (standard or rev_share) + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get_api_list( + f"/affiliates/{id}/overrides", + page=SyncCursorPage[OverrideListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "before": before, + "first": first, + "last": last, + "override_type": override_type, + }, + override_list_params.OverrideListParams, + ), + ), + model=OverrideListResponse, + ) + + def delete( + self, + override_id: str, + *, + id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverrideDeleteResponse: + """ + Deletes an affiliate override. + + Required permissions: + + - `affiliate:update` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + if not override_id: + raise ValueError(f"Expected a non-empty value for `override_id` but received {override_id!r}") + return self._delete( + f"/affiliates/{id}/overrides/{override_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OverrideDeleteResponse, + ) + + +class AsyncOverridesResource(AsyncAPIResource): + """Affiliates""" + + @cached_property + def with_raw_response(self) -> AsyncOverridesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/whopio/whopsdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncOverridesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncOverridesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/whopio/whopsdk-python#with_streaming_response + """ + return AsyncOverridesResourceWithStreamingResponse(self) + + @overload + async def create( + self, + path_id: str, + *, + body_id: str, + commission_value: float, + override_type: Literal["standard"], + plan_id: str, + applies_to_payments: Optional[AffiliateAppliesToPayments] | Omit = omit, + commission_type: Optional[AffiliatePayoutTypes] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverrideCreateResponse: + """ + Creates a commission override for an affiliate. + + Required permissions: + + - `affiliate:create` + + Args: + body_id: The affiliate ID. + + commission_value: The commission value (percentage 1-100 or flat fee). + + plan_id: The plan ID (required for standard overrides). + + applies_to_payments: Whether the affiliate commission applies to the first payment or all payments + + commission_type: The types of payouts an affiliate can have + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + path_id: str, + *, + body_id: str, + commission_value: float, + override_type: Literal["rev_share"], + commission_type: Optional[AffiliatePayoutTypes] | Omit = omit, + product_id: Optional[str] | Omit = omit, + revenue_basis: Optional[AffiliateRevenueBases] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverrideCreateResponse: + """ + Creates a commission override for an affiliate. + + Required permissions: + + - `affiliate:create` + + Args: + body_id: The affiliate ID. + + commission_value: The commission value (percentage 1-100 or flat fee). + + commission_type: The types of payouts an affiliate can have + + product_id: The product ID (for rev-share overrides, omit for company-wide). + + revenue_basis: The calculation method for affiliate rev-share percentages + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args( + ["body_id", "commission_value", "override_type", "plan_id"], ["body_id", "commission_value", "override_type"] + ) + async def create( + self, + path_id: str, + *, + body_id: str, + commission_value: float, + override_type: Literal["standard"] | Literal["rev_share"], + plan_id: str | Omit = omit, + applies_to_payments: Optional[AffiliateAppliesToPayments] | Omit = omit, + commission_type: Optional[AffiliatePayoutTypes] | Omit = omit, + product_id: Optional[str] | Omit = omit, + revenue_basis: Optional[AffiliateRevenueBases] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverrideCreateResponse: + if not path_id: + raise ValueError(f"Expected a non-empty value for `path_id` but received {path_id!r}") + return await self._post( + f"/affiliates/{path_id}/overrides", + body=await async_maybe_transform( + { + "body_id": body_id, + "commission_value": commission_value, + "override_type": override_type, + "plan_id": plan_id, + "applies_to_payments": applies_to_payments, + "commission_type": commission_type, + "product_id": product_id, + "revenue_basis": revenue_basis, + }, + override_create_params.OverrideCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OverrideCreateResponse, + ) + + async def retrieve( + self, + override_id: str, + *, + id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverrideRetrieveResponse: + """ + Retrieves the details of a specific affiliate override. + + Required permissions: + + - `affiliate:basic:read` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + if not override_id: + raise ValueError(f"Expected a non-empty value for `override_id` but received {override_id!r}") + return await self._get( + f"/affiliates/{id}/overrides/{override_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OverrideRetrieveResponse, + ) + + async def update( + self, + override_id: str, + *, + id: str, + applies_to_payments: Optional[AffiliateAppliesToPayments] | Omit = omit, + commission_type: Optional[AffiliatePayoutTypes] | Omit = omit, + commission_value: Optional[float] | Omit = omit, + revenue_basis: Optional[AffiliateRevenueBases] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverrideUpdateResponse: + """ + Updates an existing affiliate override. + + Required permissions: + + - `affiliate:update` + + Args: + applies_to_payments: Whether the affiliate commission applies to the first payment or all payments + + commission_type: The types of payouts an affiliate can have + + commission_value: The commission value (percentage 1-100 or flat fee in dollars). + + revenue_basis: The calculation method for affiliate rev-share percentages + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + if not override_id: + raise ValueError(f"Expected a non-empty value for `override_id` but received {override_id!r}") + return await self._patch( + f"/affiliates/{id}/overrides/{override_id}", + body=await async_maybe_transform( + { + "applies_to_payments": applies_to_payments, + "commission_type": commission_type, + "commission_value": commission_value, + "revenue_basis": revenue_basis, + }, + override_update_params.OverrideUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OverrideUpdateResponse, + ) + + def list( + self, + id: str, + *, + after: Optional[str] | Omit = omit, + before: Optional[str] | Omit = omit, + first: Optional[int] | Omit = omit, + last: Optional[int] | Omit = omit, + override_type: Optional[AffiliateOverrideRoles] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[OverrideListResponse, AsyncCursorPage[OverrideListResponse]]: + """ + Returns a paginated list of overrides for an affiliate. + + Required permissions: + + - `affiliate:basic:read` + + Args: + after: Returns the elements in the list that come after the specified cursor. + + before: Returns the elements in the list that come before the specified cursor. + + first: Returns the first _n_ elements from the list. + + last: Returns the last _n_ elements from the list. + + override_type: The role of an affiliate override (standard or rev_share) + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get_api_list( + f"/affiliates/{id}/overrides", + page=AsyncCursorPage[OverrideListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "before": before, + "first": first, + "last": last, + "override_type": override_type, + }, + override_list_params.OverrideListParams, + ), + ), + model=OverrideListResponse, + ) + + async def delete( + self, + override_id: str, + *, + id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverrideDeleteResponse: + """ + Deletes an affiliate override. + + Required permissions: + + - `affiliate:update` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + if not override_id: + raise ValueError(f"Expected a non-empty value for `override_id` but received {override_id!r}") + return await self._delete( + f"/affiliates/{id}/overrides/{override_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OverrideDeleteResponse, + ) + + +class OverridesResourceWithRawResponse: + def __init__(self, overrides: OverridesResource) -> None: + self._overrides = overrides + + self.create = to_raw_response_wrapper( + overrides.create, + ) + self.retrieve = to_raw_response_wrapper( + overrides.retrieve, + ) + self.update = to_raw_response_wrapper( + overrides.update, + ) + self.list = to_raw_response_wrapper( + overrides.list, + ) + self.delete = to_raw_response_wrapper( + overrides.delete, + ) + + +class AsyncOverridesResourceWithRawResponse: + def __init__(self, overrides: AsyncOverridesResource) -> None: + self._overrides = overrides + + self.create = async_to_raw_response_wrapper( + overrides.create, + ) + self.retrieve = async_to_raw_response_wrapper( + overrides.retrieve, + ) + self.update = async_to_raw_response_wrapper( + overrides.update, + ) + self.list = async_to_raw_response_wrapper( + overrides.list, + ) + self.delete = async_to_raw_response_wrapper( + overrides.delete, + ) + + +class OverridesResourceWithStreamingResponse: + def __init__(self, overrides: OverridesResource) -> None: + self._overrides = overrides + + self.create = to_streamed_response_wrapper( + overrides.create, + ) + self.retrieve = to_streamed_response_wrapper( + overrides.retrieve, + ) + self.update = to_streamed_response_wrapper( + overrides.update, + ) + self.list = to_streamed_response_wrapper( + overrides.list, + ) + self.delete = to_streamed_response_wrapper( + overrides.delete, + ) + + +class AsyncOverridesResourceWithStreamingResponse: + def __init__(self, overrides: AsyncOverridesResource) -> None: + self._overrides = overrides + + self.create = async_to_streamed_response_wrapper( + overrides.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + overrides.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + overrides.update, + ) + self.list = async_to_streamed_response_wrapper( + overrides.list, + ) + self.delete = async_to_streamed_response_wrapper( + overrides.delete, + ) diff --git a/src/whop_sdk/resources/ai_chats.py b/src/whop_sdk/resources/ai_chats.py index 4eff698..6c9f4a1 100644 --- a/src/whop_sdk/resources/ai_chats.py +++ b/src/whop_sdk/resources/ai_chats.py @@ -7,7 +7,7 @@ import httpx -from ..types import ai_chat_list_params, ai_chat_create_params, ai_chat_update_params +from ..types import NotificationPreferences, ai_chat_list_params, ai_chat_create_params, ai_chat_update_params from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property @@ -23,6 +23,7 @@ from ..types.ai_chat import AIChat from ..types.ai_chat_list_response import AIChatListResponse from ..types.ai_chat_delete_response import AIChatDeleteResponse +from ..types.notification_preferences import NotificationPreferences __all__ = ["AIChatsResource", "AsyncAIChatsResource"] @@ -146,6 +147,7 @@ def update( id: str, *, current_company_id: Optional[str] | Omit = omit, + notification_preference: Optional[NotificationPreferences] | Omit = omit, title: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -155,7 +157,8 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AIChat: """ - Update an AI chat's title or associated company context. + Update an AI chat's title, notification preferences, or associated company + context. Required permissions: @@ -165,6 +168,8 @@ def update( current_company_id: The unique identifier of the company to set as context for the AI chat (e.g., "biz_XXXXX"). + notification_preference: The notification preference for an AI chat + title: The new display title for the AI chat thread (e.g., "Help with billing"). extra_headers: Send extra headers @@ -182,6 +187,7 @@ def update( body=maybe_transform( { "current_company_id": current_company_id, + "notification_preference": notification_preference, "title": title, }, ai_chat_update_params.AIChatUpdateParams, @@ -408,6 +414,7 @@ async def update( id: str, *, current_company_id: Optional[str] | Omit = omit, + notification_preference: Optional[NotificationPreferences] | Omit = omit, title: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -417,7 +424,8 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AIChat: """ - Update an AI chat's title or associated company context. + Update an AI chat's title, notification preferences, or associated company + context. Required permissions: @@ -427,6 +435,8 @@ async def update( current_company_id: The unique identifier of the company to set as context for the AI chat (e.g., "biz_XXXXX"). + notification_preference: The notification preference for an AI chat + title: The new display title for the AI chat thread (e.g., "Help with billing"). extra_headers: Send extra headers @@ -444,6 +454,7 @@ async def update( body=await async_maybe_transform( { "current_company_id": current_company_id, + "notification_preference": notification_preference, "title": title, }, ai_chat_update_params.AIChatUpdateParams, diff --git a/src/whop_sdk/types/__init__.py b/src/whop_sdk/types/__init__.py index 0cadc48..c4684b3 100644 --- a/src/whop_sdk/types/__init__.py +++ b/src/whop_sdk/types/__init__.py @@ -66,10 +66,12 @@ EmailNotificationPreferences as EmailNotificationPreferences, CourseLessonInteractionListItem as CourseLessonInteractionListItem, ) +from .status import Status as Status from .ai_chat import AIChat as AIChat from .dispute import Dispute as Dispute from .webhook import Webhook as Webhook from .app_type import AppType as AppType +from .affiliate import Affiliate as Affiliate from .dm_member import DmMember as DmMember from .languages import Languages as Languages from .dm_channel import DmChannel as DmChannel @@ -150,6 +152,7 @@ from .transfer_list_params import TransferListParams as TransferListParams from .unwrap_webhook_event import UnwrapWebhookEvent as UnwrapWebhookEvent from .withdrawal_fee_types import WithdrawalFeeTypes as WithdrawalFeeTypes +from .affiliate_list_params import AffiliateListParams as AffiliateListParams from .ai_chat_create_params import AIChatCreateParams as AIChatCreateParams from .ai_chat_list_response import AIChatListResponse as AIChatListResponse from .ai_chat_update_params import AIChatUpdateParams as AIChatUpdateParams @@ -191,6 +194,8 @@ from .transfer_create_params import TransferCreateParams as TransferCreateParams from .transfer_list_response import TransferListResponse as TransferListResponse from .withdrawal_list_params import WithdrawalListParams as WithdrawalListParams +from .affiliate_create_params import AffiliateCreateParams as AffiliateCreateParams +from .affiliate_list_response import AffiliateListResponse as AffiliateListResponse from .ai_chat_delete_response import AIChatDeleteResponse as AIChatDeleteResponse from .app_build_create_params import AppBuildCreateParams as AppBuildCreateParams from .app_build_list_response import AppBuildListResponse as AppBuildListResponse @@ -223,6 +228,7 @@ from .membership_cancel_params import MembershipCancelParams as MembershipCancelParams from .membership_list_response import MembershipListResponse as MembershipListResponse from .membership_update_params import MembershipUpdateParams as MembershipUpdateParams +from .notification_preferences import NotificationPreferences as NotificationPreferences from .payment_list_fees_params import PaymentListFeesParams as PaymentListFeesParams from .promo_code_create_params import PromoCodeCreateParams as PromoCodeCreateParams from .promo_code_list_response import PromoCodeListResponse as PromoCodeListResponse @@ -241,6 +247,7 @@ from .payout_method_list_params import PayoutMethodListParams as PayoutMethodListParams from .access_token_create_params import AccessTokenCreateParams as AccessTokenCreateParams from .account_link_create_params import AccountLinkCreateParams as AccountLinkCreateParams +from .affiliate_archive_response import AffiliateArchiveResponse as AffiliateArchiveResponse from .chat_channel_list_response import ChatChannelListResponse as ChatChannelListResponse from .chat_channel_update_params import ChatChannelUpdateParams as ChatChannelUpdateParams from .course_chapter_list_params import CourseChapterListParams as CourseChapterListParams @@ -273,6 +280,7 @@ from .support_channel_list_params import SupportChannelListParams as SupportChannelListParams from .access_token_create_response import AccessTokenCreateResponse as AccessTokenCreateResponse from .account_link_create_response import AccountLinkCreateResponse as AccountLinkCreateResponse +from .affiliate_unarchive_response import AffiliateUnarchiveResponse as AffiliateUnarchiveResponse from .course_chapter_create_params import CourseChapterCreateParams as CourseChapterCreateParams from .course_chapter_list_response import CourseChapterListResponse as CourseChapterListResponse from .course_chapter_update_params import CourseChapterUpdateParams as CourseChapterUpdateParams diff --git a/src/whop_sdk/types/affiliate.py b/src/whop_sdk/types/affiliate.py new file mode 100644 index 0000000..26de2b8 --- /dev/null +++ b/src/whop_sdk/types/affiliate.py @@ -0,0 +1,84 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from .status import Status +from .._models import BaseModel + +__all__ = ["Affiliate", "Company", "User"] + + +class Company(BaseModel): + """The company attached to this affiliate""" + + id: str + """The unique identifier for the company.""" + + title: str + """The written name of the company.""" + + +class User(BaseModel): + """The user attached to this affiliate""" + + id: str + """The unique identifier for the user.""" + + name: Optional[str] = None + """The display name set on the user's Whop profile. + + Null if the user has not set a name. + """ + + username: Optional[str] = None + """The unique username chosen by the user for their Whop profile. + + Null if the user has not set a username. + """ + + +class Affiliate(BaseModel): + """An affiliate of a company or a global affiliate""" + + id: str + """The unique identifier for the affiliate.""" + + active_members_count: int + """The total active members of the affiliate""" + + company: Company + """The company attached to this affiliate""" + + created_at: datetime + """The datetime the affiliate was created.""" + + customer_retention_rate: str + """How many referrals have remained since they joined as members""" + + customer_retention_rate_ninety_days: str + """A rolling 90-day retention rate for this affiliate""" + + monthly_recurring_revenue_usd: str + """The total MRR of the affiliate""" + + status: Optional[Status] = None + """Statuses for resources""" + + total_overrides_count: int + """The total count of all overrides for this affiliate""" + + total_referral_earnings_usd: str + """The total earnings of the affiliate from the users they referred""" + + total_referrals_count: int + """The total referrals of the affiliate""" + + total_revenue_usd: str + """The total revenue of the affiliate from their referrals""" + + updated_at: datetime + """The datetime the affiliate was last updated.""" + + user: User + """The user attached to this affiliate""" diff --git a/src/whop_sdk/types/affiliate_archive_response.py b/src/whop_sdk/types/affiliate_archive_response.py new file mode 100644 index 0000000..ea8a705 --- /dev/null +++ b/src/whop_sdk/types/affiliate_archive_response.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import TypeAlias + +__all__ = ["AffiliateArchiveResponse"] + +AffiliateArchiveResponse: TypeAlias = bool diff --git a/src/whop_sdk/types/affiliate_create_params.py b/src/whop_sdk/types/affiliate_create_params.py new file mode 100644 index 0000000..59ea1cb --- /dev/null +++ b/src/whop_sdk/types/affiliate_create_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["AffiliateCreateParams"] + + +class AffiliateCreateParams(TypedDict, total=False): + company_id: Required[str] + """The ID of the company to create the affiliate for.""" + + user_identifier: Required[str] + """The user identifier (username, email, user ID, or Discord ID).""" diff --git a/src/whop_sdk/types/affiliate_list_params.py b/src/whop_sdk/types/affiliate_list_params.py new file mode 100644 index 0000000..e2baeee --- /dev/null +++ b/src/whop_sdk/types/affiliate_list_params.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +from .status import Status +from .shared.direction import Direction + +__all__ = ["AffiliateListParams"] + + +class AffiliateListParams(TypedDict, total=False): + company_id: Required[str] + """The unique identifier of the company to list affiliates for.""" + + after: Optional[str] + """Returns the elements in the list that come after the specified cursor.""" + + before: Optional[str] + """Returns the elements in the list that come before the specified cursor.""" + + direction: Optional[Direction] + """The direction of the sort.""" + + first: Optional[int] + """Returns the first _n_ elements from the list.""" + + last: Optional[int] + """Returns the last _n_ elements from the list.""" + + order: Optional[Literal["id", "created_at", "cached_total_referrals", "cached_total_rewards"]] + """Which columns can be used to sort.""" + + query: Optional[str] + """Search affiliates by username.""" + + status: Optional[Status] + """Statuses for resources""" diff --git a/src/whop_sdk/types/affiliate_list_response.py b/src/whop_sdk/types/affiliate_list_response.py new file mode 100644 index 0000000..9e24c35 --- /dev/null +++ b/src/whop_sdk/types/affiliate_list_response.py @@ -0,0 +1,84 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from .status import Status +from .._models import BaseModel + +__all__ = ["AffiliateListResponse", "Company", "User"] + + +class Company(BaseModel): + """The company attached to this affiliate""" + + id: str + """The unique identifier for the company.""" + + title: str + """The written name of the company.""" + + +class User(BaseModel): + """The user attached to this affiliate""" + + id: str + """The unique identifier for the user.""" + + name: Optional[str] = None + """The display name set on the user's Whop profile. + + Null if the user has not set a name. + """ + + username: Optional[str] = None + """The unique username chosen by the user for their Whop profile. + + Null if the user has not set a username. + """ + + +class AffiliateListResponse(BaseModel): + """An affiliate of a company or a global affiliate""" + + id: str + """The unique identifier for the affiliate.""" + + active_members_count: int + """The total active members of the affiliate""" + + company: Company + """The company attached to this affiliate""" + + created_at: datetime + """The datetime the affiliate was created.""" + + customer_retention_rate: str + """How many referrals have remained since they joined as members""" + + customer_retention_rate_ninety_days: str + """A rolling 90-day retention rate for this affiliate""" + + monthly_recurring_revenue_usd: str + """The total MRR of the affiliate""" + + status: Optional[Status] = None + """Statuses for resources""" + + total_overrides_count: int + """The total count of all overrides for this affiliate""" + + total_referral_earnings_usd: str + """The total earnings of the affiliate from the users they referred""" + + total_referrals_count: int + """The total referrals of the affiliate""" + + total_revenue_usd: str + """The total revenue of the affiliate from their referrals""" + + updated_at: datetime + """The datetime the affiliate was last updated.""" + + user: User + """The user attached to this affiliate""" diff --git a/src/whop_sdk/types/affiliate_unarchive_response.py b/src/whop_sdk/types/affiliate_unarchive_response.py new file mode 100644 index 0000000..34c8c2a --- /dev/null +++ b/src/whop_sdk/types/affiliate_unarchive_response.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import TypeAlias + +__all__ = ["AffiliateUnarchiveResponse"] + +AffiliateUnarchiveResponse: TypeAlias = bool diff --git a/src/whop_sdk/types/affiliates/__init__.py b/src/whop_sdk/types/affiliates/__init__.py new file mode 100644 index 0000000..c072b83 --- /dev/null +++ b/src/whop_sdk/types/affiliates/__init__.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .override_list_params import OverrideListParams as OverrideListParams +from .affiliate_payout_types import AffiliatePayoutTypes as AffiliatePayoutTypes +from .override_create_params import OverrideCreateParams as OverrideCreateParams +from .override_list_response import OverrideListResponse as OverrideListResponse +from .override_update_params import OverrideUpdateParams as OverrideUpdateParams +from .affiliate_revenue_bases import AffiliateRevenueBases as AffiliateRevenueBases +from .affiliate_override_roles import AffiliateOverrideRoles as AffiliateOverrideRoles +from .override_create_response import OverrideCreateResponse as OverrideCreateResponse +from .override_delete_response import OverrideDeleteResponse as OverrideDeleteResponse +from .override_update_response import OverrideUpdateResponse as OverrideUpdateResponse +from .override_retrieve_response import OverrideRetrieveResponse as OverrideRetrieveResponse +from .affiliate_applies_to_payments import AffiliateAppliesToPayments as AffiliateAppliesToPayments +from .affiliate_applies_to_products import AffiliateAppliesToProducts as AffiliateAppliesToProducts diff --git a/src/whop_sdk/types/affiliates/affiliate_applies_to_payments.py b/src/whop_sdk/types/affiliates/affiliate_applies_to_payments.py new file mode 100644 index 0000000..e25a592 --- /dev/null +++ b/src/whop_sdk/types/affiliates/affiliate_applies_to_payments.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["AffiliateAppliesToPayments"] + +AffiliateAppliesToPayments: TypeAlias = Literal["first_payment", "all_payments"] diff --git a/src/whop_sdk/types/affiliates/affiliate_applies_to_products.py b/src/whop_sdk/types/affiliates/affiliate_applies_to_products.py new file mode 100644 index 0000000..2e7e21d --- /dev/null +++ b/src/whop_sdk/types/affiliates/affiliate_applies_to_products.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["AffiliateAppliesToProducts"] + +AffiliateAppliesToProducts: TypeAlias = Literal["single_product", "all_products"] diff --git a/src/whop_sdk/types/affiliates/affiliate_override_roles.py b/src/whop_sdk/types/affiliates/affiliate_override_roles.py new file mode 100644 index 0000000..a123816 --- /dev/null +++ b/src/whop_sdk/types/affiliates/affiliate_override_roles.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["AffiliateOverrideRoles"] + +AffiliateOverrideRoles: TypeAlias = Literal["standard", "rev_share"] diff --git a/src/whop_sdk/types/affiliates/affiliate_payout_types.py b/src/whop_sdk/types/affiliates/affiliate_payout_types.py new file mode 100644 index 0000000..2bc6e63 --- /dev/null +++ b/src/whop_sdk/types/affiliates/affiliate_payout_types.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["AffiliatePayoutTypes"] + +AffiliatePayoutTypes: TypeAlias = Literal["percentage", "flat_fee"] diff --git a/src/whop_sdk/types/affiliates/affiliate_revenue_bases.py b/src/whop_sdk/types/affiliates/affiliate_revenue_bases.py new file mode 100644 index 0000000..0d8f781 --- /dev/null +++ b/src/whop_sdk/types/affiliates/affiliate_revenue_bases.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["AffiliateRevenueBases"] + +AffiliateRevenueBases: TypeAlias = Literal["pre_fees", "post_fees"] diff --git a/src/whop_sdk/types/affiliates/override_create_params.py b/src/whop_sdk/types/affiliates/override_create_params.py new file mode 100644 index 0000000..b136a4f --- /dev/null +++ b/src/whop_sdk/types/affiliates/override_create_params.py @@ -0,0 +1,60 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from ..._utils import PropertyInfo +from .affiliate_payout_types import AffiliatePayoutTypes +from .affiliate_revenue_bases import AffiliateRevenueBases +from .affiliate_applies_to_payments import AffiliateAppliesToPayments + +__all__ = [ + "OverrideCreateParams", + "CreateAffiliateOverrideInputOverrideTypeStandard", + "CreateAffiliateOverrideInputOverrideTypeRevShare", +] + + +class CreateAffiliateOverrideInputOverrideTypeStandard(TypedDict, total=False): + body_id: Required[Annotated[str, PropertyInfo(alias="id")]] + """The affiliate ID.""" + + commission_value: Required[float] + """The commission value (percentage 1-100 or flat fee).""" + + override_type: Required[Literal["standard"]] + + plan_id: Required[str] + """The plan ID (required for standard overrides).""" + + applies_to_payments: Optional[AffiliateAppliesToPayments] + """Whether the affiliate commission applies to the first payment or all payments""" + + commission_type: Optional[AffiliatePayoutTypes] + """The types of payouts an affiliate can have""" + + +class CreateAffiliateOverrideInputOverrideTypeRevShare(TypedDict, total=False): + body_id: Required[Annotated[str, PropertyInfo(alias="id")]] + """The affiliate ID.""" + + commission_value: Required[float] + """The commission value (percentage 1-100 or flat fee).""" + + override_type: Required[Literal["rev_share"]] + + commission_type: Optional[AffiliatePayoutTypes] + """The types of payouts an affiliate can have""" + + product_id: Optional[str] + """The product ID (for rev-share overrides, omit for company-wide).""" + + revenue_basis: Optional[AffiliateRevenueBases] + """The calculation method for affiliate rev-share percentages""" + + +OverrideCreateParams: TypeAlias = Union[ + CreateAffiliateOverrideInputOverrideTypeStandard, CreateAffiliateOverrideInputOverrideTypeRevShare +] diff --git a/src/whop_sdk/types/affiliates/override_create_response.py b/src/whop_sdk/types/affiliates/override_create_response.py new file mode 100644 index 0000000..b7c63d4 --- /dev/null +++ b/src/whop_sdk/types/affiliates/override_create_response.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .affiliate_payout_types import AffiliatePayoutTypes +from .affiliate_revenue_bases import AffiliateRevenueBases +from .affiliate_override_roles import AffiliateOverrideRoles +from .affiliate_applies_to_payments import AffiliateAppliesToPayments +from .affiliate_applies_to_products import AffiliateAppliesToProducts + +__all__ = ["OverrideCreateResponse"] + + +class OverrideCreateResponse(BaseModel): + """An object storing information about the affiliate""" + + id: str + """The unique identifier for the affiliate override.""" + + applies_to_payments: Optional[AffiliateAppliesToPayments] = None + """Whether the affiliate commission applies to the first payment or all payments""" + + applies_to_products: Optional[AffiliateAppliesToProducts] = None + """Whether a rev-share override applies to a single product or all products""" + + checkout_direct_link: Optional[str] = None + """The checkout direct link for referrals (standard overrides only).""" + + commission_type: AffiliatePayoutTypes + """The type of commission (percentage or flat_fee).""" + + commission_value: float + """The commission value (percentage 1-100 or flat fee in dollars).""" + + override_type: AffiliateOverrideRoles + """The type of override (standard or rev_share).""" + + plan_id: Optional[str] = None + """The plan ID (for standard overrides).""" + + product_direct_link: Optional[str] = None + """The product page direct link for referrals (standard overrides only).""" + + product_id: Optional[str] = None + """The product ID (for rev-share overrides).""" + + revenue_basis: Optional[AffiliateRevenueBases] = None + """The calculation method for affiliate rev-share percentages""" + + total_referral_earnings_usd: float + """ + The total earnings paid to this affiliate for referrals to this specific plan, + in USD. + """ diff --git a/src/whop_sdk/types/affiliates/override_delete_response.py b/src/whop_sdk/types/affiliates/override_delete_response.py new file mode 100644 index 0000000..0cb553b --- /dev/null +++ b/src/whop_sdk/types/affiliates/override_delete_response.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import TypeAlias + +__all__ = ["OverrideDeleteResponse"] + +OverrideDeleteResponse: TypeAlias = bool diff --git a/src/whop_sdk/types/affiliates/override_list_params.py b/src/whop_sdk/types/affiliates/override_list_params.py new file mode 100644 index 0000000..76f82be --- /dev/null +++ b/src/whop_sdk/types/affiliates/override_list_params.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +from .affiliate_override_roles import AffiliateOverrideRoles + +__all__ = ["OverrideListParams"] + + +class OverrideListParams(TypedDict, total=False): + after: Optional[str] + """Returns the elements in the list that come after the specified cursor.""" + + before: Optional[str] + """Returns the elements in the list that come before the specified cursor.""" + + first: Optional[int] + """Returns the first _n_ elements from the list.""" + + last: Optional[int] + """Returns the last _n_ elements from the list.""" + + override_type: Optional[AffiliateOverrideRoles] + """The role of an affiliate override (standard or rev_share)""" diff --git a/src/whop_sdk/types/affiliates/override_list_response.py b/src/whop_sdk/types/affiliates/override_list_response.py new file mode 100644 index 0000000..09ce176 --- /dev/null +++ b/src/whop_sdk/types/affiliates/override_list_response.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .affiliate_payout_types import AffiliatePayoutTypes +from .affiliate_revenue_bases import AffiliateRevenueBases +from .affiliate_override_roles import AffiliateOverrideRoles +from .affiliate_applies_to_payments import AffiliateAppliesToPayments +from .affiliate_applies_to_products import AffiliateAppliesToProducts + +__all__ = ["OverrideListResponse"] + + +class OverrideListResponse(BaseModel): + """An object storing information about the affiliate""" + + id: str + """The unique identifier for the affiliate override.""" + + applies_to_payments: Optional[AffiliateAppliesToPayments] = None + """Whether the affiliate commission applies to the first payment or all payments""" + + applies_to_products: Optional[AffiliateAppliesToProducts] = None + """Whether a rev-share override applies to a single product or all products""" + + checkout_direct_link: Optional[str] = None + """The checkout direct link for referrals (standard overrides only).""" + + commission_type: AffiliatePayoutTypes + """The type of commission (percentage or flat_fee).""" + + commission_value: float + """The commission value (percentage 1-100 or flat fee in dollars).""" + + override_type: AffiliateOverrideRoles + """The type of override (standard or rev_share).""" + + plan_id: Optional[str] = None + """The plan ID (for standard overrides).""" + + product_direct_link: Optional[str] = None + """The product page direct link for referrals (standard overrides only).""" + + product_id: Optional[str] = None + """The product ID (for rev-share overrides).""" + + revenue_basis: Optional[AffiliateRevenueBases] = None + """The calculation method for affiliate rev-share percentages""" + + total_referral_earnings_usd: float + """ + The total earnings paid to this affiliate for referrals to this specific plan, + in USD. + """ diff --git a/src/whop_sdk/types/affiliates/override_retrieve_response.py b/src/whop_sdk/types/affiliates/override_retrieve_response.py new file mode 100644 index 0000000..4e54c0f --- /dev/null +++ b/src/whop_sdk/types/affiliates/override_retrieve_response.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .affiliate_payout_types import AffiliatePayoutTypes +from .affiliate_revenue_bases import AffiliateRevenueBases +from .affiliate_override_roles import AffiliateOverrideRoles +from .affiliate_applies_to_payments import AffiliateAppliesToPayments +from .affiliate_applies_to_products import AffiliateAppliesToProducts + +__all__ = ["OverrideRetrieveResponse"] + + +class OverrideRetrieveResponse(BaseModel): + """An object storing information about the affiliate""" + + id: str + """The unique identifier for the affiliate override.""" + + applies_to_payments: Optional[AffiliateAppliesToPayments] = None + """Whether the affiliate commission applies to the first payment or all payments""" + + applies_to_products: Optional[AffiliateAppliesToProducts] = None + """Whether a rev-share override applies to a single product or all products""" + + checkout_direct_link: Optional[str] = None + """The checkout direct link for referrals (standard overrides only).""" + + commission_type: AffiliatePayoutTypes + """The type of commission (percentage or flat_fee).""" + + commission_value: float + """The commission value (percentage 1-100 or flat fee in dollars).""" + + override_type: AffiliateOverrideRoles + """The type of override (standard or rev_share).""" + + plan_id: Optional[str] = None + """The plan ID (for standard overrides).""" + + product_direct_link: Optional[str] = None + """The product page direct link for referrals (standard overrides only).""" + + product_id: Optional[str] = None + """The product ID (for rev-share overrides).""" + + revenue_basis: Optional[AffiliateRevenueBases] = None + """The calculation method for affiliate rev-share percentages""" + + total_referral_earnings_usd: float + """ + The total earnings paid to this affiliate for referrals to this specific plan, + in USD. + """ diff --git a/src/whop_sdk/types/affiliates/override_update_params.py b/src/whop_sdk/types/affiliates/override_update_params.py new file mode 100644 index 0000000..fa1ab86 --- /dev/null +++ b/src/whop_sdk/types/affiliates/override_update_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +from .affiliate_payout_types import AffiliatePayoutTypes +from .affiliate_revenue_bases import AffiliateRevenueBases +from .affiliate_applies_to_payments import AffiliateAppliesToPayments + +__all__ = ["OverrideUpdateParams"] + + +class OverrideUpdateParams(TypedDict, total=False): + id: Required[str] + + applies_to_payments: Optional[AffiliateAppliesToPayments] + """Whether the affiliate commission applies to the first payment or all payments""" + + commission_type: Optional[AffiliatePayoutTypes] + """The types of payouts an affiliate can have""" + + commission_value: Optional[float] + """The commission value (percentage 1-100 or flat fee in dollars).""" + + revenue_basis: Optional[AffiliateRevenueBases] + """The calculation method for affiliate rev-share percentages""" diff --git a/src/whop_sdk/types/affiliates/override_update_response.py b/src/whop_sdk/types/affiliates/override_update_response.py new file mode 100644 index 0000000..b9ed5c9 --- /dev/null +++ b/src/whop_sdk/types/affiliates/override_update_response.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .affiliate_payout_types import AffiliatePayoutTypes +from .affiliate_revenue_bases import AffiliateRevenueBases +from .affiliate_override_roles import AffiliateOverrideRoles +from .affiliate_applies_to_payments import AffiliateAppliesToPayments +from .affiliate_applies_to_products import AffiliateAppliesToProducts + +__all__ = ["OverrideUpdateResponse"] + + +class OverrideUpdateResponse(BaseModel): + """An object storing information about the affiliate""" + + id: str + """The unique identifier for the affiliate override.""" + + applies_to_payments: Optional[AffiliateAppliesToPayments] = None + """Whether the affiliate commission applies to the first payment or all payments""" + + applies_to_products: Optional[AffiliateAppliesToProducts] = None + """Whether a rev-share override applies to a single product or all products""" + + checkout_direct_link: Optional[str] = None + """The checkout direct link for referrals (standard overrides only).""" + + commission_type: AffiliatePayoutTypes + """The type of commission (percentage or flat_fee).""" + + commission_value: float + """The commission value (percentage 1-100 or flat fee in dollars).""" + + override_type: AffiliateOverrideRoles + """The type of override (standard or rev_share).""" + + plan_id: Optional[str] = None + """The plan ID (for standard overrides).""" + + product_direct_link: Optional[str] = None + """The product page direct link for referrals (standard overrides only).""" + + product_id: Optional[str] = None + """The product ID (for rev-share overrides).""" + + revenue_basis: Optional[AffiliateRevenueBases] = None + """The calculation method for affiliate rev-share percentages""" + + total_referral_earnings_usd: float + """ + The total earnings paid to this affiliate for referrals to this specific plan, + in USD. + """ diff --git a/src/whop_sdk/types/ai_chat.py b/src/whop_sdk/types/ai_chat.py index 2ddbc6e..cf370c2 100644 --- a/src/whop_sdk/types/ai_chat.py +++ b/src/whop_sdk/types/ai_chat.py @@ -4,6 +4,7 @@ from datetime import datetime from .._models import BaseModel +from .notification_preferences import NotificationPreferences __all__ = ["AIChat", "User"] @@ -38,6 +39,12 @@ class AIChat(BaseModel): message_count: int """The total number of messages exchanged in this conversation.""" + notification_preference: NotificationPreferences + """The notification preference for this AI chat. + + `all` delivers AI chat notifications and badges, while `none` mutes them. + """ + title: Optional[str] = None """A short descriptive title for this AI chat conversation. diff --git a/src/whop_sdk/types/ai_chat_list_response.py b/src/whop_sdk/types/ai_chat_list_response.py index af211b4..3b67653 100644 --- a/src/whop_sdk/types/ai_chat_list_response.py +++ b/src/whop_sdk/types/ai_chat_list_response.py @@ -4,6 +4,7 @@ from datetime import datetime from .._models import BaseModel +from .notification_preferences import NotificationPreferences __all__ = ["AIChatListResponse", "User"] @@ -38,6 +39,12 @@ class AIChatListResponse(BaseModel): message_count: int """The total number of messages exchanged in this conversation.""" + notification_preference: NotificationPreferences + """The notification preference for this AI chat. + + `all` delivers AI chat notifications and badges, while `none` mutes them. + """ + title: Optional[str] = None """A short descriptive title for this AI chat conversation. diff --git a/src/whop_sdk/types/ai_chat_update_params.py b/src/whop_sdk/types/ai_chat_update_params.py index f3fc9bc..7a4773d 100644 --- a/src/whop_sdk/types/ai_chat_update_params.py +++ b/src/whop_sdk/types/ai_chat_update_params.py @@ -5,6 +5,8 @@ from typing import Optional from typing_extensions import TypedDict +from .notification_preferences import NotificationPreferences + __all__ = ["AIChatUpdateParams"] @@ -15,5 +17,8 @@ class AIChatUpdateParams(TypedDict, total=False): "biz_XXXXX"). """ + notification_preference: Optional[NotificationPreferences] + """The notification preference for an AI chat""" + title: Optional[str] """The new display title for the AI chat thread (e.g., "Help with billing").""" diff --git a/src/whop_sdk/types/card_brands.py b/src/whop_sdk/types/card_brands.py index 9d8c7c1..1243eea 100644 --- a/src/whop_sdk/types/card_brands.py +++ b/src/whop_sdk/types/card_brands.py @@ -42,5 +42,6 @@ "codensa", "cabal", "hipercard", + "jcblankapay", "unknown", ] diff --git a/src/whop_sdk/types/notification_preferences.py b/src/whop_sdk/types/notification_preferences.py new file mode 100644 index 0000000..e3cf22f --- /dev/null +++ b/src/whop_sdk/types/notification_preferences.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["NotificationPreferences"] + +NotificationPreferences: TypeAlias = Literal["all", "none"] diff --git a/src/whop_sdk/types/setup_intent.py b/src/whop_sdk/types/setup_intent.py index 6c3f3ac..a79a2b7 100644 --- a/src/whop_sdk/types/setup_intent.py +++ b/src/whop_sdk/types/setup_intent.py @@ -16,6 +16,7 @@ "MemberUser", "PaymentMethod", "PaymentMethodCard", + "PaymentMethodMailingAddress", ] @@ -89,6 +90,31 @@ class PaymentMethodCard(BaseModel): """The last four digits of the card number. Null if not available.""" +class PaymentMethodMailingAddress(BaseModel): + """The mailing address associated with the payment method's user""" + + city: Optional[str] = None + """The city of the address.""" + + country: Optional[str] = None + """The country of the address.""" + + line1: Optional[str] = None + """The line 1 of the address.""" + + line2: Optional[str] = None + """The line 2 of the address.""" + + name: Optional[str] = None + """The name of the customer.""" + + postal_code: Optional[str] = None + """The postal code of the address.""" + + state: Optional[str] = None + """The state of the address.""" + + class PaymentMethod(BaseModel): """The saved payment method created by this setup intent. @@ -106,6 +132,9 @@ class PaymentMethod(BaseModel): created_at: datetime """The datetime the payment token was created.""" + mailing_address: Optional[PaymentMethodMailingAddress] = None + """The mailing address associated with the payment method's user""" + payment_method_type: PaymentMethodTypes """The payment method type of the payment method""" diff --git a/src/whop_sdk/types/setup_intent_list_response.py b/src/whop_sdk/types/setup_intent_list_response.py index cd30204..93d409a 100644 --- a/src/whop_sdk/types/setup_intent_list_response.py +++ b/src/whop_sdk/types/setup_intent_list_response.py @@ -16,6 +16,7 @@ "MemberUser", "PaymentMethod", "PaymentMethodCard", + "PaymentMethodMailingAddress", ] @@ -89,6 +90,31 @@ class PaymentMethodCard(BaseModel): """The last four digits of the card number. Null if not available.""" +class PaymentMethodMailingAddress(BaseModel): + """The mailing address associated with the payment method's user""" + + city: Optional[str] = None + """The city of the address.""" + + country: Optional[str] = None + """The country of the address.""" + + line1: Optional[str] = None + """The line 1 of the address.""" + + line2: Optional[str] = None + """The line 2 of the address.""" + + name: Optional[str] = None + """The name of the customer.""" + + postal_code: Optional[str] = None + """The postal code of the address.""" + + state: Optional[str] = None + """The state of the address.""" + + class PaymentMethod(BaseModel): """The saved payment method created by this setup intent. @@ -106,6 +132,9 @@ class PaymentMethod(BaseModel): created_at: datetime """The datetime the payment token was created.""" + mailing_address: Optional[PaymentMethodMailingAddress] = None + """The mailing address associated with the payment method's user""" + payment_method_type: PaymentMethodTypes """The payment method type of the payment method""" diff --git a/src/whop_sdk/types/shared/payment.py b/src/whop_sdk/types/shared/payment.py index c9403c4..009f035 100644 --- a/src/whop_sdk/types/shared/payment.py +++ b/src/whop_sdk/types/shared/payment.py @@ -166,6 +166,7 @@ class FinancingTransaction(BaseModel): "cancel", "verify", "chargeback", + "pre_chargeback", "three_d_secure", "fraud_screening", "authorization", diff --git a/src/whop_sdk/types/status.py b/src/whop_sdk/types/status.py new file mode 100644 index 0000000..eff0ae9 --- /dev/null +++ b/src/whop_sdk/types/status.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["Status"] + +Status: TypeAlias = Literal["active", "archived", "deleted"] diff --git a/tests/api_resources/affiliates/__init__.py b/tests/api_resources/affiliates/__init__.py new file mode 100644 index 0000000..fd8019a --- /dev/null +++ b/tests/api_resources/affiliates/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/affiliates/test_overrides.py b/tests/api_resources/affiliates/test_overrides.py new file mode 100644 index 0000000..4a9d7f4 --- /dev/null +++ b/tests/api_resources/affiliates/test_overrides.py @@ -0,0 +1,759 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from whop_sdk import Whop, AsyncWhop +from tests.utils import assert_matches_type +from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage +from whop_sdk.types.affiliates import ( + OverrideListResponse, + OverrideCreateResponse, + OverrideDeleteResponse, + OverrideUpdateResponse, + OverrideRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestOverrides: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_overload_1(self, client: Whop) -> None: + override = client.affiliates.overrides.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="standard", + plan_id="plan_xxxxxxxxxxxxx", + ) + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params_overload_1(self, client: Whop) -> None: + override = client.affiliates.overrides.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="standard", + plan_id="plan_xxxxxxxxxxxxx", + applies_to_payments="first_payment", + commission_type="percentage", + ) + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create_overload_1(self, client: Whop) -> None: + response = client.affiliates.overrides.with_raw_response.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="standard", + plan_id="plan_xxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + override = response.parse() + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create_overload_1(self, client: Whop) -> None: + with client.affiliates.overrides.with_streaming_response.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="standard", + plan_id="plan_xxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + override = response.parse() + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_create_overload_1(self, client: Whop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"): + client.affiliates.overrides.with_raw_response.create( + path_id="", + body_id="id", + commission_value=6.9, + override_type="standard", + plan_id="plan_xxxxxxxxxxxxx", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_overload_2(self, client: Whop) -> None: + override = client.affiliates.overrides.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="rev_share", + ) + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params_overload_2(self, client: Whop) -> None: + override = client.affiliates.overrides.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="rev_share", + commission_type="percentage", + product_id="prod_xxxxxxxxxxxxx", + revenue_basis="pre_fees", + ) + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create_overload_2(self, client: Whop) -> None: + response = client.affiliates.overrides.with_raw_response.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="rev_share", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + override = response.parse() + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create_overload_2(self, client: Whop) -> None: + with client.affiliates.overrides.with_streaming_response.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="rev_share", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + override = response.parse() + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_create_overload_2(self, client: Whop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"): + client.affiliates.overrides.with_raw_response.create( + path_id="", + body_id="id", + commission_value=6.9, + override_type="rev_share", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Whop) -> None: + override = client.affiliates.overrides.retrieve( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) + assert_matches_type(OverrideRetrieveResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Whop) -> None: + response = client.affiliates.overrides.with_raw_response.retrieve( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + override = response.parse() + assert_matches_type(OverrideRetrieveResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Whop) -> None: + with client.affiliates.overrides.with_streaming_response.retrieve( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + override = response.parse() + assert_matches_type(OverrideRetrieveResponse, override, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Whop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.affiliates.overrides.with_raw_response.retrieve( + override_id="override_id", + id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `override_id` but received ''"): + client.affiliates.overrides.with_raw_response.retrieve( + override_id="", + id="aff_xxxxxxxxxxxxxx", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_update(self, client: Whop) -> None: + override = client.affiliates.overrides.update( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) + assert_matches_type(OverrideUpdateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_update_with_all_params(self, client: Whop) -> None: + override = client.affiliates.overrides.update( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + applies_to_payments="first_payment", + commission_type="percentage", + commission_value=6.9, + revenue_basis="pre_fees", + ) + assert_matches_type(OverrideUpdateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_update(self, client: Whop) -> None: + response = client.affiliates.overrides.with_raw_response.update( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + override = response.parse() + assert_matches_type(OverrideUpdateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_update(self, client: Whop) -> None: + with client.affiliates.overrides.with_streaming_response.update( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + override = response.parse() + assert_matches_type(OverrideUpdateResponse, override, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_update(self, client: Whop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.affiliates.overrides.with_raw_response.update( + override_id="override_id", + id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `override_id` but received ''"): + client.affiliates.overrides.with_raw_response.update( + override_id="", + id="aff_xxxxxxxxxxxxxx", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Whop) -> None: + override = client.affiliates.overrides.list( + id="aff_xxxxxxxxxxxxxx", + ) + assert_matches_type(SyncCursorPage[OverrideListResponse], override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Whop) -> None: + override = client.affiliates.overrides.list( + id="aff_xxxxxxxxxxxxxx", + after="after", + before="before", + first=42, + last=42, + override_type="standard", + ) + assert_matches_type(SyncCursorPage[OverrideListResponse], override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Whop) -> None: + response = client.affiliates.overrides.with_raw_response.list( + id="aff_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + override = response.parse() + assert_matches_type(SyncCursorPage[OverrideListResponse], override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Whop) -> None: + with client.affiliates.overrides.with_streaming_response.list( + id="aff_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + override = response.parse() + assert_matches_type(SyncCursorPage[OverrideListResponse], override, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_list(self, client: Whop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.affiliates.overrides.with_raw_response.list( + id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_delete(self, client: Whop) -> None: + override = client.affiliates.overrides.delete( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) + assert_matches_type(OverrideDeleteResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_delete(self, client: Whop) -> None: + response = client.affiliates.overrides.with_raw_response.delete( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + override = response.parse() + assert_matches_type(OverrideDeleteResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_delete(self, client: Whop) -> None: + with client.affiliates.overrides.with_streaming_response.delete( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + override = response.parse() + assert_matches_type(OverrideDeleteResponse, override, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_delete(self, client: Whop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.affiliates.overrides.with_raw_response.delete( + override_id="override_id", + id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `override_id` but received ''"): + client.affiliates.overrides.with_raw_response.delete( + override_id="", + id="aff_xxxxxxxxxxxxxx", + ) + + +class TestAsyncOverrides: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_overload_1(self, async_client: AsyncWhop) -> None: + override = await async_client.affiliates.overrides.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="standard", + plan_id="plan_xxxxxxxxxxxxx", + ) + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params_overload_1(self, async_client: AsyncWhop) -> None: + override = await async_client.affiliates.overrides.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="standard", + plan_id="plan_xxxxxxxxxxxxx", + applies_to_payments="first_payment", + commission_type="percentage", + ) + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create_overload_1(self, async_client: AsyncWhop) -> None: + response = await async_client.affiliates.overrides.with_raw_response.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="standard", + plan_id="plan_xxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + override = await response.parse() + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create_overload_1(self, async_client: AsyncWhop) -> None: + async with async_client.affiliates.overrides.with_streaming_response.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="standard", + plan_id="plan_xxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + override = await response.parse() + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_create_overload_1(self, async_client: AsyncWhop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"): + await async_client.affiliates.overrides.with_raw_response.create( + path_id="", + body_id="id", + commission_value=6.9, + override_type="standard", + plan_id="plan_xxxxxxxxxxxxx", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_overload_2(self, async_client: AsyncWhop) -> None: + override = await async_client.affiliates.overrides.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="rev_share", + ) + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params_overload_2(self, async_client: AsyncWhop) -> None: + override = await async_client.affiliates.overrides.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="rev_share", + commission_type="percentage", + product_id="prod_xxxxxxxxxxxxx", + revenue_basis="pre_fees", + ) + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create_overload_2(self, async_client: AsyncWhop) -> None: + response = await async_client.affiliates.overrides.with_raw_response.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="rev_share", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + override = await response.parse() + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create_overload_2(self, async_client: AsyncWhop) -> None: + async with async_client.affiliates.overrides.with_streaming_response.create( + path_id="aff_xxxxxxxxxxxxxx", + body_id="id", + commission_value=6.9, + override_type="rev_share", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + override = await response.parse() + assert_matches_type(OverrideCreateResponse, override, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_create_overload_2(self, async_client: AsyncWhop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"): + await async_client.affiliates.overrides.with_raw_response.create( + path_id="", + body_id="id", + commission_value=6.9, + override_type="rev_share", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncWhop) -> None: + override = await async_client.affiliates.overrides.retrieve( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) + assert_matches_type(OverrideRetrieveResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None: + response = await async_client.affiliates.overrides.with_raw_response.retrieve( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + override = await response.parse() + assert_matches_type(OverrideRetrieveResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncWhop) -> None: + async with async_client.affiliates.overrides.with_streaming_response.retrieve( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + override = await response.parse() + assert_matches_type(OverrideRetrieveResponse, override, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncWhop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.affiliates.overrides.with_raw_response.retrieve( + override_id="override_id", + id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `override_id` but received ''"): + await async_client.affiliates.overrides.with_raw_response.retrieve( + override_id="", + id="aff_xxxxxxxxxxxxxx", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_update(self, async_client: AsyncWhop) -> None: + override = await async_client.affiliates.overrides.update( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) + assert_matches_type(OverrideUpdateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> None: + override = await async_client.affiliates.overrides.update( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + applies_to_payments="first_payment", + commission_type="percentage", + commission_value=6.9, + revenue_basis="pre_fees", + ) + assert_matches_type(OverrideUpdateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_update(self, async_client: AsyncWhop) -> None: + response = await async_client.affiliates.overrides.with_raw_response.update( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + override = await response.parse() + assert_matches_type(OverrideUpdateResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_update(self, async_client: AsyncWhop) -> None: + async with async_client.affiliates.overrides.with_streaming_response.update( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + override = await response.parse() + assert_matches_type(OverrideUpdateResponse, override, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_update(self, async_client: AsyncWhop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.affiliates.overrides.with_raw_response.update( + override_id="override_id", + id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `override_id` but received ''"): + await async_client.affiliates.overrides.with_raw_response.update( + override_id="", + id="aff_xxxxxxxxxxxxxx", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncWhop) -> None: + override = await async_client.affiliates.overrides.list( + id="aff_xxxxxxxxxxxxxx", + ) + assert_matches_type(AsyncCursorPage[OverrideListResponse], override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncWhop) -> None: + override = await async_client.affiliates.overrides.list( + id="aff_xxxxxxxxxxxxxx", + after="after", + before="before", + first=42, + last=42, + override_type="standard", + ) + assert_matches_type(AsyncCursorPage[OverrideListResponse], override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncWhop) -> None: + response = await async_client.affiliates.overrides.with_raw_response.list( + id="aff_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + override = await response.parse() + assert_matches_type(AsyncCursorPage[OverrideListResponse], override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncWhop) -> None: + async with async_client.affiliates.overrides.with_streaming_response.list( + id="aff_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + override = await response.parse() + assert_matches_type(AsyncCursorPage[OverrideListResponse], override, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_list(self, async_client: AsyncWhop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.affiliates.overrides.with_raw_response.list( + id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_delete(self, async_client: AsyncWhop) -> None: + override = await async_client.affiliates.overrides.delete( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) + assert_matches_type(OverrideDeleteResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_delete(self, async_client: AsyncWhop) -> None: + response = await async_client.affiliates.overrides.with_raw_response.delete( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + override = await response.parse() + assert_matches_type(OverrideDeleteResponse, override, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncWhop) -> None: + async with async_client.affiliates.overrides.with_streaming_response.delete( + override_id="override_id", + id="aff_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + override = await response.parse() + assert_matches_type(OverrideDeleteResponse, override, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_delete(self, async_client: AsyncWhop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.affiliates.overrides.with_raw_response.delete( + override_id="override_id", + id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `override_id` but received ''"): + await async_client.affiliates.overrides.with_raw_response.delete( + override_id="", + id="aff_xxxxxxxxxxxxxx", + ) diff --git a/tests/api_resources/test_affiliates.py b/tests/api_resources/test_affiliates.py new file mode 100644 index 0000000..b4c8041 --- /dev/null +++ b/tests/api_resources/test_affiliates.py @@ -0,0 +1,456 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from whop_sdk import Whop, AsyncWhop +from tests.utils import assert_matches_type +from whop_sdk.types import ( + Affiliate, + AffiliateListResponse, + AffiliateArchiveResponse, + AffiliateUnarchiveResponse, +) +from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAffiliates: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Whop) -> None: + affiliate = client.affiliates.create( + company_id="biz_xxxxxxxxxxxxxx", + user_identifier="user_identifier", + ) + assert_matches_type(Affiliate, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Whop) -> None: + response = client.affiliates.with_raw_response.create( + company_id="biz_xxxxxxxxxxxxxx", + user_identifier="user_identifier", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + affiliate = response.parse() + assert_matches_type(Affiliate, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Whop) -> None: + with client.affiliates.with_streaming_response.create( + company_id="biz_xxxxxxxxxxxxxx", + user_identifier="user_identifier", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + affiliate = response.parse() + assert_matches_type(Affiliate, affiliate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Whop) -> None: + affiliate = client.affiliates.retrieve( + "aff_xxxxxxxxxxxxxx", + ) + assert_matches_type(Affiliate, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Whop) -> None: + response = client.affiliates.with_raw_response.retrieve( + "aff_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + affiliate = response.parse() + assert_matches_type(Affiliate, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Whop) -> None: + with client.affiliates.with_streaming_response.retrieve( + "aff_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + affiliate = response.parse() + assert_matches_type(Affiliate, affiliate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Whop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.affiliates.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Whop) -> None: + affiliate = client.affiliates.list( + company_id="biz_xxxxxxxxxxxxxx", + ) + assert_matches_type(SyncCursorPage[AffiliateListResponse], affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Whop) -> None: + affiliate = client.affiliates.list( + company_id="biz_xxxxxxxxxxxxxx", + after="after", + before="before", + direction="asc", + first=42, + last=42, + order="id", + query="query", + status="active", + ) + assert_matches_type(SyncCursorPage[AffiliateListResponse], affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Whop) -> None: + response = client.affiliates.with_raw_response.list( + company_id="biz_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + affiliate = response.parse() + assert_matches_type(SyncCursorPage[AffiliateListResponse], affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Whop) -> None: + with client.affiliates.with_streaming_response.list( + company_id="biz_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + affiliate = response.parse() + assert_matches_type(SyncCursorPage[AffiliateListResponse], affiliate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_archive(self, client: Whop) -> None: + affiliate = client.affiliates.archive( + "aff_xxxxxxxxxxxxxx", + ) + assert_matches_type(AffiliateArchiveResponse, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_archive(self, client: Whop) -> None: + response = client.affiliates.with_raw_response.archive( + "aff_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + affiliate = response.parse() + assert_matches_type(AffiliateArchiveResponse, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_archive(self, client: Whop) -> None: + with client.affiliates.with_streaming_response.archive( + "aff_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + affiliate = response.parse() + assert_matches_type(AffiliateArchiveResponse, affiliate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_archive(self, client: Whop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.affiliates.with_raw_response.archive( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_unarchive(self, client: Whop) -> None: + affiliate = client.affiliates.unarchive( + "aff_xxxxxxxxxxxxxx", + ) + assert_matches_type(AffiliateUnarchiveResponse, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_unarchive(self, client: Whop) -> None: + response = client.affiliates.with_raw_response.unarchive( + "aff_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + affiliate = response.parse() + assert_matches_type(AffiliateUnarchiveResponse, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_unarchive(self, client: Whop) -> None: + with client.affiliates.with_streaming_response.unarchive( + "aff_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + affiliate = response.parse() + assert_matches_type(AffiliateUnarchiveResponse, affiliate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_unarchive(self, client: Whop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.affiliates.with_raw_response.unarchive( + "", + ) + + +class TestAsyncAffiliates: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncWhop) -> None: + affiliate = await async_client.affiliates.create( + company_id="biz_xxxxxxxxxxxxxx", + user_identifier="user_identifier", + ) + assert_matches_type(Affiliate, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncWhop) -> None: + response = await async_client.affiliates.with_raw_response.create( + company_id="biz_xxxxxxxxxxxxxx", + user_identifier="user_identifier", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + affiliate = await response.parse() + assert_matches_type(Affiliate, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncWhop) -> None: + async with async_client.affiliates.with_streaming_response.create( + company_id="biz_xxxxxxxxxxxxxx", + user_identifier="user_identifier", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + affiliate = await response.parse() + assert_matches_type(Affiliate, affiliate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncWhop) -> None: + affiliate = await async_client.affiliates.retrieve( + "aff_xxxxxxxxxxxxxx", + ) + assert_matches_type(Affiliate, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None: + response = await async_client.affiliates.with_raw_response.retrieve( + "aff_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + affiliate = await response.parse() + assert_matches_type(Affiliate, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncWhop) -> None: + async with async_client.affiliates.with_streaming_response.retrieve( + "aff_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + affiliate = await response.parse() + assert_matches_type(Affiliate, affiliate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncWhop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.affiliates.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncWhop) -> None: + affiliate = await async_client.affiliates.list( + company_id="biz_xxxxxxxxxxxxxx", + ) + assert_matches_type(AsyncCursorPage[AffiliateListResponse], affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncWhop) -> None: + affiliate = await async_client.affiliates.list( + company_id="biz_xxxxxxxxxxxxxx", + after="after", + before="before", + direction="asc", + first=42, + last=42, + order="id", + query="query", + status="active", + ) + assert_matches_type(AsyncCursorPage[AffiliateListResponse], affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncWhop) -> None: + response = await async_client.affiliates.with_raw_response.list( + company_id="biz_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + affiliate = await response.parse() + assert_matches_type(AsyncCursorPage[AffiliateListResponse], affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncWhop) -> None: + async with async_client.affiliates.with_streaming_response.list( + company_id="biz_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + affiliate = await response.parse() + assert_matches_type(AsyncCursorPage[AffiliateListResponse], affiliate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_archive(self, async_client: AsyncWhop) -> None: + affiliate = await async_client.affiliates.archive( + "aff_xxxxxxxxxxxxxx", + ) + assert_matches_type(AffiliateArchiveResponse, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_archive(self, async_client: AsyncWhop) -> None: + response = await async_client.affiliates.with_raw_response.archive( + "aff_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + affiliate = await response.parse() + assert_matches_type(AffiliateArchiveResponse, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_archive(self, async_client: AsyncWhop) -> None: + async with async_client.affiliates.with_streaming_response.archive( + "aff_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + affiliate = await response.parse() + assert_matches_type(AffiliateArchiveResponse, affiliate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_archive(self, async_client: AsyncWhop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.affiliates.with_raw_response.archive( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_unarchive(self, async_client: AsyncWhop) -> None: + affiliate = await async_client.affiliates.unarchive( + "aff_xxxxxxxxxxxxxx", + ) + assert_matches_type(AffiliateUnarchiveResponse, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_unarchive(self, async_client: AsyncWhop) -> None: + response = await async_client.affiliates.with_raw_response.unarchive( + "aff_xxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + affiliate = await response.parse() + assert_matches_type(AffiliateUnarchiveResponse, affiliate, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_unarchive(self, async_client: AsyncWhop) -> None: + async with async_client.affiliates.with_streaming_response.unarchive( + "aff_xxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + affiliate = await response.parse() + assert_matches_type(AffiliateUnarchiveResponse, affiliate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_unarchive(self, async_client: AsyncWhop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.affiliates.with_raw_response.unarchive( + "", + ) diff --git a/tests/api_resources/test_ai_chats.py b/tests/api_resources/test_ai_chats.py index 6de8558..d4d6bc2 100644 --- a/tests/api_resources/test_ai_chats.py +++ b/tests/api_resources/test_ai_chats.py @@ -124,6 +124,7 @@ def test_method_update_with_all_params(self, client: Whop) -> None: ai_chat = client.ai_chats.update( id="aich_xxxxxxxxxxxxx", current_company_id="current_company_id", + notification_preference="all", title="title", ) assert_matches_type(AIChat, ai_chat, path=["response"]) @@ -352,6 +353,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> N ai_chat = await async_client.ai_chats.update( id="aich_xxxxxxxxxxxxx", current_company_id="current_company_id", + notification_preference="all", title="title", ) assert_matches_type(AIChat, ai_chat, path=["response"])