diff --git a/.stats.yml b/.stats.yml
index a5722ed0..61c2bc47 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1 +1 @@
-configured_endpoints: 226
+configured_endpoints: 260
diff --git a/README.md b/README.md
index f695ea0b..98667424 100644
--- a/README.md
+++ b/README.md
@@ -13,8 +13,8 @@ It is generated with [Stainless](https://www.stainless.com/).
Use the Whop MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.
-[](https://cursor.com/en-US/install-mcp?name=%40whop%2Fmcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB3aG9wL21jcCJdLCJlbnYiOnsiV0hPUF9BUElfS0VZIjoiTXkgQVBJIEtleSIsIldIT1BfV0VCSE9PS19TRUNSRVQiOiJNeSBXZWJob29rIEtleSIsIldIT1BfQVBQX0lEIjoiYXBwX3h4eHh4eHh4eHh4eHh4In19)
-[](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40whop%2Fmcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40whop%2Fmcp%22%5D%2C%22env%22%3A%7B%22WHOP_API_KEY%22%3A%22My%20API%20Key%22%2C%22WHOP_WEBHOOK_SECRET%22%3A%22My%20Webhook%20Key%22%2C%22WHOP_APP_ID%22%3A%22app_xxxxxxxxxxxxxx%22%7D%7D)
+[](https://cursor.com/en-US/install-mcp?name=%40whop%2Fmcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB3aG9wL21jcCJdLCJlbnYiOnsiV0hPUF9BUElfS0VZIjoiTXkgQVBJIEtleSIsIldIT1BfV0VCSE9PS19TRUNSRVQiOiJNeSBXZWJob29rIEtleSIsIldIT1BfQVBQX0lEIjoiYXBwX3h4eHh4eHh4eHh4eHh4IiwiV0hPUF9BUElfVkVSU0lPTiI6IjIwMjYtMDctMDEifX0)
+[](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40whop%2Fmcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40whop%2Fmcp%22%5D%2C%22env%22%3A%7B%22WHOP_API_KEY%22%3A%22My%20API%20Key%22%2C%22WHOP_WEBHOOK_SECRET%22%3A%22My%20Webhook%20Key%22%2C%22WHOP_APP_ID%22%3A%22app_xxxxxxxxxxxxxx%22%2C%22WHOP_API_VERSION%22%3A%222026-07-01%22%7D%7D)
> Note: You may need to set environment variables in your MCP client.
diff --git a/api.md b/api.md
index 8c7ec82d..ef677de4 100644
--- a/api.md
+++ b/api.md
@@ -53,7 +53,6 @@ from whop_sdk.types import (
ShipmentSubstatus,
SupportChannel,
TaxType,
- Transfer,
Visibility,
VisibilityFilter,
WhoCanCommentTypes,
@@ -126,6 +125,66 @@ Methods:
- client.products.list(\*\*params) -> SyncCursorPage[ProductListItem]
- client.products.delete(id) -> ProductDeleteResponse
+# SocialAccounts
+
+Types:
+
+```python
+from whop_sdk.types import (
+ SocialAccount,
+ SocialAccountPost,
+ SocialAccountCreateResponse,
+ SocialAccountDeleteResponse,
+ SocialAccountPostsResponse,
+)
+```
+
+Methods:
+
+- client.social_accounts.create(\*\*params) -> SocialAccountCreateResponse
+- client.social_accounts.list(\*\*params) -> SyncCursorPage[SocialAccount]
+- client.social_accounts.delete(id, \*\*params) -> SocialAccountDeleteResponse
+- client.social_accounts.posts(id, \*\*params) -> SocialAccountPostsResponse
+
+# Audiences
+
+Types:
+
+```python
+from whop_sdk.types import Audience, AudienceDeleteResponse
+```
+
+Methods:
+
+- client.audiences.create(\*\*params) -> Audience
+- client.audiences.list(\*\*params) -> SyncCursorPage[Audience]
+- client.audiences.delete(audience_id) -> AudienceDeleteResponse
+
+# People
+
+Types:
+
+```python
+from whop_sdk.types import PersonRetrieveResponse, PersonListResponse
+```
+
+Methods:
+
+- client.people.retrieve(person_id, \*\*params) -> PersonRetrieveResponse
+- client.people.list(\*\*params) -> PersonListResponse
+
+# Events
+
+Types:
+
+```python
+from whop_sdk.types import EventListResponse
+```
+
+Methods:
+
+- client.events.list(\*\*params) -> EventListResponse
+
# Companies
Types:
@@ -154,6 +213,8 @@ from whop_sdk.types import (
WebhookCreateResponse,
WebhookListResponse,
WebhookDeleteResponse,
+ ChatMessageCreatedWebhookEvent,
+ ChatReactionCreatedWebhookEvent,
CourseLessonInteractionCompletedWebhookEvent,
DisputeCreatedWebhookEvent,
DisputeUpdatedWebhookEvent,
@@ -171,9 +232,11 @@ from whop_sdk.types import (
InvoicePaidWebhookEvent,
InvoicePastDueWebhookEvent,
InvoiceVoidedWebhookEvent,
+ LedgerAccountFundsAvailableWebhookEvent,
MembershipActivatedWebhookEvent,
MembershipCancelAtPeriodEndChangedWebhookEvent,
MembershipDeactivatedWebhookEvent,
+ MembershipTrialEndingSoonWebhookEvent,
PaymentCreatedWebhookEvent,
PaymentFailedWebhookEvent,
PaymentPendingWebhookEvent,
@@ -208,7 +271,13 @@ Methods:
Types:
```python
-from whop_sdk.types import CheckoutFont, CheckoutShape, PlanListResponse, PlanDeleteResponse
+from whop_sdk.types import (
+ CheckoutFont,
+ CheckoutShape,
+ PlanListResponse,
+ PlanDeleteResponse,
+ PlanCalculateTaxResponse,
+)
```
Methods:
@@ -218,6 +287,7 @@ Methods:
- client.plans.update(id, \*\*params) -> Plan
- client.plans.list(\*\*params) -> SyncCursorPage[PlanListResponse]
- client.plans.delete(id) -> PlanDeleteResponse
+- client.plans.calculate_tax(id, \*\*params) -> PlanCalculateTaxResponse
# Entries
@@ -254,13 +324,13 @@ Methods:
Types:
```python
-from whop_sdk.types import TransferListResponse
+from whop_sdk.types import TransferCreateResponse, TransferRetrieveResponse, TransferListResponse
```
Methods:
-- client.transfers.create(\*\*params) -> Transfer
-- client.transfers.retrieve(id) -> Transfer
+- client.transfers.create(\*\*params) -> TransferCreateResponse
+- client.transfers.retrieve(id) -> TransferRetrieveResponse
- client.transfers.list(\*\*params) -> SyncCursorPage[TransferListResponse]
# LedgerAccounts
@@ -343,14 +413,20 @@ Methods:
Types:
```python
-from whop_sdk.types import CheckoutModes, CheckoutConfigurationListResponse
+from whop_sdk.types import (
+ CheckoutModes,
+ CheckoutConfigurationCreateResponse,
+ CheckoutConfigurationRetrieveResponse,
+ CheckoutConfigurationListResponse,
+)
```
Methods:
-- client.checkout_configurations.create(\*\*params) -> CheckoutConfiguration
-- client.checkout_configurations.retrieve(id) -> CheckoutConfiguration
+- client.checkout_configurations.create(\*\*params) -> CheckoutConfigurationCreateResponse
+- client.checkout_configurations.retrieve(id) -> CheckoutConfigurationRetrieveResponse
- client.checkout_configurations.list(\*\*params) -> SyncCursorPage[CheckoutConfigurationListResponse]
+- client.checkout_configurations.delete(id) -> None
# Messages
@@ -387,15 +463,16 @@ Methods:
Types:
```python
-from whop_sdk.types import User, UserListResponse, UserCheckAccessResponse
+from whop_sdk.types import User, UserCheckAccessResponse
```
Methods:
- client.users.retrieve(id, \*\*params) -> User
- client.users.update(id, \*\*params) -> User
-- client.users.list(\*\*params) -> SyncCursorPage[UserListResponse]
+- client.users.list(\*\*params) -> SyncCursorPage[User]
- client.users.check_access(resource_id, \*, id) -> UserCheckAccessResponse
+- client.users.update_me(\*\*params) -> User
# Payments
@@ -708,7 +785,7 @@ Methods:
Types:
```python
-from whop_sdk.types import Account, AccountSocialLink, AccountListResponse
+from whop_sdk.types import Account, AccountSocialLink
```
Methods:
@@ -716,38 +793,110 @@ Methods:
- client.accounts.create(\*\*params) -> Account
- client.accounts.retrieve(account_id) -> Account
- client.accounts.update(account_id, \*\*params) -> Account
-- client.accounts.list(\*\*params) -> AccountListResponse
+- client.accounts.list(\*\*params) -> SyncCursorPage[Account]
- client.accounts.me() -> Account
-# Wallets
+# FinancialActivity
Types:
```python
-from whop_sdk.types import (
- AccountWallet,
- WalletListResponse,
- WalletBalanceResponse,
- WalletSendResponse,
+from whop_sdk.types import FinancialActivityListResponse
+```
+
+Methods:
+
+- client.financial_activity.list(\*\*params) -> FinancialActivityListResponse
+
+# Stats
+
+Types:
+
+```python
+from whop_sdk.types import StatRetrieveResponse, StatListResponse
+```
+
+Methods:
+
+- client.stats.retrieve(metric, \*\*params) -> StatRetrieveResponse
+- client.stats.list() -> StatListResponse
+
+# Payouts
+
+Types:
+
+```python
+from whop_sdk.types import PayoutListResponse
+```
+
+Methods:
+
+- client.payouts.list(\*\*params) -> SyncCursorPage[PayoutListResponse]
+
+# Referrals
+
+## Businesses
+
+Types:
+
+```python
+from whop_sdk.types.referrals import (
+ BusinessRetrieveResponse,
+ BusinessListResponse,
+ BusinessListEarningsResponse,
)
```
Methods:
-- client.wallets.list() -> WalletListResponse
-- client.wallets.balance(account_id) -> WalletBalanceResponse
-- client.wallets.send(account_id, \*\*params) -> WalletSendResponse
+- client.referrals.businesses.retrieve(id) -> BusinessRetrieveResponse
+- client.referrals.businesses.list(\*\*params) -> SyncCursorPage[BusinessListResponse]
+- client.referrals.businesses.list_earnings(\*\*params) -> SyncCursorPage[BusinessListEarningsResponse]
+
+### Earnings
+
+Types:
+
+```python
+from whop_sdk.types.referrals.businesses import EarningListResponse
+```
+
+Methods:
+
+- client.referrals.businesses.earnings.list(id, \*\*params) -> SyncCursorPage[EarningListResponse]
+
+# Cards
+
+Types:
+
+```python
+from whop_sdk.types import CardCreateResponse, CardRetrieveResponse, CardListResponse
+```
+
+Methods:
+
+- client.cards.create(\*\*params) -> CardCreateResponse
+- client.cards.retrieve(card_id, \*\*params) -> CardRetrieveResponse
+- client.cards.list(\*\*params) -> CardListResponse
# Swaps
Types:
```python
-from whop_sdk.types import SwapCreateQuoteResponse
+from whop_sdk.types import (
+ SwapCreateResponse,
+ SwapRetrieveResponse,
+ SwapListResponse,
+ SwapCreateQuoteResponse,
+)
```
Methods:
+- client.swaps.create(\*\*params) -> SwapCreateResponse
+- client.swaps.retrieve(id) -> SwapRetrieveResponse
+- client.swaps.list(\*\*params) -> SwapListResponse
- client.swaps.create_quote(\*\*params) -> SwapCreateQuoteResponse
# Deposits
@@ -755,12 +904,13 @@ Methods:
Types:
```python
-from whop_sdk.types import DepositCreateResponse
+from whop_sdk.types import DepositCreateResponse, DepositListResponse
```
Methods:
- client.deposits.create(\*\*params) -> DepositCreateResponse
+- client.deposits.list(\*\*params) -> DepositListResponse
# SetupIntents
@@ -832,15 +982,21 @@ Types:
from whop_sdk.types import (
VerificationErrorCode,
VerificationStatus,
+ VerificationCreateResponse,
VerificationRetrieveResponse,
+ VerificationUpdateResponse,
VerificationListResponse,
+ VerificationDeleteResponse,
)
```
Methods:
-- client.verifications.retrieve(id) -> VerificationRetrieveResponse
-- client.verifications.list(\*\*params) -> SyncCursorPage[VerificationListResponse]
+- client.verifications.create(\*\*params) -> VerificationCreateResponse
+- client.verifications.retrieve(verification_id) -> VerificationRetrieveResponse
+- client.verifications.update(verification_id, \*\*params) -> VerificationUpdateResponse
+- client.verifications.list(\*\*params) -> VerificationListResponse
+- client.verifications.delete(verification_id) -> VerificationDeleteResponse
# Leads
@@ -1068,14 +1224,16 @@ Methods:
Types:
```python
-from whop_sdk.types import AdCampaign, AdCampaignPlatform, AdCampaignStatus, AdCampaignListResponse
+from whop_sdk.types import AdCampaign, AdCampaignDeleteResponse
```
Methods:
-- client.ad_campaigns.retrieve(id) -> AdCampaign
+- client.ad_campaigns.create(\*\*params) -> AdCampaign
+- client.ad_campaigns.retrieve(id, \*\*params) -> AdCampaign
- client.ad_campaigns.update(id, \*\*params) -> AdCampaign
-- client.ad_campaigns.list(\*\*params) -> SyncCursorPage[AdCampaignListResponse]
+- client.ad_campaigns.list(\*\*params) -> SyncCursorPage[AdCampaign]
+- client.ad_campaigns.delete(id) -> AdCampaignDeleteResponse
- client.ad_campaigns.pause(id) -> AdCampaign
- client.ad_campaigns.unpause(id) -> AdCampaign
@@ -1084,20 +1242,15 @@ Methods:
Types:
```python
-from whop_sdk.types import (
- AdBudgetType,
- AdGroup,
- AdGroupStatus,
- AdGroupListResponse,
- AdGroupDeleteResponse,
-)
+from whop_sdk.types import AdGroup, AdGroupDeleteResponse
```
Methods:
-- client.ad_groups.retrieve(id) -> AdGroup
+- client.ad_groups.create(\*\*params) -> AdGroup
+- client.ad_groups.retrieve(id, \*\*params) -> AdGroup
- client.ad_groups.update(id, \*\*params) -> AdGroup
-- client.ad_groups.list(\*\*params) -> SyncCursorPage[AdGroupListResponse]
+- client.ad_groups.list(\*\*params) -> SyncCursorPage[AdGroup]
- client.ad_groups.delete(id) -> AdGroupDeleteResponse
- client.ad_groups.pause(id) -> AdGroup
- client.ad_groups.unpause(id) -> AdGroup
@@ -1107,13 +1260,16 @@ Methods:
Types:
```python
-from whop_sdk.types import Ad, ExternalAdStatus, AdListResponse
+from whop_sdk.types import Ad, AdDeleteResponse
```
Methods:
-- client.ads.retrieve(id) -> Ad
-- client.ads.list(\*\*params) -> SyncCursorPage[AdListResponse]
+- client.ads.create(\*\*params) -> Ad
+- client.ads.retrieve(id, \*\*params) -> Ad
+- client.ads.update(id, \*\*params) -> Ad
+- client.ads.list(\*\*params) -> SyncCursorPage[Ad]
+- client.ads.delete(id) -> AdDeleteResponse
- client.ads.pause(id) -> Ad
- client.ads.unpause(id) -> Ad
diff --git a/src/whop_sdk/_client.py b/src/whop_sdk/_client.py
index 81df0bfb..8ff06c15 100644
--- a/src/whop_sdk/_client.py
+++ b/src/whop_sdk/_client.py
@@ -38,19 +38,23 @@
from .resources import (
ads,
apps,
+ cards,
files,
leads,
plans,
+ stats,
swaps,
users,
+ events,
forums,
+ people,
topups,
courses,
entries,
members,
+ payouts,
refunds,
reviews,
- wallets,
accounts,
ai_chats,
bounties,
@@ -62,8 +66,10 @@
products,
webhooks,
ad_groups,
+ audiences,
companies,
reactions,
+ referrals,
shipments,
transfers,
ad_reports,
@@ -93,8 +99,10 @@
ledger_accounts,
payment_methods,
payout_accounts,
+ social_accounts,
authorized_users,
support_channels,
+ financial_activity,
checkout_configurations,
resolution_center_cases,
company_token_transactions,
@@ -102,19 +110,23 @@
)
from .resources.ads import AdsResource, AsyncAdsResource
from .resources.apps import AppsResource, AsyncAppsResource
+ from .resources.cards import CardsResource, AsyncCardsResource
from .resources.files import FilesResource, AsyncFilesResource
from .resources.leads import LeadsResource, AsyncLeadsResource
from .resources.plans import PlansResource, AsyncPlansResource
+ from .resources.stats import StatsResource, AsyncStatsResource
from .resources.swaps import SwapsResource, AsyncSwapsResource
from .resources.users import UsersResource, AsyncUsersResource
+ from .resources.events import EventsResource, AsyncEventsResource
from .resources.forums import ForumsResource, AsyncForumsResource
+ from .resources.people import PeopleResource, AsyncPeopleResource
from .resources.topups import TopupsResource, AsyncTopupsResource
from .resources.courses import CoursesResource, AsyncCoursesResource
from .resources.entries import EntriesResource, AsyncEntriesResource
from .resources.members import MembersResource, AsyncMembersResource
+ from .resources.payouts import PayoutsResource, AsyncPayoutsResource
from .resources.refunds import RefundsResource, AsyncRefundsResource
from .resources.reviews import ReviewsResource, AsyncReviewsResource
- from .resources.wallets import WalletsResource, AsyncWalletsResource
from .resources.accounts import AccountsResource, AsyncAccountsResource
from .resources.ai_chats import AIChatsResource, AsyncAIChatsResource
from .resources.bounties import BountiesResource, AsyncBountiesResource
@@ -126,6 +138,7 @@
from .resources.products import ProductsResource, AsyncProductsResource
from .resources.webhooks import WebhooksResource, AsyncWebhooksResource
from .resources.ad_groups import AdGroupsResource, AsyncAdGroupsResource
+ from .resources.audiences import AudiencesResource, AsyncAudiencesResource
from .resources.companies import CompaniesResource, AsyncCompaniesResource
from .resources.reactions import ReactionsResource, AsyncReactionsResource
from .resources.shipments import ShipmentsResource, AsyncShipmentsResource
@@ -156,8 +169,11 @@
from .resources.ledger_accounts import LedgerAccountsResource, AsyncLedgerAccountsResource
from .resources.payment_methods import PaymentMethodsResource, AsyncPaymentMethodsResource
from .resources.payout_accounts import PayoutAccountsResource, AsyncPayoutAccountsResource
+ from .resources.social_accounts import SocialAccountsResource, AsyncSocialAccountsResource
from .resources.authorized_users import AuthorizedUsersResource, AsyncAuthorizedUsersResource
from .resources.support_channels import SupportChannelsResource, AsyncSupportChannelsResource
+ from .resources.financial_activity import FinancialActivityResource, AsyncFinancialActivityResource
+ from .resources.referrals.referrals import ReferralsResource, AsyncReferralsResource
from .resources.affiliates.affiliates import AffiliatesResource, AsyncAffiliatesResource
from .resources.checkout_configurations import CheckoutConfigurationsResource, AsyncCheckoutConfigurationsResource
from .resources.resolution_center_cases import ResolutionCenterCasesResource, AsyncResolutionCenterCasesResource
@@ -178,6 +194,7 @@ class Whop(SyncAPIClient):
api_key: str
webhook_key: str | None
app_id: str | None
+ version: str | None
def __init__(
self,
@@ -185,6 +202,7 @@ def __init__(
api_key: str | None = None,
webhook_key: str | None = None,
app_id: str | None = None,
+ version: str | None = None,
base_url: str | httpx.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
max_retries: int = DEFAULT_MAX_RETRIES,
@@ -210,6 +228,7 @@ def __init__(
- `api_key` from `WHOP_API_KEY`
- `webhook_key` from `WHOP_WEBHOOK_SECRET`
- `app_id` from `WHOP_APP_ID`
+ - `version` from `WHOP_API_VERSION`
"""
if api_key is None:
api_key = os.environ.get("WHOP_API_KEY")
@@ -227,6 +246,10 @@ def __init__(
app_id = os.environ.get("WHOP_APP_ID")
self.app_id = app_id
+ if version is None:
+ version = os.environ.get("WHOP_API_VERSION") or "2026-07-01"
+ self.version = version
+
if base_url is None:
base_url = os.environ.get("WHOP_BASE_URL")
if base_url is None:
@@ -280,6 +303,30 @@ def products(self) -> ProductsResource:
return ProductsResource(self)
+ @cached_property
+ def social_accounts(self) -> SocialAccountsResource:
+ from .resources.social_accounts import SocialAccountsResource
+
+ return SocialAccountsResource(self)
+
+ @cached_property
+ def audiences(self) -> AudiencesResource:
+ from .resources.audiences import AudiencesResource
+
+ return AudiencesResource(self)
+
+ @cached_property
+ def people(self) -> PeopleResource:
+ from .resources.people import PeopleResource
+
+ return PeopleResource(self)
+
+ @cached_property
+ def events(self) -> EventsResource:
+ from .resources.events import EventsResource
+
+ return EventsResource(self)
+
@cached_property
def companies(self) -> CompaniesResource:
"""Companies"""
@@ -296,7 +343,6 @@ def webhooks(self) -> WebhooksResource:
@cached_property
def plans(self) -> PlansResource:
- """Plans"""
from .resources.plans import PlansResource
return PlansResource(self)
@@ -317,7 +363,6 @@ def forum_posts(self) -> ForumPostsResource:
@cached_property
def transfers(self) -> TransfersResource:
- """Transfers"""
from .resources.transfers import TransfersResource
return TransfersResource(self)
@@ -359,7 +404,6 @@ def shipments(self) -> ShipmentsResource:
@cached_property
def checkout_configurations(self) -> CheckoutConfigurationsResource:
- """Checkout configurations"""
from .resources.checkout_configurations import CheckoutConfigurationsResource
return CheckoutConfigurationsResource(self)
@@ -380,7 +424,6 @@ def chat_channels(self) -> ChatChannelsResource:
@cached_property
def users(self) -> UsersResource:
- """Users"""
from .resources.users import UsersResource
return UsersResource(self)
@@ -518,10 +561,35 @@ def accounts(self) -> AccountsResource:
return AccountsResource(self)
@cached_property
- def wallets(self) -> WalletsResource:
- from .resources.wallets import WalletsResource
+ def financial_activity(self) -> FinancialActivityResource:
+ from .resources.financial_activity import FinancialActivityResource
+
+ return FinancialActivityResource(self)
+
+ @cached_property
+ def stats(self) -> StatsResource:
+ """Stats"""
+ from .resources.stats import StatsResource
+
+ return StatsResource(self)
+
+ @cached_property
+ def payouts(self) -> PayoutsResource:
+ from .resources.payouts import PayoutsResource
- return WalletsResource(self)
+ return PayoutsResource(self)
+
+ @cached_property
+ def referrals(self) -> ReferralsResource:
+ from .resources.referrals import ReferralsResource
+
+ return ReferralsResource(self)
+
+ @cached_property
+ def cards(self) -> CardsResource:
+ from .resources.cards import CardsResource
+
+ return CardsResource(self)
@cached_property
def swaps(self) -> SwapsResource:
@@ -656,21 +724,18 @@ def bounties(self) -> BountiesResource:
@cached_property
def ad_campaigns(self) -> AdCampaignsResource:
- """Ad campaigns"""
from .resources.ad_campaigns import AdCampaignsResource
return AdCampaignsResource(self)
@cached_property
def ad_groups(self) -> AdGroupsResource:
- """Ad groups"""
from .resources.ad_groups import AdGroupsResource
return AdGroupsResource(self)
@cached_property
def ads(self) -> AdsResource:
- """Ads"""
from .resources.ads import AdsResource
return AdsResource(self)
@@ -715,6 +780,7 @@ def default_headers(self) -> dict[str, str | Omit]:
**super().default_headers,
"X-Stainless-Async": "false",
"X-Whop-App-Id": self.app_id if self.app_id is not None else Omit(),
+ "Api-Version-Date": self.version if self.version is not None else Omit(),
**self._custom_headers,
}
@@ -724,6 +790,7 @@ def copy(
api_key: str | None = None,
webhook_key: str | None = None,
app_id: str | None = None,
+ version: str | None = None,
base_url: str | httpx.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
http_client: httpx.Client | None = None,
@@ -760,6 +827,7 @@ def copy(
api_key=api_key or self.api_key,
webhook_key=webhook_key or self.webhook_key,
app_id=app_id or self.app_id,
+ version=version or self.version,
base_url=base_url or self.base_url,
timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
http_client=http_client,
@@ -812,6 +880,7 @@ class AsyncWhop(AsyncAPIClient):
api_key: str
webhook_key: str | None
app_id: str | None
+ version: str | None
def __init__(
self,
@@ -819,6 +888,7 @@ def __init__(
api_key: str | None = None,
webhook_key: str | None = None,
app_id: str | None = None,
+ version: str | None = None,
base_url: str | httpx.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
max_retries: int = DEFAULT_MAX_RETRIES,
@@ -844,6 +914,7 @@ def __init__(
- `api_key` from `WHOP_API_KEY`
- `webhook_key` from `WHOP_WEBHOOK_SECRET`
- `app_id` from `WHOP_APP_ID`
+ - `version` from `WHOP_API_VERSION`
"""
if api_key is None:
api_key = os.environ.get("WHOP_API_KEY")
@@ -861,6 +932,10 @@ def __init__(
app_id = os.environ.get("WHOP_APP_ID")
self.app_id = app_id
+ if version is None:
+ version = os.environ.get("WHOP_API_VERSION") or "2026-07-01"
+ self.version = version
+
if base_url is None:
base_url = os.environ.get("WHOP_BASE_URL")
if base_url is None:
@@ -914,6 +989,30 @@ def products(self) -> AsyncProductsResource:
return AsyncProductsResource(self)
+ @cached_property
+ def social_accounts(self) -> AsyncSocialAccountsResource:
+ from .resources.social_accounts import AsyncSocialAccountsResource
+
+ return AsyncSocialAccountsResource(self)
+
+ @cached_property
+ def audiences(self) -> AsyncAudiencesResource:
+ from .resources.audiences import AsyncAudiencesResource
+
+ return AsyncAudiencesResource(self)
+
+ @cached_property
+ def people(self) -> AsyncPeopleResource:
+ from .resources.people import AsyncPeopleResource
+
+ return AsyncPeopleResource(self)
+
+ @cached_property
+ def events(self) -> AsyncEventsResource:
+ from .resources.events import AsyncEventsResource
+
+ return AsyncEventsResource(self)
+
@cached_property
def companies(self) -> AsyncCompaniesResource:
"""Companies"""
@@ -930,7 +1029,6 @@ def webhooks(self) -> AsyncWebhooksResource:
@cached_property
def plans(self) -> AsyncPlansResource:
- """Plans"""
from .resources.plans import AsyncPlansResource
return AsyncPlansResource(self)
@@ -951,7 +1049,6 @@ def forum_posts(self) -> AsyncForumPostsResource:
@cached_property
def transfers(self) -> AsyncTransfersResource:
- """Transfers"""
from .resources.transfers import AsyncTransfersResource
return AsyncTransfersResource(self)
@@ -993,7 +1090,6 @@ def shipments(self) -> AsyncShipmentsResource:
@cached_property
def checkout_configurations(self) -> AsyncCheckoutConfigurationsResource:
- """Checkout configurations"""
from .resources.checkout_configurations import AsyncCheckoutConfigurationsResource
return AsyncCheckoutConfigurationsResource(self)
@@ -1014,7 +1110,6 @@ def chat_channels(self) -> AsyncChatChannelsResource:
@cached_property
def users(self) -> AsyncUsersResource:
- """Users"""
from .resources.users import AsyncUsersResource
return AsyncUsersResource(self)
@@ -1152,10 +1247,35 @@ def accounts(self) -> AsyncAccountsResource:
return AsyncAccountsResource(self)
@cached_property
- def wallets(self) -> AsyncWalletsResource:
- from .resources.wallets import AsyncWalletsResource
+ def financial_activity(self) -> AsyncFinancialActivityResource:
+ from .resources.financial_activity import AsyncFinancialActivityResource
+
+ return AsyncFinancialActivityResource(self)
+
+ @cached_property
+ def stats(self) -> AsyncStatsResource:
+ """Stats"""
+ from .resources.stats import AsyncStatsResource
+
+ return AsyncStatsResource(self)
+
+ @cached_property
+ def payouts(self) -> AsyncPayoutsResource:
+ from .resources.payouts import AsyncPayoutsResource
+
+ return AsyncPayoutsResource(self)
+
+ @cached_property
+ def referrals(self) -> AsyncReferralsResource:
+ from .resources.referrals import AsyncReferralsResource
- return AsyncWalletsResource(self)
+ return AsyncReferralsResource(self)
+
+ @cached_property
+ def cards(self) -> AsyncCardsResource:
+ from .resources.cards import AsyncCardsResource
+
+ return AsyncCardsResource(self)
@cached_property
def swaps(self) -> AsyncSwapsResource:
@@ -1290,21 +1410,18 @@ def bounties(self) -> AsyncBountiesResource:
@cached_property
def ad_campaigns(self) -> AsyncAdCampaignsResource:
- """Ad campaigns"""
from .resources.ad_campaigns import AsyncAdCampaignsResource
return AsyncAdCampaignsResource(self)
@cached_property
def ad_groups(self) -> AsyncAdGroupsResource:
- """Ad groups"""
from .resources.ad_groups import AsyncAdGroupsResource
return AsyncAdGroupsResource(self)
@cached_property
def ads(self) -> AsyncAdsResource:
- """Ads"""
from .resources.ads import AsyncAdsResource
return AsyncAdsResource(self)
@@ -1349,6 +1466,7 @@ def default_headers(self) -> dict[str, str | Omit]:
**super().default_headers,
"X-Stainless-Async": f"async:{get_async_library()}",
"X-Whop-App-Id": self.app_id if self.app_id is not None else Omit(),
+ "Api-Version-Date": self.version if self.version is not None else Omit(),
**self._custom_headers,
}
@@ -1358,6 +1476,7 @@ def copy(
api_key: str | None = None,
webhook_key: str | None = None,
app_id: str | None = None,
+ version: str | None = None,
base_url: str | httpx.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
http_client: httpx.AsyncClient | None = None,
@@ -1394,6 +1513,7 @@ def copy(
api_key=api_key or self.api_key,
webhook_key=webhook_key or self.webhook_key,
app_id=app_id or self.app_id,
+ version=version or self.version,
base_url=base_url or self.base_url,
timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
http_client=http_client,
@@ -1475,6 +1595,30 @@ def products(self) -> products.ProductsResourceWithRawResponse:
return ProductsResourceWithRawResponse(self._client.products)
+ @cached_property
+ def social_accounts(self) -> social_accounts.SocialAccountsResourceWithRawResponse:
+ from .resources.social_accounts import SocialAccountsResourceWithRawResponse
+
+ return SocialAccountsResourceWithRawResponse(self._client.social_accounts)
+
+ @cached_property
+ def audiences(self) -> audiences.AudiencesResourceWithRawResponse:
+ from .resources.audiences import AudiencesResourceWithRawResponse
+
+ return AudiencesResourceWithRawResponse(self._client.audiences)
+
+ @cached_property
+ def people(self) -> people.PeopleResourceWithRawResponse:
+ from .resources.people import PeopleResourceWithRawResponse
+
+ return PeopleResourceWithRawResponse(self._client.people)
+
+ @cached_property
+ def events(self) -> events.EventsResourceWithRawResponse:
+ from .resources.events import EventsResourceWithRawResponse
+
+ return EventsResourceWithRawResponse(self._client.events)
+
@cached_property
def companies(self) -> companies.CompaniesResourceWithRawResponse:
"""Companies"""
@@ -1491,7 +1635,6 @@ def webhooks(self) -> webhooks.WebhooksResourceWithRawResponse:
@cached_property
def plans(self) -> plans.PlansResourceWithRawResponse:
- """Plans"""
from .resources.plans import PlansResourceWithRawResponse
return PlansResourceWithRawResponse(self._client.plans)
@@ -1512,7 +1655,6 @@ def forum_posts(self) -> forum_posts.ForumPostsResourceWithRawResponse:
@cached_property
def transfers(self) -> transfers.TransfersResourceWithRawResponse:
- """Transfers"""
from .resources.transfers import TransfersResourceWithRawResponse
return TransfersResourceWithRawResponse(self._client.transfers)
@@ -1554,7 +1696,6 @@ def shipments(self) -> shipments.ShipmentsResourceWithRawResponse:
@cached_property
def checkout_configurations(self) -> checkout_configurations.CheckoutConfigurationsResourceWithRawResponse:
- """Checkout configurations"""
from .resources.checkout_configurations import CheckoutConfigurationsResourceWithRawResponse
return CheckoutConfigurationsResourceWithRawResponse(self._client.checkout_configurations)
@@ -1575,7 +1716,6 @@ def chat_channels(self) -> chat_channels.ChatChannelsResourceWithRawResponse:
@cached_property
def users(self) -> users.UsersResourceWithRawResponse:
- """Users"""
from .resources.users import UsersResourceWithRawResponse
return UsersResourceWithRawResponse(self._client.users)
@@ -1713,10 +1853,35 @@ def accounts(self) -> accounts.AccountsResourceWithRawResponse:
return AccountsResourceWithRawResponse(self._client.accounts)
@cached_property
- def wallets(self) -> wallets.WalletsResourceWithRawResponse:
- from .resources.wallets import WalletsResourceWithRawResponse
+ def financial_activity(self) -> financial_activity.FinancialActivityResourceWithRawResponse:
+ from .resources.financial_activity import FinancialActivityResourceWithRawResponse
+
+ return FinancialActivityResourceWithRawResponse(self._client.financial_activity)
+
+ @cached_property
+ def stats(self) -> stats.StatsResourceWithRawResponse:
+ """Stats"""
+ from .resources.stats import StatsResourceWithRawResponse
+
+ return StatsResourceWithRawResponse(self._client.stats)
+
+ @cached_property
+ def payouts(self) -> payouts.PayoutsResourceWithRawResponse:
+ from .resources.payouts import PayoutsResourceWithRawResponse
+
+ return PayoutsResourceWithRawResponse(self._client.payouts)
+
+ @cached_property
+ def referrals(self) -> referrals.ReferralsResourceWithRawResponse:
+ from .resources.referrals import ReferralsResourceWithRawResponse
+
+ return ReferralsResourceWithRawResponse(self._client.referrals)
+
+ @cached_property
+ def cards(self) -> cards.CardsResourceWithRawResponse:
+ from .resources.cards import CardsResourceWithRawResponse
- return WalletsResourceWithRawResponse(self._client.wallets)
+ return CardsResourceWithRawResponse(self._client.cards)
@cached_property
def swaps(self) -> swaps.SwapsResourceWithRawResponse:
@@ -1851,21 +2016,18 @@ def bounties(self) -> bounties.BountiesResourceWithRawResponse:
@cached_property
def ad_campaigns(self) -> ad_campaigns.AdCampaignsResourceWithRawResponse:
- """Ad campaigns"""
from .resources.ad_campaigns import AdCampaignsResourceWithRawResponse
return AdCampaignsResourceWithRawResponse(self._client.ad_campaigns)
@cached_property
def ad_groups(self) -> ad_groups.AdGroupsResourceWithRawResponse:
- """Ad groups"""
from .resources.ad_groups import AdGroupsResourceWithRawResponse
return AdGroupsResourceWithRawResponse(self._client.ad_groups)
@cached_property
def ads(self) -> ads.AdsResourceWithRawResponse:
- """Ads"""
from .resources.ads import AdsResourceWithRawResponse
return AdsResourceWithRawResponse(self._client.ads)
@@ -1921,6 +2083,30 @@ def products(self) -> products.AsyncProductsResourceWithRawResponse:
return AsyncProductsResourceWithRawResponse(self._client.products)
+ @cached_property
+ def social_accounts(self) -> social_accounts.AsyncSocialAccountsResourceWithRawResponse:
+ from .resources.social_accounts import AsyncSocialAccountsResourceWithRawResponse
+
+ return AsyncSocialAccountsResourceWithRawResponse(self._client.social_accounts)
+
+ @cached_property
+ def audiences(self) -> audiences.AsyncAudiencesResourceWithRawResponse:
+ from .resources.audiences import AsyncAudiencesResourceWithRawResponse
+
+ return AsyncAudiencesResourceWithRawResponse(self._client.audiences)
+
+ @cached_property
+ def people(self) -> people.AsyncPeopleResourceWithRawResponse:
+ from .resources.people import AsyncPeopleResourceWithRawResponse
+
+ return AsyncPeopleResourceWithRawResponse(self._client.people)
+
+ @cached_property
+ def events(self) -> events.AsyncEventsResourceWithRawResponse:
+ from .resources.events import AsyncEventsResourceWithRawResponse
+
+ return AsyncEventsResourceWithRawResponse(self._client.events)
+
@cached_property
def companies(self) -> companies.AsyncCompaniesResourceWithRawResponse:
"""Companies"""
@@ -1937,7 +2123,6 @@ def webhooks(self) -> webhooks.AsyncWebhooksResourceWithRawResponse:
@cached_property
def plans(self) -> plans.AsyncPlansResourceWithRawResponse:
- """Plans"""
from .resources.plans import AsyncPlansResourceWithRawResponse
return AsyncPlansResourceWithRawResponse(self._client.plans)
@@ -1958,7 +2143,6 @@ def forum_posts(self) -> forum_posts.AsyncForumPostsResourceWithRawResponse:
@cached_property
def transfers(self) -> transfers.AsyncTransfersResourceWithRawResponse:
- """Transfers"""
from .resources.transfers import AsyncTransfersResourceWithRawResponse
return AsyncTransfersResourceWithRawResponse(self._client.transfers)
@@ -2000,7 +2184,6 @@ def shipments(self) -> shipments.AsyncShipmentsResourceWithRawResponse:
@cached_property
def checkout_configurations(self) -> checkout_configurations.AsyncCheckoutConfigurationsResourceWithRawResponse:
- """Checkout configurations"""
from .resources.checkout_configurations import AsyncCheckoutConfigurationsResourceWithRawResponse
return AsyncCheckoutConfigurationsResourceWithRawResponse(self._client.checkout_configurations)
@@ -2021,7 +2204,6 @@ def chat_channels(self) -> chat_channels.AsyncChatChannelsResourceWithRawRespons
@cached_property
def users(self) -> users.AsyncUsersResourceWithRawResponse:
- """Users"""
from .resources.users import AsyncUsersResourceWithRawResponse
return AsyncUsersResourceWithRawResponse(self._client.users)
@@ -2159,10 +2341,35 @@ def accounts(self) -> accounts.AsyncAccountsResourceWithRawResponse:
return AsyncAccountsResourceWithRawResponse(self._client.accounts)
@cached_property
- def wallets(self) -> wallets.AsyncWalletsResourceWithRawResponse:
- from .resources.wallets import AsyncWalletsResourceWithRawResponse
+ def financial_activity(self) -> financial_activity.AsyncFinancialActivityResourceWithRawResponse:
+ from .resources.financial_activity import AsyncFinancialActivityResourceWithRawResponse
+
+ return AsyncFinancialActivityResourceWithRawResponse(self._client.financial_activity)
+
+ @cached_property
+ def stats(self) -> stats.AsyncStatsResourceWithRawResponse:
+ """Stats"""
+ from .resources.stats import AsyncStatsResourceWithRawResponse
+
+ return AsyncStatsResourceWithRawResponse(self._client.stats)
+
+ @cached_property
+ def payouts(self) -> payouts.AsyncPayoutsResourceWithRawResponse:
+ from .resources.payouts import AsyncPayoutsResourceWithRawResponse
- return AsyncWalletsResourceWithRawResponse(self._client.wallets)
+ return AsyncPayoutsResourceWithRawResponse(self._client.payouts)
+
+ @cached_property
+ def referrals(self) -> referrals.AsyncReferralsResourceWithRawResponse:
+ from .resources.referrals import AsyncReferralsResourceWithRawResponse
+
+ return AsyncReferralsResourceWithRawResponse(self._client.referrals)
+
+ @cached_property
+ def cards(self) -> cards.AsyncCardsResourceWithRawResponse:
+ from .resources.cards import AsyncCardsResourceWithRawResponse
+
+ return AsyncCardsResourceWithRawResponse(self._client.cards)
@cached_property
def swaps(self) -> swaps.AsyncSwapsResourceWithRawResponse:
@@ -2299,21 +2506,18 @@ def bounties(self) -> bounties.AsyncBountiesResourceWithRawResponse:
@cached_property
def ad_campaigns(self) -> ad_campaigns.AsyncAdCampaignsResourceWithRawResponse:
- """Ad campaigns"""
from .resources.ad_campaigns import AsyncAdCampaignsResourceWithRawResponse
return AsyncAdCampaignsResourceWithRawResponse(self._client.ad_campaigns)
@cached_property
def ad_groups(self) -> ad_groups.AsyncAdGroupsResourceWithRawResponse:
- """Ad groups"""
from .resources.ad_groups import AsyncAdGroupsResourceWithRawResponse
return AsyncAdGroupsResourceWithRawResponse(self._client.ad_groups)
@cached_property
def ads(self) -> ads.AsyncAdsResourceWithRawResponse:
- """Ads"""
from .resources.ads import AsyncAdsResourceWithRawResponse
return AsyncAdsResourceWithRawResponse(self._client.ads)
@@ -2369,6 +2573,30 @@ def products(self) -> products.ProductsResourceWithStreamingResponse:
return ProductsResourceWithStreamingResponse(self._client.products)
+ @cached_property
+ def social_accounts(self) -> social_accounts.SocialAccountsResourceWithStreamingResponse:
+ from .resources.social_accounts import SocialAccountsResourceWithStreamingResponse
+
+ return SocialAccountsResourceWithStreamingResponse(self._client.social_accounts)
+
+ @cached_property
+ def audiences(self) -> audiences.AudiencesResourceWithStreamingResponse:
+ from .resources.audiences import AudiencesResourceWithStreamingResponse
+
+ return AudiencesResourceWithStreamingResponse(self._client.audiences)
+
+ @cached_property
+ def people(self) -> people.PeopleResourceWithStreamingResponse:
+ from .resources.people import PeopleResourceWithStreamingResponse
+
+ return PeopleResourceWithStreamingResponse(self._client.people)
+
+ @cached_property
+ def events(self) -> events.EventsResourceWithStreamingResponse:
+ from .resources.events import EventsResourceWithStreamingResponse
+
+ return EventsResourceWithStreamingResponse(self._client.events)
+
@cached_property
def companies(self) -> companies.CompaniesResourceWithStreamingResponse:
"""Companies"""
@@ -2385,7 +2613,6 @@ def webhooks(self) -> webhooks.WebhooksResourceWithStreamingResponse:
@cached_property
def plans(self) -> plans.PlansResourceWithStreamingResponse:
- """Plans"""
from .resources.plans import PlansResourceWithStreamingResponse
return PlansResourceWithStreamingResponse(self._client.plans)
@@ -2406,7 +2633,6 @@ def forum_posts(self) -> forum_posts.ForumPostsResourceWithStreamingResponse:
@cached_property
def transfers(self) -> transfers.TransfersResourceWithStreamingResponse:
- """Transfers"""
from .resources.transfers import TransfersResourceWithStreamingResponse
return TransfersResourceWithStreamingResponse(self._client.transfers)
@@ -2448,7 +2674,6 @@ def shipments(self) -> shipments.ShipmentsResourceWithStreamingResponse:
@cached_property
def checkout_configurations(self) -> checkout_configurations.CheckoutConfigurationsResourceWithStreamingResponse:
- """Checkout configurations"""
from .resources.checkout_configurations import CheckoutConfigurationsResourceWithStreamingResponse
return CheckoutConfigurationsResourceWithStreamingResponse(self._client.checkout_configurations)
@@ -2469,7 +2694,6 @@ def chat_channels(self) -> chat_channels.ChatChannelsResourceWithStreamingRespon
@cached_property
def users(self) -> users.UsersResourceWithStreamingResponse:
- """Users"""
from .resources.users import UsersResourceWithStreamingResponse
return UsersResourceWithStreamingResponse(self._client.users)
@@ -2607,10 +2831,35 @@ def accounts(self) -> accounts.AccountsResourceWithStreamingResponse:
return AccountsResourceWithStreamingResponse(self._client.accounts)
@cached_property
- def wallets(self) -> wallets.WalletsResourceWithStreamingResponse:
- from .resources.wallets import WalletsResourceWithStreamingResponse
+ def financial_activity(self) -> financial_activity.FinancialActivityResourceWithStreamingResponse:
+ from .resources.financial_activity import FinancialActivityResourceWithStreamingResponse
- return WalletsResourceWithStreamingResponse(self._client.wallets)
+ return FinancialActivityResourceWithStreamingResponse(self._client.financial_activity)
+
+ @cached_property
+ def stats(self) -> stats.StatsResourceWithStreamingResponse:
+ """Stats"""
+ from .resources.stats import StatsResourceWithStreamingResponse
+
+ return StatsResourceWithStreamingResponse(self._client.stats)
+
+ @cached_property
+ def payouts(self) -> payouts.PayoutsResourceWithStreamingResponse:
+ from .resources.payouts import PayoutsResourceWithStreamingResponse
+
+ return PayoutsResourceWithStreamingResponse(self._client.payouts)
+
+ @cached_property
+ def referrals(self) -> referrals.ReferralsResourceWithStreamingResponse:
+ from .resources.referrals import ReferralsResourceWithStreamingResponse
+
+ return ReferralsResourceWithStreamingResponse(self._client.referrals)
+
+ @cached_property
+ def cards(self) -> cards.CardsResourceWithStreamingResponse:
+ from .resources.cards import CardsResourceWithStreamingResponse
+
+ return CardsResourceWithStreamingResponse(self._client.cards)
@cached_property
def swaps(self) -> swaps.SwapsResourceWithStreamingResponse:
@@ -2747,21 +2996,18 @@ def bounties(self) -> bounties.BountiesResourceWithStreamingResponse:
@cached_property
def ad_campaigns(self) -> ad_campaigns.AdCampaignsResourceWithStreamingResponse:
- """Ad campaigns"""
from .resources.ad_campaigns import AdCampaignsResourceWithStreamingResponse
return AdCampaignsResourceWithStreamingResponse(self._client.ad_campaigns)
@cached_property
def ad_groups(self) -> ad_groups.AdGroupsResourceWithStreamingResponse:
- """Ad groups"""
from .resources.ad_groups import AdGroupsResourceWithStreamingResponse
return AdGroupsResourceWithStreamingResponse(self._client.ad_groups)
@cached_property
def ads(self) -> ads.AdsResourceWithStreamingResponse:
- """Ads"""
from .resources.ads import AdsResourceWithStreamingResponse
return AdsResourceWithStreamingResponse(self._client.ads)
@@ -2817,6 +3063,30 @@ def products(self) -> products.AsyncProductsResourceWithStreamingResponse:
return AsyncProductsResourceWithStreamingResponse(self._client.products)
+ @cached_property
+ def social_accounts(self) -> social_accounts.AsyncSocialAccountsResourceWithStreamingResponse:
+ from .resources.social_accounts import AsyncSocialAccountsResourceWithStreamingResponse
+
+ return AsyncSocialAccountsResourceWithStreamingResponse(self._client.social_accounts)
+
+ @cached_property
+ def audiences(self) -> audiences.AsyncAudiencesResourceWithStreamingResponse:
+ from .resources.audiences import AsyncAudiencesResourceWithStreamingResponse
+
+ return AsyncAudiencesResourceWithStreamingResponse(self._client.audiences)
+
+ @cached_property
+ def people(self) -> people.AsyncPeopleResourceWithStreamingResponse:
+ from .resources.people import AsyncPeopleResourceWithStreamingResponse
+
+ return AsyncPeopleResourceWithStreamingResponse(self._client.people)
+
+ @cached_property
+ def events(self) -> events.AsyncEventsResourceWithStreamingResponse:
+ from .resources.events import AsyncEventsResourceWithStreamingResponse
+
+ return AsyncEventsResourceWithStreamingResponse(self._client.events)
+
@cached_property
def companies(self) -> companies.AsyncCompaniesResourceWithStreamingResponse:
"""Companies"""
@@ -2833,7 +3103,6 @@ def webhooks(self) -> webhooks.AsyncWebhooksResourceWithStreamingResponse:
@cached_property
def plans(self) -> plans.AsyncPlansResourceWithStreamingResponse:
- """Plans"""
from .resources.plans import AsyncPlansResourceWithStreamingResponse
return AsyncPlansResourceWithStreamingResponse(self._client.plans)
@@ -2854,7 +3123,6 @@ def forum_posts(self) -> forum_posts.AsyncForumPostsResourceWithStreamingRespons
@cached_property
def transfers(self) -> transfers.AsyncTransfersResourceWithStreamingResponse:
- """Transfers"""
from .resources.transfers import AsyncTransfersResourceWithStreamingResponse
return AsyncTransfersResourceWithStreamingResponse(self._client.transfers)
@@ -2898,7 +3166,6 @@ def shipments(self) -> shipments.AsyncShipmentsResourceWithStreamingResponse:
def checkout_configurations(
self,
) -> checkout_configurations.AsyncCheckoutConfigurationsResourceWithStreamingResponse:
- """Checkout configurations"""
from .resources.checkout_configurations import AsyncCheckoutConfigurationsResourceWithStreamingResponse
return AsyncCheckoutConfigurationsResourceWithStreamingResponse(self._client.checkout_configurations)
@@ -2919,7 +3186,6 @@ def chat_channels(self) -> chat_channels.AsyncChatChannelsResourceWithStreamingR
@cached_property
def users(self) -> users.AsyncUsersResourceWithStreamingResponse:
- """Users"""
from .resources.users import AsyncUsersResourceWithStreamingResponse
return AsyncUsersResourceWithStreamingResponse(self._client.users)
@@ -3057,10 +3323,35 @@ def accounts(self) -> accounts.AsyncAccountsResourceWithStreamingResponse:
return AsyncAccountsResourceWithStreamingResponse(self._client.accounts)
@cached_property
- def wallets(self) -> wallets.AsyncWalletsResourceWithStreamingResponse:
- from .resources.wallets import AsyncWalletsResourceWithStreamingResponse
+ def financial_activity(self) -> financial_activity.AsyncFinancialActivityResourceWithStreamingResponse:
+ from .resources.financial_activity import AsyncFinancialActivityResourceWithStreamingResponse
+
+ return AsyncFinancialActivityResourceWithStreamingResponse(self._client.financial_activity)
+
+ @cached_property
+ def stats(self) -> stats.AsyncStatsResourceWithStreamingResponse:
+ """Stats"""
+ from .resources.stats import AsyncStatsResourceWithStreamingResponse
+
+ return AsyncStatsResourceWithStreamingResponse(self._client.stats)
+
+ @cached_property
+ def payouts(self) -> payouts.AsyncPayoutsResourceWithStreamingResponse:
+ from .resources.payouts import AsyncPayoutsResourceWithStreamingResponse
+
+ return AsyncPayoutsResourceWithStreamingResponse(self._client.payouts)
+
+ @cached_property
+ def referrals(self) -> referrals.AsyncReferralsResourceWithStreamingResponse:
+ from .resources.referrals import AsyncReferralsResourceWithStreamingResponse
+
+ return AsyncReferralsResourceWithStreamingResponse(self._client.referrals)
+
+ @cached_property
+ def cards(self) -> cards.AsyncCardsResourceWithStreamingResponse:
+ from .resources.cards import AsyncCardsResourceWithStreamingResponse
- return AsyncWalletsResourceWithStreamingResponse(self._client.wallets)
+ return AsyncCardsResourceWithStreamingResponse(self._client.cards)
@cached_property
def swaps(self) -> swaps.AsyncSwapsResourceWithStreamingResponse:
@@ -3199,21 +3490,18 @@ def bounties(self) -> bounties.AsyncBountiesResourceWithStreamingResponse:
@cached_property
def ad_campaigns(self) -> ad_campaigns.AsyncAdCampaignsResourceWithStreamingResponse:
- """Ad campaigns"""
from .resources.ad_campaigns import AsyncAdCampaignsResourceWithStreamingResponse
return AsyncAdCampaignsResourceWithStreamingResponse(self._client.ad_campaigns)
@cached_property
def ad_groups(self) -> ad_groups.AsyncAdGroupsResourceWithStreamingResponse:
- """Ad groups"""
from .resources.ad_groups import AsyncAdGroupsResourceWithStreamingResponse
return AsyncAdGroupsResourceWithStreamingResponse(self._client.ad_groups)
@cached_property
def ads(self) -> ads.AsyncAdsResourceWithStreamingResponse:
- """Ads"""
from .resources.ads import AsyncAdsResourceWithStreamingResponse
return AsyncAdsResourceWithStreamingResponse(self._client.ads)
diff --git a/src/whop_sdk/resources/__init__.py b/src/whop_sdk/resources/__init__.py
index 6cd6f052..6aa67330 100644
--- a/src/whop_sdk/resources/__init__.py
+++ b/src/whop_sdk/resources/__init__.py
@@ -16,6 +16,14 @@
AppsResourceWithStreamingResponse,
AsyncAppsResourceWithStreamingResponse,
)
+from .cards import (
+ CardsResource,
+ AsyncCardsResource,
+ CardsResourceWithRawResponse,
+ AsyncCardsResourceWithRawResponse,
+ CardsResourceWithStreamingResponse,
+ AsyncCardsResourceWithStreamingResponse,
+)
from .files import (
FilesResource,
AsyncFilesResource,
@@ -40,6 +48,14 @@
PlansResourceWithStreamingResponse,
AsyncPlansResourceWithStreamingResponse,
)
+from .stats import (
+ StatsResource,
+ AsyncStatsResource,
+ StatsResourceWithRawResponse,
+ AsyncStatsResourceWithRawResponse,
+ StatsResourceWithStreamingResponse,
+ AsyncStatsResourceWithStreamingResponse,
+)
from .swaps import (
SwapsResource,
AsyncSwapsResource,
@@ -56,6 +72,14 @@
UsersResourceWithStreamingResponse,
AsyncUsersResourceWithStreamingResponse,
)
+from .events import (
+ EventsResource,
+ AsyncEventsResource,
+ EventsResourceWithRawResponse,
+ AsyncEventsResourceWithRawResponse,
+ EventsResourceWithStreamingResponse,
+ AsyncEventsResourceWithStreamingResponse,
+)
from .forums import (
ForumsResource,
AsyncForumsResource,
@@ -64,6 +88,14 @@
ForumsResourceWithStreamingResponse,
AsyncForumsResourceWithStreamingResponse,
)
+from .people import (
+ PeopleResource,
+ AsyncPeopleResource,
+ PeopleResourceWithRawResponse,
+ AsyncPeopleResourceWithRawResponse,
+ PeopleResourceWithStreamingResponse,
+ AsyncPeopleResourceWithStreamingResponse,
+)
from .topups import (
TopupsResource,
AsyncTopupsResource,
@@ -96,6 +128,14 @@
MembersResourceWithStreamingResponse,
AsyncMembersResourceWithStreamingResponse,
)
+from .payouts import (
+ PayoutsResource,
+ AsyncPayoutsResource,
+ PayoutsResourceWithRawResponse,
+ AsyncPayoutsResourceWithRawResponse,
+ PayoutsResourceWithStreamingResponse,
+ AsyncPayoutsResourceWithStreamingResponse,
+)
from .refunds import (
RefundsResource,
AsyncRefundsResource,
@@ -112,14 +152,6 @@
ReviewsResourceWithStreamingResponse,
AsyncReviewsResourceWithStreamingResponse,
)
-from .wallets import (
- WalletsResource,
- AsyncWalletsResource,
- WalletsResourceWithRawResponse,
- AsyncWalletsResourceWithRawResponse,
- WalletsResourceWithStreamingResponse,
- AsyncWalletsResourceWithStreamingResponse,
-)
from .accounts import (
AccountsResource,
AsyncAccountsResource,
@@ -208,6 +240,14 @@
AdGroupsResourceWithStreamingResponse,
AsyncAdGroupsResourceWithStreamingResponse,
)
+from .audiences import (
+ AudiencesResource,
+ AsyncAudiencesResource,
+ AudiencesResourceWithRawResponse,
+ AsyncAudiencesResourceWithRawResponse,
+ AudiencesResourceWithStreamingResponse,
+ AsyncAudiencesResourceWithStreamingResponse,
+)
from .companies import (
CompaniesResource,
AsyncCompaniesResource,
@@ -224,6 +264,14 @@
ReactionsResourceWithStreamingResponse,
AsyncReactionsResourceWithStreamingResponse,
)
+from .referrals import (
+ ReferralsResource,
+ AsyncReferralsResource,
+ ReferralsResourceWithRawResponse,
+ AsyncReferralsResourceWithRawResponse,
+ ReferralsResourceWithStreamingResponse,
+ AsyncReferralsResourceWithStreamingResponse,
+)
from .shipments import (
ShipmentsResource,
AsyncShipmentsResource,
@@ -456,6 +504,14 @@
PayoutAccountsResourceWithStreamingResponse,
AsyncPayoutAccountsResourceWithStreamingResponse,
)
+from .social_accounts import (
+ SocialAccountsResource,
+ AsyncSocialAccountsResource,
+ SocialAccountsResourceWithRawResponse,
+ AsyncSocialAccountsResourceWithRawResponse,
+ SocialAccountsResourceWithStreamingResponse,
+ AsyncSocialAccountsResourceWithStreamingResponse,
+)
from .authorized_users import (
AuthorizedUsersResource,
AsyncAuthorizedUsersResource,
@@ -472,6 +528,14 @@
SupportChannelsResourceWithStreamingResponse,
AsyncSupportChannelsResourceWithStreamingResponse,
)
+from .financial_activity import (
+ FinancialActivityResource,
+ AsyncFinancialActivityResource,
+ FinancialActivityResourceWithRawResponse,
+ AsyncFinancialActivityResourceWithRawResponse,
+ FinancialActivityResourceWithStreamingResponse,
+ AsyncFinancialActivityResourceWithStreamingResponse,
+)
from .checkout_configurations import (
CheckoutConfigurationsResource,
AsyncCheckoutConfigurationsResource,
@@ -530,6 +594,30 @@
"AsyncProductsResourceWithRawResponse",
"ProductsResourceWithStreamingResponse",
"AsyncProductsResourceWithStreamingResponse",
+ "SocialAccountsResource",
+ "AsyncSocialAccountsResource",
+ "SocialAccountsResourceWithRawResponse",
+ "AsyncSocialAccountsResourceWithRawResponse",
+ "SocialAccountsResourceWithStreamingResponse",
+ "AsyncSocialAccountsResourceWithStreamingResponse",
+ "AudiencesResource",
+ "AsyncAudiencesResource",
+ "AudiencesResourceWithRawResponse",
+ "AsyncAudiencesResourceWithRawResponse",
+ "AudiencesResourceWithStreamingResponse",
+ "AsyncAudiencesResourceWithStreamingResponse",
+ "PeopleResource",
+ "AsyncPeopleResource",
+ "PeopleResourceWithRawResponse",
+ "AsyncPeopleResourceWithRawResponse",
+ "PeopleResourceWithStreamingResponse",
+ "AsyncPeopleResourceWithStreamingResponse",
+ "EventsResource",
+ "AsyncEventsResource",
+ "EventsResourceWithRawResponse",
+ "AsyncEventsResourceWithRawResponse",
+ "EventsResourceWithStreamingResponse",
+ "AsyncEventsResourceWithStreamingResponse",
"CompaniesResource",
"AsyncCompaniesResource",
"CompaniesResourceWithRawResponse",
@@ -734,12 +822,36 @@
"AsyncAccountsResourceWithRawResponse",
"AccountsResourceWithStreamingResponse",
"AsyncAccountsResourceWithStreamingResponse",
- "WalletsResource",
- "AsyncWalletsResource",
- "WalletsResourceWithRawResponse",
- "AsyncWalletsResourceWithRawResponse",
- "WalletsResourceWithStreamingResponse",
- "AsyncWalletsResourceWithStreamingResponse",
+ "FinancialActivityResource",
+ "AsyncFinancialActivityResource",
+ "FinancialActivityResourceWithRawResponse",
+ "AsyncFinancialActivityResourceWithRawResponse",
+ "FinancialActivityResourceWithStreamingResponse",
+ "AsyncFinancialActivityResourceWithStreamingResponse",
+ "StatsResource",
+ "AsyncStatsResource",
+ "StatsResourceWithRawResponse",
+ "AsyncStatsResourceWithRawResponse",
+ "StatsResourceWithStreamingResponse",
+ "AsyncStatsResourceWithStreamingResponse",
+ "PayoutsResource",
+ "AsyncPayoutsResource",
+ "PayoutsResourceWithRawResponse",
+ "AsyncPayoutsResourceWithRawResponse",
+ "PayoutsResourceWithStreamingResponse",
+ "AsyncPayoutsResourceWithStreamingResponse",
+ "ReferralsResource",
+ "AsyncReferralsResource",
+ "ReferralsResourceWithRawResponse",
+ "AsyncReferralsResourceWithRawResponse",
+ "ReferralsResourceWithStreamingResponse",
+ "AsyncReferralsResourceWithStreamingResponse",
+ "CardsResource",
+ "AsyncCardsResource",
+ "CardsResourceWithRawResponse",
+ "AsyncCardsResourceWithRawResponse",
+ "CardsResourceWithStreamingResponse",
+ "AsyncCardsResourceWithStreamingResponse",
"SwapsResource",
"AsyncSwapsResource",
"SwapsResourceWithRawResponse",
diff --git a/src/whop_sdk/resources/accounts.py b/src/whop_sdk/resources/accounts.py
index 16264fbd..cafcc5ab 100644
--- a/src/whop_sdk/resources/accounts.py
+++ b/src/whop_sdk/resources/accounts.py
@@ -3,11 +3,12 @@
from __future__ import annotations
from typing import Dict, Iterable, Optional
+from typing_extensions import Literal
import httpx
from ..types import account_list_params, account_create_params, account_update_params
-from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
@@ -17,9 +18,9 @@
async_to_raw_response_wrapper,
async_to_streamed_response_wrapper,
)
-from .._base_client import make_request_options
+from ..pagination import SyncCursorPage, AsyncCursorPage
+from .._base_client import AsyncPaginator, make_request_options
from ..types.account import Account
-from ..types.account_list_response import AccountListResponse
__all__ = ["AccountsResource", "AsyncAccountsResource"]
@@ -59,7 +60,9 @@ def create(
"""Creates an account.
User tokens create business accounts; business account API
- keys create connected accounts.
+ keys create connected accounts. Tax fields (`tax_remitted_by`,
+ `product_tax_code_id`, `business_address`, `tax_identifiers`) are configured
+ with Update Account, not at creation.
Args:
email: The email address of the account owner. Required for business account API key
@@ -131,18 +134,36 @@ def update(
affiliate_application_required: bool | Omit = omit,
affiliate_instructions: Optional[str] | Omit = omit,
banner_image: Optional[Dict[str, object]] | Omit = omit,
+ business_address: account_update_params.BusinessAddress | Omit = omit,
business_type: Optional[str] | Omit = omit,
+ country: Optional[str] | Omit = omit,
description: Optional[str] | Omit = omit,
featured_affiliate_product_id: Optional[str] | Omit = omit,
+ home_preferences: SequenceNotStr[str] | Omit = omit,
industry_group: Optional[str] | Omit = omit,
industry_type: Optional[str] | Omit = omit,
+ invoice_prefix: Optional[str] | Omit = omit,
logo: Optional[Dict[str, object]] | Omit = omit,
metadata: Dict[str, object] | Omit = omit,
+ onboarding_type: Optional[str] | Omit = omit,
+ opengraph_image: Optional[Dict[str, object]] | Omit = omit,
+ opengraph_image_variant: Optional[str] | Omit = omit,
+ other_business_description: Optional[str] | Omit = omit,
+ other_industry_description: Optional[str] | Omit = omit,
+ product_tax_code_id: Optional[str] | Omit = omit,
+ require_2fa: bool | Omit = omit,
route: Optional[str] | Omit = omit,
send_customer_emails: bool | Omit = omit,
+ show_joined_whops: bool | Omit = omit,
+ show_reviews_dtc: bool | Omit = omit,
+ show_user_directory: bool | Omit = omit,
social_links: Iterable[Dict[str, object]] | Omit = omit,
+ store_page_config: Optional[Dict[str, object]] | Omit = omit,
target_audience: Optional[str] | Omit = omit,
+ tax_identifiers: Iterable[account_update_params.TaxIdentifier] | Omit = omit,
+ tax_remitted_by: Literal["whop", "self", "none"] | Omit = omit,
title: Optional[str] | Omit = omit,
+ use_logo_as_opengraph_image_fallback: bool | 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,
@@ -163,30 +184,73 @@ def update(
banner_image: Attachment input for the account banner image.
- business_type: The high-level business category for the account.
+ business_address: Account business address used to calculate tax. A complete address in a
+ supported country is required when `tax_remitted_by` is `self`.
- description: A promotional description for the account.
+ business_type: High-level business category for the account.
- featured_affiliate_product_id: The ID of the product to feature for affiliates. Pass null to clear.
+ country: Country where the account is located.
- industry_group: The industry group the account belongs to.
+ description: Account promotional description.
- industry_type: The specific industry vertical the account operates in.
+ featured_affiliate_product_id: The ID of the product to feature for affiliates. Pass `null` to clear.
+
+ home_preferences: Public account home page preferences.
+
+ industry_group: Account industry group.
+
+ industry_type: Specific industry vertical for the account.
+
+ invoice_prefix: Prefix used for account invoices.
logo: Attachment input for the account logo.
metadata: Arbitrary key/value metadata to store on the account.
+ onboarding_type: The type of onboarding the account has completed.
+
+ opengraph_image: Attachment input for the account Open Graph image.
+
+ opengraph_image_variant: The account Open Graph image variant.
+
+ other_business_description: The description of the business type when business_type is other.
+
+ other_industry_description: The description of the industry type when industry_type is other.
+
+ product_tax_code_id: ID of the tax classification code applied by default to the account's products.
+
+ require_2fa: Whether the account requires authorized users to have two-factor authentication
+ enabled.
+
route: The unique URL slug for the account.
send_customer_emails: Whether Whop sends transactional emails to customers on behalf of this account.
+ show_joined_whops: Whether the account appears in joined whops on other accounts.
+
+ show_reviews_dtc: Whether reviews are displayed on direct-to-consumer product pages.
+
+ show_user_directory: Whether the account shows users in the user directory.
+
social_links: The full list of social links to display for the account.
+ store_page_config: Account store page display configuration.
+
target_audience: The target audience for this account.
+ tax_identifiers: Account tax/VAT registrations to add or update. When `tax_remitted_by` is
+ `self`, tax is calculated and collected only in the countries where the account
+ holds a registration.
+
+ tax_remitted_by: Who calculates and remits tax for the account: `whop` (Whop calculates and
+ remits), `self` (Whop calculates; the account collects and remits), or `none`
+ (neither; the account is responsible). `self` requires a `business_address` in a
+ supported country.
+
title: The display name of the account.
+ use_logo_as_opengraph_image_fallback: Whether the account uses its logo as the fallback Open Graph image.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -204,18 +268,36 @@ def update(
"affiliate_application_required": affiliate_application_required,
"affiliate_instructions": affiliate_instructions,
"banner_image": banner_image,
+ "business_address": business_address,
"business_type": business_type,
+ "country": country,
"description": description,
"featured_affiliate_product_id": featured_affiliate_product_id,
+ "home_preferences": home_preferences,
"industry_group": industry_group,
"industry_type": industry_type,
+ "invoice_prefix": invoice_prefix,
"logo": logo,
"metadata": metadata,
+ "onboarding_type": onboarding_type,
+ "opengraph_image": opengraph_image,
+ "opengraph_image_variant": opengraph_image_variant,
+ "other_business_description": other_business_description,
+ "other_industry_description": other_industry_description,
+ "product_tax_code_id": product_tax_code_id,
+ "require_2fa": require_2fa,
"route": route,
"send_customer_emails": send_customer_emails,
+ "show_joined_whops": show_joined_whops,
+ "show_reviews_dtc": show_reviews_dtc,
+ "show_user_directory": show_user_directory,
"social_links": social_links,
+ "store_page_config": store_page_config,
"target_audience": target_audience,
+ "tax_identifiers": tax_identifiers,
+ "tax_remitted_by": tax_remitted_by,
"title": title,
+ "use_logo_as_opengraph_image_fallback": use_logo_as_opengraph_image_fallback,
},
account_update_params.AccountUpdateParams,
),
@@ -228,15 +310,19 @@ def update(
def list(
self,
*,
- page: int | Omit = omit,
- per: int | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal["created_at"] | 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,
- ) -> AccountListResponse:
+ ) -> SyncCursorPage[Account]:
"""Lists accounts visible to the credential.
User tokens return the user's business
@@ -244,10 +330,17 @@ def list(
its connected accounts.
Args:
- page: The page number to retrieve
+ after: A cursor; returns accounts after this position.
- per: The number of resources to return per page. There is a limit of 50 results per
- page.
+ before: A cursor; returns accounts before this position.
+
+ direction: Sort direction.
+
+ first: The number of accounts to return (default 10, max 50).
+
+ last: The number of accounts to return from the end of the range.
+
+ order: The field to sort accounts by.
extra_headers: Send extra headers
@@ -257,8 +350,9 @@ def list(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return self._get(
+ return self._get_api_list(
"/accounts",
+ page=SyncCursorPage[Account],
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -266,13 +360,17 @@ def list(
timeout=timeout,
query=maybe_transform(
{
- "page": page,
- "per": per,
+ "after": after,
+ "before": before,
+ "direction": direction,
+ "first": first,
+ "last": last,
+ "order": order,
},
account_list_params.AccountListParams,
),
),
- cast_to=AccountListResponse,
+ model=Account,
)
def me(
@@ -333,7 +431,9 @@ async def create(
"""Creates an account.
User tokens create business accounts; business account API
- keys create connected accounts.
+ keys create connected accounts. Tax fields (`tax_remitted_by`,
+ `product_tax_code_id`, `business_address`, `tax_identifiers`) are configured
+ with Update Account, not at creation.
Args:
email: The email address of the account owner. Required for business account API key
@@ -405,18 +505,36 @@ async def update(
affiliate_application_required: bool | Omit = omit,
affiliate_instructions: Optional[str] | Omit = omit,
banner_image: Optional[Dict[str, object]] | Omit = omit,
+ business_address: account_update_params.BusinessAddress | Omit = omit,
business_type: Optional[str] | Omit = omit,
+ country: Optional[str] | Omit = omit,
description: Optional[str] | Omit = omit,
featured_affiliate_product_id: Optional[str] | Omit = omit,
+ home_preferences: SequenceNotStr[str] | Omit = omit,
industry_group: Optional[str] | Omit = omit,
industry_type: Optional[str] | Omit = omit,
+ invoice_prefix: Optional[str] | Omit = omit,
logo: Optional[Dict[str, object]] | Omit = omit,
metadata: Dict[str, object] | Omit = omit,
+ onboarding_type: Optional[str] | Omit = omit,
+ opengraph_image: Optional[Dict[str, object]] | Omit = omit,
+ opengraph_image_variant: Optional[str] | Omit = omit,
+ other_business_description: Optional[str] | Omit = omit,
+ other_industry_description: Optional[str] | Omit = omit,
+ product_tax_code_id: Optional[str] | Omit = omit,
+ require_2fa: bool | Omit = omit,
route: Optional[str] | Omit = omit,
send_customer_emails: bool | Omit = omit,
+ show_joined_whops: bool | Omit = omit,
+ show_reviews_dtc: bool | Omit = omit,
+ show_user_directory: bool | Omit = omit,
social_links: Iterable[Dict[str, object]] | Omit = omit,
+ store_page_config: Optional[Dict[str, object]] | Omit = omit,
target_audience: Optional[str] | Omit = omit,
+ tax_identifiers: Iterable[account_update_params.TaxIdentifier] | Omit = omit,
+ tax_remitted_by: Literal["whop", "self", "none"] | Omit = omit,
title: Optional[str] | Omit = omit,
+ use_logo_as_opengraph_image_fallback: bool | 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,
@@ -437,30 +555,73 @@ async def update(
banner_image: Attachment input for the account banner image.
- business_type: The high-level business category for the account.
+ business_address: Account business address used to calculate tax. A complete address in a
+ supported country is required when `tax_remitted_by` is `self`.
+
+ business_type: High-level business category for the account.
- description: A promotional description for the account.
+ country: Country where the account is located.
- featured_affiliate_product_id: The ID of the product to feature for affiliates. Pass null to clear.
+ description: Account promotional description.
- industry_group: The industry group the account belongs to.
+ featured_affiliate_product_id: The ID of the product to feature for affiliates. Pass `null` to clear.
- industry_type: The specific industry vertical the account operates in.
+ home_preferences: Public account home page preferences.
+
+ industry_group: Account industry group.
+
+ industry_type: Specific industry vertical for the account.
+
+ invoice_prefix: Prefix used for account invoices.
logo: Attachment input for the account logo.
metadata: Arbitrary key/value metadata to store on the account.
+ onboarding_type: The type of onboarding the account has completed.
+
+ opengraph_image: Attachment input for the account Open Graph image.
+
+ opengraph_image_variant: The account Open Graph image variant.
+
+ other_business_description: The description of the business type when business_type is other.
+
+ other_industry_description: The description of the industry type when industry_type is other.
+
+ product_tax_code_id: ID of the tax classification code applied by default to the account's products.
+
+ require_2fa: Whether the account requires authorized users to have two-factor authentication
+ enabled.
+
route: The unique URL slug for the account.
send_customer_emails: Whether Whop sends transactional emails to customers on behalf of this account.
+ show_joined_whops: Whether the account appears in joined whops on other accounts.
+
+ show_reviews_dtc: Whether reviews are displayed on direct-to-consumer product pages.
+
+ show_user_directory: Whether the account shows users in the user directory.
+
social_links: The full list of social links to display for the account.
+ store_page_config: Account store page display configuration.
+
target_audience: The target audience for this account.
+ tax_identifiers: Account tax/VAT registrations to add or update. When `tax_remitted_by` is
+ `self`, tax is calculated and collected only in the countries where the account
+ holds a registration.
+
+ tax_remitted_by: Who calculates and remits tax for the account: `whop` (Whop calculates and
+ remits), `self` (Whop calculates; the account collects and remits), or `none`
+ (neither; the account is responsible). `self` requires a `business_address` in a
+ supported country.
+
title: The display name of the account.
+ use_logo_as_opengraph_image_fallback: Whether the account uses its logo as the fallback Open Graph image.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -478,18 +639,36 @@ async def update(
"affiliate_application_required": affiliate_application_required,
"affiliate_instructions": affiliate_instructions,
"banner_image": banner_image,
+ "business_address": business_address,
"business_type": business_type,
+ "country": country,
"description": description,
"featured_affiliate_product_id": featured_affiliate_product_id,
+ "home_preferences": home_preferences,
"industry_group": industry_group,
"industry_type": industry_type,
+ "invoice_prefix": invoice_prefix,
"logo": logo,
"metadata": metadata,
+ "onboarding_type": onboarding_type,
+ "opengraph_image": opengraph_image,
+ "opengraph_image_variant": opengraph_image_variant,
+ "other_business_description": other_business_description,
+ "other_industry_description": other_industry_description,
+ "product_tax_code_id": product_tax_code_id,
+ "require_2fa": require_2fa,
"route": route,
"send_customer_emails": send_customer_emails,
+ "show_joined_whops": show_joined_whops,
+ "show_reviews_dtc": show_reviews_dtc,
+ "show_user_directory": show_user_directory,
"social_links": social_links,
+ "store_page_config": store_page_config,
"target_audience": target_audience,
+ "tax_identifiers": tax_identifiers,
+ "tax_remitted_by": tax_remitted_by,
"title": title,
+ "use_logo_as_opengraph_image_fallback": use_logo_as_opengraph_image_fallback,
},
account_update_params.AccountUpdateParams,
),
@@ -499,18 +678,22 @@ async def update(
cast_to=Account,
)
- async def list(
+ def list(
self,
*,
- page: int | Omit = omit,
- per: int | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal["created_at"] | 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,
- ) -> AccountListResponse:
+ ) -> AsyncPaginator[Account, AsyncCursorPage[Account]]:
"""Lists accounts visible to the credential.
User tokens return the user's business
@@ -518,10 +701,17 @@ async def list(
its connected accounts.
Args:
- page: The page number to retrieve
+ after: A cursor; returns accounts after this position.
- per: The number of resources to return per page. There is a limit of 50 results per
- page.
+ before: A cursor; returns accounts before this position.
+
+ direction: Sort direction.
+
+ first: The number of accounts to return (default 10, max 50).
+
+ last: The number of accounts to return from the end of the range.
+
+ order: The field to sort accounts by.
extra_headers: Send extra headers
@@ -531,22 +721,27 @@ async def list(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return await self._get(
+ return self._get_api_list(
"/accounts",
+ page=AsyncCursorPage[Account],
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
- query=await async_maybe_transform(
+ query=maybe_transform(
{
- "page": page,
- "per": per,
+ "after": after,
+ "before": before,
+ "direction": direction,
+ "first": first,
+ "last": last,
+ "order": order,
},
account_list_params.AccountListParams,
),
),
- cast_to=AccountListResponse,
+ model=Account,
)
async def me(
diff --git a/src/whop_sdk/resources/ad_campaigns.py b/src/whop_sdk/resources/ad_campaigns.py
index 3cbade58..f8cfbce1 100644
--- a/src/whop_sdk/resources/ad_campaigns.py
+++ b/src/whop_sdk/resources/ad_campaigns.py
@@ -2,12 +2,17 @@
from __future__ import annotations
-from typing import Union, Optional
-from datetime import datetime
+from typing import List
+from typing_extensions import Literal
import httpx
-from ..types import AdCampaignStatus, ad_campaign_list_params, ad_campaign_update_params
+from ..types import (
+ ad_campaign_list_params,
+ ad_campaign_create_params,
+ ad_campaign_update_params,
+ ad_campaign_retrieve_params,
+)
from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
@@ -21,15 +26,12 @@
from ..pagination import SyncCursorPage, AsyncCursorPage
from .._base_client import AsyncPaginator, make_request_options
from ..types.ad_campaign import AdCampaign
-from ..types.ad_campaign_status import AdCampaignStatus
-from ..types.ad_campaign_list_response import AdCampaignListResponse
+from ..types.ad_campaign_delete_response import AdCampaignDeleteResponse
__all__ = ["AdCampaignsResource", "AsyncAdCampaignsResource"]
class AdCampaignsResource(SyncAPIResource):
- """Ad campaigns"""
-
@cached_property
def with_raw_response(self) -> AdCampaignsResourceWithRawResponse:
"""
@@ -49,10 +51,103 @@ def with_streaming_response(self) -> AdCampaignsResourceWithStreamingResponse:
"""
return AdCampaignsResourceWithStreamingResponse(self)
+ def create(
+ self,
+ *,
+ objective: Literal["awareness", "traffic", "engagement", "leads", "sales"],
+ platform: Literal["meta"],
+ title: str,
+ account_id: str | Omit = omit,
+ bid_type: Literal["minimum_cost", "average_target", "maximum_target"] | Omit = omit,
+ budget_amount: float | Omit = omit,
+ budget_optimization: Literal["ad_campaign", "ad_group"] | Omit = omit,
+ budget_type: Literal["daily", "lifetime"] | Omit = omit,
+ desired_cost_per_result: float | Omit = omit,
+ ends_at: str | Omit = omit,
+ special_ad_categories: List[Literal["housing", "employment", "financial_products", "politics"]] | Omit = omit,
+ starts_at: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AdCampaign:
+ """
+ Creates an ad campaign for an account.
+
+ Args:
+ objective: The goal the campaign optimizes toward.
+
+ platform: The ad network the campaign runs on.
+
+ title: The title of the campaign.
+
+ account_id: The account to create the campaign under. Defaults to the account-scoped key's
+ own account.
+
+ bid_type: CBO bid strategy: minimum_cost (lowest cost), average_target (cost cap), or
+ maximum_target (bid cap). CBO only.
+
+ budget_amount:
+ The campaign budget, in USD. Required for CBO (budget_optimization:
+ ad_campaign); omit for ABO.
+
+ budget_optimization: Which level owns the budget — the campaign (CBO) or each ad group (ABO).
+ Defaults to ad_group.
+
+ budget_type: Whether the budget is spent per day or over the campaign's lifetime. Defaults to
+ daily.
+
+ desired_cost_per_result: Target/cap cost per result in USD for average_target / maximum_target bidding.
+ CBO only.
+
+ ends_at: Campaign schedule end (ISO 8601). CBO only.
+
+ special_ad_categories: Regulated categories the campaign falls under. Ads in these categories are
+ subject to extra targeting restrictions.
+
+ starts_at: Campaign schedule start (ISO 8601). CBO only.
+
+ 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(
+ "/ad_campaigns",
+ body=maybe_transform(
+ {
+ "objective": objective,
+ "platform": platform,
+ "title": title,
+ "account_id": account_id,
+ "bid_type": bid_type,
+ "budget_amount": budget_amount,
+ "budget_optimization": budget_optimization,
+ "budget_type": budget_type,
+ "desired_cost_per_result": desired_cost_per_result,
+ "ends_at": ends_at,
+ "special_ad_categories": special_ad_categories,
+ "starts_at": starts_at,
+ },
+ ad_campaign_create_params.AdCampaignCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AdCampaign,
+ )
+
def retrieve(
self,
id: str,
*,
+ stats_from: str | Omit = omit,
+ stats_to: 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.
extra_headers: Headers | None = None,
@@ -61,13 +156,13 @@ def retrieve(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdCampaign:
"""
- Retrieves a single ad campaign by its unique identifier.
+ Retrieves a single ad campaign with stats over the requested window.
- Required permissions:
+ Args:
+ stats_from: Start of the stats window.
- - `ad_campaign:basic:read`
+ stats_to: End of the stats window.
- Args:
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -81,7 +176,17 @@ def retrieve(
return self._get(
path_template("/ad_campaigns/{id}", id=id),
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "stats_from": stats_from,
+ "stats_to": stats_to,
+ },
+ ad_campaign_retrieve_params.AdCampaignRetrieveParams,
+ ),
),
cast_to=AdCampaign,
)
@@ -90,7 +195,11 @@ def update(
self,
id: str,
*,
- budget: Optional[float] | Omit = omit,
+ budget_amount: float | Omit = omit,
+ ends_at: str | Omit = omit,
+ starts_at: str | Omit = omit,
+ status: Literal["active"] | Omit = omit,
+ title: 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.
extra_headers: Headers | None = None,
@@ -99,15 +208,23 @@ def update(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdCampaign:
"""
- Updates an ad campaign synchronously.
+ Updates an ad campaign's editable fields (title, budget, schedule), and launches
+ a draft campaign by setting status to active. Objective, budget optimization,
+ budget type, special ad categories, bid type and desired cost per result are
+ fixed at creation and cannot be changed.
- Required permissions:
+ Args:
+ budget_amount: The campaign budget, in the account's currency. Interpreted as daily or lifetime
+ per the campaign's existing budget type.
- - `ad_campaign:update`
+ ends_at: Campaign schedule end (ISO 8601). CBO only.
- Args:
- budget: The campaign budget in dollars. The interpretation (daily or lifetime) follows
- the campaign's existing budget type.
+ starts_at: Campaign schedule start (ISO 8601). CBO only.
+
+ status: Set to active to launch a draft campaign (moderates and pushes it live).
+ Live-campaign pause and resume use the pause and unpause actions.
+
+ title: The name of the campaign.
extra_headers: Send extra headers
@@ -121,7 +238,16 @@ def update(
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._patch(
path_template("/ad_campaigns/{id}", id=id),
- body=maybe_transform({"budget": budget}, ad_campaign_update_params.AdCampaignUpdateParams),
+ body=maybe_transform(
+ {
+ "budget_amount": budget_amount,
+ "ends_at": ends_at,
+ "starts_at": starts_at,
+ "status": status,
+ "title": title,
+ },
+ ad_campaign_update_params.AdCampaignUpdateParams,
+ ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -131,48 +257,74 @@ def update(
def list(
self,
*,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- company_id: Optional[str] | Omit = omit,
- created_after: Union[str, datetime, None] | Omit = omit,
- created_before: Union[str, datetime, None] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[int] | Omit = omit,
- query: Optional[str] | Omit = omit,
- status: Optional[AdCampaignStatus] | Omit = omit,
+ account_id: str | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ created_after: str | Omit = omit,
+ created_before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal[
+ "created_at",
+ "updated_at",
+ "spend",
+ "impressions",
+ "clicks",
+ "reach",
+ "unique_clicks",
+ "results",
+ "click_through_rate",
+ "cost_per_click",
+ "cost_per_mille",
+ "cost_per_result",
+ "frequency",
+ "return_on_ad_spend",
+ ]
+ | Omit = omit,
+ query: str | Omit = omit,
+ stats_from: str | Omit = omit,
+ stats_to: str | Omit = omit,
+ status: Literal["draft", "active", "paused", "payment_failed"] | 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[AdCampaignListResponse]:
+ ) -> SyncCursorPage[AdCampaign]:
"""
- Returns a paginated list of ad campaigns for a company, with optional filtering
- by status, and creation date.
+ Lists the ad campaigns for an account, with stats over the requested window.
- Required permissions:
+ Args:
+ account_id: The account the campaigns belong to. Defaults to the account-scoped key's own
+ account.
- - `ad_campaign:basic:read`
+ after: Cursor to fetch the page after (from page_info.end_cursor).
- Args:
- after: Returns the elements in the list that come after the specified cursor.
+ before: Cursor to fetch the page before (from page_info.start_cursor).
+
+ created_after: Only return campaigns created after this timestamp.
- before: Returns the elements in the list that come before the specified cursor.
+ created_before: Only return campaigns created before this timestamp.
- company_id: The unique identifier of the company to list ad campaigns for.
+ direction: The sort direction. Defaults to desc.
- created_after: Only return ad campaigns created after this timestamp.
+ first: The number of campaigns to return.
- created_before: Only return ad campaigns created before this timestamp.
+ last: The number of campaigns to return from the end of the range.
- first: Returns the first _n_ elements from the list.
+ order: The field to sort by. Defaults to created_at. Stat columns (spend, impressions,
+ …) rank over the stats_from/stats_to window across the whole list, not just the
+ current page.
- last: Returns the last _n_ elements from the list.
+ query: Filter campaigns by a title or ID substring.
- query: Case-insensitive substring match against the campaign title.
+ stats_from: Start of the stats window. Defaults to all-time.
- status: The status of an ad campaign.
+ stats_to: End of the stats window. Defaults to now.
+
+ status: Only return campaigns with this status.
extra_headers: Send extra headers
@@ -184,7 +336,7 @@ def list(
"""
return self._get_api_list(
"/ad_campaigns",
- page=SyncCursorPage[AdCampaignListResponse],
+ page=SyncCursorPage[AdCampaign],
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -192,23 +344,27 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "account_id": account_id,
"after": after,
"before": before,
- "company_id": company_id,
"created_after": created_after,
"created_before": created_before,
+ "direction": direction,
"first": first,
"last": last,
+ "order": order,
"query": query,
+ "stats_from": stats_from,
+ "stats_to": stats_to,
"status": status,
},
ad_campaign_list_params.AdCampaignListParams,
),
),
- model=AdCampaignListResponse,
+ model=AdCampaign,
)
- def pause(
+ def delete(
self,
id: str,
*,
@@ -218,13 +374,43 @@ def pause(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> AdCampaign:
+ ) -> AdCampaignDeleteResponse:
"""
- Pauses an ad campaign, optionally until a specific date.
+ Deletes an ad campaign and archives it on the ad platform (cascades to ad groups
+ and ads). Returns true on success.
+
+ Args:
+ extra_headers: Send extra headers
- Required permissions:
+ extra_query: Add additional query parameters to the request
- - `ad_campaign:update`
+ 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._delete(
+ path_template("/ad_campaigns/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AdCampaignDeleteResponse,
+ )
+
+ def pause(
+ 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,
+ ) -> AdCampaign:
+ """
+ Pauses an active ad campaign.
Args:
extra_headers: Send extra headers
@@ -259,10 +445,6 @@ def unpause(
"""
Resumes a paused ad campaign.
- Required permissions:
-
- - `ad_campaign:update`
-
Args:
extra_headers: Send extra headers
@@ -284,8 +466,6 @@ def unpause(
class AsyncAdCampaignsResource(AsyncAPIResource):
- """Ad campaigns"""
-
@cached_property
def with_raw_response(self) -> AsyncAdCampaignsResourceWithRawResponse:
"""
@@ -305,10 +485,103 @@ def with_streaming_response(self) -> AsyncAdCampaignsResourceWithStreamingRespon
"""
return AsyncAdCampaignsResourceWithStreamingResponse(self)
+ async def create(
+ self,
+ *,
+ objective: Literal["awareness", "traffic", "engagement", "leads", "sales"],
+ platform: Literal["meta"],
+ title: str,
+ account_id: str | Omit = omit,
+ bid_type: Literal["minimum_cost", "average_target", "maximum_target"] | Omit = omit,
+ budget_amount: float | Omit = omit,
+ budget_optimization: Literal["ad_campaign", "ad_group"] | Omit = omit,
+ budget_type: Literal["daily", "lifetime"] | Omit = omit,
+ desired_cost_per_result: float | Omit = omit,
+ ends_at: str | Omit = omit,
+ special_ad_categories: List[Literal["housing", "employment", "financial_products", "politics"]] | Omit = omit,
+ starts_at: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AdCampaign:
+ """
+ Creates an ad campaign for an account.
+
+ Args:
+ objective: The goal the campaign optimizes toward.
+
+ platform: The ad network the campaign runs on.
+
+ title: The title of the campaign.
+
+ account_id: The account to create the campaign under. Defaults to the account-scoped key's
+ own account.
+
+ bid_type: CBO bid strategy: minimum_cost (lowest cost), average_target (cost cap), or
+ maximum_target (bid cap). CBO only.
+
+ budget_amount:
+ The campaign budget, in USD. Required for CBO (budget_optimization:
+ ad_campaign); omit for ABO.
+
+ budget_optimization: Which level owns the budget — the campaign (CBO) or each ad group (ABO).
+ Defaults to ad_group.
+
+ budget_type: Whether the budget is spent per day or over the campaign's lifetime. Defaults to
+ daily.
+
+ desired_cost_per_result: Target/cap cost per result in USD for average_target / maximum_target bidding.
+ CBO only.
+
+ ends_at: Campaign schedule end (ISO 8601). CBO only.
+
+ special_ad_categories: Regulated categories the campaign falls under. Ads in these categories are
+ subject to extra targeting restrictions.
+
+ starts_at: Campaign schedule start (ISO 8601). CBO only.
+
+ 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(
+ "/ad_campaigns",
+ body=await async_maybe_transform(
+ {
+ "objective": objective,
+ "platform": platform,
+ "title": title,
+ "account_id": account_id,
+ "bid_type": bid_type,
+ "budget_amount": budget_amount,
+ "budget_optimization": budget_optimization,
+ "budget_type": budget_type,
+ "desired_cost_per_result": desired_cost_per_result,
+ "ends_at": ends_at,
+ "special_ad_categories": special_ad_categories,
+ "starts_at": starts_at,
+ },
+ ad_campaign_create_params.AdCampaignCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AdCampaign,
+ )
+
async def retrieve(
self,
id: str,
*,
+ stats_from: str | Omit = omit,
+ stats_to: 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.
extra_headers: Headers | None = None,
@@ -317,13 +590,13 @@ async def retrieve(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdCampaign:
"""
- Retrieves a single ad campaign by its unique identifier.
+ Retrieves a single ad campaign with stats over the requested window.
- Required permissions:
+ Args:
+ stats_from: Start of the stats window.
- - `ad_campaign:basic:read`
+ stats_to: End of the stats window.
- Args:
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -337,7 +610,17 @@ async def retrieve(
return await self._get(
path_template("/ad_campaigns/{id}", id=id),
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "stats_from": stats_from,
+ "stats_to": stats_to,
+ },
+ ad_campaign_retrieve_params.AdCampaignRetrieveParams,
+ ),
),
cast_to=AdCampaign,
)
@@ -346,7 +629,11 @@ async def update(
self,
id: str,
*,
- budget: Optional[float] | Omit = omit,
+ budget_amount: float | Omit = omit,
+ ends_at: str | Omit = omit,
+ starts_at: str | Omit = omit,
+ status: Literal["active"] | Omit = omit,
+ title: 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.
extra_headers: Headers | None = None,
@@ -355,15 +642,23 @@ async def update(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdCampaign:
"""
- Updates an ad campaign synchronously.
+ Updates an ad campaign's editable fields (title, budget, schedule), and launches
+ a draft campaign by setting status to active. Objective, budget optimization,
+ budget type, special ad categories, bid type and desired cost per result are
+ fixed at creation and cannot be changed.
- Required permissions:
+ Args:
+ budget_amount: The campaign budget, in the account's currency. Interpreted as daily or lifetime
+ per the campaign's existing budget type.
- - `ad_campaign:update`
+ ends_at: Campaign schedule end (ISO 8601). CBO only.
- Args:
- budget: The campaign budget in dollars. The interpretation (daily or lifetime) follows
- the campaign's existing budget type.
+ starts_at: Campaign schedule start (ISO 8601). CBO only.
+
+ status: Set to active to launch a draft campaign (moderates and pushes it live).
+ Live-campaign pause and resume use the pause and unpause actions.
+
+ title: The name of the campaign.
extra_headers: Send extra headers
@@ -377,7 +672,16 @@ async def update(
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._patch(
path_template("/ad_campaigns/{id}", id=id),
- body=await async_maybe_transform({"budget": budget}, ad_campaign_update_params.AdCampaignUpdateParams),
+ body=await async_maybe_transform(
+ {
+ "budget_amount": budget_amount,
+ "ends_at": ends_at,
+ "starts_at": starts_at,
+ "status": status,
+ "title": title,
+ },
+ ad_campaign_update_params.AdCampaignUpdateParams,
+ ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -387,48 +691,74 @@ async def update(
def list(
self,
*,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- company_id: Optional[str] | Omit = omit,
- created_after: Union[str, datetime, None] | Omit = omit,
- created_before: Union[str, datetime, None] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[int] | Omit = omit,
- query: Optional[str] | Omit = omit,
- status: Optional[AdCampaignStatus] | Omit = omit,
+ account_id: str | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ created_after: str | Omit = omit,
+ created_before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal[
+ "created_at",
+ "updated_at",
+ "spend",
+ "impressions",
+ "clicks",
+ "reach",
+ "unique_clicks",
+ "results",
+ "click_through_rate",
+ "cost_per_click",
+ "cost_per_mille",
+ "cost_per_result",
+ "frequency",
+ "return_on_ad_spend",
+ ]
+ | Omit = omit,
+ query: str | Omit = omit,
+ stats_from: str | Omit = omit,
+ stats_to: str | Omit = omit,
+ status: Literal["draft", "active", "paused", "payment_failed"] | 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[AdCampaignListResponse, AsyncCursorPage[AdCampaignListResponse]]:
+ ) -> AsyncPaginator[AdCampaign, AsyncCursorPage[AdCampaign]]:
"""
- Returns a paginated list of ad campaigns for a company, with optional filtering
- by status, and creation date.
+ Lists the ad campaigns for an account, with stats over the requested window.
- Required permissions:
+ Args:
+ account_id: The account the campaigns belong to. Defaults to the account-scoped key's own
+ account.
- - `ad_campaign:basic:read`
+ after: Cursor to fetch the page after (from page_info.end_cursor).
- Args:
- after: Returns the elements in the list that come after the specified cursor.
+ before: Cursor to fetch the page before (from page_info.start_cursor).
- before: Returns the elements in the list that come before the specified cursor.
+ created_after: Only return campaigns created after this timestamp.
- company_id: The unique identifier of the company to list ad campaigns for.
+ created_before: Only return campaigns created before this timestamp.
- created_after: Only return ad campaigns created after this timestamp.
+ direction: The sort direction. Defaults to desc.
- created_before: Only return ad campaigns created before this timestamp.
+ first: The number of campaigns to return.
- first: Returns the first _n_ elements from the list.
+ last: The number of campaigns to return from the end of the range.
- last: Returns the last _n_ elements from the list.
+ order: The field to sort by. Defaults to created_at. Stat columns (spend, impressions,
+ …) rank over the stats_from/stats_to window across the whole list, not just the
+ current page.
- query: Case-insensitive substring match against the campaign title.
+ query: Filter campaigns by a title or ID substring.
- status: The status of an ad campaign.
+ stats_from: Start of the stats window. Defaults to all-time.
+
+ stats_to: End of the stats window. Defaults to now.
+
+ status: Only return campaigns with this status.
extra_headers: Send extra headers
@@ -440,7 +770,7 @@ def list(
"""
return self._get_api_list(
"/ad_campaigns",
- page=AsyncCursorPage[AdCampaignListResponse],
+ page=AsyncCursorPage[AdCampaign],
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -448,23 +778,27 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "account_id": account_id,
"after": after,
"before": before,
- "company_id": company_id,
"created_after": created_after,
"created_before": created_before,
+ "direction": direction,
"first": first,
"last": last,
+ "order": order,
"query": query,
+ "stats_from": stats_from,
+ "stats_to": stats_to,
"status": status,
},
ad_campaign_list_params.AdCampaignListParams,
),
),
- model=AdCampaignListResponse,
+ model=AdCampaign,
)
- async def pause(
+ async def delete(
self,
id: str,
*,
@@ -474,13 +808,43 @@ async def pause(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> AdCampaign:
+ ) -> AdCampaignDeleteResponse:
"""
- Pauses an ad campaign, optionally until a specific date.
+ Deletes an ad campaign and archives it on the ad platform (cascades to ad groups
+ and ads). Returns true on success.
- Required permissions:
+ Args:
+ extra_headers: Send extra headers
- - `ad_campaign:update`
+ 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._delete(
+ path_template("/ad_campaigns/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AdCampaignDeleteResponse,
+ )
+
+ async def pause(
+ 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,
+ ) -> AdCampaign:
+ """
+ Pauses an active ad campaign.
Args:
extra_headers: Send extra headers
@@ -515,10 +879,6 @@ async def unpause(
"""
Resumes a paused ad campaign.
- Required permissions:
-
- - `ad_campaign:update`
-
Args:
extra_headers: Send extra headers
@@ -543,6 +903,9 @@ class AdCampaignsResourceWithRawResponse:
def __init__(self, ad_campaigns: AdCampaignsResource) -> None:
self._ad_campaigns = ad_campaigns
+ self.create = to_raw_response_wrapper(
+ ad_campaigns.create,
+ )
self.retrieve = to_raw_response_wrapper(
ad_campaigns.retrieve,
)
@@ -552,6 +915,9 @@ def __init__(self, ad_campaigns: AdCampaignsResource) -> None:
self.list = to_raw_response_wrapper(
ad_campaigns.list,
)
+ self.delete = to_raw_response_wrapper(
+ ad_campaigns.delete,
+ )
self.pause = to_raw_response_wrapper(
ad_campaigns.pause,
)
@@ -564,6 +930,9 @@ class AsyncAdCampaignsResourceWithRawResponse:
def __init__(self, ad_campaigns: AsyncAdCampaignsResource) -> None:
self._ad_campaigns = ad_campaigns
+ self.create = async_to_raw_response_wrapper(
+ ad_campaigns.create,
+ )
self.retrieve = async_to_raw_response_wrapper(
ad_campaigns.retrieve,
)
@@ -573,6 +942,9 @@ def __init__(self, ad_campaigns: AsyncAdCampaignsResource) -> None:
self.list = async_to_raw_response_wrapper(
ad_campaigns.list,
)
+ self.delete = async_to_raw_response_wrapper(
+ ad_campaigns.delete,
+ )
self.pause = async_to_raw_response_wrapper(
ad_campaigns.pause,
)
@@ -585,6 +957,9 @@ class AdCampaignsResourceWithStreamingResponse:
def __init__(self, ad_campaigns: AdCampaignsResource) -> None:
self._ad_campaigns = ad_campaigns
+ self.create = to_streamed_response_wrapper(
+ ad_campaigns.create,
+ )
self.retrieve = to_streamed_response_wrapper(
ad_campaigns.retrieve,
)
@@ -594,6 +969,9 @@ def __init__(self, ad_campaigns: AdCampaignsResource) -> None:
self.list = to_streamed_response_wrapper(
ad_campaigns.list,
)
+ self.delete = to_streamed_response_wrapper(
+ ad_campaigns.delete,
+ )
self.pause = to_streamed_response_wrapper(
ad_campaigns.pause,
)
@@ -606,6 +984,9 @@ class AsyncAdCampaignsResourceWithStreamingResponse:
def __init__(self, ad_campaigns: AsyncAdCampaignsResource) -> None:
self._ad_campaigns = ad_campaigns
+ self.create = async_to_streamed_response_wrapper(
+ ad_campaigns.create,
+ )
self.retrieve = async_to_streamed_response_wrapper(
ad_campaigns.retrieve,
)
@@ -615,6 +996,9 @@ def __init__(self, ad_campaigns: AsyncAdCampaignsResource) -> None:
self.list = async_to_streamed_response_wrapper(
ad_campaigns.list,
)
+ self.delete = async_to_streamed_response_wrapper(
+ ad_campaigns.delete,
+ )
self.pause = async_to_streamed_response_wrapper(
ad_campaigns.pause,
)
diff --git a/src/whop_sdk/resources/ad_groups.py b/src/whop_sdk/resources/ad_groups.py
index 25cdded6..1ebaf668 100644
--- a/src/whop_sdk/resources/ad_groups.py
+++ b/src/whop_sdk/resources/ad_groups.py
@@ -2,13 +2,13 @@
from __future__ import annotations
-from typing import Union, Optional
-from datetime import datetime
+from typing import List, Union
+from typing_extensions import Literal
import httpx
-from ..types import AdBudgetType, AdGroupStatus, ad_group_list_params, ad_group_update_params
-from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ..types import ad_group_list_params, ad_group_create_params, ad_group_update_params, ad_group_retrieve_params
+from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
@@ -21,17 +21,12 @@
from ..pagination import SyncCursorPage, AsyncCursorPage
from .._base_client import AsyncPaginator, make_request_options
from ..types.ad_group import AdGroup
-from ..types.ad_budget_type import AdBudgetType
-from ..types.ad_group_status import AdGroupStatus
-from ..types.ad_group_list_response import AdGroupListResponse
from ..types.ad_group_delete_response import AdGroupDeleteResponse
__all__ = ["AdGroupsResource", "AsyncAdGroupsResource"]
class AdGroupsResource(SyncAPIResource):
- """Ad groups"""
-
@cached_property
def with_raw_response(self) -> AdGroupsResourceWithRawResponse:
"""
@@ -51,10 +46,174 @@ def with_streaming_response(self) -> AdGroupsResourceWithStreamingResponse:
"""
return AdGroupsResourceWithStreamingResponse(self)
+ def create(
+ self,
+ *,
+ ad_campaign_id: str,
+ audiences: object | Omit = omit,
+ bid_type: Literal["minimum_cost", "average_target", "maximum_target"] | Omit = omit,
+ budget_amount: float | Omit = omit,
+ budget_type: Literal["daily", "lifetime"] | Omit = omit,
+ conversion_event: Union[
+ Literal[
+ "purchase",
+ "add_to_cart",
+ "initiated_checkout",
+ "add_payment_info",
+ "complete_registration",
+ "lead",
+ "content_view",
+ "search",
+ "contact",
+ "customize_product",
+ "donate",
+ "find_location",
+ "schedule",
+ "start_trial",
+ "submit_application",
+ "subscribe",
+ ],
+ str,
+ None,
+ ]
+ | Omit = omit,
+ conversion_location: Literal[
+ "website",
+ "profile",
+ "messaging",
+ "on_ad",
+ "instant_forms",
+ "instant_forms_and_messenger",
+ "website_and_instant_forms",
+ ]
+ | Omit = omit,
+ demographics: object | Omit = omit,
+ desired_cost_per_result: float | Omit = omit,
+ devices: object | Omit = omit,
+ dynamic_creative: bool | Omit = omit,
+ ends_at: str | Omit = omit,
+ frequency_cap: object | Omit = omit,
+ languages: SequenceNotStr[str] | Omit = omit,
+ message_apps: List[Literal["messenger", "instagram", "whatsapp"]] | Omit = omit,
+ minimum_daily_spend: float | Omit = omit,
+ optimization_goal: str | Omit = omit,
+ placements: object | Omit = omit,
+ regions: object | Omit = omit,
+ starts_at: str | Omit = omit,
+ status: Literal["active", "paused"] | Omit = omit,
+ title: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AdGroup:
+ """
+ Creates an ad group (ad set) in a campaign.
+
+ Args:
+ ad_campaign_id: The ad campaign to create the ad group in.
+
+ audiences: Saved-audience targeting: { include, exclude } arrays of audience IDs.
+ Incompatible with demographics.automatic (Advantage+).
+
+ bid_type: Bid strategy.
+
+ budget_amount: Ad-set budget in dollars (ABO only; omit under CBO).
+
+ budget_type: Whether the budget is daily or lifetime.
+
+ conversion_event: The pixel event optimized for. A standard event, or any custom pixel event name.
+
+ conversion_location: Where results happen: website (conversions), profile (IG/FB engagement),
+ messaging (DM), on_ad (engagement on the ad, surface follows the optimization
+ goal), or the lead destinations (instant_forms, instant_forms_and_messenger,
+ website_and_instant_forms). The lead form itself is set on the ad.
+
+ demographics: Demographic targeting: { automatic, minimum_age, maximum_age, gender }.
+
+ desired_cost_per_result: Target/cap cost for average_target / maximum_target.
+
+ devices: Device targeting: { platforms, operating_systems: [{ os, minimum_version }] }.
+
+ dynamic_creative: Run Meta dynamic (Advantage+) creative for this ad set. Set at creation;
+ immutable afterward.
+
+ ends_at: Schedule end, ISO 8601.
+
+ frequency_cap: { maximum_impressions, per_days } — only valid for reach optimization.
+
+ languages: Languages to target as ISO 639 codes (e.g. en, es). Empty/omitted = all
+ languages.
+
+ message_apps: Required when conversion_location is messaging: which apps to message on.
+ Combinations map to the matching Meta destination.
+
+ minimum_daily_spend: Daily spend floor within the budget.
+
+ optimization_goal: What the ad group optimizes for (e.g. conversions, link_clicks, reach).
+
+ placements: 'automatic' (Advantage+) or a list of { platform, positions }.
+
+ regions: Geo targeting: { include / exclude: { countries (ISO 3166-1), regions
+ (states/provinces as ISO 3166-2, e.g. US-CA), cities (keyed), zips } }.
+
+ starts_at: Schedule start, ISO 8601.
+
+ status: Initial status (default: active).
+
+ title: The display name of the ad group.
+
+ 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(
+ "/ad_groups",
+ body=maybe_transform(
+ {
+ "ad_campaign_id": ad_campaign_id,
+ "audiences": audiences,
+ "bid_type": bid_type,
+ "budget_amount": budget_amount,
+ "budget_type": budget_type,
+ "conversion_event": conversion_event,
+ "conversion_location": conversion_location,
+ "demographics": demographics,
+ "desired_cost_per_result": desired_cost_per_result,
+ "devices": devices,
+ "dynamic_creative": dynamic_creative,
+ "ends_at": ends_at,
+ "frequency_cap": frequency_cap,
+ "languages": languages,
+ "message_apps": message_apps,
+ "minimum_daily_spend": minimum_daily_spend,
+ "optimization_goal": optimization_goal,
+ "placements": placements,
+ "regions": regions,
+ "starts_at": starts_at,
+ "status": status,
+ "title": title,
+ },
+ ad_group_create_params.AdGroupCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AdGroup,
+ )
+
def retrieve(
self,
id: str,
*,
+ stats_from: str | Omit = omit,
+ stats_to: 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.
extra_headers: Headers | None = None,
@@ -63,13 +222,13 @@ def retrieve(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdGroup:
"""
- Retrieves a single ad group by its unique identifier.
+ Retrieves a single ad group.
- Required permissions:
+ Args:
+ stats_from: Start of the stats window.
- - `ad_campaign:basic:read`
+ stats_to: End of the stats window.
- Args:
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -83,7 +242,17 @@ def retrieve(
return self._get(
path_template("/ad_groups/{id}", id=id),
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "stats_from": stats_from,
+ "stats_to": stats_to,
+ },
+ ad_group_retrieve_params.AdGroupRetrieveParams,
+ ),
),
cast_to=AdGroup,
)
@@ -92,13 +261,57 @@ def update(
self,
id: str,
*,
- budget: Optional[float] | Omit = omit,
- budget_type: Optional[AdBudgetType] | Omit = omit,
- config: Optional[ad_group_update_params.Config] | Omit = omit,
- daily_budget: Optional[float] | Omit = omit,
- name: Optional[str] | Omit = omit,
- platform_config: Optional[ad_group_update_params.PlatformConfig] | Omit = omit,
- status: Optional[AdGroupStatus] | Omit = omit,
+ audiences: object | Omit = omit,
+ bid_type: Literal["minimum_cost", "average_target", "maximum_target"] | Omit = omit,
+ budget_amount: float | Omit = omit,
+ budget_type: Literal["daily", "lifetime"] | Omit = omit,
+ conversion_event: Union[
+ Literal[
+ "purchase",
+ "add_to_cart",
+ "initiated_checkout",
+ "add_payment_info",
+ "complete_registration",
+ "lead",
+ "content_view",
+ "search",
+ "contact",
+ "customize_product",
+ "donate",
+ "find_location",
+ "schedule",
+ "start_trial",
+ "submit_application",
+ "subscribe",
+ ],
+ str,
+ None,
+ ]
+ | Omit = omit,
+ conversion_location: Literal[
+ "website",
+ "profile",
+ "messaging",
+ "on_ad",
+ "instant_forms",
+ "instant_forms_and_messenger",
+ "website_and_instant_forms",
+ ]
+ | Omit = omit,
+ demographics: object | Omit = omit,
+ desired_cost_per_result: float | Omit = omit,
+ devices: object | Omit = omit,
+ ends_at: str | Omit = omit,
+ frequency_cap: object | Omit = omit,
+ languages: SequenceNotStr[str] | Omit = omit,
+ message_apps: List[Literal["messenger", "instagram", "whatsapp"]] | Omit = omit,
+ minimum_daily_spend: float | Omit = omit,
+ optimization_goal: str | Omit = omit,
+ placements: object | Omit = omit,
+ regions: object | Omit = omit,
+ starts_at: str | Omit = omit,
+ status: Literal["active", "paused"] | Omit = omit,
+ title: 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.
extra_headers: Headers | None = None,
@@ -106,28 +319,57 @@ def update(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdGroup:
- """
- Updates an existing ad group.
+ """Updates an ad group's editable fields.
- Required permissions:
-
- - `ad_campaign:update`
- - `ad_campaign:basic:read`
+ Only the keys you send are changed.
Args:
- budget: Budget amount in dollars.
+ audiences: Saved-audience targeting: { include, exclude } arrays of audience IDs.
+ Incompatible with demographics.automatic (Advantage+).
+
+ bid_type: Bid strategy.
+
+ budget_amount: Ad-set budget in dollars (ABO only; omit under CBO).
- budget_type: The budget type for an ad campaign or ad group.
+ budget_type: Whether the budget is daily or lifetime.
- config: Unified ad group configuration (bidding, optimization, targeting).
+ conversion_event: The pixel event optimized for. A standard event, or any custom pixel event name.
- daily_budget: Daily budget in dollars.
+ conversion_location: Where results happen: website (conversions), profile (IG/FB engagement),
+ messaging (DM), on_ad (engagement on the ad, surface follows the optimization
+ goal), or the lead destinations (instant_forms, instant_forms_and_messenger,
+ website_and_instant_forms). The lead form itself is set on the ad.
- name: Human-readable ad group name.
+ demographics: Demographic targeting: { automatic, minimum_age, maximum_age, gender }.
- platform_config: Platform-specific ad group configuration.
+ desired_cost_per_result: Target/cap cost for average_target / maximum_target.
- status: The status of an external ad group.
+ devices: Device targeting: { platforms, operating_systems: [{ os, minimum_version }] }.
+
+ ends_at: Schedule end, ISO 8601.
+
+ frequency_cap: { maximum_impressions, per_days } — only valid for reach optimization.
+
+ languages: Languages to target as ISO 639 codes (e.g. en, es). Empty/omitted = all
+ languages.
+
+ message_apps: Required when conversion_location is messaging: which apps to message on.
+ Combinations map to the matching Meta destination.
+
+ minimum_daily_spend: Daily spend floor within the budget.
+
+ optimization_goal: What the ad group optimizes for (e.g. conversions, link_clicks, reach).
+
+ placements: 'automatic' (Advantage+) or a list of { platform, positions }.
+
+ regions: Geo targeting: { include / exclude: { countries (ISO 3166-1), regions
+ (states/provinces as ISO 3166-2, e.g. US-CA), cities (keyed), zips } }.
+
+ starts_at: Schedule start, ISO 8601.
+
+ status: Initial status (default: active).
+
+ title: The display name of the ad group.
extra_headers: Send extra headers
@@ -143,13 +385,26 @@ def update(
path_template("/ad_groups/{id}", id=id),
body=maybe_transform(
{
- "budget": budget,
+ "audiences": audiences,
+ "bid_type": bid_type,
+ "budget_amount": budget_amount,
"budget_type": budget_type,
- "config": config,
- "daily_budget": daily_budget,
- "name": name,
- "platform_config": platform_config,
+ "conversion_event": conversion_event,
+ "conversion_location": conversion_location,
+ "demographics": demographics,
+ "desired_cost_per_result": desired_cost_per_result,
+ "devices": devices,
+ "ends_at": ends_at,
+ "frequency_cap": frequency_cap,
+ "languages": languages,
+ "message_apps": message_apps,
+ "minimum_daily_spend": minimum_daily_spend,
+ "optimization_goal": optimization_goal,
+ "placements": placements,
+ "regions": regions,
+ "starts_at": starts_at,
"status": status,
+ "title": title,
},
ad_group_update_params.AdGroupUpdateParams,
),
@@ -162,55 +417,76 @@ def update(
def list(
self,
*,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- campaign_id: Optional[str] | Omit = omit,
- company_id: Optional[str] | Omit = omit,
- created_after: Union[str, datetime, None] | Omit = omit,
- created_before: Union[str, datetime, None] | Omit = omit,
- first: Optional[int] | Omit = omit,
- include_paused: Optional[bool] | Omit = omit,
- last: Optional[int] | Omit = omit,
- query: Optional[str] | Omit = omit,
- status: Optional[AdGroupStatus] | Omit = omit,
+ account_id: str | Omit = omit,
+ ad_campaign_id: str | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ created_after: str | Omit = omit,
+ created_before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal[
+ "created_at",
+ "updated_at",
+ "spend",
+ "impressions",
+ "clicks",
+ "reach",
+ "unique_clicks",
+ "results",
+ "click_through_rate",
+ "cost_per_click",
+ "cost_per_mille",
+ "cost_per_result",
+ "frequency",
+ "return_on_ad_spend",
+ ]
+ | Omit = omit,
+ query: str | Omit = omit,
+ stats_from: str | Omit = omit,
+ stats_to: str | Omit = omit,
+ status: 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.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> SyncCursorPage[AdGroupListResponse]:
+ ) -> SyncCursorPage[AdGroup]:
"""
- Returns a paginated list of ad groups scoped by campaign or company, with
- optional filtering by status and creation date.
-
- Required permissions:
-
- - `ad_campaign:basic:read`
+ Lists ad groups for the account, newest first.
Args:
- after: Returns the elements in the list that come after the specified cursor.
+ account_id: Account whose ad groups to list. Defaults to the authenticated account.
- before: Returns the elements in the list that come before the specified cursor.
+ ad_campaign_id: Filter to ad groups in this campaign.
- campaign_id: Filter by campaign. Provide exactly one of campaign_id or company_id.
+ after: Cursor to fetch the page after (from page_info.end_cursor).
- company_id: Filter by company. Provide exactly one of campaign_id or company_id.
+ before: Cursor to fetch the page before (from page_info.start_cursor).
created_after: Only return ad groups created after this timestamp.
created_before: Only return ad groups created before this timestamp.
- first: Returns the first _n_ elements from the list.
+ direction: The sort direction. Defaults to desc.
+
+ first: The number of ad groups to return.
+
+ last: The number of ad groups to return from the end of the range.
- include_paused: When false, excludes paused ad groups so pagination matches the dashboard's
- hide-paused toggle.
+ order: The field to sort by. Defaults to created_at. Stat columns (spend, impressions,
+ …) rank over the stats_from/stats_to window across the whole list, not just the
+ current page.
- last: Returns the last _n_ elements from the list.
+ query: Filter ad groups by a title or ID substring.
- query: Case-insensitive substring match against the ad group name.
+ stats_from: Start of the stats window. Defaults to all-time.
- status: The status of an external ad group.
+ stats_to: End of the stats window. Defaults to now.
+
+ status: Filter to a status (active, paused, in_review, rejected).
extra_headers: Send extra headers
@@ -222,7 +498,7 @@ def list(
"""
return self._get_api_list(
"/ad_groups",
- page=SyncCursorPage[AdGroupListResponse],
+ page=SyncCursorPage[AdGroup],
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -230,22 +506,25 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "account_id": account_id,
+ "ad_campaign_id": ad_campaign_id,
"after": after,
"before": before,
- "campaign_id": campaign_id,
- "company_id": company_id,
"created_after": created_after,
"created_before": created_before,
+ "direction": direction,
"first": first,
- "include_paused": include_paused,
"last": last,
+ "order": order,
"query": query,
+ "stats_from": stats_from,
+ "stats_to": stats_to,
"status": status,
},
ad_group_list_params.AdGroupListParams,
),
),
- model=AdGroupListResponse,
+ model=AdGroup,
)
def delete(
@@ -259,12 +538,9 @@ def delete(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdGroupDeleteResponse:
- """
- Soft-deletes an ad group.
-
- Required permissions:
+ """Deletes an ad group.
- - `ad_campaign:update`
+ Returns true on success.
Args:
extra_headers: Send extra headers
@@ -297,12 +573,7 @@ def pause(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdGroup:
"""
- Pauses an ad group.
-
- Required permissions:
-
- - `ad_campaign:update`
- - `ad_campaign:basic:read`
+ Pauses delivery of an ad group.
Args:
extra_headers: Send extra headers
@@ -335,12 +606,7 @@ def unpause(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdGroup:
"""
- Resumes a paused ad group.
-
- Required permissions:
-
- - `ad_campaign:update`
- - `ad_campaign:basic:read`
+ Resumes delivery of a paused ad group.
Args:
extra_headers: Send extra headers
@@ -363,8 +629,6 @@ def unpause(
class AsyncAdGroupsResource(AsyncAPIResource):
- """Ad groups"""
-
@cached_property
def with_raw_response(self) -> AsyncAdGroupsResourceWithRawResponse:
"""
@@ -384,10 +648,174 @@ def with_streaming_response(self) -> AsyncAdGroupsResourceWithStreamingResponse:
"""
return AsyncAdGroupsResourceWithStreamingResponse(self)
+ async def create(
+ self,
+ *,
+ ad_campaign_id: str,
+ audiences: object | Omit = omit,
+ bid_type: Literal["minimum_cost", "average_target", "maximum_target"] | Omit = omit,
+ budget_amount: float | Omit = omit,
+ budget_type: Literal["daily", "lifetime"] | Omit = omit,
+ conversion_event: Union[
+ Literal[
+ "purchase",
+ "add_to_cart",
+ "initiated_checkout",
+ "add_payment_info",
+ "complete_registration",
+ "lead",
+ "content_view",
+ "search",
+ "contact",
+ "customize_product",
+ "donate",
+ "find_location",
+ "schedule",
+ "start_trial",
+ "submit_application",
+ "subscribe",
+ ],
+ str,
+ None,
+ ]
+ | Omit = omit,
+ conversion_location: Literal[
+ "website",
+ "profile",
+ "messaging",
+ "on_ad",
+ "instant_forms",
+ "instant_forms_and_messenger",
+ "website_and_instant_forms",
+ ]
+ | Omit = omit,
+ demographics: object | Omit = omit,
+ desired_cost_per_result: float | Omit = omit,
+ devices: object | Omit = omit,
+ dynamic_creative: bool | Omit = omit,
+ ends_at: str | Omit = omit,
+ frequency_cap: object | Omit = omit,
+ languages: SequenceNotStr[str] | Omit = omit,
+ message_apps: List[Literal["messenger", "instagram", "whatsapp"]] | Omit = omit,
+ minimum_daily_spend: float | Omit = omit,
+ optimization_goal: str | Omit = omit,
+ placements: object | Omit = omit,
+ regions: object | Omit = omit,
+ starts_at: str | Omit = omit,
+ status: Literal["active", "paused"] | Omit = omit,
+ title: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AdGroup:
+ """
+ Creates an ad group (ad set) in a campaign.
+
+ Args:
+ ad_campaign_id: The ad campaign to create the ad group in.
+
+ audiences: Saved-audience targeting: { include, exclude } arrays of audience IDs.
+ Incompatible with demographics.automatic (Advantage+).
+
+ bid_type: Bid strategy.
+
+ budget_amount: Ad-set budget in dollars (ABO only; omit under CBO).
+
+ budget_type: Whether the budget is daily or lifetime.
+
+ conversion_event: The pixel event optimized for. A standard event, or any custom pixel event name.
+
+ conversion_location: Where results happen: website (conversions), profile (IG/FB engagement),
+ messaging (DM), on_ad (engagement on the ad, surface follows the optimization
+ goal), or the lead destinations (instant_forms, instant_forms_and_messenger,
+ website_and_instant_forms). The lead form itself is set on the ad.
+
+ demographics: Demographic targeting: { automatic, minimum_age, maximum_age, gender }.
+
+ desired_cost_per_result: Target/cap cost for average_target / maximum_target.
+
+ devices: Device targeting: { platforms, operating_systems: [{ os, minimum_version }] }.
+
+ dynamic_creative: Run Meta dynamic (Advantage+) creative for this ad set. Set at creation;
+ immutable afterward.
+
+ ends_at: Schedule end, ISO 8601.
+
+ frequency_cap: { maximum_impressions, per_days } — only valid for reach optimization.
+
+ languages: Languages to target as ISO 639 codes (e.g. en, es). Empty/omitted = all
+ languages.
+
+ message_apps: Required when conversion_location is messaging: which apps to message on.
+ Combinations map to the matching Meta destination.
+
+ minimum_daily_spend: Daily spend floor within the budget.
+
+ optimization_goal: What the ad group optimizes for (e.g. conversions, link_clicks, reach).
+
+ placements: 'automatic' (Advantage+) or a list of { platform, positions }.
+
+ regions: Geo targeting: { include / exclude: { countries (ISO 3166-1), regions
+ (states/provinces as ISO 3166-2, e.g. US-CA), cities (keyed), zips } }.
+
+ starts_at: Schedule start, ISO 8601.
+
+ status: Initial status (default: active).
+
+ title: The display name of the ad group.
+
+ 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(
+ "/ad_groups",
+ body=await async_maybe_transform(
+ {
+ "ad_campaign_id": ad_campaign_id,
+ "audiences": audiences,
+ "bid_type": bid_type,
+ "budget_amount": budget_amount,
+ "budget_type": budget_type,
+ "conversion_event": conversion_event,
+ "conversion_location": conversion_location,
+ "demographics": demographics,
+ "desired_cost_per_result": desired_cost_per_result,
+ "devices": devices,
+ "dynamic_creative": dynamic_creative,
+ "ends_at": ends_at,
+ "frequency_cap": frequency_cap,
+ "languages": languages,
+ "message_apps": message_apps,
+ "minimum_daily_spend": minimum_daily_spend,
+ "optimization_goal": optimization_goal,
+ "placements": placements,
+ "regions": regions,
+ "starts_at": starts_at,
+ "status": status,
+ "title": title,
+ },
+ ad_group_create_params.AdGroupCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AdGroup,
+ )
+
async def retrieve(
self,
id: str,
*,
+ stats_from: str | Omit = omit,
+ stats_to: 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.
extra_headers: Headers | None = None,
@@ -396,13 +824,13 @@ async def retrieve(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdGroup:
"""
- Retrieves a single ad group by its unique identifier.
+ Retrieves a single ad group.
- Required permissions:
+ Args:
+ stats_from: Start of the stats window.
- - `ad_campaign:basic:read`
+ stats_to: End of the stats window.
- Args:
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -416,7 +844,17 @@ async def retrieve(
return await self._get(
path_template("/ad_groups/{id}", id=id),
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "stats_from": stats_from,
+ "stats_to": stats_to,
+ },
+ ad_group_retrieve_params.AdGroupRetrieveParams,
+ ),
),
cast_to=AdGroup,
)
@@ -425,13 +863,57 @@ async def update(
self,
id: str,
*,
- budget: Optional[float] | Omit = omit,
- budget_type: Optional[AdBudgetType] | Omit = omit,
- config: Optional[ad_group_update_params.Config] | Omit = omit,
- daily_budget: Optional[float] | Omit = omit,
- name: Optional[str] | Omit = omit,
- platform_config: Optional[ad_group_update_params.PlatformConfig] | Omit = omit,
- status: Optional[AdGroupStatus] | Omit = omit,
+ audiences: object | Omit = omit,
+ bid_type: Literal["minimum_cost", "average_target", "maximum_target"] | Omit = omit,
+ budget_amount: float | Omit = omit,
+ budget_type: Literal["daily", "lifetime"] | Omit = omit,
+ conversion_event: Union[
+ Literal[
+ "purchase",
+ "add_to_cart",
+ "initiated_checkout",
+ "add_payment_info",
+ "complete_registration",
+ "lead",
+ "content_view",
+ "search",
+ "contact",
+ "customize_product",
+ "donate",
+ "find_location",
+ "schedule",
+ "start_trial",
+ "submit_application",
+ "subscribe",
+ ],
+ str,
+ None,
+ ]
+ | Omit = omit,
+ conversion_location: Literal[
+ "website",
+ "profile",
+ "messaging",
+ "on_ad",
+ "instant_forms",
+ "instant_forms_and_messenger",
+ "website_and_instant_forms",
+ ]
+ | Omit = omit,
+ demographics: object | Omit = omit,
+ desired_cost_per_result: float | Omit = omit,
+ devices: object | Omit = omit,
+ ends_at: str | Omit = omit,
+ frequency_cap: object | Omit = omit,
+ languages: SequenceNotStr[str] | Omit = omit,
+ message_apps: List[Literal["messenger", "instagram", "whatsapp"]] | Omit = omit,
+ minimum_daily_spend: float | Omit = omit,
+ optimization_goal: str | Omit = omit,
+ placements: object | Omit = omit,
+ regions: object | Omit = omit,
+ starts_at: str | Omit = omit,
+ status: Literal["active", "paused"] | Omit = omit,
+ title: 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.
extra_headers: Headers | None = None,
@@ -439,28 +921,57 @@ async def update(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdGroup:
- """
- Updates an existing ad group.
+ """Updates an ad group's editable fields.
- Required permissions:
-
- - `ad_campaign:update`
- - `ad_campaign:basic:read`
+ Only the keys you send are changed.
Args:
- budget: Budget amount in dollars.
+ audiences: Saved-audience targeting: { include, exclude } arrays of audience IDs.
+ Incompatible with demographics.automatic (Advantage+).
+
+ bid_type: Bid strategy.
+
+ budget_amount: Ad-set budget in dollars (ABO only; omit under CBO).
+
+ budget_type: Whether the budget is daily or lifetime.
+
+ conversion_event: The pixel event optimized for. A standard event, or any custom pixel event name.
+
+ conversion_location: Where results happen: website (conversions), profile (IG/FB engagement),
+ messaging (DM), on_ad (engagement on the ad, surface follows the optimization
+ goal), or the lead destinations (instant_forms, instant_forms_and_messenger,
+ website_and_instant_forms). The lead form itself is set on the ad.
- budget_type: The budget type for an ad campaign or ad group.
+ demographics: Demographic targeting: { automatic, minimum_age, maximum_age, gender }.
- config: Unified ad group configuration (bidding, optimization, targeting).
+ desired_cost_per_result: Target/cap cost for average_target / maximum_target.
- daily_budget: Daily budget in dollars.
+ devices: Device targeting: { platforms, operating_systems: [{ os, minimum_version }] }.
- name: Human-readable ad group name.
+ ends_at: Schedule end, ISO 8601.
- platform_config: Platform-specific ad group configuration.
+ frequency_cap: { maximum_impressions, per_days } — only valid for reach optimization.
- status: The status of an external ad group.
+ languages: Languages to target as ISO 639 codes (e.g. en, es). Empty/omitted = all
+ languages.
+
+ message_apps: Required when conversion_location is messaging: which apps to message on.
+ Combinations map to the matching Meta destination.
+
+ minimum_daily_spend: Daily spend floor within the budget.
+
+ optimization_goal: What the ad group optimizes for (e.g. conversions, link_clicks, reach).
+
+ placements: 'automatic' (Advantage+) or a list of { platform, positions }.
+
+ regions: Geo targeting: { include / exclude: { countries (ISO 3166-1), regions
+ (states/provinces as ISO 3166-2, e.g. US-CA), cities (keyed), zips } }.
+
+ starts_at: Schedule start, ISO 8601.
+
+ status: Initial status (default: active).
+
+ title: The display name of the ad group.
extra_headers: Send extra headers
@@ -476,13 +987,26 @@ async def update(
path_template("/ad_groups/{id}", id=id),
body=await async_maybe_transform(
{
- "budget": budget,
+ "audiences": audiences,
+ "bid_type": bid_type,
+ "budget_amount": budget_amount,
"budget_type": budget_type,
- "config": config,
- "daily_budget": daily_budget,
- "name": name,
- "platform_config": platform_config,
+ "conversion_event": conversion_event,
+ "conversion_location": conversion_location,
+ "demographics": demographics,
+ "desired_cost_per_result": desired_cost_per_result,
+ "devices": devices,
+ "ends_at": ends_at,
+ "frequency_cap": frequency_cap,
+ "languages": languages,
+ "message_apps": message_apps,
+ "minimum_daily_spend": minimum_daily_spend,
+ "optimization_goal": optimization_goal,
+ "placements": placements,
+ "regions": regions,
+ "starts_at": starts_at,
"status": status,
+ "title": title,
},
ad_group_update_params.AdGroupUpdateParams,
),
@@ -495,55 +1019,76 @@ async def update(
def list(
self,
*,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- campaign_id: Optional[str] | Omit = omit,
- company_id: Optional[str] | Omit = omit,
- created_after: Union[str, datetime, None] | Omit = omit,
- created_before: Union[str, datetime, None] | Omit = omit,
- first: Optional[int] | Omit = omit,
- include_paused: Optional[bool] | Omit = omit,
- last: Optional[int] | Omit = omit,
- query: Optional[str] | Omit = omit,
- status: Optional[AdGroupStatus] | Omit = omit,
+ account_id: str | Omit = omit,
+ ad_campaign_id: str | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ created_after: str | Omit = omit,
+ created_before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal[
+ "created_at",
+ "updated_at",
+ "spend",
+ "impressions",
+ "clicks",
+ "reach",
+ "unique_clicks",
+ "results",
+ "click_through_rate",
+ "cost_per_click",
+ "cost_per_mille",
+ "cost_per_result",
+ "frequency",
+ "return_on_ad_spend",
+ ]
+ | Omit = omit,
+ query: str | Omit = omit,
+ stats_from: str | Omit = omit,
+ stats_to: str | Omit = omit,
+ status: 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.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> AsyncPaginator[AdGroupListResponse, AsyncCursorPage[AdGroupListResponse]]:
+ ) -> AsyncPaginator[AdGroup, AsyncCursorPage[AdGroup]]:
"""
- Returns a paginated list of ad groups scoped by campaign or company, with
- optional filtering by status and creation date.
-
- Required permissions:
-
- - `ad_campaign:basic:read`
+ Lists ad groups for the account, newest first.
Args:
- after: Returns the elements in the list that come after the specified cursor.
+ account_id: Account whose ad groups to list. Defaults to the authenticated account.
- before: Returns the elements in the list that come before the specified cursor.
+ ad_campaign_id: Filter to ad groups in this campaign.
- campaign_id: Filter by campaign. Provide exactly one of campaign_id or company_id.
+ after: Cursor to fetch the page after (from page_info.end_cursor).
- company_id: Filter by company. Provide exactly one of campaign_id or company_id.
+ before: Cursor to fetch the page before (from page_info.start_cursor).
created_after: Only return ad groups created after this timestamp.
created_before: Only return ad groups created before this timestamp.
- first: Returns the first _n_ elements from the list.
+ direction: The sort direction. Defaults to desc.
+
+ first: The number of ad groups to return.
+
+ last: The number of ad groups to return from the end of the range.
- include_paused: When false, excludes paused ad groups so pagination matches the dashboard's
- hide-paused toggle.
+ order: The field to sort by. Defaults to created_at. Stat columns (spend, impressions,
+ …) rank over the stats_from/stats_to window across the whole list, not just the
+ current page.
- last: Returns the last _n_ elements from the list.
+ query: Filter ad groups by a title or ID substring.
- query: Case-insensitive substring match against the ad group name.
+ stats_from: Start of the stats window. Defaults to all-time.
- status: The status of an external ad group.
+ stats_to: End of the stats window. Defaults to now.
+
+ status: Filter to a status (active, paused, in_review, rejected).
extra_headers: Send extra headers
@@ -555,7 +1100,7 @@ def list(
"""
return self._get_api_list(
"/ad_groups",
- page=AsyncCursorPage[AdGroupListResponse],
+ page=AsyncCursorPage[AdGroup],
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -563,22 +1108,25 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "account_id": account_id,
+ "ad_campaign_id": ad_campaign_id,
"after": after,
"before": before,
- "campaign_id": campaign_id,
- "company_id": company_id,
"created_after": created_after,
"created_before": created_before,
+ "direction": direction,
"first": first,
- "include_paused": include_paused,
"last": last,
+ "order": order,
"query": query,
+ "stats_from": stats_from,
+ "stats_to": stats_to,
"status": status,
},
ad_group_list_params.AdGroupListParams,
),
),
- model=AdGroupListResponse,
+ model=AdGroup,
)
async def delete(
@@ -592,12 +1140,9 @@ async def delete(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdGroupDeleteResponse:
- """
- Soft-deletes an ad group.
-
- Required permissions:
+ """Deletes an ad group.
- - `ad_campaign:update`
+ Returns true on success.
Args:
extra_headers: Send extra headers
@@ -630,12 +1175,7 @@ async def pause(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdGroup:
"""
- Pauses an ad group.
-
- Required permissions:
-
- - `ad_campaign:update`
- - `ad_campaign:basic:read`
+ Pauses delivery of an ad group.
Args:
extra_headers: Send extra headers
@@ -668,12 +1208,7 @@ async def unpause(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdGroup:
"""
- Resumes a paused ad group.
-
- Required permissions:
-
- - `ad_campaign:update`
- - `ad_campaign:basic:read`
+ Resumes delivery of a paused ad group.
Args:
extra_headers: Send extra headers
@@ -699,6 +1234,9 @@ class AdGroupsResourceWithRawResponse:
def __init__(self, ad_groups: AdGroupsResource) -> None:
self._ad_groups = ad_groups
+ self.create = to_raw_response_wrapper(
+ ad_groups.create,
+ )
self.retrieve = to_raw_response_wrapper(
ad_groups.retrieve,
)
@@ -723,6 +1261,9 @@ class AsyncAdGroupsResourceWithRawResponse:
def __init__(self, ad_groups: AsyncAdGroupsResource) -> None:
self._ad_groups = ad_groups
+ self.create = async_to_raw_response_wrapper(
+ ad_groups.create,
+ )
self.retrieve = async_to_raw_response_wrapper(
ad_groups.retrieve,
)
@@ -747,6 +1288,9 @@ class AdGroupsResourceWithStreamingResponse:
def __init__(self, ad_groups: AdGroupsResource) -> None:
self._ad_groups = ad_groups
+ self.create = to_streamed_response_wrapper(
+ ad_groups.create,
+ )
self.retrieve = to_streamed_response_wrapper(
ad_groups.retrieve,
)
@@ -771,6 +1315,9 @@ class AsyncAdGroupsResourceWithStreamingResponse:
def __init__(self, ad_groups: AsyncAdGroupsResource) -> None:
self._ad_groups = ad_groups
+ self.create = async_to_streamed_response_wrapper(
+ ad_groups.create,
+ )
self.retrieve = async_to_streamed_response_wrapper(
ad_groups.retrieve,
)
diff --git a/src/whop_sdk/resources/ad_reports.py b/src/whop_sdk/resources/ad_reports.py
index 1c8cbd81..232bd119 100644
--- a/src/whop_sdk/resources/ad_reports.py
+++ b/src/whop_sdk/resources/ad_reports.py
@@ -9,7 +9,7 @@
import httpx
from ..types import Granularities, ad_report_retrieve_params
-from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
from .._utils import maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
@@ -53,9 +53,9 @@ def retrieve(
*,
from_: Union[str, datetime],
to: Union[str, datetime],
- ad_campaign_id: Optional[str] | Omit = omit,
- ad_group_id: Optional[str] | Omit = omit,
- ad_id: Optional[str] | Omit = omit,
+ ad_campaign_ids: Optional[SequenceNotStr[str]] | Omit = omit,
+ ad_group_ids: Optional[SequenceNotStr[str]] | Omit = omit,
+ ad_ids: Optional[SequenceNotStr[str]] | Omit = omit,
breakdown: Optional[Literal["campaign", "ad_group", "ad"]] | Omit = omit,
company_id: Optional[str] | Omit = omit,
currency: Optional[str] | Omit = omit,
@@ -67,13 +67,13 @@ def retrieve(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdReportRetrieveResponse:
- """Performance report for a company, ad campaign, ad group, or ad.
+ """Performance report for a company, ad campaigns, ad groups, or ads.
- Always returns
- aggregate `summary` totals. Set `granularity` (`daily`/`hourly`) to additionally
- get a time series, or set `breakdown` (`campaign`/`ad_group`/`ad`) to
- additionally get per-entity rows inside the requested scope. Exactly one of
- `companyId`, `adCampaignId`, `adGroupId`, or `adId` must be provided.
+ Always
+ returns aggregate `summary` totals summed across the scope. Set `granularity` to
+ additionally get a time series, or set `breakdown` (`campaign`/`ad_group`/`ad`)
+ to additionally get per-entity rows inside the requested scope. Exactly one of
+ `companyId`, `adCampaignIds`, `adGroupIds`, or `adIds` must be provided.
Required permissions:
@@ -84,20 +84,20 @@ def retrieve(
to: Inclusive end of the reporting window.
- ad_campaign_id: The unique identifier of an ad campaign. Mutually exclusive with `companyId`,
- `adGroupId`, and `adId`.
+ ad_campaign_ids: Scope the report to these ad campaigns (max 100); stats are summed across them.
+ Mutually exclusive with `companyId`, `adGroupIds`, and `adIds`.
- ad_group_id: The unique identifier of an ad group. Mutually exclusive with `companyId`,
- `adCampaignId`, and `adId`.
+ ad_group_ids: Scope the report to these ad groups (max 100); stats are summed across them.
+ Mutually exclusive with `companyId`, `adCampaignIds`, and `adIds`.
- ad_id: The unique identifier of an ad. Mutually exclusive with `companyId`,
- `adCampaignId`, and `adGroupId`.
+ ad_ids: Scope the report to these ads (max 100); stats are summed across them. Mutually
+ exclusive with `companyId`, `adCampaignIds`, and `adGroupIds`.
breakdown: Entity level to group an ad report by.
- company_id: The unique identifier of a company. Mutually exclusive with `adCampaignId`,
- `adGroupId`, and `adId`. Use with `breakdown` to fan out across every campaign,
- ad group, or ad in the company without paging.
+ company_id: The unique identifier of a company. Mutually exclusive with `adCampaignIds`,
+ `adGroupIds`, and `adIds`. Use with `breakdown` to fan out across every
+ campaign, ad group, or ad in the company without paging.
currency: ISO 4217 currency code to report `spend` in. Defaults to the company's ads
reporting currency.
@@ -123,9 +123,9 @@ def retrieve(
{
"from_": from_,
"to": to,
- "ad_campaign_id": ad_campaign_id,
- "ad_group_id": ad_group_id,
- "ad_id": ad_id,
+ "ad_campaign_ids": ad_campaign_ids,
+ "ad_group_ids": ad_group_ids,
+ "ad_ids": ad_ids,
"breakdown": breakdown,
"company_id": company_id,
"currency": currency,
@@ -165,9 +165,9 @@ async def retrieve(
*,
from_: Union[str, datetime],
to: Union[str, datetime],
- ad_campaign_id: Optional[str] | Omit = omit,
- ad_group_id: Optional[str] | Omit = omit,
- ad_id: Optional[str] | Omit = omit,
+ ad_campaign_ids: Optional[SequenceNotStr[str]] | Omit = omit,
+ ad_group_ids: Optional[SequenceNotStr[str]] | Omit = omit,
+ ad_ids: Optional[SequenceNotStr[str]] | Omit = omit,
breakdown: Optional[Literal["campaign", "ad_group", "ad"]] | Omit = omit,
company_id: Optional[str] | Omit = omit,
currency: Optional[str] | Omit = omit,
@@ -179,13 +179,13 @@ async def retrieve(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdReportRetrieveResponse:
- """Performance report for a company, ad campaign, ad group, or ad.
+ """Performance report for a company, ad campaigns, ad groups, or ads.
- Always returns
- aggregate `summary` totals. Set `granularity` (`daily`/`hourly`) to additionally
- get a time series, or set `breakdown` (`campaign`/`ad_group`/`ad`) to
- additionally get per-entity rows inside the requested scope. Exactly one of
- `companyId`, `adCampaignId`, `adGroupId`, or `adId` must be provided.
+ Always
+ returns aggregate `summary` totals summed across the scope. Set `granularity` to
+ additionally get a time series, or set `breakdown` (`campaign`/`ad_group`/`ad`)
+ to additionally get per-entity rows inside the requested scope. Exactly one of
+ `companyId`, `adCampaignIds`, `adGroupIds`, or `adIds` must be provided.
Required permissions:
@@ -196,20 +196,20 @@ async def retrieve(
to: Inclusive end of the reporting window.
- ad_campaign_id: The unique identifier of an ad campaign. Mutually exclusive with `companyId`,
- `adGroupId`, and `adId`.
+ ad_campaign_ids: Scope the report to these ad campaigns (max 100); stats are summed across them.
+ Mutually exclusive with `companyId`, `adGroupIds`, and `adIds`.
- ad_group_id: The unique identifier of an ad group. Mutually exclusive with `companyId`,
- `adCampaignId`, and `adId`.
+ ad_group_ids: Scope the report to these ad groups (max 100); stats are summed across them.
+ Mutually exclusive with `companyId`, `adCampaignIds`, and `adIds`.
- ad_id: The unique identifier of an ad. Mutually exclusive with `companyId`,
- `adCampaignId`, and `adGroupId`.
+ ad_ids: Scope the report to these ads (max 100); stats are summed across them. Mutually
+ exclusive with `companyId`, `adCampaignIds`, and `adGroupIds`.
breakdown: Entity level to group an ad report by.
- company_id: The unique identifier of a company. Mutually exclusive with `adCampaignId`,
- `adGroupId`, and `adId`. Use with `breakdown` to fan out across every campaign,
- ad group, or ad in the company without paging.
+ company_id: The unique identifier of a company. Mutually exclusive with `adCampaignIds`,
+ `adGroupIds`, and `adIds`. Use with `breakdown` to fan out across every
+ campaign, ad group, or ad in the company without paging.
currency: ISO 4217 currency code to report `spend` in. Defaults to the company's ads
reporting currency.
@@ -235,9 +235,9 @@ async def retrieve(
{
"from_": from_,
"to": to,
- "ad_campaign_id": ad_campaign_id,
- "ad_group_id": ad_group_id,
- "ad_id": ad_id,
+ "ad_campaign_ids": ad_campaign_ids,
+ "ad_group_ids": ad_group_ids,
+ "ad_ids": ad_ids,
"breakdown": breakdown,
"company_id": company_id,
"currency": currency,
diff --git a/src/whop_sdk/resources/ads.py b/src/whop_sdk/resources/ads.py
index fc6351c6..1a938f28 100644
--- a/src/whop_sdk/resources/ads.py
+++ b/src/whop_sdk/resources/ads.py
@@ -2,15 +2,14 @@
from __future__ import annotations
-from typing import Union, Optional
-from datetime import datetime
+from typing import Iterable
from typing_extensions import Literal
import httpx
-from ..types import ExternalAdStatus, ad_list_params
-from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from .._utils import path_template, maybe_transform
+from ..types import ad_list_params, ad_create_params, ad_update_params, ad_retrieve_params
+from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
+from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from ..types.ad import Ad
from .._resource import SyncAPIResource, AsyncAPIResource
@@ -22,16 +21,12 @@
)
from ..pagination import SyncCursorPage, AsyncCursorPage
from .._base_client import AsyncPaginator, make_request_options
-from ..types.ad_list_response import AdListResponse
-from ..types.shared.direction import Direction
-from ..types.external_ad_status import ExternalAdStatus
+from ..types.ad_delete_response import AdDeleteResponse
__all__ = ["AdsResource", "AsyncAdsResource"]
class AdsResource(SyncAPIResource):
- """Ads"""
-
@cached_property
def with_raw_response(self) -> AdsResourceWithRawResponse:
"""
@@ -51,10 +46,139 @@ def with_streaming_response(self) -> AdsResourceWithStreamingResponse:
"""
return AdsResourceWithStreamingResponse(self)
+ def create(
+ self,
+ *,
+ ad_group: object | Omit = omit,
+ ad_group_id: str | Omit = omit,
+ call_to_action: Literal[
+ "apply_now",
+ "book_now",
+ "call_now",
+ "contact_us",
+ "download",
+ "get_directions",
+ "get_offer",
+ "get_quote",
+ "learn_more",
+ "listen_now",
+ "message_page",
+ "no_button",
+ "open_link",
+ "order_now",
+ "request_time",
+ "see_details",
+ "see_menu",
+ "send_updates",
+ "shop_now",
+ "sign_up",
+ "subscribe",
+ "watch_more",
+ ]
+ | Omit = omit,
+ creatives: Iterable[ad_create_params.Creative] | Omit = omit,
+ descriptions: SequenceNotStr[str] | Omit = omit,
+ headlines: SequenceNotStr[str] | Omit = omit,
+ lead_form: ad_create_params.LeadForm | Omit = omit,
+ messaging_config: ad_create_params.MessagingConfig | Omit = omit,
+ multi_advertiser_ads: bool | Omit = omit,
+ post_id: str | Omit = omit,
+ primary_texts: SequenceNotStr[str] | Omit = omit,
+ social_accounts: Iterable[ad_create_params.SocialAccount] | Omit = omit,
+ title: str | Omit = omit,
+ url: str | Omit = omit,
+ url_parameters: object | 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,
+ ) -> Ad:
+ """
+ Creates an ad in an ad group.
+
+ Args:
+ ad_group: An inline ad group to create (same shape as POST /ad_groups, including
+ ad_campaign_id). Creates the ad group and the ad together. Provide this OR
+ ad_group_id.
+
+ ad_group_id: The existing ad group to create the ad in. Provide this OR ad_group, not both.
+
+ call_to_action: The call-to-action button shown on the ad.
+
+ creatives: The ad's creatives. Each entry is an uploaded file id with an optional format;
+ omit format for the original/uncropped asset.
+
+ descriptions: The description variants shown on the ad.
+
+ headlines: The headline variants shown on the ad.
+
+ lead_form: Instant lead form for the ad. Only allowed when the ad group's
+ conversion_location is an instant-form destination (instant_forms,
+ instant_forms_and_messenger, website_and_instant_forms).
+
+ messaging_config: Click-to-message welcome copy: the greeting (message) and the ice-breaker prompt
+ (keyword).
+
+ multi_advertiser_ads: Whether the ad can appear alongside other advertisers' ads in the same unit.
+ Defaults to true.
+
+ post_id: Promote an existing post instead of uploading creatives — a Facebook post or
+ Instagram media id. Mutually exclusive with creatives.
+
+ primary_texts: The primary text variants shown in the ad body.
+
+ social_accounts: The social accounts (Facebook page, Instagram profile) the ad runs under.
+
+ title: The display name of the ad.
+
+ url: The URL the ad links to.
+
+ url_parameters: Query parameters appended to the destination URL, as a string-to-string map.
+
+ 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(
+ "/ads",
+ body=maybe_transform(
+ {
+ "ad_group": ad_group,
+ "ad_group_id": ad_group_id,
+ "call_to_action": call_to_action,
+ "creatives": creatives,
+ "descriptions": descriptions,
+ "headlines": headlines,
+ "lead_form": lead_form,
+ "messaging_config": messaging_config,
+ "multi_advertiser_ads": multi_advertiser_ads,
+ "post_id": post_id,
+ "primary_texts": primary_texts,
+ "social_accounts": social_accounts,
+ "title": title,
+ "url": url,
+ "url_parameters": url_parameters,
+ },
+ ad_create_params.AdCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Ad,
+ )
+
def retrieve(
self,
id: str,
*,
+ stats_from: str | Omit = omit,
+ stats_to: 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.
extra_headers: Headers | None = None,
@@ -63,13 +187,13 @@ def retrieve(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Ad:
"""
- Retrieve an ad by its unique identifier.
+ Retrieves a single ad with stats over the requested window.
- Required permissions:
+ Args:
+ stats_from: Start of the stats window.
- - `ad_campaign:basic:read`
+ stats_to: End of the stats window.
- Args:
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -83,80 +207,218 @@ def retrieve(
return self._get(
path_template("/ads/{id}", id=id),
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "stats_from": stats_from,
+ "stats_to": stats_to,
+ },
+ ad_retrieve_params.AdRetrieveParams,
+ ),
),
cast_to=Ad,
)
- def list(
+ def update(
self,
+ id: str,
*,
- ad_group_id: Optional[str] | Omit = omit,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- campaign_id: Optional[str] | Omit = omit,
- company_id: Optional[str] | Omit = omit,
- created_after: Union[str, datetime, None] | Omit = omit,
- created_before: Union[str, datetime, None] | Omit = omit,
- first: Optional[int] | Omit = omit,
- include_paused: Optional[bool] | Omit = omit,
- last: Optional[int] | Omit = omit,
- order_by: Optional[Literal["spend", "roas"]] | Omit = omit,
- order_direction: Optional[Direction] | Omit = omit,
- query: Optional[str] | Omit = omit,
- stats_from: Union[str, datetime, None] | Omit = omit,
- stats_to: Union[str, datetime, None] | Omit = omit,
- status: Optional[ExternalAdStatus] | Omit = omit,
+ call_to_action: Literal[
+ "apply_now",
+ "book_now",
+ "call_now",
+ "contact_us",
+ "download",
+ "get_directions",
+ "get_offer",
+ "get_quote",
+ "learn_more",
+ "listen_now",
+ "message_page",
+ "no_button",
+ "open_link",
+ "order_now",
+ "request_time",
+ "see_details",
+ "see_menu",
+ "send_updates",
+ "shop_now",
+ "sign_up",
+ "subscribe",
+ "watch_more",
+ ]
+ | Omit = omit,
+ creatives: Iterable[ad_update_params.Creative] | Omit = omit,
+ descriptions: SequenceNotStr[str] | Omit = omit,
+ headlines: SequenceNotStr[str] | Omit = omit,
+ lead_form: ad_update_params.LeadForm | Omit = omit,
+ messaging_config: ad_update_params.MessagingConfig | Omit = omit,
+ multi_advertiser_ads: bool | Omit = omit,
+ post_id: str | Omit = omit,
+ primary_texts: SequenceNotStr[str] | Omit = omit,
+ social_accounts: Iterable[ad_update_params.SocialAccount] | Omit = omit,
+ title: str | Omit = omit,
+ url: str | Omit = omit,
+ url_parameters: object | 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[AdListResponse]:
+ ) -> Ad:
"""
- List ads scoped by ad group, campaign, or company.
+ Updates an ad's editable fields.
+
+ Args:
+ call_to_action: The call-to-action button shown on the ad.
+
+ creatives: The ad's creatives. Each entry is an uploaded file id with an optional format;
+ omit format for the original/uncropped asset. Replaces a live ad's creative on
+ the platform.
+
+ descriptions: The description variants shown on the ad.
+
+ headlines: The headline variants shown on the ad.
+
+ lead_form: Instant lead form for the ad. Only allowed when the ad group's
+ conversion_location is an instant-form destination (instant_forms,
+ instant_forms_and_messenger, website_and_instant_forms).
+
+ messaging_config: Click-to-message welcome copy: the greeting (message) and the ice-breaker prompt
+ (keyword).
+
+ multi_advertiser_ads: Whether the ad can appear alongside other advertisers' ads in the same unit.
+ Defaults to true.
+
+ post_id: Promote an existing post instead of uploading creatives — a Facebook post or
+ Instagram media id. Mutually exclusive with creatives.
+
+ primary_texts: The primary text variants shown in the ad body.
- Required permissions:
+ social_accounts: The social accounts the ad runs under.
- - `ad_campaign:basic:read`
+ title: The display name of the ad.
+
+ url: The URL the ad links to.
+
+ url_parameters: Query parameters appended to the destination URL, as a string-to-string map.
+
+ 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._patch(
+ path_template("/ads/{id}", id=id),
+ body=maybe_transform(
+ {
+ "call_to_action": call_to_action,
+ "creatives": creatives,
+ "descriptions": descriptions,
+ "headlines": headlines,
+ "lead_form": lead_form,
+ "messaging_config": messaging_config,
+ "multi_advertiser_ads": multi_advertiser_ads,
+ "post_id": post_id,
+ "primary_texts": primary_texts,
+ "social_accounts": social_accounts,
+ "title": title,
+ "url": url,
+ "url_parameters": url_parameters,
+ },
+ ad_update_params.AdUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Ad,
+ )
+
+ def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ ad_campaign_id: str | Omit = omit,
+ ad_group_id: str | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ created_after: str | Omit = omit,
+ created_before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal[
+ "created_at",
+ "updated_at",
+ "spend",
+ "impressions",
+ "clicks",
+ "reach",
+ "unique_clicks",
+ "results",
+ "click_through_rate",
+ "cost_per_click",
+ "cost_per_mille",
+ "cost_per_result",
+ "frequency",
+ "return_on_ad_spend",
+ ]
+ | Omit = omit,
+ query: str | Omit = omit,
+ stats_from: str | Omit = omit,
+ stats_to: str | Omit = omit,
+ status: Literal["active", "paused", "in_review", "rejected"] | 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[Ad]:
+ """
+ Lists the ads for an account, with stats over the requested window.
Args:
- ad_group_id: Filter by ad group. Provide exactly one of ad_group_id, campaign_id, or
- company_id.
+ account_id: The account the ads belong to. Defaults to the account-scoped key's own account.
- after: Returns the elements in the list that come after the specified cursor.
+ ad_campaign_id: Only return ads in this ad campaign.
- before: Returns the elements in the list that come before the specified cursor.
+ ad_group_id: Only return ads in this ad group.
- campaign_id: Filter by campaign. Provide exactly one of ad_group_id, campaign_id, or
- company_id.
+ after: Cursor to fetch the page after (from page_info.end_cursor).
- company_id: Filter by company. Provide exactly one of ad_group_id, campaign_id, or
- company_id.
+ before: Cursor to fetch the page before (from page_info.start_cursor).
created_after: Only return ads created after this timestamp.
created_before: Only return ads created before this timestamp.
- first: Returns the first _n_ elements from the list.
+ direction: The sort direction. Defaults to desc.
- include_paused: When false, excludes paused ads so pagination matches the dashboard's
- hide-paused toggle.
+ first: The number of ads to return.
- last: Returns the last _n_ elements from the list.
+ last: The number of ads to return from the end of the range.
- order_by: Columns that the listAds query can sort by.
+ order: The field to sort by. Defaults to created_at. Stat columns (spend, impressions,
+ …) rank over the stats_from/stats_to window across the whole list, not just the
+ current page.
- order_direction: The direction of the sort.
+ query: Filter ads by a title or ID substring.
- query: Case-insensitive substring match against the ad title or tag.
+ stats_from: Start of the stats window. Defaults to all-time.
- stats_from: Start of the stats date range used when order_by is a stats column.
+ stats_to: End of the stats window. Defaults to now.
- stats_to: End of the stats date range used when order_by is a stats column.
-
- status: The status of an external ad.
+ status: Only return ads with this status.
extra_headers: Send extra headers
@@ -168,7 +430,7 @@ def list(
"""
return self._get_api_list(
"/ads",
- page=SyncCursorPage[AdListResponse],
+ page=SyncCursorPage[Ad],
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -176,18 +438,17 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "account_id": account_id,
+ "ad_campaign_id": ad_campaign_id,
"ad_group_id": ad_group_id,
"after": after,
"before": before,
- "campaign_id": campaign_id,
- "company_id": company_id,
"created_after": created_after,
"created_before": created_before,
+ "direction": direction,
"first": first,
- "include_paused": include_paused,
"last": last,
- "order_by": order_by,
- "order_direction": order_direction,
+ "order": order,
"query": query,
"stats_from": stats_from,
"stats_to": stats_to,
@@ -196,7 +457,41 @@ def list(
ad_list_params.AdListParams,
),
),
- model=AdListResponse,
+ model=Ad,
+ )
+
+ def delete(
+ 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,
+ ) -> AdDeleteResponse:
+ """Deletes an ad.
+
+ Returns true on success.
+
+ 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._delete(
+ path_template("/ads/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AdDeleteResponse,
)
def pause(
@@ -211,12 +506,7 @@ def pause(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Ad:
"""
- Pauses an ad.
-
- Required permissions:
-
- - `ad_campaign:update`
- - `ad_campaign:basic:read`
+ Pauses an active ad.
Args:
extra_headers: Send extra headers
@@ -251,11 +541,6 @@ def unpause(
"""
Resumes a paused ad.
- Required permissions:
-
- - `ad_campaign:update`
- - `ad_campaign:basic:read`
-
Args:
extra_headers: Send extra headers
@@ -277,8 +562,6 @@ def unpause(
class AsyncAdsResource(AsyncAPIResource):
- """Ads"""
-
@cached_property
def with_raw_response(self) -> AsyncAdsResourceWithRawResponse:
"""
@@ -298,10 +581,139 @@ def with_streaming_response(self) -> AsyncAdsResourceWithStreamingResponse:
"""
return AsyncAdsResourceWithStreamingResponse(self)
+ async def create(
+ self,
+ *,
+ ad_group: object | Omit = omit,
+ ad_group_id: str | Omit = omit,
+ call_to_action: Literal[
+ "apply_now",
+ "book_now",
+ "call_now",
+ "contact_us",
+ "download",
+ "get_directions",
+ "get_offer",
+ "get_quote",
+ "learn_more",
+ "listen_now",
+ "message_page",
+ "no_button",
+ "open_link",
+ "order_now",
+ "request_time",
+ "see_details",
+ "see_menu",
+ "send_updates",
+ "shop_now",
+ "sign_up",
+ "subscribe",
+ "watch_more",
+ ]
+ | Omit = omit,
+ creatives: Iterable[ad_create_params.Creative] | Omit = omit,
+ descriptions: SequenceNotStr[str] | Omit = omit,
+ headlines: SequenceNotStr[str] | Omit = omit,
+ lead_form: ad_create_params.LeadForm | Omit = omit,
+ messaging_config: ad_create_params.MessagingConfig | Omit = omit,
+ multi_advertiser_ads: bool | Omit = omit,
+ post_id: str | Omit = omit,
+ primary_texts: SequenceNotStr[str] | Omit = omit,
+ social_accounts: Iterable[ad_create_params.SocialAccount] | Omit = omit,
+ title: str | Omit = omit,
+ url: str | Omit = omit,
+ url_parameters: object | 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,
+ ) -> Ad:
+ """
+ Creates an ad in an ad group.
+
+ Args:
+ ad_group: An inline ad group to create (same shape as POST /ad_groups, including
+ ad_campaign_id). Creates the ad group and the ad together. Provide this OR
+ ad_group_id.
+
+ ad_group_id: The existing ad group to create the ad in. Provide this OR ad_group, not both.
+
+ call_to_action: The call-to-action button shown on the ad.
+
+ creatives: The ad's creatives. Each entry is an uploaded file id with an optional format;
+ omit format for the original/uncropped asset.
+
+ descriptions: The description variants shown on the ad.
+
+ headlines: The headline variants shown on the ad.
+
+ lead_form: Instant lead form for the ad. Only allowed when the ad group's
+ conversion_location is an instant-form destination (instant_forms,
+ instant_forms_and_messenger, website_and_instant_forms).
+
+ messaging_config: Click-to-message welcome copy: the greeting (message) and the ice-breaker prompt
+ (keyword).
+
+ multi_advertiser_ads: Whether the ad can appear alongside other advertisers' ads in the same unit.
+ Defaults to true.
+
+ post_id: Promote an existing post instead of uploading creatives — a Facebook post or
+ Instagram media id. Mutually exclusive with creatives.
+
+ primary_texts: The primary text variants shown in the ad body.
+
+ social_accounts: The social accounts (Facebook page, Instagram profile) the ad runs under.
+
+ title: The display name of the ad.
+
+ url: The URL the ad links to.
+
+ url_parameters: Query parameters appended to the destination URL, as a string-to-string map.
+
+ 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(
+ "/ads",
+ body=await async_maybe_transform(
+ {
+ "ad_group": ad_group,
+ "ad_group_id": ad_group_id,
+ "call_to_action": call_to_action,
+ "creatives": creatives,
+ "descriptions": descriptions,
+ "headlines": headlines,
+ "lead_form": lead_form,
+ "messaging_config": messaging_config,
+ "multi_advertiser_ads": multi_advertiser_ads,
+ "post_id": post_id,
+ "primary_texts": primary_texts,
+ "social_accounts": social_accounts,
+ "title": title,
+ "url": url,
+ "url_parameters": url_parameters,
+ },
+ ad_create_params.AdCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Ad,
+ )
+
async def retrieve(
self,
id: str,
*,
+ stats_from: str | Omit = omit,
+ stats_to: 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.
extra_headers: Headers | None = None,
@@ -310,13 +722,13 @@ async def retrieve(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Ad:
"""
- Retrieve an ad by its unique identifier.
+ Retrieves a single ad with stats over the requested window.
- Required permissions:
+ Args:
+ stats_from: Start of the stats window.
- - `ad_campaign:basic:read`
+ stats_to: End of the stats window.
- Args:
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -330,80 +742,218 @@ async def retrieve(
return await self._get(
path_template("/ads/{id}", id=id),
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "stats_from": stats_from,
+ "stats_to": stats_to,
+ },
+ ad_retrieve_params.AdRetrieveParams,
+ ),
),
cast_to=Ad,
)
- def list(
+ async def update(
self,
+ id: str,
*,
- ad_group_id: Optional[str] | Omit = omit,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- campaign_id: Optional[str] | Omit = omit,
- company_id: Optional[str] | Omit = omit,
- created_after: Union[str, datetime, None] | Omit = omit,
- created_before: Union[str, datetime, None] | Omit = omit,
- first: Optional[int] | Omit = omit,
- include_paused: Optional[bool] | Omit = omit,
- last: Optional[int] | Omit = omit,
- order_by: Optional[Literal["spend", "roas"]] | Omit = omit,
- order_direction: Optional[Direction] | Omit = omit,
- query: Optional[str] | Omit = omit,
- stats_from: Union[str, datetime, None] | Omit = omit,
- stats_to: Union[str, datetime, None] | Omit = omit,
- status: Optional[ExternalAdStatus] | Omit = omit,
+ call_to_action: Literal[
+ "apply_now",
+ "book_now",
+ "call_now",
+ "contact_us",
+ "download",
+ "get_directions",
+ "get_offer",
+ "get_quote",
+ "learn_more",
+ "listen_now",
+ "message_page",
+ "no_button",
+ "open_link",
+ "order_now",
+ "request_time",
+ "see_details",
+ "see_menu",
+ "send_updates",
+ "shop_now",
+ "sign_up",
+ "subscribe",
+ "watch_more",
+ ]
+ | Omit = omit,
+ creatives: Iterable[ad_update_params.Creative] | Omit = omit,
+ descriptions: SequenceNotStr[str] | Omit = omit,
+ headlines: SequenceNotStr[str] | Omit = omit,
+ lead_form: ad_update_params.LeadForm | Omit = omit,
+ messaging_config: ad_update_params.MessagingConfig | Omit = omit,
+ multi_advertiser_ads: bool | Omit = omit,
+ post_id: str | Omit = omit,
+ primary_texts: SequenceNotStr[str] | Omit = omit,
+ social_accounts: Iterable[ad_update_params.SocialAccount] | Omit = omit,
+ title: str | Omit = omit,
+ url: str | Omit = omit,
+ url_parameters: object | 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[AdListResponse, AsyncCursorPage[AdListResponse]]:
+ ) -> Ad:
"""
- List ads scoped by ad group, campaign, or company.
+ Updates an ad's editable fields.
+
+ Args:
+ call_to_action: The call-to-action button shown on the ad.
+
+ creatives: The ad's creatives. Each entry is an uploaded file id with an optional format;
+ omit format for the original/uncropped asset. Replaces a live ad's creative on
+ the platform.
+
+ descriptions: The description variants shown on the ad.
+
+ headlines: The headline variants shown on the ad.
+
+ lead_form: Instant lead form for the ad. Only allowed when the ad group's
+ conversion_location is an instant-form destination (instant_forms,
+ instant_forms_and_messenger, website_and_instant_forms).
+
+ messaging_config: Click-to-message welcome copy: the greeting (message) and the ice-breaker prompt
+ (keyword).
+
+ multi_advertiser_ads: Whether the ad can appear alongside other advertisers' ads in the same unit.
+ Defaults to true.
+
+ post_id: Promote an existing post instead of uploading creatives — a Facebook post or
+ Instagram media id. Mutually exclusive with creatives.
+
+ primary_texts: The primary text variants shown in the ad body.
+
+ social_accounts: The social accounts the ad runs under.
+
+ title: The display name of the ad.
+
+ url: The URL the ad links to.
+
+ url_parameters: Query parameters appended to the destination URL, as a string-to-string map.
+
+ extra_headers: Send extra headers
- Required permissions:
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
- - `ad_campaign:basic:read`
+ 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._patch(
+ path_template("/ads/{id}", id=id),
+ body=await async_maybe_transform(
+ {
+ "call_to_action": call_to_action,
+ "creatives": creatives,
+ "descriptions": descriptions,
+ "headlines": headlines,
+ "lead_form": lead_form,
+ "messaging_config": messaging_config,
+ "multi_advertiser_ads": multi_advertiser_ads,
+ "post_id": post_id,
+ "primary_texts": primary_texts,
+ "social_accounts": social_accounts,
+ "title": title,
+ "url": url,
+ "url_parameters": url_parameters,
+ },
+ ad_update_params.AdUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Ad,
+ )
+
+ def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ ad_campaign_id: str | Omit = omit,
+ ad_group_id: str | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ created_after: str | Omit = omit,
+ created_before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal[
+ "created_at",
+ "updated_at",
+ "spend",
+ "impressions",
+ "clicks",
+ "reach",
+ "unique_clicks",
+ "results",
+ "click_through_rate",
+ "cost_per_click",
+ "cost_per_mille",
+ "cost_per_result",
+ "frequency",
+ "return_on_ad_spend",
+ ]
+ | Omit = omit,
+ query: str | Omit = omit,
+ stats_from: str | Omit = omit,
+ stats_to: str | Omit = omit,
+ status: Literal["active", "paused", "in_review", "rejected"] | 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[Ad, AsyncCursorPage[Ad]]:
+ """
+ Lists the ads for an account, with stats over the requested window.
Args:
- ad_group_id: Filter by ad group. Provide exactly one of ad_group_id, campaign_id, or
- company_id.
+ account_id: The account the ads belong to. Defaults to the account-scoped key's own account.
- after: Returns the elements in the list that come after the specified cursor.
+ ad_campaign_id: Only return ads in this ad campaign.
- before: Returns the elements in the list that come before the specified cursor.
+ ad_group_id: Only return ads in this ad group.
- campaign_id: Filter by campaign. Provide exactly one of ad_group_id, campaign_id, or
- company_id.
+ after: Cursor to fetch the page after (from page_info.end_cursor).
- company_id: Filter by company. Provide exactly one of ad_group_id, campaign_id, or
- company_id.
+ before: Cursor to fetch the page before (from page_info.start_cursor).
created_after: Only return ads created after this timestamp.
created_before: Only return ads created before this timestamp.
- first: Returns the first _n_ elements from the list.
+ direction: The sort direction. Defaults to desc.
- include_paused: When false, excludes paused ads so pagination matches the dashboard's
- hide-paused toggle.
+ first: The number of ads to return.
- last: Returns the last _n_ elements from the list.
+ last: The number of ads to return from the end of the range.
- order_by: Columns that the listAds query can sort by.
+ order: The field to sort by. Defaults to created_at. Stat columns (spend, impressions,
+ …) rank over the stats_from/stats_to window across the whole list, not just the
+ current page.
- order_direction: The direction of the sort.
+ query: Filter ads by a title or ID substring.
- query: Case-insensitive substring match against the ad title or tag.
+ stats_from: Start of the stats window. Defaults to all-time.
- stats_from: Start of the stats date range used when order_by is a stats column.
+ stats_to: End of the stats window. Defaults to now.
- stats_to: End of the stats date range used when order_by is a stats column.
-
- status: The status of an external ad.
+ status: Only return ads with this status.
extra_headers: Send extra headers
@@ -415,7 +965,7 @@ def list(
"""
return self._get_api_list(
"/ads",
- page=AsyncCursorPage[AdListResponse],
+ page=AsyncCursorPage[Ad],
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -423,18 +973,17 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "account_id": account_id,
+ "ad_campaign_id": ad_campaign_id,
"ad_group_id": ad_group_id,
"after": after,
"before": before,
- "campaign_id": campaign_id,
- "company_id": company_id,
"created_after": created_after,
"created_before": created_before,
+ "direction": direction,
"first": first,
- "include_paused": include_paused,
"last": last,
- "order_by": order_by,
- "order_direction": order_direction,
+ "order": order,
"query": query,
"stats_from": stats_from,
"stats_to": stats_to,
@@ -443,7 +992,41 @@ def list(
ad_list_params.AdListParams,
),
),
- model=AdListResponse,
+ model=Ad,
+ )
+
+ async def delete(
+ 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,
+ ) -> AdDeleteResponse:
+ """Deletes an ad.
+
+ Returns true on success.
+
+ 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._delete(
+ path_template("/ads/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AdDeleteResponse,
)
async def pause(
@@ -458,12 +1041,7 @@ async def pause(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Ad:
"""
- Pauses an ad.
-
- Required permissions:
-
- - `ad_campaign:update`
- - `ad_campaign:basic:read`
+ Pauses an active ad.
Args:
extra_headers: Send extra headers
@@ -498,11 +1076,6 @@ async def unpause(
"""
Resumes a paused ad.
- Required permissions:
-
- - `ad_campaign:update`
- - `ad_campaign:basic:read`
-
Args:
extra_headers: Send extra headers
@@ -527,12 +1100,21 @@ class AdsResourceWithRawResponse:
def __init__(self, ads: AdsResource) -> None:
self._ads = ads
+ self.create = to_raw_response_wrapper(
+ ads.create,
+ )
self.retrieve = to_raw_response_wrapper(
ads.retrieve,
)
+ self.update = to_raw_response_wrapper(
+ ads.update,
+ )
self.list = to_raw_response_wrapper(
ads.list,
)
+ self.delete = to_raw_response_wrapper(
+ ads.delete,
+ )
self.pause = to_raw_response_wrapper(
ads.pause,
)
@@ -545,12 +1127,21 @@ class AsyncAdsResourceWithRawResponse:
def __init__(self, ads: AsyncAdsResource) -> None:
self._ads = ads
+ self.create = async_to_raw_response_wrapper(
+ ads.create,
+ )
self.retrieve = async_to_raw_response_wrapper(
ads.retrieve,
)
+ self.update = async_to_raw_response_wrapper(
+ ads.update,
+ )
self.list = async_to_raw_response_wrapper(
ads.list,
)
+ self.delete = async_to_raw_response_wrapper(
+ ads.delete,
+ )
self.pause = async_to_raw_response_wrapper(
ads.pause,
)
@@ -563,12 +1154,21 @@ class AdsResourceWithStreamingResponse:
def __init__(self, ads: AdsResource) -> None:
self._ads = ads
+ self.create = to_streamed_response_wrapper(
+ ads.create,
+ )
self.retrieve = to_streamed_response_wrapper(
ads.retrieve,
)
+ self.update = to_streamed_response_wrapper(
+ ads.update,
+ )
self.list = to_streamed_response_wrapper(
ads.list,
)
+ self.delete = to_streamed_response_wrapper(
+ ads.delete,
+ )
self.pause = to_streamed_response_wrapper(
ads.pause,
)
@@ -581,12 +1181,21 @@ class AsyncAdsResourceWithStreamingResponse:
def __init__(self, ads: AsyncAdsResource) -> None:
self._ads = ads
+ self.create = async_to_streamed_response_wrapper(
+ ads.create,
+ )
self.retrieve = async_to_streamed_response_wrapper(
ads.retrieve,
)
+ self.update = async_to_streamed_response_wrapper(
+ ads.update,
+ )
self.list = async_to_streamed_response_wrapper(
ads.list,
)
+ self.delete = async_to_streamed_response_wrapper(
+ ads.delete,
+ )
self.pause = async_to_streamed_response_wrapper(
ads.pause,
)
diff --git a/src/whop_sdk/resources/audiences.py b/src/whop_sdk/resources/audiences.py
new file mode 100644
index 00000000..edb747e6
--- /dev/null
+++ b/src/whop_sdk/resources/audiences.py
@@ -0,0 +1,411 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ..types import audience_list_params, audience_create_params
+from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from .._utils import path_template, 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.audience import Audience
+from ..types.audience_delete_response import AudienceDeleteResponse
+
+__all__ = ["AudiencesResource", "AsyncAudiencesResource"]
+
+
+class AudiencesResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AudiencesResourceWithRawResponse:
+ """
+ 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 AudiencesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AudiencesResourceWithStreamingResponse:
+ """
+ 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 AudiencesResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ account_id: str,
+ column_mapping: audience_create_params.ColumnMapping,
+ file_id: str,
+ name: 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,
+ ) -> Audience:
+ """
+ Creates an audience from an uploaded customer identity CSV file and starts
+ processing it.
+
+ Args:
+ account_id: Account ID, prefixed `biz_`.
+
+ column_mapping: Maps supported identity fields to CSV column headers. Map at least one of
+ `email` or `phone`.
+
+ file_id: Direct upload ID from the standard media upload endpoint.
+
+ name: Audience display name.
+
+ 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(
+ "/audiences",
+ body=maybe_transform(
+ {
+ "account_id": account_id,
+ "column_mapping": column_mapping,
+ "file_id": file_id,
+ "name": name,
+ },
+ audience_create_params.AudienceCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Audience,
+ )
+
+ def list(
+ self,
+ *,
+ account_id: str,
+ after: str | Omit = omit,
+ audience_id: str | Omit = omit,
+ first: int | 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[Audience]:
+ """Lists uploaded customer-list audiences for an account.
+
+ Pass `audience_id` to
+ return a specific audience.
+
+ Args:
+ account_id: Account ID, prefixed `biz_`.
+
+ after: Cursor for the next page of audiences.
+
+ audience_id: Audience ID, prefixed `adaud_`, used to filter the response to one audience.
+
+ first: Number of audiences to return. Defaults to 20; maximum 100.
+
+ 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(
+ "/audiences",
+ page=SyncCursorPage[Audience],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "account_id": account_id,
+ "after": after,
+ "audience_id": audience_id,
+ "first": first,
+ },
+ audience_list_params.AudienceListParams,
+ ),
+ ),
+ model=Audience,
+ )
+
+ def delete(
+ self,
+ audience_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,
+ ) -> AudienceDeleteResponse:
+ """
+ Deletes an audience so it is no longer available for targeting.
+
+ 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 audience_id:
+ raise ValueError(f"Expected a non-empty value for `audience_id` but received {audience_id!r}")
+ return self._delete(
+ path_template("/audiences/{audience_id}", audience_id=audience_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AudienceDeleteResponse,
+ )
+
+
+class AsyncAudiencesResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncAudiencesResourceWithRawResponse:
+ """
+ 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 AsyncAudiencesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncAudiencesResourceWithStreamingResponse:
+ """
+ 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 AsyncAudiencesResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ account_id: str,
+ column_mapping: audience_create_params.ColumnMapping,
+ file_id: str,
+ name: 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,
+ ) -> Audience:
+ """
+ Creates an audience from an uploaded customer identity CSV file and starts
+ processing it.
+
+ Args:
+ account_id: Account ID, prefixed `biz_`.
+
+ column_mapping: Maps supported identity fields to CSV column headers. Map at least one of
+ `email` or `phone`.
+
+ file_id: Direct upload ID from the standard media upload endpoint.
+
+ name: Audience display name.
+
+ 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(
+ "/audiences",
+ body=await async_maybe_transform(
+ {
+ "account_id": account_id,
+ "column_mapping": column_mapping,
+ "file_id": file_id,
+ "name": name,
+ },
+ audience_create_params.AudienceCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Audience,
+ )
+
+ def list(
+ self,
+ *,
+ account_id: str,
+ after: str | Omit = omit,
+ audience_id: str | Omit = omit,
+ first: int | 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[Audience, AsyncCursorPage[Audience]]:
+ """Lists uploaded customer-list audiences for an account.
+
+ Pass `audience_id` to
+ return a specific audience.
+
+ Args:
+ account_id: Account ID, prefixed `biz_`.
+
+ after: Cursor for the next page of audiences.
+
+ audience_id: Audience ID, prefixed `adaud_`, used to filter the response to one audience.
+
+ first: Number of audiences to return. Defaults to 20; maximum 100.
+
+ 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(
+ "/audiences",
+ page=AsyncCursorPage[Audience],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "account_id": account_id,
+ "after": after,
+ "audience_id": audience_id,
+ "first": first,
+ },
+ audience_list_params.AudienceListParams,
+ ),
+ ),
+ model=Audience,
+ )
+
+ async def delete(
+ self,
+ audience_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,
+ ) -> AudienceDeleteResponse:
+ """
+ Deletes an audience so it is no longer available for targeting.
+
+ 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 audience_id:
+ raise ValueError(f"Expected a non-empty value for `audience_id` but received {audience_id!r}")
+ return await self._delete(
+ path_template("/audiences/{audience_id}", audience_id=audience_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AudienceDeleteResponse,
+ )
+
+
+class AudiencesResourceWithRawResponse:
+ def __init__(self, audiences: AudiencesResource) -> None:
+ self._audiences = audiences
+
+ self.create = to_raw_response_wrapper(
+ audiences.create,
+ )
+ self.list = to_raw_response_wrapper(
+ audiences.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ audiences.delete,
+ )
+
+
+class AsyncAudiencesResourceWithRawResponse:
+ def __init__(self, audiences: AsyncAudiencesResource) -> None:
+ self._audiences = audiences
+
+ self.create = async_to_raw_response_wrapper(
+ audiences.create,
+ )
+ self.list = async_to_raw_response_wrapper(
+ audiences.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ audiences.delete,
+ )
+
+
+class AudiencesResourceWithStreamingResponse:
+ def __init__(self, audiences: AudiencesResource) -> None:
+ self._audiences = audiences
+
+ self.create = to_streamed_response_wrapper(
+ audiences.create,
+ )
+ self.list = to_streamed_response_wrapper(
+ audiences.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ audiences.delete,
+ )
+
+
+class AsyncAudiencesResourceWithStreamingResponse:
+ def __init__(self, audiences: AsyncAudiencesResource) -> None:
+ self._audiences = audiences
+
+ self.create = async_to_streamed_response_wrapper(
+ audiences.create,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ audiences.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ audiences.delete,
+ )
diff --git a/src/whop_sdk/resources/authorized_users.py b/src/whop_sdk/resources/authorized_users.py
index 0519e3e2..90c75893 100644
--- a/src/whop_sdk/resources/authorized_users.py
+++ b/src/whop_sdk/resources/authorized_users.py
@@ -56,6 +56,7 @@ def create(
company_id: str,
role: AuthorizedUserRoles,
user_id: str,
+ elevation: Optional[authorized_user_create_params.Elevation] | Omit = omit,
send_emails: Optional[bool] | 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.
@@ -81,6 +82,8 @@ def create(
user_id: The ID of the user to add as an authorized user.
+ elevation: Re-authentication proof required to perform this sensitive action.
+
send_emails: Whether to send notification emails to the user on creation.
extra_headers: Send extra headers
@@ -98,6 +101,7 @@ def create(
"company_id": company_id,
"role": role,
"user_id": user_id,
+ "elevation": elevation,
"send_emails": send_emails,
},
authorized_user_create_params.AuthorizedUserCreateParams,
@@ -304,6 +308,7 @@ async def create(
company_id: str,
role: AuthorizedUserRoles,
user_id: str,
+ elevation: Optional[authorized_user_create_params.Elevation] | Omit = omit,
send_emails: Optional[bool] | 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.
@@ -329,6 +334,8 @@ async def create(
user_id: The ID of the user to add as an authorized user.
+ elevation: Re-authentication proof required to perform this sensitive action.
+
send_emails: Whether to send notification emails to the user on creation.
extra_headers: Send extra headers
@@ -346,6 +353,7 @@ async def create(
"company_id": company_id,
"role": role,
"user_id": user_id,
+ "elevation": elevation,
"send_emails": send_emails,
},
authorized_user_create_params.AuthorizedUserCreateParams,
diff --git a/src/whop_sdk/resources/bounties.py b/src/whop_sdk/resources/bounties.py
index ea396695..033c9929 100644
--- a/src/whop_sdk/resources/bounties.py
+++ b/src/whop_sdk/resources/bounties.py
@@ -2,7 +2,8 @@
from __future__ import annotations
-from typing import Optional
+from typing import Union, Optional
+from datetime import datetime
from typing_extensions import Literal
import httpx
@@ -60,10 +61,17 @@ def create(
title: str,
accepted_submissions_limit: Optional[int] | Omit = omit,
allowed_country_codes: Optional[SequenceNotStr[str]] | Omit = omit,
+ business_goal_type: Optional[
+ Literal["clipping", "post_engagement", "owned_account_growth", "ugc_content", "local_activation", "other"]
+ ]
+ | Omit = omit,
experience_id: Optional[str] | Omit = omit,
origin_account_id: Optional[str] | Omit = omit,
post_markdown_content: Optional[str] | Omit = omit,
post_title: Optional[str] | Omit = omit,
+ scheduled_frequency: Optional[Literal["once", "hourly", "daily", "weekly", "monthly"]] | Omit = omit,
+ scheduled_publish_at: Union[str, datetime, None] | Omit = omit,
+ scheduled_timezone: 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.
extra_headers: Headers | None = None,
@@ -80,7 +88,8 @@ def create(
Args:
base_unit_amount: The amount paid to each approved submission. The total bounty pool funded is
- this amount times accepted_submissions_limit.
+ this amount times accepted_submissions_limit, and must be at least 5 in the
+ bounty's currency.
currency: The currency for the bounty pool funding amount.
@@ -89,11 +98,15 @@ def create(
title: The title of the bounty.
accepted_submissions_limit: The number of submissions that can be approved before the bounty closes.
- Defaults to 1.
+ Defaults to 1. The total pool (base_unit_amount times this limit) must be at
+ least 5 in the bounty's currency.
allowed_country_codes: The ISO3166 country codes where this bounty should be visible. Empty means
globally visible.
+ business_goal_type: What the poster is trying to accomplish with a workforce bounty. Used for
+ product taxonomy and analytics, separate from the bounty's implementation type.
+
experience_id: An optional experience to scope the bounty to.
origin_account_id: The user (user*\\**) or company (biz*\\**) tag whose balance funds this bounty pool.
@@ -106,6 +119,14 @@ def create(
post_title: Optional title for the anchor forum post. Falls back to the bounty title when
omitted.
+ scheduled_frequency: How often a scheduled bounty republishes a new bounty.
+
+ scheduled_publish_at: When to publish the bounty. When provided, the bounty is created as a hidden
+ draft and published at this time instead of immediately. Must be in the future.
+
+ scheduled_timezone: The IANA timezone used for recurring occurrences. Required when
+ scheduled_publish_at is provided.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -124,10 +145,14 @@ def create(
"title": title,
"accepted_submissions_limit": accepted_submissions_limit,
"allowed_country_codes": allowed_country_codes,
+ "business_goal_type": business_goal_type,
"experience_id": experience_id,
"origin_account_id": origin_account_id,
"post_markdown_content": post_markdown_content,
"post_title": post_title,
+ "scheduled_frequency": scheduled_frequency,
+ "scheduled_publish_at": scheduled_publish_at,
+ "scheduled_timezone": scheduled_timezone,
},
bounty_create_params.BountyCreateParams,
),
@@ -179,7 +204,7 @@ def list(
experience_id: Optional[str] | Omit = omit,
first: Optional[int] | Omit = omit,
last: Optional[int] | Omit = omit,
- status: Optional[Literal["published", "archived"]] | Omit = omit,
+ status: Optional[Literal["published", "archived", "scheduled"]] | 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,
@@ -273,10 +298,17 @@ async def create(
title: str,
accepted_submissions_limit: Optional[int] | Omit = omit,
allowed_country_codes: Optional[SequenceNotStr[str]] | Omit = omit,
+ business_goal_type: Optional[
+ Literal["clipping", "post_engagement", "owned_account_growth", "ugc_content", "local_activation", "other"]
+ ]
+ | Omit = omit,
experience_id: Optional[str] | Omit = omit,
origin_account_id: Optional[str] | Omit = omit,
post_markdown_content: Optional[str] | Omit = omit,
post_title: Optional[str] | Omit = omit,
+ scheduled_frequency: Optional[Literal["once", "hourly", "daily", "weekly", "monthly"]] | Omit = omit,
+ scheduled_publish_at: Union[str, datetime, None] | Omit = omit,
+ scheduled_timezone: 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.
extra_headers: Headers | None = None,
@@ -293,7 +325,8 @@ async def create(
Args:
base_unit_amount: The amount paid to each approved submission. The total bounty pool funded is
- this amount times accepted_submissions_limit.
+ this amount times accepted_submissions_limit, and must be at least 5 in the
+ bounty's currency.
currency: The currency for the bounty pool funding amount.
@@ -302,11 +335,15 @@ async def create(
title: The title of the bounty.
accepted_submissions_limit: The number of submissions that can be approved before the bounty closes.
- Defaults to 1.
+ Defaults to 1. The total pool (base_unit_amount times this limit) must be at
+ least 5 in the bounty's currency.
allowed_country_codes: The ISO3166 country codes where this bounty should be visible. Empty means
globally visible.
+ business_goal_type: What the poster is trying to accomplish with a workforce bounty. Used for
+ product taxonomy and analytics, separate from the bounty's implementation type.
+
experience_id: An optional experience to scope the bounty to.
origin_account_id: The user (user*\\**) or company (biz*\\**) tag whose balance funds this bounty pool.
@@ -319,6 +356,14 @@ async def create(
post_title: Optional title for the anchor forum post. Falls back to the bounty title when
omitted.
+ scheduled_frequency: How often a scheduled bounty republishes a new bounty.
+
+ scheduled_publish_at: When to publish the bounty. When provided, the bounty is created as a hidden
+ draft and published at this time instead of immediately. Must be in the future.
+
+ scheduled_timezone: The IANA timezone used for recurring occurrences. Required when
+ scheduled_publish_at is provided.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -337,10 +382,14 @@ async def create(
"title": title,
"accepted_submissions_limit": accepted_submissions_limit,
"allowed_country_codes": allowed_country_codes,
+ "business_goal_type": business_goal_type,
"experience_id": experience_id,
"origin_account_id": origin_account_id,
"post_markdown_content": post_markdown_content,
"post_title": post_title,
+ "scheduled_frequency": scheduled_frequency,
+ "scheduled_publish_at": scheduled_publish_at,
+ "scheduled_timezone": scheduled_timezone,
},
bounty_create_params.BountyCreateParams,
),
@@ -392,7 +441,7 @@ def list(
experience_id: Optional[str] | Omit = omit,
first: Optional[int] | Omit = omit,
last: Optional[int] | Omit = omit,
- status: Optional[Literal["published", "archived"]] | Omit = omit,
+ status: Optional[Literal["published", "archived", "scheduled"]] | 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,
diff --git a/src/whop_sdk/resources/cards.py b/src/whop_sdk/resources/cards.py
new file mode 100644
index 00000000..6cf50577
--- /dev/null
+++ b/src/whop_sdk/resources/cards.py
@@ -0,0 +1,473 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal
+
+import httpx
+
+from ..types import card_list_params, card_create_params, card_retrieve_params
+from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from .._utils import path_template, 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 .._base_client import make_request_options
+from ..types.card_list_response import CardListResponse
+from ..types.card_create_response import CardCreateResponse
+from ..types.card_retrieve_response import CardRetrieveResponse
+
+__all__ = ["CardsResource", "AsyncCardsResource"]
+
+
+class CardsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> CardsResourceWithRawResponse:
+ """
+ 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 CardsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> CardsResourceWithStreamingResponse:
+ """
+ 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 CardsResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ assigned_user_id: str | Omit = omit,
+ name: str | Omit = omit,
+ spend_limit: float | Omit = omit,
+ spend_limit_frequency: Literal["daily", "weekly", "monthly", "one_time"] | Omit = omit,
+ transaction_limit: float | Omit = omit,
+ user_id: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> CardCreateResponse:
+ """Issues a virtual card.
+
+ For an individual (consumer) card issuing account, the
+ card is issued to the account's own cardholder. For a company (business) card
+ issuing account, pass assigned*user_id to issue the card to a company member; if
+ that member is not yet an approved card-issuing user, the card is provisioned
+ asynchronously or an onboarding invitation is sent (HTTP 202). Pass exactly one
+ of account_id (a biz* identifier) or user*id (a user* identifier). Returns the
+ newly created card resource.
+
+ Args:
+ account_id: The owning account ID (a biz\\__ identifier). Provide this or user_id.
+
+ assigned_user_id: The company member (a user\\__ identifier) to assign the card to. Required for
+ company (business) card issuing accounts.
+
+ name: A display name for the card.
+
+ spend_limit: Spending limit amount, in dollars.
+
+ spend_limit_frequency: The spending limit window.
+
+ transaction_limit: Per-transaction limit amount, in dollars.
+
+ user_id: The owning user ID (a user\\__ identifier). Provide this or account_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(
+ "/cards",
+ body=maybe_transform(
+ {
+ "account_id": account_id,
+ "assigned_user_id": assigned_user_id,
+ "name": name,
+ "spend_limit": spend_limit,
+ "spend_limit_frequency": spend_limit_frequency,
+ "transaction_limit": transaction_limit,
+ "user_id": user_id,
+ },
+ card_create_params.CardCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=CardCreateResponse,
+ )
+
+ def retrieve(
+ self,
+ card_id: str,
+ *,
+ account_id: str | Omit = omit,
+ user_id: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> CardRetrieveResponse:
+ """
+ Retrieves a single card by its icrd\\__ identifier, including its secrets (full
+ card number, CVC, and cardholder name) for active cards.
+
+ Args:
+ account_id: The owning account ID (a biz\\__ identifier). Provide this or user_id.
+
+ user_id: The owning user ID (a user\\__ identifier). Provide this or account_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
+ """
+ if not card_id:
+ raise ValueError(f"Expected a non-empty value for `card_id` but received {card_id!r}")
+ return self._get(
+ path_template("/cards/{card_id}", card_id=card_id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "account_id": account_id,
+ "user_id": user_id,
+ },
+ card_retrieve_params.CardRetrieveParams,
+ ),
+ ),
+ cast_to=CardRetrieveResponse,
+ )
+
+ def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ user_id: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> CardListResponse:
+ """
+ Lists issued Whop virtual cards for an account or user, including pending
+ invitation cards that have not been issued by the card provider yet. Pass
+ exactly one of account*id (a biz* identifier) or user*id (a user* identifier).
+ Non-owner team members only see cards assigned to them. Users without the
+ payout:account:read scope can still list cards assigned to them (for example
+ moderators or external cardholders). Use GET /cards/:card_id to retrieve a
+ single card with its secrets.
+
+ Args:
+ account_id: The owning account ID (a biz\\__ identifier). Provide this or user_id.
+
+ user_id: The owning user ID (a user\\__ identifier). Provide this or account_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._get(
+ "/cards",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "account_id": account_id,
+ "user_id": user_id,
+ },
+ card_list_params.CardListParams,
+ ),
+ ),
+ cast_to=CardListResponse,
+ )
+
+
+class AsyncCardsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncCardsResourceWithRawResponse:
+ """
+ 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 AsyncCardsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncCardsResourceWithStreamingResponse:
+ """
+ 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 AsyncCardsResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ assigned_user_id: str | Omit = omit,
+ name: str | Omit = omit,
+ spend_limit: float | Omit = omit,
+ spend_limit_frequency: Literal["daily", "weekly", "monthly", "one_time"] | Omit = omit,
+ transaction_limit: float | Omit = omit,
+ user_id: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> CardCreateResponse:
+ """Issues a virtual card.
+
+ For an individual (consumer) card issuing account, the
+ card is issued to the account's own cardholder. For a company (business) card
+ issuing account, pass assigned*user_id to issue the card to a company member; if
+ that member is not yet an approved card-issuing user, the card is provisioned
+ asynchronously or an onboarding invitation is sent (HTTP 202). Pass exactly one
+ of account_id (a biz* identifier) or user*id (a user* identifier). Returns the
+ newly created card resource.
+
+ Args:
+ account_id: The owning account ID (a biz\\__ identifier). Provide this or user_id.
+
+ assigned_user_id: The company member (a user\\__ identifier) to assign the card to. Required for
+ company (business) card issuing accounts.
+
+ name: A display name for the card.
+
+ spend_limit: Spending limit amount, in dollars.
+
+ spend_limit_frequency: The spending limit window.
+
+ transaction_limit: Per-transaction limit amount, in dollars.
+
+ user_id: The owning user ID (a user\\__ identifier). Provide this or account_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(
+ "/cards",
+ body=await async_maybe_transform(
+ {
+ "account_id": account_id,
+ "assigned_user_id": assigned_user_id,
+ "name": name,
+ "spend_limit": spend_limit,
+ "spend_limit_frequency": spend_limit_frequency,
+ "transaction_limit": transaction_limit,
+ "user_id": user_id,
+ },
+ card_create_params.CardCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=CardCreateResponse,
+ )
+
+ async def retrieve(
+ self,
+ card_id: str,
+ *,
+ account_id: str | Omit = omit,
+ user_id: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> CardRetrieveResponse:
+ """
+ Retrieves a single card by its icrd\\__ identifier, including its secrets (full
+ card number, CVC, and cardholder name) for active cards.
+
+ Args:
+ account_id: The owning account ID (a biz\\__ identifier). Provide this or user_id.
+
+ user_id: The owning user ID (a user\\__ identifier). Provide this or account_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
+ """
+ if not card_id:
+ raise ValueError(f"Expected a non-empty value for `card_id` but received {card_id!r}")
+ return await self._get(
+ path_template("/cards/{card_id}", card_id=card_id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "account_id": account_id,
+ "user_id": user_id,
+ },
+ card_retrieve_params.CardRetrieveParams,
+ ),
+ ),
+ cast_to=CardRetrieveResponse,
+ )
+
+ async def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ user_id: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> CardListResponse:
+ """
+ Lists issued Whop virtual cards for an account or user, including pending
+ invitation cards that have not been issued by the card provider yet. Pass
+ exactly one of account*id (a biz* identifier) or user*id (a user* identifier).
+ Non-owner team members only see cards assigned to them. Users without the
+ payout:account:read scope can still list cards assigned to them (for example
+ moderators or external cardholders). Use GET /cards/:card_id to retrieve a
+ single card with its secrets.
+
+ Args:
+ account_id: The owning account ID (a biz\\__ identifier). Provide this or user_id.
+
+ user_id: The owning user ID (a user\\__ identifier). Provide this or account_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._get(
+ "/cards",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "account_id": account_id,
+ "user_id": user_id,
+ },
+ card_list_params.CardListParams,
+ ),
+ ),
+ cast_to=CardListResponse,
+ )
+
+
+class CardsResourceWithRawResponse:
+ def __init__(self, cards: CardsResource) -> None:
+ self._cards = cards
+
+ self.create = to_raw_response_wrapper(
+ cards.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ cards.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ cards.list,
+ )
+
+
+class AsyncCardsResourceWithRawResponse:
+ def __init__(self, cards: AsyncCardsResource) -> None:
+ self._cards = cards
+
+ self.create = async_to_raw_response_wrapper(
+ cards.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ cards.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ cards.list,
+ )
+
+
+class CardsResourceWithStreamingResponse:
+ def __init__(self, cards: CardsResource) -> None:
+ self._cards = cards
+
+ self.create = to_streamed_response_wrapper(
+ cards.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ cards.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ cards.list,
+ )
+
+
+class AsyncCardsResourceWithStreamingResponse:
+ def __init__(self, cards: AsyncCardsResource) -> None:
+ self._cards = cards
+
+ self.create = async_to_streamed_response_wrapper(
+ cards.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ cards.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ cards.list,
+ )
diff --git a/src/whop_sdk/resources/checkout_configurations.py b/src/whop_sdk/resources/checkout_configurations.py
index b2e70eeb..a196a4b9 100644
--- a/src/whop_sdk/resources/checkout_configurations.py
+++ b/src/whop_sdk/resources/checkout_configurations.py
@@ -2,15 +2,14 @@
from __future__ import annotations
-from typing import Dict, Union, Optional
-from datetime import datetime
-from typing_extensions import Literal, overload
+from typing import Optional
+from typing_extensions import Literal
import httpx
from ..types import checkout_configuration_list_params, checkout_configuration_create_params
-from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from .._utils import path_template, required_args, maybe_transform, async_maybe_transform
+from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
+from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -21,17 +20,14 @@
)
from ..pagination import SyncCursorPage, AsyncCursorPage
from .._base_client import AsyncPaginator, make_request_options
-from ..types.shared.currency import Currency
-from ..types.shared.direction import Direction
-from ..types.shared.checkout_configuration import CheckoutConfiguration
from ..types.checkout_configuration_list_response import CheckoutConfigurationListResponse
+from ..types.checkout_configuration_create_response import CheckoutConfigurationCreateResponse
+from ..types.checkout_configuration_retrieve_response import CheckoutConfigurationRetrieveResponse
__all__ = ["CheckoutConfigurationsResource", "AsyncCheckoutConfigurationsResource"]
class CheckoutConfigurationsResource(SyncAPIResource):
- """Checkout configurations"""
-
@cached_property
def with_raw_response(self) -> CheckoutConfigurationsResourceWithRawResponse:
"""
@@ -51,207 +47,50 @@ def with_streaming_response(self) -> CheckoutConfigurationsResourceWithStreaming
"""
return CheckoutConfigurationsResourceWithStreamingResponse(self)
- @overload
def create(
self,
*,
- plan: checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanPlan,
affiliate_code: Optional[str] | Omit = omit,
- allow_promo_codes: Optional[bool] | Omit = omit,
- checkout_styling: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanCheckoutStyling
- ]
- | Omit = omit,
- currency: Optional[Currency] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
- mode: Literal["payment"] | Omit = omit,
- payment_method_configuration: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanPaymentMethodConfiguration
- ]
- | Omit = omit,
- redirect_url: Optional[str] | Omit = omit,
- source_url: 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.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> CheckoutConfiguration:
- """
- Creates a new checkout configuration
-
- Required permissions:
-
- - `checkout_configuration:create`
- - `plan:create`
- - `access_pass:create`
- - `access_pass:update`
- - `checkout_configuration:basic:read`
-
- Args:
- plan: The plan attributes to create a new plan inline for this checkout configuration.
-
- affiliate_code: An affiliate tracking code to attribute the checkout to a specific affiliate.
-
- allow_promo_codes: Whether the checkout should show the promo code input field and accept promo
- codes. Defaults to true.
-
- checkout_styling: Checkout styling overrides for this session. Overrides plan and company
- defaults.
-
- currency: The available currencies on the platform
-
- metadata: Custom key-value metadata to attach to the checkout configuration.
-
- payment_method_configuration: The explicit payment method configuration for the checkout session. Only applies
- to setup mode. If not provided, the platform or company defaults will apply.
-
- redirect_url: The URL to redirect the user to after checkout is completed.
-
- source_url: The URL of the page where the checkout is being initiated from.
-
- 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,
- *,
- plan_id: str,
- affiliate_code: Optional[str] | Omit = omit,
- allow_promo_codes: Optional[bool] | Omit = omit,
- checkout_styling: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanIDCheckoutStyling
- ]
- | Omit = omit,
- currency: Optional[Currency] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
- mode: Literal["payment"] | Omit = omit,
- payment_method_configuration: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanIDPaymentMethodConfiguration
- ]
- | Omit = omit,
- redirect_url: Optional[str] | Omit = omit,
- source_url: 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.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> CheckoutConfiguration:
- """
- Creates a new checkout configuration
-
- Required permissions:
-
- - `checkout_configuration:create`
- - `plan:create`
- - `access_pass:create`
- - `access_pass:update`
- - `checkout_configuration:basic:read`
-
- Args:
- plan_id: The unique identifier of an existing plan to use for this checkout
- configuration.
-
- affiliate_code: An affiliate tracking code to attribute the checkout to a specific affiliate.
-
- allow_promo_codes: Whether the checkout should show the promo code input field and accept promo
- codes. Defaults to true.
-
- checkout_styling: Checkout styling overrides for this session. Overrides plan and company
- defaults.
-
- currency: The available currencies on the platform
-
- metadata: Custom key-value metadata to attach to the checkout configuration.
-
- payment_method_configuration: The explicit payment method configuration for the checkout session. Only applies
- to setup mode. If not provided, the platform or company defaults will apply.
-
- redirect_url: The URL to redirect the user to after checkout is completed.
-
- source_url: The URL of the page where the checkout is being initiated from.
-
- 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,
- *,
- company_id: str,
- mode: Literal["setup"],
- allow_promo_codes: Optional[bool] | Omit = omit,
- checkout_styling: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModeSetupCheckoutStyling
- ]
- | Omit = omit,
- currency: Optional[Currency] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
- payment_method_configuration: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModeSetupPaymentMethodConfiguration
- ]
+ company_id: str | Omit = omit,
+ currency: Optional[str] | Omit = omit,
+ metadata: Optional[object] | Omit = omit,
+ mode: Literal["payment", "setup"] | Omit = omit,
+ payment_method_configuration: Optional[checkout_configuration_create_params.PaymentMethodConfiguration]
| Omit = omit,
+ plan: Optional[checkout_configuration_create_params.Plan] | Omit = omit,
+ plan_id: Optional[str] | Omit = omit,
redirect_url: Optional[str] | Omit = omit,
- source_url: Optional[str] | Omit = omit,
- three_ds_level: Optional[Literal["mandate_challenge", "frictionless"]] | Omit = omit,
+ three_ds_level: 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.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> CheckoutConfiguration:
- """
- Creates a new checkout configuration
-
- Required permissions:
+ ) -> CheckoutConfigurationCreateResponse:
+ """Creates a checkout configuration for a plan.
- - `checkout_configuration:create`
- - `plan:create`
- - `access_pass:create`
- - `access_pass:update`
- - `checkout_configuration:basic:read`
+ Mode defaults to 'payment'.
Args:
- company_id: The unique identifier of the company to create the checkout configuration for.
- Only required in setup mode.
+ affiliate_code: An affiliate code to apply.
- allow_promo_codes: Whether the checkout should show the promo code input field and accept promo
- codes. Defaults to true.
+ company_id: The ID of the company.
- checkout_styling: Checkout styling overrides for this session. Overrides plan and company
- defaults.
+ currency: The currency code.
- currency: The available currencies on the platform
+ metadata: Arbitrary key-value metadata.
- metadata: Custom key-value metadata to attach to the checkout configuration.
+ mode: Checkout mode. Defaults to 'payment'.
- payment_method_configuration: The explicit payment method configuration for the checkout session. Only applies
- to setup mode. If not provided, the platform or company defaults will apply.
+ plan: Plan attributes to create a new plan inline for this checkout configuration.
+ Mutually exclusive with plan_id.
- redirect_url: The URL to redirect the user to after checkout is completed.
+ plan_id: The ID of an existing plan to attach.
- source_url: The URL of the page where the checkout is being initiated from.
+ redirect_url: URL to redirect after checkout.
- three_ds_level: The 3D Secure behavior for a plan.
+ three_ds_level: 3D Secure enforcement level.
extra_headers: Send extra headers
@@ -261,60 +100,19 @@ def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- ...
-
- @required_args(["plan"], ["plan_id"], ["company_id", "mode"])
- def create(
- self,
- *,
- plan: checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanPlan | Omit = omit,
- affiliate_code: Optional[str] | Omit = omit,
- allow_promo_codes: Optional[bool] | Omit = omit,
- checkout_styling: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanCheckoutStyling
- ]
- | Optional[checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanIDCheckoutStyling]
- | Optional[checkout_configuration_create_params.CreateCheckoutSessionInputModeSetupCheckoutStyling]
- | Omit = omit,
- currency: Optional[Currency] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
- mode: Literal["payment"] | Literal["setup"] | Omit = omit,
- payment_method_configuration: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanPaymentMethodConfiguration
- ]
- | Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanIDPaymentMethodConfiguration
- ]
- | Optional[checkout_configuration_create_params.CreateCheckoutSessionInputModeSetupPaymentMethodConfiguration]
- | Omit = omit,
- redirect_url: Optional[str] | Omit = omit,
- source_url: Optional[str] | Omit = omit,
- plan_id: str | Omit = omit,
- company_id: str | Omit = omit,
- three_ds_level: Optional[Literal["mandate_challenge", "frictionless"]] | 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,
- ) -> CheckoutConfiguration:
return self._post(
"/checkout_configurations",
body=maybe_transform(
{
- "plan": plan,
"affiliate_code": affiliate_code,
- "allow_promo_codes": allow_promo_codes,
- "checkout_styling": checkout_styling,
+ "company_id": company_id,
"currency": currency,
"metadata": metadata,
"mode": mode,
"payment_method_configuration": payment_method_configuration,
- "redirect_url": redirect_url,
- "source_url": source_url,
+ "plan": plan,
"plan_id": plan_id,
- "company_id": company_id,
+ "redirect_url": redirect_url,
"three_ds_level": three_ds_level,
},
checkout_configuration_create_params.CheckoutConfigurationCreateParams,
@@ -322,7 +120,7 @@ def create(
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=CheckoutConfiguration,
+ cast_to=CheckoutConfigurationCreateResponse,
)
def retrieve(
@@ -335,13 +133,10 @@ def retrieve(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> CheckoutConfiguration:
- """
- Retrieves the details of an existing checkout configuration.
-
- Required permissions:
+ ) -> CheckoutConfigurationRetrieveResponse:
+ """Retrieves a checkout configuration by ID.
- - `checkout_configuration:basic:read`
+ No authentication required.
Args:
extra_headers: Send extra headers
@@ -359,21 +154,20 @@ def retrieve(
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=CheckoutConfiguration,
+ cast_to=CheckoutConfigurationRetrieveResponse,
)
def list(
self,
*,
company_id: str,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- created_after: Union[str, datetime, None] | Omit = omit,
- created_before: Union[str, datetime, None] | Omit = omit,
- direction: Optional[Direction] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[int] | Omit = omit,
- plan_id: Optional[str] | Omit = omit,
+ after: str | Omit = omit,
+ created_after: int | Omit = omit,
+ created_before: int | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ order: Literal["created_at"] | Omit = omit,
+ plan_id: 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.
extra_headers: Headers | None = None,
@@ -382,32 +176,24 @@ def list(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[CheckoutConfigurationListResponse]:
"""
- Returns a paginated list of checkout configurations for a company, with optional
- filtering by plan and creation date.
-
- Required permissions:
-
- - `checkout_configuration:basic:read`
+ Returns a paginated list of checkout configurations for a company.
Args:
- company_id: The unique identifier of the company to list checkout configurations for.
-
- after: Returns the elements in the list that come after the specified cursor.
+ company_id: The ID of the company to list checkout configurations for.
- before: Returns the elements in the list that come before the specified cursor.
+ after: Cursor for forward pagination.
- created_after: Only return checkout configurations created after this timestamp.
+ created_after: Filter to configurations created after this Unix timestamp.
- created_before: Only return checkout configurations created before this timestamp.
+ created_before: Filter to configurations created before this Unix timestamp.
- direction: The direction of the sort.
+ direction: Sort direction.
- first: Returns the first _n_ elements from the list.
+ first: Number of results to return (forward pagination).
- last: Returns the last _n_ elements from the list.
+ order: The field to sort checkout configurations by.
- plan_id: Filter checkout configurations to only those associated with this plan
- identifier.
+ plan_id: Filter by plan ID.
extra_headers: Send extra headers
@@ -429,12 +215,11 @@ def list(
{
"company_id": company_id,
"after": after,
- "before": before,
"created_after": created_after,
"created_before": created_before,
"direction": direction,
"first": first,
- "last": last,
+ "order": order,
"plan_id": plan_id,
},
checkout_configuration_list_params.CheckoutConfigurationListParams,
@@ -443,89 +228,21 @@ def list(
model=CheckoutConfigurationListResponse,
)
-
-class AsyncCheckoutConfigurationsResource(AsyncAPIResource):
- """Checkout configurations"""
-
- @cached_property
- def with_raw_response(self) -> AsyncCheckoutConfigurationsResourceWithRawResponse:
- """
- 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 AsyncCheckoutConfigurationsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncCheckoutConfigurationsResourceWithStreamingResponse:
- """
- 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 AsyncCheckoutConfigurationsResourceWithStreamingResponse(self)
-
- @overload
- async def create(
+ def delete(
self,
+ id: str,
*,
- plan: checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanPlan,
- affiliate_code: Optional[str] | Omit = omit,
- allow_promo_codes: Optional[bool] | Omit = omit,
- checkout_styling: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanCheckoutStyling
- ]
- | Omit = omit,
- currency: Optional[Currency] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
- mode: Literal["payment"] | Omit = omit,
- payment_method_configuration: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanPaymentMethodConfiguration
- ]
- | Omit = omit,
- redirect_url: Optional[str] | Omit = omit,
- source_url: 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.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> CheckoutConfiguration:
+ ) -> None:
"""
- Creates a new checkout configuration
-
- Required permissions:
-
- - `checkout_configuration:create`
- - `plan:create`
- - `access_pass:create`
- - `access_pass:update`
- - `checkout_configuration:basic:read`
+ Deletes a checkout configuration.
Args:
- plan: The plan attributes to create a new plan inline for this checkout configuration.
-
- affiliate_code: An affiliate tracking code to attribute the checkout to a specific affiliate.
-
- allow_promo_codes: Whether the checkout should show the promo code input field and accept promo
- codes. Defaults to true.
-
- checkout_styling: Checkout styling overrides for this session. Overrides plan and company
- defaults.
-
- currency: The available currencies on the platform
-
- metadata: Custom key-value metadata to attach to the checkout configuration.
-
- payment_method_configuration: The explicit payment method configuration for the checkout session. Only applies
- to setup mode. If not provided, the platform or company defaults will apply.
-
- redirect_url: The URL to redirect the user to after checkout is completed.
-
- source_url: The URL of the page where the checkout is being initiated from.
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -534,139 +251,82 @@ async def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- ...
-
- @overload
- async def create(
- self,
- *,
- plan_id: str,
- affiliate_code: Optional[str] | Omit = omit,
- allow_promo_codes: Optional[bool] | Omit = omit,
- checkout_styling: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanIDCheckoutStyling
- ]
- | Omit = omit,
- currency: Optional[Currency] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
- mode: Literal["payment"] | Omit = omit,
- payment_method_configuration: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanIDPaymentMethodConfiguration
- ]
- | Omit = omit,
- redirect_url: Optional[str] | Omit = omit,
- source_url: 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.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> CheckoutConfiguration:
- """
- Creates a new checkout configuration
-
- Required permissions:
-
- - `checkout_configuration:create`
- - `plan:create`
- - `access_pass:create`
- - `access_pass:update`
- - `checkout_configuration:basic:read`
-
- Args:
- plan_id: The unique identifier of an existing plan to use for this checkout
- configuration.
-
- affiliate_code: An affiliate tracking code to attribute the checkout to a specific affiliate.
-
- allow_promo_codes: Whether the checkout should show the promo code input field and accept promo
- codes. Defaults to true.
-
- checkout_styling: Checkout styling overrides for this session. Overrides plan and company
- defaults.
-
- currency: The available currencies on the platform
-
- metadata: Custom key-value metadata to attach to the checkout configuration.
-
- payment_method_configuration: The explicit payment method configuration for the checkout session. Only applies
- to setup mode. If not provided, the platform or company defaults will apply.
-
- redirect_url: The URL to redirect the user to after checkout is completed.
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return self._delete(
+ path_template("/checkout_configurations/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
- source_url: The URL of the page where the checkout is being initiated from.
- extra_headers: Send extra headers
+class AsyncCheckoutConfigurationsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncCheckoutConfigurationsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
- extra_query: Add additional query parameters to the request
+ For more information, see https://www.github.com/whopio/whopsdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncCheckoutConfigurationsResourceWithRawResponse(self)
- extra_body: Add additional JSON properties to the request
+ @cached_property
+ def with_streaming_response(self) -> AsyncCheckoutConfigurationsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
- timeout: Override the client-level default timeout for this request, in seconds
+ For more information, see https://www.github.com/whopio/whopsdk-python#with_streaming_response
"""
- ...
+ return AsyncCheckoutConfigurationsResourceWithStreamingResponse(self)
- @overload
async def create(
self,
*,
- company_id: str,
- mode: Literal["setup"],
- allow_promo_codes: Optional[bool] | Omit = omit,
- checkout_styling: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModeSetupCheckoutStyling
- ]
- | Omit = omit,
- currency: Optional[Currency] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
- payment_method_configuration: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModeSetupPaymentMethodConfiguration
- ]
+ affiliate_code: Optional[str] | Omit = omit,
+ company_id: str | Omit = omit,
+ currency: Optional[str] | Omit = omit,
+ metadata: Optional[object] | Omit = omit,
+ mode: Literal["payment", "setup"] | Omit = omit,
+ payment_method_configuration: Optional[checkout_configuration_create_params.PaymentMethodConfiguration]
| Omit = omit,
+ plan: Optional[checkout_configuration_create_params.Plan] | Omit = omit,
+ plan_id: Optional[str] | Omit = omit,
redirect_url: Optional[str] | Omit = omit,
- source_url: Optional[str] | Omit = omit,
- three_ds_level: Optional[Literal["mandate_challenge", "frictionless"]] | Omit = omit,
+ three_ds_level: 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.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> CheckoutConfiguration:
- """
- Creates a new checkout configuration
-
- Required permissions:
+ ) -> CheckoutConfigurationCreateResponse:
+ """Creates a checkout configuration for a plan.
- - `checkout_configuration:create`
- - `plan:create`
- - `access_pass:create`
- - `access_pass:update`
- - `checkout_configuration:basic:read`
+ Mode defaults to 'payment'.
Args:
- company_id: The unique identifier of the company to create the checkout configuration for.
- Only required in setup mode.
+ affiliate_code: An affiliate code to apply.
- allow_promo_codes: Whether the checkout should show the promo code input field and accept promo
- codes. Defaults to true.
+ company_id: The ID of the company.
- checkout_styling: Checkout styling overrides for this session. Overrides plan and company
- defaults.
+ currency: The currency code.
- currency: The available currencies on the platform
+ metadata: Arbitrary key-value metadata.
- metadata: Custom key-value metadata to attach to the checkout configuration.
+ mode: Checkout mode. Defaults to 'payment'.
- payment_method_configuration: The explicit payment method configuration for the checkout session. Only applies
- to setup mode. If not provided, the platform or company defaults will apply.
+ plan: Plan attributes to create a new plan inline for this checkout configuration.
+ Mutually exclusive with plan_id.
- redirect_url: The URL to redirect the user to after checkout is completed.
+ plan_id: The ID of an existing plan to attach.
- source_url: The URL of the page where the checkout is being initiated from.
+ redirect_url: URL to redirect after checkout.
- three_ds_level: The 3D Secure behavior for a plan.
+ three_ds_level: 3D Secure enforcement level.
extra_headers: Send extra headers
@@ -676,60 +336,19 @@ async def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- ...
-
- @required_args(["plan"], ["plan_id"], ["company_id", "mode"])
- async def create(
- self,
- *,
- plan: checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanPlan | Omit = omit,
- affiliate_code: Optional[str] | Omit = omit,
- allow_promo_codes: Optional[bool] | Omit = omit,
- checkout_styling: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanCheckoutStyling
- ]
- | Optional[checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanIDCheckoutStyling]
- | Optional[checkout_configuration_create_params.CreateCheckoutSessionInputModeSetupCheckoutStyling]
- | Omit = omit,
- currency: Optional[Currency] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
- mode: Literal["payment"] | Literal["setup"] | Omit = omit,
- payment_method_configuration: Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanPaymentMethodConfiguration
- ]
- | Optional[
- checkout_configuration_create_params.CreateCheckoutSessionInputModePaymentWithPlanIDPaymentMethodConfiguration
- ]
- | Optional[checkout_configuration_create_params.CreateCheckoutSessionInputModeSetupPaymentMethodConfiguration]
- | Omit = omit,
- redirect_url: Optional[str] | Omit = omit,
- source_url: Optional[str] | Omit = omit,
- plan_id: str | Omit = omit,
- company_id: str | Omit = omit,
- three_ds_level: Optional[Literal["mandate_challenge", "frictionless"]] | 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,
- ) -> CheckoutConfiguration:
return await self._post(
"/checkout_configurations",
body=await async_maybe_transform(
{
- "plan": plan,
"affiliate_code": affiliate_code,
- "allow_promo_codes": allow_promo_codes,
- "checkout_styling": checkout_styling,
+ "company_id": company_id,
"currency": currency,
"metadata": metadata,
"mode": mode,
"payment_method_configuration": payment_method_configuration,
- "redirect_url": redirect_url,
- "source_url": source_url,
+ "plan": plan,
"plan_id": plan_id,
- "company_id": company_id,
+ "redirect_url": redirect_url,
"three_ds_level": three_ds_level,
},
checkout_configuration_create_params.CheckoutConfigurationCreateParams,
@@ -737,7 +356,7 @@ async def create(
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=CheckoutConfiguration,
+ cast_to=CheckoutConfigurationCreateResponse,
)
async def retrieve(
@@ -750,13 +369,10 @@ async def retrieve(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> CheckoutConfiguration:
- """
- Retrieves the details of an existing checkout configuration.
-
- Required permissions:
+ ) -> CheckoutConfigurationRetrieveResponse:
+ """Retrieves a checkout configuration by ID.
- - `checkout_configuration:basic:read`
+ No authentication required.
Args:
extra_headers: Send extra headers
@@ -774,21 +390,20 @@ async def retrieve(
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=CheckoutConfiguration,
+ cast_to=CheckoutConfigurationRetrieveResponse,
)
def list(
self,
*,
company_id: str,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- created_after: Union[str, datetime, None] | Omit = omit,
- created_before: Union[str, datetime, None] | Omit = omit,
- direction: Optional[Direction] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[int] | Omit = omit,
- plan_id: Optional[str] | Omit = omit,
+ after: str | Omit = omit,
+ created_after: int | Omit = omit,
+ created_before: int | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ order: Literal["created_at"] | Omit = omit,
+ plan_id: 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.
extra_headers: Headers | None = None,
@@ -797,32 +412,24 @@ def list(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[CheckoutConfigurationListResponse, AsyncCursorPage[CheckoutConfigurationListResponse]]:
"""
- Returns a paginated list of checkout configurations for a company, with optional
- filtering by plan and creation date.
-
- Required permissions:
-
- - `checkout_configuration:basic:read`
+ Returns a paginated list of checkout configurations for a company.
Args:
- company_id: The unique identifier of the company to list checkout configurations for.
+ company_id: The ID of the company to list checkout configurations for.
- after: Returns the elements in the list that come after the specified cursor.
+ after: Cursor for forward pagination.
- before: Returns the elements in the list that come before the specified cursor.
+ created_after: Filter to configurations created after this Unix timestamp.
- created_after: Only return checkout configurations created after this timestamp.
+ created_before: Filter to configurations created before this Unix timestamp.
- created_before: Only return checkout configurations created before this timestamp.
+ direction: Sort direction.
- direction: The direction of the sort.
+ first: Number of results to return (forward pagination).
- first: Returns the first _n_ elements from the list.
+ order: The field to sort checkout configurations by.
- last: Returns the last _n_ elements from the list.
-
- plan_id: Filter checkout configurations to only those associated with this plan
- identifier.
+ plan_id: Filter by plan ID.
extra_headers: Send extra headers
@@ -844,12 +451,11 @@ def list(
{
"company_id": company_id,
"after": after,
- "before": before,
"created_after": created_after,
"created_before": created_before,
"direction": direction,
"first": first,
- "last": last,
+ "order": order,
"plan_id": plan_id,
},
checkout_configuration_list_params.CheckoutConfigurationListParams,
@@ -858,6 +464,40 @@ def list(
model=CheckoutConfigurationListResponse,
)
+ async def delete(
+ 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,
+ ) -> None:
+ """
+ Deletes a checkout configuration.
+
+ 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}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return await self._delete(
+ path_template("/checkout_configurations/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
class CheckoutConfigurationsResourceWithRawResponse:
def __init__(self, checkout_configurations: CheckoutConfigurationsResource) -> None:
@@ -872,6 +512,9 @@ def __init__(self, checkout_configurations: CheckoutConfigurationsResource) -> N
self.list = to_raw_response_wrapper(
checkout_configurations.list,
)
+ self.delete = to_raw_response_wrapper(
+ checkout_configurations.delete,
+ )
class AsyncCheckoutConfigurationsResourceWithRawResponse:
@@ -887,6 +530,9 @@ def __init__(self, checkout_configurations: AsyncCheckoutConfigurationsResource)
self.list = async_to_raw_response_wrapper(
checkout_configurations.list,
)
+ self.delete = async_to_raw_response_wrapper(
+ checkout_configurations.delete,
+ )
class CheckoutConfigurationsResourceWithStreamingResponse:
@@ -902,6 +548,9 @@ def __init__(self, checkout_configurations: CheckoutConfigurationsResource) -> N
self.list = to_streamed_response_wrapper(
checkout_configurations.list,
)
+ self.delete = to_streamed_response_wrapper(
+ checkout_configurations.delete,
+ )
class AsyncCheckoutConfigurationsResourceWithStreamingResponse:
@@ -917,3 +566,6 @@ def __init__(self, checkout_configurations: AsyncCheckoutConfigurationsResource)
self.list = async_to_streamed_response_wrapper(
checkout_configurations.list,
)
+ self.delete = async_to_streamed_response_wrapper(
+ checkout_configurations.delete,
+ )
diff --git a/src/whop_sdk/resources/conversions.py b/src/whop_sdk/resources/conversions.py
index a3dd6259..4f70d949 100644
--- a/src/whop_sdk/resources/conversions.py
+++ b/src/whop_sdk/resources/conversions.py
@@ -52,7 +52,17 @@ def create(
self,
*,
company_id: str,
- event_name: Literal["lead", "submit_application", "contact", "complete_registration", "schedule", "custom"],
+ event_name: Literal[
+ "lead",
+ "submit_application",
+ "contact",
+ "complete_registration",
+ "schedule",
+ "view_content",
+ "add_to_cart",
+ "custom",
+ "page",
+ ],
action_source: Optional[
Literal[
"email",
@@ -70,11 +80,15 @@ def create(
context: Optional[conversion_create_params.Context] | Omit = omit,
currency: Optional[Currency] | Omit = omit,
custom_name: Optional[str] | Omit = omit,
+ duration: Optional[int] | Omit = omit,
event_id: Optional[str] | Omit = omit,
event_time: Union[str, datetime, None] | Omit = omit,
plan_id: Optional[str] | Omit = omit,
product_id: Optional[str] | Omit = omit,
referrer_url: Optional[str] | Omit = omit,
+ resumed: Optional[bool] | Omit = omit,
+ source: Optional[str] | Omit = omit,
+ title: Optional[str] | Omit = omit,
url: Optional[str] | Omit = omit,
user: Optional[conversion_create_params.User] | Omit = omit,
value: Optional[float] | Omit = omit,
@@ -103,7 +117,9 @@ def create(
currency: The available currencies on the platform
- custom_name: Custom event name when event_name is 'custom'.
+ custom_name: Custom event name when event_name is 'custom'. Maximum 35 chars for this value.
+
+ duration: For 'leave' events: milliseconds the visitor spent on the page.
event_id: Client-provided identifier for deduplication. Generated if omitted.
@@ -115,6 +131,13 @@ def create(
referrer_url: The referring URL.
+ resumed: For 'page' events: true when the page was restored from the back/forward cache.
+
+ source: For 'identify' events: where the identity was captured (url, form, manual,
+ iframe).
+
+ title: For 'page' events: the document title.
+
url: The URL where the event occurred.
user: User identity and profile data.
@@ -139,11 +162,15 @@ def create(
"context": context,
"currency": currency,
"custom_name": custom_name,
+ "duration": duration,
"event_id": event_id,
"event_time": event_time,
"plan_id": plan_id,
"product_id": product_id,
"referrer_url": referrer_url,
+ "resumed": resumed,
+ "source": source,
+ "title": title,
"url": url,
"user": user,
"value": value,
@@ -183,7 +210,17 @@ async def create(
self,
*,
company_id: str,
- event_name: Literal["lead", "submit_application", "contact", "complete_registration", "schedule", "custom"],
+ event_name: Literal[
+ "lead",
+ "submit_application",
+ "contact",
+ "complete_registration",
+ "schedule",
+ "view_content",
+ "add_to_cart",
+ "custom",
+ "page",
+ ],
action_source: Optional[
Literal[
"email",
@@ -201,11 +238,15 @@ async def create(
context: Optional[conversion_create_params.Context] | Omit = omit,
currency: Optional[Currency] | Omit = omit,
custom_name: Optional[str] | Omit = omit,
+ duration: Optional[int] | Omit = omit,
event_id: Optional[str] | Omit = omit,
event_time: Union[str, datetime, None] | Omit = omit,
plan_id: Optional[str] | Omit = omit,
product_id: Optional[str] | Omit = omit,
referrer_url: Optional[str] | Omit = omit,
+ resumed: Optional[bool] | Omit = omit,
+ source: Optional[str] | Omit = omit,
+ title: Optional[str] | Omit = omit,
url: Optional[str] | Omit = omit,
user: Optional[conversion_create_params.User] | Omit = omit,
value: Optional[float] | Omit = omit,
@@ -234,7 +275,9 @@ async def create(
currency: The available currencies on the platform
- custom_name: Custom event name when event_name is 'custom'.
+ custom_name: Custom event name when event_name is 'custom'. Maximum 35 chars for this value.
+
+ duration: For 'leave' events: milliseconds the visitor spent on the page.
event_id: Client-provided identifier for deduplication. Generated if omitted.
@@ -246,6 +289,13 @@ async def create(
referrer_url: The referring URL.
+ resumed: For 'page' events: true when the page was restored from the back/forward cache.
+
+ source: For 'identify' events: where the identity was captured (url, form, manual,
+ iframe).
+
+ title: For 'page' events: the document title.
+
url: The URL where the event occurred.
user: User identity and profile data.
@@ -270,11 +320,15 @@ async def create(
"context": context,
"currency": currency,
"custom_name": custom_name,
+ "duration": duration,
"event_id": event_id,
"event_time": event_time,
"plan_id": plan_id,
"product_id": product_id,
"referrer_url": referrer_url,
+ "resumed": resumed,
+ "source": source,
+ "title": title,
"url": url,
"user": user,
"value": value,
diff --git a/src/whop_sdk/resources/deposits.py b/src/whop_sdk/resources/deposits.py
index 9d32c93d..760571df 100644
--- a/src/whop_sdk/resources/deposits.py
+++ b/src/whop_sdk/resources/deposits.py
@@ -6,7 +6,7 @@
import httpx
-from ..types import deposit_create_params
+from ..types import deposit_list_params, deposit_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
@@ -18,6 +18,7 @@
async_to_streamed_response_wrapper,
)
from .._base_client import make_request_options
+from ..types.deposit_list_response import DepositListResponse
from ..types.deposit_create_response import DepositCreateResponse
__all__ = ["DepositsResource", "AsyncDepositsResource"]
@@ -46,8 +47,8 @@ def with_streaming_response(self) -> DepositsResourceWithStreamingResponse:
def create(
self,
*,
- amount: float,
destination: deposit_create_params.Destination,
+ amount: float | Omit = omit,
metadata: Dict[str, object] | Omit = omit,
network: Optional[str] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -59,17 +60,18 @@ def create(
) -> DepositCreateResponse:
"""
Resolves a deposit destination and returns the on-chain addresses that can fund
- it.
+ it. No authentication is required; any business can be resolved by its account
+ ID.
Args:
- amount: Amount to deposit.
-
destination: Destination account ID or wallet address. Object form is supported for
compatibility.
- metadata: Arbitrary metadata echoed in the response.
+ amount: Amount to prefill on hosted deposit page.
+
+ metadata: Metadata to include with the deposit response.
- network: Optional destination network override.
+ network: Destination network override.
extra_headers: Send extra headers
@@ -83,8 +85,8 @@ def create(
"/deposits",
body=maybe_transform(
{
- "amount": amount,
"destination": destination,
+ "amount": amount,
"metadata": metadata,
"network": network,
},
@@ -96,6 +98,45 @@ def create(
cast_to=DepositCreateResponse,
)
+ def list(
+ self,
+ *,
+ account_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,
+ ) -> DepositListResponse:
+ """Returns deposit transactions for a business account.
+
+ Bank deposit transactions
+ are nested under the bank field.
+
+ Args:
+ account_id: Business account ID (biz\\__\\**).
+
+ 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(
+ "/deposits",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"account_id": account_id}, deposit_list_params.DepositListParams),
+ ),
+ cast_to=DepositListResponse,
+ )
+
class AsyncDepositsResource(AsyncAPIResource):
@cached_property
@@ -120,8 +161,8 @@ def with_streaming_response(self) -> AsyncDepositsResourceWithStreamingResponse:
async def create(
self,
*,
- amount: float,
destination: deposit_create_params.Destination,
+ amount: float | Omit = omit,
metadata: Dict[str, object] | Omit = omit,
network: Optional[str] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -133,17 +174,18 @@ async def create(
) -> DepositCreateResponse:
"""
Resolves a deposit destination and returns the on-chain addresses that can fund
- it.
+ it. No authentication is required; any business can be resolved by its account
+ ID.
Args:
- amount: Amount to deposit.
-
destination: Destination account ID or wallet address. Object form is supported for
compatibility.
- metadata: Arbitrary metadata echoed in the response.
+ amount: Amount to prefill on hosted deposit page.
+
+ metadata: Metadata to include with the deposit response.
- network: Optional destination network override.
+ network: Destination network override.
extra_headers: Send extra headers
@@ -157,8 +199,8 @@ async def create(
"/deposits",
body=await async_maybe_transform(
{
- "amount": amount,
"destination": destination,
+ "amount": amount,
"metadata": metadata,
"network": network,
},
@@ -170,6 +212,45 @@ async def create(
cast_to=DepositCreateResponse,
)
+ async def list(
+ self,
+ *,
+ account_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,
+ ) -> DepositListResponse:
+ """Returns deposit transactions for a business account.
+
+ Bank deposit transactions
+ are nested under the bank field.
+
+ Args:
+ account_id: Business account ID (biz\\__\\**).
+
+ 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._get(
+ "/deposits",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform({"account_id": account_id}, deposit_list_params.DepositListParams),
+ ),
+ cast_to=DepositListResponse,
+ )
+
class DepositsResourceWithRawResponse:
def __init__(self, deposits: DepositsResource) -> None:
@@ -178,6 +259,9 @@ def __init__(self, deposits: DepositsResource) -> None:
self.create = to_raw_response_wrapper(
deposits.create,
)
+ self.list = to_raw_response_wrapper(
+ deposits.list,
+ )
class AsyncDepositsResourceWithRawResponse:
@@ -187,6 +271,9 @@ def __init__(self, deposits: AsyncDepositsResource) -> None:
self.create = async_to_raw_response_wrapper(
deposits.create,
)
+ self.list = async_to_raw_response_wrapper(
+ deposits.list,
+ )
class DepositsResourceWithStreamingResponse:
@@ -196,6 +283,9 @@ def __init__(self, deposits: DepositsResource) -> None:
self.create = to_streamed_response_wrapper(
deposits.create,
)
+ self.list = to_streamed_response_wrapper(
+ deposits.list,
+ )
class AsyncDepositsResourceWithStreamingResponse:
@@ -205,3 +295,6 @@ def __init__(self, deposits: AsyncDepositsResource) -> None:
self.create = async_to_streamed_response_wrapper(
deposits.create,
)
+ self.list = async_to_streamed_response_wrapper(
+ deposits.list,
+ )
diff --git a/src/whop_sdk/resources/events.py b/src/whop_sdk/resources/events.py
new file mode 100644
index 00000000..c7c061b8
--- /dev/null
+++ b/src/whop_sdk/resources/events.py
@@ -0,0 +1,221 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ..types import event_list_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 .._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 .._base_client import make_request_options
+from ..types.event_list_response import EventListResponse
+
+__all__ = ["EventsResource", "AsyncEventsResource"]
+
+
+class EventsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> EventsResourceWithRawResponse:
+ """
+ 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 EventsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> EventsResourceWithStreamingResponse:
+ """
+ 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 EventsResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ *,
+ person_id: str,
+ account_id: str | Omit = omit,
+ first: int | Omit = omit,
+ from_: int | Omit = omit,
+ to: int | 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,
+ ) -> EventListResponse:
+ """Lists pixel events for a person, most recent first.
+
+ Events are shaped like the
+ POST /conversions intake: attribution in context, identity in user.
+
+ Args:
+ person_id: The ID of the person.
+
+ account_id: The ID of the account, which will look like biz\\__******\\********. Optional for
+ account API keys; required for credentials that can access multiple accounts.
+
+ first: The number of events to return.
+
+ from_: Start of the time range as a Unix timestamp.
+
+ to: End of the time range as a Unix timestamp. Defaults to now.
+
+ 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(
+ "/events",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "person_id": person_id,
+ "account_id": account_id,
+ "first": first,
+ "from_": from_,
+ "to": to,
+ },
+ event_list_params.EventListParams,
+ ),
+ ),
+ cast_to=EventListResponse,
+ )
+
+
+class AsyncEventsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncEventsResourceWithRawResponse:
+ """
+ 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 AsyncEventsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncEventsResourceWithStreamingResponse:
+ """
+ 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 AsyncEventsResourceWithStreamingResponse(self)
+
+ async def list(
+ self,
+ *,
+ person_id: str,
+ account_id: str | Omit = omit,
+ first: int | Omit = omit,
+ from_: int | Omit = omit,
+ to: int | 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,
+ ) -> EventListResponse:
+ """Lists pixel events for a person, most recent first.
+
+ Events are shaped like the
+ POST /conversions intake: attribution in context, identity in user.
+
+ Args:
+ person_id: The ID of the person.
+
+ account_id: The ID of the account, which will look like biz\\__******\\********. Optional for
+ account API keys; required for credentials that can access multiple accounts.
+
+ first: The number of events to return.
+
+ from_: Start of the time range as a Unix timestamp.
+
+ to: End of the time range as a Unix timestamp. Defaults to now.
+
+ 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._get(
+ "/events",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "person_id": person_id,
+ "account_id": account_id,
+ "first": first,
+ "from_": from_,
+ "to": to,
+ },
+ event_list_params.EventListParams,
+ ),
+ ),
+ cast_to=EventListResponse,
+ )
+
+
+class EventsResourceWithRawResponse:
+ def __init__(self, events: EventsResource) -> None:
+ self._events = events
+
+ self.list = to_raw_response_wrapper(
+ events.list,
+ )
+
+
+class AsyncEventsResourceWithRawResponse:
+ def __init__(self, events: AsyncEventsResource) -> None:
+ self._events = events
+
+ self.list = async_to_raw_response_wrapper(
+ events.list,
+ )
+
+
+class EventsResourceWithStreamingResponse:
+ def __init__(self, events: EventsResource) -> None:
+ self._events = events
+
+ self.list = to_streamed_response_wrapper(
+ events.list,
+ )
+
+
+class AsyncEventsResourceWithStreamingResponse:
+ def __init__(self, events: AsyncEventsResource) -> None:
+ self._events = events
+
+ self.list = async_to_streamed_response_wrapper(
+ events.list,
+ )
diff --git a/src/whop_sdk/resources/financial_activity.py b/src/whop_sdk/resources/financial_activity.py
new file mode 100644
index 00000000..1dda7a0b
--- /dev/null
+++ b/src/whop_sdk/resources/financial_activity.py
@@ -0,0 +1,276 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from datetime import date, datetime
+
+import httpx
+
+from ..types import financial_activity_list_params
+from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
+from .._utils import 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 .._base_client import make_request_options
+from ..types.financial_activity_list_response import FinancialActivityListResponse
+
+__all__ = ["FinancialActivityResource", "AsyncFinancialActivityResource"]
+
+
+class FinancialActivityResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> FinancialActivityResourceWithRawResponse:
+ """
+ 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 FinancialActivityResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> FinancialActivityResourceWithStreamingResponse:
+ """
+ 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 FinancialActivityResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ available_after: Union[str, date] | Omit = omit,
+ available_before: Union[str, date] | Omit = omit,
+ currency: str | Omit = omit,
+ cursor: str | Omit = omit,
+ limit: int | Omit = omit,
+ line_types: SequenceNotStr[str] | Omit = omit,
+ posted_after: Union[str, datetime] | Omit = omit,
+ posted_before: Union[str, datetime] | Omit = omit,
+ user_id: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> FinancialActivityListResponse:
+ """
+ Returns a paginated activity feed for one account or user, derived from ledger
+ lines with typed resource and source objects for presentation. Pass exactly one
+ of `account_id` (a `biz_` identifier) or `user_id` (a `user_` identifier).
+ Filter by line type, currency, posted timestamp, or settlement date to reconcile
+ a specific window.
+
+ Args:
+ account_id: The owning account ID (a biz\\__ identifier). Provide this or user_id.
+
+ available_after: Only include rows whose funds became withdrawable on or after this `YYYY-MM-DD`
+ settlement date (UTC), distinct from posted_at. Requires currency.
+
+ available_before: Only include rows whose funds became withdrawable on or before this `YYYY-MM-DD`
+ settlement date (UTC). Set equal to available_after for a single day. Requires
+ currency.
+
+ currency: Optional currency code filter, for example `usd`.
+
+ cursor: Cursor returned by the previous page.
+
+ limit: Maximum number of rows to return.
+
+ line_types: Optional ledger line categories to include. Some categories (for example
+ `onchain_deposit`, which covers inbound crypto deposits such as MoonPay onramps)
+ are only returned when explicitly requested here.
+
+ posted_after: Only include rows posted after this ISO 8601 timestamp.
+
+ posted_before: Only include rows posted before this ISO 8601 timestamp.
+
+ user_id: The owning user ID (a user\\__ identifier). Provide this or account_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._get(
+ "/financial-activity",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "account_id": account_id,
+ "available_after": available_after,
+ "available_before": available_before,
+ "currency": currency,
+ "cursor": cursor,
+ "limit": limit,
+ "line_types": line_types,
+ "posted_after": posted_after,
+ "posted_before": posted_before,
+ "user_id": user_id,
+ },
+ financial_activity_list_params.FinancialActivityListParams,
+ ),
+ ),
+ cast_to=FinancialActivityListResponse,
+ )
+
+
+class AsyncFinancialActivityResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncFinancialActivityResourceWithRawResponse:
+ """
+ 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 AsyncFinancialActivityResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncFinancialActivityResourceWithStreamingResponse:
+ """
+ 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 AsyncFinancialActivityResourceWithStreamingResponse(self)
+
+ async def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ available_after: Union[str, date] | Omit = omit,
+ available_before: Union[str, date] | Omit = omit,
+ currency: str | Omit = omit,
+ cursor: str | Omit = omit,
+ limit: int | Omit = omit,
+ line_types: SequenceNotStr[str] | Omit = omit,
+ posted_after: Union[str, datetime] | Omit = omit,
+ posted_before: Union[str, datetime] | Omit = omit,
+ user_id: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> FinancialActivityListResponse:
+ """
+ Returns a paginated activity feed for one account or user, derived from ledger
+ lines with typed resource and source objects for presentation. Pass exactly one
+ of `account_id` (a `biz_` identifier) or `user_id` (a `user_` identifier).
+ Filter by line type, currency, posted timestamp, or settlement date to reconcile
+ a specific window.
+
+ Args:
+ account_id: The owning account ID (a biz\\__ identifier). Provide this or user_id.
+
+ available_after: Only include rows whose funds became withdrawable on or after this `YYYY-MM-DD`
+ settlement date (UTC), distinct from posted_at. Requires currency.
+
+ available_before: Only include rows whose funds became withdrawable on or before this `YYYY-MM-DD`
+ settlement date (UTC). Set equal to available_after for a single day. Requires
+ currency.
+
+ currency: Optional currency code filter, for example `usd`.
+
+ cursor: Cursor returned by the previous page.
+
+ limit: Maximum number of rows to return.
+
+ line_types: Optional ledger line categories to include. Some categories (for example
+ `onchain_deposit`, which covers inbound crypto deposits such as MoonPay onramps)
+ are only returned when explicitly requested here.
+
+ posted_after: Only include rows posted after this ISO 8601 timestamp.
+
+ posted_before: Only include rows posted before this ISO 8601 timestamp.
+
+ user_id: The owning user ID (a user\\__ identifier). Provide this or account_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._get(
+ "/financial-activity",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "account_id": account_id,
+ "available_after": available_after,
+ "available_before": available_before,
+ "currency": currency,
+ "cursor": cursor,
+ "limit": limit,
+ "line_types": line_types,
+ "posted_after": posted_after,
+ "posted_before": posted_before,
+ "user_id": user_id,
+ },
+ financial_activity_list_params.FinancialActivityListParams,
+ ),
+ ),
+ cast_to=FinancialActivityListResponse,
+ )
+
+
+class FinancialActivityResourceWithRawResponse:
+ def __init__(self, financial_activity: FinancialActivityResource) -> None:
+ self._financial_activity = financial_activity
+
+ self.list = to_raw_response_wrapper(
+ financial_activity.list,
+ )
+
+
+class AsyncFinancialActivityResourceWithRawResponse:
+ def __init__(self, financial_activity: AsyncFinancialActivityResource) -> None:
+ self._financial_activity = financial_activity
+
+ self.list = async_to_raw_response_wrapper(
+ financial_activity.list,
+ )
+
+
+class FinancialActivityResourceWithStreamingResponse:
+ def __init__(self, financial_activity: FinancialActivityResource) -> None:
+ self._financial_activity = financial_activity
+
+ self.list = to_streamed_response_wrapper(
+ financial_activity.list,
+ )
+
+
+class AsyncFinancialActivityResourceWithStreamingResponse:
+ def __init__(self, financial_activity: AsyncFinancialActivityResource) -> None:
+ self._financial_activity = financial_activity
+
+ self.list = async_to_streamed_response_wrapper(
+ financial_activity.list,
+ )
diff --git a/src/whop_sdk/resources/payouts.py b/src/whop_sdk/resources/payouts.py
new file mode 100644
index 00000000..bf2e03e0
--- /dev/null
+++ b/src/whop_sdk/resources/payouts.py
@@ -0,0 +1,240 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ..types import payout_list_params
+from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from .._utils import 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.payout_list_response import PayoutListResponse
+
+__all__ = ["PayoutsResource", "AsyncPayoutsResource"]
+
+
+class PayoutsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> PayoutsResourceWithRawResponse:
+ """
+ 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 PayoutsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> PayoutsResourceWithStreamingResponse:
+ """
+ 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 PayoutsResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ currency: str | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ user_id: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> SyncCursorPage[PayoutListResponse]:
+ """
+ Lists payouts (withdrawal requests) for an account or user, most recent first.
+ Pass exactly one of account*id (a biz* identifier) or user*id (a user*
+ identifier). The saved payout method on each payout additionally requires the
+ payout:destination:read scope and is null without it.
+
+ Args:
+ account_id: The owning account ID (a biz\\__ identifier). Provide this or user_id.
+
+ after: Cursor to fetch the page after (from page_info.end_cursor).
+
+ before: Cursor to fetch the page before (from page_info.start_cursor).
+
+ currency: Optional currency code filter, for example `usd`.
+
+ first: Number of payouts to return from the start of the window.
+
+ last: Number of payouts to return from the end of the window.
+
+ user_id: The owning user ID (a user\\__ identifier). Provide this or account_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._get_api_list(
+ "/payouts",
+ page=SyncCursorPage[PayoutListResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "account_id": account_id,
+ "after": after,
+ "before": before,
+ "currency": currency,
+ "first": first,
+ "last": last,
+ "user_id": user_id,
+ },
+ payout_list_params.PayoutListParams,
+ ),
+ ),
+ model=PayoutListResponse,
+ )
+
+
+class AsyncPayoutsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncPayoutsResourceWithRawResponse:
+ """
+ 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 AsyncPayoutsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncPayoutsResourceWithStreamingResponse:
+ """
+ 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 AsyncPayoutsResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ currency: str | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ user_id: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AsyncPaginator[PayoutListResponse, AsyncCursorPage[PayoutListResponse]]:
+ """
+ Lists payouts (withdrawal requests) for an account or user, most recent first.
+ Pass exactly one of account*id (a biz* identifier) or user*id (a user*
+ identifier). The saved payout method on each payout additionally requires the
+ payout:destination:read scope and is null without it.
+
+ Args:
+ account_id: The owning account ID (a biz\\__ identifier). Provide this or user_id.
+
+ after: Cursor to fetch the page after (from page_info.end_cursor).
+
+ before: Cursor to fetch the page before (from page_info.start_cursor).
+
+ currency: Optional currency code filter, for example `usd`.
+
+ first: Number of payouts to return from the start of the window.
+
+ last: Number of payouts to return from the end of the window.
+
+ user_id: The owning user ID (a user\\__ identifier). Provide this or account_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._get_api_list(
+ "/payouts",
+ page=AsyncCursorPage[PayoutListResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "account_id": account_id,
+ "after": after,
+ "before": before,
+ "currency": currency,
+ "first": first,
+ "last": last,
+ "user_id": user_id,
+ },
+ payout_list_params.PayoutListParams,
+ ),
+ ),
+ model=PayoutListResponse,
+ )
+
+
+class PayoutsResourceWithRawResponse:
+ def __init__(self, payouts: PayoutsResource) -> None:
+ self._payouts = payouts
+
+ self.list = to_raw_response_wrapper(
+ payouts.list,
+ )
+
+
+class AsyncPayoutsResourceWithRawResponse:
+ def __init__(self, payouts: AsyncPayoutsResource) -> None:
+ self._payouts = payouts
+
+ self.list = async_to_raw_response_wrapper(
+ payouts.list,
+ )
+
+
+class PayoutsResourceWithStreamingResponse:
+ def __init__(self, payouts: PayoutsResource) -> None:
+ self._payouts = payouts
+
+ self.list = to_streamed_response_wrapper(
+ payouts.list,
+ )
+
+
+class AsyncPayoutsResourceWithStreamingResponse:
+ def __init__(self, payouts: AsyncPayoutsResource) -> None:
+ self._payouts = payouts
+
+ self.list = async_to_streamed_response_wrapper(
+ payouts.list,
+ )
diff --git a/src/whop_sdk/resources/people.py b/src/whop_sdk/resources/people.py
new file mode 100644
index 00000000..9b3236da
--- /dev/null
+++ b/src/whop_sdk/resources/people.py
@@ -0,0 +1,370 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal
+
+import httpx
+
+from ..types import person_list_params, person_retrieve_params
+from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from .._utils import path_template, 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 .._base_client import make_request_options
+from ..types.person_list_response import PersonListResponse
+from ..types.person_retrieve_response import PersonRetrieveResponse
+
+__all__ = ["PeopleResource", "AsyncPeopleResource"]
+
+
+class PeopleResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> PeopleResourceWithRawResponse:
+ """
+ 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 PeopleResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> PeopleResourceWithStreamingResponse:
+ """
+ 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 PeopleResourceWithStreamingResponse(self)
+
+ def retrieve(
+ self,
+ person_id: str,
+ *,
+ account_id: str | Omit = omit,
+ from_: int | Omit = omit,
+ to: int | 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,
+ ) -> PersonRetrieveResponse:
+ """
+ Retrieves one person for an account, aggregated from pixel events.
+
+ Args:
+ account_id: The ID of the account, which will look like biz\\__******\\********. Optional for
+ account API keys; required for credentials that can access multiple accounts.
+
+ from_: Start of the time range as a Unix timestamp.
+
+ to: End of the time range as a Unix timestamp. Defaults to now.
+
+ 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 person_id:
+ raise ValueError(f"Expected a non-empty value for `person_id` but received {person_id!r}")
+ return self._get(
+ path_template("/people/{person_id}", person_id=person_id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "account_id": account_id,
+ "from_": from_,
+ "to": to,
+ },
+ person_retrieve_params.PersonRetrieveParams,
+ ),
+ ),
+ cast_to=PersonRetrieveResponse,
+ )
+
+ def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ filters: str | Omit = omit,
+ first: int | Omit = omit,
+ from_: int | Omit = omit,
+ offset: int | Omit = omit,
+ sort: str | Omit = omit,
+ to: int | 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,
+ ) -> PersonListResponse:
+ """
+ Lists the people (visitors and customers) of an account, aggregated from pixel
+ events. The account is inferred from an account API key; other credentials must
+ pass account_id.
+
+ Args:
+ account_id: The ID of the account, which will look like biz\\__******\\********. Optional for
+ account API keys; required for credentials that can access multiple accounts.
+
+ direction: Sort direction. Defaults to desc.
+
+ filters: A JSON-encoded array of filters, each with field, operator, and value keys.
+
+ first: The number of people to return (default 100, max 101).
+
+ from_: Start of the time range as a Unix timestamp. Defaults to 366 days before `to`.
+
+ offset: The number of people to skip, for offset pagination.
+
+ sort: Column to sort by (e.g. last_seen_at, ltv, purchase_count). Defaults to
+ last_seen_at.
+
+ to: End of the time range as a Unix timestamp. Defaults to now.
+
+ 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(
+ "/people",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "account_id": account_id,
+ "direction": direction,
+ "filters": filters,
+ "first": first,
+ "from_": from_,
+ "offset": offset,
+ "sort": sort,
+ "to": to,
+ },
+ person_list_params.PersonListParams,
+ ),
+ ),
+ cast_to=PersonListResponse,
+ )
+
+
+class AsyncPeopleResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncPeopleResourceWithRawResponse:
+ """
+ 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 AsyncPeopleResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncPeopleResourceWithStreamingResponse:
+ """
+ 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 AsyncPeopleResourceWithStreamingResponse(self)
+
+ async def retrieve(
+ self,
+ person_id: str,
+ *,
+ account_id: str | Omit = omit,
+ from_: int | Omit = omit,
+ to: int | 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,
+ ) -> PersonRetrieveResponse:
+ """
+ Retrieves one person for an account, aggregated from pixel events.
+
+ Args:
+ account_id: The ID of the account, which will look like biz\\__******\\********. Optional for
+ account API keys; required for credentials that can access multiple accounts.
+
+ from_: Start of the time range as a Unix timestamp.
+
+ to: End of the time range as a Unix timestamp. Defaults to now.
+
+ 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 person_id:
+ raise ValueError(f"Expected a non-empty value for `person_id` but received {person_id!r}")
+ return await self._get(
+ path_template("/people/{person_id}", person_id=person_id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "account_id": account_id,
+ "from_": from_,
+ "to": to,
+ },
+ person_retrieve_params.PersonRetrieveParams,
+ ),
+ ),
+ cast_to=PersonRetrieveResponse,
+ )
+
+ async def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ filters: str | Omit = omit,
+ first: int | Omit = omit,
+ from_: int | Omit = omit,
+ offset: int | Omit = omit,
+ sort: str | Omit = omit,
+ to: int | 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,
+ ) -> PersonListResponse:
+ """
+ Lists the people (visitors and customers) of an account, aggregated from pixel
+ events. The account is inferred from an account API key; other credentials must
+ pass account_id.
+
+ Args:
+ account_id: The ID of the account, which will look like biz\\__******\\********. Optional for
+ account API keys; required for credentials that can access multiple accounts.
+
+ direction: Sort direction. Defaults to desc.
+
+ filters: A JSON-encoded array of filters, each with field, operator, and value keys.
+
+ first: The number of people to return (default 100, max 101).
+
+ from_: Start of the time range as a Unix timestamp. Defaults to 366 days before `to`.
+
+ offset: The number of people to skip, for offset pagination.
+
+ sort: Column to sort by (e.g. last_seen_at, ltv, purchase_count). Defaults to
+ last_seen_at.
+
+ to: End of the time range as a Unix timestamp. Defaults to now.
+
+ 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._get(
+ "/people",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "account_id": account_id,
+ "direction": direction,
+ "filters": filters,
+ "first": first,
+ "from_": from_,
+ "offset": offset,
+ "sort": sort,
+ "to": to,
+ },
+ person_list_params.PersonListParams,
+ ),
+ ),
+ cast_to=PersonListResponse,
+ )
+
+
+class PeopleResourceWithRawResponse:
+ def __init__(self, people: PeopleResource) -> None:
+ self._people = people
+
+ self.retrieve = to_raw_response_wrapper(
+ people.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ people.list,
+ )
+
+
+class AsyncPeopleResourceWithRawResponse:
+ def __init__(self, people: AsyncPeopleResource) -> None:
+ self._people = people
+
+ self.retrieve = async_to_raw_response_wrapper(
+ people.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ people.list,
+ )
+
+
+class PeopleResourceWithStreamingResponse:
+ def __init__(self, people: PeopleResource) -> None:
+ self._people = people
+
+ self.retrieve = to_streamed_response_wrapper(
+ people.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ people.list,
+ )
+
+
+class AsyncPeopleResourceWithStreamingResponse:
+ def __init__(self, people: AsyncPeopleResource) -> None:
+ self._people = people
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ people.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ people.list,
+ )
diff --git a/src/whop_sdk/resources/plans.py b/src/whop_sdk/resources/plans.py
index e351bc6f..03519e0a 100644
--- a/src/whop_sdk/resources/plans.py
+++ b/src/whop_sdk/resources/plans.py
@@ -2,13 +2,12 @@
from __future__ import annotations
-from typing import Dict, List, Union, Iterable, Optional
-from datetime import datetime
+from typing import Iterable, Optional
from typing_extensions import Literal
import httpx
-from ..types import plan_list_params, plan_create_params, plan_update_params
+from ..types import plan_list_params, plan_create_params, plan_update_params, plan_calculate_tax_params
from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
@@ -22,22 +21,14 @@
from ..pagination import SyncCursorPage, AsyncCursorPage
from .._base_client import AsyncPaginator, make_request_options
from ..types.shared.plan import Plan
-from ..types.shared.currency import Currency
-from ..types.shared.tax_type import TaxType
-from ..types.shared.direction import Direction
-from ..types.shared.plan_type import PlanType
-from ..types.shared.visibility import Visibility
from ..types.plan_list_response import PlanListResponse
from ..types.plan_delete_response import PlanDeleteResponse
-from ..types.shared.release_method import ReleaseMethod
-from ..types.shared.visibility_filter import VisibilityFilter
+from ..types.plan_calculate_tax_response import PlanCalculateTaxResponse
__all__ = ["PlansResource", "AsyncPlansResource"]
class PlansResource(SyncAPIResource):
- """Plans"""
-
@cached_property
def with_raw_response(self) -> PlansResourceWithRawResponse:
"""
@@ -60,12 +51,11 @@ def with_streaming_response(self) -> PlansResourceWithStreamingResponse:
def create(
self,
*,
- company_id: str,
- product_id: str,
+ account_id: str | Omit = omit,
adaptive_pricing_enabled: Optional[bool] | Omit = omit,
billing_period: Optional[int] | Omit = omit,
- checkout_styling: Optional[plan_create_params.CheckoutStyling] | Omit = omit,
- currency: Optional[Currency] | Omit = omit,
+ checkout_styling: Optional[object] | Omit = omit,
+ currency: str | Omit = omit,
custom_fields: Optional[Iterable[plan_create_params.CustomField]] | Omit = omit,
description: Optional[str] | Omit = omit,
expiration_days: Optional[int] | Omit = omit,
@@ -73,19 +63,20 @@ def create(
initial_price: Optional[float] | Omit = omit,
internal_notes: Optional[str] | Omit = omit,
legacy_payment_method_controls: Optional[bool] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
- override_tax_type: Optional[TaxType] | Omit = omit,
+ metadata: Optional[object] | Omit = omit,
+ override_tax_type: str | Omit = omit,
payment_method_configuration: Optional[plan_create_params.PaymentMethodConfiguration] | Omit = omit,
- plan_type: Optional[PlanType] | Omit = omit,
- release_method: Optional[ReleaseMethod] | Omit = omit,
+ plan_type: str | Omit = omit,
+ product_id: str | Omit = omit,
+ release_method: str | Omit = omit,
renewal_price: Optional[float] | Omit = omit,
split_pay_required_payments: Optional[int] | Omit = omit,
stock: Optional[int] | Omit = omit,
- three_ds_level: Optional[Literal["mandate_challenge", "frictionless"]] | Omit = omit,
+ three_ds_level: Literal["mandate_challenge", "frictionless"] | Omit = omit,
title: Optional[str] | Omit = omit,
trial_period_days: Optional[int] | Omit = omit,
unlimited_stock: Optional[bool] | Omit = omit,
- visibility: Optional[Visibility] | Omit = omit,
+ visibility: 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.
extra_headers: Headers | None = None,
@@ -98,76 +89,65 @@ def create(
The plan defines the billing interval,
price, and availability for customers.
- Required permissions:
-
- - `plan:create`
- - `access_pass:basic:read`
- - `plan:basic:read`
-
Args:
- company_id: The unique identifier of the company to create this plan for.
-
- product_id: The unique identifier of the product to attach this plan to.
+ account_id: The unique identifier of the account to create this plan for. Defaults to the
+ caller's account.
adaptive_pricing_enabled: Whether this plan accepts local currency payments via adaptive pricing.
- billing_period: The number of days between recurring charges. For example, 30 for monthly or 365
- for yearly.
+ billing_period: Recurring billing interval in days, such as 30 for monthly or 365 for annual.
- checkout_styling: Checkout styling overrides for this plan. Pass null to inherit from the company
- default.
+ checkout_styling: Checkout styling overrides for this plan.
- currency: The available currencies on the platform
+ currency: The three-letter ISO currency code for the plan's pricing. Defaults to USD.
custom_fields: An array of custom field definitions to collect from customers at checkout.
+ Omitting this field clears existing custom fields.
description: A text description of the plan displayed to customers on the product page.
- expiration_days: The number of days until the membership expires and access is revoked. Used for
- expiration-based plans.
+ expiration_days: Access duration in days before the membership expires.
image: An image displayed on the product page to represent this plan.
- initial_price: The amount charged on the first purchase. For one-time plans, this is the full
- price. For recurring plans, this is an additional charge on top of the renewal
- price. Provided in the plan's currency (e.g., 10.43 for $10.43).
+ initial_price: Initial amount charged in the plan's currency, e.g. 10.43 for $10.43.
- internal_notes: Private notes visible only to the business owner. Not shown to customers.
+ internal_notes: Private notes visible only to the account owner. Not shown to customers.
legacy_payment_method_controls: Whether this plan uses legacy payment method controls.
metadata: Custom key-value pairs to store on the plan. Included in webhook payloads for
- payment and membership events. Max 50 keys, 500 chars per key, 5000 chars per
- value.
+ payment and membership events. Max 50 keys, 100 chars per key, 500 chars per
+ string value.
- override_tax_type: Whether or not the tax is included in a plan's price (or if it hasn't been set
- up)
+ override_tax_type: Override the default tax classification for this specific plan.
payment_method_configuration: Explicit payment method configuration for the plan. When not provided, the
- company's defaults apply.
+ account's defaults apply.
+
+ plan_type: Plan billing type, such as `one_time` or `renewal`.
- plan_type: The type of plan that can be attached to a product
+ product_id: The unique identifier of the product to attach this plan to.
- release_method: The methods of how a plan can be released.
+ release_method: Sales method for this plan, such as `buy_now` or `waitlist`.
- renewal_price: The amount charged each billing period for recurring plans. Provided in the
- plan's currency (e.g., 10.43 for $10.43).
+ renewal_price: The amount charged each billing period for recurring plans, in the plan's
+ currency.
- split_pay_required_payments: The number of installment payments required before the subscription pauses.
+ split_pay_required_payments: Installment payments required before the subscription pauses.
stock: The maximum number of units available for purchase. Ignored when unlimited_stock
is true.
- three_ds_level: The 3D Secure behavior for a plan.
+ three_ds_level: 3D Secure behavior for this plan. Send `null` to inherit the account default.
title: The display name of the plan shown to customers on the product page.
- trial_period_days: The number of free trial days before the first charge on a recurring plan.
+ trial_period_days: Free trial duration before the first recurring charge.
unlimited_stock: Whether the plan has unlimited stock. When true, the stock field is ignored.
- Defaults to true.
- visibility: Visibility of a resource
+ visibility: Whether the plan is visible to customers or hidden from public view.
extra_headers: Send extra headers
@@ -181,8 +161,7 @@ def create(
"/plans",
body=maybe_transform(
{
- "company_id": company_id,
- "product_id": product_id,
+ "account_id": account_id,
"adaptive_pricing_enabled": adaptive_pricing_enabled,
"billing_period": billing_period,
"checkout_styling": checkout_styling,
@@ -198,6 +177,7 @@ def create(
"override_tax_type": override_tax_type,
"payment_method_configuration": payment_method_configuration,
"plan_type": plan_type,
+ "product_id": product_id,
"release_method": release_method,
"renewal_price": renewal_price,
"split_pay_required_payments": split_pay_required_payments,
@@ -230,10 +210,6 @@ def retrieve(
"""
Retrieves the details of an existing plan.
- Required permissions:
-
- - `plan:basic:read`
-
Args:
extra_headers: Send extra headers
@@ -259,8 +235,8 @@ def update(
*,
adaptive_pricing_enabled: Optional[bool] | Omit = omit,
billing_period: Optional[int] | Omit = omit,
- checkout_styling: Optional[plan_update_params.CheckoutStyling] | Omit = omit,
- currency: Optional[Currency] | Omit = omit,
+ checkout_styling: Optional[object] | Omit = omit,
+ currency: str | Omit = omit,
custom_fields: Optional[Iterable[plan_update_params.CustomField]] | Omit = omit,
description: Optional[str] | Omit = omit,
expiration_days: Optional[int] | Omit = omit,
@@ -268,19 +244,19 @@ def update(
initial_price: Optional[float] | Omit = omit,
internal_notes: Optional[str] | Omit = omit,
legacy_payment_method_controls: Optional[bool] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
+ metadata: Optional[object] | Omit = omit,
offer_cancel_discount: Optional[bool] | Omit = omit,
- override_tax_type: Optional[TaxType] | Omit = omit,
+ override_tax_type: str | Omit = omit,
payment_method_configuration: Optional[plan_update_params.PaymentMethodConfiguration] | Omit = omit,
renewal_price: Optional[float] | Omit = omit,
stock: Optional[int] | Omit = omit,
strike_through_initial_price: Optional[float] | Omit = omit,
strike_through_renewal_price: Optional[float] | Omit = omit,
- three_ds_level: Optional[Literal["mandate_challenge", "frictionless"]] | Omit = omit,
+ three_ds_level: Literal["mandate_challenge", "frictionless"] | Omit = omit,
title: Optional[str] | Omit = omit,
trial_period_days: Optional[int] | Omit = omit,
unlimited_stock: Optional[bool] | Omit = omit,
- visibility: Optional[Visibility] | Omit = omit,
+ visibility: 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.
extra_headers: Headers | None = None,
@@ -292,72 +268,60 @@ def update(
Update a plan's pricing, billing interval, visibility, stock, and other
settings.
- Required permissions:
-
- - `plan:update`
- - `access_pass:basic:read`
- - `plan:basic:read`
-
Args:
adaptive_pricing_enabled: Whether this plan accepts local currency payments via adaptive pricing.
- billing_period: The number of days between recurring charges. For example, 30 for monthly or 365
- for yearly.
+ billing_period: Recurring billing interval in days, such as 30 for monthly or 365 for annual.
- checkout_styling: Checkout styling overrides for this plan. Pass null to remove all overrides and
- inherit from the company default.
+ checkout_styling: Checkout styling overrides for this plan.
- currency: The available currencies on the platform
+ currency: The three-letter ISO currency code for the plan's pricing. Defaults to USD.
custom_fields: An array of custom field definitions to collect from customers at checkout.
+ Omitting this field clears existing custom fields.
description: A text description of the plan displayed to customers on the product page.
- expiration_days: The number of days until the membership expires and access is revoked. For
- example, 365 for one-year access.
+ expiration_days: Access duration in days before the membership expires.
image: An image displayed on the product page to represent this plan.
- initial_price: The amount charged on the first purchase. Provided in the plan's currency (e.g.,
- 10.43 for $10.43).
+ initial_price: Initial amount charged in the plan's currency, e.g. 10.43 for $10.43.
- internal_notes: Private notes visible only to the business owner. Not shown to customers.
+ internal_notes: Private notes visible only to the account owner. Not shown to customers.
legacy_payment_method_controls: Whether this plan uses legacy payment method controls.
metadata: Custom key-value pairs to store on the plan. Included in webhook payloads for
- payment and membership events. Max 50 keys, 500 chars per key, 5000 chars per
- value.
+ payment and membership events. Max 50 keys, 100 chars per key, 500 chars per
+ string value.
offer_cancel_discount: Whether to offer a retention discount when a customer attempts to cancel.
- override_tax_type: Whether or not the tax is included in a plan's price (or if it hasn't been set
- up)
+ override_tax_type: Override the default tax classification for this specific plan.
- payment_method_configuration: Explicit payment method configuration for the plan. Sending null removes any
- custom configuration.
+ payment_method_configuration: Explicit payment method configuration for the plan. When not provided, the
+ account's defaults apply.
- renewal_price: The amount charged each billing period for recurring plans. Provided in the
- plan's currency (e.g., 10.43 for $10.43).
+ renewal_price: The amount charged each billing period for recurring plans, in the plan's
+ currency.
stock: The maximum number of units available for purchase. Ignored when unlimited_stock
is true.
strike_through_initial_price: A comparison price displayed with a strikethrough for the initial price.
- Provided in the plan's currency (e.g., 19.99 for $19.99).
strike_through_renewal_price: A comparison price displayed with a strikethrough for the renewal price.
- Provided in the plan's currency (e.g., 19.99 for $19.99).
- three_ds_level: The 3D Secure behavior for a plan.
+ three_ds_level: 3D Secure behavior for this plan. Send `null` to inherit the account default.
title: The display name of the plan shown to customers on the product page.
- trial_period_days: The number of free trial days before the first charge on a recurring plan.
+ trial_period_days: Free trial duration before the first recurring charge.
unlimited_stock: Whether the plan has unlimited stock. When true, the stock field is ignored.
- visibility: Visibility of a resource
+ visibility: Whether the plan is visible to customers or hidden from public view.
extra_headers: Send extra headers
@@ -409,20 +373,19 @@ def update(
def list(
self,
*,
- company_id: str,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- created_after: Union[str, datetime, None] | Omit = omit,
- created_before: Union[str, datetime, None] | Omit = omit,
- direction: Optional[Direction] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[int] | Omit = omit,
- order: Optional[Literal["id", "active_members_count", "created_at", "internal_notes", "expires_at"]]
- | Omit = omit,
- plan_types: Optional[List[PlanType]] | Omit = omit,
- product_ids: Optional[SequenceNotStr[str]] | Omit = omit,
- release_methods: Optional[List[ReleaseMethod]] | Omit = omit,
- visibilities: Optional[List[VisibilityFilter]] | Omit = omit,
+ account_id: str,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ created_after: str | Omit = omit,
+ created_before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal["id", "active_members_count", "created_at", "internal_notes", "expiration_days"] | Omit = omit,
+ plan_types: SequenceNotStr[str] | Omit = omit,
+ product_ids: SequenceNotStr[str] | Omit = omit,
+ release_methods: SequenceNotStr[str] | Omit = omit,
+ visibilities: SequenceNotStr[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.
extra_headers: Headers | None = None,
@@ -431,31 +394,27 @@ def list(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[PlanListResponse]:
"""
- Returns a paginated list of plans belonging to a company, with optional
+ Returns a paginated list of plans belonging to an account, with optional
filtering by visibility, type, release method, and product.
- Required permissions:
-
- - `plan:basic:read`
-
Args:
- company_id: The unique identifier of the company to list plans for.
+ account_id: The unique identifier of the account to list plans for.
- after: Returns the elements in the list that come after the specified cursor.
+ after: A cursor; returns plans after this position.
- before: Returns the elements in the list that come before the specified cursor.
+ before: A cursor; returns plans before this position.
created_after: Only return plans created after this timestamp.
created_before: Only return plans created before this timestamp.
- direction: The direction of the sort.
+ direction: The sort direction for results. Defaults to descending.
- first: Returns the first _n_ elements from the list.
+ first: The number of plans to return (default and max 100).
- last: Returns the last _n_ elements from the list.
+ last: The number of plans to return from the end of the range.
- order: The ways a relation of Plans can be ordered
+ order: The field to sort results by. Defaults to created_at.
plan_types: Filter to only plans matching these billing types.
@@ -483,7 +442,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
- "company_id": company_id,
+ "account_id": account_id,
"after": after,
"before": before,
"created_after": created_after,
@@ -519,10 +478,6 @@ def delete(
Existing memberships on this plan will
not be affected.
- Required permissions:
-
- - `plan:delete`
-
Args:
extra_headers: Send extra headers
@@ -542,10 +497,60 @@ def delete(
cast_to=PlanDeleteResponse,
)
+ def calculate_tax(
+ self,
+ id: str,
+ *,
+ address: Optional[plan_calculate_tax_params.Address] | Omit = omit,
+ ip_address: str | Omit = omit,
+ tax_ids: Optional[Iterable[plan_calculate_tax_params.TaxID]] | 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,
+ ) -> PlanCalculateTaxResponse:
+ """
+ Calculates the tax owed on a plan based on the buyer's location.
-class AsyncPlansResource(AsyncAPIResource):
- """Plans"""
+ Args:
+ address: The buyer's billing address. Provide this or ip_address.
+
+ ip_address: The buyer's IP address, used to resolve their location when no address is
+ provided.
+
+ tax_ids: The buyer's tax IDs, such as a VAT number, used to apply B2B reverse-charge
+ exemptions.
+
+ 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(
+ path_template("/plans/{id}/calculate_tax", id=id),
+ body=maybe_transform(
+ {
+ "address": address,
+ "ip_address": ip_address,
+ "tax_ids": tax_ids,
+ },
+ plan_calculate_tax_params.PlanCalculateTaxParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=PlanCalculateTaxResponse,
+ )
+
+
+class AsyncPlansResource(AsyncAPIResource):
@cached_property
def with_raw_response(self) -> AsyncPlansResourceWithRawResponse:
"""
@@ -568,12 +573,11 @@ def with_streaming_response(self) -> AsyncPlansResourceWithStreamingResponse:
async def create(
self,
*,
- company_id: str,
- product_id: str,
+ account_id: str | Omit = omit,
adaptive_pricing_enabled: Optional[bool] | Omit = omit,
billing_period: Optional[int] | Omit = omit,
- checkout_styling: Optional[plan_create_params.CheckoutStyling] | Omit = omit,
- currency: Optional[Currency] | Omit = omit,
+ checkout_styling: Optional[object] | Omit = omit,
+ currency: str | Omit = omit,
custom_fields: Optional[Iterable[plan_create_params.CustomField]] | Omit = omit,
description: Optional[str] | Omit = omit,
expiration_days: Optional[int] | Omit = omit,
@@ -581,19 +585,20 @@ async def create(
initial_price: Optional[float] | Omit = omit,
internal_notes: Optional[str] | Omit = omit,
legacy_payment_method_controls: Optional[bool] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
- override_tax_type: Optional[TaxType] | Omit = omit,
+ metadata: Optional[object] | Omit = omit,
+ override_tax_type: str | Omit = omit,
payment_method_configuration: Optional[plan_create_params.PaymentMethodConfiguration] | Omit = omit,
- plan_type: Optional[PlanType] | Omit = omit,
- release_method: Optional[ReleaseMethod] | Omit = omit,
+ plan_type: str | Omit = omit,
+ product_id: str | Omit = omit,
+ release_method: str | Omit = omit,
renewal_price: Optional[float] | Omit = omit,
split_pay_required_payments: Optional[int] | Omit = omit,
stock: Optional[int] | Omit = omit,
- three_ds_level: Optional[Literal["mandate_challenge", "frictionless"]] | Omit = omit,
+ three_ds_level: Literal["mandate_challenge", "frictionless"] | Omit = omit,
title: Optional[str] | Omit = omit,
trial_period_days: Optional[int] | Omit = omit,
unlimited_stock: Optional[bool] | Omit = omit,
- visibility: Optional[Visibility] | Omit = omit,
+ visibility: 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.
extra_headers: Headers | None = None,
@@ -606,76 +611,65 @@ async def create(
The plan defines the billing interval,
price, and availability for customers.
- Required permissions:
-
- - `plan:create`
- - `access_pass:basic:read`
- - `plan:basic:read`
-
Args:
- company_id: The unique identifier of the company to create this plan for.
-
- product_id: The unique identifier of the product to attach this plan to.
+ account_id: The unique identifier of the account to create this plan for. Defaults to the
+ caller's account.
adaptive_pricing_enabled: Whether this plan accepts local currency payments via adaptive pricing.
- billing_period: The number of days between recurring charges. For example, 30 for monthly or 365
- for yearly.
+ billing_period: Recurring billing interval in days, such as 30 for monthly or 365 for annual.
- checkout_styling: Checkout styling overrides for this plan. Pass null to inherit from the company
- default.
+ checkout_styling: Checkout styling overrides for this plan.
- currency: The available currencies on the platform
+ currency: The three-letter ISO currency code for the plan's pricing. Defaults to USD.
custom_fields: An array of custom field definitions to collect from customers at checkout.
+ Omitting this field clears existing custom fields.
description: A text description of the plan displayed to customers on the product page.
- expiration_days: The number of days until the membership expires and access is revoked. Used for
- expiration-based plans.
+ expiration_days: Access duration in days before the membership expires.
image: An image displayed on the product page to represent this plan.
- initial_price: The amount charged on the first purchase. For one-time plans, this is the full
- price. For recurring plans, this is an additional charge on top of the renewal
- price. Provided in the plan's currency (e.g., 10.43 for $10.43).
+ initial_price: Initial amount charged in the plan's currency, e.g. 10.43 for $10.43.
- internal_notes: Private notes visible only to the business owner. Not shown to customers.
+ internal_notes: Private notes visible only to the account owner. Not shown to customers.
legacy_payment_method_controls: Whether this plan uses legacy payment method controls.
metadata: Custom key-value pairs to store on the plan. Included in webhook payloads for
- payment and membership events. Max 50 keys, 500 chars per key, 5000 chars per
- value.
+ payment and membership events. Max 50 keys, 100 chars per key, 500 chars per
+ string value.
- override_tax_type: Whether or not the tax is included in a plan's price (or if it hasn't been set
- up)
+ override_tax_type: Override the default tax classification for this specific plan.
payment_method_configuration: Explicit payment method configuration for the plan. When not provided, the
- company's defaults apply.
+ account's defaults apply.
- plan_type: The type of plan that can be attached to a product
+ plan_type: Plan billing type, such as `one_time` or `renewal`.
- release_method: The methods of how a plan can be released.
+ product_id: The unique identifier of the product to attach this plan to.
- renewal_price: The amount charged each billing period for recurring plans. Provided in the
- plan's currency (e.g., 10.43 for $10.43).
+ release_method: Sales method for this plan, such as `buy_now` or `waitlist`.
- split_pay_required_payments: The number of installment payments required before the subscription pauses.
+ renewal_price: The amount charged each billing period for recurring plans, in the plan's
+ currency.
+
+ split_pay_required_payments: Installment payments required before the subscription pauses.
stock: The maximum number of units available for purchase. Ignored when unlimited_stock
is true.
- three_ds_level: The 3D Secure behavior for a plan.
+ three_ds_level: 3D Secure behavior for this plan. Send `null` to inherit the account default.
title: The display name of the plan shown to customers on the product page.
- trial_period_days: The number of free trial days before the first charge on a recurring plan.
+ trial_period_days: Free trial duration before the first recurring charge.
unlimited_stock: Whether the plan has unlimited stock. When true, the stock field is ignored.
- Defaults to true.
- visibility: Visibility of a resource
+ visibility: Whether the plan is visible to customers or hidden from public view.
extra_headers: Send extra headers
@@ -689,8 +683,7 @@ async def create(
"/plans",
body=await async_maybe_transform(
{
- "company_id": company_id,
- "product_id": product_id,
+ "account_id": account_id,
"adaptive_pricing_enabled": adaptive_pricing_enabled,
"billing_period": billing_period,
"checkout_styling": checkout_styling,
@@ -706,6 +699,7 @@ async def create(
"override_tax_type": override_tax_type,
"payment_method_configuration": payment_method_configuration,
"plan_type": plan_type,
+ "product_id": product_id,
"release_method": release_method,
"renewal_price": renewal_price,
"split_pay_required_payments": split_pay_required_payments,
@@ -738,10 +732,6 @@ async def retrieve(
"""
Retrieves the details of an existing plan.
- Required permissions:
-
- - `plan:basic:read`
-
Args:
extra_headers: Send extra headers
@@ -767,8 +757,8 @@ async def update(
*,
adaptive_pricing_enabled: Optional[bool] | Omit = omit,
billing_period: Optional[int] | Omit = omit,
- checkout_styling: Optional[plan_update_params.CheckoutStyling] | Omit = omit,
- currency: Optional[Currency] | Omit = omit,
+ checkout_styling: Optional[object] | Omit = omit,
+ currency: str | Omit = omit,
custom_fields: Optional[Iterable[plan_update_params.CustomField]] | Omit = omit,
description: Optional[str] | Omit = omit,
expiration_days: Optional[int] | Omit = omit,
@@ -776,19 +766,19 @@ async def update(
initial_price: Optional[float] | Omit = omit,
internal_notes: Optional[str] | Omit = omit,
legacy_payment_method_controls: Optional[bool] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
+ metadata: Optional[object] | Omit = omit,
offer_cancel_discount: Optional[bool] | Omit = omit,
- override_tax_type: Optional[TaxType] | Omit = omit,
+ override_tax_type: str | Omit = omit,
payment_method_configuration: Optional[plan_update_params.PaymentMethodConfiguration] | Omit = omit,
renewal_price: Optional[float] | Omit = omit,
stock: Optional[int] | Omit = omit,
strike_through_initial_price: Optional[float] | Omit = omit,
strike_through_renewal_price: Optional[float] | Omit = omit,
- three_ds_level: Optional[Literal["mandate_challenge", "frictionless"]] | Omit = omit,
+ three_ds_level: Literal["mandate_challenge", "frictionless"] | Omit = omit,
title: Optional[str] | Omit = omit,
trial_period_days: Optional[int] | Omit = omit,
unlimited_stock: Optional[bool] | Omit = omit,
- visibility: Optional[Visibility] | Omit = omit,
+ visibility: 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.
extra_headers: Headers | None = None,
@@ -800,72 +790,60 @@ async def update(
Update a plan's pricing, billing interval, visibility, stock, and other
settings.
- Required permissions:
-
- - `plan:update`
- - `access_pass:basic:read`
- - `plan:basic:read`
-
Args:
adaptive_pricing_enabled: Whether this plan accepts local currency payments via adaptive pricing.
- billing_period: The number of days between recurring charges. For example, 30 for monthly or 365
- for yearly.
+ billing_period: Recurring billing interval in days, such as 30 for monthly or 365 for annual.
- checkout_styling: Checkout styling overrides for this plan. Pass null to remove all overrides and
- inherit from the company default.
+ checkout_styling: Checkout styling overrides for this plan.
- currency: The available currencies on the platform
+ currency: The three-letter ISO currency code for the plan's pricing. Defaults to USD.
custom_fields: An array of custom field definitions to collect from customers at checkout.
+ Omitting this field clears existing custom fields.
description: A text description of the plan displayed to customers on the product page.
- expiration_days: The number of days until the membership expires and access is revoked. For
- example, 365 for one-year access.
+ expiration_days: Access duration in days before the membership expires.
image: An image displayed on the product page to represent this plan.
- initial_price: The amount charged on the first purchase. Provided in the plan's currency (e.g.,
- 10.43 for $10.43).
+ initial_price: Initial amount charged in the plan's currency, e.g. 10.43 for $10.43.
- internal_notes: Private notes visible only to the business owner. Not shown to customers.
+ internal_notes: Private notes visible only to the account owner. Not shown to customers.
legacy_payment_method_controls: Whether this plan uses legacy payment method controls.
metadata: Custom key-value pairs to store on the plan. Included in webhook payloads for
- payment and membership events. Max 50 keys, 500 chars per key, 5000 chars per
- value.
+ payment and membership events. Max 50 keys, 100 chars per key, 500 chars per
+ string value.
offer_cancel_discount: Whether to offer a retention discount when a customer attempts to cancel.
- override_tax_type: Whether or not the tax is included in a plan's price (or if it hasn't been set
- up)
+ override_tax_type: Override the default tax classification for this specific plan.
- payment_method_configuration: Explicit payment method configuration for the plan. Sending null removes any
- custom configuration.
+ payment_method_configuration: Explicit payment method configuration for the plan. When not provided, the
+ account's defaults apply.
- renewal_price: The amount charged each billing period for recurring plans. Provided in the
- plan's currency (e.g., 10.43 for $10.43).
+ renewal_price: The amount charged each billing period for recurring plans, in the plan's
+ currency.
stock: The maximum number of units available for purchase. Ignored when unlimited_stock
is true.
strike_through_initial_price: A comparison price displayed with a strikethrough for the initial price.
- Provided in the plan's currency (e.g., 19.99 for $19.99).
strike_through_renewal_price: A comparison price displayed with a strikethrough for the renewal price.
- Provided in the plan's currency (e.g., 19.99 for $19.99).
- three_ds_level: The 3D Secure behavior for a plan.
+ three_ds_level: 3D Secure behavior for this plan. Send `null` to inherit the account default.
title: The display name of the plan shown to customers on the product page.
- trial_period_days: The number of free trial days before the first charge on a recurring plan.
+ trial_period_days: Free trial duration before the first recurring charge.
unlimited_stock: Whether the plan has unlimited stock. When true, the stock field is ignored.
- visibility: Visibility of a resource
+ visibility: Whether the plan is visible to customers or hidden from public view.
extra_headers: Send extra headers
@@ -917,20 +895,19 @@ async def update(
def list(
self,
*,
- company_id: str,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- created_after: Union[str, datetime, None] | Omit = omit,
- created_before: Union[str, datetime, None] | Omit = omit,
- direction: Optional[Direction] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[int] | Omit = omit,
- order: Optional[Literal["id", "active_members_count", "created_at", "internal_notes", "expires_at"]]
- | Omit = omit,
- plan_types: Optional[List[PlanType]] | Omit = omit,
- product_ids: Optional[SequenceNotStr[str]] | Omit = omit,
- release_methods: Optional[List[ReleaseMethod]] | Omit = omit,
- visibilities: Optional[List[VisibilityFilter]] | Omit = omit,
+ account_id: str,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ created_after: str | Omit = omit,
+ created_before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal["id", "active_members_count", "created_at", "internal_notes", "expiration_days"] | Omit = omit,
+ plan_types: SequenceNotStr[str] | Omit = omit,
+ product_ids: SequenceNotStr[str] | Omit = omit,
+ release_methods: SequenceNotStr[str] | Omit = omit,
+ visibilities: SequenceNotStr[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.
extra_headers: Headers | None = None,
@@ -939,31 +916,27 @@ def list(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[PlanListResponse, AsyncCursorPage[PlanListResponse]]:
"""
- Returns a paginated list of plans belonging to a company, with optional
+ Returns a paginated list of plans belonging to an account, with optional
filtering by visibility, type, release method, and product.
- Required permissions:
-
- - `plan:basic:read`
-
Args:
- company_id: The unique identifier of the company to list plans for.
+ account_id: The unique identifier of the account to list plans for.
- after: Returns the elements in the list that come after the specified cursor.
+ after: A cursor; returns plans after this position.
- before: Returns the elements in the list that come before the specified cursor.
+ before: A cursor; returns plans before this position.
created_after: Only return plans created after this timestamp.
created_before: Only return plans created before this timestamp.
- direction: The direction of the sort.
+ direction: The sort direction for results. Defaults to descending.
- first: Returns the first _n_ elements from the list.
+ first: The number of plans to return (default and max 100).
- last: Returns the last _n_ elements from the list.
+ last: The number of plans to return from the end of the range.
- order: The ways a relation of Plans can be ordered
+ order: The field to sort results by. Defaults to created_at.
plan_types: Filter to only plans matching these billing types.
@@ -991,7 +964,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
- "company_id": company_id,
+ "account_id": account_id,
"after": after,
"before": before,
"created_after": created_after,
@@ -1027,10 +1000,6 @@ async def delete(
Existing memberships on this plan will
not be affected.
- Required permissions:
-
- - `plan:delete`
-
Args:
extra_headers: Send extra headers
@@ -1050,6 +1019,58 @@ async def delete(
cast_to=PlanDeleteResponse,
)
+ async def calculate_tax(
+ self,
+ id: str,
+ *,
+ address: Optional[plan_calculate_tax_params.Address] | Omit = omit,
+ ip_address: str | Omit = omit,
+ tax_ids: Optional[Iterable[plan_calculate_tax_params.TaxID]] | 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,
+ ) -> PlanCalculateTaxResponse:
+ """
+ Calculates the tax owed on a plan based on the buyer's location.
+
+ Args:
+ address: The buyer's billing address. Provide this or ip_address.
+
+ ip_address: The buyer's IP address, used to resolve their location when no address is
+ provided.
+
+ tax_ids: The buyer's tax IDs, such as a VAT number, used to apply B2B reverse-charge
+ exemptions.
+
+ 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(
+ path_template("/plans/{id}/calculate_tax", id=id),
+ body=await async_maybe_transform(
+ {
+ "address": address,
+ "ip_address": ip_address,
+ "tax_ids": tax_ids,
+ },
+ plan_calculate_tax_params.PlanCalculateTaxParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=PlanCalculateTaxResponse,
+ )
+
class PlansResourceWithRawResponse:
def __init__(self, plans: PlansResource) -> None:
@@ -1070,6 +1091,9 @@ def __init__(self, plans: PlansResource) -> None:
self.delete = to_raw_response_wrapper(
plans.delete,
)
+ self.calculate_tax = to_raw_response_wrapper(
+ plans.calculate_tax,
+ )
class AsyncPlansResourceWithRawResponse:
@@ -1091,6 +1115,9 @@ def __init__(self, plans: AsyncPlansResource) -> None:
self.delete = async_to_raw_response_wrapper(
plans.delete,
)
+ self.calculate_tax = async_to_raw_response_wrapper(
+ plans.calculate_tax,
+ )
class PlansResourceWithStreamingResponse:
@@ -1112,6 +1139,9 @@ def __init__(self, plans: PlansResource) -> None:
self.delete = to_streamed_response_wrapper(
plans.delete,
)
+ self.calculate_tax = to_streamed_response_wrapper(
+ plans.calculate_tax,
+ )
class AsyncPlansResourceWithStreamingResponse:
@@ -1133,3 +1163,6 @@ def __init__(self, plans: AsyncPlansResource) -> None:
self.delete = async_to_streamed_response_wrapper(
plans.delete,
)
+ self.calculate_tax = async_to_streamed_response_wrapper(
+ plans.calculate_tax,
+ )
diff --git a/src/whop_sdk/resources/products.py b/src/whop_sdk/resources/products.py
index 505de8e1..a9fb7d02 100644
--- a/src/whop_sdk/resources/products.py
+++ b/src/whop_sdk/resources/products.py
@@ -2,8 +2,7 @@
from __future__ import annotations
-from typing import Dict, List, Union, Iterable, Optional
-from datetime import datetime
+from typing import Optional
from typing_extensions import Literal
import httpx
@@ -22,14 +21,8 @@
from ..pagination import SyncCursorPage, AsyncCursorPage
from .._base_client import AsyncPaginator, make_request_options
from ..types.shared.product import Product
-from ..types.shared.direction import Direction
-from ..types.shared.custom_cta import CustomCta
-from ..types.shared.visibility import Visibility
from ..types.product_delete_response import ProductDeleteResponse
-from ..types.shared.access_pass_type import AccessPassType
from ..types.shared.product_list_item import ProductListItem
-from ..types.shared.visibility_filter import VisibilityFilter
-from ..types.shared.global_affiliate_status import GlobalAffiliateStatus
__all__ = ["ProductsResource", "AsyncProductsResource"]
@@ -59,26 +52,23 @@ def with_streaming_response(self) -> ProductsResourceWithStreamingResponse:
def create(
self,
*,
- company_id: str,
title: str,
collect_shipping_address: Optional[bool] | Omit = omit,
- custom_cta: Optional[CustomCta] | Omit = omit,
+ company_id: str | Omit = omit,
+ custom_cta: Optional[str] | Omit = omit,
custom_cta_url: Optional[str] | Omit = omit,
custom_statement_descriptor: Optional[str] | Omit = omit,
description: Optional[str] | Omit = omit,
- experience_ids: Optional[SequenceNotStr[str]] | Omit = omit,
global_affiliate_percentage: Optional[float] | Omit = omit,
- global_affiliate_status: Optional[GlobalAffiliateStatus] | Omit = omit,
+ global_affiliate_status: str | Omit = omit,
headline: Optional[str] | Omit = omit,
member_affiliate_percentage: Optional[float] | Omit = omit,
- member_affiliate_status: Optional[GlobalAffiliateStatus] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
- plan_options: Optional[product_create_params.PlanOptions] | Omit = omit,
+ member_affiliate_status: str | Omit = omit,
+ metadata: Optional[object] | Omit = omit,
product_tax_code_id: Optional[str] | Omit = omit,
redirect_purchase_url: Optional[str] | Omit = omit,
route: Optional[str] | Omit = omit,
- send_welcome_message: Optional[bool] | Omit = omit,
- visibility: Optional[Visibility] | Omit = omit,
+ visibility: 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.
extra_headers: Headers | None = None,
@@ -86,64 +76,43 @@ def create(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Product:
- """Create a new product for a company.
-
- The product serves as the top-level
- container for plans and experiences.
-
- Required permissions:
-
- - `access_pass:create`
- - `access_pass:basic:read`
+ """
+ Creates a new product for a company.
Args:
- company_id: The unique identifier of the company to create this product for.
-
title: The display name of the product. Maximum 80 characters.
- collect_shipping_address: Whether the checkout flow collects a shipping address from the customer.
+ collect_shipping_address: Whether to collect a shipping address at checkout.
- custom_cta: The different types of custom CTAs that can be selected.
-
- custom_cta_url: A URL that the call-to-action button links to instead of the default checkout
- flow.
+ company_id: The unique identifier of the company to create this product for.
- custom_statement_descriptor: A custom text label that appears on the customer's bank statement. Must be 5-22
- characters, contain at least one letter, and not contain <, >, \\,, ', or "
- characters.
+ custom_cta: The call-to-action button label.
- description: A written description of the product displayed on its product page.
+ custom_cta_url: A URL the call-to-action button links to.
- experience_ids: The unique identifiers of experiences to connect to this product.
+ custom_statement_descriptor: Custom bank statement descriptor. Must start with WHOP\\**.
- global_affiliate_percentage: The commission rate as a percentage that affiliates earn through the global
- affiliate program.
+ description: A written description displayed on the product page.
- global_affiliate_status: The different statuses of the global affiliate program for a product.
+ global_affiliate_percentage: The commission rate affiliates earn.
- headline: A short marketing headline displayed prominently on the product page.
+ global_affiliate_status: The enrollment status in the global affiliate program.
- member_affiliate_percentage: The commission rate as a percentage that members earn through the member
- affiliate program.
+ headline: A short marketing headline for the product page.
- member_affiliate_status: The different statuses of the global affiliate program for a product.
+ member_affiliate_percentage: The commission rate members earn.
- metadata: Custom key-value pairs to store on the product. Included in webhook payloads for
- payment and membership events. Max 50 keys, 500 chars per key, 5000 chars per
- value.
+ member_affiliate_status: The enrollment status in the member affiliate program.
- plan_options: Configuration for an automatically generated plan to attach to this product.
+ metadata: Custom key-value pairs to store on the product.
- product_tax_code_id: The unique identifier of the tax classification code to apply to this product.
+ product_tax_code_id: The unique identifier of the tax classification code.
- redirect_purchase_url: A URL to redirect the customer to after completing a purchase.
+ redirect_purchase_url: A URL to redirect the customer to after purchase.
route: The URL slug for the product's public link.
- send_welcome_message: Whether to send an automated welcome message via support chat when a user joins
- this product. Defaults to true.
-
- visibility: Visibility of a resource
+ visibility: Whether the product is visible to customers.
extra_headers: Send extra headers
@@ -157,25 +126,22 @@ def create(
"/products",
body=maybe_transform(
{
- "company_id": company_id,
"title": title,
"collect_shipping_address": collect_shipping_address,
+ "company_id": company_id,
"custom_cta": custom_cta,
"custom_cta_url": custom_cta_url,
"custom_statement_descriptor": custom_statement_descriptor,
"description": description,
- "experience_ids": experience_ids,
"global_affiliate_percentage": global_affiliate_percentage,
"global_affiliate_status": global_affiliate_status,
"headline": headline,
"member_affiliate_percentage": member_affiliate_percentage,
"member_affiliate_status": member_affiliate_status,
"metadata": metadata,
- "plan_options": plan_options,
"product_tax_code_id": product_tax_code_id,
"redirect_purchase_url": redirect_purchase_url,
"route": route,
- "send_welcome_message": send_welcome_message,
"visibility": visibility,
},
product_create_params.ProductCreateParams,
@@ -197,12 +163,10 @@ def retrieve(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Product:
- """
- Retrieves the details of an existing product.
-
- Required permissions:
+ """Retrieves the details of an existing product.
- - `access_pass:basic:read`
+ This endpoint is publicly
+ accessible.
Args:
extra_headers: Send extra headers
@@ -227,25 +191,12 @@ def update(
self,
id: str,
*,
- collect_shipping_address: Optional[bool] | Omit = omit,
- custom_cta: Optional[CustomCta] | Omit = omit,
- custom_cta_url: Optional[str] | Omit = omit,
- custom_statement_descriptor: Optional[str] | Omit = omit,
description: Optional[str] | Omit = omit,
- gallery_images: Optional[Iterable[product_update_params.GalleryImage]] | Omit = omit,
- global_affiliate_percentage: Optional[float] | Omit = omit,
- global_affiliate_status: Optional[GlobalAffiliateStatus] | Omit = omit,
headline: Optional[str] | Omit = omit,
- member_affiliate_percentage: Optional[float] | Omit = omit,
- member_affiliate_status: Optional[GlobalAffiliateStatus] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
+ metadata: Optional[object] | Omit = omit,
product_tax_code_id: Optional[str] | Omit = omit,
- redirect_purchase_url: Optional[str] | Omit = omit,
- route: Optional[str] | Omit = omit,
- send_welcome_message: Optional[bool] | Omit = omit,
- store_page_config: Optional[product_update_params.StorePageConfig] | Omit = omit,
- title: Optional[str] | Omit = omit,
- visibility: Optional[Visibility] | Omit = omit,
+ title: str | Omit = omit,
+ visibility: 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.
extra_headers: Headers | None = None,
@@ -254,59 +205,20 @@ def update(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Product:
"""
- Update a product's title, description, visibility, and other settings.
-
- Required permissions:
-
- - `access_pass:update`
- - `access_pass:basic:read`
+ Updates an existing product.
Args:
- collect_shipping_address: Whether the checkout flow collects a shipping address from the customer.
-
- custom_cta: The different types of custom CTAs that can be selected.
-
- custom_cta_url: A URL that the call-to-action button links to instead of the default checkout
- flow.
-
- custom_statement_descriptor: A custom text label that appears on the customer's bank statement. Must be 5-22
- characters, contain at least one letter, and not contain <, >, \\,, ', or "
- characters.
-
- description: A written description of the product displayed on its product page.
+ description: A written description displayed on the product page.
- gallery_images: The gallery images for the product.
+ headline: A short marketing headline for the product page.
- global_affiliate_percentage: The commission rate as a percentage that affiliates earn through the global
- affiliate program.
+ metadata: Custom key-value pairs to store on the product.
- global_affiliate_status: The different statuses of the global affiliate program for a product.
+ product_tax_code_id: The unique identifier of the tax classification code.
- headline: A short marketing headline displayed prominently on the product page.
+ title: The display name of the product.
- member_affiliate_percentage: The commission rate as a percentage that members earn through the member
- affiliate program.
-
- member_affiliate_status: The different statuses of the global affiliate program for a product.
-
- metadata: Custom key-value pairs to store on the product. Included in webhook payloads for
- payment and membership events. Max 50 keys, 500 chars per key, 5000 chars per
- value.
-
- product_tax_code_id: The unique identifier of the tax classification code to apply to this product.
-
- redirect_purchase_url: A URL to redirect the customer to after completing a purchase.
-
- route: The URL slug for the product's public link.
-
- send_welcome_message: Whether to send an automated welcome message via support chat when a user joins
- this product.
-
- store_page_config: Layout and display configuration for this product on the company's store page.
-
- title: The display name of the product. Maximum 80 characters.
-
- visibility: Visibility of a resource
+ visibility: Whether the product is visible to customers.
extra_headers: Send extra headers
@@ -322,23 +234,10 @@ def update(
path_template("/products/{id}", id=id),
body=maybe_transform(
{
- "collect_shipping_address": collect_shipping_address,
- "custom_cta": custom_cta,
- "custom_cta_url": custom_cta_url,
- "custom_statement_descriptor": custom_statement_descriptor,
"description": description,
- "gallery_images": gallery_images,
- "global_affiliate_percentage": global_affiliate_percentage,
- "global_affiliate_status": global_affiliate_status,
"headline": headline,
- "member_affiliate_percentage": member_affiliate_percentage,
- "member_affiliate_status": member_affiliate_status,
"metadata": metadata,
"product_tax_code_id": product_tax_code_id,
- "redirect_purchase_url": redirect_purchase_url,
- "route": route,
- "send_welcome_message": send_welcome_message,
- "store_page_config": store_page_config,
"title": title,
"visibility": visibility,
},
@@ -354,16 +253,14 @@ def list(
self,
*,
company_id: str,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- created_after: Union[str, datetime, None] | Omit = omit,
- created_before: Union[str, datetime, None] | Omit = omit,
- direction: Optional[Direction] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[int] | Omit = omit,
- order: Optional[Literal["active_memberships_count", "created_at", "usd_gmv", "usd_gmv_30_days"]] | Omit = omit,
- product_types: Optional[List[AccessPassType]] | Omit = omit,
- visibilities: Optional[List[VisibilityFilter]] | Omit = omit,
+ access_pass_types: SequenceNotStr[str] | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: str | Omit = omit,
+ visibilities: SequenceNotStr[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.
extra_headers: Headers | None = None,
@@ -372,33 +269,24 @@ def list(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[ProductListItem]:
"""
- Returns a paginated list of products belonging to a company, with optional
- filtering by type, visibility, and creation date.
-
- Required permissions:
-
- - `access_pass:basic:read`
+ Returns a paginated list of products belonging to a company.
Args:
company_id: The unique identifier of the company to list products 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.
+ access_pass_types: Filter to only products matching these types.
- created_after: Only return products created after this timestamp.
+ after: A cursor; returns products after this position.
- created_before: Only return products created before this timestamp.
+ before: A cursor; returns products before this position.
- direction: The direction of the sort.
+ direction: The sort direction for results. Defaults to descending.
- first: Returns the first _n_ elements from the list.
+ first: The number of products to return (default and max 100).
- last: Returns the last _n_ elements from the list.
+ last: The number of products to return from the end of the range.
- order: The ways a relation of AccessPasses can be ordered
-
- product_types: Filter to only products matching these type classifications.
+ order: The field to sort results by. Defaults to created_at.
visibilities: Filter to only products matching these visibility states.
@@ -421,15 +309,13 @@ def list(
query=maybe_transform(
{
"company_id": company_id,
+ "access_pass_types": access_pass_types,
"after": after,
"before": before,
- "created_after": created_after,
- "created_before": created_before,
"direction": direction,
"first": first,
"last": last,
"order": order,
- "product_types": product_types,
"visibilities": visibilities,
},
product_list_params.ProductListParams,
@@ -449,12 +335,10 @@ def delete(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> ProductDeleteResponse:
- """
- Permanently delete a product and remove it from the company's catalog.
-
- Required permissions:
+ """Deletes a product.
- - `access_pass:delete`
+ Only products with no memberships, entries, reviews, or
+ invoices can be deleted.
Args:
extra_headers: Send extra headers
@@ -501,26 +385,23 @@ def with_streaming_response(self) -> AsyncProductsResourceWithStreamingResponse:
async def create(
self,
*,
- company_id: str,
title: str,
collect_shipping_address: Optional[bool] | Omit = omit,
- custom_cta: Optional[CustomCta] | Omit = omit,
+ company_id: str | Omit = omit,
+ custom_cta: Optional[str] | Omit = omit,
custom_cta_url: Optional[str] | Omit = omit,
custom_statement_descriptor: Optional[str] | Omit = omit,
description: Optional[str] | Omit = omit,
- experience_ids: Optional[SequenceNotStr[str]] | Omit = omit,
global_affiliate_percentage: Optional[float] | Omit = omit,
- global_affiliate_status: Optional[GlobalAffiliateStatus] | Omit = omit,
+ global_affiliate_status: str | Omit = omit,
headline: Optional[str] | Omit = omit,
member_affiliate_percentage: Optional[float] | Omit = omit,
- member_affiliate_status: Optional[GlobalAffiliateStatus] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
- plan_options: Optional[product_create_params.PlanOptions] | Omit = omit,
+ member_affiliate_status: str | Omit = omit,
+ metadata: Optional[object] | Omit = omit,
product_tax_code_id: Optional[str] | Omit = omit,
redirect_purchase_url: Optional[str] | Omit = omit,
route: Optional[str] | Omit = omit,
- send_welcome_message: Optional[bool] | Omit = omit,
- visibility: Optional[Visibility] | Omit = omit,
+ visibility: 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.
extra_headers: Headers | None = None,
@@ -528,64 +409,43 @@ async def create(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Product:
- """Create a new product for a company.
-
- The product serves as the top-level
- container for plans and experiences.
-
- Required permissions:
-
- - `access_pass:create`
- - `access_pass:basic:read`
+ """
+ Creates a new product for a company.
Args:
- company_id: The unique identifier of the company to create this product for.
-
title: The display name of the product. Maximum 80 characters.
- collect_shipping_address: Whether the checkout flow collects a shipping address from the customer.
+ collect_shipping_address: Whether to collect a shipping address at checkout.
- custom_cta: The different types of custom CTAs that can be selected.
-
- custom_cta_url: A URL that the call-to-action button links to instead of the default checkout
- flow.
+ company_id: The unique identifier of the company to create this product for.
- custom_statement_descriptor: A custom text label that appears on the customer's bank statement. Must be 5-22
- characters, contain at least one letter, and not contain <, >, \\,, ', or "
- characters.
+ custom_cta: The call-to-action button label.
- description: A written description of the product displayed on its product page.
+ custom_cta_url: A URL the call-to-action button links to.
- experience_ids: The unique identifiers of experiences to connect to this product.
+ custom_statement_descriptor: Custom bank statement descriptor. Must start with WHOP\\**.
- global_affiliate_percentage: The commission rate as a percentage that affiliates earn through the global
- affiliate program.
+ description: A written description displayed on the product page.
- global_affiliate_status: The different statuses of the global affiliate program for a product.
+ global_affiliate_percentage: The commission rate affiliates earn.
- headline: A short marketing headline displayed prominently on the product page.
+ global_affiliate_status: The enrollment status in the global affiliate program.
- member_affiliate_percentage: The commission rate as a percentage that members earn through the member
- affiliate program.
+ headline: A short marketing headline for the product page.
- member_affiliate_status: The different statuses of the global affiliate program for a product.
+ member_affiliate_percentage: The commission rate members earn.
- metadata: Custom key-value pairs to store on the product. Included in webhook payloads for
- payment and membership events. Max 50 keys, 500 chars per key, 5000 chars per
- value.
+ member_affiliate_status: The enrollment status in the member affiliate program.
- plan_options: Configuration for an automatically generated plan to attach to this product.
+ metadata: Custom key-value pairs to store on the product.
- product_tax_code_id: The unique identifier of the tax classification code to apply to this product.
+ product_tax_code_id: The unique identifier of the tax classification code.
- redirect_purchase_url: A URL to redirect the customer to after completing a purchase.
+ redirect_purchase_url: A URL to redirect the customer to after purchase.
route: The URL slug for the product's public link.
- send_welcome_message: Whether to send an automated welcome message via support chat when a user joins
- this product. Defaults to true.
-
- visibility: Visibility of a resource
+ visibility: Whether the product is visible to customers.
extra_headers: Send extra headers
@@ -599,25 +459,22 @@ async def create(
"/products",
body=await async_maybe_transform(
{
- "company_id": company_id,
"title": title,
"collect_shipping_address": collect_shipping_address,
+ "company_id": company_id,
"custom_cta": custom_cta,
"custom_cta_url": custom_cta_url,
"custom_statement_descriptor": custom_statement_descriptor,
"description": description,
- "experience_ids": experience_ids,
"global_affiliate_percentage": global_affiliate_percentage,
"global_affiliate_status": global_affiliate_status,
"headline": headline,
"member_affiliate_percentage": member_affiliate_percentage,
"member_affiliate_status": member_affiliate_status,
"metadata": metadata,
- "plan_options": plan_options,
"product_tax_code_id": product_tax_code_id,
"redirect_purchase_url": redirect_purchase_url,
"route": route,
- "send_welcome_message": send_welcome_message,
"visibility": visibility,
},
product_create_params.ProductCreateParams,
@@ -639,12 +496,10 @@ async def retrieve(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Product:
- """
- Retrieves the details of an existing product.
-
- Required permissions:
+ """Retrieves the details of an existing product.
- - `access_pass:basic:read`
+ This endpoint is publicly
+ accessible.
Args:
extra_headers: Send extra headers
@@ -669,25 +524,12 @@ async def update(
self,
id: str,
*,
- collect_shipping_address: Optional[bool] | Omit = omit,
- custom_cta: Optional[CustomCta] | Omit = omit,
- custom_cta_url: Optional[str] | Omit = omit,
- custom_statement_descriptor: Optional[str] | Omit = omit,
description: Optional[str] | Omit = omit,
- gallery_images: Optional[Iterable[product_update_params.GalleryImage]] | Omit = omit,
- global_affiliate_percentage: Optional[float] | Omit = omit,
- global_affiliate_status: Optional[GlobalAffiliateStatus] | Omit = omit,
headline: Optional[str] | Omit = omit,
- member_affiliate_percentage: Optional[float] | Omit = omit,
- member_affiliate_status: Optional[GlobalAffiliateStatus] | Omit = omit,
- metadata: Optional[Dict[str, object]] | Omit = omit,
+ metadata: Optional[object] | Omit = omit,
product_tax_code_id: Optional[str] | Omit = omit,
- redirect_purchase_url: Optional[str] | Omit = omit,
- route: Optional[str] | Omit = omit,
- send_welcome_message: Optional[bool] | Omit = omit,
- store_page_config: Optional[product_update_params.StorePageConfig] | Omit = omit,
- title: Optional[str] | Omit = omit,
- visibility: Optional[Visibility] | Omit = omit,
+ title: str | Omit = omit,
+ visibility: 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.
extra_headers: Headers | None = None,
@@ -696,59 +538,20 @@ async def update(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Product:
"""
- Update a product's title, description, visibility, and other settings.
-
- Required permissions:
-
- - `access_pass:update`
- - `access_pass:basic:read`
+ Updates an existing product.
Args:
- collect_shipping_address: Whether the checkout flow collects a shipping address from the customer.
-
- custom_cta: The different types of custom CTAs that can be selected.
-
- custom_cta_url: A URL that the call-to-action button links to instead of the default checkout
- flow.
-
- custom_statement_descriptor: A custom text label that appears on the customer's bank statement. Must be 5-22
- characters, contain at least one letter, and not contain <, >, \\,, ', or "
- characters.
-
- description: A written description of the product displayed on its product page.
+ description: A written description displayed on the product page.
- gallery_images: The gallery images for the product.
+ headline: A short marketing headline for the product page.
- global_affiliate_percentage: The commission rate as a percentage that affiliates earn through the global
- affiliate program.
+ metadata: Custom key-value pairs to store on the product.
- global_affiliate_status: The different statuses of the global affiliate program for a product.
+ product_tax_code_id: The unique identifier of the tax classification code.
- headline: A short marketing headline displayed prominently on the product page.
+ title: The display name of the product.
- member_affiliate_percentage: The commission rate as a percentage that members earn through the member
- affiliate program.
-
- member_affiliate_status: The different statuses of the global affiliate program for a product.
-
- metadata: Custom key-value pairs to store on the product. Included in webhook payloads for
- payment and membership events. Max 50 keys, 500 chars per key, 5000 chars per
- value.
-
- product_tax_code_id: The unique identifier of the tax classification code to apply to this product.
-
- redirect_purchase_url: A URL to redirect the customer to after completing a purchase.
-
- route: The URL slug for the product's public link.
-
- send_welcome_message: Whether to send an automated welcome message via support chat when a user joins
- this product.
-
- store_page_config: Layout and display configuration for this product on the company's store page.
-
- title: The display name of the product. Maximum 80 characters.
-
- visibility: Visibility of a resource
+ visibility: Whether the product is visible to customers.
extra_headers: Send extra headers
@@ -764,23 +567,10 @@ async def update(
path_template("/products/{id}", id=id),
body=await async_maybe_transform(
{
- "collect_shipping_address": collect_shipping_address,
- "custom_cta": custom_cta,
- "custom_cta_url": custom_cta_url,
- "custom_statement_descriptor": custom_statement_descriptor,
"description": description,
- "gallery_images": gallery_images,
- "global_affiliate_percentage": global_affiliate_percentage,
- "global_affiliate_status": global_affiliate_status,
"headline": headline,
- "member_affiliate_percentage": member_affiliate_percentage,
- "member_affiliate_status": member_affiliate_status,
"metadata": metadata,
"product_tax_code_id": product_tax_code_id,
- "redirect_purchase_url": redirect_purchase_url,
- "route": route,
- "send_welcome_message": send_welcome_message,
- "store_page_config": store_page_config,
"title": title,
"visibility": visibility,
},
@@ -796,16 +586,14 @@ def list(
self,
*,
company_id: str,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- created_after: Union[str, datetime, None] | Omit = omit,
- created_before: Union[str, datetime, None] | Omit = omit,
- direction: Optional[Direction] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[int] | Omit = omit,
- order: Optional[Literal["active_memberships_count", "created_at", "usd_gmv", "usd_gmv_30_days"]] | Omit = omit,
- product_types: Optional[List[AccessPassType]] | Omit = omit,
- visibilities: Optional[List[VisibilityFilter]] | Omit = omit,
+ access_pass_types: SequenceNotStr[str] | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: str | Omit = omit,
+ visibilities: SequenceNotStr[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.
extra_headers: Headers | None = None,
@@ -814,33 +602,24 @@ def list(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[ProductListItem, AsyncCursorPage[ProductListItem]]:
"""
- Returns a paginated list of products belonging to a company, with optional
- filtering by type, visibility, and creation date.
-
- Required permissions:
-
- - `access_pass:basic:read`
+ Returns a paginated list of products belonging to a company.
Args:
company_id: The unique identifier of the company to list products 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.
+ access_pass_types: Filter to only products matching these types.
- created_after: Only return products created after this timestamp.
+ after: A cursor; returns products after this position.
- created_before: Only return products created before this timestamp.
+ before: A cursor; returns products before this position.
- direction: The direction of the sort.
+ direction: The sort direction for results. Defaults to descending.
- first: Returns the first _n_ elements from the list.
+ first: The number of products to return (default and max 100).
- last: Returns the last _n_ elements from the list.
+ last: The number of products to return from the end of the range.
- order: The ways a relation of AccessPasses can be ordered
-
- product_types: Filter to only products matching these type classifications.
+ order: The field to sort results by. Defaults to created_at.
visibilities: Filter to only products matching these visibility states.
@@ -863,15 +642,13 @@ def list(
query=maybe_transform(
{
"company_id": company_id,
+ "access_pass_types": access_pass_types,
"after": after,
"before": before,
- "created_after": created_after,
- "created_before": created_before,
"direction": direction,
"first": first,
"last": last,
"order": order,
- "product_types": product_types,
"visibilities": visibilities,
},
product_list_params.ProductListParams,
@@ -891,12 +668,10 @@ async def delete(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> ProductDeleteResponse:
- """
- Permanently delete a product and remove it from the company's catalog.
-
- Required permissions:
+ """Deletes a product.
- - `access_pass:delete`
+ Only products with no memberships, entries, reviews, or
+ invoices can be deleted.
Args:
extra_headers: Send extra headers
diff --git a/src/whop_sdk/resources/referrals/__init__.py b/src/whop_sdk/resources/referrals/__init__.py
new file mode 100644
index 00000000..9d40a31a
--- /dev/null
+++ b/src/whop_sdk/resources/referrals/__init__.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .referrals import (
+ ReferralsResource,
+ AsyncReferralsResource,
+ ReferralsResourceWithRawResponse,
+ AsyncReferralsResourceWithRawResponse,
+ ReferralsResourceWithStreamingResponse,
+ AsyncReferralsResourceWithStreamingResponse,
+)
+from .businesses import (
+ BusinessesResource,
+ AsyncBusinessesResource,
+ BusinessesResourceWithRawResponse,
+ AsyncBusinessesResourceWithRawResponse,
+ BusinessesResourceWithStreamingResponse,
+ AsyncBusinessesResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "BusinessesResource",
+ "AsyncBusinessesResource",
+ "BusinessesResourceWithRawResponse",
+ "AsyncBusinessesResourceWithRawResponse",
+ "BusinessesResourceWithStreamingResponse",
+ "AsyncBusinessesResourceWithStreamingResponse",
+ "ReferralsResource",
+ "AsyncReferralsResource",
+ "ReferralsResourceWithRawResponse",
+ "AsyncReferralsResourceWithRawResponse",
+ "ReferralsResourceWithStreamingResponse",
+ "AsyncReferralsResourceWithStreamingResponse",
+]
diff --git a/src/whop_sdk/resources/referrals/businesses/__init__.py b/src/whop_sdk/resources/referrals/businesses/__init__.py
new file mode 100644
index 00000000..bd5fa65b
--- /dev/null
+++ b/src/whop_sdk/resources/referrals/businesses/__init__.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .earnings import (
+ EarningsResource,
+ AsyncEarningsResource,
+ EarningsResourceWithRawResponse,
+ AsyncEarningsResourceWithRawResponse,
+ EarningsResourceWithStreamingResponse,
+ AsyncEarningsResourceWithStreamingResponse,
+)
+from .businesses import (
+ BusinessesResource,
+ AsyncBusinessesResource,
+ BusinessesResourceWithRawResponse,
+ AsyncBusinessesResourceWithRawResponse,
+ BusinessesResourceWithStreamingResponse,
+ AsyncBusinessesResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "EarningsResource",
+ "AsyncEarningsResource",
+ "EarningsResourceWithRawResponse",
+ "AsyncEarningsResourceWithRawResponse",
+ "EarningsResourceWithStreamingResponse",
+ "AsyncEarningsResourceWithStreamingResponse",
+ "BusinessesResource",
+ "AsyncBusinessesResource",
+ "BusinessesResourceWithRawResponse",
+ "AsyncBusinessesResourceWithRawResponse",
+ "BusinessesResourceWithStreamingResponse",
+ "AsyncBusinessesResourceWithStreamingResponse",
+]
diff --git a/src/whop_sdk/resources/referrals/businesses/businesses.py b/src/whop_sdk/resources/referrals/businesses/businesses.py
new file mode 100644
index 00000000..daadc73a
--- /dev/null
+++ b/src/whop_sdk/resources/referrals/businesses/businesses.py
@@ -0,0 +1,508 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal
+
+import httpx
+
+from .earnings import (
+ EarningsResource,
+ AsyncEarningsResource,
+ EarningsResourceWithRawResponse,
+ AsyncEarningsResourceWithRawResponse,
+ EarningsResourceWithStreamingResponse,
+ AsyncEarningsResourceWithStreamingResponse,
+)
+from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ...._utils import path_template, 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.referrals import business_list_params, business_list_earnings_params
+from ....types.referrals.business_list_response import BusinessListResponse
+from ....types.referrals.business_retrieve_response import BusinessRetrieveResponse
+from ....types.referrals.business_list_earnings_response import BusinessListEarningsResponse
+
+__all__ = ["BusinessesResource", "AsyncBusinessesResource"]
+
+
+class BusinessesResource(SyncAPIResource):
+ @cached_property
+ def earnings(self) -> EarningsResource:
+ return EarningsResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> BusinessesResourceWithRawResponse:
+ """
+ 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 BusinessesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> BusinessesResourceWithStreamingResponse:
+ """
+ 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 BusinessesResourceWithStreamingResponse(self)
+
+ 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,
+ ) -> BusinessRetrieveResponse:
+ """
+ Retrieves a single referred business and its referral terms.
+
+ 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(
+ path_template("/referrals/businesses/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=BusinessRetrieveResponse,
+ )
+
+ def list(
+ self,
+ *,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ has_earnings: bool | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal[
+ "created_at",
+ "referral_started_at",
+ "referral_expires_at",
+ "payout_percentage",
+ "volume_usd",
+ "earnings_usd",
+ ]
+ | Omit = omit,
+ status: Literal["active", "removed"] | 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[BusinessListResponse]:
+ """
+ Lists the businesses the authenticated user referred onto Whop, most recent
+ first.
+
+ Args:
+ after: Cursor to fetch the page after (from page_info.end_cursor).
+
+ before: Cursor to fetch the page before (from page_info.start_cursor).
+
+ direction: Sort direction.
+
+ first: Number of business referrals to return from the start of the window.
+
+ has_earnings: When true, only businesses with at least one non-canceled, non-reversed earning
+ paid to the caller.
+
+ last: Number of business referrals to return from the end of the window.
+
+ order: The field to sort business referrals by.
+
+ status: Filter by referral status.
+
+ 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(
+ "/referrals/businesses",
+ page=SyncCursorPage[BusinessListResponse],
+ 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,
+ "direction": direction,
+ "first": first,
+ "has_earnings": has_earnings,
+ "last": last,
+ "order": order,
+ "status": status,
+ },
+ business_list_params.BusinessListParams,
+ ),
+ ),
+ model=BusinessListResponse,
+ )
+
+ def list_earnings(
+ self,
+ *,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal["created_at", "commission_amount", "transaction_amount", "payout_at"] | Omit = omit,
+ status: Literal["awaiting_settlement", "pending", "completed", "canceled", "reversed"] | 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[BusinessListEarningsResponse]:
+ """
+ Lists every business referral earning the authenticated user has, most recent
+ first.
+
+ Args:
+ direction: Sort direction.
+
+ order: The field to sort earnings by.
+
+ status: Filter by earning status.
+
+ 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(
+ "/referrals/businesses/earnings",
+ page=SyncCursorPage[BusinessListEarningsResponse],
+ 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,
+ "direction": direction,
+ "first": first,
+ "last": last,
+ "order": order,
+ "status": status,
+ },
+ business_list_earnings_params.BusinessListEarningsParams,
+ ),
+ ),
+ model=BusinessListEarningsResponse,
+ )
+
+
+class AsyncBusinessesResource(AsyncAPIResource):
+ @cached_property
+ def earnings(self) -> AsyncEarningsResource:
+ return AsyncEarningsResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AsyncBusinessesResourceWithRawResponse:
+ """
+ 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 AsyncBusinessesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncBusinessesResourceWithStreamingResponse:
+ """
+ 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 AsyncBusinessesResourceWithStreamingResponse(self)
+
+ 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,
+ ) -> BusinessRetrieveResponse:
+ """
+ Retrieves a single referred business and its referral terms.
+
+ 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(
+ path_template("/referrals/businesses/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=BusinessRetrieveResponse,
+ )
+
+ def list(
+ self,
+ *,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ has_earnings: bool | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal[
+ "created_at",
+ "referral_started_at",
+ "referral_expires_at",
+ "payout_percentage",
+ "volume_usd",
+ "earnings_usd",
+ ]
+ | Omit = omit,
+ status: Literal["active", "removed"] | 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[BusinessListResponse, AsyncCursorPage[BusinessListResponse]]:
+ """
+ Lists the businesses the authenticated user referred onto Whop, most recent
+ first.
+
+ Args:
+ after: Cursor to fetch the page after (from page_info.end_cursor).
+
+ before: Cursor to fetch the page before (from page_info.start_cursor).
+
+ direction: Sort direction.
+
+ first: Number of business referrals to return from the start of the window.
+
+ has_earnings: When true, only businesses with at least one non-canceled, non-reversed earning
+ paid to the caller.
+
+ last: Number of business referrals to return from the end of the window.
+
+ order: The field to sort business referrals by.
+
+ status: Filter by referral status.
+
+ 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(
+ "/referrals/businesses",
+ page=AsyncCursorPage[BusinessListResponse],
+ 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,
+ "direction": direction,
+ "first": first,
+ "has_earnings": has_earnings,
+ "last": last,
+ "order": order,
+ "status": status,
+ },
+ business_list_params.BusinessListParams,
+ ),
+ ),
+ model=BusinessListResponse,
+ )
+
+ def list_earnings(
+ self,
+ *,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal["created_at", "commission_amount", "transaction_amount", "payout_at"] | Omit = omit,
+ status: Literal["awaiting_settlement", "pending", "completed", "canceled", "reversed"] | 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[BusinessListEarningsResponse, AsyncCursorPage[BusinessListEarningsResponse]]:
+ """
+ Lists every business referral earning the authenticated user has, most recent
+ first.
+
+ Args:
+ direction: Sort direction.
+
+ order: The field to sort earnings by.
+
+ status: Filter by earning status.
+
+ 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(
+ "/referrals/businesses/earnings",
+ page=AsyncCursorPage[BusinessListEarningsResponse],
+ 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,
+ "direction": direction,
+ "first": first,
+ "last": last,
+ "order": order,
+ "status": status,
+ },
+ business_list_earnings_params.BusinessListEarningsParams,
+ ),
+ ),
+ model=BusinessListEarningsResponse,
+ )
+
+
+class BusinessesResourceWithRawResponse:
+ def __init__(self, businesses: BusinessesResource) -> None:
+ self._businesses = businesses
+
+ self.retrieve = to_raw_response_wrapper(
+ businesses.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ businesses.list,
+ )
+ self.list_earnings = to_raw_response_wrapper(
+ businesses.list_earnings,
+ )
+
+ @cached_property
+ def earnings(self) -> EarningsResourceWithRawResponse:
+ return EarningsResourceWithRawResponse(self._businesses.earnings)
+
+
+class AsyncBusinessesResourceWithRawResponse:
+ def __init__(self, businesses: AsyncBusinessesResource) -> None:
+ self._businesses = businesses
+
+ self.retrieve = async_to_raw_response_wrapper(
+ businesses.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ businesses.list,
+ )
+ self.list_earnings = async_to_raw_response_wrapper(
+ businesses.list_earnings,
+ )
+
+ @cached_property
+ def earnings(self) -> AsyncEarningsResourceWithRawResponse:
+ return AsyncEarningsResourceWithRawResponse(self._businesses.earnings)
+
+
+class BusinessesResourceWithStreamingResponse:
+ def __init__(self, businesses: BusinessesResource) -> None:
+ self._businesses = businesses
+
+ self.retrieve = to_streamed_response_wrapper(
+ businesses.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ businesses.list,
+ )
+ self.list_earnings = to_streamed_response_wrapper(
+ businesses.list_earnings,
+ )
+
+ @cached_property
+ def earnings(self) -> EarningsResourceWithStreamingResponse:
+ return EarningsResourceWithStreamingResponse(self._businesses.earnings)
+
+
+class AsyncBusinessesResourceWithStreamingResponse:
+ def __init__(self, businesses: AsyncBusinessesResource) -> None:
+ self._businesses = businesses
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ businesses.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ businesses.list,
+ )
+ self.list_earnings = async_to_streamed_response_wrapper(
+ businesses.list_earnings,
+ )
+
+ @cached_property
+ def earnings(self) -> AsyncEarningsResourceWithStreamingResponse:
+ return AsyncEarningsResourceWithStreamingResponse(self._businesses.earnings)
diff --git a/src/whop_sdk/resources/referrals/businesses/earnings.py b/src/whop_sdk/resources/referrals/businesses/earnings.py
new file mode 100644
index 00000000..a0df618c
--- /dev/null
+++ b/src/whop_sdk/resources/referrals/businesses/earnings.py
@@ -0,0 +1,228 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal
+
+import httpx
+
+from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ...._utils import path_template, 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.referrals.businesses import earning_list_params
+from ....types.referrals.businesses.earning_list_response import EarningListResponse
+
+__all__ = ["EarningsResource", "AsyncEarningsResource"]
+
+
+class EarningsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> EarningsResourceWithRawResponse:
+ """
+ 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 EarningsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> EarningsResourceWithStreamingResponse:
+ """
+ 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 EarningsResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ id: str,
+ *,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal["created_at", "commission_amount", "transaction_amount", "payout_at"] | Omit = omit,
+ status: Literal["awaiting_settlement", "pending", "completed", "canceled", "reversed"] | 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[EarningListResponse]:
+ """
+ Lists the earnings Whop pays out for one referred business's activity, most
+ recent first.
+
+ Args:
+ direction: Sort direction.
+
+ order: The field to sort earnings by.
+
+ status: Filter by earning status.
+
+ 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(
+ path_template("/referrals/businesses/{id}/earnings", id=id),
+ page=SyncCursorPage[EarningListResponse],
+ 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,
+ "direction": direction,
+ "first": first,
+ "last": last,
+ "order": order,
+ "status": status,
+ },
+ earning_list_params.EarningListParams,
+ ),
+ ),
+ model=EarningListResponse,
+ )
+
+
+class AsyncEarningsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncEarningsResourceWithRawResponse:
+ """
+ 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 AsyncEarningsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncEarningsResourceWithStreamingResponse:
+ """
+ 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 AsyncEarningsResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ id: str,
+ *,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal["created_at", "commission_amount", "transaction_amount", "payout_at"] | Omit = omit,
+ status: Literal["awaiting_settlement", "pending", "completed", "canceled", "reversed"] | 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[EarningListResponse, AsyncCursorPage[EarningListResponse]]:
+ """
+ Lists the earnings Whop pays out for one referred business's activity, most
+ recent first.
+
+ Args:
+ direction: Sort direction.
+
+ order: The field to sort earnings by.
+
+ status: Filter by earning status.
+
+ 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(
+ path_template("/referrals/businesses/{id}/earnings", id=id),
+ page=AsyncCursorPage[EarningListResponse],
+ 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,
+ "direction": direction,
+ "first": first,
+ "last": last,
+ "order": order,
+ "status": status,
+ },
+ earning_list_params.EarningListParams,
+ ),
+ ),
+ model=EarningListResponse,
+ )
+
+
+class EarningsResourceWithRawResponse:
+ def __init__(self, earnings: EarningsResource) -> None:
+ self._earnings = earnings
+
+ self.list = to_raw_response_wrapper(
+ earnings.list,
+ )
+
+
+class AsyncEarningsResourceWithRawResponse:
+ def __init__(self, earnings: AsyncEarningsResource) -> None:
+ self._earnings = earnings
+
+ self.list = async_to_raw_response_wrapper(
+ earnings.list,
+ )
+
+
+class EarningsResourceWithStreamingResponse:
+ def __init__(self, earnings: EarningsResource) -> None:
+ self._earnings = earnings
+
+ self.list = to_streamed_response_wrapper(
+ earnings.list,
+ )
+
+
+class AsyncEarningsResourceWithStreamingResponse:
+ def __init__(self, earnings: AsyncEarningsResource) -> None:
+ self._earnings = earnings
+
+ self.list = async_to_streamed_response_wrapper(
+ earnings.list,
+ )
diff --git a/src/whop_sdk/resources/referrals/referrals.py b/src/whop_sdk/resources/referrals/referrals.py
new file mode 100644
index 00000000..949735f3
--- /dev/null
+++ b/src/whop_sdk/resources/referrals/referrals.py
@@ -0,0 +1,102 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from .businesses.businesses import (
+ BusinessesResource,
+ AsyncBusinessesResource,
+ BusinessesResourceWithRawResponse,
+ AsyncBusinessesResourceWithRawResponse,
+ BusinessesResourceWithStreamingResponse,
+ AsyncBusinessesResourceWithStreamingResponse,
+)
+
+__all__ = ["ReferralsResource", "AsyncReferralsResource"]
+
+
+class ReferralsResource(SyncAPIResource):
+ @cached_property
+ def businesses(self) -> BusinessesResource:
+ return BusinessesResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> ReferralsResourceWithRawResponse:
+ """
+ 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 ReferralsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> ReferralsResourceWithStreamingResponse:
+ """
+ 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 ReferralsResourceWithStreamingResponse(self)
+
+
+class AsyncReferralsResource(AsyncAPIResource):
+ @cached_property
+ def businesses(self) -> AsyncBusinessesResource:
+ return AsyncBusinessesResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AsyncReferralsResourceWithRawResponse:
+ """
+ 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 AsyncReferralsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncReferralsResourceWithStreamingResponse:
+ """
+ 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 AsyncReferralsResourceWithStreamingResponse(self)
+
+
+class ReferralsResourceWithRawResponse:
+ def __init__(self, referrals: ReferralsResource) -> None:
+ self._referrals = referrals
+
+ @cached_property
+ def businesses(self) -> BusinessesResourceWithRawResponse:
+ return BusinessesResourceWithRawResponse(self._referrals.businesses)
+
+
+class AsyncReferralsResourceWithRawResponse:
+ def __init__(self, referrals: AsyncReferralsResource) -> None:
+ self._referrals = referrals
+
+ @cached_property
+ def businesses(self) -> AsyncBusinessesResourceWithRawResponse:
+ return AsyncBusinessesResourceWithRawResponse(self._referrals.businesses)
+
+
+class ReferralsResourceWithStreamingResponse:
+ def __init__(self, referrals: ReferralsResource) -> None:
+ self._referrals = referrals
+
+ @cached_property
+ def businesses(self) -> BusinessesResourceWithStreamingResponse:
+ return BusinessesResourceWithStreamingResponse(self._referrals.businesses)
+
+
+class AsyncReferralsResourceWithStreamingResponse:
+ def __init__(self, referrals: AsyncReferralsResource) -> None:
+ self._referrals = referrals
+
+ @cached_property
+ def businesses(self) -> AsyncBusinessesResourceWithStreamingResponse:
+ return AsyncBusinessesResourceWithStreamingResponse(self._referrals.businesses)
diff --git a/src/whop_sdk/resources/social_accounts.py b/src/whop_sdk/resources/social_accounts.py
new file mode 100644
index 00000000..d3d2da41
--- /dev/null
+++ b/src/whop_sdk/resources/social_accounts.py
@@ -0,0 +1,665 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List
+from typing_extensions import Literal
+
+import httpx
+
+from ..types import (
+ social_account_list_params,
+ social_account_posts_params,
+ social_account_create_params,
+ social_account_delete_params,
+)
+from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from .._utils import path_template, 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.social_account import SocialAccount
+from ..types.social_account_posts_response import SocialAccountPostsResponse
+from ..types.social_account_create_response import SocialAccountCreateResponse
+from ..types.social_account_delete_response import SocialAccountDeleteResponse
+
+__all__ = ["SocialAccountsResource", "AsyncSocialAccountsResource"]
+
+
+class SocialAccountsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> SocialAccountsResourceWithRawResponse:
+ """
+ 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 SocialAccountsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> SocialAccountsResourceWithStreamingResponse:
+ """
+ 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 SocialAccountsResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ platform: Literal["meta_business"],
+ redirect_url: str,
+ account_id: str | Omit = omit,
+ scopes: List[Literal["advertise"]] | 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,
+ ) -> SocialAccountCreateResponse:
+ """
+ Starts an OAuth connection flow for a social account and returns an
+ authorize*url to redirect the user to. Today the only supported platform is
+ meta_business, which grants the advertise scope so the connected Facebook page
+ and Instagram account can run ads. The required permission follows the requested
+ capability: the advertise scope requires ad_campaign:create (so advertiser roles
+ can connect), other scopes require social_account:create. The connection is
+ authorized against the account given by account_id (a biz* identifier); an
+ account-scoped API key may omit it to default to its own account.
+
+ Args:
+ platform: The platform to connect the social account on.
+
+ redirect_url: The Whop URL to redirect the user to after they finish connecting.
+
+ account_id: The Account (biz\\__ identifier) to connect the social account for. An
+ account-scoped API key may omit this to default to its own account.
+
+ scopes: Capabilities to grant for the connected social account, for example `advertise`.
+
+ 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(
+ "/social_accounts",
+ body=maybe_transform(
+ {
+ "platform": platform,
+ "redirect_url": redirect_url,
+ "account_id": account_id,
+ "scopes": scopes,
+ },
+ social_account_create_params.SocialAccountCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SocialAccountCreateResponse,
+ )
+
+ def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal["display_order", "created_at"] | Omit = omit,
+ platform: Literal["x", "instagram", "youtube", "tiktok", "facebook"] | Omit = omit,
+ scopes: List[Literal["advertise"]] | Omit = omit,
+ user_id: str | Omit = omit,
+ verified: bool | 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[SocialAccount]:
+ """Lists the social accounts linked to an account or user.
+
+ The owner is passed as
+ exactly one of account*id (a biz* identifier) or user*id (a user* identifier);
+ an account-scoped API key defaults to its own account when neither is given.
+
+ Args:
+ account_id: The Account that the social accounts are connected to. Provide either this or
+ user_id.
+
+ after: Cursor to fetch the page after (from page_info.end_cursor).
+
+ before: Cursor to fetch the page before (from page_info.start_cursor).
+
+ direction: Sort direction.
+
+ first: The number of social accounts to return.
+
+ last: The number of social accounts to return from the end of the range.
+
+ order: The field to sort social accounts by.
+
+ platform: Only return social accounts for the platform that is specified.
+
+ scopes: Only return social accounts that have these scopes.
+
+ user_id: The User that the social accounts are connected to. Provide either this or
+ account_id.
+
+ verified: Only return social accounts that are verified on the platform.
+
+ 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(
+ "/social_accounts",
+ page=SyncCursorPage[SocialAccount],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "account_id": account_id,
+ "after": after,
+ "before": before,
+ "direction": direction,
+ "first": first,
+ "last": last,
+ "order": order,
+ "platform": platform,
+ "scopes": scopes,
+ "user_id": user_id,
+ "verified": verified,
+ },
+ social_account_list_params.SocialAccountListParams,
+ ),
+ ),
+ model=SocialAccount,
+ )
+
+ def delete(
+ self,
+ id: str,
+ *,
+ account_id: str | Omit = omit,
+ user_id: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> SocialAccountDeleteResponse:
+ """
+ Disconnects a social account from an account or user by discarding the link
+ record. The underlying social account record is retained.
+
+ Args:
+ account_id: The Account that the social account is connected to. Provide either this or
+ user_id.
+
+ user_id: The User that the social account is connected to. Provide either this or
+ account_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
+ """
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return self._delete(
+ path_template("/social_accounts/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "account_id": account_id,
+ "user_id": user_id,
+ },
+ social_account_delete_params.SocialAccountDeleteParams,
+ ),
+ ),
+ cast_to=SocialAccountDeleteResponse,
+ )
+
+ def posts(
+ self,
+ id: str,
+ *,
+ account_id: str,
+ after: str | Omit = omit,
+ first: int | Omit = omit,
+ post_id: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> SocialAccountPostsResponse:
+ """Lists the existing posts of a connected social account.
+
+ Supported for Facebook
+ pages and Instagram accounts. Pass post*id to return only that single post. The
+ owning account is passed as account_id (a biz* identifier).
+
+ Args:
+ account_id: The Account (a biz\\__ identifier) the social account is connected to.
+
+ after: Cursor to fetch the page after (from page_info.end_cursor).
+
+ first: The number of posts to return.
+
+ post_id: Return only the single post with this platform id, instead of the full list.
+
+ 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(
+ path_template("/social_accounts/{id}/posts", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "account_id": account_id,
+ "after": after,
+ "first": first,
+ "post_id": post_id,
+ },
+ social_account_posts_params.SocialAccountPostsParams,
+ ),
+ ),
+ cast_to=SocialAccountPostsResponse,
+ )
+
+
+class AsyncSocialAccountsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncSocialAccountsResourceWithRawResponse:
+ """
+ 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 AsyncSocialAccountsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncSocialAccountsResourceWithStreamingResponse:
+ """
+ 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 AsyncSocialAccountsResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ platform: Literal["meta_business"],
+ redirect_url: str,
+ account_id: str | Omit = omit,
+ scopes: List[Literal["advertise"]] | 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,
+ ) -> SocialAccountCreateResponse:
+ """
+ Starts an OAuth connection flow for a social account and returns an
+ authorize*url to redirect the user to. Today the only supported platform is
+ meta_business, which grants the advertise scope so the connected Facebook page
+ and Instagram account can run ads. The required permission follows the requested
+ capability: the advertise scope requires ad_campaign:create (so advertiser roles
+ can connect), other scopes require social_account:create. The connection is
+ authorized against the account given by account_id (a biz* identifier); an
+ account-scoped API key may omit it to default to its own account.
+
+ Args:
+ platform: The platform to connect the social account on.
+
+ redirect_url: The Whop URL to redirect the user to after they finish connecting.
+
+ account_id: The Account (biz\\__ identifier) to connect the social account for. An
+ account-scoped API key may omit this to default to its own account.
+
+ scopes: Capabilities to grant for the connected social account, for example `advertise`.
+
+ 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(
+ "/social_accounts",
+ body=await async_maybe_transform(
+ {
+ "platform": platform,
+ "redirect_url": redirect_url,
+ "account_id": account_id,
+ "scopes": scopes,
+ },
+ social_account_create_params.SocialAccountCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SocialAccountCreateResponse,
+ )
+
+ def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal["display_order", "created_at"] | Omit = omit,
+ platform: Literal["x", "instagram", "youtube", "tiktok", "facebook"] | Omit = omit,
+ scopes: List[Literal["advertise"]] | Omit = omit,
+ user_id: str | Omit = omit,
+ verified: bool | 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[SocialAccount, AsyncCursorPage[SocialAccount]]:
+ """Lists the social accounts linked to an account or user.
+
+ The owner is passed as
+ exactly one of account*id (a biz* identifier) or user*id (a user* identifier);
+ an account-scoped API key defaults to its own account when neither is given.
+
+ Args:
+ account_id: The Account that the social accounts are connected to. Provide either this or
+ user_id.
+
+ after: Cursor to fetch the page after (from page_info.end_cursor).
+
+ before: Cursor to fetch the page before (from page_info.start_cursor).
+
+ direction: Sort direction.
+
+ first: The number of social accounts to return.
+
+ last: The number of social accounts to return from the end of the range.
+
+ order: The field to sort social accounts by.
+
+ platform: Only return social accounts for the platform that is specified.
+
+ scopes: Only return social accounts that have these scopes.
+
+ user_id: The User that the social accounts are connected to. Provide either this or
+ account_id.
+
+ verified: Only return social accounts that are verified on the platform.
+
+ 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(
+ "/social_accounts",
+ page=AsyncCursorPage[SocialAccount],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "account_id": account_id,
+ "after": after,
+ "before": before,
+ "direction": direction,
+ "first": first,
+ "last": last,
+ "order": order,
+ "platform": platform,
+ "scopes": scopes,
+ "user_id": user_id,
+ "verified": verified,
+ },
+ social_account_list_params.SocialAccountListParams,
+ ),
+ ),
+ model=SocialAccount,
+ )
+
+ async def delete(
+ self,
+ id: str,
+ *,
+ account_id: str | Omit = omit,
+ user_id: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> SocialAccountDeleteResponse:
+ """
+ Disconnects a social account from an account or user by discarding the link
+ record. The underlying social account record is retained.
+
+ Args:
+ account_id: The Account that the social account is connected to. Provide either this or
+ user_id.
+
+ user_id: The User that the social account is connected to. Provide either this or
+ account_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
+ """
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return await self._delete(
+ path_template("/social_accounts/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "account_id": account_id,
+ "user_id": user_id,
+ },
+ social_account_delete_params.SocialAccountDeleteParams,
+ ),
+ ),
+ cast_to=SocialAccountDeleteResponse,
+ )
+
+ async def posts(
+ self,
+ id: str,
+ *,
+ account_id: str,
+ after: str | Omit = omit,
+ first: int | Omit = omit,
+ post_id: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> SocialAccountPostsResponse:
+ """Lists the existing posts of a connected social account.
+
+ Supported for Facebook
+ pages and Instagram accounts. Pass post*id to return only that single post. The
+ owning account is passed as account_id (a biz* identifier).
+
+ Args:
+ account_id: The Account (a biz\\__ identifier) the social account is connected to.
+
+ after: Cursor to fetch the page after (from page_info.end_cursor).
+
+ first: The number of posts to return.
+
+ post_id: Return only the single post with this platform id, instead of the full list.
+
+ 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(
+ path_template("/social_accounts/{id}/posts", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "account_id": account_id,
+ "after": after,
+ "first": first,
+ "post_id": post_id,
+ },
+ social_account_posts_params.SocialAccountPostsParams,
+ ),
+ ),
+ cast_to=SocialAccountPostsResponse,
+ )
+
+
+class SocialAccountsResourceWithRawResponse:
+ def __init__(self, social_accounts: SocialAccountsResource) -> None:
+ self._social_accounts = social_accounts
+
+ self.create = to_raw_response_wrapper(
+ social_accounts.create,
+ )
+ self.list = to_raw_response_wrapper(
+ social_accounts.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ social_accounts.delete,
+ )
+ self.posts = to_raw_response_wrapper(
+ social_accounts.posts,
+ )
+
+
+class AsyncSocialAccountsResourceWithRawResponse:
+ def __init__(self, social_accounts: AsyncSocialAccountsResource) -> None:
+ self._social_accounts = social_accounts
+
+ self.create = async_to_raw_response_wrapper(
+ social_accounts.create,
+ )
+ self.list = async_to_raw_response_wrapper(
+ social_accounts.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ social_accounts.delete,
+ )
+ self.posts = async_to_raw_response_wrapper(
+ social_accounts.posts,
+ )
+
+
+class SocialAccountsResourceWithStreamingResponse:
+ def __init__(self, social_accounts: SocialAccountsResource) -> None:
+ self._social_accounts = social_accounts
+
+ self.create = to_streamed_response_wrapper(
+ social_accounts.create,
+ )
+ self.list = to_streamed_response_wrapper(
+ social_accounts.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ social_accounts.delete,
+ )
+ self.posts = to_streamed_response_wrapper(
+ social_accounts.posts,
+ )
+
+
+class AsyncSocialAccountsResourceWithStreamingResponse:
+ def __init__(self, social_accounts: AsyncSocialAccountsResource) -> None:
+ self._social_accounts = social_accounts
+
+ self.create = async_to_streamed_response_wrapper(
+ social_accounts.create,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ social_accounts.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ social_accounts.delete,
+ )
+ self.posts = async_to_streamed_response_wrapper(
+ social_accounts.posts,
+ )
diff --git a/src/whop_sdk/resources/stats.py b/src/whop_sdk/resources/stats.py
new file mode 100644
index 00000000..73848ba2
--- /dev/null
+++ b/src/whop_sdk/resources/stats.py
@@ -0,0 +1,358 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from datetime import date
+from typing_extensions import Literal
+
+import httpx
+
+from ..types import stat_retrieve_params
+from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from .._utils import path_template, 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 .._base_client import make_request_options
+from ..types.stat_list_response import StatListResponse
+from ..types.stat_retrieve_response import StatRetrieveResponse
+
+__all__ = ["StatsResource", "AsyncStatsResource"]
+
+
+class StatsResource(SyncAPIResource):
+ """Stats"""
+
+ @cached_property
+ def with_raw_response(self) -> StatsResourceWithRawResponse:
+ """
+ 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 StatsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> StatsResourceWithStreamingResponse:
+ """
+ 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 StatsResourceWithStreamingResponse(self)
+
+ def retrieve(
+ self,
+ metric: str,
+ *,
+ account_id: str,
+ from_: Union[str, date],
+ to: Union[str, date],
+ breakdown_by: str | Omit = omit,
+ card_network: str | Omit = omit,
+ convert_to: str | Omit = omit,
+ currency: str | Omit = omit,
+ interval: Literal["hour", "day", "week", "month"] | Omit = omit,
+ payment_method: str | Omit = omit,
+ snapshot_window: Literal["30d"] | Omit = omit,
+ time_zone: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> StatRetrieveResponse:
+ """
+ Retrieves a metric as a time series of points for an account over a date range.
+
+ Args:
+ account_id: The account to measure, for example biz_AbC123.
+
+ from_: Start of the date range (YYYY-MM-DD).
+
+ to: End of the date range (YYYY-MM-DD).
+
+ breakdown_by: Split the metric out by one of its properties — each point gets a breakdown
+ array. For example breakdown_by=currency returns an entry for usd, an entry for
+ eur, and so on.
+
+ card_network: Filter to a single card brand, for example visa. A refinement of
+ payment_method=card. Available on metrics that list card_network.
+
+ convert_to: Display currency for money metrics — every amount is converted into this ISO
+ currency using the exchange rate on each period's date. Defaults to usd. Ignored
+ when you filter or break down by currency (those report the original transaction
+ currency, unconverted).
+
+ currency: Filter to transactions made in this original ISO currency, for example eur —
+ reported in that currency, not converted. Pair with breakdown_by=currency to
+ split a metric by currency. Available on metrics that list currency.
+
+ interval: How wide each point is. Defaults to day. Snapshot metrics are day-only.
+
+ payment_method: Filter to a single payment method, for example card or crypto. Available on
+ metrics that list payment_method.
+
+ snapshot_window: Trailing window for snapshot metrics. Only accepted by snapshot metrics (each
+ lists its allowed windows in the catalog); defaults to the metric's first
+ supported window. Only 30d today.
+
+ time_zone: IANA time zone to bucket the series in, for example America/New_York. Defaults
+ to UTC. Not accepted by snapshot metrics, which are UTC only.
+
+ 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 metric:
+ raise ValueError(f"Expected a non-empty value for `metric` but received {metric!r}")
+ return self._get(
+ path_template("/stats/{metric}", metric=metric),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "account_id": account_id,
+ "from_": from_,
+ "to": to,
+ "breakdown_by": breakdown_by,
+ "card_network": card_network,
+ "convert_to": convert_to,
+ "currency": currency,
+ "interval": interval,
+ "payment_method": payment_method,
+ "snapshot_window": snapshot_window,
+ "time_zone": time_zone,
+ },
+ stat_retrieve_params.StatRetrieveParams,
+ ),
+ ),
+ cast_to=StatRetrieveResponse,
+ )
+
+ def list(
+ self,
+ *,
+ # 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,
+ ) -> StatListResponse:
+ """
+ Lists every metric you can query, with its unit and the properties you can
+ filter or break it down by.
+ """
+ return self._get(
+ "/stats",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=StatListResponse,
+ )
+
+
+class AsyncStatsResource(AsyncAPIResource):
+ """Stats"""
+
+ @cached_property
+ def with_raw_response(self) -> AsyncStatsResourceWithRawResponse:
+ """
+ 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 AsyncStatsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncStatsResourceWithStreamingResponse:
+ """
+ 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 AsyncStatsResourceWithStreamingResponse(self)
+
+ async def retrieve(
+ self,
+ metric: str,
+ *,
+ account_id: str,
+ from_: Union[str, date],
+ to: Union[str, date],
+ breakdown_by: str | Omit = omit,
+ card_network: str | Omit = omit,
+ convert_to: str | Omit = omit,
+ currency: str | Omit = omit,
+ interval: Literal["hour", "day", "week", "month"] | Omit = omit,
+ payment_method: str | Omit = omit,
+ snapshot_window: Literal["30d"] | Omit = omit,
+ time_zone: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> StatRetrieveResponse:
+ """
+ Retrieves a metric as a time series of points for an account over a date range.
+
+ Args:
+ account_id: The account to measure, for example biz_AbC123.
+
+ from_: Start of the date range (YYYY-MM-DD).
+
+ to: End of the date range (YYYY-MM-DD).
+
+ breakdown_by: Split the metric out by one of its properties — each point gets a breakdown
+ array. For example breakdown_by=currency returns an entry for usd, an entry for
+ eur, and so on.
+
+ card_network: Filter to a single card brand, for example visa. A refinement of
+ payment_method=card. Available on metrics that list card_network.
+
+ convert_to: Display currency for money metrics — every amount is converted into this ISO
+ currency using the exchange rate on each period's date. Defaults to usd. Ignored
+ when you filter or break down by currency (those report the original transaction
+ currency, unconverted).
+
+ currency: Filter to transactions made in this original ISO currency, for example eur —
+ reported in that currency, not converted. Pair with breakdown_by=currency to
+ split a metric by currency. Available on metrics that list currency.
+
+ interval: How wide each point is. Defaults to day. Snapshot metrics are day-only.
+
+ payment_method: Filter to a single payment method, for example card or crypto. Available on
+ metrics that list payment_method.
+
+ snapshot_window: Trailing window for snapshot metrics. Only accepted by snapshot metrics (each
+ lists its allowed windows in the catalog); defaults to the metric's first
+ supported window. Only 30d today.
+
+ time_zone: IANA time zone to bucket the series in, for example America/New_York. Defaults
+ to UTC. Not accepted by snapshot metrics, which are UTC only.
+
+ 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 metric:
+ raise ValueError(f"Expected a non-empty value for `metric` but received {metric!r}")
+ return await self._get(
+ path_template("/stats/{metric}", metric=metric),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "account_id": account_id,
+ "from_": from_,
+ "to": to,
+ "breakdown_by": breakdown_by,
+ "card_network": card_network,
+ "convert_to": convert_to,
+ "currency": currency,
+ "interval": interval,
+ "payment_method": payment_method,
+ "snapshot_window": snapshot_window,
+ "time_zone": time_zone,
+ },
+ stat_retrieve_params.StatRetrieveParams,
+ ),
+ ),
+ cast_to=StatRetrieveResponse,
+ )
+
+ async def list(
+ self,
+ *,
+ # 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,
+ ) -> StatListResponse:
+ """
+ Lists every metric you can query, with its unit and the properties you can
+ filter or break it down by.
+ """
+ return await self._get(
+ "/stats",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=StatListResponse,
+ )
+
+
+class StatsResourceWithRawResponse:
+ def __init__(self, stats: StatsResource) -> None:
+ self._stats = stats
+
+ self.retrieve = to_raw_response_wrapper(
+ stats.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ stats.list,
+ )
+
+
+class AsyncStatsResourceWithRawResponse:
+ def __init__(self, stats: AsyncStatsResource) -> None:
+ self._stats = stats
+
+ self.retrieve = async_to_raw_response_wrapper(
+ stats.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ stats.list,
+ )
+
+
+class StatsResourceWithStreamingResponse:
+ def __init__(self, stats: StatsResource) -> None:
+ self._stats = stats
+
+ self.retrieve = to_streamed_response_wrapper(
+ stats.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ stats.list,
+ )
+
+
+class AsyncStatsResourceWithStreamingResponse:
+ def __init__(self, stats: AsyncStatsResource) -> None:
+ self._stats = stats
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ stats.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ stats.list,
+ )
diff --git a/src/whop_sdk/resources/swaps.py b/src/whop_sdk/resources/swaps.py
index a79eabbe..77fbcc9d 100644
--- a/src/whop_sdk/resources/swaps.py
+++ b/src/whop_sdk/resources/swaps.py
@@ -6,9 +6,9 @@
import httpx
-from ..types import swap_create_quote_params
+from ..types import swap_list_params, swap_create_params, swap_create_quote_params
from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from .._utils import maybe_transform, async_maybe_transform
+from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -18,6 +18,9 @@
async_to_streamed_response_wrapper,
)
from .._base_client import make_request_options
+from ..types.swap_list_response import SwapListResponse
+from ..types.swap_create_response import SwapCreateResponse
+from ..types.swap_retrieve_response import SwapRetrieveResponse
from ..types.swap_create_quote_response import SwapCreateQuoteResponse
__all__ = ["SwapsResource", "AsyncSwapsResource"]
@@ -43,6 +46,145 @@ def with_streaming_response(self) -> SwapsResourceWithStreamingResponse:
"""
return SwapsResourceWithStreamingResponse(self)
+ def create(
+ self,
+ *,
+ account_id: str,
+ amount: str,
+ from_token: str,
+ to_token: str,
+ from_chain: Union[str, int, None] | Omit = omit,
+ slippage_bps: Optional[int] | Omit = omit,
+ to_chain: Union[str, int, None] | 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,
+ ) -> SwapCreateResponse:
+ """Executes a swap from the account's wallet.
+
+ Runs asynchronously; poll GET
+ /swaps/{id} for status.
+
+ Args:
+ account_id: Business or user account ID (biz*\\** / user*\\**).
+
+ amount: Source token amount.
+
+ from_token: Source token contract address or ticker symbol, such as "USDT".
+
+ to_token: Destination token contract address or ticker symbol, such as "XAUT".
+
+ from_chain: Source chain name or chain ID. Defaults to the source token's chain when
+ omitted.
+
+ slippage_bps: Maximum slippage tolerance in basis points.
+
+ to_chain: Destination chain name or chain ID. Defaults to the destination token's chain
+ when omitted.
+
+ 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(
+ "/swaps",
+ body=maybe_transform(
+ {
+ "account_id": account_id,
+ "amount": amount,
+ "from_token": from_token,
+ "to_token": to_token,
+ "from_chain": from_chain,
+ "slippage_bps": slippage_bps,
+ "to_chain": to_chain,
+ },
+ swap_create_params.SwapCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SwapCreateResponse,
+ )
+
+ 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,
+ ) -> SwapRetrieveResponse:
+ """
+ Returns the status of a specific swap, by the id returned from POST /swaps.
+
+ 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(
+ path_template("/swaps/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SwapRetrieveResponse,
+ )
+
+ def list(
+ self,
+ *,
+ account_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,
+ ) -> SwapListResponse:
+ """Lists the account's swaps.
+
+ Currently returns the in-flight or most recent swap,
+ so zero or one rows.
+
+ Args:
+ account_id: Business or user account ID (biz*\\** / user*\\**).
+
+ 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(
+ "/swaps",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"account_id": account_id}, swap_list_params.SwapListParams),
+ ),
+ cast_to=SwapListResponse,
+ )
+
def create_quote(
self,
*,
@@ -67,11 +209,25 @@ def create_quote(
No funds move and nothing is persisted.
Args:
- amount: Input token amount.
+ amount: Source token amount.
+
+ from_token: Source token contract address or ticker symbol, such as "USDT".
+
+ to_token: Destination token contract address or ticker symbol, such as "XAUT".
+
+ from_address: Source wallet address used for the quote.
+
+ from_chain: Source chain name or chain ID. Defaults to the source token's chain when
+ omitted.
+
+ metadata: Metadata to include with the quote response.
+
+ slippage_bps: Maximum slippage tolerance in basis points.
- from_token: Source token contract address.
+ to_address: Destination wallet address used for the quote.
- to_token: Destination token contract address.
+ to_chain: Destination chain name or chain ID. Defaults to the destination token's chain
+ when omitted.
extra_headers: Send extra headers
@@ -124,6 +280,145 @@ def with_streaming_response(self) -> AsyncSwapsResourceWithStreamingResponse:
"""
return AsyncSwapsResourceWithStreamingResponse(self)
+ async def create(
+ self,
+ *,
+ account_id: str,
+ amount: str,
+ from_token: str,
+ to_token: str,
+ from_chain: Union[str, int, None] | Omit = omit,
+ slippage_bps: Optional[int] | Omit = omit,
+ to_chain: Union[str, int, None] | 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,
+ ) -> SwapCreateResponse:
+ """Executes a swap from the account's wallet.
+
+ Runs asynchronously; poll GET
+ /swaps/{id} for status.
+
+ Args:
+ account_id: Business or user account ID (biz*\\** / user*\\**).
+
+ amount: Source token amount.
+
+ from_token: Source token contract address or ticker symbol, such as "USDT".
+
+ to_token: Destination token contract address or ticker symbol, such as "XAUT".
+
+ from_chain: Source chain name or chain ID. Defaults to the source token's chain when
+ omitted.
+
+ slippage_bps: Maximum slippage tolerance in basis points.
+
+ to_chain: Destination chain name or chain ID. Defaults to the destination token's chain
+ when omitted.
+
+ 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(
+ "/swaps",
+ body=await async_maybe_transform(
+ {
+ "account_id": account_id,
+ "amount": amount,
+ "from_token": from_token,
+ "to_token": to_token,
+ "from_chain": from_chain,
+ "slippage_bps": slippage_bps,
+ "to_chain": to_chain,
+ },
+ swap_create_params.SwapCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SwapCreateResponse,
+ )
+
+ 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,
+ ) -> SwapRetrieveResponse:
+ """
+ Returns the status of a specific swap, by the id returned from POST /swaps.
+
+ 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(
+ path_template("/swaps/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SwapRetrieveResponse,
+ )
+
+ async def list(
+ self,
+ *,
+ account_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,
+ ) -> SwapListResponse:
+ """Lists the account's swaps.
+
+ Currently returns the in-flight or most recent swap,
+ so zero or one rows.
+
+ Args:
+ account_id: Business or user account ID (biz*\\** / user*\\**).
+
+ 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._get(
+ "/swaps",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform({"account_id": account_id}, swap_list_params.SwapListParams),
+ ),
+ cast_to=SwapListResponse,
+ )
+
async def create_quote(
self,
*,
@@ -148,11 +443,25 @@ async def create_quote(
No funds move and nothing is persisted.
Args:
- amount: Input token amount.
+ amount: Source token amount.
+
+ from_token: Source token contract address or ticker symbol, such as "USDT".
+
+ to_token: Destination token contract address or ticker symbol, such as "XAUT".
+
+ from_address: Source wallet address used for the quote.
+
+ from_chain: Source chain name or chain ID. Defaults to the source token's chain when
+ omitted.
+
+ metadata: Metadata to include with the quote response.
- from_token: Source token contract address.
+ slippage_bps: Maximum slippage tolerance in basis points.
- to_token: Destination token contract address.
+ to_address: Destination wallet address used for the quote.
+
+ to_chain: Destination chain name or chain ID. Defaults to the destination token's chain
+ when omitted.
extra_headers: Send extra headers
@@ -189,6 +498,15 @@ class SwapsResourceWithRawResponse:
def __init__(self, swaps: SwapsResource) -> None:
self._swaps = swaps
+ self.create = to_raw_response_wrapper(
+ swaps.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ swaps.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ swaps.list,
+ )
self.create_quote = to_raw_response_wrapper(
swaps.create_quote,
)
@@ -198,6 +516,15 @@ class AsyncSwapsResourceWithRawResponse:
def __init__(self, swaps: AsyncSwapsResource) -> None:
self._swaps = swaps
+ self.create = async_to_raw_response_wrapper(
+ swaps.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ swaps.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ swaps.list,
+ )
self.create_quote = async_to_raw_response_wrapper(
swaps.create_quote,
)
@@ -207,6 +534,15 @@ class SwapsResourceWithStreamingResponse:
def __init__(self, swaps: SwapsResource) -> None:
self._swaps = swaps
+ self.create = to_streamed_response_wrapper(
+ swaps.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ swaps.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ swaps.list,
+ )
self.create_quote = to_streamed_response_wrapper(
swaps.create_quote,
)
@@ -216,6 +552,15 @@ class AsyncSwapsResourceWithStreamingResponse:
def __init__(self, swaps: AsyncSwapsResource) -> None:
self._swaps = swaps
+ self.create = async_to_streamed_response_wrapper(
+ swaps.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ swaps.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ swaps.list,
+ )
self.create_quote = async_to_streamed_response_wrapper(
swaps.create_quote,
)
diff --git a/src/whop_sdk/resources/transfers.py b/src/whop_sdk/resources/transfers.py
index 806984ba..896acdd8 100644
--- a/src/whop_sdk/resources/transfers.py
+++ b/src/whop_sdk/resources/transfers.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-from typing import Dict, Union, Optional
+from typing import Any, Dict, Union, Optional, cast
from datetime import datetime
from typing_extensions import Literal
@@ -21,17 +21,14 @@
)
from ..pagination import SyncCursorPage, AsyncCursorPage
from .._base_client import AsyncPaginator, make_request_options
-from ..types.shared.currency import Currency
-from ..types.shared.transfer import Transfer
-from ..types.shared.direction import Direction
from ..types.transfer_list_response import TransferListResponse
+from ..types.transfer_create_response import TransferCreateResponse
+from ..types.transfer_retrieve_response import TransferRetrieveResponse
__all__ = ["TransfersResource", "AsyncTransfersResource"]
class TransfersResource(SyncAPIResource):
- """Transfers"""
-
@cached_property
def with_raw_response(self) -> TransfersResourceWithRawResponse:
"""
@@ -55,48 +52,54 @@ def create(
self,
*,
amount: float,
- currency: Currency,
- destination_id: str,
origin_id: str,
+ currency: str | Omit = omit,
+ destination_id: str | Omit = omit,
+ expires_at: Union[str, datetime, None] | Omit = omit,
idempotence_key: Optional[str] | Omit = omit,
metadata: Optional[Dict[str, object]] | Omit = omit,
notes: Optional[str] | Omit = omit,
+ redeemable_count: int | Omit = omit,
+ type: Literal["ledger", "wallet_send", "claim_link"] | 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,
- ) -> Transfer:
- """
- Transfer funds between two ledger accounts, such as from a company balance to a
- user balance.
-
- Required permissions:
+ ) -> TransferCreateResponse:
+ """Moves funds out of an account.
- - `payout:transfer_funds`
+ `type` selects the kind of movement (default
+ `ledger`): `ledger` transfers credit between two ledger accounts and returns a
+ Transfer; `wallet_send` sends USDT from the origin account's Ethereum wallet to
+ a recipient; `claim_link` funds a shareable claim link anyone with the URL can
+ redeem.
Args:
- amount: The amount to transfer in the specified currency. For example, 25.00 for $25.00
- USD.
+ amount: The amount to move, in the transfer currency. For example 25.00.
+
+ origin_id: The account sending the funds. A user ID (user_xxx), account ID (biz_xxx), or
+ ledger account ID (ldgr_xxx).
+
+ currency: Currency, such as `usd`. Required for ledger transfers.
- currency: The currency of the transfer amount, such as 'usd'.
+ destination_id: The recipient. Required for ledger and wallet*send (a user*/biz*/ldgr* ID, or —
+ for sends — an email). Omit for claim_link.
- destination_id: The identifier of the account receiving the funds. Accepts a user ID
- ('user_xxx'), company ID ('biz_xxx'), ledger account ID ('ldgr_xxx'), or an
- email address — emails without an existing Whop user trigger a placeholder-user
- signup.
+ expires_at: claim_link only. Link expiry as an ISO 8601 timestamp. Defaults to 24 hours from
+ creation.
- origin_id: The identifier of the account sending the funds. Accepts a user ID ('user_xxx'),
- company ID ('biz_xxx'), or ledger account ID ('ldgr_xxx').
+ idempotence_key: Ledger transfers only. A unique key to prevent duplicate transfers.
- idempotence_key: A unique key to prevent duplicate transfers. Use a UUID or similar unique
- string.
+ metadata: Ledger transfers only. Custom key-value pairs attached to the transfer. Max 50
+ keys, 100 chars per key, 500 chars per string value.
- metadata: A JSON object of custom metadata to attach to the transfer for tracking
- purposes.
+ notes: Ledger transfers only. A short note describing the transfer.
- notes: A short note describing the transfer, up to 50 characters.
+ redeemable_count: claim_link only. How many different users can claim the link. Defaults to 1.
+
+ type: The kind of money movement. Defaults to ledger.
extra_headers: Send extra headers
@@ -106,24 +109,32 @@ def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return self._post(
- "/transfers",
- body=maybe_transform(
- {
- "amount": amount,
- "currency": currency,
- "destination_id": destination_id,
- "origin_id": origin_id,
- "idempotence_key": idempotence_key,
- "metadata": metadata,
- "notes": notes,
- },
- transfer_create_params.TransferCreateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ return cast(
+ TransferCreateResponse,
+ self._post(
+ "/transfers",
+ body=maybe_transform(
+ {
+ "amount": amount,
+ "origin_id": origin_id,
+ "currency": currency,
+ "destination_id": destination_id,
+ "expires_at": expires_at,
+ "idempotence_key": idempotence_key,
+ "metadata": metadata,
+ "notes": notes,
+ "redeemable_count": redeemable_count,
+ "type": type,
+ },
+ transfer_create_params.TransferCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, TransferCreateResponse
+ ), # Union types cannot be passed in as arguments in the type system
),
- cast_to=Transfer,
)
def retrieve(
@@ -136,13 +147,9 @@ def retrieve(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> Transfer:
+ ) -> TransferRetrieveResponse:
"""
- Retrieves the details of an existing transfer.
-
- Required permissions:
-
- - `payout:transfer:read`
+ Retrieves a ledger transfer by ID.
Args:
extra_headers: Send extra headers
@@ -160,22 +167,22 @@ def retrieve(
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=Transfer,
+ cast_to=TransferRetrieveResponse,
)
def list(
self,
*,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- created_after: Union[str, datetime, None] | Omit = omit,
- created_before: Union[str, datetime, None] | Omit = omit,
- destination_id: Optional[str] | Omit = omit,
- direction: Optional[Direction] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[int] | Omit = omit,
- order: Optional[Literal["amount", "created_at"]] | Omit = omit,
- origin_id: Optional[str] | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ created_after: str | Omit = omit,
+ created_before: str | Omit = omit,
+ destination_id: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal["created_at", "amount"] | Omit = omit,
+ origin_id: 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.
extra_headers: Headers | None = None,
@@ -183,36 +190,31 @@ def list(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[TransferListResponse]:
- """
- Returns a paginated list of fund transfers, filtered by origin or destination
- account, with optional sorting and date filtering.
-
- Required permissions:
+ """Lists ledger transfers for an account.
- - `payout:transfer:read`
+ You must specify an origin_id or a
+ destination_id.
Args:
- after: Returns the elements in the list that come after the specified cursor.
+ after: Cursor to fetch the page after (from page_info.end_cursor).
- before: Returns the elements in the list that come before the specified cursor.
+ before: Cursor to fetch the page before (from page_info.start_cursor).
- created_after: Only return transfers created after this timestamp.
+ created_after: Only transfers created strictly after this ISO 8601 timestamp.
- created_before: Only return transfers created before this timestamp.
+ created_before: Only transfers created strictly before this ISO 8601 timestamp.
- destination_id: Filter to transfers received by this account. Accepts a user, company, or ledger
- account ID.
+ destination_id: Filter to transfers received by this account.
- direction: The direction of the sort.
+ direction: Sort direction. Defaults to desc.
- first: Returns the first _n_ elements from the list.
+ first: Number of transfers to return from the start of the window.
- last: Returns the last _n_ elements from the list.
+ last: Number of transfers to return from the end of the window.
- order: Which columns can be used to sort.
+ order: Sort column. Defaults to created_at.
- origin_id: Filter to transfers sent from this account. Accepts a user, company, or ledger
- account ID.
+ origin_id: Filter to transfers sent from this account.
extra_headers: Send extra headers
@@ -251,8 +253,6 @@ def list(
class AsyncTransfersResource(AsyncAPIResource):
- """Transfers"""
-
@cached_property
def with_raw_response(self) -> AsyncTransfersResourceWithRawResponse:
"""
@@ -276,48 +276,54 @@ async def create(
self,
*,
amount: float,
- currency: Currency,
- destination_id: str,
origin_id: str,
+ currency: str | Omit = omit,
+ destination_id: str | Omit = omit,
+ expires_at: Union[str, datetime, None] | Omit = omit,
idempotence_key: Optional[str] | Omit = omit,
metadata: Optional[Dict[str, object]] | Omit = omit,
notes: Optional[str] | Omit = omit,
+ redeemable_count: int | Omit = omit,
+ type: Literal["ledger", "wallet_send", "claim_link"] | 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,
- ) -> Transfer:
- """
- Transfer funds between two ledger accounts, such as from a company balance to a
- user balance.
-
- Required permissions:
+ ) -> TransferCreateResponse:
+ """Moves funds out of an account.
- - `payout:transfer_funds`
+ `type` selects the kind of movement (default
+ `ledger`): `ledger` transfers credit between two ledger accounts and returns a
+ Transfer; `wallet_send` sends USDT from the origin account's Ethereum wallet to
+ a recipient; `claim_link` funds a shareable claim link anyone with the URL can
+ redeem.
Args:
- amount: The amount to transfer in the specified currency. For example, 25.00 for $25.00
- USD.
+ amount: The amount to move, in the transfer currency. For example 25.00.
+
+ origin_id: The account sending the funds. A user ID (user_xxx), account ID (biz_xxx), or
+ ledger account ID (ldgr_xxx).
+
+ currency: Currency, such as `usd`. Required for ledger transfers.
- currency: The currency of the transfer amount, such as 'usd'.
+ destination_id: The recipient. Required for ledger and wallet*send (a user*/biz*/ldgr* ID, or —
+ for sends — an email). Omit for claim_link.
- destination_id: The identifier of the account receiving the funds. Accepts a user ID
- ('user_xxx'), company ID ('biz_xxx'), ledger account ID ('ldgr_xxx'), or an
- email address — emails without an existing Whop user trigger a placeholder-user
- signup.
+ expires_at: claim_link only. Link expiry as an ISO 8601 timestamp. Defaults to 24 hours from
+ creation.
- origin_id: The identifier of the account sending the funds. Accepts a user ID ('user_xxx'),
- company ID ('biz_xxx'), or ledger account ID ('ldgr_xxx').
+ idempotence_key: Ledger transfers only. A unique key to prevent duplicate transfers.
- idempotence_key: A unique key to prevent duplicate transfers. Use a UUID or similar unique
- string.
+ metadata: Ledger transfers only. Custom key-value pairs attached to the transfer. Max 50
+ keys, 100 chars per key, 500 chars per string value.
- metadata: A JSON object of custom metadata to attach to the transfer for tracking
- purposes.
+ notes: Ledger transfers only. A short note describing the transfer.
- notes: A short note describing the transfer, up to 50 characters.
+ redeemable_count: claim_link only. How many different users can claim the link. Defaults to 1.
+
+ type: The kind of money movement. Defaults to ledger.
extra_headers: Send extra headers
@@ -327,24 +333,32 @@ async def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return await self._post(
- "/transfers",
- body=await async_maybe_transform(
- {
- "amount": amount,
- "currency": currency,
- "destination_id": destination_id,
- "origin_id": origin_id,
- "idempotence_key": idempotence_key,
- "metadata": metadata,
- "notes": notes,
- },
- transfer_create_params.TransferCreateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ return cast(
+ TransferCreateResponse,
+ await self._post(
+ "/transfers",
+ body=await async_maybe_transform(
+ {
+ "amount": amount,
+ "origin_id": origin_id,
+ "currency": currency,
+ "destination_id": destination_id,
+ "expires_at": expires_at,
+ "idempotence_key": idempotence_key,
+ "metadata": metadata,
+ "notes": notes,
+ "redeemable_count": redeemable_count,
+ "type": type,
+ },
+ transfer_create_params.TransferCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, TransferCreateResponse
+ ), # Union types cannot be passed in as arguments in the type system
),
- cast_to=Transfer,
)
async def retrieve(
@@ -357,13 +371,9 @@ async def retrieve(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> Transfer:
+ ) -> TransferRetrieveResponse:
"""
- Retrieves the details of an existing transfer.
-
- Required permissions:
-
- - `payout:transfer:read`
+ Retrieves a ledger transfer by ID.
Args:
extra_headers: Send extra headers
@@ -381,22 +391,22 @@ async def retrieve(
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=Transfer,
+ cast_to=TransferRetrieveResponse,
)
def list(
self,
*,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- created_after: Union[str, datetime, None] | Omit = omit,
- created_before: Union[str, datetime, None] | Omit = omit,
- destination_id: Optional[str] | Omit = omit,
- direction: Optional[Direction] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[int] | Omit = omit,
- order: Optional[Literal["amount", "created_at"]] | Omit = omit,
- origin_id: Optional[str] | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ created_after: str | Omit = omit,
+ created_before: str | Omit = omit,
+ destination_id: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ order: Literal["created_at", "amount"] | Omit = omit,
+ origin_id: 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.
extra_headers: Headers | None = None,
@@ -404,36 +414,31 @@ def list(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[TransferListResponse, AsyncCursorPage[TransferListResponse]]:
- """
- Returns a paginated list of fund transfers, filtered by origin or destination
- account, with optional sorting and date filtering.
-
- Required permissions:
+ """Lists ledger transfers for an account.
- - `payout:transfer:read`
+ You must specify an origin_id or a
+ destination_id.
Args:
- after: Returns the elements in the list that come after the specified cursor.
+ after: Cursor to fetch the page after (from page_info.end_cursor).
- before: Returns the elements in the list that come before the specified cursor.
+ before: Cursor to fetch the page before (from page_info.start_cursor).
- created_after: Only return transfers created after this timestamp.
+ created_after: Only transfers created strictly after this ISO 8601 timestamp.
- created_before: Only return transfers created before this timestamp.
+ created_before: Only transfers created strictly before this ISO 8601 timestamp.
- destination_id: Filter to transfers received by this account. Accepts a user, company, or ledger
- account ID.
+ destination_id: Filter to transfers received by this account.
- direction: The direction of the sort.
+ direction: Sort direction. Defaults to desc.
- first: Returns the first _n_ elements from the list.
+ first: Number of transfers to return from the start of the window.
- last: Returns the last _n_ elements from the list.
+ last: Number of transfers to return from the end of the window.
- order: Which columns can be used to sort.
+ order: Sort column. Defaults to created_at.
- origin_id: Filter to transfers sent from this account. Accepts a user, company, or ledger
- account ID.
+ origin_id: Filter to transfers sent from this account.
extra_headers: Send extra headers
diff --git a/src/whop_sdk/resources/users.py b/src/whop_sdk/resources/users.py
index e0ce27c0..0393836e 100644
--- a/src/whop_sdk/resources/users.py
+++ b/src/whop_sdk/resources/users.py
@@ -2,11 +2,9 @@
from __future__ import annotations
-from typing import Optional
-
import httpx
-from ..types import user_list_params, user_update_params, user_retrieve_params
+from ..types import user_list_params, user_update_params, user_retrieve_params, user_update_me_params
from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
@@ -20,15 +18,12 @@
from ..pagination import SyncCursorPage, AsyncCursorPage
from ..types.user import User
from .._base_client import AsyncPaginator, make_request_options
-from ..types.user_list_response import UserListResponse
from ..types.user_check_access_response import UserCheckAccessResponse
__all__ = ["UsersResource", "AsyncUsersResource"]
class UsersResource(SyncAPIResource):
- """Users"""
-
@cached_property
def with_raw_response(self) -> UsersResourceWithRawResponse:
"""
@@ -52,7 +47,7 @@ def retrieve(
self,
id: str,
*,
- company_id: Optional[str] | Omit = omit,
+ account_id: 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.
extra_headers: Headers | None = None,
@@ -61,11 +56,11 @@ def retrieve(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> User:
"""
- Retrieves the details of an existing user.
+ Retrieves a user's public profile by user\\__ tag, username, or 'me'.
Args:
- company_id: When provided, returns the user's company-specific profile overrides (name,
- profile picture) instead of their global profile.
+ account_id: When set, returns the user's account-specific profile overrides for this
+ account.
extra_headers: Send extra headers
@@ -84,7 +79,7 @@ def retrieve(
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
- query=maybe_transform({"company_id": company_id}, user_retrieve_params.UserRetrieveParams),
+ query=maybe_transform({"account_id": account_id}, user_retrieve_params.UserRetrieveParams),
),
cast_to=User,
)
@@ -93,11 +88,11 @@ def update(
self,
id: str,
*,
- bio: Optional[str] | Omit = omit,
- company_id: Optional[str] | Omit = omit,
- name: Optional[str] | Omit = omit,
- profile_picture: Optional[user_update_params.ProfilePicture] | Omit = omit,
- username: Optional[str] | Omit = omit,
+ account_id: str | Omit = omit,
+ bio: str | Omit = omit,
+ name: str | Omit = omit,
+ profile_picture: user_update_params.ProfilePicture | Omit = omit,
+ username: 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.
extra_headers: Headers | None = None,
@@ -105,26 +100,13 @@ def update(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> User:
- """
- Update a user's profile by their ID.
-
- Required permissions:
+ """Updates a user.
- - `user:profile:update`
+ A user token updates their own global profile; an API key
+ updates the user's account-specific profile override (account_id required).
Args:
- bio: A short biography displayed on the user's public profile.
-
- company_id: When provided, updates the user's profile overrides for this company instead of
- the global profile. Pass name and profile_picture to set overrides, or null to
- clear them.
-
- name: The user's display name shown on their public profile. Maximum 100 characters.
-
- profile_picture: The user's profile picture image attachment.
-
- username: The user's unique username. Alphanumeric characters and hyphens only. Maximum 42
- characters.
+ account_id: The account whose profile override to update. Required for API key callers.
extra_headers: Send extra headers
@@ -141,7 +123,6 @@ def update(
body=maybe_transform(
{
"bio": bio,
- "company_id": company_id,
"name": name,
"profile_picture": profile_picture,
"username": username,
@@ -149,7 +130,11 @@ def update(
user_update_params.UserUpdateParams,
),
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"account_id": account_id}, user_update_params.UserUpdateParams),
),
cast_to=User,
)
@@ -157,32 +142,33 @@ def update(
def list(
self,
*,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[int] | Omit = omit,
- query: Optional[str] | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ query: 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.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> SyncCursorPage[UserListResponse]:
+ ) -> SyncCursorPage[User]:
"""
Search for users by name or username, ranked by social proximity to the
- authenticated user.
+ authenticated user. Returns the user's most recently followed users when no
+ query is given.
Args:
- after: Returns the elements in the list that come after the specified cursor.
+ after: A cursor; returns users after this position.
- before: Returns the elements in the list that come before the specified cursor.
+ before: A cursor; returns users before this position.
- first: Returns the first _n_ elements from the list.
+ first: The number of users to return (max 50).
- last: Returns the last _n_ elements from the list.
+ last: The number of users to return from the end of the range.
- query: Search term to filter by name or username.
+ query: A search term to filter users by name or username.
extra_headers: Send extra headers
@@ -194,7 +180,7 @@ def list(
"""
return self._get_api_list(
"/users",
- page=SyncCursorPage[UserListResponse],
+ page=SyncCursorPage[User],
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -211,7 +197,7 @@ def list(
user_list_params.UserListParams,
),
),
- model=UserListResponse,
+ model=User,
)
def check_access(
@@ -227,8 +213,8 @@ def check_access(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> UserCheckAccessResponse:
"""
- Check whether a user has access to a specific resource, and return their access
- level.
+ Checks whether a user has access to an account, product, or experience the
+ caller can reach.
Args:
extra_headers: Send extra headers
@@ -251,10 +237,60 @@ def check_access(
cast_to=UserCheckAccessResponse,
)
+ def update_me(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ bio: str | Omit = omit,
+ name: str | Omit = omit,
+ profile_picture: user_update_me_params.ProfilePicture | Omit = omit,
+ username: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> User:
+ """
+ Updates the authenticated user's global profile, or their profile override for
+ an account when account_id is given. Not available to API keys.
-class AsyncUsersResource(AsyncAPIResource):
- """Users"""
+ Args:
+ account_id: When set, updates the authenticated user's profile override for this account
+ instead of their global profile.
+
+ 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._patch(
+ "/users/me",
+ body=maybe_transform(
+ {
+ "bio": bio,
+ "name": name,
+ "profile_picture": profile_picture,
+ "username": username,
+ },
+ user_update_me_params.UserUpdateMeParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"account_id": account_id}, user_update_me_params.UserUpdateMeParams),
+ ),
+ cast_to=User,
+ )
+
+
+class AsyncUsersResource(AsyncAPIResource):
@cached_property
def with_raw_response(self) -> AsyncUsersResourceWithRawResponse:
"""
@@ -278,7 +314,7 @@ async def retrieve(
self,
id: str,
*,
- company_id: Optional[str] | Omit = omit,
+ account_id: 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.
extra_headers: Headers | None = None,
@@ -287,11 +323,11 @@ async def retrieve(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> User:
"""
- Retrieves the details of an existing user.
+ Retrieves a user's public profile by user\\__ tag, username, or 'me'.
Args:
- company_id: When provided, returns the user's company-specific profile overrides (name,
- profile picture) instead of their global profile.
+ account_id: When set, returns the user's account-specific profile overrides for this
+ account.
extra_headers: Send extra headers
@@ -310,7 +346,7 @@ async def retrieve(
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
- query=await async_maybe_transform({"company_id": company_id}, user_retrieve_params.UserRetrieveParams),
+ query=await async_maybe_transform({"account_id": account_id}, user_retrieve_params.UserRetrieveParams),
),
cast_to=User,
)
@@ -319,11 +355,11 @@ async def update(
self,
id: str,
*,
- bio: Optional[str] | Omit = omit,
- company_id: Optional[str] | Omit = omit,
- name: Optional[str] | Omit = omit,
- profile_picture: Optional[user_update_params.ProfilePicture] | Omit = omit,
- username: Optional[str] | Omit = omit,
+ account_id: str | Omit = omit,
+ bio: str | Omit = omit,
+ name: str | Omit = omit,
+ profile_picture: user_update_params.ProfilePicture | Omit = omit,
+ username: 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.
extra_headers: Headers | None = None,
@@ -331,26 +367,13 @@ async def update(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> User:
- """
- Update a user's profile by their ID.
+ """Updates a user.
- Required permissions:
-
- - `user:profile:update`
+ A user token updates their own global profile; an API key
+ updates the user's account-specific profile override (account_id required).
Args:
- bio: A short biography displayed on the user's public profile.
-
- company_id: When provided, updates the user's profile overrides for this company instead of
- the global profile. Pass name and profile_picture to set overrides, or null to
- clear them.
-
- name: The user's display name shown on their public profile. Maximum 100 characters.
-
- profile_picture: The user's profile picture image attachment.
-
- username: The user's unique username. Alphanumeric characters and hyphens only. Maximum 42
- characters.
+ account_id: The account whose profile override to update. Required for API key callers.
extra_headers: Send extra headers
@@ -367,7 +390,6 @@ async def update(
body=await async_maybe_transform(
{
"bio": bio,
- "company_id": company_id,
"name": name,
"profile_picture": profile_picture,
"username": username,
@@ -375,7 +397,11 @@ async def update(
user_update_params.UserUpdateParams,
),
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform({"account_id": account_id}, user_update_params.UserUpdateParams),
),
cast_to=User,
)
@@ -383,32 +409,33 @@ async def update(
def list(
self,
*,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[int] | Omit = omit,
- query: Optional[str] | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ first: int | Omit = omit,
+ last: int | Omit = omit,
+ query: 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.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> AsyncPaginator[UserListResponse, AsyncCursorPage[UserListResponse]]:
+ ) -> AsyncPaginator[User, AsyncCursorPage[User]]:
"""
Search for users by name or username, ranked by social proximity to the
- authenticated user.
+ authenticated user. Returns the user's most recently followed users when no
+ query is given.
Args:
- after: Returns the elements in the list that come after the specified cursor.
+ after: A cursor; returns users after this position.
- before: Returns the elements in the list that come before the specified cursor.
+ before: A cursor; returns users before this position.
- first: Returns the first _n_ elements from the list.
+ first: The number of users to return (max 50).
- last: Returns the last _n_ elements from the list.
+ last: The number of users to return from the end of the range.
- query: Search term to filter by name or username.
+ query: A search term to filter users by name or username.
extra_headers: Send extra headers
@@ -420,7 +447,7 @@ def list(
"""
return self._get_api_list(
"/users",
- page=AsyncCursorPage[UserListResponse],
+ page=AsyncCursorPage[User],
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -437,7 +464,7 @@ def list(
user_list_params.UserListParams,
),
),
- model=UserListResponse,
+ model=User,
)
async def check_access(
@@ -453,8 +480,8 @@ async def check_access(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> UserCheckAccessResponse:
"""
- Check whether a user has access to a specific resource, and return their access
- level.
+ Checks whether a user has access to an account, product, or experience the
+ caller can reach.
Args:
extra_headers: Send extra headers
@@ -477,6 +504,58 @@ async def check_access(
cast_to=UserCheckAccessResponse,
)
+ async def update_me(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ bio: str | Omit = omit,
+ name: str | Omit = omit,
+ profile_picture: user_update_me_params.ProfilePicture | Omit = omit,
+ username: 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> User:
+ """
+ Updates the authenticated user's global profile, or their profile override for
+ an account when account_id is given. Not available to API keys.
+
+ Args:
+ account_id: When set, updates the authenticated user's profile override for this account
+ instead of their global profile.
+
+ 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._patch(
+ "/users/me",
+ body=await async_maybe_transform(
+ {
+ "bio": bio,
+ "name": name,
+ "profile_picture": profile_picture,
+ "username": username,
+ },
+ user_update_me_params.UserUpdateMeParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform({"account_id": account_id}, user_update_me_params.UserUpdateMeParams),
+ ),
+ cast_to=User,
+ )
+
class UsersResourceWithRawResponse:
def __init__(self, users: UsersResource) -> None:
@@ -494,6 +573,9 @@ def __init__(self, users: UsersResource) -> None:
self.check_access = to_raw_response_wrapper(
users.check_access,
)
+ self.update_me = to_raw_response_wrapper(
+ users.update_me,
+ )
class AsyncUsersResourceWithRawResponse:
@@ -512,6 +594,9 @@ def __init__(self, users: AsyncUsersResource) -> None:
self.check_access = async_to_raw_response_wrapper(
users.check_access,
)
+ self.update_me = async_to_raw_response_wrapper(
+ users.update_me,
+ )
class UsersResourceWithStreamingResponse:
@@ -530,6 +615,9 @@ def __init__(self, users: UsersResource) -> None:
self.check_access = to_streamed_response_wrapper(
users.check_access,
)
+ self.update_me = to_streamed_response_wrapper(
+ users.update_me,
+ )
class AsyncUsersResourceWithStreamingResponse:
@@ -548,3 +636,6 @@ def __init__(self, users: AsyncUsersResource) -> None:
self.check_access = async_to_streamed_response_wrapper(
users.check_access,
)
+ self.update_me = async_to_streamed_response_wrapper(
+ users.update_me,
+ )
diff --git a/src/whop_sdk/resources/verifications.py b/src/whop_sdk/resources/verifications.py
index 4fce0869..485df1ce 100644
--- a/src/whop_sdk/resources/verifications.py
+++ b/src/whop_sdk/resources/verifications.py
@@ -2,13 +2,14 @@
from __future__ import annotations
-from typing import Optional
+from typing import Dict, Iterable
+from typing_extensions import Literal
import httpx
-from ..types import verification_list_params
+from ..types import verification_list_params, verification_create_params, verification_update_params
from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from .._utils import path_template, maybe_transform
+from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -17,9 +18,11 @@
async_to_raw_response_wrapper,
async_to_streamed_response_wrapper,
)
-from ..pagination import SyncCursorPage, AsyncCursorPage
-from .._base_client import AsyncPaginator, make_request_options
+from .._base_client import make_request_options
from ..types.verification_list_response import VerificationListResponse
+from ..types.verification_create_response import VerificationCreateResponse
+from ..types.verification_delete_response import VerificationDeleteResponse
+from ..types.verification_update_response import VerificationUpdateResponse
from ..types.verification_retrieve_response import VerificationRetrieveResponse
__all__ = ["VerificationsResource", "AsyncVerificationsResource"]
@@ -47,23 +50,122 @@ def with_streaming_response(self) -> VerificationsResourceWithStreamingResponse:
"""
return VerificationsResourceWithStreamingResponse(self)
- def retrieve(
+ def create(
self,
- id: str,
*,
+ account_id: str,
+ address: Dict[str, object] | Omit = omit,
+ business_name: str | Omit = omit,
+ business_structure: str | Omit = omit,
+ business_website: str | Omit = omit,
+ country: str | Omit = omit,
+ date_of_birth: str | Omit = omit,
+ first_name: str | Omit = omit,
+ kind: Literal["individual", "business"] | Omit = omit,
+ last_name: str | Omit = omit,
+ phone: str | Omit = omit,
+ place_of_incorporation: str | Omit = omit,
+ restart: bool | Omit = omit,
+ tax_identification_number: 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.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> VerificationRetrieveResponse:
+ ) -> VerificationCreateResponse:
"""
- Retrieves the details of an existing verification.
+ Creates or resumes a verification session for an account.
+
+ Args:
+ account_id: The account ID to verify (biz\\__ tag).
+
+ address: Optional pre-fill claim. Address (line1, city, state, postal_code).
+
+ business_name: Optional pre-fill claim for businesses.
+
+ business_structure: Optional. Business structure (e.g. llc, corporation).
+
+ business_website: Optional. Business website URL. Accepted for both individual and business
+ verifications on company accounts; persisted to the account's metadata and used
+ to provision the payout account on approval. Whop store pages are rejected.
+
+ country: Optional pre-fill claim. Country code; for businesses, the country of
+ incorporation.
+
+ date_of_birth: Optional pre-fill claim. Seeds the Sumsub session; attested values come from
+ Sumsub on approval.
+
+ first_name: Optional pre-fill claim. Seeds the Sumsub session; attested values come from
+ Sumsub on approval.
+
+ kind: The verification type. Defaults to individual.
+
+ last_name: Optional pre-fill claim. Seeds the Sumsub session; attested values come from
+ Sumsub on approval.
+
+ phone: Optional pre-fill claim — phone number.
- Required permissions:
+ place_of_incorporation: Optional. Place of incorporation (state/region); maps to the business address
+ state.
+
+ restart: Whether to restart an in-flight verification.
+
+ tax_identification_number: Optional. Tax identification number — SSN for individuals, EIN for businesses.
+ Tokenized in transit, never stored raw; stored on the profile so the payout
+ account, provisioned on approval, doesn't raise a tax-id RFI.
+
+ 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(
+ "/verifications",
+ body=maybe_transform(
+ {
+ "address": address,
+ "business_name": business_name,
+ "business_structure": business_structure,
+ "business_website": business_website,
+ "country": country,
+ "date_of_birth": date_of_birth,
+ "first_name": first_name,
+ "kind": kind,
+ "last_name": last_name,
+ "phone": phone,
+ "place_of_incorporation": place_of_incorporation,
+ "restart": restart,
+ "tax_identification_number": tax_identification_number,
+ },
+ verification_create_params.VerificationCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"account_id": account_id}, verification_create_params.VerificationCreateParams),
+ ),
+ cast_to=VerificationCreateResponse,
+ )
- - `payout:account:read`
+ def retrieve(
+ self,
+ verification_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,
+ ) -> VerificationRetrieveResponse:
+ """
+ Retrieves a single identity verification profile by its idpf\\__ tag.
Args:
extra_headers: Send extra headers
@@ -74,49 +176,59 @@ def retrieve(
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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
return self._get(
- path_template("/verifications/{id}", id=id),
+ path_template("/verifications/{verification_id}", verification_id=verification_id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
cast_to=VerificationRetrieveResponse,
)
- def list(
+ def update(
self,
+ verification_id: str,
*,
- payout_account_id: str,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[int] | Omit = omit,
+ business_address: Dict[str, object] | Omit = omit,
+ business_name: str | Omit = omit,
+ business_structure: str | Omit = omit,
+ country: str | Omit = omit,
+ date_of_birth: str | Omit = omit,
+ first_name: str | Omit = omit,
+ last_name: str | Omit = omit,
+ personal_address: Dict[str, object] | Omit = omit,
+ requested_information: Iterable[verification_update_params.RequestedInformation] | 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[VerificationListResponse]:
+ ) -> VerificationUpdateResponse:
"""
- Returns a list of identity verifications for a payout account, ordered by most
- recent first.
+ Updates fields on an identity verification profile, or responds to outstanding
+ RFIs.
- Required permissions:
+ Args:
+ business_address: The business address.
- - `payout:account:read`
+ business_name: The business name.
- Args:
- payout_account_id: The unique identifier of the payout account to list verifications for.
+ business_structure: The business structure.
+
+ country: The country code.
- after: Returns the elements in the list that come after the specified cursor.
+ date_of_birth: The date of birth.
- before: Returns the elements in the list that come before the specified cursor.
+ first_name: The first name on the verification.
- first: Returns the first _n_ elements from the list.
+ last_name: The last name on the verification.
- last: Returns the last _n_ elements from the list.
+ personal_address: The personal address.
+
+ requested_information: Answers to requested information. Each entry must include id and a value,
+ address, or files payload.
extra_headers: Send extra headers
@@ -126,9 +238,63 @@ def list(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return self._get_api_list(
+ if not verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
+ return self._patch(
+ path_template("/verifications/{verification_id}", verification_id=verification_id),
+ body=maybe_transform(
+ {
+ "business_address": business_address,
+ "business_name": business_name,
+ "business_structure": business_structure,
+ "country": country,
+ "date_of_birth": date_of_birth,
+ "first_name": first_name,
+ "last_name": last_name,
+ "personal_address": personal_address,
+ "requested_information": requested_information,
+ },
+ verification_update_params.VerificationUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VerificationUpdateResponse,
+ )
+
+ def list(
+ self,
+ *,
+ account_id: str,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ order: Literal["updated_at", "created_at"] | 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,
+ ) -> VerificationListResponse:
+ """
+ Lists identity verification profiles for an account.
+
+ Args:
+ account_id: The account ID to list verifications for (biz\\__ tag).
+
+ direction: Sort direction.
+
+ order: The field to sort verifications by.
+
+ 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(
"/verifications",
- page=SyncCursorPage[VerificationListResponse],
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -136,16 +302,47 @@ def list(
timeout=timeout,
query=maybe_transform(
{
- "payout_account_id": payout_account_id,
- "after": after,
- "before": before,
- "first": first,
- "last": last,
+ "account_id": account_id,
+ "direction": direction,
+ "order": order,
},
verification_list_params.VerificationListParams,
),
),
- model=VerificationListResponse,
+ cast_to=VerificationListResponse,
+ )
+
+ def delete(
+ self,
+ verification_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,
+ ) -> VerificationDeleteResponse:
+ """
+ Unlinks a verification from the caller's accounts.
+
+ 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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
+ return self._delete(
+ path_template("/verifications/{verification_id}", verification_id=verification_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VerificationDeleteResponse,
)
@@ -171,23 +368,124 @@ def with_streaming_response(self) -> AsyncVerificationsResourceWithStreamingResp
"""
return AsyncVerificationsResourceWithStreamingResponse(self)
- async def retrieve(
+ async def create(
self,
- id: str,
*,
+ account_id: str,
+ address: Dict[str, object] | Omit = omit,
+ business_name: str | Omit = omit,
+ business_structure: str | Omit = omit,
+ business_website: str | Omit = omit,
+ country: str | Omit = omit,
+ date_of_birth: str | Omit = omit,
+ first_name: str | Omit = omit,
+ kind: Literal["individual", "business"] | Omit = omit,
+ last_name: str | Omit = omit,
+ phone: str | Omit = omit,
+ place_of_incorporation: str | Omit = omit,
+ restart: bool | Omit = omit,
+ tax_identification_number: 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.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> VerificationRetrieveResponse:
+ ) -> VerificationCreateResponse:
"""
- Retrieves the details of an existing verification.
+ Creates or resumes a verification session for an account.
+
+ Args:
+ account_id: The account ID to verify (biz\\__ tag).
+
+ address: Optional pre-fill claim. Address (line1, city, state, postal_code).
+
+ business_name: Optional pre-fill claim for businesses.
+
+ business_structure: Optional. Business structure (e.g. llc, corporation).
- Required permissions:
+ business_website: Optional. Business website URL. Accepted for both individual and business
+ verifications on company accounts; persisted to the account's metadata and used
+ to provision the payout account on approval. Whop store pages are rejected.
- - `payout:account:read`
+ country: Optional pre-fill claim. Country code; for businesses, the country of
+ incorporation.
+
+ date_of_birth: Optional pre-fill claim. Seeds the Sumsub session; attested values come from
+ Sumsub on approval.
+
+ first_name: Optional pre-fill claim. Seeds the Sumsub session; attested values come from
+ Sumsub on approval.
+
+ kind: The verification type. Defaults to individual.
+
+ last_name: Optional pre-fill claim. Seeds the Sumsub session; attested values come from
+ Sumsub on approval.
+
+ phone: Optional pre-fill claim — phone number.
+
+ place_of_incorporation: Optional. Place of incorporation (state/region); maps to the business address
+ state.
+
+ restart: Whether to restart an in-flight verification.
+
+ tax_identification_number: Optional. Tax identification number — SSN for individuals, EIN for businesses.
+ Tokenized in transit, never stored raw; stored on the profile so the payout
+ account, provisioned on approval, doesn't raise a tax-id RFI.
+
+ 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(
+ "/verifications",
+ body=await async_maybe_transform(
+ {
+ "address": address,
+ "business_name": business_name,
+ "business_structure": business_structure,
+ "business_website": business_website,
+ "country": country,
+ "date_of_birth": date_of_birth,
+ "first_name": first_name,
+ "kind": kind,
+ "last_name": last_name,
+ "phone": phone,
+ "place_of_incorporation": place_of_incorporation,
+ "restart": restart,
+ "tax_identification_number": tax_identification_number,
+ },
+ verification_create_params.VerificationCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {"account_id": account_id}, verification_create_params.VerificationCreateParams
+ ),
+ ),
+ cast_to=VerificationCreateResponse,
+ )
+
+ async def retrieve(
+ self,
+ verification_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,
+ ) -> VerificationRetrieveResponse:
+ """
+ Retrieves a single identity verification profile by its idpf\\__ tag.
Args:
extra_headers: Send extra headers
@@ -198,49 +496,114 @@ async def retrieve(
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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
return await self._get(
- path_template("/verifications/{id}", id=id),
+ path_template("/verifications/{verification_id}", verification_id=verification_id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
cast_to=VerificationRetrieveResponse,
)
- def list(
+ async def update(
self,
+ verification_id: str,
*,
- payout_account_id: str,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[int] | Omit = omit,
+ business_address: Dict[str, object] | Omit = omit,
+ business_name: str | Omit = omit,
+ business_structure: str | Omit = omit,
+ country: str | Omit = omit,
+ date_of_birth: str | Omit = omit,
+ first_name: str | Omit = omit,
+ last_name: str | Omit = omit,
+ personal_address: Dict[str, object] | Omit = omit,
+ requested_information: Iterable[verification_update_params.RequestedInformation] | 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[VerificationListResponse, AsyncCursorPage[VerificationListResponse]]:
+ ) -> VerificationUpdateResponse:
"""
- Returns a list of identity verifications for a payout account, ordered by most
- recent first.
+ Updates fields on an identity verification profile, or responds to outstanding
+ RFIs.
- Required permissions:
+ Args:
+ business_address: The business address.
- - `payout:account:read`
+ business_name: The business name.
- Args:
- payout_account_id: The unique identifier of the payout account to list verifications for.
+ business_structure: The business structure.
+
+ country: The country code.
+
+ date_of_birth: The date of birth.
+
+ first_name: The first name on the verification.
+
+ last_name: The last name on the verification.
+
+ personal_address: The personal address.
+
+ requested_information: Answers to requested information. Each entry must include id and a value,
+ address, or files payload.
+
+ 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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
+ return await self._patch(
+ path_template("/verifications/{verification_id}", verification_id=verification_id),
+ body=await async_maybe_transform(
+ {
+ "business_address": business_address,
+ "business_name": business_name,
+ "business_structure": business_structure,
+ "country": country,
+ "date_of_birth": date_of_birth,
+ "first_name": first_name,
+ "last_name": last_name,
+ "personal_address": personal_address,
+ "requested_information": requested_information,
+ },
+ verification_update_params.VerificationUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VerificationUpdateResponse,
+ )
- after: Returns the elements in the list that come after the specified cursor.
+ async def list(
+ self,
+ *,
+ account_id: str,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ order: Literal["updated_at", "created_at"] | 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,
+ ) -> VerificationListResponse:
+ """
+ Lists identity verification profiles for an account.
- before: Returns the elements in the list that come before the specified cursor.
+ Args:
+ account_id: The account ID to list verifications for (biz\\__ tag).
- first: Returns the first _n_ elements from the list.
+ direction: Sort direction.
- last: Returns the last _n_ elements from the list.
+ order: The field to sort verifications by.
extra_headers: Send extra headers
@@ -250,26 +613,56 @@ def list(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return self._get_api_list(
+ return await self._get(
"/verifications",
- page=AsyncCursorPage[VerificationListResponse],
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
- query=maybe_transform(
+ query=await async_maybe_transform(
{
- "payout_account_id": payout_account_id,
- "after": after,
- "before": before,
- "first": first,
- "last": last,
+ "account_id": account_id,
+ "direction": direction,
+ "order": order,
},
verification_list_params.VerificationListParams,
),
),
- model=VerificationListResponse,
+ cast_to=VerificationListResponse,
+ )
+
+ async def delete(
+ self,
+ verification_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,
+ ) -> VerificationDeleteResponse:
+ """
+ Unlinks a verification from the caller's accounts.
+
+ 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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
+ return await self._delete(
+ path_template("/verifications/{verification_id}", verification_id=verification_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VerificationDeleteResponse,
)
@@ -277,45 +670,81 @@ class VerificationsResourceWithRawResponse:
def __init__(self, verifications: VerificationsResource) -> None:
self._verifications = verifications
+ self.create = to_raw_response_wrapper(
+ verifications.create,
+ )
self.retrieve = to_raw_response_wrapper(
verifications.retrieve,
)
+ self.update = to_raw_response_wrapper(
+ verifications.update,
+ )
self.list = to_raw_response_wrapper(
verifications.list,
)
+ self.delete = to_raw_response_wrapper(
+ verifications.delete,
+ )
class AsyncVerificationsResourceWithRawResponse:
def __init__(self, verifications: AsyncVerificationsResource) -> None:
self._verifications = verifications
+ self.create = async_to_raw_response_wrapper(
+ verifications.create,
+ )
self.retrieve = async_to_raw_response_wrapper(
verifications.retrieve,
)
+ self.update = async_to_raw_response_wrapper(
+ verifications.update,
+ )
self.list = async_to_raw_response_wrapper(
verifications.list,
)
+ self.delete = async_to_raw_response_wrapper(
+ verifications.delete,
+ )
class VerificationsResourceWithStreamingResponse:
def __init__(self, verifications: VerificationsResource) -> None:
self._verifications = verifications
+ self.create = to_streamed_response_wrapper(
+ verifications.create,
+ )
self.retrieve = to_streamed_response_wrapper(
verifications.retrieve,
)
+ self.update = to_streamed_response_wrapper(
+ verifications.update,
+ )
self.list = to_streamed_response_wrapper(
verifications.list,
)
+ self.delete = to_streamed_response_wrapper(
+ verifications.delete,
+ )
class AsyncVerificationsResourceWithStreamingResponse:
def __init__(self, verifications: AsyncVerificationsResource) -> None:
self._verifications = verifications
+ self.create = async_to_streamed_response_wrapper(
+ verifications.create,
+ )
self.retrieve = async_to_streamed_response_wrapper(
verifications.retrieve,
)
+ self.update = async_to_streamed_response_wrapper(
+ verifications.update,
+ )
self.list = async_to_streamed_response_wrapper(
verifications.list,
)
+ self.delete = async_to_streamed_response_wrapper(
+ verifications.delete,
+ )
diff --git a/src/whop_sdk/resources/wallets.py b/src/whop_sdk/resources/wallets.py
deleted file mode 100644
index 42e8018d..00000000
--- a/src/whop_sdk/resources/wallets.py
+++ /dev/null
@@ -1,321 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import httpx
-
-from ..types import wallet_send_params
-from .._types import Body, Query, Headers, NotGiven, not_given
-from .._utils import path_template, 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 .._base_client import make_request_options
-from ..types.wallet_list_response import WalletListResponse
-from ..types.wallet_send_response import WalletSendResponse
-from ..types.wallet_balance_response import WalletBalanceResponse
-
-__all__ = ["WalletsResource", "AsyncWalletsResource"]
-
-
-class WalletsResource(SyncAPIResource):
- @cached_property
- def with_raw_response(self) -> WalletsResourceWithRawResponse:
- """
- 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 WalletsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> WalletsResourceWithStreamingResponse:
- """
- 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 WalletsResourceWithStreamingResponse(self)
-
- def list(
- self,
- *,
- # 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,
- ) -> WalletListResponse:
- """Lists every crypto wallet linked to the authenticated resource."""
- return self._get(
- "/wallets",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=WalletListResponse,
- )
-
- def balance(
- self,
- account_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,
- ) -> WalletBalanceResponse:
- """
- Returns per-token balances held in an account's wallet.
-
- 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 account_id:
- raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}")
- return self._get(
- path_template("/wallets/{account_id}/balance", account_id=account_id),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=WalletBalanceResponse,
- )
-
- def send(
- self,
- account_id: str,
- *,
- amount: str,
- to: 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,
- ) -> WalletSendResponse:
- """
- Sends USDT from an account's wallet to another Whop user or business.
-
- Args:
- amount: USDT amount to send.
-
- to: Recipient user ID, business account ID, ledger account ID, or email.
-
- 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 account_id:
- raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}")
- return self._post(
- path_template("/wallets/{account_id}/sends", account_id=account_id),
- body=maybe_transform(
- {
- "amount": amount,
- "to": to,
- },
- wallet_send_params.WalletSendParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=WalletSendResponse,
- )
-
-
-class AsyncWalletsResource(AsyncAPIResource):
- @cached_property
- def with_raw_response(self) -> AsyncWalletsResourceWithRawResponse:
- """
- 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 AsyncWalletsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncWalletsResourceWithStreamingResponse:
- """
- 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 AsyncWalletsResourceWithStreamingResponse(self)
-
- async def list(
- self,
- *,
- # 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,
- ) -> WalletListResponse:
- """Lists every crypto wallet linked to the authenticated resource."""
- return await self._get(
- "/wallets",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=WalletListResponse,
- )
-
- async def balance(
- self,
- account_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,
- ) -> WalletBalanceResponse:
- """
- Returns per-token balances held in an account's wallet.
-
- 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 account_id:
- raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}")
- return await self._get(
- path_template("/wallets/{account_id}/balance", account_id=account_id),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=WalletBalanceResponse,
- )
-
- async def send(
- self,
- account_id: str,
- *,
- amount: str,
- to: 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,
- ) -> WalletSendResponse:
- """
- Sends USDT from an account's wallet to another Whop user or business.
-
- Args:
- amount: USDT amount to send.
-
- to: Recipient user ID, business account ID, ledger account ID, or email.
-
- 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 account_id:
- raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}")
- return await self._post(
- path_template("/wallets/{account_id}/sends", account_id=account_id),
- body=await async_maybe_transform(
- {
- "amount": amount,
- "to": to,
- },
- wallet_send_params.WalletSendParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=WalletSendResponse,
- )
-
-
-class WalletsResourceWithRawResponse:
- def __init__(self, wallets: WalletsResource) -> None:
- self._wallets = wallets
-
- self.list = to_raw_response_wrapper(
- wallets.list,
- )
- self.balance = to_raw_response_wrapper(
- wallets.balance,
- )
- self.send = to_raw_response_wrapper(
- wallets.send,
- )
-
-
-class AsyncWalletsResourceWithRawResponse:
- def __init__(self, wallets: AsyncWalletsResource) -> None:
- self._wallets = wallets
-
- self.list = async_to_raw_response_wrapper(
- wallets.list,
- )
- self.balance = async_to_raw_response_wrapper(
- wallets.balance,
- )
- self.send = async_to_raw_response_wrapper(
- wallets.send,
- )
-
-
-class WalletsResourceWithStreamingResponse:
- def __init__(self, wallets: WalletsResource) -> None:
- self._wallets = wallets
-
- self.list = to_streamed_response_wrapper(
- wallets.list,
- )
- self.balance = to_streamed_response_wrapper(
- wallets.balance,
- )
- self.send = to_streamed_response_wrapper(
- wallets.send,
- )
-
-
-class AsyncWalletsResourceWithStreamingResponse:
- def __init__(self, wallets: AsyncWalletsResource) -> None:
- self._wallets = wallets
-
- self.list = async_to_streamed_response_wrapper(
- wallets.list,
- )
- self.balance = async_to_streamed_response_wrapper(
- wallets.balance,
- )
- self.send = async_to_streamed_response_wrapper(
- wallets.send,
- )
diff --git a/src/whop_sdk/resources/withdrawals.py b/src/whop_sdk/resources/withdrawals.py
index 0eb7bde9..78a2336c 100644
--- a/src/whop_sdk/resources/withdrawals.py
+++ b/src/whop_sdk/resources/withdrawals.py
@@ -83,7 +83,7 @@ def create(
payout_method_id: The ID of the payout method to use for the withdrawal.
- platform_covers_fees: Whether the platform covers the payout fees instead of the connected account.
+ platform_covers_fees: Whether the platform covers the payout fees.
statement_descriptor: Custom statement descriptor for the withdrawal. Must be between 5 and 22
characters and contain only alphanumeric characters.
@@ -285,7 +285,7 @@ async def create(
payout_method_id: The ID of the payout method to use for the withdrawal.
- platform_covers_fees: Whether the platform covers the payout fees instead of the connected account.
+ platform_covers_fees: Whether the platform covers the payout fees.
statement_descriptor: Custom statement descriptor for the withdrawal. Must be between 5 and 22
characters and contain only alphanumeric characters.
diff --git a/src/whop_sdk/types/__init__.py b/src/whop_sdk/types/__init__.py
index c41c9b9b..e7bc92ff 100644
--- a/src/whop_sdk/types/__init__.py
+++ b/src/whop_sdk/types/__init__.py
@@ -24,7 +24,6 @@
PlanType as PlanType,
Reaction as Reaction,
Shipment as Shipment,
- Transfer as Transfer,
CustomCta as CustomCta,
Direction as Direction,
ForumPost as ForumPost,
@@ -74,6 +73,7 @@
from .webhook import Webhook as Webhook
from .ad_group import AdGroup as AdGroup
from .app_type import AppType as AppType
+from .audience import Audience as Audience
from .affiliate import Affiliate as Affiliate
from .dm_member import DmMember as DmMember
from .languages import Languages as Languages
@@ -92,60 +92,69 @@
from .review_status import ReviewStatus as ReviewStatus
from .upload_status import UploadStatus as UploadStatus
from .webhook_event import WebhookEvent as WebhookEvent
-from .account_wallet import AccountWallet as AccountWallet
-from .ad_budget_type import AdBudgetType as AdBudgetType
from .ad_list_params import AdListParams as AdListParams
from .cancel_options import CancelOptions as CancelOptions
from .checkout_modes import CheckoutModes as CheckoutModes
from .checkout_shape import CheckoutShape as CheckoutShape
from .course_chapter import CourseChapter as CourseChapter
from .promo_duration import PromoDuration as PromoDuration
-from .ad_group_status import AdGroupStatus as AdGroupStatus
+from .social_account import SocialAccount as SocialAccount
from .app_list_params import AppListParams as AppListParams
from .authorized_user import AuthorizedUser as AuthorizedUser
from .billing_reasons import BillingReasons as BillingReasons
from .fee_markup_type import FeeMarkupType as FeeMarkupType
from .file_visibility import FileVisibility as FileVisibility
-from .ad_list_response import AdListResponse as AdListResponse
+from .ad_create_params import AdCreateParams as AdCreateParams
+from .ad_update_params import AdUpdateParams as AdUpdateParams
+from .card_list_params import CardListParams as CardListParams
from .dispute_statuses import DisputeStatuses as DisputeStatuses
from .lead_list_params import LeadListParams as LeadListParams
from .payment_provider import PaymentProvider as PaymentProvider
from .plan_list_params import PlanListParams as PlanListParams
+from .swap_list_params import SwapListParams as SwapListParams
from .user_list_params import UserListParams as UserListParams
from .app_create_params import AppCreateParams as AppCreateParams
from .app_list_response import AppListResponse as AppListResponse
from .app_update_params import AppUpdateParams as AppUpdateParams
from .entry_list_params import EntryListParams as EntryListParams
+from .event_list_params import EventListParams as EventListParams
from .forum_list_params import ForumListParams as ForumListParams
from .promo_code_status import PromoCodeStatus as PromoCodeStatus
from .result_label_keys import ResultLabelKeys as ResultLabelKeys
from .withdrawal_speeds import WithdrawalSpeeds as WithdrawalSpeeds
from .withdrawal_status import WithdrawalStatus as WithdrawalStatus
-from .ad_campaign_status import AdCampaignStatus as AdCampaignStatus
+from .ad_delete_response import AdDeleteResponse as AdDeleteResponse
+from .ad_retrieve_params import AdRetrieveParams as AdRetrieveParams
from .bounty_list_params import BountyListParams as BountyListParams
+from .card_create_params import CardCreateParams as CardCreateParams
+from .card_list_response import CardListResponse as CardListResponse
from .course_list_params import CourseListParams as CourseListParams
from .dispute_alert_type import DisputeAlertType as DisputeAlertType
-from .external_ad_status import ExternalAdStatus as ExternalAdStatus
from .file_create_params import FileCreateParams as FileCreateParams
from .lead_create_params import LeadCreateParams as LeadCreateParams
from .lead_list_response import LeadListResponse as LeadListResponse
from .lead_update_params import LeadUpdateParams as LeadUpdateParams
from .member_list_params import MemberListParams as MemberListParams
+from .payout_list_params import PayoutListParams as PayoutListParams
+from .person_list_params import PersonListParams as PersonListParams
from .plan_create_params import PlanCreateParams as PlanCreateParams
from .plan_list_response import PlanListResponse as PlanListResponse
from .plan_update_params import PlanUpdateParams as PlanUpdateParams
from .refund_list_params import RefundListParams as RefundListParams
from .review_list_params import ReviewListParams as ReviewListParams
-from .user_list_response import UserListResponse as UserListResponse
+from .stat_list_response import StatListResponse as StatListResponse
+from .swap_create_params import SwapCreateParams as SwapCreateParams
+from .swap_list_response import SwapListResponse as SwapListResponse
from .user_update_params import UserUpdateParams as UserUpdateParams
-from .wallet_send_params import WalletSendParams as WalletSendParams
from .account_list_params import AccountListParams as AccountListParams
from .account_social_link import AccountSocialLink as AccountSocialLink
from .ai_chat_list_params import AIChatListParams as AIChatListParams
from .company_list_params import CompanyListParams as CompanyListParams
from .course_visibilities import CourseVisibilities as CourseVisibilities
+from .deposit_list_params import DepositListParams as DepositListParams
from .dispute_list_params import DisputeListParams as DisputeListParams
from .entry_list_response import EntryListResponse as EntryListResponse
+from .event_list_response import EventListResponse as EventListResponse
from .forum_list_response import ForumListResponse as ForumListResponse
from .forum_update_params import ForumUpdateParams as ForumUpdateParams
from .invoice_list_params import InvoiceListParams as InvoiceListParams
@@ -154,20 +163,25 @@
from .payment_list_params import PaymentListParams as PaymentListParams
from .product_list_params import ProductListParams as ProductListParams
from .setup_intent_status import SetupIntentStatus as SetupIntentStatus
+from .social_account_post import SocialAccountPost as SocialAccountPost
from .tax_identifier_type import TaxIdentifierType as TaxIdentifierType
from .topup_create_params import TopupCreateParams as TopupCreateParams
from .verification_status import VerificationStatus as VerificationStatus
from .webhook_list_params import WebhookListParams as WebhookListParams
-from .ad_campaign_platform import AdCampaignPlatform as AdCampaignPlatform
from .ad_group_list_params import AdGroupListParams as AdGroupListParams
+from .audience_list_params import AudienceListParams as AudienceListParams
from .bounty_create_params import BountyCreateParams as BountyCreateParams
from .bounty_list_response import BountyListResponse as BountyListResponse
+from .card_create_response import CardCreateResponse as CardCreateResponse
+from .card_retrieve_params import CardRetrieveParams as CardRetrieveParams
from .course_create_params import CourseCreateParams as CourseCreateParams
from .course_list_response import CourseListResponse as CourseListResponse
from .course_update_params import CourseUpdateParams as CourseUpdateParams
from .file_create_response import FileCreateResponse as FileCreateResponse
from .member_list_response import MemberListResponse as MemberListResponse
from .payment_method_types import PaymentMethodTypes as PaymentMethodTypes
+from .payout_list_response import PayoutListResponse as PayoutListResponse
+from .person_list_response import PersonListResponse as PersonListResponse
from .plan_delete_response import PlanDeleteResponse as PlanDeleteResponse
from .reaction_list_params import ReactionListParams as ReactionListParams
from .receipt_tax_behavior import ReceiptTaxBehavior as ReceiptTaxBehavior
@@ -175,14 +189,13 @@
from .review_list_response import ReviewListResponse as ReviewListResponse
from .shipment_list_params import ShipmentListParams as ShipmentListParams
from .social_link_websites import SocialLinkWebsites as SocialLinkWebsites
+from .stat_retrieve_params import StatRetrieveParams as StatRetrieveParams
+from .swap_create_response import SwapCreateResponse as SwapCreateResponse
from .transfer_list_params import TransferListParams as TransferListParams
from .unwrap_webhook_event import UnwrapWebhookEvent as UnwrapWebhookEvent
from .user_retrieve_params import UserRetrieveParams as UserRetrieveParams
-from .wallet_list_response import WalletListResponse as WalletListResponse
-from .wallet_send_response import WalletSendResponse as WalletSendResponse
from .withdrawal_fee_types import WithdrawalFeeTypes as WithdrawalFeeTypes
from .account_create_params import AccountCreateParams as AccountCreateParams
-from .account_list_response import AccountListResponse as AccountListResponse
from .account_update_params import AccountUpdateParams as AccountUpdateParams
from .affiliate_list_params import AffiliateListParams as AffiliateListParams
from .ai_chat_create_params import AIChatCreateParams as AIChatCreateParams
@@ -193,6 +206,7 @@
from .company_list_response import CompanyListResponse as CompanyListResponse
from .company_update_params import CompanyUpdateParams as CompanyUpdateParams
from .deposit_create_params import DepositCreateParams as DepositCreateParams
+from .deposit_list_response import DepositListResponse as DepositListResponse
from .dispute_list_response import DisputeListResponse as DisputeListResponse
from .dm_member_list_params import DmMemberListParams as DmMemberListParams
from .invoice_create_params import InvoiceCreateParams as InvoiceCreateParams
@@ -208,12 +222,15 @@
from .product_update_params import ProductUpdateParams as ProductUpdateParams
from .refund_reference_type import RefundReferenceType as RefundReferenceType
from .topup_create_response import TopupCreateResponse as TopupCreateResponse
+from .user_update_me_params import UserUpdateMeParams as UserUpdateMeParams
from .webhook_create_params import WebhookCreateParams as WebhookCreateParams
from .webhook_list_response import WebhookListResponse as WebhookListResponse
from .webhook_update_params import WebhookUpdateParams as WebhookUpdateParams
-from .ad_group_list_response import AdGroupListResponse as AdGroupListResponse
+from .ad_group_create_params import AdGroupCreateParams as AdGroupCreateParams
from .ad_group_update_params import AdGroupUpdateParams as AdGroupUpdateParams
+from .audience_create_params import AudienceCreateParams as AudienceCreateParams
from .bounty_create_response import BountyCreateResponse as BountyCreateResponse
+from .card_retrieve_response import CardRetrieveResponse as CardRetrieveResponse
from .course_delete_response import CourseDeleteResponse as CourseDeleteResponse
from .dm_channel_list_params import DmChannelListParams as DmChannelListParams
from .entry_approve_response import EntryApproveResponse as EntryApproveResponse
@@ -222,12 +239,15 @@
from .file_retrieve_response import FileRetrieveResponse as FileRetrieveResponse
from .forum_post_list_params import ForumPostListParams as ForumPostListParams
from .membership_list_params import MembershipListParams as MembershipListParams
+from .person_retrieve_params import PersonRetrieveParams as PersonRetrieveParams
from .promo_code_list_params import PromoCodeListParams as PromoCodeListParams
from .reaction_create_params import ReactionCreateParams as ReactionCreateParams
from .reaction_delete_params import ReactionDeleteParams as ReactionDeleteParams
from .reaction_list_response import ReactionListResponse as ReactionListResponse
from .shipment_create_params import ShipmentCreateParams as ShipmentCreateParams
from .shipment_list_response import ShipmentListResponse as ShipmentListResponse
+from .stat_retrieve_response import StatRetrieveResponse as StatRetrieveResponse
+from .swap_retrieve_response import SwapRetrieveResponse as SwapRetrieveResponse
from .transfer_create_params import TransferCreateParams as TransferCreateParams
from .transfer_list_response import TransferListResponse as TransferListResponse
from .withdrawal_list_params import WithdrawalListParams as WithdrawalListParams
@@ -248,10 +268,11 @@
from .product_delete_response import ProductDeleteResponse as ProductDeleteResponse
from .refund_reference_status import RefundReferenceStatus as RefundReferenceStatus
from .verification_error_code import VerificationErrorCode as VerificationErrorCode
-from .wallet_balance_response import WalletBalanceResponse as WalletBalanceResponse
from .webhook_create_response import WebhookCreateResponse as WebhookCreateResponse
from .webhook_delete_response import WebhookDeleteResponse as WebhookDeleteResponse
from .ad_group_delete_response import AdGroupDeleteResponse as AdGroupDeleteResponse
+from .ad_group_retrieve_params import AdGroupRetrieveParams as AdGroupRetrieveParams
+from .audience_delete_response import AudienceDeleteResponse as AudienceDeleteResponse
from .bounty_retrieve_response import BountyRetrieveResponse as BountyRetrieveResponse
from .chat_channel_list_params import ChatChannelListParams as ChatChannelListParams
from .conversion_create_params import ConversionCreateParams as ConversionCreateParams
@@ -274,6 +295,7 @@
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 .person_retrieve_response import PersonRetrieveResponse as PersonRetrieveResponse
from .promo_code_create_params import PromoCodeCreateParams as PromoCodeCreateParams
from .promo_code_list_response import PromoCodeListResponse as PromoCodeListResponse
from .reaction_delete_response import ReactionDeleteResponse as ReactionDeleteResponse
@@ -281,10 +303,11 @@
from .review_retrieve_response import ReviewRetrieveResponse as ReviewRetrieveResponse
from .setup_intent_list_params import SetupIntentListParams as SetupIntentListParams
from .swap_create_quote_params import SwapCreateQuoteParams as SwapCreateQuoteParams
+from .transfer_create_response import TransferCreateResponse as TransferCreateResponse
from .verification_list_params import VerificationListParams as VerificationListParams
from .withdrawal_create_params import WithdrawalCreateParams as WithdrawalCreateParams
from .withdrawal_list_response import WithdrawalListResponse as WithdrawalListResponse
-from .ad_campaign_list_response import AdCampaignListResponse as AdCampaignListResponse
+from .ad_campaign_create_params import AdCampaignCreateParams as AdCampaignCreateParams
from .ad_campaign_update_params import AdCampaignUpdateParams as AdCampaignUpdateParams
from .ad_report_retrieve_params import AdReportRetrieveParams as AdReportRetrieveParams
from .assessment_question_types import AssessmentQuestionTypes as AssessmentQuestionTypes
@@ -293,6 +316,7 @@
from .dispute_alert_list_params import DisputeAlertListParams as DisputeAlertListParams
from .dm_member_delete_response import DmMemberDeleteResponse as DmMemberDeleteResponse
from .payout_method_list_params import PayoutMethodListParams as PayoutMethodListParams
+from .plan_calculate_tax_params import PlanCalculateTaxParams as PlanCalculateTaxParams
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
@@ -314,9 +338,15 @@
from .payment_method_list_params import PaymentMethodListParams as PaymentMethodListParams
from .promo_code_delete_response import PromoCodeDeleteResponse as PromoCodeDeleteResponse
from .setup_intent_list_response import SetupIntentListResponse as SetupIntentListResponse
+from .social_account_list_params import SocialAccountListParams as SocialAccountListParams
from .swap_create_quote_response import SwapCreateQuoteResponse as SwapCreateQuoteResponse
+from .transfer_retrieve_response import TransferRetrieveResponse as TransferRetrieveResponse
from .user_check_access_response import UserCheckAccessResponse as UserCheckAccessResponse
+from .verification_create_params import VerificationCreateParams as VerificationCreateParams
from .verification_list_response import VerificationListResponse as VerificationListResponse
+from .verification_update_params import VerificationUpdateParams as VerificationUpdateParams
+from .ad_campaign_delete_response import AdCampaignDeleteResponse as AdCampaignDeleteResponse
+from .ad_campaign_retrieve_params import AdCampaignRetrieveParams as AdCampaignRetrieveParams
from .ad_report_retrieve_response import AdReportRetrieveResponse as AdReportRetrieveResponse
from .authorized_user_list_params import AuthorizedUserListParams as AuthorizedUserListParams
from .course_lesson_create_params import CourseLessonCreateParams as CourseLessonCreateParams
@@ -328,6 +358,8 @@
from .experience_duplicate_params import ExperienceDuplicateParams as ExperienceDuplicateParams
from .payout_destination_category import PayoutDestinationCategory as PayoutDestinationCategory
from .payout_method_list_response import PayoutMethodListResponse as PayoutMethodListResponse
+from .plan_calculate_tax_response import PlanCalculateTaxResponse as PlanCalculateTaxResponse
+from .social_account_posts_params import SocialAccountPostsParams as SocialAccountPostsParams
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
@@ -344,6 +376,11 @@
from .payment_method_list_response import PaymentMethodListResponse as PaymentMethodListResponse
from .refund_created_webhook_event import RefundCreatedWebhookEvent as RefundCreatedWebhookEvent
from .refund_updated_webhook_event import RefundUpdatedWebhookEvent as RefundUpdatedWebhookEvent
+from .social_account_create_params import SocialAccountCreateParams as SocialAccountCreateParams
+from .social_account_delete_params import SocialAccountDeleteParams as SocialAccountDeleteParams
+from .verification_create_response import VerificationCreateResponse as VerificationCreateResponse
+from .verification_delete_response import VerificationDeleteResponse as VerificationDeleteResponse
+from .verification_update_response import VerificationUpdateResponse as VerificationUpdateResponse
from .authorized_user_create_params import AuthorizedUserCreateParams as AuthorizedUserCreateParams
from .authorized_user_delete_params import AuthorizedUserDeleteParams as AuthorizedUserDeleteParams
from .authorized_user_list_response import AuthorizedUserListResponse as AuthorizedUserListResponse
@@ -355,13 +392,17 @@
from .payment_created_webhook_event import PaymentCreatedWebhookEvent as PaymentCreatedWebhookEvent
from .payment_pending_webhook_event import PaymentPendingWebhookEvent as PaymentPendingWebhookEvent
from .resolution_center_case_status import ResolutionCenterCaseStatus as ResolutionCenterCaseStatus
+from .social_account_posts_response import SocialAccountPostsResponse as SocialAccountPostsResponse
from .support_channel_create_params import SupportChannelCreateParams as SupportChannelCreateParams
from .support_channel_list_response import SupportChannelListResponse as SupportChannelListResponse
from .company_token_transaction_type import CompanyTokenTransactionType as CompanyTokenTransactionType
from .course_chapter_delete_response import CourseChapterDeleteResponse as CourseChapterDeleteResponse
from .dispute_update_evidence_params import DisputeUpdateEvidenceParams as DisputeUpdateEvidenceParams
+from .financial_activity_list_params import FinancialActivityListParams as FinancialActivityListParams
from .invoice_past_due_webhook_event import InvoicePastDueWebhookEvent as InvoicePastDueWebhookEvent
from .payment_method_retrieve_params import PaymentMethodRetrieveParams as PaymentMethodRetrieveParams
+from .social_account_create_response import SocialAccountCreateResponse as SocialAccountCreateResponse
+from .social_account_delete_response import SocialAccountDeleteResponse as SocialAccountDeleteResponse
from .verification_retrieve_response import VerificationRetrieveResponse as VerificationRetrieveResponse
from .authorized_user_delete_response import AuthorizedUserDeleteResponse as AuthorizedUserDeleteResponse
from .company_create_api_key_response import CompanyCreateAPIKeyResponse as CompanyCreateAPIKeyResponse
@@ -370,16 +411,19 @@
from .payment_succeeded_webhook_event import PaymentSucceededWebhookEvent as PaymentSucceededWebhookEvent
from .payout_method_retrieve_response import PayoutMethodRetrieveResponse as PayoutMethodRetrieveResponse
from .course_student_retrieve_response import CourseStudentRetrieveResponse as CourseStudentRetrieveResponse
+from .financial_activity_list_response import FinancialActivityListResponse as FinancialActivityListResponse
from .ledger_account_retrieve_response import LedgerAccountRetrieveResponse as LedgerAccountRetrieveResponse
from .payment_method_retrieve_response import PaymentMethodRetrieveResponse as PaymentMethodRetrieveResponse
from .payout_account_retrieve_response import PayoutAccountRetrieveResponse as PayoutAccountRetrieveResponse
from .withdrawal_created_webhook_event import WithdrawalCreatedWebhookEvent as WithdrawalCreatedWebhookEvent
from .withdrawal_updated_webhook_event import WithdrawalUpdatedWebhookEvent as WithdrawalUpdatedWebhookEvent
from .resolution_center_case_issue_type import ResolutionCenterCaseIssueType as ResolutionCenterCaseIssueType
+from .chat_message_created_webhook_event import ChatMessageCreatedWebhookEvent as ChatMessageCreatedWebhookEvent
from .checkout_configuration_list_params import CheckoutConfigurationListParams as CheckoutConfigurationListParams
from .membership_activated_webhook_event import MembershipActivatedWebhookEvent as MembershipActivatedWebhookEvent
from .payout_account_calculated_statuses import PayoutAccountCalculatedStatuses as PayoutAccountCalculatedStatuses
from .resolution_center_case_list_params import ResolutionCenterCaseListParams as ResolutionCenterCaseListParams
+from .chat_reaction_created_webhook_event import ChatReactionCreatedWebhookEvent as ChatReactionCreatedWebhookEvent
from .dispute_alert_created_webhook_event import DisputeAlertCreatedWebhookEvent as DisputeAlertCreatedWebhookEvent
from .invoice_mark_uncollectible_response import InvoiceMarkUncollectibleResponse as InvoiceMarkUncollectibleResponse
from .payout_method_created_webhook_event import PayoutMethodCreatedWebhookEvent as PayoutMethodCreatedWebhookEvent
@@ -396,6 +440,9 @@
from .course_lesson_interaction_list_params import (
CourseLessonInteractionListParams as CourseLessonInteractionListParams,
)
+from .checkout_configuration_create_response import (
+ CheckoutConfigurationCreateResponse as CheckoutConfigurationCreateResponse,
+)
from .course_lesson_submit_assessment_params import (
CourseLessonSubmitAssessmentParams as CourseLessonSubmitAssessmentParams,
)
@@ -417,6 +464,9 @@
from .identity_profile_rejected_webhook_event import (
IdentityProfileRejectedWebhookEvent as IdentityProfileRejectedWebhookEvent,
)
+from .checkout_configuration_retrieve_response import (
+ CheckoutConfigurationRetrieveResponse as CheckoutConfigurationRetrieveResponse,
+)
from .course_lesson_mark_as_completed_response import (
CourseLessonMarkAsCompletedResponse as CourseLessonMarkAsCompletedResponse,
)
@@ -438,6 +488,9 @@
from .invoice_marked_uncollectible_webhook_event import (
InvoiceMarkedUncollectibleWebhookEvent as InvoiceMarkedUncollectibleWebhookEvent,
)
+from .membership_trial_ending_soon_webhook_event import (
+ MembershipTrialEndingSoonWebhookEvent as MembershipTrialEndingSoonWebhookEvent,
+)
from .setup_intent_requires_action_webhook_event import (
SetupIntentRequiresActionWebhookEvent as SetupIntentRequiresActionWebhookEvent,
)
@@ -447,6 +500,9 @@
from .payout_account_status_updated_webhook_event import (
PayoutAccountStatusUpdatedWebhookEvent as PayoutAccountStatusUpdatedWebhookEvent,
)
+from .ledger_account_funds_available_webhook_event import (
+ LedgerAccountFundsAvailableWebhookEvent as LedgerAccountFundsAvailableWebhookEvent,
+)
from .resolution_center_case_created_webhook_event import (
ResolutionCenterCaseCreatedWebhookEvent as ResolutionCenterCaseCreatedWebhookEvent,
)
diff --git a/src/whop_sdk/types/account.py b/src/whop_sdk/types/account.py
index 6a1d0063..76f5f34e 100644
--- a/src/whop_sdk/types/account.py
+++ b/src/whop_sdk/types/account.py
@@ -1,61 +1,315 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
+from typing_extensions import Literal
from .._models import BaseModel
-from .account_wallet import AccountWallet
from .account_social_link import AccountSocialLink
-__all__ = ["Account"]
+__all__ = ["Account", "Balance", "Capabilities", "RecommendedAction", "RequiredAction", "Wallet"]
+
+
+class Balance(BaseModel):
+ """Account holdings, each with USD value. Empty when `total_usd` is `null`."""
+
+ balance: str
+ """Total amount held in native units, as a decimal string."""
+
+ breakdown: object
+ """
+ Balance split into available, pending, and reserve amounts, as native-unit
+ decimal strings. On-chain crypto is entirely available; good_funds and fiat cash
+ can have pending or reserve portions.
+ """
+
+ icon_url: Optional[str] = None
+ """Holding icon URL."""
+
+ name: str
+ """The holding's display name"""
+
+ price_usd: Optional[float] = None
+ """USD price per unit, or `null` when no exchange rate is available."""
+
+ symbol: str
+ """Holding display symbol, such as `USDT`, `cbBTC`, or `EUR`."""
+
+ value_usd: Optional[str] = None
+ """Holding USD value, or `null` when no exchange rate is available."""
+
+
+class Capabilities(BaseModel):
+ """
+ Payment rails enabled for this account, each `active`, `inactive`, or `pending` (onboarding or review in progress). Computed only on `retrieve` and `me` for callers with `company:balance:read` scope; `null` otherwise.
+ """
+
+ accept_bank_payments: Literal["active", "inactive", "pending"]
+ """Bank payins: debits, transfers, and local bank rails"""
+
+ accept_bnpl_payments: Literal["active", "inactive", "pending"]
+ """Buy-now-pay-later payins; requires approval"""
+
+ accept_card_payments: Literal["active", "inactive", "pending"]
+ """Card payins, including Apple Pay and Google Pay"""
+
+ bank_deposit: Literal["active", "inactive", "pending"]
+ """Deposits by bank wire or ACH to the account's virtual bank account"""
+
+ card_deposit: Literal["active", "inactive", "pending"]
+ """Balance top-ups by charging a stored payment method"""
+
+ card_issuing: Literal["active", "inactive", "pending"]
+ """Issuing Whop cards; requires card application approval"""
+
+ crypto_deposit: Literal["active", "inactive", "pending"]
+ """On-chain deposits to the account's crypto wallet"""
+
+ crypto_payout: Literal["active", "inactive", "pending"]
+ """On-chain payouts to a crypto wallet"""
+
+ instant_payout: Literal["active", "inactive", "pending"]
+ """Instant payouts to an eligible payout destination"""
+
+ standard_payout: Literal["active", "inactive", "pending"]
+ """Standard payouts to an external payout destination"""
+
+ transfer: Literal["active", "inactive", "pending"]
+ """Transfers to other accounts"""
+
+
+class RecommendedAction(BaseModel):
+ """
+ Optional actions that unlock capabilities or grow the account, same shape as `required_actions`. Computed only on `retrieve` and `me`; `null` otherwise.
+ """
+
+ action: Literal["apply_for_financing", "migrate_from_stripe", "accept_first_payment", "join_whop_university"]
+ """
+ The recommendation; new values may be added, so handle unknown actions
+ gracefully
+ """
+
+ blocked_capabilities: List[str]
+
+ cta: str
+ """The URL the call-to-action links to"""
+
+ cta_label: str
+ """Button label"""
+
+ description: str
+ """Supporting copy, or empty"""
+
+ icon_url: Optional[str] = None
+ """Illustration icon URL, or `null`"""
+
+ status: Literal["optional"]
+ """Always optional — never blocking"""
+
+ title: str
+ """Headline for the recommendation"""
+
+
+class RequiredAction(BaseModel):
+ """
+ Actions the account owner must take to unblock capabilities like payouts and card spend, ordered by display priority. Computed only on `retrieve` and `me` for callers with `company:balance:read` scope; `null` otherwise.
+ """
+
+ action: Literal["deposit_funds", "submit_information_request", "verify_identity", "connect_fulfillment_tracker"]
+ """
+ What the holder must do; new values may be added, so handle unknown actions
+ gracefully
+ """
+
+ blocked_capabilities: List[str]
+
+ cta: Optional[str] = None
+ """The URL the call-to-action links to, or null when there is no button"""
+
+ cta_label: str
+ """Button label, or empty when there is no button"""
+
+ description: str
+ """Supporting copy, or empty"""
+
+ icon_url: Optional[str] = None
+ """The URL of the action's illustration icon, or null if it has none"""
+
+ status: Literal["required", "pending"]
+ """required (act now) or pending (under review)"""
+
+ title: str
+ """Headline for the action"""
+
+
+class Wallet(BaseModel):
+ """Account primary crypto wallet, or `null` if none has been provisioned."""
+
+ id: str
+ """Wallet ID, prefixed `wallet_`."""
+
+ address: str
+ """The on-chain address of the wallet"""
+
+ network: Literal["solana", "ethereum", "bitcoin"]
+ """The blockchain network the wallet lives on"""
class Account(BaseModel):
id: str
- """The ID of the account, which will look like biz\\__******\\********"""
+ """Account ID, prefixed `biz_`."""
+
+ balances: List[Balance]
banner_image_url: Optional[str] = None
- """The URL of the account banner image"""
+ """Account banner image URL."""
+
+ business_address: Optional[object] = None
+ """
+ Account business address used to calculate tax, with `line1`, `line2`, `city`,
+ `state`, `postal_code`, and `country`. `null` when no address is set.
+ """
business_type: Optional[str] = None
- """The high-level business category for the account"""
+ """High-level business category for the account."""
+
+ capabilities: Optional[Capabilities] = None
+ """
+ Payment rails enabled for this account, each `active`, `inactive`, or `pending`
+ (onboarding or review in progress). Computed only on `retrieve` and `me` for
+ callers with `company:balance:read` scope; `null` otherwise.
+ """
+
+ country: Optional[str] = None
+ """Country where the account is located."""
created_at: str
- """When the account was created, as an ISO 8601 timestamp"""
+ """When the account was created, as an ISO 8601 timestamp."""
description: Optional[str] = None
- """A promotional description for the account"""
+ """Account promotional description."""
email: Optional[str] = None
- """The email address of the account owner"""
+ """Account owner email address."""
+
+ home_preferences: List[str]
industry_group: Optional[str] = None
- """The industry group the account belongs to"""
+ """Account industry group."""
industry_type: Optional[str] = None
- """The specific industry vertical the account operates in"""
+ """Specific industry vertical for the account."""
+
+ invoice_prefix: Optional[str] = None
+ """Prefix used for account invoices."""
logo_url: Optional[str] = None
- """The URL of the account logo image"""
+ """Account logo image URL."""
metadata: object
- """Arbitrary key/value metadata supplied when the account was created"""
+ """Arbitrary key/value metadata supplied at account creation."""
+
+ onboarding_type: Optional[str] = None
+ """Type of onboarding the account has completed."""
+
+ opengraph_image_url: Optional[str] = None
+ """Account Open Graph image URL."""
+
+ opengraph_image_variant: Optional[str] = None
+ """Account Open Graph image variant."""
+
+ other_business_description: Optional[str] = None
+ """Business type details when business_type is `other`."""
+
+ other_industry_description: Optional[str] = None
+ """Industry details when industry_type is `other`."""
parent_account_id: Optional[str] = None
- """The parent account ID for connected accounts"""
+ """Parent account ID for connected accounts."""
+
+ product_tax_code: Optional[object] = None
+ """
+ Tax classification code applied by default to the account's products, with `id`,
+ `name`, and `product_type`. `null` when no default is set.
+ """
+
+ recommended_actions: Optional[List[RecommendedAction]] = None
+
+ require_2fa: bool
+ """Whether authorized users must enable two-factor authentication."""
+
+ required_actions: Optional[List[RequiredAction]] = None
route: str
- """The account's public route identifier"""
+ """Account public route identifier."""
send_customer_emails: bool
- """Whether Whop sends transactional emails to customers on behalf of this account"""
+ """Whether Whop sends transactional emails to customers on behalf of this account."""
+
+ show_joined_whops: bool
+ """Whether the account appears in joined whops on other accounts."""
+
+ show_reviews_dtc: bool
+ """Whether reviews are displayed on direct-to-consumer product pages."""
+
+ show_user_directory: bool
+ """Whether the account shows users in the user directory."""
social_links: List[AccountSocialLink]
+ status: Optional[str] = None
+ """Whether the account can operate on Whop: `active` or `suspended`.
+
+ Computed only on `retrieve` and `me`; `null` otherwise.
+ """
+
+ store_page_config: object
+ """Account store page display configuration."""
+
target_audience: Optional[str] = None
- """The target audience for this account"""
+ """Target audience for this account."""
+
+ tax_identifiers: List[object]
+ """Account tax/VAT registrations, each with `id`, `tax_id_type`, and
+ `tax_id_value`.
+
+ Empty when none are set.
+ """
+
+ tax_remitted_by: Optional[str] = None
+ """
+ Who calculates and remits tax for the account: `whop` (Whop calculates and
+ remits), `self` (Whop calculates; the account collects and remits), or `none`
+ (neither; the account is responsible). `null` until the account enrolls in the
+ Whop tax service.
+ """
title: str
- """The display name of the account"""
+ """Account display name."""
+
+ total_earned_usd: Optional[float] = None
+ """Account lifetime sales, normalized to USD.
+
+ Computed only on `retrieve` and `me` for callers with `stats:read` scope; `null`
+ otherwise.
+ """
+
+ total_usd: Optional[str] = None
+ """Total USD value across balances with known exchange rates.
+
+ Computed only on single-account reads (`retrieve` and `me`); `null` on list
+ responses, writes, missing balance-read permission, or unavailable balance
+ source.
+ """
+
+ use_logo_as_opengraph_image_fallback: bool
+ """Whether the account uses its logo as the fallback Open Graph image."""
+
+ verification: object
+ """
+ Account identity verification status for the `individual` (KYC) and `business`
+ (KYB) profiles. Each is `null` until created, otherwise a `status` of
+ `not_started`, `pending`, `approved`, or `rejected`.
+ """
- wallet: Optional[AccountWallet] = None
- """The account's primary crypto wallet, or null if none has been provisioned"""
+ wallet: Optional[Wallet] = None
+ """Account primary crypto wallet, or `null` if none has been provisioned."""
diff --git a/src/whop_sdk/types/account_list_params.py b/src/whop_sdk/types/account_list_params.py
index 3462edca..1b9cd3b9 100644
--- a/src/whop_sdk/types/account_list_params.py
+++ b/src/whop_sdk/types/account_list_params.py
@@ -2,17 +2,26 @@
from __future__ import annotations
-from typing_extensions import TypedDict
+from typing_extensions import Literal, TypedDict
__all__ = ["AccountListParams"]
class AccountListParams(TypedDict, total=False):
- page: int
- """The page number to retrieve"""
+ after: str
+ """A cursor; returns accounts after this position."""
- per: int
- """The number of resources to return per page.
+ before: str
+ """A cursor; returns accounts before this position."""
- There is a limit of 50 results per page.
- """
+ direction: Literal["asc", "desc"]
+ """Sort direction."""
+
+ first: int
+ """The number of accounts to return (default 10, max 50)."""
+
+ last: int
+ """The number of accounts to return from the end of the range."""
+
+ order: Literal["created_at"]
+ """The field to sort accounts by."""
diff --git a/src/whop_sdk/types/account_list_response.py b/src/whop_sdk/types/account_list_response.py
deleted file mode 100644
index d4250efb..00000000
--- a/src/whop_sdk/types/account_list_response.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List, Optional
-
-from .account import Account
-from .._models import BaseModel
-
-__all__ = ["AccountListResponse", "Pagination"]
-
-
-class Pagination(BaseModel):
- current_page: float
- """Current page number"""
-
- next_page: Optional[float] = None
- """Next page number"""
-
- prev_page: Optional[float] = None
- """Previous page number"""
-
- total_count: float
- """Total number of records"""
-
- total_pages: float
- """Total number of pages"""
-
-
-class AccountListResponse(BaseModel):
- accounts: List[Account]
-
- pagination: Pagination
diff --git a/src/whop_sdk/types/account_update_params.py b/src/whop_sdk/types/account_update_params.py
index 1efb814c..6c59c954 100644
--- a/src/whop_sdk/types/account_update_params.py
+++ b/src/whop_sdk/types/account_update_params.py
@@ -3,9 +3,11 @@
from __future__ import annotations
from typing import Dict, Iterable, Optional
-from typing_extensions import TypedDict
+from typing_extensions import Literal, Required, TypedDict
-__all__ = ["AccountUpdateParams"]
+from .._types import SequenceNotStr
+
+__all__ = ["AccountUpdateParams", "BusinessAddress", "TaxIdentifier"]
class AccountUpdateParams(TypedDict, total=False):
@@ -21,20 +23,36 @@ class AccountUpdateParams(TypedDict, total=False):
banner_image: Optional[Dict[str, object]]
"""Attachment input for the account banner image."""
+ business_address: BusinessAddress
+ """Account business address used to calculate tax.
+
+ A complete address in a supported country is required when `tax_remitted_by` is
+ `self`.
+ """
+
business_type: Optional[str]
- """The high-level business category for the account."""
+ """High-level business category for the account."""
+
+ country: Optional[str]
+ """Country where the account is located."""
description: Optional[str]
- """A promotional description for the account."""
+ """Account promotional description."""
featured_affiliate_product_id: Optional[str]
- """The ID of the product to feature for affiliates. Pass null to clear."""
+ """The ID of the product to feature for affiliates. Pass `null` to clear."""
+
+ home_preferences: SequenceNotStr[str]
+ """Public account home page preferences."""
industry_group: Optional[str]
- """The industry group the account belongs to."""
+ """Account industry group."""
industry_type: Optional[str]
- """The specific industry vertical the account operates in."""
+ """Specific industry vertical for the account."""
+
+ invoice_prefix: Optional[str]
+ """Prefix used for account invoices."""
logo: Optional[Dict[str, object]]
"""Attachment input for the account logo."""
@@ -42,17 +60,218 @@ class AccountUpdateParams(TypedDict, total=False):
metadata: Dict[str, object]
"""Arbitrary key/value metadata to store on the account."""
+ onboarding_type: Optional[str]
+ """The type of onboarding the account has completed."""
+
+ opengraph_image: Optional[Dict[str, object]]
+ """Attachment input for the account Open Graph image."""
+
+ opengraph_image_variant: Optional[str]
+ """The account Open Graph image variant."""
+
+ other_business_description: Optional[str]
+ """The description of the business type when business_type is other."""
+
+ other_industry_description: Optional[str]
+ """The description of the industry type when industry_type is other."""
+
+ product_tax_code_id: Optional[str]
+ """ID of the tax classification code applied by default to the account's products."""
+
+ require_2fa: bool
+ """
+ Whether the account requires authorized users to have two-factor authentication
+ enabled.
+ """
+
route: Optional[str]
"""The unique URL slug for the account."""
send_customer_emails: bool
"""Whether Whop sends transactional emails to customers on behalf of this account."""
+ show_joined_whops: bool
+ """Whether the account appears in joined whops on other accounts."""
+
+ show_reviews_dtc: bool
+ """Whether reviews are displayed on direct-to-consumer product pages."""
+
+ show_user_directory: bool
+ """Whether the account shows users in the user directory."""
+
social_links: Iterable[Dict[str, object]]
"""The full list of social links to display for the account."""
+ store_page_config: Optional[Dict[str, object]]
+ """Account store page display configuration."""
+
target_audience: Optional[str]
"""The target audience for this account."""
+ tax_identifiers: Iterable[TaxIdentifier]
+ """Account tax/VAT registrations to add or update.
+
+ When `tax_remitted_by` is `self`, tax is calculated and collected only in the
+ countries where the account holds a registration.
+ """
+
+ tax_remitted_by: Literal["whop", "self", "none"]
+ """
+ Who calculates and remits tax for the account: `whop` (Whop calculates and
+ remits), `self` (Whop calculates; the account collects and remits), or `none`
+ (neither; the account is responsible). `self` requires a `business_address` in a
+ supported country.
+ """
+
title: Optional[str]
"""The display name of the account."""
+
+ use_logo_as_opengraph_image_fallback: bool
+ """Whether the account uses its logo as the fallback Open Graph image."""
+
+
+class BusinessAddress(TypedDict, total=False):
+ """Account business address used to calculate tax.
+
+ A complete address in a supported country is required when `tax_remitted_by` is `self`.
+ """
+
+ city: Optional[str]
+ """City name."""
+
+ country: str
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ line1: str
+ """First line of the street address."""
+
+ line2: Optional[str]
+ """Second line of the street address."""
+
+ postal_code: Optional[str]
+ """Postal or ZIP code."""
+
+ state: Optional[str]
+ """State, province, or region code, for example `CA`."""
+
+
+class TaxIdentifier(TypedDict, total=False):
+ tax_id_type: Required[
+ Literal[
+ "ad_nrt",
+ "ao_tin",
+ "ar_cuit",
+ "al_tin",
+ "am_tin",
+ "aw_tin",
+ "au_abn",
+ "au_arn",
+ "eu_vat",
+ "az_tin",
+ "bs_tin",
+ "bh_vat",
+ "bd_bin",
+ "bb_tin",
+ "by_tin",
+ "bj_ifu",
+ "bo_tin",
+ "ba_tin",
+ "br_cnpj",
+ "br_cpf",
+ "bg_uic",
+ "bf_ifu",
+ "kh_tin",
+ "cm_niu",
+ "ca_bn",
+ "ca_gst_hst",
+ "ca_pst_bc",
+ "ca_pst_mb",
+ "ca_pst_sk",
+ "ca_qst",
+ "cv_nif",
+ "cl_tin",
+ "cn_tin",
+ "co_nit",
+ "cd_nif",
+ "cr_tin",
+ "hr_oib",
+ "do_rcn",
+ "ec_ruc",
+ "eg_tin",
+ "sv_nit",
+ "et_tin",
+ "eu_oss_vat",
+ "ge_vat",
+ "gh_tin",
+ "de_stn",
+ "gb_vat",
+ "gn_nif",
+ "hk_br",
+ "hu_tin",
+ "is_vat",
+ "in_gst",
+ "id_npwp",
+ "il_vat",
+ "jp_cn",
+ "jp_rn",
+ "jp_trn",
+ "kz_bin",
+ "ke_pin",
+ "kg_tin",
+ "la_tin",
+ "li_uid",
+ "li_vat",
+ "my_frp",
+ "my_itn",
+ "my_sst",
+ "mr_nif",
+ "mx_rfc",
+ "md_vat",
+ "me_pib",
+ "ma_vat",
+ "np_pan",
+ "nz_gst",
+ "ng_tin",
+ "mk_vat",
+ "no_vat",
+ "no_voec",
+ "om_vat",
+ "pe_ruc",
+ "ph_tin",
+ "ro_tin",
+ "ru_inn",
+ "ru_kpp",
+ "sa_vat",
+ "sn_ninea",
+ "rs_pib",
+ "sg_gst",
+ "sg_uen",
+ "si_tin",
+ "za_vat",
+ "kr_brn",
+ "es_cif",
+ "ch_uid",
+ "ch_vat",
+ "tw_vat",
+ "tj_tin",
+ "tz_vat",
+ "th_vat",
+ "tr_tin",
+ "ug_tin",
+ "ua_vat",
+ "ae_trn",
+ "us_ein",
+ "uy_ruc",
+ "uz_tin",
+ "uz_vat",
+ "ve_rif",
+ "vn_tin",
+ "zm_tin",
+ "zw_tin",
+ "sr_fin",
+ ]
+ ]
+ """Tax ID type, for example `eu_vat`, `gb_vat`, or `us_ein`."""
+
+ tax_id_value: Required[str]
+ """Tax ID value, for example `DE123456789`."""
diff --git a/src/whop_sdk/types/account_wallet.py b/src/whop_sdk/types/account_wallet.py
deleted file mode 100644
index 0f32e70d..00000000
--- a/src/whop_sdk/types/account_wallet.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing_extensions import Literal
-
-from .._models import BaseModel
-
-__all__ = ["AccountWallet"]
-
-
-class AccountWallet(BaseModel):
- id: str
- """The ID of the wallet, which will look like wallet\\__******\\********"""
-
- address: str
- """The on-chain address of the wallet"""
-
- network: Literal["solana", "ethereum", "bitcoin"]
- """The blockchain network the wallet lives on"""
diff --git a/src/whop_sdk/types/ad.py b/src/whop_sdk/types/ad.py
index e2a1a0bd..0722be96 100644
--- a/src/whop_sdk/types/ad.py
+++ b/src/whop_sdk/types/ad.py
@@ -1,52 +1,309 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Optional
-from datetime import datetime
+from typing import List, Optional
+from typing_extensions import Literal
from .._models import BaseModel
-from .external_ad_status import ExternalAdStatus
-from .ad_campaign_platform import AdCampaignPlatform
-__all__ = ["Ad", "AdCampaign", "AdGroup"]
+__all__ = ["Ad", "AdCampaign", "AdGroup", "Creative", "Issue"]
class AdCampaign(BaseModel):
- """The ad campaign this ad belongs to."""
+ """The ad campaign this ad belongs to, an object with an id."""
id: str
- """The unique identifier for this ad campaign."""
+ """The referenced entity's id."""
class AdGroup(BaseModel):
- """The parent ad group this ad belongs to."""
+ """The ad group this ad belongs to, an object with an id."""
id: str
- """The unique identifier for this ad group."""
+ """The referenced entity's id."""
-class Ad(BaseModel):
- """An ad belonging to an ad group."""
+class Creative(BaseModel):
+ """The creatives used by this ad.
+
+ The original/uncropped asset has a null format; square, vertical, and horizontal entries are its per-placement crops.
+ """
+
+ id: str
+ """The creative attachment's file id."""
+
+ format: Optional[Literal["square", "vertical", "horizontal"]] = None
+ """The placement crop this asset covers, or null for the original/uncropped asset."""
+
+ media_type: Optional[str] = None
+ """The kind of asset, image or video."""
+
+ url: Optional[str] = None
+ """CDN url of the asset."""
+
+class Issue(BaseModel):
+ """Open issues affecting this ad. Empty when there are none."""
+
+ id: str
+ """Unique identifier for the issue."""
+
+ message: str
+ """A description of what the issue is and how it can be resolved."""
+
+ resource_id: Optional[str] = None
+ """The ID of the campaign, ad group, or ad the issue is attached to."""
+
+ resource_type: Literal["ad_campaign", "ad_group", "ad"]
+ """The type of resource the issue is attached to."""
+
+
+class Ad(BaseModel):
id: str
- """The unique identifier for this ad."""
+ """Unique identifier for the ad."""
ad_campaign: AdCampaign
- """The ad campaign this ad belongs to."""
+ """The ad campaign this ad belongs to, an object with an id."""
ad_group: AdGroup
- """The parent ad group this ad belongs to."""
+ """The ad group this ad belongs to, an object with an id."""
+
+ added_to_carts: float
+ """Whop pixel-attributed add-to-cart events, last-click."""
+
+ call_to_action: Optional[
+ Literal[
+ "learn_more",
+ "shop_now",
+ "sign_up",
+ "subscribe",
+ "get_started",
+ "book_now",
+ "apply_now",
+ "contact_us",
+ "download",
+ "order_now",
+ "buy_now",
+ "get_quote",
+ "message_page",
+ "whatsapp_message",
+ "instagram_message",
+ "call_now",
+ "get_directions",
+ "send_updates",
+ "get_offer",
+ "watch_more",
+ "listen_now",
+ "play_game",
+ "open_link",
+ "no_button",
+ "get_offer_view",
+ "get_event_tickets",
+ "see_menu",
+ "request_time",
+ "event_rsvp",
+ "see_details",
+ "view_instagram_profile",
+ ]
+ ] = None
+ """The call-to-action button shown on the ad."""
+
+ click_through_rate: float
+ """Clicks divided by impressions, between 0 and 1."""
+
+ clicks: float
+ """The number of clicks."""
+
+ completed_registrations: float
+ """Whop pixel-attributed complete-registration events, last-click."""
+
+ contacts: float
+ """Whop pixel-attributed contact events, last-click."""
+
+ cost_per_added_to_cart: Optional[float] = None
+ """
+ Spend divided by attributed add-to-cart events; null when they are not the goal
+ and none are attributed.
+ """
+
+ cost_per_click: float
+ """Spend divided by clicks; 0 when there are no clicks."""
+
+ cost_per_completed_registration: Optional[float] = None
+ """
+ Spend divided by attributed complete-registration events; null when they are not
+ the goal and none are attributed.
+ """
+
+ cost_per_contact: Optional[float] = None
+ """
+ Spend divided by attributed contact events; null when contacts are not the goal
+ and none are attributed.
+ """
+
+ cost_per_lead: Optional[float] = None
+ """
+ Spend divided by attributed leads; null when leads are not a goal and none are
+ attributed.
+ """
+
+ cost_per_mille: float
+ """Spend per 1,000 impressions; 0 when there are no impressions."""
+
+ cost_per_purchase: Optional[float] = None
+ """
+ Spend divided by attributed purchases; null when purchases are not a goal and
+ none are attributed.
+ """
+
+ cost_per_result: Optional[float] = None
+ """
+ Spend divided by Whop pixel-attributed results; null when nothing
+ Whop-attributable is being optimized for.
+ """
+
+ cost_per_schedule: Optional[float] = None
+ """
+ Spend divided by attributed schedule events; null when schedules are not the
+ goal and none are attributed.
+ """
- created_at: datetime
- """When the ad was created."""
+ cost_per_submitted_application: Optional[float] = None
+ """
+ Spend divided by attributed submit-application events; null when they are not
+ the goal and none are attributed.
+ """
- platform: AdCampaignPlatform
- """The external ad platform this ad is running on (e.g., meta, tiktok)."""
+ cost_per_viewed_content: Optional[float] = None
+ """
+ Spend divided by attributed view-content events; null when they are not the goal
+ and none are attributed.
+ """
- status: ExternalAdStatus
- """Current delivery status of the ad."""
+ created_at: str
+ """When the ad was created, as an ISO 8601 timestamp."""
+
+ creatives: List[Creative]
+
+ custom_conversions: float
+ """
+ Whop pixel-attributed custom (merchant-defined) conversion events, last-click,
+ across all custom event names.
+ """
+
+ descriptions: List[str]
+
+ frequency: Optional[float] = None
+ """Platform-reported impressions divided by reach."""
+
+ headlines: List[str]
+
+ impressions: float
+ """The number of impressions."""
+
+ issues: List[Issue]
+
+ lead_form: Optional[object] = None
+ """
+ The instant lead form on the ad (Meta lead ads), or null when the ad group's
+ conversion_location is not an instant-form destination. An object with name,
+ form_type (more_volume or higher_intent), an optional intro, questions, a
+ privacy_policy, an optional completion screen, and phone_verification.
+ """
+
+ leads: float
+ """Whop pixel-attributed leads, last-click."""
+
+ messaging_config: Optional[object] = None
+ """
+ The click-to-message welcome copy, an object with message and keyword, or null
+ when the ad has none.
+ """
+
+ multi_advertiser_ads: bool
+ """Whether the ad can appear alongside other advertisers' ads in the same unit.
+
+ Defaults to true.
+ """
+
+ post_id: Optional[str] = None
+ """
+ The existing post this ad promotes (a Facebook post or Instagram media), or null
+ when it uses uploaded creatives.
+ """
+
+ primary_texts: List[str]
+
+ purchase_value: float
+ """USD value of pixel-attributed purchases."""
+
+ purchases: float
+ """Whop pixel-attributed purchases, last-click."""
+
+ reach: float
+ """The number of unique people who saw this."""
+
+ result_event: Optional[
+ Literal[
+ "purchase",
+ "lead",
+ "schedule",
+ "submit_application",
+ "contact",
+ "complete_registration",
+ "view_content",
+ "add_to_cart",
+ "custom",
+ ]
+ ] = None
+ """
+ The Whop pixel conversion event whose attributed count represents results — the
+ optimization goal, or the highest-volume attributed event for campaigns that
+ budget per ad group. Null when the goal isn't a Whop-attributed event.
+ """
+
+ result_event_name: Optional[str] = None
+ """
+ The merchant-defined event name when result_event is custom; null for the
+ standard events.
+ """
+
+ return_on_ad_spend: float
+ """Purchase value divided by spend; 0 when there is no spend."""
+
+ schedules: float
+ """Whop pixel-attributed schedule events, last-click."""
+
+ social_accounts: List[object]
+
+ spend: float
+ """The amount charged, in spend_currency."""
+
+ spend_currency: Optional[str] = None
+ """The ISO 4217 currency code of all monetary metrics."""
+
+ status: Literal["active", "paused", "in_review", "rejected"]
+ """The delivery status of the ad."""
+
+ submitted_applications: float
+ """Whop pixel-attributed submit-application events, last-click."""
title: Optional[str] = None
"""The display title of the ad. Falls back to the creative set caption when unset."""
- updated_at: datetime
- """When the ad was last updated."""
+ unique_click_through_rate: Optional[float] = None
+ """Unique clicks divided by impressions, between 0 and 1."""
+
+ unique_clicks: float
+ """The number of unique clicks."""
+
+ updated_at: str
+ """When the ad was last updated, as an ISO 8601 timestamp."""
+
+ url: Optional[str] = None
+ """The URL the ad links to."""
+
+ url_parameters: object
+ """Query parameters appended to the URL, as a string-to-string map."""
+
+ viewed_contents: float
+ """Whop pixel-attributed view-content events, last-click."""
diff --git a/src/whop_sdk/types/ad_budget_type.py b/src/whop_sdk/types/ad_budget_type.py
deleted file mode 100644
index d3eee5dd..00000000
--- a/src/whop_sdk/types/ad_budget_type.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing_extensions import Literal, TypeAlias
-
-__all__ = ["AdBudgetType"]
-
-AdBudgetType: TypeAlias = Literal["daily", "lifetime"]
diff --git a/src/whop_sdk/types/ad_campaign.py b/src/whop_sdk/types/ad_campaign.py
index 6d201157..f04c1c84 100644
--- a/src/whop_sdk/types/ad_campaign.py
+++ b/src/whop_sdk/types/ad_campaign.py
@@ -1,108 +1,233 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
-from datetime import datetime
from typing_extensions import Literal
from .._models import BaseModel
-from .ad_budget_type import AdBudgetType
-from .ad_campaign_status import AdCampaignStatus
-from .ad_campaign_platform import AdCampaignPlatform
-__all__ = ["AdCampaign", "CreatedByUser", "MetaConfig"]
+__all__ = ["AdCampaign", "Issue"]
-class CreatedByUser(BaseModel):
- """The user who created this ad campaign."""
+class Issue(BaseModel):
+ """Open issues affecting the campaign and its descendant ad groups and ads."""
id: str
- """The unique identifier for the user."""
+ """Unique identifier for the issue."""
- name: Optional[str] = None
- """The user's display name shown on their public profile."""
+ message: str
+ """A description of what the issue is and how it can be resolved."""
- username: str
- """The user's unique username shown on their public profile."""
+ resource_id: Optional[str] = None
+ """The ID of the campaign, ad group, or ad the issue is attached to."""
+ resource_type: Literal["ad_campaign", "ad_group", "ad"]
+ """The type of resource the issue is attached to."""
-class MetaConfig(BaseModel):
- """Meta-specific campaign configuration (objective, budget mode, etc.).
- Null for non-Meta campaigns.
+class AdCampaign(BaseModel):
+ id: str
+ """Unique identifier for the ad campaign."""
+
+ added_to_carts: float
+ """Whop pixel-attributed add-to-cart events, last-click."""
+
+ bid_type: Optional[Literal["minimum_cost", "average_target", "maximum_target"]] = None
+ """The bidding strategy the campaign uses."""
+
+ budget_amount: Optional[float] = None
+ """The campaign budget in USD.
+
+ Null when budget is set at the ad group level (ABO).
"""
- bid_amount: Optional[int] = None
- """Bid cap amount in cents. Only used when bid_strategy is bid_cap."""
+ budget_optimization: Optional[Literal["ad_campaign", "ad_group"]] = None
+ """Which level owns the budget — the campaign (CBO) or each ad group (ABO)."""
- bid_strategy: Optional[Literal["lowest_cost", "bid_cap", "cost_cap"]] = None
- """The bidding strategy used to optimize spend for this campaign."""
+ budget_type: Optional[Literal["daily", "lifetime"]] = None
+ """Whether the budget is spent per day or over the campaign's lifetime."""
- budget_optimization: Optional[bool] = None
+ click_through_rate: float
+ """Clicks divided by impressions, between 0 and 1."""
+
+ clicks: float
+ """The number of clicks."""
+
+ completed_registrations: float
+ """Whop pixel-attributed complete-registration events, last-click."""
+
+ contacts: float
+ """Whop pixel-attributed contact events, last-click."""
+
+ cost_per_added_to_cart: Optional[float] = None
"""
- Whether campaign budget optimization (CBO) is enabled, allowing the platform to
- distribute budget across ad groups.
+ Spend divided by attributed add-to-cart events; null when they are not the goal
+ and none are attributed.
"""
- effective_status: Optional[Literal["active", "paused", "deleted", "in_review", "rejected", "with_issues"]] = None
+ cost_per_click: float
+ """Spend divided by clicks; 0 when there are no clicks."""
+
+ cost_per_completed_registration: Optional[float] = None
"""
- The actual delivery status, accounting for platform overrides (e.g., in_review,
- rejected).
+ Spend divided by attributed complete-registration events; null when they are not
+ the goal and none are attributed.
"""
- end_time: Optional[str] = None
- """The scheduled end time of the campaign (ISO8601)."""
+ cost_per_contact: Optional[float] = None
+ """
+ Spend divided by attributed contact events; null when contacts are not the goal
+ and none are attributed.
+ """
- objective: Optional[Literal["awareness", "traffic", "engagement", "leads", "sales"]] = None
- """The campaign objective that determines how Meta optimizes delivery."""
+ cost_per_lead: Optional[float] = None
+ """
+ Spend divided by attributed leads; null when leads are not a goal and none are
+ attributed.
+ """
+
+ cost_per_mille: float
+ """Spend per 1,000 impressions; 0 when there are no impressions."""
- special_categories: Optional[List[str]] = None
+ cost_per_purchase: Optional[float] = None
"""
- Special ad categories required by the platform (e.g., housing, employment,
- credit).
+ Spend divided by attributed purchases; null when purchases are not a goal and
+ none are attributed.
"""
- start_time: Optional[str] = None
- """The scheduled start time of the campaign (ISO8601)."""
+ cost_per_result: Optional[float] = None
+ """
+ Spend divided by Whop pixel-attributed results; null when nothing
+ Whop-attributable is being optimized for.
+ """
- status: Optional[Literal["active", "paused"]] = None
- """The campaign status as set by the advertiser (active or paused)."""
+ cost_per_schedule: Optional[float] = None
+ """
+ Spend divided by attributed schedule events; null when schedules are not the
+ goal and none are attributed.
+ """
+ cost_per_submitted_application: Optional[float] = None
+ """
+ Spend divided by attributed submit-application events; null when they are not
+ the goal and none are attributed.
+ """
-class AdCampaign(BaseModel):
- """An advertising campaign running on an external platform or within Whop."""
+ cost_per_viewed_content: Optional[float] = None
+ """
+ Spend divided by attributed view-content events; null when they are not the goal
+ and none are attributed.
+ """
- id: str
- """The unique identifier for this ad campaign."""
+ created_at: str
+ """When the campaign was created, as an ISO 8601 timestamp."""
- budget: Optional[float] = None
- """Total budget in dollars."""
+ custom_conversions: float
+ """
+ Whop pixel-attributed custom (merchant-defined) conversion events, last-click,
+ across all custom event names.
+ """
- budget_type: Optional[AdBudgetType] = None
- """The budget type for an ad campaign or ad group."""
+ frequency: Optional[float] = None
+ """Platform-reported impressions divided by reach."""
+
+ impressions: float
+ """The number of impressions."""
+
+ issues: List[Issue]
+
+ leads: float
+ """Whop pixel-attributed leads, last-click."""
+
+ objective: Optional[Literal["awareness", "traffic", "engagement", "leads", "sales"]] = None
+ """The goal the campaign optimizes toward."""
- created_at: datetime
- """When the ad campaign was created."""
+ optimization_goal: Optional[str] = None
+ """The specific event the campaign optimizes for.
- created_by_user: CreatedByUser
- """The user who created this ad campaign."""
+ If the campaign is CBO, then all ad groups will have the same optimization goal,
+ which will be returned here.
+ """
- meta_config: Optional[MetaConfig] = None
- """Meta-specific campaign configuration (objective, budget mode, etc.).
+ platform: Literal["meta"]
+ """The ad network the campaign runs on."""
+
+ purchase_value: float
+ """USD value of pixel-attributed purchases."""
+
+ purchases: float
+ """Whop pixel-attributed purchases, last-click."""
+
+ reach: float
+ """The number of unique people who saw this."""
+
+ result_event: Optional[
+ Literal[
+ "purchase",
+ "lead",
+ "schedule",
+ "submit_application",
+ "contact",
+ "complete_registration",
+ "view_content",
+ "add_to_cart",
+ "custom",
+ ]
+ ] = None
+ """
+ The Whop pixel conversion event whose attributed count represents results — the
+ optimization goal, or the highest-volume attributed event for campaigns that
+ budget per ad group. Null when the goal isn't a Whop-attributed event.
+ """
- Null for non-Meta campaigns.
+ result_event_name: Optional[str] = None
"""
+ The merchant-defined event name when result_event is custom; null for the
+ standard events.
+ """
+
+ return_on_ad_spend: float
+ """Purchase value divided by spend; 0 when there is no spend."""
+
+ schedules: float
+ """Whop pixel-attributed schedule events, last-click."""
- platform: AdCampaignPlatform
- """The external ad platform this campaign is running on (e.g., meta, tiktok)."""
+ special_ad_categories: List[Literal["housing", "employment", "financial_products", "politics"]]
- status: AdCampaignStatus
- """Current status of the campaign (active, paused, or inactive)."""
+ spend: float
+ """The amount charged, in spend_currency."""
+
+ spend_currency: Optional[str] = None
+ """The ISO 4217 currency code of all monetary metrics."""
+
+ status: Literal[
+ "active",
+ "paused",
+ "inactive",
+ "stale",
+ "pending_refund",
+ "payment_failed",
+ "draft",
+ "in_review",
+ "flagged",
+ "importing",
+ "imported",
+ ]
+ """The lifecycle status of the ad campaign."""
+
+ submitted_applications: float
+ """Whop pixel-attributed submit-application events, last-click."""
title: str
- """The campaign name shown in the Whop dashboard."""
+ """The title of the ad campaign."""
+
+ unique_click_through_rate: Optional[float] = None
+ """Unique clicks divided by impressions, between 0 and 1."""
+
+ unique_clicks: float
+ """The number of unique clicks."""
- total_spend: float
- """Total amount spent in dollars."""
+ updated_at: str
+ """When the campaign was last updated, as an ISO 8601 timestamp."""
- updated_at: datetime
- """When the ad campaign was last updated."""
+ viewed_contents: float
+ """Whop pixel-attributed view-content events, last-click."""
diff --git a/src/whop_sdk/types/ad_campaign_create_params.py b/src/whop_sdk/types/ad_campaign_create_params.py
new file mode 100644
index 00000000..1cb7db21
--- /dev/null
+++ b/src/whop_sdk/types/ad_campaign_create_params.py
@@ -0,0 +1,67 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["AdCampaignCreateParams"]
+
+
+class AdCampaignCreateParams(TypedDict, total=False):
+ objective: Required[Literal["awareness", "traffic", "engagement", "leads", "sales"]]
+ """The goal the campaign optimizes toward."""
+
+ platform: Required[Literal["meta"]]
+ """The ad network the campaign runs on."""
+
+ title: Required[str]
+ """The title of the campaign."""
+
+ account_id: str
+ """The account to create the campaign under.
+
+ Defaults to the account-scoped key's own account.
+ """
+
+ bid_type: Literal["minimum_cost", "average_target", "maximum_target"]
+ """
+ CBO bid strategy: minimum_cost (lowest cost), average_target (cost cap), or
+ maximum_target (bid cap). CBO only.
+ """
+
+ budget_amount: float
+ """The campaign budget, in USD.
+
+ Required for CBO (budget_optimization: ad_campaign); omit for ABO.
+ """
+
+ budget_optimization: Literal["ad_campaign", "ad_group"]
+ """Which level owns the budget — the campaign (CBO) or each ad group (ABO).
+
+ Defaults to ad_group.
+ """
+
+ budget_type: Literal["daily", "lifetime"]
+ """Whether the budget is spent per day or over the campaign's lifetime.
+
+ Defaults to daily.
+ """
+
+ desired_cost_per_result: float
+ """Target/cap cost per result in USD for average_target / maximum_target bidding.
+
+ CBO only.
+ """
+
+ ends_at: str
+ """Campaign schedule end (ISO 8601). CBO only."""
+
+ special_ad_categories: List[Literal["housing", "employment", "financial_products", "politics"]]
+ """Regulated categories the campaign falls under.
+
+ Ads in these categories are subject to extra targeting restrictions.
+ """
+
+ starts_at: str
+ """Campaign schedule start (ISO 8601). CBO only."""
diff --git a/src/whop_sdk/types/ad_campaign_delete_response.py b/src/whop_sdk/types/ad_campaign_delete_response.py
new file mode 100644
index 00000000..359d4542
--- /dev/null
+++ b/src/whop_sdk/types/ad_campaign_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__ = ["AdCampaignDeleteResponse"]
+
+AdCampaignDeleteResponse: TypeAlias = bool
diff --git a/src/whop_sdk/types/ad_campaign_list_params.py b/src/whop_sdk/types/ad_campaign_list_params.py
index ab696839..c46323a4 100644
--- a/src/whop_sdk/types/ad_campaign_list_params.py
+++ b/src/whop_sdk/types/ad_campaign_list_params.py
@@ -2,40 +2,69 @@
from __future__ import annotations
-from typing import Union, Optional
-from datetime import datetime
-from typing_extensions import Annotated, TypedDict
-
-from .._utils import PropertyInfo
-from .ad_campaign_status import AdCampaignStatus
+from typing_extensions import Literal, TypedDict
__all__ = ["AdCampaignListParams"]
class AdCampaignListParams(TypedDict, total=False):
- after: Optional[str]
- """Returns the elements in the list that come after the specified cursor."""
+ account_id: str
+ """The account the campaigns belong to.
+
+ Defaults to the account-scoped key's own account.
+ """
+
+ after: str
+ """Cursor to fetch the page after (from page_info.end_cursor)."""
+
+ before: str
+ """Cursor to fetch the page before (from page_info.start_cursor)."""
+
+ created_after: str
+ """Only return campaigns created after this timestamp."""
+
+ created_before: str
+ """Only return campaigns created before this timestamp."""
+
+ direction: Literal["asc", "desc"]
+ """The sort direction. Defaults to desc."""
- before: Optional[str]
- """Returns the elements in the list that come before the specified cursor."""
+ first: int
+ """The number of campaigns to return."""
- company_id: Optional[str]
- """The unique identifier of the company to list ad campaigns for."""
+ last: int
+ """The number of campaigns to return from the end of the range."""
- created_after: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """Only return ad campaigns created after this timestamp."""
+ order: Literal[
+ "created_at",
+ "updated_at",
+ "spend",
+ "impressions",
+ "clicks",
+ "reach",
+ "unique_clicks",
+ "results",
+ "click_through_rate",
+ "cost_per_click",
+ "cost_per_mille",
+ "cost_per_result",
+ "frequency",
+ "return_on_ad_spend",
+ ]
+ """The field to sort by.
- created_before: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """Only return ad campaigns created before this timestamp."""
+ Defaults to created_at. Stat columns (spend, impressions, …) rank over the
+ stats_from/stats_to window across the whole list, not just the current page.
+ """
- first: Optional[int]
- """Returns the first _n_ elements from the list."""
+ query: str
+ """Filter campaigns by a title or ID substring."""
- last: Optional[int]
- """Returns the last _n_ elements from the list."""
+ stats_from: str
+ """Start of the stats window. Defaults to all-time."""
- query: Optional[str]
- """Case-insensitive substring match against the campaign title."""
+ stats_to: str
+ """End of the stats window. Defaults to now."""
- status: Optional[AdCampaignStatus]
- """The status of an ad campaign."""
+ status: Literal["draft", "active", "paused", "payment_failed"]
+ """Only return campaigns with this status."""
diff --git a/src/whop_sdk/types/ad_campaign_list_response.py b/src/whop_sdk/types/ad_campaign_list_response.py
deleted file mode 100644
index 7123408d..00000000
--- a/src/whop_sdk/types/ad_campaign_list_response.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-from datetime import datetime
-
-from .._models import BaseModel
-from .ad_budget_type import AdBudgetType
-from .ad_campaign_status import AdCampaignStatus
-from .ad_campaign_platform import AdCampaignPlatform
-
-__all__ = ["AdCampaignListResponse"]
-
-
-class AdCampaignListResponse(BaseModel):
- """An advertising campaign running on an external platform or within Whop."""
-
- id: str
- """The unique identifier for this ad campaign."""
-
- budget: Optional[float] = None
- """Total budget in dollars."""
-
- budget_type: Optional[AdBudgetType] = None
- """The budget type for an ad campaign or ad group."""
-
- created_at: datetime
- """When the ad campaign was created."""
-
- platform: AdCampaignPlatform
- """The external ad platform this campaign is running on (e.g., meta, tiktok)."""
-
- status: AdCampaignStatus
- """Current status of the campaign (active, paused, or inactive)."""
-
- title: str
- """The campaign name shown in the Whop dashboard."""
-
- total_spend: float
- """Total amount spent in dollars."""
-
- updated_at: datetime
- """When the ad campaign was last updated."""
diff --git a/src/whop_sdk/types/ad_campaign_platform.py b/src/whop_sdk/types/ad_campaign_platform.py
deleted file mode 100644
index 1e841130..00000000
--- a/src/whop_sdk/types/ad_campaign_platform.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing_extensions import Literal, TypeAlias
-
-__all__ = ["AdCampaignPlatform"]
-
-AdCampaignPlatform: TypeAlias = Literal["meta", "tiktok"]
diff --git a/src/whop_sdk/types/ad_campaign_retrieve_params.py b/src/whop_sdk/types/ad_campaign_retrieve_params.py
new file mode 100644
index 00000000..63e9b2b8
--- /dev/null
+++ b/src/whop_sdk/types/ad_campaign_retrieve_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 TypedDict
+
+__all__ = ["AdCampaignRetrieveParams"]
+
+
+class AdCampaignRetrieveParams(TypedDict, total=False):
+ stats_from: str
+ """Start of the stats window."""
+
+ stats_to: str
+ """End of the stats window."""
diff --git a/src/whop_sdk/types/ad_campaign_status.py b/src/whop_sdk/types/ad_campaign_status.py
deleted file mode 100644
index ddfbdf4e..00000000
--- a/src/whop_sdk/types/ad_campaign_status.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing_extensions import Literal, TypeAlias
-
-__all__ = ["AdCampaignStatus"]
-
-AdCampaignStatus: TypeAlias = Literal["active", "paused", "payment_failed", "draft", "in_review", "flagged"]
diff --git a/src/whop_sdk/types/ad_campaign_update_params.py b/src/whop_sdk/types/ad_campaign_update_params.py
index 7c476aea..a332c7eb 100644
--- a/src/whop_sdk/types/ad_campaign_update_params.py
+++ b/src/whop_sdk/types/ad_campaign_update_params.py
@@ -2,16 +2,29 @@
from __future__ import annotations
-from typing import Optional
-from typing_extensions import TypedDict
+from typing_extensions import Literal, TypedDict
__all__ = ["AdCampaignUpdateParams"]
class AdCampaignUpdateParams(TypedDict, total=False):
- budget: Optional[float]
- """The campaign budget in dollars.
+ budget_amount: float
+ """The campaign budget, in the account's currency.
- The interpretation (daily or lifetime) follows the campaign's existing budget
- type.
+ Interpreted as daily or lifetime per the campaign's existing budget type.
"""
+
+ ends_at: str
+ """Campaign schedule end (ISO 8601). CBO only."""
+
+ starts_at: str
+ """Campaign schedule start (ISO 8601). CBO only."""
+
+ status: Literal["active"]
+ """Set to active to launch a draft campaign (moderates and pushes it live).
+
+ Live-campaign pause and resume use the pause and unpause actions.
+ """
+
+ title: str
+ """The name of the campaign."""
diff --git a/src/whop_sdk/types/ad_create_params.py b/src/whop_sdk/types/ad_create_params.py
new file mode 100644
index 00000000..25f3e452
--- /dev/null
+++ b/src/whop_sdk/types/ad_create_params.py
@@ -0,0 +1,276 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Iterable
+from typing_extensions import Literal, TypedDict
+
+from .._types import SequenceNotStr
+
+__all__ = [
+ "AdCreateParams",
+ "Creative",
+ "LeadForm",
+ "LeadFormCompletion",
+ "LeadFormDisclaimer",
+ "LeadFormDisclaimerCheckbox",
+ "LeadFormIntro",
+ "LeadFormPrivacyPolicy",
+ "LeadFormQuestion",
+ "LeadFormQuestionOption",
+ "LeadFormQuestionOptionLogic",
+ "MessagingConfig",
+ "SocialAccount",
+]
+
+
+class AdCreateParams(TypedDict, total=False):
+ ad_group: object
+ """
+ An inline ad group to create (same shape as POST /ad_groups, including
+ ad_campaign_id). Creates the ad group and the ad together. Provide this OR
+ ad_group_id.
+ """
+
+ ad_group_id: str
+ """The existing ad group to create the ad in. Provide this OR ad_group, not both."""
+
+ call_to_action: Literal[
+ "apply_now",
+ "book_now",
+ "call_now",
+ "contact_us",
+ "download",
+ "get_directions",
+ "get_offer",
+ "get_quote",
+ "learn_more",
+ "listen_now",
+ "message_page",
+ "no_button",
+ "open_link",
+ "order_now",
+ "request_time",
+ "see_details",
+ "see_menu",
+ "send_updates",
+ "shop_now",
+ "sign_up",
+ "subscribe",
+ "watch_more",
+ ]
+ """The call-to-action button shown on the ad."""
+
+ creatives: Iterable[Creative]
+ """The ad's creatives.
+
+ Each entry is an uploaded file id with an optional format; omit format for the
+ original/uncropped asset.
+ """
+
+ descriptions: SequenceNotStr[str]
+ """The description variants shown on the ad."""
+
+ headlines: SequenceNotStr[str]
+ """The headline variants shown on the ad."""
+
+ lead_form: LeadForm
+ """Instant lead form for the ad.
+
+ Only allowed when the ad group's conversion_location is an instant-form
+ destination (instant_forms, instant_forms_and_messenger,
+ website_and_instant_forms).
+ """
+
+ messaging_config: MessagingConfig
+ """
+ Click-to-message welcome copy: the greeting (message) and the ice-breaker prompt
+ (keyword).
+ """
+
+ multi_advertiser_ads: bool
+ """Whether the ad can appear alongside other advertisers' ads in the same unit.
+
+ Defaults to true.
+ """
+
+ post_id: str
+ """
+ Promote an existing post instead of uploading creatives — a Facebook post or
+ Instagram media id. Mutually exclusive with creatives.
+ """
+
+ primary_texts: SequenceNotStr[str]
+ """The primary text variants shown in the ad body."""
+
+ social_accounts: Iterable[SocialAccount]
+ """The social accounts (Facebook page, Instagram profile) the ad runs under."""
+
+ title: str
+ """The display name of the ad."""
+
+ url: str
+ """The URL the ad links to."""
+
+ url_parameters: object
+ """Query parameters appended to the destination URL, as a string-to-string map."""
+
+
+class Creative(TypedDict, total=False):
+ id: str
+
+ format: Literal["square", "vertical", "horizontal"]
+
+
+class LeadFormCompletion(TypedDict, total=False):
+ """
+ Optional completion screen shown after submission; url sets the follow-up website button.
+ """
+
+ button_text: str
+
+ description: str
+
+ headline: str
+
+ url: str
+
+
+class LeadFormDisclaimerCheckbox(TypedDict, total=False):
+ checked_by_default: bool
+
+ key: str
+
+ required: bool
+
+ text: str
+
+
+class LeadFormDisclaimer(TypedDict, total=False):
+ """Optional custom consent disclaimer with checkboxes."""
+
+ body: str
+
+ checkboxes: Iterable[LeadFormDisclaimerCheckbox]
+
+ title: str
+
+
+class LeadFormIntro(TypedDict, total=False):
+ """Optional intro screen shown before the questions."""
+
+ description: str
+
+ headline: str
+
+
+class LeadFormPrivacyPolicy(TypedDict, total=False):
+ """Your privacy policy. url is required by Meta."""
+
+ link_text: str
+
+ url: str
+
+
+class LeadFormQuestionOptionLogic(TypedDict, total=False):
+ action: Literal["go_to_question", "submit_form", "close_form"]
+
+ target_end_page_index: int
+
+ target_question_index: int
+
+
+class LeadFormQuestionOption(TypedDict, total=False):
+ key: str
+
+ logic: LeadFormQuestionOptionLogic
+
+ value: str
+
+
+class LeadFormQuestion(TypedDict, total=False):
+ format: Literal["short_answer", "multiple_choice", "appointment"]
+
+ label: str
+
+ options: Iterable[LeadFormQuestionOption]
+
+ type: Literal[
+ "email",
+ "phone",
+ "full_name",
+ "first_name",
+ "last_name",
+ "city",
+ "state",
+ "zip",
+ "country",
+ "street_address",
+ "job_title",
+ "company_name",
+ "work_email",
+ "work_phone_number",
+ "dob",
+ "gender",
+ "marital_status",
+ "relationship_status",
+ "military_status",
+ "date_time",
+ "custom",
+ ]
+
+
+class LeadForm(TypedDict, total=False):
+ """Instant lead form for the ad.
+
+ Only allowed when the ad group's conversion_location is an instant-form destination (instant_forms, instant_forms_and_messenger, website_and_instant_forms).
+ """
+
+ completion: LeadFormCompletion
+ """
+ Optional completion screen shown after submission; url sets the follow-up
+ website button.
+ """
+
+ disclaimer: LeadFormDisclaimer
+ """Optional custom consent disclaimer with checkboxes."""
+
+ form_type: Literal["more_volume", "higher_intent"]
+ """
+ more_volume (default) is quickest to submit; higher_intent adds a confirmation
+ step.
+ """
+
+ intro: LeadFormIntro
+ """Optional intro screen shown before the questions."""
+
+ name: str
+ """Internal name for the form. Auto-generated if omitted."""
+
+ phone_verification: bool
+ """Require SMS verification of the phone number (higher_intent forms)."""
+
+ privacy_policy: LeadFormPrivacyPolicy
+ """Your privacy policy. url is required by Meta."""
+
+ questions: Iterable[LeadFormQuestion]
+ """The questions on the form.
+
+ Standard prefill types need only a type; a custom question needs a label and a
+ format (plus options for multiple_choice). Options carry an optional key and
+ answer-routing logic.
+ """
+
+
+class MessagingConfig(TypedDict, total=False):
+ """
+ Click-to-message welcome copy: the greeting (message) and the ice-breaker prompt (keyword).
+ """
+
+ keyword: str
+
+ message: str
+
+
+class SocialAccount(TypedDict, total=False):
+ id: str
diff --git a/src/whop_sdk/types/ad_delete_response.py b/src/whop_sdk/types/ad_delete_response.py
new file mode 100644
index 00000000..7bb78972
--- /dev/null
+++ b/src/whop_sdk/types/ad_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__ = ["AdDeleteResponse"]
+
+AdDeleteResponse: TypeAlias = bool
diff --git a/src/whop_sdk/types/ad_group.py b/src/whop_sdk/types/ad_group.py
index 384dbf5f..18790628 100644
--- a/src/whop_sdk/types/ad_group.py
+++ b/src/whop_sdk/types/ad_group.py
@@ -1,49 +1,299 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Optional
-from datetime import datetime
+from typing import List, Union, Optional
+from typing_extensions import Literal
from .._models import BaseModel
-from .ad_budget_type import AdBudgetType
-from .ad_group_status import AdGroupStatus
-from .ad_campaign_platform import AdCampaignPlatform
-__all__ = ["AdGroup", "AdCampaign"]
+__all__ = ["AdGroup", "AdCampaign", "Issue"]
class AdCampaign(BaseModel):
- """The ad campaign this ad group belongs to."""
+ """The ad campaign this ad group belongs to, an object with an id."""
id: str
- """The unique identifier for this ad campaign."""
+ """The referenced entity's id."""
-class AdGroup(BaseModel):
- """An ad group (ad set) belonging to an ad campaign."""
+class Issue(BaseModel):
+ """Open issues affecting this ad group. Empty when there are none."""
+
+ id: str
+ """Unique identifier for the issue."""
+
+ message: str
+ """A description of what the issue is and how it can be resolved."""
+ resource_id: Optional[str] = None
+ """The ID of the campaign, ad group, or ad the issue is attached to."""
+
+ resource_type: Literal["ad_campaign", "ad_group", "ad"]
+ """The type of resource the issue is attached to."""
+
+
+class AdGroup(BaseModel):
id: str
- """The unique identifier for this ad group."""
+ """Unique identifier for the ad group."""
ad_campaign: AdCampaign
- """The ad campaign this ad group belongs to."""
+ """The ad campaign this ad group belongs to, an object with an id."""
+
+ added_to_carts: float
+ """Whop pixel-attributed add-to-cart events, last-click."""
+
+ audiences: object
+ """Saved-audience targeting: { include, exclude } arrays of audience IDs."""
+
+ bid_type: Optional[Literal["minimum_cost", "average_target", "maximum_target"]] = None
+ """Bid strategy."""
+
+ budget_amount: Optional[float] = None
+ """Ad-set budget; null when the campaign owns budget (CBO)."""
+
+ budget_type: Optional[Literal["daily", "lifetime"]] = None
+ """Whether the budget is daily or lifetime."""
+
+ click_through_rate: float
+ """Clicks divided by impressions, between 0 and 1."""
+
+ clicks: float
+ """The number of clicks."""
+
+ completed_registrations: float
+ """Whop pixel-attributed complete-registration events, last-click."""
+
+ contacts: float
+ """Whop pixel-attributed contact events, last-click."""
+
+ conversion_event: Union[
+ Literal[
+ "purchase",
+ "add_to_cart",
+ "initiated_checkout",
+ "add_payment_info",
+ "complete_registration",
+ "lead",
+ "content_view",
+ "search",
+ "contact",
+ "customize_product",
+ "donate",
+ "find_location",
+ "schedule",
+ "start_trial",
+ "submit_application",
+ "subscribe",
+ ],
+ str,
+ None,
+ ] = None
+ """The pixel event optimized for.
+
+ A standard event, or any custom pixel event name.
+ """
+
+ conversion_location: Optional[
+ Literal[
+ "website",
+ "profile",
+ "messaging",
+ "on_ad",
+ "instant_forms",
+ "instant_forms_and_messenger",
+ "website_and_instant_forms",
+ ]
+ ] = None
+ """
+ Where results happen: website, profile (IG/FB), messaging (DM), on_ad
+ (engagement), or the lead destinations (instant_forms,
+ instant_forms_and_messenger, website_and_instant_forms).
+ """
+
+ cost_per_added_to_cart: Optional[float] = None
+ """
+ Spend divided by attributed add-to-cart events; null when they are not the goal
+ and none are attributed.
+ """
+
+ cost_per_click: float
+ """Spend divided by clicks; 0 when there are no clicks."""
+
+ cost_per_completed_registration: Optional[float] = None
+ """
+ Spend divided by attributed complete-registration events; null when they are not
+ the goal and none are attributed.
+ """
+
+ cost_per_contact: Optional[float] = None
+ """
+ Spend divided by attributed contact events; null when contacts are not the goal
+ and none are attributed.
+ """
+
+ cost_per_lead: Optional[float] = None
+ """
+ Spend divided by attributed leads; null when leads are not a goal and none are
+ attributed.
+ """
+
+ cost_per_mille: float
+ """Spend per 1,000 impressions; 0 when there are no impressions."""
+
+ cost_per_purchase: Optional[float] = None
+ """
+ Spend divided by attributed purchases; null when purchases are not a goal and
+ none are attributed.
+ """
+
+ cost_per_result: Optional[float] = None
+ """
+ Spend divided by Whop pixel-attributed results; null when nothing
+ Whop-attributable is being optimized for.
+ """
+
+ cost_per_schedule: Optional[float] = None
+ """
+ Spend divided by attributed schedule events; null when schedules are not the
+ goal and none are attributed.
+ """
+
+ cost_per_submitted_application: Optional[float] = None
+ """
+ Spend divided by attributed submit-application events; null when they are not
+ the goal and none are attributed.
+ """
- budget: Optional[float] = None
- """Budget amount in dollars."""
+ cost_per_viewed_content: Optional[float] = None
+ """
+ Spend divided by attributed view-content events; null when they are not the goal
+ and none are attributed.
+ """
- budget_type: Optional[AdBudgetType] = None
- """The budget type for an ad campaign or ad group."""
+ created_at: str
+ """When the ad group was created, ISO 8601."""
- created_at: datetime
- """When the ad group was created."""
+ custom_conversions: float
+ """
+ Whop pixel-attributed custom (merchant-defined) conversion events, last-click,
+ across all custom event names.
+ """
- platform: AdCampaignPlatform
- """The external ad platform this ad group is running on (e.g., meta, tiktok)."""
+ demographics: object
+ """Demographic targeting: automatic (Advantage+), age range, gender."""
- status: AdGroupStatus
- """Current operational status of the ad group."""
+ desired_cost_per_result: Optional[float] = None
+ """Target/cap cost for average_target / maximum_target."""
+
+ devices: object
+ """Device targeting: platforms and operating systems."""
+
+ dynamic_creative: bool
+ """
+ Whether ads within this ad group have their creatives and copy dynamically AB
+ tested.
+ """
+
+ ends_at: Optional[str] = None
+ """Schedule end, ISO 8601."""
+
+ frequency: Optional[float] = None
+ """Platform-reported impressions divided by reach."""
+
+ frequency_cap: Optional[object] = None
+ """Impression cap; only valid for reach optimization."""
+
+ impressions: float
+ """The number of impressions."""
+
+ issues: List[Issue]
+
+ languages: List[str]
+
+ leads: float
+ """Whop pixel-attributed leads, last-click."""
+
+ message_apps: List[str]
+
+ minimum_daily_spend: Optional[float] = None
+ """Daily spend floor within the budget."""
+
+ optimization_goal: Optional[str] = None
+ """What the ad group optimizes for."""
+
+ placements: List[object]
+
+ purchase_value: float
+ """USD value of pixel-attributed purchases."""
+
+ purchases: float
+ """Whop pixel-attributed purchases, last-click."""
+
+ reach: float
+ """The number of unique people who saw this."""
+
+ regions: object
+ """Geo targeting: include/exclude countries, regions (ISO 3166-2 states, e.g.
+
+ US-CA), cities, zips.
+ """
+
+ result_event: Optional[
+ Literal[
+ "purchase",
+ "lead",
+ "schedule",
+ "submit_application",
+ "contact",
+ "complete_registration",
+ "view_content",
+ "add_to_cart",
+ "custom",
+ ]
+ ] = None
+ """
+ The Whop pixel conversion event whose attributed count represents results — the
+ optimization goal, or the highest-volume attributed event for campaigns that
+ budget per ad group. Null when the goal isn't a Whop-attributed event.
+ """
+
+ result_event_name: Optional[str] = None
+ """
+ The merchant-defined event name when result_event is custom; null for the
+ standard events.
+ """
+
+ return_on_ad_spend: float
+ """Purchase value divided by spend; 0 when there is no spend."""
+
+ schedules: float
+ """Whop pixel-attributed schedule events, last-click."""
+
+ spend: float
+ """The amount charged, in spend_currency."""
+
+ spend_currency: Optional[str] = None
+ """The ISO 4217 currency code of all monetary metrics."""
+
+ starts_at: Optional[str] = None
+ """Schedule start, ISO 8601."""
+
+ status: Literal["active", "paused", "rejected"]
+ """Delivery status of the ad group."""
+
+ submitted_applications: float
+ """Whop pixel-attributed submit-application events, last-click."""
title: Optional[str] = None
- """Human-readable name shown on the external platform."""
+ """The display title of the ad group."""
+
+ unique_click_through_rate: Optional[float] = None
+ """Unique clicks divided by impressions, between 0 and 1."""
+
+ unique_clicks: float
+ """The number of unique clicks."""
+
+ updated_at: str
+ """When the ad group was last updated, ISO 8601."""
- updated_at: datetime
- """When the ad group was last updated."""
+ viewed_contents: float
+ """Whop pixel-attributed view-content events, last-click."""
diff --git a/src/whop_sdk/types/ad_group_create_params.py b/src/whop_sdk/types/ad_group_create_params.py
new file mode 100644
index 00000000..5cbfb890
--- /dev/null
+++ b/src/whop_sdk/types/ad_group_create_params.py
@@ -0,0 +1,130 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List, Union
+from typing_extensions import Literal, Required, TypedDict
+
+from .._types import SequenceNotStr
+
+__all__ = ["AdGroupCreateParams"]
+
+
+class AdGroupCreateParams(TypedDict, total=False):
+ ad_campaign_id: Required[str]
+ """The ad campaign to create the ad group in."""
+
+ audiences: object
+ """Saved-audience targeting: { include, exclude } arrays of audience IDs.
+
+ Incompatible with demographics.automatic (Advantage+).
+ """
+
+ bid_type: Literal["minimum_cost", "average_target", "maximum_target"]
+ """Bid strategy."""
+
+ budget_amount: float
+ """Ad-set budget in dollars (ABO only; omit under CBO)."""
+
+ budget_type: Literal["daily", "lifetime"]
+ """Whether the budget is daily or lifetime."""
+
+ conversion_event: Union[
+ Literal[
+ "purchase",
+ "add_to_cart",
+ "initiated_checkout",
+ "add_payment_info",
+ "complete_registration",
+ "lead",
+ "content_view",
+ "search",
+ "contact",
+ "customize_product",
+ "donate",
+ "find_location",
+ "schedule",
+ "start_trial",
+ "submit_application",
+ "subscribe",
+ ],
+ str,
+ None,
+ ]
+ """The pixel event optimized for.
+
+ A standard event, or any custom pixel event name.
+ """
+
+ conversion_location: Literal[
+ "website",
+ "profile",
+ "messaging",
+ "on_ad",
+ "instant_forms",
+ "instant_forms_and_messenger",
+ "website_and_instant_forms",
+ ]
+ """
+ Where results happen: website (conversions), profile (IG/FB engagement),
+ messaging (DM), on_ad (engagement on the ad, surface follows the optimization
+ goal), or the lead destinations (instant_forms, instant_forms_and_messenger,
+ website_and_instant_forms). The lead form itself is set on the ad.
+ """
+
+ demographics: object
+ """Demographic targeting: { automatic, minimum_age, maximum_age, gender }."""
+
+ desired_cost_per_result: float
+ """Target/cap cost for average_target / maximum_target."""
+
+ devices: object
+ """Device targeting: { platforms, operating_systems: [{ os, minimum_version }] }."""
+
+ dynamic_creative: bool
+ """Run Meta dynamic (Advantage+) creative for this ad set.
+
+ Set at creation; immutable afterward.
+ """
+
+ ends_at: str
+ """Schedule end, ISO 8601."""
+
+ frequency_cap: object
+ """{ maximum_impressions, per_days } — only valid for reach optimization."""
+
+ languages: SequenceNotStr[str]
+ """Languages to target as ISO 639 codes (e.g.
+
+ en, es). Empty/omitted = all languages.
+ """
+
+ message_apps: List[Literal["messenger", "instagram", "whatsapp"]]
+ """Required when conversion_location is messaging: which apps to message on.
+
+ Combinations map to the matching Meta destination.
+ """
+
+ minimum_daily_spend: float
+ """Daily spend floor within the budget."""
+
+ optimization_goal: str
+ """What the ad group optimizes for (e.g. conversions, link_clicks, reach)."""
+
+ placements: object
+ """'automatic' (Advantage+) or a list of { platform, positions }."""
+
+ regions: object
+ """
+ Geo targeting: { include / exclude: { countries (ISO 3166-1), regions
+ (states/provinces as ISO 3166-2, e.g. US-CA), cities (keyed), zips } }.
+ """
+
+ starts_at: str
+ """Schedule start, ISO 8601."""
+
+ status: Literal["active", "paused"]
+ """Initial status (default: active)."""
+
+ title: str
+ """The display name of the ad group."""
diff --git a/src/whop_sdk/types/ad_group_list_params.py b/src/whop_sdk/types/ad_group_list_params.py
index 9bda52fb..856d60d4 100644
--- a/src/whop_sdk/types/ad_group_list_params.py
+++ b/src/whop_sdk/types/ad_group_list_params.py
@@ -2,49 +2,69 @@
from __future__ import annotations
-from typing import Union, Optional
-from datetime import datetime
-from typing_extensions import Annotated, TypedDict
-
-from .._utils import PropertyInfo
-from .ad_group_status import AdGroupStatus
+from typing_extensions import Literal, TypedDict
__all__ = ["AdGroupListParams"]
class AdGroupListParams(TypedDict, total=False):
- after: Optional[str]
- """Returns the elements in the list that come after the specified cursor."""
+ account_id: str
+ """Account whose ad groups to list. Defaults to the authenticated account."""
- before: Optional[str]
- """Returns the elements in the list that come before the specified cursor."""
+ ad_campaign_id: str
+ """Filter to ad groups in this campaign."""
- campaign_id: Optional[str]
- """Filter by campaign. Provide exactly one of campaign_id or company_id."""
+ after: str
+ """Cursor to fetch the page after (from page_info.end_cursor)."""
- company_id: Optional[str]
- """Filter by company. Provide exactly one of campaign_id or company_id."""
+ before: str
+ """Cursor to fetch the page before (from page_info.start_cursor)."""
- created_after: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
+ created_after: str
"""Only return ad groups created after this timestamp."""
- created_before: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
+ created_before: str
"""Only return ad groups created before this timestamp."""
- first: Optional[int]
- """Returns the first _n_ elements from the list."""
-
- include_paused: Optional[bool]
- """
- When false, excludes paused ad groups so pagination matches the dashboard's
- hide-paused toggle.
+ direction: Literal["asc", "desc"]
+ """The sort direction. Defaults to desc."""
+
+ first: int
+ """The number of ad groups to return."""
+
+ last: int
+ """The number of ad groups to return from the end of the range."""
+
+ order: Literal[
+ "created_at",
+ "updated_at",
+ "spend",
+ "impressions",
+ "clicks",
+ "reach",
+ "unique_clicks",
+ "results",
+ "click_through_rate",
+ "cost_per_click",
+ "cost_per_mille",
+ "cost_per_result",
+ "frequency",
+ "return_on_ad_spend",
+ ]
+ """The field to sort by.
+
+ Defaults to created_at. Stat columns (spend, impressions, …) rank over the
+ stats_from/stats_to window across the whole list, not just the current page.
"""
- last: Optional[int]
- """Returns the last _n_ elements from the list."""
+ query: str
+ """Filter ad groups by a title or ID substring."""
+
+ stats_from: str
+ """Start of the stats window. Defaults to all-time."""
- query: Optional[str]
- """Case-insensitive substring match against the ad group name."""
+ stats_to: str
+ """End of the stats window. Defaults to now."""
- status: Optional[AdGroupStatus]
- """The status of an external ad group."""
+ status: str
+ """Filter to a status (active, paused, in_review, rejected)."""
diff --git a/src/whop_sdk/types/ad_group_list_response.py b/src/whop_sdk/types/ad_group_list_response.py
deleted file mode 100644
index dac01854..00000000
--- a/src/whop_sdk/types/ad_group_list_response.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-from datetime import datetime
-
-from .._models import BaseModel
-from .ad_budget_type import AdBudgetType
-from .ad_group_status import AdGroupStatus
-from .ad_campaign_platform import AdCampaignPlatform
-
-__all__ = ["AdGroupListResponse", "AdCampaign"]
-
-
-class AdCampaign(BaseModel):
- """The ad campaign this ad group belongs to."""
-
- id: str
- """The unique identifier for this ad campaign."""
-
-
-class AdGroupListResponse(BaseModel):
- """An ad group (ad set) belonging to an ad campaign."""
-
- id: str
- """The unique identifier for this ad group."""
-
- ad_campaign: AdCampaign
- """The ad campaign this ad group belongs to."""
-
- budget: Optional[float] = None
- """Budget amount in dollars."""
-
- budget_type: Optional[AdBudgetType] = None
- """The budget type for an ad campaign or ad group."""
-
- created_at: datetime
- """When the ad group was created."""
-
- platform: AdCampaignPlatform
- """The external ad platform this ad group is running on (e.g., meta, tiktok)."""
-
- status: AdGroupStatus
- """Current operational status of the ad group."""
-
- title: Optional[str] = None
- """Human-readable name shown on the external platform."""
-
- updated_at: datetime
- """When the ad group was last updated."""
diff --git a/src/whop_sdk/types/ad_group_retrieve_params.py b/src/whop_sdk/types/ad_group_retrieve_params.py
new file mode 100644
index 00000000..f3982cec
--- /dev/null
+++ b/src/whop_sdk/types/ad_group_retrieve_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 TypedDict
+
+__all__ = ["AdGroupRetrieveParams"]
+
+
+class AdGroupRetrieveParams(TypedDict, total=False):
+ stats_from: str
+ """Start of the stats window."""
+
+ stats_to: str
+ """End of the stats window."""
diff --git a/src/whop_sdk/types/ad_group_status.py b/src/whop_sdk/types/ad_group_status.py
deleted file mode 100644
index 625dbfda..00000000
--- a/src/whop_sdk/types/ad_group_status.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing_extensions import Literal, TypeAlias
-
-__all__ = ["AdGroupStatus"]
-
-AdGroupStatus: TypeAlias = Literal["active", "paused", "inactive", "in_review", "rejected", "flagged"]
diff --git a/src/whop_sdk/types/ad_group_update_params.py b/src/whop_sdk/types/ad_group_update_params.py
index 97f6403e..8972976f 100644
--- a/src/whop_sdk/types/ad_group_update_params.py
+++ b/src/whop_sdk/types/ad_group_update_params.py
@@ -2,1220 +2,120 @@
from __future__ import annotations
-from typing import Dict, List, Iterable, Optional
-from typing_extensions import Literal, Required, TypedDict
+from typing import List, Union
+from typing_extensions import Literal, TypedDict
from .._types import SequenceNotStr
-from .ad_budget_type import AdBudgetType
-from .ad_group_status import AdGroupStatus
-__all__ = [
- "AdGroupUpdateParams",
- "Config",
- "ConfigTargeting",
- "PlatformConfig",
- "PlatformConfigMeta",
- "PlatformConfigMetaAttributionSpec",
- "PlatformConfigMetaExcludedGeoLocations",
- "PlatformConfigMetaExcludedGeoLocationsCity",
- "PlatformConfigMetaExcludedGeoLocationsRegion",
- "PlatformConfigMetaExcludedGeoLocationsZip",
- "PlatformConfigMetaGeoCity",
- "PlatformConfigMetaGeoLocations",
- "PlatformConfigMetaGeoLocationsCity",
- "PlatformConfigMetaGeoLocationsRegion",
- "PlatformConfigMetaGeoLocationsZip",
- "PlatformConfigMetaGeoRegion",
- "PlatformConfigMetaLeadFormConfig",
- "PlatformConfigMetaLeadFormConfigQuestion",
- "PlatformConfigMetaLeadFormConfigQuestionDependentConditionalQuestion",
- "PlatformConfigMetaLeadFormConfigQuestionDependentConditionalQuestionOption",
- "PlatformConfigMetaLeadFormConfigQuestionDependentConditionalQuestionOptionLogic",
- "PlatformConfigMetaLeadFormConfigQuestionOption",
- "PlatformConfigMetaLeadFormConfigQuestionOptionLogic",
- "PlatformConfigMetaLeadFormConfigCustomDisclaimerCheckbox",
- "PlatformConfigMetaLeadFormConfigThankYouPage",
- "PlatformConfigMetaPromotedObject",
- "PlatformConfigMetaTargetingAutomation",
- "PlatformConfigTiktok",
- "PlatformConfigTiktokAction",
- "PlatformConfigTiktokInstantFormConfig",
- "PlatformConfigTiktokInstantFormConfigQuestion",
-]
+__all__ = ["AdGroupUpdateParams"]
class AdGroupUpdateParams(TypedDict, total=False):
- budget: Optional[float]
- """Budget amount in dollars."""
+ audiences: object
+ """Saved-audience targeting: { include, exclude } arrays of audience IDs.
- budget_type: Optional[AdBudgetType]
- """The budget type for an ad campaign or ad group."""
-
- config: Optional[Config]
- """Unified ad group configuration (bidding, optimization, targeting)."""
-
- daily_budget: Optional[float]
- """Daily budget in dollars."""
-
- name: Optional[str]
- """Human-readable ad group name."""
-
- platform_config: Optional[PlatformConfig]
- """Platform-specific ad group configuration."""
-
- status: Optional[AdGroupStatus]
- """The status of an external ad group."""
-
-
-class ConfigTargeting(TypedDict, total=False):
- """Audience targeting settings (demographics, geo, interests, audiences, devices)."""
-
- age_max: Optional[int]
- """Maximum age for demographic targeting."""
-
- age_min: Optional[int]
- """Minimum age for demographic targeting."""
-
- countries: Optional[SequenceNotStr[str]]
- """ISO 3166-1 alpha-2 country codes to target."""
-
- device_platforms: Optional[List[Literal["mobile", "desktop"]]]
- """Device platforms to target."""
-
- exclude_audience_ids: Optional[SequenceNotStr[str]]
- """Platform audience IDs to exclude."""
-
- genders: Optional[List[Literal["male", "female", "all"]]]
- """Genders to target."""
-
- include_audience_ids: Optional[SequenceNotStr[str]]
- """Platform audience IDs to include."""
-
- interest_ids: Optional[SequenceNotStr[str]]
- """Platform-specific interest IDs to target."""
-
- languages: Optional[SequenceNotStr[str]]
- """Language codes to target."""
-
- placement_type: Optional[Literal["automatic", "manual"]]
- """Placement strategy for ad delivery."""
-
-
-class Config(TypedDict, total=False):
- """Unified ad group configuration (bidding, optimization, targeting)."""
-
- bid_amount: Optional[int]
- """Bid cap amount in cents. Used when bid_strategy is bid_cap or cost_cap."""
-
- bid_strategy: Optional[Literal["lowest_cost", "bid_cap", "cost_cap"]]
- """Bid strategy: lowest_cost, bid_cap, or cost_cap."""
-
- billing_event: Optional[Literal["impressions", "clicks", "optimized_cpm", "video_views"]]
- """How you are billed (e.g., impressions, clicks)."""
-
- end_time: Optional[str]
- """Scheduled end time (ISO8601). Required for lifetime budgets."""
-
- frequency_cap: Optional[int]
- """Maximum number of times to show ads to each person in the frequency interval."""
-
- frequency_cap_interval_days: Optional[int]
- """Number of days for the frequency cap interval."""
-
- optimization_goal: Optional[
- Literal[
- "conversions",
- "link_clicks",
- "landing_page_views",
- "reach",
- "impressions",
- "app_installs",
- "video_views",
- "lead_generation",
- "value",
- "page_likes",
- "conversations",
- "ad_recall_lift",
- "two_second_continuous_video_views",
- "post_engagement",
- "event_responses",
- "reminders_set",
- "quality_lead",
- ]
- ]
- """What the ad group optimizes for (e.g., conversions, link_clicks, reach)."""
-
- pacing: Optional[Literal["standard", "accelerated"]]
- """Budget pacing: standard (even) or accelerated (fast)."""
-
- start_time: Optional[str]
- """Scheduled start time (ISO8601)."""
-
- targeting: Optional[ConfigTargeting]
- """Audience targeting settings (demographics, geo, interests, audiences, devices)."""
-
-
-class PlatformConfigMetaAttributionSpec(TypedDict, total=False):
- """Meta conversion attribution window."""
-
- event_type: Required[str]
- """Attribution event type (e.g., CLICK_THROUGH, VIEW_THROUGH)."""
-
- window_days: Required[int]
- """Attribution window in days (1, 7, 28)."""
-
-
-class PlatformConfigMetaExcludedGeoLocationsCity(TypedDict, total=False):
- """A Meta geo target entry (region, city, or zip)."""
-
- key: Required[str]
- """Meta geo target key/ID."""
-
- country: Optional[str]
- """Country code for this entry."""
-
- name: Optional[str]
- """Display name."""
-
- radius: Optional[int]
- """Radius in miles (cities only)."""
-
-
-class PlatformConfigMetaExcludedGeoLocationsRegion(TypedDict, total=False):
- """A Meta geo target entry (region, city, or zip)."""
-
- key: Required[str]
- """Meta geo target key/ID."""
-
- country: Optional[str]
- """Country code for this entry."""
-
- name: Optional[str]
- """Display name."""
-
- radius: Optional[int]
- """Radius in miles (cities only)."""
-
-
-class PlatformConfigMetaExcludedGeoLocationsZip(TypedDict, total=False):
- """A Meta geo target entry (region, city, or zip)."""
-
- key: Required[str]
- """Meta geo target key/ID."""
-
- country: Optional[str]
- """Country code for this entry."""
-
- name: Optional[str]
- """Display name."""
-
- radius: Optional[int]
- """Radius in miles (cities only)."""
-
-
-class PlatformConfigMetaExcludedGeoLocations(TypedDict, total=False):
- """Geo locations to exclude."""
-
- cities: Optional[Iterable[PlatformConfigMetaExcludedGeoLocationsCity]]
- """City targets."""
-
- countries: Optional[SequenceNotStr[str]]
- """ISO 3166-1 alpha-2 country codes."""
-
- location_types: Optional[SequenceNotStr[str]]
- """Location types (home, recent, travel_in)."""
-
- regions: Optional[Iterable[PlatformConfigMetaExcludedGeoLocationsRegion]]
- """Region/state targets."""
-
- zips: Optional[Iterable[PlatformConfigMetaExcludedGeoLocationsZip]]
- """Zip/postal code targets."""
-
-
-class PlatformConfigMetaGeoCity(TypedDict, total=False):
- """A Meta geo target entry (region, city, or zip)."""
-
- key: Required[str]
- """Meta geo target key/ID."""
-
- country: Optional[str]
- """Country code for this entry."""
-
- name: Optional[str]
- """Display name."""
-
- radius: Optional[int]
- """Radius in miles (cities only)."""
-
-
-class PlatformConfigMetaGeoLocationsCity(TypedDict, total=False):
- """A Meta geo target entry (region, city, or zip)."""
-
- key: Required[str]
- """Meta geo target key/ID."""
-
- country: Optional[str]
- """Country code for this entry."""
-
- name: Optional[str]
- """Display name."""
-
- radius: Optional[int]
- """Radius in miles (cities only)."""
-
-
-class PlatformConfigMetaGeoLocationsRegion(TypedDict, total=False):
- """A Meta geo target entry (region, city, or zip)."""
-
- key: Required[str]
- """Meta geo target key/ID."""
-
- country: Optional[str]
- """Country code for this entry."""
-
- name: Optional[str]
- """Display name."""
-
- radius: Optional[int]
- """Radius in miles (cities only)."""
-
-
-class PlatformConfigMetaGeoLocationsZip(TypedDict, total=False):
- """A Meta geo target entry (region, city, or zip)."""
-
- key: Required[str]
- """Meta geo target key/ID."""
-
- country: Optional[str]
- """Country code for this entry."""
-
- name: Optional[str]
- """Display name."""
-
- radius: Optional[int]
- """Radius in miles (cities only)."""
-
-
-class PlatformConfigMetaGeoLocations(TypedDict, total=False):
- """Geo targeting (countries, regions, cities, zips)."""
-
- cities: Optional[Iterable[PlatformConfigMetaGeoLocationsCity]]
- """City targets."""
-
- countries: Optional[SequenceNotStr[str]]
- """ISO 3166-1 alpha-2 country codes."""
-
- location_types: Optional[SequenceNotStr[str]]
- """Location types (home, recent, travel_in)."""
-
- regions: Optional[Iterable[PlatformConfigMetaGeoLocationsRegion]]
- """Region/state targets."""
-
- zips: Optional[Iterable[PlatformConfigMetaGeoLocationsZip]]
- """Zip/postal code targets."""
-
-
-class PlatformConfigMetaGeoRegion(TypedDict, total=False):
- """A Meta geo target entry (region, city, or zip)."""
-
- key: Required[str]
- """Meta geo target key/ID."""
-
- country: Optional[str]
- """Country code for this entry."""
-
- name: Optional[str]
- """Display name."""
-
- radius: Optional[int]
- """Radius in miles (cities only)."""
-
-
-class PlatformConfigMetaLeadFormConfigQuestionDependentConditionalQuestionOptionLogic(TypedDict, total=False):
- """Conditional logic routing for this answer option."""
-
- type: Required[str]
- """Logic type: go_to_question, submit_form, or close_form."""
-
- target_end_page_index: Optional[int]
- """Index of the end page to route to (for submit_form type)."""
-
- target_question_index: Optional[int]
- """Index of the question to route to (for go_to_question type)."""
-
-
-class PlatformConfigMetaLeadFormConfigQuestionDependentConditionalQuestionOption(TypedDict, total=False):
- """An answer option for a multiple choice lead form question."""
-
- key: Required[str]
- """Unique key for this option."""
-
- value: Required[str]
- """Display text for this option."""
-
- logic: Optional[PlatformConfigMetaLeadFormConfigQuestionDependentConditionalQuestionOptionLogic]
- """Conditional logic routing for this answer option."""
-
-
-class PlatformConfigMetaLeadFormConfigQuestionDependentConditionalQuestion(TypedDict, total=False):
- """A dependent conditional question (non-recursive to avoid schema recursion)."""
-
- type: Required[str]
- """Question type (EMAIL, FULL_NAME, PHONE, CUSTOM, DATE_TIME, etc.)."""
-
- inline_context: Optional[str]
- """Helper text shown below the question."""
-
- key: Optional[str]
- """Unique key for this question."""
-
- label: Optional[str]
- """Custom label for CUSTOM questions."""
-
- options: Optional[Iterable[PlatformConfigMetaLeadFormConfigQuestionDependentConditionalQuestionOption]]
- """Answer options for multiple choice questions."""
-
-
-class PlatformConfigMetaLeadFormConfigQuestionOptionLogic(TypedDict, total=False):
- """Conditional logic routing for this answer option."""
-
- type: Required[str]
- """Logic type: go_to_question, submit_form, or close_form."""
-
- target_end_page_index: Optional[int]
- """Index of the end page to route to (for submit_form type)."""
-
- target_question_index: Optional[int]
- """Index of the question to route to (for go_to_question type)."""
-
-
-class PlatformConfigMetaLeadFormConfigQuestionOption(TypedDict, total=False):
- """An answer option for a multiple choice lead form question."""
-
- key: Required[str]
- """Unique key for this option."""
-
- value: Required[str]
- """Display text for this option."""
-
- logic: Optional[PlatformConfigMetaLeadFormConfigQuestionOptionLogic]
- """Conditional logic routing for this answer option."""
-
-
-class PlatformConfigMetaLeadFormConfigQuestion(TypedDict, total=False):
- """A question on a Meta lead gen form."""
-
- type: Required[str]
- """Question type (EMAIL, FULL_NAME, PHONE, CUSTOM, DATE_TIME, etc.)."""
-
- conditional_questions_group_id: Optional[str]
- """Group ID for conditional question routing."""
-
- dependent_conditional_questions: Optional[
- Iterable[PlatformConfigMetaLeadFormConfigQuestionDependentConditionalQuestion]
- ]
- """Questions shown conditionally based on this question's answer."""
-
- inline_context: Optional[str]
- """Helper text shown below the question."""
-
- key: Optional[str]
- """Unique key for this question."""
-
- label: Optional[str]
- """Custom label for CUSTOM questions."""
-
- options: Optional[Iterable[PlatformConfigMetaLeadFormConfigQuestionOption]]
- """Answer options for multiple choice CUSTOM questions."""
-
- question_format: Optional[str]
- """UI hint: short_answer, multiple_choice, or appointment."""
-
-
-class PlatformConfigMetaLeadFormConfigCustomDisclaimerCheckbox(TypedDict, total=False):
- """A consent checkbox for the custom disclaimer section."""
-
- key: Required[str]
- """Unique key for this checkbox."""
-
- text: Required[str]
- """Label text for the checkbox."""
-
- is_checked_by_default: Optional[bool]
- """Whether the checkbox is checked by default."""
-
- is_required: Optional[bool]
- """Whether the checkbox must be checked to submit."""
-
-
-class PlatformConfigMetaLeadFormConfigThankYouPage(TypedDict, total=False):
- """A thank-you / ending page for a Meta lead gen form."""
-
- body: Optional[str]
- """Body text for this ending page."""
-
- business_phone: Optional[str]
- """Business phone number for call CTA."""
-
- button_text: Optional[str]
- """Custom button text."""
-
- button_type: Optional[str]
- """CTA button type: VIEW_WEBSITE, CALL_BUSINESS, DOWNLOAD."""
-
- conditional_question_group_id: Optional[str]
- """Question group ID for conditional routing to this page."""
-
- enable_messenger: Optional[bool]
- """Enable Messenger follow-up."""
-
- gated_file_url: Optional[str]
- """Uploaded file URL for gated content download."""
-
- link: Optional[str]
- """URL the button links to."""
-
- name: Optional[str]
- """Internal name for this ending page."""
-
- title: Optional[str]
- """Headline for this ending page."""
-
-
-class PlatformConfigMetaLeadFormConfig(TypedDict, total=False):
- """Configuration for a Meta lead gen instant form."""
-
- name: Required[str]
- """Name of the lead form."""
-
- privacy_policy_url: Required[str]
- """URL to your privacy policy. Required by Meta."""
-
- questions: Required[Iterable[PlatformConfigMetaLeadFormConfigQuestion]]
- """Questions to ask on the form."""
-
- background_image_source: Optional[str]
- """Background image source: from_ad or custom."""
-
- background_image_url: Optional[str]
- """URL of custom background image."""
-
- conditional_logic_enabled: Optional[bool]
- """Whether conditional logic is enabled for questions."""
-
- context_card_button_text: Optional[str]
- """CTA button text on the greeting card."""
-
- context_card_content: Optional[SequenceNotStr[str]]
- """Optional greeting card bullet points."""
-
- context_card_style: Optional[str]
- """Greeting layout: PARAGRAPH_STYLE or LIST_STYLE."""
-
- context_card_title: Optional[str]
- """Optional greeting card title."""
-
- custom_disclaimer_body: Optional[str]
- """Custom disclaimer body text."""
-
- custom_disclaimer_checkboxes: Optional[Iterable[PlatformConfigMetaLeadFormConfigCustomDisclaimerCheckbox]]
- """Consent checkboxes for the custom disclaimer."""
-
- custom_disclaimer_title: Optional[str]
- """Custom disclaimer section title."""
-
- form_type: Optional[str]
- """Form type: more_volume, higher_intent, or rich_creative."""
-
- messenger_enabled: Optional[bool]
- """Enable Messenger follow-up after form submission."""
-
- phone_verification_enabled: Optional[bool]
- """Require phone number verification via OTP (higher_intent only)."""
-
- privacy_policy_link_text: Optional[str]
- """Custom link text for privacy policy (max 70 chars)."""
-
- question_page_custom_headline: Optional[str]
- """Custom headline for the questions page."""
-
- rich_creative_headline: Optional[str]
- """Headline for rich creative form intro."""
-
- rich_creative_overview: Optional[str]
- """Overview description for rich creative form intro."""
-
- rich_creative_url: Optional[str]
- """Uploaded image URL for rich creative form type."""
-
- thank_you_pages: Optional[Iterable[PlatformConfigMetaLeadFormConfigThankYouPage]]
- """Thank you / ending pages (supports multiple for conditional routing)."""
-
-
-class PlatformConfigMetaPromotedObject(TypedDict, total=False):
- """The object this ad set promotes (pixel, page, etc.)."""
-
- custom_conversion_id: Optional[str]
- """Custom conversion rule ID (numeric, from Meta Events Manager)."""
-
- custom_event_str: Optional[str]
- """Pixel event name, used when custom_event_type is OTHER."""
-
- custom_event_type: Optional[str]
- """Custom event type (e.g., PURCHASE, COMPLETE_REGISTRATION, OTHER)."""
-
- page_id: Optional[str]
- """Facebook Page ID."""
-
- pixel_id: Optional[str]
- """Meta Pixel ID for conversion tracking."""
-
- whatsapp_phone_number: Optional[str]
- """WhatsApp phone number for messaging campaigns."""
-
-
-class PlatformConfigMetaTargetingAutomation(TypedDict, total=False):
- """Advantage+ audience expansion settings."""
-
- advantage_audience: Optional[int]
- """0 = off (use exact targeting), 1 = on (let Meta expand audience)."""
-
-
-class PlatformConfigMeta(TypedDict, total=False):
- """Meta (Facebook/Instagram) ad set configuration."""
-
- android_devices: Optional[SequenceNotStr[str]]
-
- attribution_setting: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
+ Incompatible with demographics.automatic (Advantage+).
"""
- attribution_spec: Optional[Iterable[PlatformConfigMetaAttributionSpec]]
- """Conversion attribution windows."""
-
- audience_network_positions: Optional[SequenceNotStr[str]]
+ bid_type: Literal["minimum_cost", "average_target", "maximum_target"]
+ """Bid strategy."""
- audience_type: Optional[str]
- """Audience type for retargeting."""
+ budget_amount: float
+ """Ad-set budget in dollars (ABO only; omit under CBO)."""
- bid_amount: Optional[int]
- """Bid amount in cents."""
+ budget_type: Literal["daily", "lifetime"]
+ """Whether the budget is daily or lifetime."""
- bid_strategy: Optional[
- Literal["LOWEST_COST_WITHOUT_CAP", "LOWEST_COST_WITH_BID_CAP", "COST_CAP", "LOWEST_COST_WITH_MIN_ROAS"]
- ]
- """Meta bid strategy."""
-
- billing_event: Optional[
+ conversion_event: Union[
Literal[
- "APP_INSTALLS",
- "CLICKS",
- "IMPRESSIONS",
- "LINK_CLICKS",
- "NONE",
- "OFFER_CLAIMS",
- "PAGE_LIKES",
- "POST_ENGAGEMENT",
- "THRUPLAY",
- "PURCHASE",
- "LISTING_INTERACTION",
- ]
+ "purchase",
+ "add_to_cart",
+ "initiated_checkout",
+ "add_payment_info",
+ "complete_registration",
+ "lead",
+ "content_view",
+ "search",
+ "contact",
+ "customize_product",
+ "donate",
+ "find_location",
+ "schedule",
+ "start_trial",
+ "submit_application",
+ "subscribe",
+ ],
+ str,
+ None,
]
- """How you are billed on Meta."""
-
- brand_safety_content_filter_levels: Optional[SequenceNotStr[str]]
-
- budget_remaining: Optional[str]
- """Represents textual data as UTF-8 character sequences.
+ """The pixel event optimized for.
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- cost_per_result_goal: Optional[float]
- """
- Represents signed double-precision fractional values as specified by
- [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).
+ A standard event, or any custom pixel event name.
"""
- created_time: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- daily_budget: Optional[int]
- """Daily budget in cents."""
-
- daily_min_spend_target: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- daily_spend_cap: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- destination_type: Optional[
- Literal[
- "UNDEFINED",
- "WEBSITE",
- "APP",
- "FACEBOOK",
- "MESSENGER",
- "WHATSAPP",
- "INSTAGRAM_DIRECT",
- "INSTAGRAM_PROFILE",
- "PHONE_CALL",
- "SHOP_AUTOMATIC",
- "APPLINKS_AUTOMATIC",
- "ON_AD",
- "ON_POST",
- "ON_VIDEO",
- "ON_PAGE",
- "ON_EVENT",
- "MESSAGING_MESSENGER_WHATSAPP",
- "MESSAGING_INSTAGRAM_DIRECT_MESSENGER",
- "MESSAGING_INSTAGRAM_DIRECT_WHATSAPP",
- "MESSAGING_INSTAGRAM_DIRECT_MESSENGER_WHATSAPP",
- "INSTAGRAM_PROFILE_AND_FACEBOOK_PAGE",
- "FACEBOOK_PAGE",
- "INSTAGRAM_LIVE",
- "FACEBOOK_LIVE",
- "IMAGINE",
- "LEAD_FROM_IG_DIRECT",
- "LEAD_FROM_MESSENGER",
- "LEAD_FORM_MESSENGER",
- "WEBSITE_AND_LEAD_FORM",
- "WEBSITE_AND_PHONE_CALL",
- "BROADCAST_CHANNEL",
- ]
+ conversion_location: Literal[
+ "website",
+ "profile",
+ "messaging",
+ "on_ad",
+ "instant_forms",
+ "instant_forms_and_messenger",
+ "website_and_instant_forms",
]
- """Where ads in this ad set direct people."""
-
- dsa_beneficiary: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
"""
-
- dsa_payor: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
+ Where results happen: website (conversions), profile (IG/FB engagement),
+ messaging (DM), on_ad (engagement on the ad, surface follows the optimization
+ goal), or the lead destinations (instant_forms, instant_forms_and_messenger,
+ website_and_instant_forms). The lead form itself is set on the ad.
"""
- end_time: Optional[str]
- """End time (ISO8601). Required for lifetime budgets."""
+ demographics: object
+ """Demographic targeting: { automatic, minimum_age, maximum_age, gender }."""
- excluded_geo_locations: Optional[PlatformConfigMetaExcludedGeoLocations]
- """Geo locations to exclude."""
+ desired_cost_per_result: float
+ """Target/cap cost for average_target / maximum_target."""
- facebook_positions: Optional[SequenceNotStr[str]]
- """Facebook ad placements (feed, reels, stories, etc.)."""
+ devices: object
+ """Device targeting: { platforms, operating_systems: [{ os, minimum_version }] }."""
- frequency_control_count: Optional[int]
- """Represents non-fractional signed whole numeric values.
+ ends_at: str
+ """Schedule end, ISO 8601."""
- Int can represent values between -(2^31) and 2^31 - 1.
- """
+ frequency_cap: object
+ """{ maximum_impressions, per_days } — only valid for reach optimization."""
- frequency_control_days: Optional[int]
- """Represents non-fractional signed whole numeric values.
+ languages: SequenceNotStr[str]
+ """Languages to target as ISO 639 codes (e.g.
- Int can represent values between -(2^31) and 2^31 - 1.
+ en, es). Empty/omitted = all languages.
"""
- frequency_control_type: Optional[str]
- """Represents textual data as UTF-8 character sequences.
+ message_apps: List[Literal["messenger", "instagram", "whatsapp"]]
+ """Required when conversion_location is messaging: which apps to message on.
- This type is most often used by GraphQL to represent free-form human-readable
- text.
+ Combinations map to the matching Meta destination.
"""
- geo_cities: Optional[Iterable[PlatformConfigMetaGeoCity]]
-
- geo_locations: Optional[PlatformConfigMetaGeoLocations]
- """Geo targeting (countries, regions, cities, zips)."""
-
- geo_regions: Optional[Iterable[PlatformConfigMetaGeoRegion]]
+ minimum_daily_spend: float
+ """Daily spend floor within the budget."""
- geo_zips: Optional[SequenceNotStr[str]]
+ optimization_goal: str
+ """What the ad group optimizes for (e.g. conversions, link_clicks, reach)."""
- instagram_actor_id: Optional[str]
- """Instagram account ID for this ad set."""
+ placements: object
+ """'automatic' (Advantage+) or a list of { platform, positions }."""
- instagram_positions: Optional[SequenceNotStr[str]]
- """Instagram ad placements (stream, story, reels, etc.)."""
-
- ios_devices: Optional[SequenceNotStr[str]]
-
- is_dynamic_creative: Optional[bool]
- """Represents `true` or `false` values."""
-
- lead_conversion_location: Optional[
- Literal["website", "instant_forms", "website_and_instant_forms", "messenger", "instagram", "calls", "app"]
- ]
-
- lead_form_config: Optional[PlatformConfigMetaLeadFormConfig]
- """Configuration for a Meta lead gen instant form."""
-
- lead_gen_form_id: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- lifetime_budget: Optional[int]
- """Lifetime budget in cents."""
-
- lifetime_min_spend_target: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- lifetime_spend_cap: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
+ regions: object
"""
-
- location_types: Optional[SequenceNotStr[str]]
-
- messenger_positions: Optional[SequenceNotStr[str]]
-
- optimization_goal: Optional[
- Literal[
- "NONE",
- "APP_INSTALLS",
- "AD_RECALL_LIFT",
- "ENGAGED_USERS",
- "EVENT_RESPONSES",
- "IMPRESSIONS",
- "LEAD_GENERATION",
- "QUALITY_LEAD",
- "LINK_CLICKS",
- "OFFSITE_CONVERSIONS",
- "PAGE_LIKES",
- "POST_ENGAGEMENT",
- "QUALITY_CALL",
- "REACH",
- "LANDING_PAGE_VIEWS",
- "VISIT_INSTAGRAM_PROFILE",
- "VALUE",
- "THRUPLAY",
- "DERIVED_EVENTS",
- "APP_INSTALLS_AND_OFFSITE_CONVERSIONS",
- "CONVERSATIONS",
- "IN_APP_VALUE",
- "MESSAGING_PURCHASE_CONVERSION",
- "SUBSCRIBERS",
- "REMINDERS_SET",
- "MEANINGFUL_CALL_ATTEMPT",
- "PROFILE_VISIT",
- "PROFILE_AND_PAGE_ENGAGEMENT",
- "TWO_SECOND_CONTINUOUS_VIDEO_VIEWS",
- "ENGAGED_REACH",
- "ENGAGED_PAGE_VIEWS",
- "MESSAGING_DEEP_CONVERSATION_AND_FOLLOW",
- "ADVERTISER_SILOED_VALUE",
- "AUTOMATIC_OBJECTIVE",
- "MESSAGING_APPOINTMENT_CONVERSION",
- ]
- ]
- """What this ad set optimizes for on Meta."""
-
- page_id: Optional[str]
- """Facebook Page ID for this ad set."""
-
- pixel_id: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
+ Geo targeting: { include / exclude: { countries (ISO 3166-1), regions
+ (states/provinces as ISO 3166-2, e.g. US-CA), cities (keyed), zips } }.
"""
- promoted_object: Optional[PlatformConfigMetaPromotedObject]
- """The object this ad set promotes (pixel, page, etc.)."""
-
- publisher_platforms: Optional[SequenceNotStr[str]]
- """Platforms to publish on (facebook, instagram, messenger, audience_network)."""
-
- source_adset_id: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- start_time: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- status: Optional[Literal["ACTIVE", "PAUSED"]]
-
- targeting_automation: Optional[PlatformConfigMetaTargetingAutomation]
- """Advantage+ audience expansion settings."""
-
- threads_positions: Optional[SequenceNotStr[str]]
-
- updated_time: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- user_device: Optional[SequenceNotStr[str]]
-
- user_os: Optional[SequenceNotStr[str]]
-
- whatsapp_phone_number: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- whatsapp_positions: Optional[SequenceNotStr[str]]
-
-
-class PlatformConfigTiktokAction(TypedDict, total=False):
- """A single TikTok behavioral targeting entry.
-
- One category of past user behavior (what they did, over what window, on which kind of content). See docs/tiktok_api/ad_group.md § actions.
- """
-
- action_category_ids: Optional[SequenceNotStr[str]]
- """Behavioral category IDs. Use /tool/action_category/ to list them."""
-
- action_period: Optional[int]
- """Lookback window in days. TikTok accepts 7, 15, 30, 60, 90, or 180."""
-
- action_scene: Optional[Literal["VIDEO_RELATED", "CREATOR_RELATED", "HASHTAG_RELATED", "LIVE_RELATED"]]
- """The category of TikTok content a behavioral targeting rule applies to.
-
- See docs/tiktok_api/ad_group.md § actions.
- """
-
- video_user_actions: Optional[
- List[Literal["WATCHED_TO_END", "LIKED", "COMMENTED", "SHARED", "FOLLOWED", "PROFILE_VISITED"]]
- ]
- """
- Specific video interactions (WATCHED_TO_END, LIKED, COMMENTED, SHARED, FOLLOWED,
- PROFILE_VISITED).
- """
-
-
-class PlatformConfigTiktokInstantFormConfigQuestion(TypedDict, total=False):
- """A question for a TikTok instant form."""
-
- field_type: Required[str]
- """Question type (EMAIL, PHONE_NUMBER, NAME, CUSTOM)."""
-
- label: Optional[str]
- """Custom label for the question."""
-
-
-class PlatformConfigTiktokInstantFormConfig(TypedDict, total=False):
- """Instant form configuration for lead generation campaigns."""
-
- privacy_policy_url: Required[str]
- """URL to your privacy policy."""
-
- questions: Required[Iterable[PlatformConfigTiktokInstantFormConfigQuestion]]
- """Form questions (at least one required)."""
-
- button_text: Optional[str]
- """Submit button text."""
-
- greeting: Optional[str]
- """Greeting text shown at the top of the form."""
-
- name: Optional[str]
- """Form name. Auto-generated if omitted."""
-
-
-class PlatformConfigTiktok(TypedDict, total=False):
- """TikTok ad group configuration."""
-
- actions: Optional[Iterable[PlatformConfigTiktokAction]]
-
- age_groups: Optional[List[Literal["AGE_13_17", "AGE_18_24", "AGE_25_34", "AGE_35_44", "AGE_45_54", "AGE_55_100"]]]
-
- app_id: Optional[str]
- """App ID for app promotion campaigns."""
-
- attribution_event_count: Optional[Literal["UNSET", "EVERY", "ONCE"]]
-
- audience_ids: Optional[SequenceNotStr[str]]
-
- audience_rule: Optional[Dict[str, object]]
- """Represents untyped JSON"""
-
- audience_type: Optional[Literal["NORMAL", "SMART_INTERESTS_BEHAVIORS"]]
-
- bid_price: Optional[float]
- """Bid price (cost per result for Cost Cap)."""
-
- bid_type: Optional[Literal["BID_TYPE_NO_BID", "BID_TYPE_CUSTOM"]]
- """Bidding strategy (BID_TYPE_NO_BID, BID_TYPE_CUSTOM)."""
-
- billing_event: Optional[Literal["CPC", "CPM", "OCPM", "CPV"]]
- """How you are billed on TikTok (CPC, CPM, OCPM, CPV)."""
-
- brand_safety_type: Optional[
- Literal["NO_BRAND_SAFETY", "STANDARD_INVENTORY", "LIMITED_INVENTORY", "FULL_INVENTORY", "EXPANDED_INVENTORY"]
- ]
-
- budget_mode: Optional[Literal["BUDGET_MODE_DAY", "BUDGET_MODE_TOTAL", "BUDGET_MODE_DYNAMIC_DAILY_BUDGET"]]
- """
- Budget mode (BUDGET_MODE_DAY, BUDGET_MODE_TOTAL,
- BUDGET_MODE_DYNAMIC_DAILY_BUDGET).
- """
-
- carrier_ids: Optional[SequenceNotStr[str]]
-
- category_exclusion_ids: Optional[SequenceNotStr[str]]
-
- click_attribution_window: Optional[Literal["OFF", "ONE_DAY", "SEVEN_DAYS", "FOURTEEN_DAYS", "TWENTY_EIGHT_DAYS"]]
-
- comment_disabled: Optional[bool]
- """Represents `true` or `false` values."""
-
- contextual_tag_ids: Optional[SequenceNotStr[str]]
-
- conversion_bid_price: Optional[float]
- """Target cost per conversion for oCPM."""
-
- creative_material_mode: Optional[str]
- """Creative delivery strategy."""
-
- dayparting: Optional[str]
- """Ad delivery schedule (48x7 character string)."""
-
- deep_funnel_event_source: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- deep_funnel_event_source_id: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- deep_funnel_optimization_status: Optional[Literal["ON", "OFF"]]
-
- device_model_ids: Optional[SequenceNotStr[str]]
-
- device_price_ranges: Optional[SequenceNotStr[str]]
-
- engaged_view_attribution_window: Optional[Literal["OFF", "ONE_DAY", "SEVEN_DAYS"]]
-
- excluded_audience_ids: Optional[SequenceNotStr[str]]
-
- excluded_location_ids: Optional[SequenceNotStr[str]]
- """TikTok location/region IDs to exclude."""
-
- frequency: Optional[int]
- """Represents non-fractional signed whole numeric values.
-
- Int can represent values between -(2^31) and 2^31 - 1.
- """
-
- frequency_schedule: Optional[int]
- """Represents non-fractional signed whole numeric values.
-
- Int can represent values between -(2^31) and 2^31 - 1.
- """
-
- gender: Optional[Literal["GENDER_UNLIMITED", "GENDER_MALE", "GENDER_FEMALE"]]
-
- identity_authorized_bc_id: Optional[str]
- """Business Center ID for BC_AUTH_TT identity."""
-
- identity_id: Optional[str]
- """TikTok identity ID for the ad group."""
-
- identity_type: Optional[str]
- """Identity type (AUTH_CODE, TT_USER, BC_AUTH_TT)."""
-
- instant_form_config: Optional[PlatformConfigTiktokInstantFormConfig]
- """Instant form configuration for lead generation campaigns."""
-
- instant_form_id: Optional[str]
- """
- TikTok instant form ID (set automatically when instant_form_config is provided).
- """
-
- interest_category_ids: Optional[SequenceNotStr[str]]
-
- interest_keyword_ids: Optional[SequenceNotStr[str]]
-
- inventory_filter_enabled: Optional[bool]
- """Represents `true` or `false` values."""
-
- ios14_targeting: Optional[Literal["UNSET", "IOS14_MINUS", "IOS14_PLUS", "ALL"]]
-
- isp_ids: Optional[SequenceNotStr[str]]
-
- languages: Optional[SequenceNotStr[str]]
-
- location_ids: Optional[SequenceNotStr[str]]
- """TikTok location/region IDs for geo targeting."""
-
- min_android_version: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- min_ios_version: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- network_types: Optional[SequenceNotStr[str]]
-
- operating_systems: Optional[List[Literal["ANDROID", "IOS"]]]
-
- operation_status: Optional[Literal["ENABLE", "DISABLE"]]
- """Initial status (ENABLE, DISABLE)."""
-
- optimization_event: Optional[str]
- """Conversion event (e.g., COMPLETE_PAYMENT)."""
-
- optimization_goal: Optional[
- Literal[
- "CLICK",
- "CONVERT",
- "INSTALL",
- "IN_APP_EVENT",
- "REACH",
- "SHOW",
- "VIDEO_VIEW",
- "ENGAGED_VIEW",
- "ENGAGED_VIEW_FIFTEEN",
- "LEAD_GENERATION",
- "PREFERRED_LEAD",
- "CONVERSATION",
- "FOLLOWERS",
- "PROFILE_VIEWS",
- "PAGE_VISIT",
- "VALUE",
- "AUTOMATIC_VALUE_OPTIMIZATION",
- "TRAFFIC_LANDING_PAGE_VIEW",
- "DESTINATION_VISIT",
- "MT_LIVE_ROOM",
- "PRODUCT_CLICK_IN_LIVE",
- ]
- ]
- """What this ad group optimizes for on TikTok."""
-
- pacing: Optional[Literal["PACING_MODE_SMOOTH", "PACING_MODE_FAST"]]
- """Budget pacing (PACING_MODE_SMOOTH, PACING_MODE_FAST)."""
-
- pangle_audience_package_exclude_ids: Optional[SequenceNotStr[str]]
-
- pangle_audience_package_include_ids: Optional[SequenceNotStr[str]]
-
- pangle_block_app_ids: Optional[SequenceNotStr[str]]
-
- pixel_id: Optional[str]
- """TikTok Pixel ID for conversion tracking."""
-
- placement_type: Optional[Literal["PLACEMENT_TYPE_AUTOMATIC", "PLACEMENT_TYPE_NORMAL"]]
- """Placement strategy (PLACEMENT_TYPE_AUTOMATIC, PLACEMENT_TYPE_NORMAL)."""
-
- placements: Optional[SequenceNotStr[str]]
- """Placements (PLACEMENT_TIKTOK, PLACEMENT_PANGLE, etc.)."""
-
- product_set_id: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- product_source: Optional[Literal["CATALOG", "STORE", "SHOWCASE"]]
-
- promotion_type: Optional[str]
- """Promotion type (optimization location)."""
-
- schedule_end_time: Optional[str]
- """Schedule end time (UTC, YYYY-MM-DD HH:MM:SS)."""
-
- schedule_start_time: Optional[str]
- """Schedule start time (UTC, YYYY-MM-DD HH:MM:SS)."""
-
- schedule_type: Optional[Literal["SCHEDULE_START_END", "SCHEDULE_FROM_NOW"]]
- """Schedule type (SCHEDULE_START_END, SCHEDULE_FROM_NOW)."""
-
- secondary_optimization_event: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- shopping_ads_retargeting_actions_days: Optional[int]
- """Represents non-fractional signed whole numeric values.
-
- Int can represent values between -(2^31) and 2^31 - 1.
- """
-
- shopping_ads_retargeting_type: Optional[Literal["OFF", "LAB1", "LAB2", "LAB3", "LAB4", "LAB5"]]
-
- spending_power: Optional[Literal["ALL", "HIGH"]]
-
- tiktok_subplacements: Optional[SequenceNotStr[str]]
- """TikTok subplacements (IN_FEED, SEARCH_FEED, etc.)."""
-
- vertical_sensitivity_id: Optional[str]
- """Represents textual data as UTF-8 character sequences.
-
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
-
- video_download_disabled: Optional[bool]
- """Represents `true` or `false` values."""
-
- video_user_actions: Optional[SequenceNotStr[str]]
-
- view_attribution_window: Optional[Literal["OFF", "ONE_DAY", "SEVEN_DAYS"]]
-
-
-class PlatformConfig(TypedDict, total=False):
- """Platform-specific ad group configuration."""
+ starts_at: str
+ """Schedule start, ISO 8601."""
- meta: Optional[PlatformConfigMeta]
- """Meta (Facebook/Instagram) ad set configuration."""
+ status: Literal["active", "paused"]
+ """Initial status (default: active)."""
- tiktok: Optional[PlatformConfigTiktok]
- """TikTok ad group configuration."""
+ title: str
+ """The display name of the ad group."""
diff --git a/src/whop_sdk/types/ad_list_params.py b/src/whop_sdk/types/ad_list_params.py
index f89c77d2..dcc24878 100644
--- a/src/whop_sdk/types/ad_list_params.py
+++ b/src/whop_sdk/types/ad_list_params.py
@@ -2,74 +2,75 @@
from __future__ import annotations
-from typing import Union, Optional
-from datetime import datetime
-from typing_extensions import Literal, Annotated, TypedDict
-
-from .._utils import PropertyInfo
-from .shared.direction import Direction
-from .external_ad_status import ExternalAdStatus
+from typing_extensions import Literal, TypedDict
__all__ = ["AdListParams"]
class AdListParams(TypedDict, total=False):
- ad_group_id: Optional[str]
- """Filter by ad group.
+ account_id: str
+ """The account the ads belong to.
- Provide exactly one of ad_group_id, campaign_id, or company_id.
+ Defaults to the account-scoped key's own account.
"""
- 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."""
+ ad_campaign_id: str
+ """Only return ads in this ad campaign."""
- campaign_id: Optional[str]
- """Filter by campaign.
+ ad_group_id: str
+ """Only return ads in this ad group."""
- Provide exactly one of ad_group_id, campaign_id, or company_id.
- """
+ after: str
+ """Cursor to fetch the page after (from page_info.end_cursor)."""
- company_id: Optional[str]
- """Filter by company.
-
- Provide exactly one of ad_group_id, campaign_id, or company_id.
- """
+ before: str
+ """Cursor to fetch the page before (from page_info.start_cursor)."""
- created_after: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
+ created_after: str
"""Only return ads created after this timestamp."""
- created_before: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
+ created_before: str
"""Only return ads created before this timestamp."""
- first: Optional[int]
- """Returns the first _n_ elements from the list."""
-
- include_paused: Optional[bool]
- """
- When false, excludes paused ads so pagination matches the dashboard's
- hide-paused toggle.
+ direction: Literal["asc", "desc"]
+ """The sort direction. Defaults to desc."""
+
+ first: int
+ """The number of ads to return."""
+
+ last: int
+ """The number of ads to return from the end of the range."""
+
+ order: Literal[
+ "created_at",
+ "updated_at",
+ "spend",
+ "impressions",
+ "clicks",
+ "reach",
+ "unique_clicks",
+ "results",
+ "click_through_rate",
+ "cost_per_click",
+ "cost_per_mille",
+ "cost_per_result",
+ "frequency",
+ "return_on_ad_spend",
+ ]
+ """The field to sort by.
+
+ Defaults to created_at. Stat columns (spend, impressions, …) rank over the
+ stats_from/stats_to window across the whole list, not just the current page.
"""
- last: Optional[int]
- """Returns the last _n_ elements from the list."""
-
- order_by: Optional[Literal["spend", "roas"]]
- """Columns that the listAds query can sort by."""
-
- order_direction: Optional[Direction]
- """The direction of the sort."""
-
- query: Optional[str]
- """Case-insensitive substring match against the ad title or tag."""
+ query: str
+ """Filter ads by a title or ID substring."""
- stats_from: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """Start of the stats date range used when order_by is a stats column."""
+ stats_from: str
+ """Start of the stats window. Defaults to all-time."""
- stats_to: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """End of the stats date range used when order_by is a stats column."""
+ stats_to: str
+ """End of the stats window. Defaults to now."""
- status: Optional[ExternalAdStatus]
- """The status of an external ad."""
+ status: Literal["active", "paused", "in_review", "rejected"]
+ """Only return ads with this status."""
diff --git a/src/whop_sdk/types/ad_list_response.py b/src/whop_sdk/types/ad_list_response.py
deleted file mode 100644
index f6a13bac..00000000
--- a/src/whop_sdk/types/ad_list_response.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-from datetime import datetime
-
-from .._models import BaseModel
-from .external_ad_status import ExternalAdStatus
-from .ad_campaign_platform import AdCampaignPlatform
-
-__all__ = ["AdListResponse", "AdCampaign", "AdGroup"]
-
-
-class AdCampaign(BaseModel):
- """The ad campaign this ad belongs to."""
-
- id: str
- """The unique identifier for this ad campaign."""
-
-
-class AdGroup(BaseModel):
- """The parent ad group this ad belongs to."""
-
- id: str
- """The unique identifier for this ad group."""
-
-
-class AdListResponse(BaseModel):
- """An ad belonging to an ad group."""
-
- id: str
- """The unique identifier for this ad."""
-
- ad_campaign: AdCampaign
- """The ad campaign this ad belongs to."""
-
- ad_group: AdGroup
- """The parent ad group this ad belongs to."""
-
- created_at: datetime
- """When the ad was created."""
-
- platform: AdCampaignPlatform
- """The external ad platform this ad is running on (e.g., meta, tiktok)."""
-
- status: ExternalAdStatus
- """Current delivery status of the ad."""
-
- title: Optional[str] = None
- """The display title of the ad. Falls back to the creative set caption when unset."""
-
- updated_at: datetime
- """When the ad was last updated."""
diff --git a/src/whop_sdk/types/ad_report_retrieve_params.py b/src/whop_sdk/types/ad_report_retrieve_params.py
index 9a779523..2b66d934 100644
--- a/src/whop_sdk/types/ad_report_retrieve_params.py
+++ b/src/whop_sdk/types/ad_report_retrieve_params.py
@@ -6,6 +6,7 @@
from datetime import datetime
from typing_extensions import Literal, Required, Annotated, TypedDict
+from .._types import SequenceNotStr
from .._utils import PropertyInfo
from .granularities import Granularities
@@ -19,22 +20,22 @@ class AdReportRetrieveParams(TypedDict, total=False):
to: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]]
"""Inclusive end of the reporting window."""
- ad_campaign_id: Optional[str]
- """The unique identifier of an ad campaign.
+ ad_campaign_ids: Optional[SequenceNotStr[str]]
+ """Scope the report to these ad campaigns (max 100); stats are summed across them.
- Mutually exclusive with `companyId`, `adGroupId`, and `adId`.
+ Mutually exclusive with `companyId`, `adGroupIds`, and `adIds`.
"""
- ad_group_id: Optional[str]
- """The unique identifier of an ad group.
+ ad_group_ids: Optional[SequenceNotStr[str]]
+ """Scope the report to these ad groups (max 100); stats are summed across them.
- Mutually exclusive with `companyId`, `adCampaignId`, and `adId`.
+ Mutually exclusive with `companyId`, `adCampaignIds`, and `adIds`.
"""
- ad_id: Optional[str]
- """The unique identifier of an ad.
+ ad_ids: Optional[SequenceNotStr[str]]
+ """Scope the report to these ads (max 100); stats are summed across them.
- Mutually exclusive with `companyId`, `adCampaignId`, and `adGroupId`.
+ Mutually exclusive with `companyId`, `adCampaignIds`, and `adGroupIds`.
"""
breakdown: Optional[Literal["campaign", "ad_group", "ad"]]
@@ -43,7 +44,7 @@ class AdReportRetrieveParams(TypedDict, total=False):
company_id: Optional[str]
"""The unique identifier of a company.
- Mutually exclusive with `adCampaignId`, `adGroupId`, and `adId`. Use with
+ Mutually exclusive with `adCampaignIds`, `adGroupIds`, and `adIds`. Use with
`breakdown` to fan out across every campaign, ad group, or ad in the company
without paging.
"""
diff --git a/src/whop_sdk/types/ad_report_retrieve_response.py b/src/whop_sdk/types/ad_report_retrieve_response.py
index 56bf2ef4..7157cbef 100644
--- a/src/whop_sdk/types/ad_report_retrieve_response.py
+++ b/src/whop_sdk/types/ad_report_retrieve_response.py
@@ -36,7 +36,7 @@ class BreakdownGranularity(BaseModel):
"""Clicks in this bucket."""
granularity: Granularities
- """The bucket size of this row (`daily` or `hourly`)."""
+ """The bucket size of this row (`hourly`, `daily`, `weekly`, or `monthly`)."""
impressions: int
"""Impressions in this bucket."""
@@ -81,20 +81,20 @@ class BreakdownGranularity(BaseModel):
class BreakdownSummary(BaseModel):
"""Aggregate totals and rates for this entity over the date range."""
+ click_through_rate: float
+ """Click-through rate (clicks / impressions)."""
+
clicks: int
"""Total clicks over the date range."""
- cost_per_result: Optional[float] = None
- """Spend divided by `resultCount`. Null when there are no results."""
-
- cpc: float
+ cost_per_click: float
"""Cost per click in the requested reporting currency."""
- cpm: Optional[float] = None
+ cost_per_mille: Optional[float] = None
"""Cost per thousand impressions in the requested reporting currency."""
- ctr: float
- """Click-through rate (clicks / impressions)."""
+ cost_per_result: Optional[float] = None
+ """Spend divided by `resultCount`. Null when there are no results."""
frequency: Optional[float] = None
"""Average number of times each reached user saw an ad."""
@@ -117,10 +117,10 @@ class BreakdownSummary(BaseModel):
result_label_override: Optional[str] = None
"""Advertiser-defined label for the result when `resultLabelKey` is `custom`."""
- roas: Optional[float] = None
+ return_on_ad_spend: Optional[float] = None
"""
- Alias for `purchaseRoas` — return on ad spend for purchases, as reported by the
- external ad platform.
+ Alias for `purchaseReturnOnAdSpend` — return on ad spend for purchases, as
+ reported by the external ad platform.
"""
spend: float
@@ -173,7 +173,7 @@ class Granularity(BaseModel):
"""Clicks in this bucket."""
granularity: Granularities
- """The bucket size of this row (`daily` or `hourly`)."""
+ """The bucket size of this row (`hourly`, `daily`, `weekly`, or `monthly`)."""
impressions: int
"""Impressions in this bucket."""
@@ -218,20 +218,20 @@ class Granularity(BaseModel):
class Summary(BaseModel):
"""Aggregate totals and rates over the date range."""
+ click_through_rate: float
+ """Click-through rate (clicks / impressions)."""
+
clicks: int
"""Total clicks over the date range."""
- cost_per_result: Optional[float] = None
- """Spend divided by `resultCount`. Null when there are no results."""
-
- cpc: float
+ cost_per_click: float
"""Cost per click in the requested reporting currency."""
- cpm: Optional[float] = None
+ cost_per_mille: Optional[float] = None
"""Cost per thousand impressions in the requested reporting currency."""
- ctr: float
- """Click-through rate (clicks / impressions)."""
+ cost_per_result: Optional[float] = None
+ """Spend divided by `resultCount`. Null when there are no results."""
frequency: Optional[float] = None
"""Average number of times each reached user saw an ad."""
@@ -254,10 +254,10 @@ class Summary(BaseModel):
result_label_override: Optional[str] = None
"""Advertiser-defined label for the result when `resultLabelKey` is `custom`."""
- roas: Optional[float] = None
+ return_on_ad_spend: Optional[float] = None
"""
- Alias for `purchaseRoas` — return on ad spend for purchases, as reported by the
- external ad platform.
+ Alias for `purchaseReturnOnAdSpend` — return on ad spend for purchases, as
+ reported by the external ad platform.
"""
spend: float
diff --git a/src/whop_sdk/types/ad_retrieve_params.py b/src/whop_sdk/types/ad_retrieve_params.py
new file mode 100644
index 00000000..51c89edc
--- /dev/null
+++ b/src/whop_sdk/types/ad_retrieve_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 TypedDict
+
+__all__ = ["AdRetrieveParams"]
+
+
+class AdRetrieveParams(TypedDict, total=False):
+ stats_from: str
+ """Start of the stats window."""
+
+ stats_to: str
+ """End of the stats window."""
diff --git a/src/whop_sdk/types/ad_update_params.py b/src/whop_sdk/types/ad_update_params.py
new file mode 100644
index 00000000..653bf6dd
--- /dev/null
+++ b/src/whop_sdk/types/ad_update_params.py
@@ -0,0 +1,266 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Iterable
+from typing_extensions import Literal, TypedDict
+
+from .._types import SequenceNotStr
+
+__all__ = [
+ "AdUpdateParams",
+ "Creative",
+ "LeadForm",
+ "LeadFormCompletion",
+ "LeadFormDisclaimer",
+ "LeadFormDisclaimerCheckbox",
+ "LeadFormIntro",
+ "LeadFormPrivacyPolicy",
+ "LeadFormQuestion",
+ "LeadFormQuestionOption",
+ "LeadFormQuestionOptionLogic",
+ "MessagingConfig",
+ "SocialAccount",
+]
+
+
+class AdUpdateParams(TypedDict, total=False):
+ call_to_action: Literal[
+ "apply_now",
+ "book_now",
+ "call_now",
+ "contact_us",
+ "download",
+ "get_directions",
+ "get_offer",
+ "get_quote",
+ "learn_more",
+ "listen_now",
+ "message_page",
+ "no_button",
+ "open_link",
+ "order_now",
+ "request_time",
+ "see_details",
+ "see_menu",
+ "send_updates",
+ "shop_now",
+ "sign_up",
+ "subscribe",
+ "watch_more",
+ ]
+ """The call-to-action button shown on the ad."""
+
+ creatives: Iterable[Creative]
+ """The ad's creatives.
+
+ Each entry is an uploaded file id with an optional format; omit format for the
+ original/uncropped asset. Replaces a live ad's creative on the platform.
+ """
+
+ descriptions: SequenceNotStr[str]
+ """The description variants shown on the ad."""
+
+ headlines: SequenceNotStr[str]
+ """The headline variants shown on the ad."""
+
+ lead_form: LeadForm
+ """Instant lead form for the ad.
+
+ Only allowed when the ad group's conversion_location is an instant-form
+ destination (instant_forms, instant_forms_and_messenger,
+ website_and_instant_forms).
+ """
+
+ messaging_config: MessagingConfig
+ """
+ Click-to-message welcome copy: the greeting (message) and the ice-breaker prompt
+ (keyword).
+ """
+
+ multi_advertiser_ads: bool
+ """Whether the ad can appear alongside other advertisers' ads in the same unit.
+
+ Defaults to true.
+ """
+
+ post_id: str
+ """
+ Promote an existing post instead of uploading creatives — a Facebook post or
+ Instagram media id. Mutually exclusive with creatives.
+ """
+
+ primary_texts: SequenceNotStr[str]
+ """The primary text variants shown in the ad body."""
+
+ social_accounts: Iterable[SocialAccount]
+ """The social accounts the ad runs under."""
+
+ title: str
+ """The display name of the ad."""
+
+ url: str
+ """The URL the ad links to."""
+
+ url_parameters: object
+ """Query parameters appended to the destination URL, as a string-to-string map."""
+
+
+class Creative(TypedDict, total=False):
+ id: str
+
+ format: Literal["square", "vertical", "horizontal"]
+
+
+class LeadFormCompletion(TypedDict, total=False):
+ """
+ Optional completion screen shown after submission; url sets the follow-up website button.
+ """
+
+ button_text: str
+
+ description: str
+
+ headline: str
+
+ url: str
+
+
+class LeadFormDisclaimerCheckbox(TypedDict, total=False):
+ checked_by_default: bool
+
+ key: str
+
+ required: bool
+
+ text: str
+
+
+class LeadFormDisclaimer(TypedDict, total=False):
+ """Optional custom consent disclaimer with checkboxes."""
+
+ body: str
+
+ checkboxes: Iterable[LeadFormDisclaimerCheckbox]
+
+ title: str
+
+
+class LeadFormIntro(TypedDict, total=False):
+ """Optional intro screen shown before the questions."""
+
+ description: str
+
+ headline: str
+
+
+class LeadFormPrivacyPolicy(TypedDict, total=False):
+ """Your privacy policy. url is required by Meta."""
+
+ link_text: str
+
+ url: str
+
+
+class LeadFormQuestionOptionLogic(TypedDict, total=False):
+ action: Literal["go_to_question", "submit_form", "close_form"]
+
+ target_end_page_index: int
+
+ target_question_index: int
+
+
+class LeadFormQuestionOption(TypedDict, total=False):
+ key: str
+
+ logic: LeadFormQuestionOptionLogic
+
+ value: str
+
+
+class LeadFormQuestion(TypedDict, total=False):
+ format: Literal["short_answer", "multiple_choice", "appointment"]
+
+ label: str
+
+ options: Iterable[LeadFormQuestionOption]
+
+ type: Literal[
+ "email",
+ "phone",
+ "full_name",
+ "first_name",
+ "last_name",
+ "city",
+ "state",
+ "zip",
+ "country",
+ "street_address",
+ "job_title",
+ "company_name",
+ "work_email",
+ "work_phone_number",
+ "dob",
+ "gender",
+ "marital_status",
+ "relationship_status",
+ "military_status",
+ "date_time",
+ "custom",
+ ]
+
+
+class LeadForm(TypedDict, total=False):
+ """Instant lead form for the ad.
+
+ Only allowed when the ad group's conversion_location is an instant-form destination (instant_forms, instant_forms_and_messenger, website_and_instant_forms).
+ """
+
+ completion: LeadFormCompletion
+ """
+ Optional completion screen shown after submission; url sets the follow-up
+ website button.
+ """
+
+ disclaimer: LeadFormDisclaimer
+ """Optional custom consent disclaimer with checkboxes."""
+
+ form_type: Literal["more_volume", "higher_intent"]
+ """
+ more_volume (default) is quickest to submit; higher_intent adds a confirmation
+ step.
+ """
+
+ intro: LeadFormIntro
+ """Optional intro screen shown before the questions."""
+
+ name: str
+ """Internal name for the form. Auto-generated if omitted."""
+
+ phone_verification: bool
+ """Require SMS verification of the phone number (higher_intent forms)."""
+
+ privacy_policy: LeadFormPrivacyPolicy
+ """Your privacy policy. url is required by Meta."""
+
+ questions: Iterable[LeadFormQuestion]
+ """The questions on the form.
+
+ Standard prefill types need only a type; a custom question needs a label and a
+ format (plus options for multiple_choice). Options carry an optional key and
+ answer-routing logic.
+ """
+
+
+class MessagingConfig(TypedDict, total=False):
+ """
+ Click-to-message welcome copy: the greeting (message) and the ice-breaker prompt (keyword).
+ """
+
+ keyword: str
+
+ message: str
+
+
+class SocialAccount(TypedDict, total=False):
+ id: str
diff --git a/src/whop_sdk/types/audience.py b/src/whop_sdk/types/audience.py
new file mode 100644
index 00000000..7adf00d5
--- /dev/null
+++ b/src/whop_sdk/types/audience.py
@@ -0,0 +1,46 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["Audience"]
+
+
+class Audience(BaseModel):
+ id: str
+ """Audience ID, prefixed `adaud_`."""
+
+ created_at: float
+ """Unix timestamp when the audience was created."""
+
+ error_message: Optional[str] = None
+ """Processing error message. `null` unless processing is partial or failed."""
+
+ matched_rows: float
+ """Rows successfully uploaded to connected ad accounts."""
+
+ name: str
+ """Audience display name."""
+
+ platform_audience_ids: List[str]
+
+ processed_rows: float
+ """Rows processed from the uploaded CSV."""
+
+ progress_percent: float
+ """Processing progress from 0 to 100."""
+
+ status: Literal["pending", "processing", "syncing", "ready", "partial", "failed"]
+ """Current state of the audience import.
+
+ `syncing` means Whop is sending matched rows to connected ad accounts. When
+ status is `partial` or `failed`, `error_message` explains what went wrong.
+ """
+
+ total_rows: float
+ """Total rows detected in the uploaded CSV."""
+
+ updated_at: float
+ """Unix timestamp when the audience was last updated."""
diff --git a/src/whop_sdk/types/audience_create_params.py b/src/whop_sdk/types/audience_create_params.py
new file mode 100644
index 00000000..b33e1550
--- /dev/null
+++ b/src/whop_sdk/types/audience_create_params.py
@@ -0,0 +1,46 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["AudienceCreateParams", "ColumnMapping"]
+
+
+class AudienceCreateParams(TypedDict, total=False):
+ account_id: Required[str]
+ """Account ID, prefixed `biz_`."""
+
+ column_mapping: Required[ColumnMapping]
+ """Maps supported identity fields to CSV column headers.
+
+ Map at least one of `email` or `phone`.
+ """
+
+ file_id: Required[str]
+ """Direct upload ID from the standard media upload endpoint."""
+
+ name: Required[str]
+ """Audience display name."""
+
+
+class ColumnMapping(TypedDict, total=False):
+ """Maps supported identity fields to CSV column headers.
+
+ Map at least one of `email` or `phone`.
+ """
+
+ country: str
+ """CSV header for ISO 3166-1 alpha-2 country codes, such as `US`."""
+
+ email: str
+ """CSV header for email addresses."""
+
+ first_name: str
+ """CSV header for first names."""
+
+ last_name: str
+ """CSV header for last names."""
+
+ phone: str
+ """CSV header for phone numbers."""
diff --git a/src/whop_sdk/types/audience_delete_response.py b/src/whop_sdk/types/audience_delete_response.py
new file mode 100644
index 00000000..6d8b5978
--- /dev/null
+++ b/src/whop_sdk/types/audience_delete_response.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .._models import BaseModel
+
+__all__ = ["AudienceDeleteResponse"]
+
+
+class AudienceDeleteResponse(BaseModel):
+ success: bool
diff --git a/src/whop_sdk/types/audience_list_params.py b/src/whop_sdk/types/audience_list_params.py
new file mode 100644
index 00000000..898c5406
--- /dev/null
+++ b/src/whop_sdk/types/audience_list_params.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["AudienceListParams"]
+
+
+class AudienceListParams(TypedDict, total=False):
+ account_id: Required[str]
+ """Account ID, prefixed `biz_`."""
+
+ after: str
+ """Cursor for the next page of audiences."""
+
+ audience_id: str
+ """Audience ID, prefixed `adaud_`, used to filter the response to one audience."""
+
+ first: int
+ """Number of audiences to return. Defaults to 20; maximum 100."""
diff --git a/src/whop_sdk/types/authorized_user_create_params.py b/src/whop_sdk/types/authorized_user_create_params.py
index b2b538a5..853bb219 100644
--- a/src/whop_sdk/types/authorized_user_create_params.py
+++ b/src/whop_sdk/types/authorized_user_create_params.py
@@ -7,7 +7,7 @@
from .shared.authorized_user_roles import AuthorizedUserRoles
-__all__ = ["AuthorizedUserCreateParams"]
+__all__ = ["AuthorizedUserCreateParams", "Elevation"]
class AuthorizedUserCreateParams(TypedDict, total=False):
@@ -23,5 +23,33 @@ class AuthorizedUserCreateParams(TypedDict, total=False):
user_id: Required[str]
"""The ID of the user to add as an authorized user."""
+ elevation: Optional[Elevation]
+ """Re-authentication proof required to perform this sensitive action."""
+
send_emails: Optional[bool]
"""Whether to send notification emails to the user on creation."""
+
+
+class Elevation(TypedDict, total=False):
+ """Re-authentication proof required to perform this sensitive action."""
+
+ authenticator_data: Optional[str]
+ """The WebAuthn authenticator data (base64)."""
+
+ client_data_json: Optional[str]
+ """The WebAuthn client data JSON (base64)."""
+
+ credential_id: Optional[str]
+ """The WebAuthn credential ID (base64)."""
+
+ email_code: Optional[str]
+ """The 6-digit code emailed to the user."""
+
+ signature: Optional[str]
+ """The WebAuthn signature (base64)."""
+
+ totp_code: Optional[str]
+ """The 6-digit code from the authenticator app or SMS."""
+
+ use_finance_session: Optional[bool]
+ """Reuse an existing elevated session (for SMS/email 2FA users)."""
diff --git a/src/whop_sdk/types/bounty_create_params.py b/src/whop_sdk/types/bounty_create_params.py
index de0e0fdb..edc77eb9 100644
--- a/src/whop_sdk/types/bounty_create_params.py
+++ b/src/whop_sdk/types/bounty_create_params.py
@@ -2,10 +2,12 @@
from __future__ import annotations
-from typing import Optional
-from typing_extensions import Required, TypedDict
+from typing import Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, Required, Annotated, TypedDict
from .._types import SequenceNotStr
+from .._utils import PropertyInfo
from .shared.currency import Currency
__all__ = ["BountyCreateParams"]
@@ -15,7 +17,8 @@ class BountyCreateParams(TypedDict, total=False):
base_unit_amount: Required[float]
"""The amount paid to each approved submission.
- The total bounty pool funded is this amount times accepted_submissions_limit.
+ The total bounty pool funded is this amount times accepted_submissions_limit,
+ and must be at least 5 in the bounty's currency.
"""
currency: Required[Currency]
@@ -30,7 +33,8 @@ class BountyCreateParams(TypedDict, total=False):
accepted_submissions_limit: Optional[int]
"""The number of submissions that can be approved before the bounty closes.
- Defaults to 1.
+ Defaults to 1. The total pool (base_unit_amount times this limit) must be at
+ least 5 in the bounty's currency.
"""
allowed_country_codes: Optional[SequenceNotStr[str]]
@@ -39,6 +43,15 @@ class BountyCreateParams(TypedDict, total=False):
Empty means globally visible.
"""
+ business_goal_type: Optional[
+ Literal["clipping", "post_engagement", "owned_account_growth", "ugc_content", "local_activation", "other"]
+ ]
+ """What the poster is trying to accomplish with a workforce bounty.
+
+ Used for product taxonomy and analytics, separate from the bounty's
+ implementation type.
+ """
+
experience_id: Optional[str]
"""An optional experience to scope the bounty to."""
@@ -60,3 +73,19 @@ class BountyCreateParams(TypedDict, total=False):
Falls back to the bounty title when omitted.
"""
+
+ scheduled_frequency: Optional[Literal["once", "hourly", "daily", "weekly", "monthly"]]
+ """How often a scheduled bounty republishes a new bounty."""
+
+ scheduled_publish_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
+ """When to publish the bounty.
+
+ When provided, the bounty is created as a hidden draft and published at this
+ time instead of immediately. Must be in the future.
+ """
+
+ scheduled_timezone: Optional[str]
+ """The IANA timezone used for recurring occurrences.
+
+ Required when scheduled_publish_at is provided.
+ """
diff --git a/src/whop_sdk/types/bounty_create_response.py b/src/whop_sdk/types/bounty_create_response.py
index 94c4f5e4..45e80b8a 100644
--- a/src/whop_sdk/types/bounty_create_response.py
+++ b/src/whop_sdk/types/bounty_create_response.py
@@ -27,7 +27,7 @@ class BountyCreateResponse(BaseModel):
description: str
"""The description of the bounty."""
- status: Literal["published", "archived"]
+ status: Literal["published", "archived", "scheduled"]
"""The current lifecycle status of the bounty."""
title: str
diff --git a/src/whop_sdk/types/bounty_list_params.py b/src/whop_sdk/types/bounty_list_params.py
index cb80eaba..08aa2311 100644
--- a/src/whop_sdk/types/bounty_list_params.py
+++ b/src/whop_sdk/types/bounty_list_params.py
@@ -32,5 +32,5 @@ class BountyListParams(TypedDict, total=False):
last: Optional[int]
"""Returns the last _n_ elements from the list."""
- status: Optional[Literal["published", "archived"]]
+ status: Optional[Literal["published", "archived", "scheduled"]]
"""The available bounty statuses to choose from."""
diff --git a/src/whop_sdk/types/bounty_list_response.py b/src/whop_sdk/types/bounty_list_response.py
index 0117a1ba..fcb7c54a 100644
--- a/src/whop_sdk/types/bounty_list_response.py
+++ b/src/whop_sdk/types/bounty_list_response.py
@@ -27,7 +27,7 @@ class BountyListResponse(BaseModel):
description: str
"""The description of the bounty."""
- status: Literal["published", "archived"]
+ status: Literal["published", "archived", "scheduled"]
"""The current lifecycle status of the bounty."""
title: str
diff --git a/src/whop_sdk/types/bounty_retrieve_response.py b/src/whop_sdk/types/bounty_retrieve_response.py
index d9df060a..56ffc09d 100644
--- a/src/whop_sdk/types/bounty_retrieve_response.py
+++ b/src/whop_sdk/types/bounty_retrieve_response.py
@@ -27,7 +27,7 @@ class BountyRetrieveResponse(BaseModel):
description: str
"""The description of the bounty."""
- status: Literal["published", "archived"]
+ status: Literal["published", "archived", "scheduled"]
"""The current lifecycle status of the bounty."""
title: str
diff --git a/src/whop_sdk/types/card_brands.py b/src/whop_sdk/types/card_brands.py
index bd4345a7..322a3221 100644
--- a/src/whop_sdk/types/card_brands.py
+++ b/src/whop_sdk/types/card_brands.py
@@ -44,5 +44,6 @@
"hipercard",
"jcblankapay",
"cmi",
+ "aura",
"unknown",
]
diff --git a/src/whop_sdk/types/card_create_params.py b/src/whop_sdk/types/card_create_params.py
new file mode 100644
index 00000000..082ca095
--- /dev/null
+++ b/src/whop_sdk/types/card_create_params.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypedDict
+
+__all__ = ["CardCreateParams"]
+
+
+class CardCreateParams(TypedDict, total=False):
+ account_id: str
+ """The owning account ID (a biz\\__ identifier). Provide this or user_id."""
+
+ assigned_user_id: str
+ """The company member (a user\\__ identifier) to assign the card to.
+
+ Required for company (business) card issuing accounts.
+ """
+
+ name: str
+ """A display name for the card."""
+
+ spend_limit: float
+ """Spending limit amount, in dollars."""
+
+ spend_limit_frequency: Literal["daily", "weekly", "monthly", "one_time"]
+ """The spending limit window."""
+
+ transaction_limit: float
+ """Per-transaction limit amount, in dollars."""
+
+ user_id: str
+ """The owning user ID (a user\\__ identifier). Provide this or account_id."""
diff --git a/src/whop_sdk/types/card_create_response.py b/src/whop_sdk/types/card_create_response.py
new file mode 100644
index 00000000..9f4db74c
--- /dev/null
+++ b/src/whop_sdk/types/card_create_response.py
@@ -0,0 +1,107 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["CardCreateResponse", "Billing", "Limit", "Secrets"]
+
+
+class Billing(BaseModel):
+ """The billing address."""
+
+ city: Optional[str] = None
+ """Billing city."""
+
+ country_code: Optional[str] = None
+ """Billing country code."""
+
+ line1: Optional[str] = None
+ """Street address line 1."""
+
+ line2: Optional[str] = None
+ """Street address line 2."""
+
+ postal_code: Optional[str] = None
+ """Billing postal code."""
+
+ region: Optional[str] = None
+ """Billing region or state."""
+
+
+class Limit(BaseModel):
+ """The spending limit configuration."""
+
+ amount: float
+ """The limit amount in dollars."""
+
+ frequency: str
+ """Limit window, for example `per24HourPeriod` or `perAuthorization`."""
+
+
+class Secrets(BaseModel):
+ """Sensitive card details.
+
+ Present only on `GET /cards/:card_id` for active cards; `null` when the card is inactive or details cannot be retrieved.
+ """
+
+ card_number: str
+ """Full card number."""
+
+ cvc: str
+ """Card verification code."""
+
+ name_on_card: Optional[str] = None
+ """Cardholder name printed on the card."""
+
+
+class CardCreateResponse(BaseModel):
+ id: str
+ """Card ID, prefixed `icrd_`."""
+
+ billing: Optional[Billing] = None
+ """The billing address."""
+
+ canceled_at: Optional[datetime] = None
+ """When the card was canceled."""
+
+ created_at: Optional[datetime] = None
+ """When the card was created."""
+
+ expiration_month: Optional[str] = None
+ """Card expiration month."""
+
+ expiration_year: Optional[str] = None
+ """Card expiration year."""
+
+ last4: Optional[str] = None
+ """Last four digits of the card number. `null` for pending invitation cards."""
+
+ limit: Optional[Limit] = None
+ """The spending limit configuration."""
+
+ name: Optional[str] = None
+ """Card display name."""
+
+ object: Literal["card"]
+
+ spent_last_month: Optional[int] = None
+ """Total spend in the last 30 days, in cents."""
+
+ status: Optional[Literal["active", "frozen", "canceled", "invited"]] = None
+ """The card status."""
+
+ type: Optional[Literal["virtual", "physical"]] = None
+ """The card type."""
+
+ user_id: Optional[str] = None
+ """Cardholder user ID, prefixed `user_`, when assigned."""
+
+ secrets: Optional[Secrets] = None
+ """Sensitive card details.
+
+ Present only on `GET /cards/:card_id` for active cards; `null` when the card is
+ inactive or details cannot be retrieved.
+ """
diff --git a/src/whop_sdk/types/card_list_params.py b/src/whop_sdk/types/card_list_params.py
new file mode 100644
index 00000000..2487fd2e
--- /dev/null
+++ b/src/whop_sdk/types/card_list_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 TypedDict
+
+__all__ = ["CardListParams"]
+
+
+class CardListParams(TypedDict, total=False):
+ account_id: str
+ """The owning account ID (a biz\\__ identifier). Provide this or user_id."""
+
+ user_id: str
+ """The owning user ID (a user\\__ identifier). Provide this or account_id."""
diff --git a/src/whop_sdk/types/card_list_response.py b/src/whop_sdk/types/card_list_response.py
new file mode 100644
index 00000000..69ed575f
--- /dev/null
+++ b/src/whop_sdk/types/card_list_response.py
@@ -0,0 +1,111 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["CardListResponse", "Data", "DataBilling", "DataLimit", "DataSecrets"]
+
+
+class DataBilling(BaseModel):
+ """The billing address."""
+
+ city: Optional[str] = None
+ """Billing city."""
+
+ country_code: Optional[str] = None
+ """Billing country code."""
+
+ line1: Optional[str] = None
+ """Street address line 1."""
+
+ line2: Optional[str] = None
+ """Street address line 2."""
+
+ postal_code: Optional[str] = None
+ """Billing postal code."""
+
+ region: Optional[str] = None
+ """Billing region or state."""
+
+
+class DataLimit(BaseModel):
+ """The spending limit configuration."""
+
+ amount: float
+ """The limit amount in dollars."""
+
+ frequency: str
+ """Limit window, for example `per24HourPeriod` or `perAuthorization`."""
+
+
+class DataSecrets(BaseModel):
+ """Sensitive card details.
+
+ Present only on `GET /cards/:card_id` for active cards; `null` when the card is inactive or details cannot be retrieved.
+ """
+
+ card_number: str
+ """Full card number."""
+
+ cvc: str
+ """Card verification code."""
+
+ name_on_card: Optional[str] = None
+ """Cardholder name printed on the card."""
+
+
+class Data(BaseModel):
+ id: str
+ """Card ID, prefixed `icrd_`."""
+
+ billing: Optional[DataBilling] = None
+ """The billing address."""
+
+ canceled_at: Optional[datetime] = None
+ """When the card was canceled."""
+
+ created_at: Optional[datetime] = None
+ """When the card was created."""
+
+ expiration_month: Optional[str] = None
+ """Card expiration month."""
+
+ expiration_year: Optional[str] = None
+ """Card expiration year."""
+
+ last4: Optional[str] = None
+ """Last four digits of the card number. `null` for pending invitation cards."""
+
+ limit: Optional[DataLimit] = None
+ """The spending limit configuration."""
+
+ name: Optional[str] = None
+ """Card display name."""
+
+ object: Literal["card"]
+
+ spent_last_month: Optional[int] = None
+ """Total spend in the last 30 days, in cents."""
+
+ status: Optional[Literal["active", "frozen", "canceled", "invited"]] = None
+ """The card status."""
+
+ type: Optional[Literal["virtual", "physical"]] = None
+ """The card type."""
+
+ user_id: Optional[str] = None
+ """Cardholder user ID, prefixed `user_`, when assigned."""
+
+ secrets: Optional[DataSecrets] = None
+ """Sensitive card details.
+
+ Present only on `GET /cards/:card_id` for active cards; `null` when the card is
+ inactive or details cannot be retrieved.
+ """
+
+
+class CardListResponse(BaseModel):
+ data: List[Data]
diff --git a/src/whop_sdk/types/card_retrieve_params.py b/src/whop_sdk/types/card_retrieve_params.py
new file mode 100644
index 00000000..b325260c
--- /dev/null
+++ b/src/whop_sdk/types/card_retrieve_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 TypedDict
+
+__all__ = ["CardRetrieveParams"]
+
+
+class CardRetrieveParams(TypedDict, total=False):
+ account_id: str
+ """The owning account ID (a biz\\__ identifier). Provide this or user_id."""
+
+ user_id: str
+ """The owning user ID (a user\\__ identifier). Provide this or account_id."""
diff --git a/src/whop_sdk/types/card_retrieve_response.py b/src/whop_sdk/types/card_retrieve_response.py
new file mode 100644
index 00000000..9e1cb9e0
--- /dev/null
+++ b/src/whop_sdk/types/card_retrieve_response.py
@@ -0,0 +1,107 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["CardRetrieveResponse", "Billing", "Limit", "Secrets"]
+
+
+class Billing(BaseModel):
+ """The billing address."""
+
+ city: Optional[str] = None
+ """Billing city."""
+
+ country_code: Optional[str] = None
+ """Billing country code."""
+
+ line1: Optional[str] = None
+ """Street address line 1."""
+
+ line2: Optional[str] = None
+ """Street address line 2."""
+
+ postal_code: Optional[str] = None
+ """Billing postal code."""
+
+ region: Optional[str] = None
+ """Billing region or state."""
+
+
+class Limit(BaseModel):
+ """The spending limit configuration."""
+
+ amount: float
+ """The limit amount in dollars."""
+
+ frequency: str
+ """Limit window, for example `per24HourPeriod` or `perAuthorization`."""
+
+
+class Secrets(BaseModel):
+ """Sensitive card details.
+
+ Present only on `GET /cards/:card_id` for active cards; `null` when the card is inactive or details cannot be retrieved.
+ """
+
+ card_number: str
+ """Full card number."""
+
+ cvc: str
+ """Card verification code."""
+
+ name_on_card: Optional[str] = None
+ """Cardholder name printed on the card."""
+
+
+class CardRetrieveResponse(BaseModel):
+ id: str
+ """Card ID, prefixed `icrd_`."""
+
+ billing: Optional[Billing] = None
+ """The billing address."""
+
+ canceled_at: Optional[datetime] = None
+ """When the card was canceled."""
+
+ created_at: Optional[datetime] = None
+ """When the card was created."""
+
+ expiration_month: Optional[str] = None
+ """Card expiration month."""
+
+ expiration_year: Optional[str] = None
+ """Card expiration year."""
+
+ last4: Optional[str] = None
+ """Last four digits of the card number. `null` for pending invitation cards."""
+
+ limit: Optional[Limit] = None
+ """The spending limit configuration."""
+
+ name: Optional[str] = None
+ """Card display name."""
+
+ object: Literal["card"]
+
+ spent_last_month: Optional[int] = None
+ """Total spend in the last 30 days, in cents."""
+
+ status: Optional[Literal["active", "frozen", "canceled", "invited"]] = None
+ """The card status."""
+
+ type: Optional[Literal["virtual", "physical"]] = None
+ """The card type."""
+
+ user_id: Optional[str] = None
+ """Cardholder user ID, prefixed `user_`, when assigned."""
+
+ secrets: Optional[Secrets] = None
+ """Sensitive card details.
+
+ Present only on `GET /cards/:card_id` for active cards; `null` when the card is
+ inactive or details cannot be retrieved.
+ """
diff --git a/src/whop_sdk/types/chat_message_created_webhook_event.py b/src/whop_sdk/types/chat_message_created_webhook_event.py
new file mode 100644
index 00000000..6f5c6493
--- /dev/null
+++ b/src/whop_sdk/types/chat_message_created_webhook_event.py
@@ -0,0 +1,54 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+from .shared.message import Message
+
+__all__ = ["ChatMessageCreatedWebhookEvent", "Data", "DataAudience", "DataChannel"]
+
+
+class DataAudience(BaseModel):
+ type: Literal["channel", "users"]
+
+ user_ids: Optional[List[str]] = None
+
+
+class DataChannel(BaseModel):
+ id: str
+
+ type: Literal["chat", "direct_message", "support"]
+
+ experience_id: Optional[str] = None
+
+
+class Data(BaseModel):
+ audience: DataAudience
+
+ channel: DataChannel
+
+ message: Message
+ """A message sent within an experience chat, direct message, or group chat."""
+
+ reason: str
+
+
+class ChatMessageCreatedWebhookEvent(BaseModel):
+ id: str
+ """A unique ID for every single webhook request"""
+
+ api_version: Literal["v1"]
+ """The API version for this webhook"""
+
+ data: Data
+
+ timestamp: datetime
+ """The timestamp in ISO 8601 format that the webhook was sent at on the server"""
+
+ type: Literal["chat.message.created"]
+ """The webhook event type"""
+
+ company_id: Optional[str] = None
+ """The company ID that this webhook event is associated with"""
diff --git a/src/whop_sdk/types/chat_reaction_created_webhook_event.py b/src/whop_sdk/types/chat_reaction_created_webhook_event.py
new file mode 100644
index 00000000..fe79585c
--- /dev/null
+++ b/src/whop_sdk/types/chat_reaction_created_webhook_event.py
@@ -0,0 +1,58 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+from .shared.message import Message
+from .shared.reaction import Reaction
+
+__all__ = ["ChatReactionCreatedWebhookEvent", "Data", "DataAudience", "DataChannel"]
+
+
+class DataAudience(BaseModel):
+ type: Literal["channel", "users"]
+
+ user_ids: Optional[List[str]] = None
+
+
+class DataChannel(BaseModel):
+ id: str
+
+ type: Literal["chat", "direct_message", "support"]
+
+ experience_id: Optional[str] = None
+
+
+class Data(BaseModel):
+ audience: DataAudience
+
+ channel: DataChannel
+
+ message: Message
+ """A message sent within an experience chat, direct message, or group chat."""
+
+ reaction: Reaction
+ """A single reaction left by a user on a feed post, such as a like or emoji."""
+
+ reason: str
+
+
+class ChatReactionCreatedWebhookEvent(BaseModel):
+ id: str
+ """A unique ID for every single webhook request"""
+
+ api_version: Literal["v1"]
+ """The API version for this webhook"""
+
+ data: Data
+
+ timestamp: datetime
+ """The timestamp in ISO 8601 format that the webhook was sent at on the server"""
+
+ type: Literal["chat.reaction.created"]
+ """The webhook event type"""
+
+ company_id: Optional[str] = None
+ """The company ID that this webhook event is associated with"""
diff --git a/src/whop_sdk/types/checkout_configuration_create_params.py b/src/whop_sdk/types/checkout_configuration_create_params.py
index de81ec08..42954cbc 100644
--- a/src/whop_sdk/types/checkout_configuration_create_params.py
+++ b/src/whop_sdk/types/checkout_configuration_create_params.py
@@ -2,539 +2,128 @@
from __future__ import annotations
-from typing import Dict, List, Union, Iterable, Optional
-from typing_extensions import Literal, Required, TypeAlias, TypedDict
-
-from .checkout_font import CheckoutFont
-from .checkout_shape import CheckoutShape
-from .shared.currency import Currency
-from .shared.tax_type import TaxType
-from .shared.plan_type import PlanType
-from .shared.visibility import Visibility
-from .payment_method_types import PaymentMethodTypes
-from .shared.release_method import ReleaseMethod
-from .shared.global_affiliate_status import GlobalAffiliateStatus
-
-__all__ = [
- "CheckoutConfigurationCreateParams",
- "CreateCheckoutSessionInputModePaymentWithPlan",
- "CreateCheckoutSessionInputModePaymentWithPlanPlan",
- "CreateCheckoutSessionInputModePaymentWithPlanPlanCustomField",
- "CreateCheckoutSessionInputModePaymentWithPlanPlanImage",
- "CreateCheckoutSessionInputModePaymentWithPlanPlanPaymentMethodConfiguration",
- "CreateCheckoutSessionInputModePaymentWithPlanPlanProduct",
- "CreateCheckoutSessionInputModePaymentWithPlanCheckoutStyling",
- "CreateCheckoutSessionInputModePaymentWithPlanPaymentMethodConfiguration",
- "CreateCheckoutSessionInputModePaymentWithPlanID",
- "CreateCheckoutSessionInputModePaymentWithPlanIDCheckoutStyling",
- "CreateCheckoutSessionInputModePaymentWithPlanIDPaymentMethodConfiguration",
- "CreateCheckoutSessionInputModeSetup",
- "CreateCheckoutSessionInputModeSetupCheckoutStyling",
- "CreateCheckoutSessionInputModeSetupPaymentMethodConfiguration",
-]
-
-
-class CreateCheckoutSessionInputModePaymentWithPlan(TypedDict, total=False):
- plan: Required[CreateCheckoutSessionInputModePaymentWithPlanPlan]
- """
- The plan attributes to create a new plan inline for this checkout configuration.
- """
-
- affiliate_code: Optional[str]
- """An affiliate tracking code to attribute the checkout to a specific affiliate."""
-
- allow_promo_codes: Optional[bool]
- """
- Whether the checkout should show the promo code input field and accept promo
- codes. Defaults to true.
- """
-
- checkout_styling: Optional[CreateCheckoutSessionInputModePaymentWithPlanCheckoutStyling]
- """Checkout styling overrides for this session.
-
- Overrides plan and company defaults.
- """
-
- currency: Optional[Currency]
- """The available currencies on the platform"""
-
- metadata: Optional[Dict[str, object]]
- """Custom key-value metadata to attach to the checkout configuration."""
-
- mode: Literal["payment"]
-
- payment_method_configuration: Optional[CreateCheckoutSessionInputModePaymentWithPlanPaymentMethodConfiguration]
- """The explicit payment method configuration for the checkout session.
-
- Only applies to setup mode. If not provided, the platform or company defaults
- will apply.
- """
-
- redirect_url: Optional[str]
- """The URL to redirect the user to after checkout is completed."""
-
- source_url: Optional[str]
- """The URL of the page where the checkout is being initiated from."""
-
-
-class CreateCheckoutSessionInputModePaymentWithPlanPlanCustomField(TypedDict, total=False):
- field_type: Required[Literal["text"]]
- """The type of the custom field."""
-
- name: Required[str]
- """The name of the custom field."""
-
- id: Optional[str]
- """The ID of the custom field (if being updated)"""
+from typing import Optional
+from typing_extensions import Literal, TypedDict
- order: Optional[int]
- """The order of the field."""
+from .._types import SequenceNotStr
- placeholder: Optional[str]
- """The placeholder value of the field."""
+__all__ = ["CheckoutConfigurationCreateParams", "PaymentMethodConfiguration", "Plan", "PlanPaymentMethodConfiguration"]
- required: Optional[bool]
- """Whether or not the field is required."""
+class CheckoutConfigurationCreateParams(TypedDict, total=False):
+ affiliate_code: Optional[str]
+ """An affiliate code to apply."""
-class CreateCheckoutSessionInputModePaymentWithPlanPlanImage(TypedDict, total=False):
- """An image for the plan. This will be visible on the product page to customers."""
-
- id: Required[str]
- """The ID of an existing file object."""
-
-
-class CreateCheckoutSessionInputModePaymentWithPlanPlanPaymentMethodConfiguration(TypedDict, total=False):
- """The explicit payment method configuration for the plan.
-
- If not provided, the platform or company's defaults will apply.
- """
-
- disabled: Required[List[PaymentMethodTypes]]
- """An array of payment method identifiers that are explicitly disabled.
-
- Only applies if the include_platform_defaults is true.
- """
-
- enabled: Required[List[PaymentMethodTypes]]
- """An array of payment method identifiers that are explicitly enabled.
-
- This means these payment methods will be shown on checkout. Example use case is
- to only enable a specific payment method like cashapp, or extending the platform
- defaults with additional methods.
- """
-
- include_platform_defaults: Optional[bool]
- """
- Whether Whop's platform default payment method enablement settings are included
- in this configuration. The full list of default payment methods can be found in
- the documentation at docs.whop.com/payments.
- """
-
-
-class CreateCheckoutSessionInputModePaymentWithPlanPlanProduct(TypedDict, total=False):
- """Pass this object to create a new product for this plan.
-
- We will use the product external identifier to find or create an existing product.
- """
+ company_id: str
+ """The ID of the company."""
- external_identifier: Required[str]
- """A unique ID used to find or create a product.
+ currency: Optional[str]
+ """The currency code."""
- When provided during creation, we will look for an existing product with this
- external identifier — if found, it will be updated; otherwise, a new product
- will be created.
- """
+ metadata: Optional[object]
+ """Arbitrary key-value metadata."""
- title: Required[str]
- """The title of the product."""
+ mode: Literal["payment", "setup"]
+ """Checkout mode. Defaults to 'payment'."""
- collect_shipping_address: Optional[bool]
- """Whether or not to collect shipping information at checkout from the customer."""
+ payment_method_configuration: Optional[PaymentMethodConfiguration]
- custom_statement_descriptor: Optional[str]
- """The custom statement descriptor for the product i.e.
+ plan: Optional[Plan]
+ """Plan attributes to create a new plan inline for this checkout configuration.
- WHOP\\**SPORTS, must be between 5 and 22 characters, contain at least one letter,
- and not contain any of the following characters: <, >, \\,, ', "
+ Mutually exclusive with plan_id.
"""
- description: Optional[str]
- """A written description of the product."""
-
- global_affiliate_percentage: Optional[float]
- """The percentage of the revenue that goes to the global affiliate program."""
+ plan_id: Optional[str]
+ """The ID of an existing plan to attach."""
- global_affiliate_status: Optional[GlobalAffiliateStatus]
- """The different statuses of the global affiliate program for a product."""
+ redirect_url: Optional[str]
+ """URL to redirect after checkout."""
- headline: Optional[str]
- """The headline of the product."""
+ three_ds_level: Optional[str]
+ """3D Secure enforcement level."""
- product_tax_code_id: Optional[str]
- """The ID of the product tax code to apply to this product."""
- redirect_purchase_url: Optional[str]
- """The URL to redirect the customer to after a purchase."""
+class PaymentMethodConfiguration(TypedDict, total=False):
+ disabled: SequenceNotStr[str]
- route: Optional[str]
- """The route of the product."""
+ enabled: SequenceNotStr[str]
- visibility: Optional[Visibility]
- """Visibility of a resource"""
+ include_platform_defaults: bool
-class CreateCheckoutSessionInputModePaymentWithPlanPlan(TypedDict, total=False):
- """
- The plan attributes to create a new plan inline for this checkout configuration.
- """
+class PlanPaymentMethodConfiguration(TypedDict, total=False):
+ disabled: SequenceNotStr[str]
- company_id: Required[str]
- """The company the plan should be created for."""
+ enabled: SequenceNotStr[str]
- currency: Required[Currency]
- """The respective currency identifier for the plan."""
+ include_platform_defaults: bool
- adaptive_pricing_enabled: Optional[bool]
- """Whether this plan accepts local currency payments via adaptive pricing."""
- application_fee_amount: Optional[float]
- """The application fee amount collected by the platform from this connected
- account.
+class Plan(TypedDict, total=False):
+ """Plan attributes to create a new plan inline for this checkout configuration.
- Provided as a number in dollars (e.g., 5.00 for $5.00). Must be less than the
- total payment amount. Only valid for connected accounts with a parent company.
+ Mutually exclusive with plan_id.
"""
billing_period: Optional[int]
- """The interval in days at which the plan charges (renewal plans).
+ """The number of days between recurring charges."""
- For example, 30 for monthly billing.
+ company_id: Optional[str]
+ """The company the plan should be created for.
+
+ Defaults to the company resolved from the request.
"""
- custom_fields: Optional[Iterable[CreateCheckoutSessionInputModePaymentWithPlanPlanCustomField]]
- """An array of custom field objects."""
+ currency: Optional[str]
+ """The three-letter ISO currency code for the plan's pricing."""
description: Optional[str]
- """The description of the plan."""
+ """A text description of the plan displayed to customers."""
expiration_days: Optional[int]
- """The number of days until the membership expires (for expiration-based plans).
-
- For example, 365 for a one-year access pass.
- """
+ """The number of days until the membership expires."""
force_create_new_plan: Optional[bool]
- """
- Whether to force the creation of a new plan even if one with the same attributes
- already exists.
- """
-
- image: Optional[CreateCheckoutSessionInputModePaymentWithPlanPlanImage]
- """An image for the plan. This will be visible on the product page to customers."""
+ """Force creating a new plan even if one with the same attributes already exists."""
initial_price: Optional[float]
- """An additional amount charged upon first purchase.
+ """The amount charged on the first purchase, in the plan's currency."""
- Provided as a number in dollars (e.g., 10.00 for $10.00).
- """
+ metadata: Optional[object]
+ """Custom key-value metadata to store on the plan."""
- internal_notes: Optional[str]
- """A personal description or notes section for the business."""
+ override_tax_type: Optional[str]
+ """Override the default tax classification for this plan."""
- override_tax_type: Optional[TaxType]
- """
- Whether or not the tax is included in a plan's price (or if it hasn't been set
- up)
- """
+ payment_method_configuration: Optional[PlanPaymentMethodConfiguration]
- payment_method_configuration: Optional[CreateCheckoutSessionInputModePaymentWithPlanPlanPaymentMethodConfiguration]
- """The explicit payment method configuration for the plan.
-
- If not provided, the platform or company's defaults will apply.
- """
-
- plan_type: Optional[PlanType]
- """The type of plan that can be attached to a product"""
-
- product: Optional[CreateCheckoutSessionInputModePaymentWithPlanPlanProduct]
- """Pass this object to create a new product for this plan.
-
- We will use the product external identifier to find or create an existing
- product.
- """
+ plan_type: Optional[str]
+ """The billing model for the plan, e.g. 'one_time' or 'renewal'."""
product_id: Optional[str]
- """The product the plan is related to. Either this or product is required."""
+ """The ID of an existing product (access pass) to attach the plan to."""
- release_method: Optional[ReleaseMethod]
- """The methods of how a plan can be released."""
+ release_method: Optional[str]
+ """How the plan is sold, e.g. 'buy_now'."""
renewal_price: Optional[float]
- """The amount the customer is charged every billing period.
-
- Provided as a number in dollars (e.g., 9.99 for $9.99/period).
"""
-
- split_pay_required_payments: Optional[int]
- """The number of payments required before pausing the subscription."""
+ The amount charged each billing period for recurring plans, in the plan's
+ currency.
+ """
stock: Optional[int]
- """The number of units available for purchase.
-
- If not provided, stock is unlimited.
- """
+ """The maximum number of units available for purchase."""
title: Optional[str]
- """The title of the plan. This will be visible on the product page to customers."""
+ """The display name of the plan shown to customers."""
trial_period_days: Optional[int]
- """The number of free trial days added before a renewal plan."""
-
- visibility: Optional[Visibility]
- """Visibility of a resource"""
-
-
-class CreateCheckoutSessionInputModePaymentWithPlanCheckoutStyling(TypedDict, total=False):
- """Checkout styling overrides for this session.
-
- Overrides plan and company defaults.
- """
-
- background_color: Optional[str]
- """
- A hex color code for the checkout page background, applied to the order summary
- panel (e.g. #F4F4F5).
- """
-
- border_style: Optional[CheckoutShape]
- """The different border-radius styles available for checkout pages."""
-
- button_color: Optional[str]
- """A hex color code for the button color (e.g. #FF5733)."""
-
- font_family: Optional[CheckoutFont]
- """The different font families available for checkout pages."""
-
-
-class CreateCheckoutSessionInputModePaymentWithPlanPaymentMethodConfiguration(TypedDict, total=False):
- """The explicit payment method configuration for the checkout session.
-
- Only applies to setup mode. If not provided, the platform or company defaults will apply.
- """
-
- disabled: Required[List[PaymentMethodTypes]]
- """An array of payment method identifiers that are explicitly disabled.
-
- Only applies if the include_platform_defaults is true.
- """
-
- enabled: Required[List[PaymentMethodTypes]]
- """An array of payment method identifiers that are explicitly enabled.
-
- This means these payment methods will be shown on checkout. Example use case is
- to only enable a specific payment method like cashapp, or extending the platform
- defaults with additional methods.
- """
-
- include_platform_defaults: Optional[bool]
- """
- Whether Whop's platform default payment method enablement settings are included
- in this configuration. The full list of default payment methods can be found in
- the documentation at docs.whop.com/payments.
- """
-
-
-class CreateCheckoutSessionInputModePaymentWithPlanID(TypedDict, total=False):
- plan_id: Required[str]
- """
- The unique identifier of an existing plan to use for this checkout
- configuration.
- """
-
- affiliate_code: Optional[str]
- """An affiliate tracking code to attribute the checkout to a specific affiliate."""
-
- allow_promo_codes: Optional[bool]
- """
- Whether the checkout should show the promo code input field and accept promo
- codes. Defaults to true.
- """
-
- checkout_styling: Optional[CreateCheckoutSessionInputModePaymentWithPlanIDCheckoutStyling]
- """Checkout styling overrides for this session.
-
- Overrides plan and company defaults.
- """
-
- currency: Optional[Currency]
- """The available currencies on the platform"""
-
- metadata: Optional[Dict[str, object]]
- """Custom key-value metadata to attach to the checkout configuration."""
-
- mode: Literal["payment"]
-
- payment_method_configuration: Optional[CreateCheckoutSessionInputModePaymentWithPlanIDPaymentMethodConfiguration]
- """The explicit payment method configuration for the checkout session.
-
- Only applies to setup mode. If not provided, the platform or company defaults
- will apply.
- """
-
- redirect_url: Optional[str]
- """The URL to redirect the user to after checkout is completed."""
-
- source_url: Optional[str]
- """The URL of the page where the checkout is being initiated from."""
-
-
-class CreateCheckoutSessionInputModePaymentWithPlanIDCheckoutStyling(TypedDict, total=False):
- """Checkout styling overrides for this session.
-
- Overrides plan and company defaults.
- """
-
- background_color: Optional[str]
- """
- A hex color code for the checkout page background, applied to the order summary
- panel (e.g. #F4F4F5).
- """
-
- border_style: Optional[CheckoutShape]
- """The different border-radius styles available for checkout pages."""
-
- button_color: Optional[str]
- """A hex color code for the button color (e.g. #FF5733)."""
-
- font_family: Optional[CheckoutFont]
- """The different font families available for checkout pages."""
-
-
-class CreateCheckoutSessionInputModePaymentWithPlanIDPaymentMethodConfiguration(TypedDict, total=False):
- """The explicit payment method configuration for the checkout session.
-
- Only applies to setup mode. If not provided, the platform or company defaults will apply.
- """
-
- disabled: Required[List[PaymentMethodTypes]]
- """An array of payment method identifiers that are explicitly disabled.
-
- Only applies if the include_platform_defaults is true.
- """
-
- enabled: Required[List[PaymentMethodTypes]]
- """An array of payment method identifiers that are explicitly enabled.
-
- This means these payment methods will be shown on checkout. Example use case is
- to only enable a specific payment method like cashapp, or extending the platform
- defaults with additional methods.
- """
-
- include_platform_defaults: Optional[bool]
- """
- Whether Whop's platform default payment method enablement settings are included
- in this configuration. The full list of default payment methods can be found in
- the documentation at docs.whop.com/payments.
- """
-
-
-class CreateCheckoutSessionInputModeSetup(TypedDict, total=False):
- company_id: Required[str]
- """The unique identifier of the company to create the checkout configuration for.
-
- Only required in setup mode.
- """
-
- mode: Required[Literal["setup"]]
-
- allow_promo_codes: Optional[bool]
- """
- Whether the checkout should show the promo code input field and accept promo
- codes. Defaults to true.
- """
-
- checkout_styling: Optional[CreateCheckoutSessionInputModeSetupCheckoutStyling]
- """Checkout styling overrides for this session.
-
- Overrides plan and company defaults.
- """
-
- currency: Optional[Currency]
- """The available currencies on the platform"""
-
- metadata: Optional[Dict[str, object]]
- """Custom key-value metadata to attach to the checkout configuration."""
-
- payment_method_configuration: Optional[CreateCheckoutSessionInputModeSetupPaymentMethodConfiguration]
- """The explicit payment method configuration for the checkout session.
-
- Only applies to setup mode. If not provided, the platform or company defaults
- will apply.
- """
-
- redirect_url: Optional[str]
- """The URL to redirect the user to after checkout is completed."""
-
- source_url: Optional[str]
- """The URL of the page where the checkout is being initiated from."""
-
- three_ds_level: Optional[Literal["mandate_challenge", "frictionless"]]
- """The 3D Secure behavior for a plan."""
-
-
-class CreateCheckoutSessionInputModeSetupCheckoutStyling(TypedDict, total=False):
- """Checkout styling overrides for this session.
-
- Overrides plan and company defaults.
- """
-
- background_color: Optional[str]
- """
- A hex color code for the checkout page background, applied to the order summary
- panel (e.g. #F4F4F5).
- """
-
- border_style: Optional[CheckoutShape]
- """The different border-radius styles available for checkout pages."""
-
- button_color: Optional[str]
- """A hex color code for the button color (e.g. #FF5733)."""
-
- font_family: Optional[CheckoutFont]
- """The different font families available for checkout pages."""
-
-
-class CreateCheckoutSessionInputModeSetupPaymentMethodConfiguration(TypedDict, total=False):
- """The explicit payment method configuration for the checkout session.
-
- Only applies to setup mode. If not provided, the platform or company defaults will apply.
- """
-
- disabled: Required[List[PaymentMethodTypes]]
- """An array of payment method identifiers that are explicitly disabled.
-
- Only applies if the include_platform_defaults is true.
- """
-
- enabled: Required[List[PaymentMethodTypes]]
- """An array of payment method identifiers that are explicitly enabled.
-
- This means these payment methods will be shown on checkout. Example use case is
- to only enable a specific payment method like cashapp, or extending the platform
- defaults with additional methods.
- """
-
- include_platform_defaults: Optional[bool]
- """
- Whether Whop's platform default payment method enablement settings are included
- in this configuration. The full list of default payment methods can be found in
- the documentation at docs.whop.com/payments.
- """
+ """The number of free trial days before the first charge."""
+ unlimited_stock: Optional[bool]
+ """Whether the plan has unlimited stock."""
-CheckoutConfigurationCreateParams: TypeAlias = Union[
- CreateCheckoutSessionInputModePaymentWithPlan,
- CreateCheckoutSessionInputModePaymentWithPlanID,
- CreateCheckoutSessionInputModeSetup,
-]
+ visibility: Optional[str]
+ """Whether the plan is visible to customers or hidden."""
diff --git a/src/whop_sdk/types/checkout_configuration_create_response.py b/src/whop_sdk/types/checkout_configuration_create_response.py
new file mode 100644
index 00000000..0e2c7e79
--- /dev/null
+++ b/src/whop_sdk/types/checkout_configuration_create_response.py
@@ -0,0 +1,52 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["CheckoutConfigurationCreateResponse"]
+
+
+class CheckoutConfigurationCreateResponse(BaseModel):
+ id: str
+ """The unique identifier of the checkout configuration."""
+
+ company_id: str
+ """The ID of the company that owns this checkout configuration."""
+
+ created_at: int
+ """Unix timestamp when the checkout configuration was created."""
+
+ mode: Literal["payment", "setup"]
+ """The checkout mode."""
+
+ updated_at: int
+ """Unix timestamp when the checkout configuration was last updated."""
+
+ affiliate_code: Optional[str] = None
+ """The affiliate code applied at checkout."""
+
+ currency: Optional[str] = None
+ """The currency for this checkout configuration."""
+
+ metadata: Optional[object] = None
+ """Arbitrary key-value metadata.
+
+ Only returned when caller has checkout_configuration:basic:read scope.
+ """
+
+ payment_method_configuration: Optional[object] = None
+ """Payment method configuration."""
+
+ plan: Optional[object] = None
+ """The plan associated with this checkout configuration."""
+
+ purchase_url: Optional[str] = None
+ """The URL for the checkout page."""
+
+ redirect_url: Optional[str] = None
+ """The URL to redirect after checkout."""
+
+ three_ds_level: Optional[str] = None
+ """The 3D Secure enforcement level."""
diff --git a/src/whop_sdk/types/checkout_configuration_list_params.py b/src/whop_sdk/types/checkout_configuration_list_params.py
index b2770334..9056e81b 100644
--- a/src/whop_sdk/types/checkout_configuration_list_params.py
+++ b/src/whop_sdk/types/checkout_configuration_list_params.py
@@ -2,43 +2,32 @@
from __future__ import annotations
-from typing import Union, Optional
-from datetime import datetime
-from typing_extensions import Required, Annotated, TypedDict
-
-from .._utils import PropertyInfo
-from .shared.direction import Direction
+from typing_extensions import Literal, Required, TypedDict
__all__ = ["CheckoutConfigurationListParams"]
class CheckoutConfigurationListParams(TypedDict, total=False):
company_id: Required[str]
- """The unique identifier of the company to list checkout configurations for."""
-
- after: Optional[str]
- """Returns the elements in the list that come after the specified cursor."""
+ """The ID of the company to list checkout configurations for."""
- before: Optional[str]
- """Returns the elements in the list that come before the specified cursor."""
+ after: str
+ """Cursor for forward pagination."""
- created_after: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """Only return checkout configurations created after this timestamp."""
+ created_after: int
+ """Filter to configurations created after this Unix timestamp."""
- created_before: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """Only return checkout configurations created before this timestamp."""
+ created_before: int
+ """Filter to configurations created before this Unix timestamp."""
- direction: Optional[Direction]
- """The direction of the sort."""
+ direction: Literal["asc", "desc"]
+ """Sort direction."""
- first: Optional[int]
- """Returns the first _n_ elements from the list."""
+ first: int
+ """Number of results to return (forward pagination)."""
- last: Optional[int]
- """Returns the last _n_ elements from the list."""
+ order: Literal["created_at"]
+ """The field to sort checkout configurations by."""
- plan_id: Optional[str]
- """
- Filter checkout configurations to only those associated with this plan
- identifier.
- """
+ plan_id: str
+ """Filter by plan ID."""
diff --git a/src/whop_sdk/types/checkout_configuration_list_response.py b/src/whop_sdk/types/checkout_configuration_list_response.py
index be80192b..5c1348c2 100644
--- a/src/whop_sdk/types/checkout_configuration_list_response.py
+++ b/src/whop_sdk/types/checkout_configuration_list_response.py
@@ -1,163 +1,52 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Dict, List, Optional
+from typing import Optional
from typing_extensions import Literal
from .._models import BaseModel
-from .checkout_modes import CheckoutModes
-from .shared.currency import Currency
-from .shared.plan_type import PlanType
-from .shared.visibility import Visibility
-from .payment_method_types import PaymentMethodTypes
-from .shared.release_method import ReleaseMethod
-__all__ = ["CheckoutConfigurationListResponse", "PaymentMethodConfiguration", "Plan"]
-
-
-class PaymentMethodConfiguration(BaseModel):
- """The explicit payment method configuration for the session, if any.
-
- This currently only works in 'setup' mode. Use the plan's payment_method_configuration for payment method.
- """
-
- disabled: List[PaymentMethodTypes]
- """An array of payment method identifiers that are explicitly disabled.
-
- Only applies if the include_platform_defaults is true.
- """
-
- enabled: List[PaymentMethodTypes]
- """An array of payment method identifiers that are explicitly enabled.
-
- This means these payment methods will be shown on checkout. Example use case is
- to only enable a specific payment method like cashapp, or extending the platform
- defaults with additional methods.
- """
-
- include_platform_defaults: bool
- """
- Whether Whop's platform default payment method enablement settings are included
- in this configuration. The full list of default payment methods can be found in
- the documentation at docs.whop.com/payments.
- """
-
-
-class Plan(BaseModel):
- """The plan to use for the checkout configuration"""
-
- id: str
- """The unique identifier for the plan."""
-
- adaptive_pricing_enabled: bool
- """Whether the creator has turned on adaptive pricing for this plan.
-
- Raw setting — does not check processor compatibility or feature flags.
- """
-
- billing_period: Optional[int] = None
- """The number of days between each recurring charge.
-
- Null for one-time plans. For example, 30 for monthly or 365 for annual billing.
- """
-
- currency: Currency
- """The currency used for all prices on this plan (e.g., 'usd', 'eur').
-
- All monetary amounts on the plan are denominated in this currency.
- """
-
- expiration_days: Optional[int] = None
- """The number of days until the membership expires (for expiration-based plans).
-
- For example, 365 for a one-year access pass.
- """
-
- initial_price: float
- """The initial purchase price in the plan's base_currency (e.g., 49.99 for $49.99).
-
- For one-time plans, this is the full price. For renewal plans, this is charged
- on top of the first renewal_price.
- """
-
- plan_type: PlanType
- """
- The billing model for this plan: 'renewal' for recurring subscriptions or
- 'one_time' for single payments.
- """
-
- release_method: ReleaseMethod
- """
- The method used to sell this plan: 'buy_now' for immediate purchase or
- 'waitlist' for waitlist-based access.
- """
-
- renewal_price: float
- """
- The recurring price charged every billing_period in the plan's base_currency
- (e.g., 9.99 for $9.99/period). Zero for one-time plans.
- """
-
- three_ds_level: Optional[Literal["mandate_challenge", "frictionless"]] = None
- """The 3D Secure behavior for a plan."""
-
- trial_period_days: Optional[int] = None
- """The number of free trial days before the first charge on a renewal plan.
-
- Null if no trial is configured or the current user has already used a trial for
- this plan.
- """
-
- visibility: Visibility
- """Controls whether the plan is visible to customers.
-
- When set to 'hidden', the plan is only accessible via direct link.
- """
+__all__ = ["CheckoutConfigurationListResponse"]
class CheckoutConfigurationListResponse(BaseModel):
- """
- A checkout configuration is a reusable configuration for a checkout, including the plan, affiliate, and custom metadata. Payments and memberships created from a checkout session inherit its metadata.
- """
-
id: str
- """The unique identifier for the checkout session."""
-
- affiliate_code: Optional[str] = None
- """The affiliate code to use for the checkout configuration"""
+ """The unique identifier of the checkout configuration."""
- allow_promo_codes: bool
- """Whether the checkout configuration allows promo codes.
+ company_id: str
+ """The ID of the company that owns this checkout configuration."""
- When false, the promo code input is hidden and promo codes are rejected.
- """
+ created_at: int
+ """Unix timestamp when the checkout configuration was created."""
- company_id: str
- """The ID of the company to use for the checkout configuration"""
+ mode: Literal["payment", "setup"]
+ """The checkout mode."""
- currency: Optional[Currency] = None
- """The available currencies on the platform"""
+ updated_at: int
+ """Unix timestamp when the checkout configuration was last updated."""
- metadata: Optional[Dict[str, object]] = None
- """The metadata to use for the checkout configuration"""
+ affiliate_code: Optional[str] = None
+ """The affiliate code applied at checkout."""
- mode: CheckoutModes
- """The mode of the checkout session."""
+ currency: Optional[str] = None
+ """The currency for this checkout configuration."""
- payment_method_configuration: Optional[PaymentMethodConfiguration] = None
- """The explicit payment method configuration for the session, if any.
+ metadata: Optional[object] = None
+ """Arbitrary key-value metadata.
- This currently only works in 'setup' mode. Use the plan's
- payment_method_configuration for payment method.
+ Only returned when caller has checkout_configuration:basic:read scope.
"""
- plan: Optional[Plan] = None
- """The plan to use for the checkout configuration"""
+ payment_method_configuration: Optional[object] = None
+ """Payment method configuration."""
- purchase_url: str
- """A URL you can send to customers to complete a checkout.
+ plan: Optional[object] = None
+ """The plan associated with this checkout configuration."""
- It looks like `/checkout/plan_xxxx?session={id}`
- """
+ purchase_url: Optional[str] = None
+ """The URL for the checkout page."""
redirect_url: Optional[str] = None
- """The URL to redirect the user to after the checkout configuration is created"""
+ """The URL to redirect after checkout."""
+
+ three_ds_level: Optional[str] = None
+ """The 3D Secure enforcement level."""
diff --git a/src/whop_sdk/types/checkout_configuration_retrieve_response.py b/src/whop_sdk/types/checkout_configuration_retrieve_response.py
new file mode 100644
index 00000000..cbaf3704
--- /dev/null
+++ b/src/whop_sdk/types/checkout_configuration_retrieve_response.py
@@ -0,0 +1,52 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["CheckoutConfigurationRetrieveResponse"]
+
+
+class CheckoutConfigurationRetrieveResponse(BaseModel):
+ id: str
+ """The unique identifier of the checkout configuration."""
+
+ company_id: str
+ """The ID of the company that owns this checkout configuration."""
+
+ created_at: int
+ """Unix timestamp when the checkout configuration was created."""
+
+ mode: Literal["payment", "setup"]
+ """The checkout mode."""
+
+ updated_at: int
+ """Unix timestamp when the checkout configuration was last updated."""
+
+ affiliate_code: Optional[str] = None
+ """The affiliate code applied at checkout."""
+
+ currency: Optional[str] = None
+ """The currency for this checkout configuration."""
+
+ metadata: Optional[object] = None
+ """Arbitrary key-value metadata.
+
+ Only returned when caller has checkout_configuration:basic:read scope.
+ """
+
+ payment_method_configuration: Optional[object] = None
+ """Payment method configuration."""
+
+ plan: Optional[object] = None
+ """The plan associated with this checkout configuration."""
+
+ purchase_url: Optional[str] = None
+ """The URL for the checkout page."""
+
+ redirect_url: Optional[str] = None
+ """The URL to redirect after checkout."""
+
+ three_ds_level: Optional[str] = None
+ """The 3D Secure enforcement level."""
diff --git a/src/whop_sdk/types/company_list_response.py b/src/whop_sdk/types/company_list_response.py
index 52d0916e..351ebd62 100644
--- a/src/whop_sdk/types/company_list_response.py
+++ b/src/whop_sdk/types/company_list_response.py
@@ -74,9 +74,7 @@ class CompanyListResponse(BaseModel):
"""
route: str
- """
- The URL slug for the company's store page (e.g., 'pickaxe' in whop.com/pickaxe).
- """
+ """URL slug for the account's store page, e.g. `pickaxe` in whop.com/pickaxe."""
send_customer_emails: bool
"""
diff --git a/src/whop_sdk/types/conversion_create_params.py b/src/whop_sdk/types/conversion_create_params.py
index e833dba0..091a72f0 100644
--- a/src/whop_sdk/types/conversion_create_params.py
+++ b/src/whop_sdk/types/conversion_create_params.py
@@ -17,7 +17,17 @@ class ConversionCreateParams(TypedDict, total=False):
"""The company to associate with this event."""
event_name: Required[
- Literal["lead", "submit_application", "contact", "complete_registration", "schedule", "custom"]
+ Literal[
+ "lead",
+ "submit_application",
+ "contact",
+ "complete_registration",
+ "schedule",
+ "view_content",
+ "add_to_cart",
+ "custom",
+ "page",
+ ]
]
"""The type of event."""
@@ -43,7 +53,10 @@ class ConversionCreateParams(TypedDict, total=False):
"""The available currencies on the platform"""
custom_name: Optional[str]
- """Custom event name when event_name is 'custom'."""
+ """Custom event name when event_name is 'custom'. Maximum 35 chars for this value."""
+
+ duration: Optional[int]
+ """For 'leave' events: milliseconds the visitor spent on the page."""
event_id: Optional[str]
"""Client-provided identifier for deduplication. Generated if omitted."""
@@ -60,6 +73,18 @@ class ConversionCreateParams(TypedDict, total=False):
referrer_url: Optional[str]
"""The referring URL."""
+ resumed: Optional[bool]
+ """For 'page' events: true when the page was restored from the back/forward cache."""
+
+ source: Optional[str]
+ """
+ For 'identify' events: where the identity was captured (url, form, manual,
+ iframe).
+ """
+
+ title: Optional[str]
+ """For 'page' events: the document title."""
+
url: Optional[str]
"""The URL where the event occurred."""
@@ -82,15 +107,27 @@ class Context(TypedDict, total=False):
ad_set_id: Optional[str]
"""Ad set ID."""
+ fbc: Optional[str]
+ """Facebook click cookie (\\__fbc, format fb.1.{timestamp}.{fbclid})."""
+
fbclid: Optional[str]
"""Facebook click ID."""
fbp: Optional[str]
"""Facebook browser pixel ID."""
+ fingerprint: Optional[str]
+ """Client-side device fingerprint."""
+
+ fingerprint_confidence: Optional[float]
+ """Confidence score (0-1) for the device fingerprint."""
+
ga: Optional[str]
"""Google Analytics client ID."""
+ gbraid: Optional[str]
+ """Google Ads gbraid click ID (iOS privacy)."""
+
gclid: Optional[str]
"""Google click ID."""
@@ -100,12 +137,36 @@ class Context(TypedDict, total=False):
ip_address: Optional[str]
"""IP address."""
+ language: Optional[str]
+ """Browser language (e.g. en-US)."""
+
+ li_fat_id: Optional[str]
+ """LinkedIn click ID."""
+
+ msclkid: Optional[str]
+ """Microsoft Advertising (Bing) click ID."""
+
+ rdt_cid: Optional[str]
+ """Reddit click ID."""
+
+ sccid: Optional[str]
+ """Snapchat click ID."""
+
+ screen_resolution: Optional[str]
+ """Screen resolution (e.g. 1920x1080)."""
+
+ timezone: Optional[str]
+ """IANA timezone (e.g. America/New_York)."""
+
ttclid: Optional[str]
"""TikTok click ID."""
ttp: Optional[str]
"""TikTok pixel ID."""
+ twclid: Optional[str]
+ """X (Twitter) click ID."""
+
user_agent: Optional[str]
"""Browser user agent string."""
@@ -127,6 +188,9 @@ class Context(TypedDict, total=False):
utm_term: Optional[str]
"""UTM term parameter."""
+ wbraid: Optional[str]
+ """Google Ads wbraid click ID (iOS privacy)."""
+
class User(TypedDict, total=False):
"""User identity and profile data."""
@@ -158,6 +222,15 @@ class User(TypedDict, total=False):
last_name: Optional[str]
"""Last name."""
+ linked_anonymous_id: Optional[str]
+ """A second anonymous identifier to link to this user (e.g.
+
+ captured across an iframe boundary).
+ """
+
+ linked_wuid: Optional[str]
+ """A wuid from a linked frame, captured across an iframe boundary."""
+
member_id: Optional[str]
"""The Whop member ID."""
diff --git a/src/whop_sdk/types/course.py b/src/whop_sdk/types/course.py
index 514fd985..38ea821d 100644
--- a/src/whop_sdk/types/course.py
+++ b/src/whop_sdk/types/course.py
@@ -111,7 +111,7 @@ class Thumbnail(BaseModel):
"""
content_type: Optional[str] = None
- """The MIME type of the uploaded file (e.g., image/jpeg, video/mp4, audio/mpeg)."""
+ """Uploaded file MIME type, such as image/jpeg, video/mp4, or audio/mpeg."""
filename: Optional[str] = None
"""The original filename of the uploaded attachment, including its file extension."""
diff --git a/src/whop_sdk/types/course_list_response.py b/src/whop_sdk/types/course_list_response.py
index 29c44d56..7178c72b 100644
--- a/src/whop_sdk/types/course_list_response.py
+++ b/src/whop_sdk/types/course_list_response.py
@@ -27,7 +27,7 @@ class Thumbnail(BaseModel):
"""
content_type: Optional[str] = None
- """The MIME type of the uploaded file (e.g., image/jpeg, video/mp4, audio/mpeg)."""
+ """Uploaded file MIME type, such as image/jpeg, video/mp4, or audio/mpeg."""
filename: Optional[str] = None
"""The original filename of the uploaded attachment, including its file extension."""
diff --git a/src/whop_sdk/types/deposit_create_params.py b/src/whop_sdk/types/deposit_create_params.py
index 6f6da819..2487a3a8 100644
--- a/src/whop_sdk/types/deposit_create_params.py
+++ b/src/whop_sdk/types/deposit_create_params.py
@@ -9,28 +9,31 @@
class DepositCreateParams(TypedDict, total=False):
- amount: Required[float]
- """Amount to deposit."""
-
destination: Required[Destination]
"""Destination account ID or wallet address.
Object form is supported for compatibility.
"""
+ amount: float
+ """Amount to prefill on hosted deposit page."""
+
metadata: Dict[str, object]
- """Arbitrary metadata echoed in the response."""
+ """Metadata to include with the deposit response."""
network: Optional[str]
- """Optional destination network override."""
+ """Destination network override."""
class DestinationUnionMember1(TypedDict, total=False):
account_id: str
+ """Destination account ID."""
address: str
+ """Destination wallet address."""
network: str
+ """Destination wallet network."""
Destination: TypeAlias = Union[str, DestinationUnionMember1]
diff --git a/src/whop_sdk/types/deposit_create_response.py b/src/whop_sdk/types/deposit_create_response.py
index f0221451..7e2d351c 100644
--- a/src/whop_sdk/types/deposit_create_response.py
+++ b/src/whop_sdk/types/deposit_create_response.py
@@ -1,38 +1,108 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Dict, Optional
+from typing import Dict, List, Optional
from typing_extensions import Literal
from .._models import BaseModel
-__all__ = ["DepositCreateResponse", "DepositAddress", "Destination"]
+__all__ = [
+ "DepositCreateResponse",
+ "Methods",
+ "MethodsBank",
+ "MethodsBankCurrency",
+ "MethodsCrypto",
+ "MethodsCryptoSupportedCurrency",
+]
-class DepositAddress(BaseModel):
- evm: str
+class MethodsBankCurrency(BaseModel):
+ account_number: Optional[str] = None
+ """Bank account number for deposits in this currency."""
- solana: str
+ currency: str
+ """Currency supported by these bank instructions."""
+ deposit_bank_name: Optional[str] = None
+ """Receiving bank name."""
-class Destination(BaseModel):
- address: str
+ deposit_beneficiary_name: Optional[str] = None
+ """Beneficiary name to use for transfer."""
- currency: str
+ deposit_reference: Optional[str] = None
+ """Reference to include with bank transfer."""
- network: str
+ rails: List[str]
+ """Active deposit rails for this currency, such as `ach`, `wire`, or `sepa`."""
- account_id: Optional[str] = None
+ routing_number: Optional[str] = None
+ """Bank routing number for deposits in this currency."""
-class DepositCreateResponse(BaseModel):
- amount: str
+class MethodsBank(BaseModel):
+ """Bank deposit details.
+
+ Only present when bank deposits are active for the destination account.
+ """
+
+ currencies: List[MethodsBankCurrency]
+ """Bank transfer currencies available for this deposit."""
+
+
+class MethodsCryptoSupportedCurrency(BaseModel):
+ icon_url: Optional[str] = None
+ """Token icon URL. Null when no icon is available."""
+
+ name: str
+ """Token symbol, such as `USDC`."""
+
+
+class MethodsCrypto(BaseModel):
+ deposit_address: Optional[str] = None
+ """Address to send funds to on this network.
+
+ Null when the provider has not issued one yet.
+ """
- deposit_address: DepositAddress
+ icon_url: Optional[str] = None
+ """Network icon URL."""
- destination: Destination
+ name: str
+ """Network display name, such as `Ethereum` or `Solana`."""
+
+ supported_currencies: List[MethodsCryptoSupportedCurrency]
+ """Tokens accepted for deposit on this network."""
+
+
+class Methods(BaseModel):
+ """Available deposit methods for destination."""
+
+ bank: Optional[MethodsBank] = None
+ """Bank deposit details.
+
+ Only present when bank deposits are active for the destination account.
+ """
+
+ crypto: List[MethodsCrypto]
+ """
+ Crypto networks available for this deposit, each with its on-chain deposit
+ address and the tokens accepted on that network.
+ """
+
+
+class DepositCreateResponse(BaseModel):
+ account_id: Optional[str] = None
+ """Account ID of the destination owner. Null for raw wallet address destinations."""
hosted_url: Optional[str] = None
+ """URL of the hosted deposit page. Only present for business destinations."""
metadata: Dict[str, object]
+ """Metadata from the request."""
+
+ methods: Methods
+ """Available deposit methods for destination."""
object: Literal["deposit"]
+
+ amount: Optional[str] = None
+ """Requested deposit amount."""
diff --git a/src/whop_sdk/types/deposit_list_params.py b/src/whop_sdk/types/deposit_list_params.py
new file mode 100644
index 00000000..4b74a28d
--- /dev/null
+++ b/src/whop_sdk/types/deposit_list_params.py
@@ -0,0 +1,12 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["DepositListParams"]
+
+
+class DepositListParams(TypedDict, total=False):
+ account_id: Required[str]
+ """Business account ID (biz\\__\\**)."""
diff --git a/src/whop_sdk/types/deposit_list_response.py b/src/whop_sdk/types/deposit_list_response.py
new file mode 100644
index 00000000..a6a3cf90
--- /dev/null
+++ b/src/whop_sdk/types/deposit_list_response.py
@@ -0,0 +1,42 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["DepositListResponse", "Bank"]
+
+
+class Bank(BaseModel):
+ id: str
+ """Bank deposit transaction ID."""
+
+ created_at: datetime
+ """When the bank deposit transaction was created."""
+
+ destination_amount: Optional[str] = None
+ """Amount credited to the account balance."""
+
+ destination_currency: Optional[str] = None
+ """Currency credited to the account balance."""
+
+ source_amount: str
+ """Amount sent by the depositor."""
+
+ source_currency: str
+ """Currency sent by the depositor."""
+
+ status: str
+ """Current bank deposit status."""
+
+
+class DepositListResponse(BaseModel):
+ account_id: str
+ """Account ID that owns these deposit transactions."""
+
+ bank: List[Bank]
+ """Bank deposit transactions for this account."""
+
+ object: Literal["deposits"]
diff --git a/src/whop_sdk/types/dispute.py b/src/whop_sdk/types/dispute.py
index b093b0c2..c34af93f 100644
--- a/src/whop_sdk/types/dispute.py
+++ b/src/whop_sdk/types/dispute.py
@@ -44,7 +44,7 @@ class CancellationPolicyAttachment(BaseModel):
"""
content_type: Optional[str] = None
- """The MIME type of the uploaded file (e.g., image/jpeg, video/mp4, audio/mpeg)."""
+ """Uploaded file MIME type, such as image/jpeg, video/mp4, or audio/mpeg."""
filename: Optional[str] = None
"""The original filename of the uploaded attachment, including its file extension."""
@@ -82,7 +82,7 @@ class CustomerCommunicationAttachment(BaseModel):
"""
content_type: Optional[str] = None
- """The MIME type of the uploaded file (e.g., image/jpeg, video/mp4, audio/mpeg)."""
+ """Uploaded file MIME type, such as image/jpeg, video/mp4, or audio/mpeg."""
filename: Optional[str] = None
"""The original filename of the uploaded attachment, including its file extension."""
@@ -231,7 +231,7 @@ class RefundPolicyAttachment(BaseModel):
"""
content_type: Optional[str] = None
- """The MIME type of the uploaded file (e.g., image/jpeg, video/mp4, audio/mpeg)."""
+ """Uploaded file MIME type, such as image/jpeg, video/mp4, or audio/mpeg."""
filename: Optional[str] = None
"""The original filename of the uploaded attachment, including its file extension."""
@@ -260,7 +260,7 @@ class UncategorizedAttachment(BaseModel):
"""
content_type: Optional[str] = None
- """The MIME type of the uploaded file (e.g., image/jpeg, video/mp4, audio/mpeg)."""
+ """Uploaded file MIME type, such as image/jpeg, video/mp4, or audio/mpeg."""
filename: Optional[str] = None
"""The original filename of the uploaded attachment, including its file extension."""
diff --git a/src/whop_sdk/types/event_list_params.py b/src/whop_sdk/types/event_list_params.py
new file mode 100644
index 00000000..1781c509
--- /dev/null
+++ b/src/whop_sdk/types/event_list_params.py
@@ -0,0 +1,30 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["EventListParams"]
+
+
+class EventListParams(TypedDict, total=False):
+ person_id: Required[str]
+ """The ID of the person."""
+
+ account_id: str
+ """The ID of the account, which will look like biz\\__******\\********.
+
+ Optional for account API keys; required for credentials that can access multiple
+ accounts.
+ """
+
+ first: int
+ """The number of events to return."""
+
+ from_: Annotated[int, PropertyInfo(alias="from")]
+ """Start of the time range as a Unix timestamp."""
+
+ to: int
+ """End of the time range as a Unix timestamp. Defaults to now."""
diff --git a/src/whop_sdk/types/event_list_response.py b/src/whop_sdk/types/event_list_response.py
new file mode 100644
index 00000000..b5fbbe18
--- /dev/null
+++ b/src/whop_sdk/types/event_list_response.py
@@ -0,0 +1,75 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from .._models import BaseModel
+
+__all__ = ["EventListResponse", "Data", "DataContext", "DataUser"]
+
+
+class DataContext(BaseModel):
+ ad_campaign_id: Optional[str] = None
+
+ ad_id: Optional[str] = None
+
+ ad_set_id: Optional[str] = None
+
+ utm_campaign: Optional[str] = None
+
+ utm_content: Optional[str] = None
+
+ utm_medium: Optional[str] = None
+
+ utm_source: Optional[str] = None
+
+ utm_term: Optional[str] = None
+
+
+class DataUser(BaseModel):
+ city: Optional[str] = None
+
+ country: Optional[str] = None
+
+ email: Optional[str] = None
+
+ first_name: Optional[str] = None
+
+ last_name: Optional[str] = None
+
+ name: Optional[str] = None
+
+ phone: Optional[str] = None
+
+ state: Optional[str] = None
+
+
+class Data(BaseModel):
+ id: str
+
+ event_id: str
+
+ event_name: str
+
+ event_time: int
+
+ context: Optional[DataContext] = None
+
+ currency: Optional[str] = None
+
+ custom_name: Optional[str] = None
+
+ path: Optional[str] = None
+
+ referrer_url: Optional[str] = None
+
+ total_usd_amount: Optional[float] = None
+
+ url: Optional[str] = None
+
+ user: Optional[DataUser] = None
+
+ value: Optional[float] = None
+
+
+class EventListResponse(BaseModel):
+ data: List[Data]
diff --git a/src/whop_sdk/types/experience_list_response.py b/src/whop_sdk/types/experience_list_response.py
index 3380a752..9b0cf573 100644
--- a/src/whop_sdk/types/experience_list_response.py
+++ b/src/whop_sdk/types/experience_list_response.py
@@ -47,9 +47,7 @@ class Company(BaseModel):
"""The unique identifier for the company."""
route: str
- """
- The URL slug for the company's store page (e.g., 'pickaxe' in whop.com/pickaxe).
- """
+ """URL slug for the account's store page, e.g. `pickaxe` in whop.com/pickaxe."""
title: str
"""The display name of the company shown to customers."""
diff --git a/src/whop_sdk/types/external_ad_status.py b/src/whop_sdk/types/external_ad_status.py
deleted file mode 100644
index 1fa97884..00000000
--- a/src/whop_sdk/types/external_ad_status.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing_extensions import Literal, TypeAlias
-
-__all__ = ["ExternalAdStatus"]
-
-ExternalAdStatus: TypeAlias = Literal["active", "paused", "inactive", "in_review", "rejected", "flagged"]
diff --git a/src/whop_sdk/types/financial_activity_list_params.py b/src/whop_sdk/types/financial_activity_list_params.py
new file mode 100644
index 00000000..33123eae
--- /dev/null
+++ b/src/whop_sdk/types/financial_activity_list_params.py
@@ -0,0 +1,56 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from datetime import date, datetime
+from typing_extensions import Annotated, TypedDict
+
+from .._types import SequenceNotStr
+from .._utils import PropertyInfo
+
+__all__ = ["FinancialActivityListParams"]
+
+
+class FinancialActivityListParams(TypedDict, total=False):
+ account_id: str
+ """The owning account ID (a biz\\__ identifier). Provide this or user_id."""
+
+ available_after: Annotated[Union[str, date], PropertyInfo(format="iso8601")]
+ """
+ Only include rows whose funds became withdrawable on or after this `YYYY-MM-DD`
+ settlement date (UTC), distinct from posted_at. Requires currency.
+ """
+
+ available_before: Annotated[Union[str, date], PropertyInfo(format="iso8601")]
+ """
+ Only include rows whose funds became withdrawable on or before this `YYYY-MM-DD`
+ settlement date (UTC). Set equal to available_after for a single day. Requires
+ currency.
+ """
+
+ currency: str
+ """Optional currency code filter, for example `usd`."""
+
+ cursor: str
+ """Cursor returned by the previous page."""
+
+ limit: int
+ """Maximum number of rows to return."""
+
+ line_types: SequenceNotStr[str]
+ """Optional ledger line categories to include.
+
+ Some categories (for example `onchain_deposit`, which covers inbound crypto
+ deposits such as MoonPay onramps) are only returned when explicitly requested
+ here.
+ """
+
+ posted_after: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]
+ """Only include rows posted after this ISO 8601 timestamp."""
+
+ posted_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]
+ """Only include rows posted before this ISO 8601 timestamp."""
+
+ user_id: str
+ """The owning user ID (a user\\__ identifier). Provide this or account_id."""
diff --git a/src/whop_sdk/types/financial_activity_list_response.py b/src/whop_sdk/types/financial_activity_list_response.py
new file mode 100644
index 00000000..a2c3248e
--- /dev/null
+++ b/src/whop_sdk/types/financial_activity_list_response.py
@@ -0,0 +1,404 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import builtins
+from typing import TYPE_CHECKING, Dict, List, Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, TypeAlias
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = [
+ "FinancialActivityListResponse",
+ "Data",
+ "DataCurrency",
+ "DataResource",
+ "DataResourceUnionMember0",
+ "DataResourceUnionMember1",
+ "DataResourceUnionMember2",
+ "DataResourceUnionMember2Owner",
+ "DataResourceUnionMember2OwnerUnionMember0",
+ "DataResourceUnionMember2OwnerUnionMember1",
+ "DataResourceUnionMember3",
+ "DataResourceUnionMember3Bank",
+ "DataResourceUnionMember3Card",
+ "DataResourceUnionMember4",
+ "DataResourceUnionMember5",
+ "DataSource",
+ "DataSourcePayoutDestination",
+ "PageInfo",
+]
+
+
+class DataCurrency(BaseModel):
+ """Currency for this ledger activity."""
+
+ code: str
+ """Currency code."""
+
+ precision: str
+ """Precision factor for the currency, for example `100000000` for USD."""
+
+
+class DataResourceUnionMember0(BaseModel):
+ id: str
+ """Account ID."""
+
+ logo_url: Optional[str] = None
+ """Account logo URL."""
+
+ object: Literal["account"]
+
+ route: Optional[str] = None
+ """Account route."""
+
+ title: Optional[str] = None
+ """Account display name."""
+
+
+class DataResourceUnionMember1(BaseModel):
+ id: str
+ """User ID."""
+
+ name: Optional[str] = None
+ """User display name."""
+
+ object: Literal["user"]
+
+ profile_picture_url: Optional[str] = None
+ """User profile image URL."""
+
+ username: Optional[str] = None
+ """User's username."""
+
+
+class DataResourceUnionMember2OwnerUnionMember0(BaseModel):
+ id: str
+ """Account ID."""
+
+ logo_url: Optional[str] = None
+ """Account logo URL."""
+
+ object: Literal["account"]
+
+ route: Optional[str] = None
+ """Account route."""
+
+ title: Optional[str] = None
+ """Account display name."""
+
+
+class DataResourceUnionMember2OwnerUnionMember1(BaseModel):
+ id: str
+ """User ID."""
+
+ name: Optional[str] = None
+ """User display name."""
+
+ object: Literal["user"]
+
+ profile_picture_url: Optional[str] = None
+ """User profile image URL."""
+
+ username: Optional[str] = None
+ """User's username."""
+
+
+DataResourceUnionMember2Owner: TypeAlias = Union[
+ DataResourceUnionMember2OwnerUnionMember0, DataResourceUnionMember2OwnerUnionMember1, None
+]
+
+
+class DataResourceUnionMember2(BaseModel):
+ id: str
+ """Ledger account ID."""
+
+ object: Literal["ledger_account"]
+
+ owner: Optional[DataResourceUnionMember2Owner] = None
+
+
+class DataResourceUnionMember3Bank(BaseModel):
+ account_name: Optional[str] = None
+ """Bank account holder name."""
+
+ account_type: Optional[str] = None
+ """Bank account type."""
+
+ bank_name: Optional[str] = None
+ """Bank name."""
+
+ last4: Optional[str] = None
+ """Last four digits of the bank account."""
+
+
+class DataResourceUnionMember3Card(BaseModel):
+ brand: Optional[str] = None
+ """Card brand."""
+
+ exp_month: Optional[int] = None
+ """Card expiration month."""
+
+ exp_year: Optional[int] = None
+ """Card expiration year."""
+
+ last4: Optional[str] = None
+ """Last four digits of the card."""
+
+
+class DataResourceUnionMember3(BaseModel):
+ id: str
+ """Payment method ID."""
+
+ bank: Optional[DataResourceUnionMember3Bank] = None
+
+ card: Optional[DataResourceUnionMember3Card] = None
+
+ email_identifier: Optional[str] = None
+ """Email identifier for email-based payment methods."""
+
+ gateway_type: Optional[str] = None
+ """Payment gateway type."""
+
+ object: Literal["payment_method"]
+
+ payment_method_type: Optional[str] = None
+ """Payment method type."""
+
+
+class DataResourceUnionMember4(BaseModel):
+ id: str
+ """Payout method ID."""
+
+ account_reference: Optional[str] = None
+ """Masked account reference."""
+
+ destination_currency_code: Optional[str] = None
+ """Destination currency code."""
+
+ institution_name: Optional[str] = None
+ """Payout institution name."""
+
+ nickname: Optional[str] = None
+ """Payout method nickname."""
+
+ object: Literal["payout_method"]
+
+ provider: Optional[str] = None
+ """Payout provider."""
+
+
+class DataResourceUnionMember5(BaseModel):
+ id: str
+ """Card transaction ID."""
+
+ authorized_at: Optional[datetime] = None
+ """ISO 8601 timestamp the transaction was authorized."""
+
+ card_id: Optional[str] = None
+ """Identifier of the card that the transaction was charged to."""
+
+ cashback_usd: Optional[str] = None
+ """Cashback earned on this transaction as a USD decimal string.
+
+ Zero for declined or ineligible transactions; null when cashback has not been
+ computed yet.
+ """
+
+ declined_reason: Optional[str] = None
+ """Reason the transaction was declined (when status is declined)."""
+
+ local_amount: Optional[str] = None
+ """Amount the merchant charged in their local currency, as a decimal string.
+
+ Pair with local_currency.
+ """
+
+ local_currency: Optional[str] = None
+ """ISO 4217 currency code of the merchant-charged amount in local_amount."""
+
+ merchant_category: Optional[str] = None
+ """Merchant category."""
+
+ merchant_icon_url: Optional[str] = None
+ """Merchant icon URL."""
+
+ merchant_name: Optional[str] = None
+ """Merchant display name."""
+
+ object: Literal["card_transaction"]
+
+ posted_at: Optional[datetime] = None
+ """ISO 8601 timestamp the transaction was settled by the card network."""
+
+ status: Optional[str] = None
+ """Current card transaction status."""
+
+ usd_amount: Optional[str] = None
+ """The processor-settled USD amount as a decimal string.
+
+ The ledger's USDT leg is posted 1:1 from this value.
+ """
+
+
+DataResource: TypeAlias = Union[
+ DataResourceUnionMember0,
+ DataResourceUnionMember1,
+ DataResourceUnionMember2,
+ DataResourceUnionMember3,
+ DataResourceUnionMember4,
+ DataResourceUnionMember5,
+ None,
+]
+
+
+class DataSourcePayoutDestination(BaseModel):
+ """Payout destination display info (withdrawal sources only)."""
+
+ icon_url: Optional[str] = None
+
+ payer_name: Optional[str] = None
+
+
+class DataSource(BaseModel):
+ """Source of this ledger activity."""
+
+ id: str
+
+ object: str
+
+ amount_float: Optional[float] = None
+ """
+ Withdrawal amount as a decimal number in the destination currency (withdrawal
+ sources only; requires payout:withdrawal:read).
+ """
+
+ chain: Optional[str] = None
+ """
+ Chain the deposit landed on, for example plasma (onchain_transaction sources
+ only).
+ """
+
+ claim_url: Optional[str] = None
+ """Public claim URL for the airdrop link (airdrop_link sources only)."""
+
+ created_at: Optional[datetime] = None
+ """
+ Withdrawal creation time as an ISO 8601 timestamp (withdrawal sources only;
+ requires payout:withdrawal:read).
+ """
+
+ estimated_arrival: Optional[datetime] = None
+ """
+ Estimated arrival as an ISO 8601 timestamp (withdrawal sources only; requires
+ payout:withdrawal:read).
+ """
+
+ from_amount: Optional[str] = None
+ """Amount converted out of from_currency as a decimal string (swap sources only)."""
+
+ from_currency: Optional[str] = None
+ """Lowercase currency code converted from (swap sources only)."""
+
+ payer_name: Optional[str] = None
+ """
+ Name of the entity processing the payout (withdrawal sources only; requires
+ payout:withdrawal:read).
+ """
+
+ payout_destination: Optional[DataSourcePayoutDestination] = None
+ """Payout destination display info (withdrawal sources only)."""
+
+ payout_token_nickname: Optional[str] = None
+ """Saved payout destination nickname (withdrawal sources only)."""
+
+ sender_address: Optional[str] = None
+ """
+ Sender wallet address or onramp provider identifier (onchain_transaction sources
+ only).
+ """
+
+ status: Optional[str] = None
+ """Lifecycle status.
+
+ On withdrawal sources this is the withdrawal status (requires
+ payout:withdrawal:read); on airdrop_link sources it is the claim-link status
+ (ungated); on payment and top-up sources it is the friendly payment status such
+ as succeeded/pending/failed (ungated).
+ """
+
+ to_amount: Optional[str] = None
+ """Amount received in to_currency as a decimal string (swap sources only)."""
+
+ to_currency: Optional[str] = None
+ """Lowercase currency code converted to (swap sources only)."""
+
+ tx_hash: Optional[str] = None
+ """On-chain transaction hash (onchain_transaction and swap sources only)."""
+
+ if TYPE_CHECKING:
+ # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a
+ # value to this field, so for compatibility we avoid doing it at runtime.
+ __pydantic_extra__: Dict[str, builtins.object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride]
+
+ # Stub to indicate that arbitrary properties are accepted.
+ # To access properties that are not valid identifiers you can use `getattr`, e.g.
+ # `getattr(obj, '$type')`
+ def __getattr__(self, attr: str) -> builtins.object: ...
+ else:
+ __pydantic_extra__: Dict[str, builtins.object]
+
+
+class Data(BaseModel):
+ id: str
+ """Ledger activity ID."""
+
+ amount: str
+ """Signed amount in the currency's smallest precision units."""
+
+ available_at: Optional[datetime] = None
+ """
+ ISO 8601 timestamp these funds became (or are scheduled to become) withdrawable:
+ the posted time for already-settled funds, or 00:00:00 UTC on the scheduled
+ release date for pending funds. Present only on inflows entering the balance
+ (payments, top-ups, incoming transfers/affiliate); null on withdrawals, refunds,
+ disputes and on-chain rows. The available_after/before filters window on its UTC
+ settlement date.
+ """
+
+ created_at: Optional[datetime] = None
+ """When the activity record was created."""
+
+ currency: DataCurrency
+ """Currency for this ledger activity."""
+
+ line_type: str
+ """Type of ledger activity."""
+
+ object: Literal["ledger_activity"]
+
+ posted_at: datetime
+ """When the activity posted to the ledger."""
+
+ resource: Optional[DataResource] = None
+ """Resource associated with this ledger activity."""
+
+ source: Optional[DataSource] = None
+ """Source of this ledger activity."""
+
+
+class PageInfo(BaseModel):
+ end_cursor: Optional[str] = None
+
+ has_next_page: bool
+
+ has_previous_page: bool
+
+ start_cursor: Optional[str] = None
+
+
+class FinancialActivityListResponse(BaseModel):
+ data: List[Data]
+
+ page_info: PageInfo
diff --git a/src/whop_sdk/types/forum_post_list_response.py b/src/whop_sdk/types/forum_post_list_response.py
index 4cbd7083..6c3fd981 100644
--- a/src/whop_sdk/types/forum_post_list_response.py
+++ b/src/whop_sdk/types/forum_post_list_response.py
@@ -22,7 +22,7 @@ class Attachment(BaseModel):
"""
content_type: Optional[str] = None
- """The MIME type of the uploaded file (e.g., image/jpeg, video/mp4, audio/mpeg)."""
+ """Uploaded file MIME type, such as image/jpeg, video/mp4, or audio/mpeg."""
filename: Optional[str] = None
"""The original filename of the uploaded attachment, including its file extension."""
diff --git a/src/whop_sdk/types/granularities.py b/src/whop_sdk/types/granularities.py
index 1a199166..62928b01 100644
--- a/src/whop_sdk/types/granularities.py
+++ b/src/whop_sdk/types/granularities.py
@@ -4,4 +4,4 @@
__all__ = ["Granularities"]
-Granularities: TypeAlias = Literal["daily", "hourly"]
+Granularities: TypeAlias = Literal["hourly", "daily", "weekly", "monthly"]
diff --git a/src/whop_sdk/types/identity_profile_approved_webhook_event.py b/src/whop_sdk/types/identity_profile_approved_webhook_event.py
index f498efd8..f03229cc 100644
--- a/src/whop_sdk/types/identity_profile_approved_webhook_event.py
+++ b/src/whop_sdk/types/identity_profile_approved_webhook_event.py
@@ -135,11 +135,10 @@ class Data(BaseModel):
"""
country: Optional[str] = None
- """ISO 3166-1 alpha-3 country code (e.g.
-
- `USA`, `GBR`). For individuals this is the country of citizenship or residence
- reported by the identity provider; for businesses this is the country of
- incorporation.
+ """
+ ISO 3166-1 alpha-2 country code reported by the identity provider, such as `US`
+ or `GB`. For individuals this is the country of citizenship or residence; for
+ businesses, the country of incorporation.
"""
created_at: datetime
diff --git a/src/whop_sdk/types/identity_profile_needs_action_webhook_event.py b/src/whop_sdk/types/identity_profile_needs_action_webhook_event.py
index 83b88252..47bdd4ac 100644
--- a/src/whop_sdk/types/identity_profile_needs_action_webhook_event.py
+++ b/src/whop_sdk/types/identity_profile_needs_action_webhook_event.py
@@ -135,11 +135,10 @@ class Data(BaseModel):
"""
country: Optional[str] = None
- """ISO 3166-1 alpha-3 country code (e.g.
-
- `USA`, `GBR`). For individuals this is the country of citizenship or residence
- reported by the identity provider; for businesses this is the country of
- incorporation.
+ """
+ ISO 3166-1 alpha-2 country code reported by the identity provider, such as `US`
+ or `GB`. For individuals this is the country of citizenship or residence; for
+ businesses, the country of incorporation.
"""
created_at: datetime
diff --git a/src/whop_sdk/types/identity_profile_rejected_webhook_event.py b/src/whop_sdk/types/identity_profile_rejected_webhook_event.py
index d6188520..473ef563 100644
--- a/src/whop_sdk/types/identity_profile_rejected_webhook_event.py
+++ b/src/whop_sdk/types/identity_profile_rejected_webhook_event.py
@@ -135,11 +135,10 @@ class Data(BaseModel):
"""
country: Optional[str] = None
- """ISO 3166-1 alpha-3 country code (e.g.
-
- `USA`, `GBR`). For individuals this is the country of citizenship or residence
- reported by the identity provider; for businesses this is the country of
- incorporation.
+ """
+ ISO 3166-1 alpha-2 country code reported by the identity provider, such as `US`
+ or `GB`. For individuals this is the country of citizenship or residence; for
+ businesses, the country of incorporation.
"""
created_at: datetime
diff --git a/src/whop_sdk/types/identity_profile_updated_webhook_event.py b/src/whop_sdk/types/identity_profile_updated_webhook_event.py
index 23b9a859..03cc5454 100644
--- a/src/whop_sdk/types/identity_profile_updated_webhook_event.py
+++ b/src/whop_sdk/types/identity_profile_updated_webhook_event.py
@@ -135,11 +135,10 @@ class Data(BaseModel):
"""
country: Optional[str] = None
- """ISO 3166-1 alpha-3 country code (e.g.
-
- `USA`, `GBR`). For individuals this is the country of citizenship or residence
- reported by the identity provider; for businesses this is the country of
- incorporation.
+ """
+ ISO 3166-1 alpha-2 country code reported by the identity provider, such as `US`
+ or `GB`. For individuals this is the country of citizenship or residence; for
+ businesses, the country of incorporation.
"""
created_at: datetime
diff --git a/src/whop_sdk/types/invoice_create_params.py b/src/whop_sdk/types/invoice_create_params.py
index 8ff9b337..ea92792c 100644
--- a/src/whop_sdk/types/invoice_create_params.py
+++ b/src/whop_sdk/types/invoice_create_params.py
@@ -7,6 +7,7 @@
from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict
from .._utils import PropertyInfo
+from .shared.currency import Currency
from .shared.plan_type import PlanType
from .shared.visibility import Visibility
from .tax_identifier_type import TaxIdentifierType
@@ -189,9 +190,15 @@ class CreateInvoiceInputWithProductPlan(TypedDict, total=False):
The plan attributes defining the price, currency, and billing interval for this invoice.
"""
+ adaptive_pricing_enabled: Optional[bool]
+ """Whether this plan accepts local currency payments via adaptive pricing."""
+
billing_period: Optional[int]
"""The interval in days at which the plan charges (renewal plans)."""
+ currency: Optional[Currency]
+ """The available currencies on the platform"""
+
custom_fields: Optional[Iterable[CreateInvoiceInputWithProductPlanCustomField]]
"""An array of custom field objects."""
@@ -475,9 +482,15 @@ class CreateInvoiceInputWithProductIDPlan(TypedDict, total=False):
The plan attributes defining the price, currency, and billing interval for this invoice.
"""
+ adaptive_pricing_enabled: Optional[bool]
+ """Whether this plan accepts local currency payments via adaptive pricing."""
+
billing_period: Optional[int]
"""The interval in days at which the plan charges (renewal plans)."""
+ currency: Optional[Currency]
+ """The available currencies on the platform"""
+
custom_fields: Optional[Iterable[CreateInvoiceInputWithProductIDPlanCustomField]]
"""An array of custom field objects."""
diff --git a/src/whop_sdk/types/invoice_update_params.py b/src/whop_sdk/types/invoice_update_params.py
index ba46184f..88d81f55 100644
--- a/src/whop_sdk/types/invoice_update_params.py
+++ b/src/whop_sdk/types/invoice_update_params.py
@@ -7,6 +7,7 @@
from typing_extensions import Literal, Required, Annotated, TypedDict
from .._utils import PropertyInfo
+from .shared.currency import Currency
from .shared.plan_type import PlanType
from .shared.visibility import Visibility
from .tax_identifier_type import TaxIdentifierType
@@ -178,9 +179,15 @@ class PlanPaymentMethodConfiguration(TypedDict, total=False):
class Plan(TypedDict, total=False):
"""Updated plan attributes."""
+ adaptive_pricing_enabled: Optional[bool]
+ """Whether this plan accepts local currency payments via adaptive pricing."""
+
billing_period: Optional[int]
"""The interval in days at which the plan charges (renewal plans)."""
+ currency: Optional[Currency]
+ """The available currencies on the platform"""
+
custom_fields: Optional[Iterable[PlanCustomField]]
"""An array of custom field objects."""
diff --git a/src/whop_sdk/types/ledger_account_funds_available_webhook_event.py b/src/whop_sdk/types/ledger_account_funds_available_webhook_event.py
new file mode 100644
index 00000000..7ceef586
--- /dev/null
+++ b/src/whop_sdk/types/ledger_account_funds_available_webhook_event.py
@@ -0,0 +1,251 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from .._utils import PropertyInfo
+from .._models import BaseModel
+from .shared.currency import Currency
+from .verification_status import VerificationStatus
+from .verification_error_code import VerificationErrorCode
+from .payout_account_calculated_statuses import PayoutAccountCalculatedStatuses
+
+__all__ = [
+ "LedgerAccountFundsAvailableWebhookEvent",
+ "Data",
+ "DataBalance",
+ "DataOwner",
+ "DataOwnerUser",
+ "DataOwnerCompany",
+ "DataPayoutAccountDetails",
+ "DataPayoutAccountDetailsAddress",
+ "DataPayoutAccountDetailsBusinessRepresentative",
+ "DataPayoutAccountDetailsLatestVerification",
+ "DataTreasuryBalance",
+]
+
+
+class DataBalance(BaseModel):
+ """A cached balance for a LedgerAccount in respect to a currency."""
+
+ balance: float
+ """The amount of the balance."""
+
+ currency: Currency
+ """The currency of the balance."""
+
+ pending_balance: float
+ """The amount of the balance that is pending."""
+
+ reserve_balance: float
+ """The amount of the balance that is reserved."""
+
+
+class DataOwnerUser(BaseModel):
+ """A user account on Whop.
+
+ Contains profile information, identity details, and social connections.
+ """
+
+ id: str
+ """The unique identifier for the user."""
+
+ name: Optional[str] = None
+ """The user's display name shown on their public profile."""
+
+ typename: Literal["User"]
+ """The typename of this object"""
+
+ username: str
+ """The user's unique username shown on their public profile."""
+
+
+class DataOwnerCompany(BaseModel):
+ """A company is a seller on Whop.
+
+ Companies own products, manage members, and receive payouts.
+ """
+
+ id: str
+ """The unique identifier for the company."""
+
+ route: str
+ """URL slug for the account's store page, e.g. `pickaxe` in whop.com/pickaxe."""
+
+ title: str
+ """The display name of the company shown to customers."""
+
+ typename: Literal["Company"]
+ """The typename of this object"""
+
+
+DataOwner: TypeAlias = Annotated[
+ Union[Optional[DataOwnerUser], Optional[DataOwnerCompany]], PropertyInfo(discriminator="typename")
+]
+
+
+class DataPayoutAccountDetailsAddress(BaseModel):
+ """The physical address associated with this payout account"""
+
+ 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."""
+
+ postal_code: Optional[str] = None
+ """The postal code of the address."""
+
+ state: Optional[str] = None
+ """The state of the address."""
+
+
+class DataPayoutAccountDetailsBusinessRepresentative(BaseModel):
+ """The business representative for this payout account"""
+
+ date_of_birth: Optional[str] = None
+ """
+ The date of birth of the business representative in ISO 8601 format
+ (YYYY-MM-DD).
+ """
+
+ first_name: Optional[str] = None
+ """The first name of the business representative."""
+
+ last_name: Optional[str] = None
+ """The last name of the business representative."""
+
+ middle_name: Optional[str] = None
+ """The middle name of the business representative."""
+
+
+class DataPayoutAccountDetailsLatestVerification(BaseModel):
+ """The latest verification for the connected account."""
+
+ id: str
+ """The numeric id of the verification record."""
+
+ last_error_code: Optional[VerificationErrorCode] = None
+ """An error code for a verification attempt."""
+
+ last_error_reason: Optional[str] = None
+ """A human-readable explanation of the most recent verification error.
+
+ Null if no error has occurred.
+ """
+
+ status: VerificationStatus
+ """The current status of this verification session."""
+
+
+class DataPayoutAccountDetails(BaseModel):
+ """The payout account associated with the LedgerAccount, if any."""
+
+ id: str
+ """The unique identifier for the payout account."""
+
+ address: Optional[DataPayoutAccountDetailsAddress] = None
+ """The physical address associated with this payout account"""
+
+ business_name: Optional[str] = None
+ """The company's legal name"""
+
+ business_representative: Optional[DataPayoutAccountDetailsBusinessRepresentative] = None
+ """The business representative for this payout account"""
+
+ email: Optional[str] = None
+ """The email address of the representative"""
+
+ latest_verification: Optional[DataPayoutAccountDetailsLatestVerification] = None
+ """The latest verification for the connected account."""
+
+ phone: Optional[str] = None
+ """The business representative's phone"""
+
+ status: Optional[PayoutAccountCalculatedStatuses] = None
+ """
+ The granular calculated statuses reflecting payout account KYC and withdrawal
+ readiness.
+ """
+
+
+class DataTreasuryBalance(BaseModel):
+ """The balance cache associated with the account by currency."""
+
+ balance: float
+ """The amount of the balance."""
+
+ balance_usd: float
+ """The balance converted to USD."""
+
+ currency: Currency
+ """The currency of the balance."""
+
+ pending_balance: float
+ """The amount of the balance that is pending."""
+
+ reserve_balance: float
+ """The amount of the balance that is reserved."""
+
+ total_withdrawable_balance: float
+ """The amount of the balance that is withdrawable."""
+
+
+class Data(BaseModel):
+ """
+ A ledger account represents a financial account on Whop that can hold many balances.
+ """
+
+ id: str
+ """The unique identifier for the ledger account."""
+
+ balances: List[DataBalance]
+ """The balances associated with the account."""
+
+ ledger_type: Literal["primary", "pool"]
+ """The type of ledger account."""
+
+ owner: DataOwner
+ """The owner of the ledger account."""
+
+ payments_approval_status: Optional[Literal["pending", "approved", "monitoring", "rejected"]] = None
+ """The different approval statuses an account can have."""
+
+ payout_account_details: Optional[DataPayoutAccountDetails] = None
+ """The payout account associated with the LedgerAccount, if any."""
+
+ transfer_fee: Optional[float] = None
+ """The fee for transfers, if applicable."""
+
+ treasury_balance: Optional[DataTreasuryBalance] = None
+ """The balance cache associated with the account by currency."""
+
+
+class LedgerAccountFundsAvailableWebhookEvent(BaseModel):
+ id: str
+ """A unique ID for every single webhook request"""
+
+ api_version: Literal["v1"]
+ """The API version for this webhook"""
+
+ data: Data
+ """
+ A ledger account represents a financial account on Whop that can hold many
+ balances.
+ """
+
+ timestamp: datetime
+ """The timestamp in ISO 8601 format that the webhook was sent at on the server"""
+
+ type: Literal["ledger_account.funds_available"]
+ """The webhook event type"""
+
+ company_id: Optional[str] = None
+ """The company ID that this webhook event is associated with"""
diff --git a/src/whop_sdk/types/ledger_account_retrieve_response.py b/src/whop_sdk/types/ledger_account_retrieve_response.py
index fcaeeed0..86b90d83 100644
--- a/src/whop_sdk/types/ledger_account_retrieve_response.py
+++ b/src/whop_sdk/types/ledger_account_retrieve_response.py
@@ -69,9 +69,7 @@ class OwnerCompany(BaseModel):
"""The unique identifier for the company."""
route: str
- """
- The URL slug for the company's store page (e.g., 'pickaxe' in whop.com/pickaxe).
- """
+ """URL slug for the account's store page, e.g. `pickaxe` in whop.com/pickaxe."""
title: str
"""The display name of the company shown to customers."""
diff --git a/src/whop_sdk/types/lesson.py b/src/whop_sdk/types/lesson.py
index a962bd3e..121e8205 100644
--- a/src/whop_sdk/types/lesson.py
+++ b/src/whop_sdk/types/lesson.py
@@ -36,7 +36,7 @@ class AssessmentQuestionImage(BaseModel):
"""
content_type: Optional[str] = None
- """The MIME type of the uploaded file (e.g., image/jpeg, video/mp4, audio/mpeg)."""
+ """Uploaded file MIME type, such as image/jpeg, video/mp4, or audio/mpeg."""
filename: Optional[str] = None
"""The original filename of the uploaded attachment, including its file extension."""
@@ -113,7 +113,7 @@ class Attachment(BaseModel):
"""
content_type: Optional[str] = None
- """The MIME type of the uploaded file (e.g., image/jpeg, video/mp4, audio/mpeg)."""
+ """Uploaded file MIME type, such as image/jpeg, video/mp4, or audio/mpeg."""
filename: Optional[str] = None
"""The original filename of the uploaded attachment, including its file extension."""
@@ -142,7 +142,7 @@ class MainPdf(BaseModel):
"""
content_type: Optional[str] = None
- """The MIME type of the uploaded file (e.g., image/jpeg, video/mp4, audio/mpeg)."""
+ """Uploaded file MIME type, such as image/jpeg, video/mp4, or audio/mpeg."""
filename: Optional[str] = None
"""The original filename of the uploaded attachment, including its file extension."""
diff --git a/src/whop_sdk/types/membership_list_response.py b/src/whop_sdk/types/membership_list_response.py
index 89bccb93..77034358 100644
--- a/src/whop_sdk/types/membership_list_response.py
+++ b/src/whop_sdk/types/membership_list_response.py
@@ -40,7 +40,8 @@ class Plan(BaseModel):
metadata: Optional[Dict[str, object]] = None
"""Custom key-value pairs stored on the plan.
- Included in webhook payloads for payment and membership events.
+ Included in webhook payloads for payment and membership events. Max 50 keys, 100
+ chars per key, 500 chars per string value.
"""
@@ -51,9 +52,10 @@ class Product(BaseModel):
"""The unique identifier for the product."""
metadata: Optional[Dict[str, object]] = None
- """Custom key-value pairs stored on the product.
-
- Included in webhook payloads for payment and membership events.
+ """
+ Custom key-value pairs stored on the product and included in payment and
+ membership webhook payloads. Max 50 keys, 100 characters per key, 500 characters
+ per string value.
"""
title: str
@@ -170,7 +172,7 @@ class MembershipListResponse(BaseModel):
metadata: Optional[Dict[str, object]] = None
"""
Custom key-value pairs for the membership (commonly used for software licensing,
- e.g., HWID). Max 50 keys, 500 chars per key, 5000 chars per value.
+ e.g., HWID). Max 50 keys, 100 chars per key, 500 chars per string value.
"""
payment_collection_paused: bool
diff --git a/src/whop_sdk/types/membership_trial_ending_soon_webhook_event.py b/src/whop_sdk/types/membership_trial_ending_soon_webhook_event.py
new file mode 100644
index 00000000..fc6d3b8e
--- /dev/null
+++ b/src/whop_sdk/types/membership_trial_ending_soon_webhook_event.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+from .shared.membership import Membership
+
+__all__ = ["MembershipTrialEndingSoonWebhookEvent"]
+
+
+class MembershipTrialEndingSoonWebhookEvent(BaseModel):
+ id: str
+ """A unique ID for every single webhook request"""
+
+ api_version: Literal["v1"]
+ """The API version for this webhook"""
+
+ data: Membership
+ """A membership represents an active relationship between a user and a product.
+
+ It tracks the user's access, billing status, and renewal schedule.
+ """
+
+ timestamp: datetime
+ """The timestamp in ISO 8601 format that the webhook was sent at on the server"""
+
+ type: Literal["membership.trial_ending_soon"]
+ """The webhook event type"""
+
+ company_id: Optional[str] = None
+ """The company ID that this webhook event is associated with"""
diff --git a/src/whop_sdk/types/payment_list_response.py b/src/whop_sdk/types/payment_list_response.py
index 44a2275d..7199461b 100644
--- a/src/whop_sdk/types/payment_list_response.py
+++ b/src/whop_sdk/types/payment_list_response.py
@@ -26,6 +26,7 @@
"Plan",
"Product",
"PromoCode",
+ "ShippingAddress",
"User",
]
@@ -167,7 +168,8 @@ class Plan(BaseModel):
metadata: Optional[Dict[str, object]] = None
"""Custom key-value pairs stored on the plan.
- Included in webhook payloads for payment and membership events.
+ Included in webhook payloads for payment and membership events. Max 50 keys, 100
+ chars per key, 500 chars per string value.
"""
@@ -178,15 +180,16 @@ class Product(BaseModel):
"""The unique identifier for the product."""
metadata: Optional[Dict[str, object]] = None
- """Custom key-value pairs stored on the product.
-
- Included in webhook payloads for payment and membership events.
+ """
+ Custom key-value pairs stored on the product and included in payment and
+ membership webhook payloads. Max 50 keys, 100 characters per key, 500 characters
+ per string value.
"""
route: str
- """
- The URL slug used in the product's public link (e.g., 'my-product' in
- whop.com/company/my-product).
+ """URL slug in the product's public link, e.g.
+
+ `pickaxe-analytics` in whop.com/company/pickaxe-analytics.
"""
title: str
@@ -223,6 +226,34 @@ class PromoCode(BaseModel):
"""The type (% or flat amount) of the promo."""
+class ShippingAddress(BaseModel):
+ """The shipping address provided by the customer for physical goods.
+
+ Null if no shipping address was collected.
+ """
+
+ 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 User(BaseModel):
"""The user that made this payment."""
@@ -364,6 +395,12 @@ class PaymentListResponse(BaseModel):
settlement_currency: Currency
"""The three-letter ISO currency code for this payment (e.g., 'usd', 'eur')."""
+ shipping_address: Optional[ShippingAddress] = None
+ """The shipping address provided by the customer for physical goods.
+
+ Null if no shipping address was collected.
+ """
+
status: Optional[ReceiptStatus] = None
"""The status of a receipt"""
diff --git a/src/whop_sdk/types/payout_list_params.py b/src/whop_sdk/types/payout_list_params.py
new file mode 100644
index 00000000..e3b0e4e7
--- /dev/null
+++ b/src/whop_sdk/types/payout_list_params.py
@@ -0,0 +1,30 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["PayoutListParams"]
+
+
+class PayoutListParams(TypedDict, total=False):
+ account_id: str
+ """The owning account ID (a biz\\__ identifier). Provide this or user_id."""
+
+ after: str
+ """Cursor to fetch the page after (from page_info.end_cursor)."""
+
+ before: str
+ """Cursor to fetch the page before (from page_info.start_cursor)."""
+
+ currency: str
+ """Optional currency code filter, for example `usd`."""
+
+ first: int
+ """Number of payouts to return from the start of the window."""
+
+ last: int
+ """Number of payouts to return from the end of the window."""
+
+ user_id: str
+ """The owning user ID (a user\\__ identifier). Provide this or account_id."""
diff --git a/src/whop_sdk/types/payout_list_response.py b/src/whop_sdk/types/payout_list_response.py
new file mode 100644
index 00000000..3d25fb3a
--- /dev/null
+++ b/src/whop_sdk/types/payout_list_response.py
@@ -0,0 +1,69 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["PayoutListResponse", "PayoutToken", "PayoutTokenPayoutDestination"]
+
+
+class PayoutTokenPayoutDestination(BaseModel):
+ """Payout destination display details."""
+
+ icon_url: Optional[str] = None
+ """Payout destination icon URL."""
+
+ payer_name: Optional[str] = None
+ """Payout destination display name."""
+
+
+class PayoutToken(BaseModel):
+ """The saved payout method used.
+
+ Requires payout:destination:read; null without it.
+ """
+
+ nickname: Optional[str] = None
+ """Saved payout method nickname."""
+
+ payout_destination: Optional[PayoutTokenPayoutDestination] = None
+ """Payout destination display details."""
+
+
+class PayoutListResponse(BaseModel):
+ id: str
+ """Payout ID."""
+
+ amount: float
+ """The payout amount in whole currency units."""
+
+ created_at: datetime
+ """When the payout was created."""
+
+ currency: str
+ """Payout currency."""
+
+ estimated_arrival: Optional[datetime] = None
+ """Estimated time the funds become available in the destination account."""
+
+ fee_amount: float
+ """The fee charged for the payout, in the payout currency."""
+
+ object: Literal["payout"]
+
+ payer_name: Optional[str] = None
+ """Name of the entity processing the payout."""
+
+ payout_token: Optional[PayoutToken] = None
+ """The saved payout method used.
+
+ Requires payout:destination:read; null without it.
+ """
+
+ speed: Literal["standard", "instant"]
+ """Payout delivery speed."""
+
+ status: Literal["requested", "awaiting_payment", "in_transit", "completed", "failed", "canceled", "denied"]
+ """Current payout status."""
diff --git a/src/whop_sdk/types/person_list_params.py b/src/whop_sdk/types/person_list_params.py
new file mode 100644
index 00000000..af89c9be
--- /dev/null
+++ b/src/whop_sdk/types/person_list_params.py
@@ -0,0 +1,42 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["PersonListParams"]
+
+
+class PersonListParams(TypedDict, total=False):
+ account_id: str
+ """The ID of the account, which will look like biz\\__******\\********.
+
+ Optional for account API keys; required for credentials that can access multiple
+ accounts.
+ """
+
+ direction: Literal["asc", "desc"]
+ """Sort direction. Defaults to desc."""
+
+ filters: str
+ """A JSON-encoded array of filters, each with field, operator, and value keys."""
+
+ first: int
+ """The number of people to return (default 100, max 101)."""
+
+ from_: Annotated[int, PropertyInfo(alias="from")]
+ """Start of the time range as a Unix timestamp. Defaults to 366 days before `to`."""
+
+ offset: int
+ """The number of people to skip, for offset pagination."""
+
+ sort: str
+ """Column to sort by (e.g.
+
+ last_seen_at, ltv, purchase_count). Defaults to last_seen_at.
+ """
+
+ to: int
+ """End of the time range as a Unix timestamp. Defaults to now."""
diff --git a/src/whop_sdk/types/person_list_response.py b/src/whop_sdk/types/person_list_response.py
new file mode 100644
index 00000000..3d5d8ad4
--- /dev/null
+++ b/src/whop_sdk/types/person_list_response.py
@@ -0,0 +1,67 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from .._models import BaseModel
+
+__all__ = ["PersonListResponse", "Data", "DataAdSet", "DataAd", "DataCampaign"]
+
+
+class DataAdSet(BaseModel):
+ id: str
+
+ name: Optional[str] = None
+
+ thumbnail_url: Optional[str] = None
+
+
+class DataAd(BaseModel):
+ id: str
+
+ name: Optional[str] = None
+
+ thumbnail_url: Optional[str] = None
+
+
+class DataCampaign(BaseModel):
+ id: str
+
+ name: Optional[str] = None
+
+ thumbnail_url: Optional[str] = None
+
+
+class Data(BaseModel):
+ id: str
+
+ first_seen_at: int
+
+ last_seen_at: int
+
+ person_id: str
+
+ purchase_count: int
+
+ ad_sets: Optional[List[DataAdSet]] = None
+
+ ads: Optional[List[DataAd]] = None
+
+ aov: Optional[float] = None
+
+ campaigns: Optional[List[DataCampaign]] = None
+
+ email: Optional[str] = None
+
+ has_failed_payment: Optional[bool] = None
+
+ ltv: Optional[float] = None
+
+ name: Optional[str] = None
+
+ phone: Optional[str] = None
+
+
+class PersonListResponse(BaseModel):
+ data: List[Data]
+
+ total_count: int
diff --git a/src/whop_sdk/types/person_retrieve_params.py b/src/whop_sdk/types/person_retrieve_params.py
new file mode 100644
index 00000000..eb58b6db
--- /dev/null
+++ b/src/whop_sdk/types/person_retrieve_params.py
@@ -0,0 +1,24 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["PersonRetrieveParams"]
+
+
+class PersonRetrieveParams(TypedDict, total=False):
+ account_id: str
+ """The ID of the account, which will look like biz\\__******\\********.
+
+ Optional for account API keys; required for credentials that can access multiple
+ accounts.
+ """
+
+ from_: Annotated[int, PropertyInfo(alias="from")]
+ """Start of the time range as a Unix timestamp."""
+
+ to: int
+ """End of the time range as a Unix timestamp. Defaults to now."""
diff --git a/src/whop_sdk/types/person_retrieve_response.py b/src/whop_sdk/types/person_retrieve_response.py
new file mode 100644
index 00000000..359b1949
--- /dev/null
+++ b/src/whop_sdk/types/person_retrieve_response.py
@@ -0,0 +1,65 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from .._models import BaseModel
+
+__all__ = ["PersonRetrieveResponse", "Data", "DataAdSet", "DataAd", "DataCampaign"]
+
+
+class DataAdSet(BaseModel):
+ id: str
+
+ name: Optional[str] = None
+
+ thumbnail_url: Optional[str] = None
+
+
+class DataAd(BaseModel):
+ id: str
+
+ name: Optional[str] = None
+
+ thumbnail_url: Optional[str] = None
+
+
+class DataCampaign(BaseModel):
+ id: str
+
+ name: Optional[str] = None
+
+ thumbnail_url: Optional[str] = None
+
+
+class Data(BaseModel):
+ id: str
+
+ first_seen_at: int
+
+ last_seen_at: int
+
+ person_id: str
+
+ purchase_count: int
+
+ ad_sets: Optional[List[DataAdSet]] = None
+
+ ads: Optional[List[DataAd]] = None
+
+ aov: Optional[float] = None
+
+ campaigns: Optional[List[DataCampaign]] = None
+
+ email: Optional[str] = None
+
+ has_failed_payment: Optional[bool] = None
+
+ ltv: Optional[float] = None
+
+ name: Optional[str] = None
+
+ phone: Optional[str] = None
+
+
+class PersonRetrieveResponse(BaseModel):
+ data: Data
diff --git a/src/whop_sdk/types/plan_calculate_tax_params.py b/src/whop_sdk/types/plan_calculate_tax_params.py
new file mode 100644
index 00000000..7e7c98e5
--- /dev/null
+++ b/src/whop_sdk/types/plan_calculate_tax_params.py
@@ -0,0 +1,167 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Iterable, Optional
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["PlanCalculateTaxParams", "Address", "TaxID"]
+
+
+class PlanCalculateTaxParams(TypedDict, total=False):
+ address: Optional[Address]
+ """The buyer's billing address. Provide this or ip_address."""
+
+ ip_address: str
+ """
+ The buyer's IP address, used to resolve their location when no address is
+ provided.
+ """
+
+ tax_ids: Optional[Iterable[TaxID]]
+ """
+ The buyer's tax IDs, such as a VAT number, used to apply B2B reverse-charge
+ exemptions.
+ """
+
+
+class Address(TypedDict, total=False):
+ """The buyer's billing address. Provide this or ip_address."""
+
+ country: Required[str]
+ """The two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ city: Optional[str]
+ """The city name."""
+
+ line1: Optional[str]
+ """The first line of the street address."""
+
+ line2: Optional[str]
+ """The second line of the street address."""
+
+ postal_code: Optional[str]
+ """The postal or ZIP code."""
+
+ state: Optional[str]
+ """The state, province, or region code, for example `CA`."""
+
+
+class TaxID(TypedDict, total=False):
+ type: Literal[
+ "ad_nrt",
+ "ao_tin",
+ "ar_cuit",
+ "al_tin",
+ "am_tin",
+ "aw_tin",
+ "au_abn",
+ "au_arn",
+ "eu_vat",
+ "az_tin",
+ "bs_tin",
+ "bh_vat",
+ "bd_bin",
+ "bb_tin",
+ "by_tin",
+ "bj_ifu",
+ "bo_tin",
+ "ba_tin",
+ "br_cnpj",
+ "br_cpf",
+ "bg_uic",
+ "bf_ifu",
+ "kh_tin",
+ "cm_niu",
+ "ca_bn",
+ "ca_gst_hst",
+ "ca_pst_bc",
+ "ca_pst_mb",
+ "ca_pst_sk",
+ "ca_qst",
+ "cv_nif",
+ "cl_tin",
+ "cn_tin",
+ "co_nit",
+ "cd_nif",
+ "cr_tin",
+ "hr_oib",
+ "do_rcn",
+ "ec_ruc",
+ "eg_tin",
+ "sv_nit",
+ "et_tin",
+ "eu_oss_vat",
+ "ge_vat",
+ "gh_tin",
+ "de_stn",
+ "gb_vat",
+ "gn_nif",
+ "hk_br",
+ "hu_tin",
+ "is_vat",
+ "in_gst",
+ "id_npwp",
+ "il_vat",
+ "jp_cn",
+ "jp_rn",
+ "jp_trn",
+ "kz_bin",
+ "ke_pin",
+ "kg_tin",
+ "la_tin",
+ "li_uid",
+ "li_vat",
+ "my_frp",
+ "my_itn",
+ "my_sst",
+ "mr_nif",
+ "mx_rfc",
+ "md_vat",
+ "me_pib",
+ "ma_vat",
+ "np_pan",
+ "nz_gst",
+ "ng_tin",
+ "mk_vat",
+ "no_vat",
+ "no_voec",
+ "om_vat",
+ "pe_ruc",
+ "ph_tin",
+ "ro_tin",
+ "ru_inn",
+ "ru_kpp",
+ "sa_vat",
+ "sn_ninea",
+ "rs_pib",
+ "sg_gst",
+ "sg_uen",
+ "si_tin",
+ "za_vat",
+ "kr_brn",
+ "es_cif",
+ "ch_uid",
+ "ch_vat",
+ "tw_vat",
+ "tj_tin",
+ "tz_vat",
+ "th_vat",
+ "tr_tin",
+ "ug_tin",
+ "ua_vat",
+ "ae_trn",
+ "us_ein",
+ "uy_ruc",
+ "uz_tin",
+ "uz_vat",
+ "ve_rif",
+ "vn_tin",
+ "zm_tin",
+ "zw_tin",
+ "sr_fin",
+ ]
+ """Tax ID type, for example `eu_vat`."""
+
+ value: str
+ """Tax ID number, for example `DE123456789`."""
diff --git a/src/whop_sdk/types/plan_calculate_tax_response.py b/src/whop_sdk/types/plan_calculate_tax_response.py
new file mode 100644
index 00000000..7201920e
--- /dev/null
+++ b/src/whop_sdk/types/plan_calculate_tax_response.py
@@ -0,0 +1,41 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["PlanCalculateTaxResponse"]
+
+
+class PlanCalculateTaxResponse(BaseModel):
+ currency: str
+ """The three-letter ISO 4217 currency code of the amounts."""
+
+ status: Literal["calculated", "not_calculated"]
+ """Whether tax was successfully calculated.
+
+ Returns not_calculated when tax could not be determined.
+ """
+
+ subtotal: int
+ """The plan price in the currency's smallest unit, for example cents.
+
+ For exclusive tax this is the pre-tax amount; for inclusive tax it already
+ contains the tax and equals the total.
+ """
+
+ tax_amount: int
+ """The tax owed, in the currency's smallest unit.
+
+ For exclusive tax it is added on top of the subtotal; for inclusive tax it is
+ the portion already contained in the subtotal.
+ """
+
+ tax_behavior: Literal["exclusive", "inclusive"]
+ """
+ Whether tax is added on top of the price (exclusive) or already included in it
+ (inclusive).
+ """
+
+ total: int
+ """The total amount the buyer pays, in the currency's smallest unit."""
diff --git a/src/whop_sdk/types/plan_create_params.py b/src/whop_sdk/types/plan_create_params.py
index 34e9edc1..86d54694 100644
--- a/src/whop_sdk/types/plan_create_params.py
+++ b/src/whop_sdk/types/plan_create_params.py
@@ -2,108 +2,90 @@
from __future__ import annotations
-from typing import Dict, List, Iterable, Optional
-from typing_extensions import Literal, Required, TypedDict
+from typing import Iterable, Optional
+from typing_extensions import Literal, TypedDict
-from .checkout_font import CheckoutFont
-from .checkout_shape import CheckoutShape
-from .shared.currency import Currency
-from .shared.tax_type import TaxType
-from .shared.plan_type import PlanType
-from .shared.visibility import Visibility
-from .payment_method_types import PaymentMethodTypes
-from .shared.release_method import ReleaseMethod
+from .._types import SequenceNotStr
-__all__ = ["PlanCreateParams", "CheckoutStyling", "CustomField", "Image", "PaymentMethodConfiguration"]
+__all__ = ["PlanCreateParams", "CustomField", "Image", "PaymentMethodConfiguration"]
class PlanCreateParams(TypedDict, total=False):
- company_id: Required[str]
- """The unique identifier of the company to create this plan for."""
+ account_id: str
+ """The unique identifier of the account to create this plan for.
- product_id: Required[str]
- """The unique identifier of the product to attach this plan to."""
+ Defaults to the caller's account.
+ """
adaptive_pricing_enabled: Optional[bool]
"""Whether this plan accepts local currency payments via adaptive pricing."""
billing_period: Optional[int]
- """The number of days between recurring charges.
-
- For example, 30 for monthly or 365 for yearly.
- """
-
- checkout_styling: Optional[CheckoutStyling]
- """Checkout styling overrides for this plan.
+ """Recurring billing interval in days, such as 30 for monthly or 365 for annual."""
- Pass null to inherit from the company default.
- """
+ checkout_styling: Optional[object]
+ """Checkout styling overrides for this plan."""
- currency: Optional[Currency]
- """The available currencies on the platform"""
+ currency: str
+ """The three-letter ISO currency code for the plan's pricing. Defaults to USD."""
custom_fields: Optional[Iterable[CustomField]]
- """An array of custom field definitions to collect from customers at checkout."""
+ """An array of custom field definitions to collect from customers at checkout.
+
+ Omitting this field clears existing custom fields.
+ """
description: Optional[str]
"""A text description of the plan displayed to customers on the product page."""
expiration_days: Optional[int]
- """The number of days until the membership expires and access is revoked.
-
- Used for expiration-based plans.
- """
+ """Access duration in days before the membership expires."""
image: Optional[Image]
"""An image displayed on the product page to represent this plan."""
initial_price: Optional[float]
- """The amount charged on the first purchase.
-
- For one-time plans, this is the full price. For recurring plans, this is an
- additional charge on top of the renewal price. Provided in the plan's currency
- (e.g., 10.43 for $10.43).
- """
+ """Initial amount charged in the plan's currency, e.g. 10.43 for $10.43."""
internal_notes: Optional[str]
- """Private notes visible only to the business owner. Not shown to customers."""
+ """Private notes visible only to the account owner. Not shown to customers."""
legacy_payment_method_controls: Optional[bool]
"""Whether this plan uses legacy payment method controls."""
- metadata: Optional[Dict[str, object]]
+ metadata: Optional[object]
"""Custom key-value pairs to store on the plan.
- Included in webhook payloads for payment and membership events. Max 50 keys, 500
- chars per key, 5000 chars per value.
+ Included in webhook payloads for payment and membership events. Max 50 keys, 100
+ chars per key, 500 chars per string value.
"""
- override_tax_type: Optional[TaxType]
- """
- Whether or not the tax is included in a plan's price (or if it hasn't been set
- up)
- """
+ override_tax_type: str
+ """Override the default tax classification for this specific plan."""
payment_method_configuration: Optional[PaymentMethodConfiguration]
"""Explicit payment method configuration for the plan.
- When not provided, the company's defaults apply.
+ When not provided, the account's defaults apply.
"""
- plan_type: Optional[PlanType]
- """The type of plan that can be attached to a product"""
+ plan_type: str
+ """Plan billing type, such as `one_time` or `renewal`."""
+
+ product_id: str
+ """The unique identifier of the product to attach this plan to."""
- release_method: Optional[ReleaseMethod]
- """The methods of how a plan can be released."""
+ release_method: str
+ """Sales method for this plan, such as `buy_now` or `waitlist`."""
renewal_price: Optional[float]
- """The amount charged each billing period for recurring plans.
-
- Provided in the plan's currency (e.g., 10.43 for $10.43).
+ """
+ The amount charged each billing period for recurring plans, in the plan's
+ currency.
"""
split_pay_required_payments: Optional[int]
- """The number of installment payments required before the subscription pauses."""
+ """Installment payments required before the subscription pauses."""
stock: Optional[int]
"""The maximum number of units available for purchase.
@@ -111,97 +93,58 @@ class PlanCreateParams(TypedDict, total=False):
Ignored when unlimited_stock is true.
"""
- three_ds_level: Optional[Literal["mandate_challenge", "frictionless"]]
- """The 3D Secure behavior for a plan."""
+ three_ds_level: Literal["mandate_challenge", "frictionless"]
+ """3D Secure behavior for this plan. Send `null` to inherit the account default."""
title: Optional[str]
"""The display name of the plan shown to customers on the product page."""
trial_period_days: Optional[int]
- """The number of free trial days before the first charge on a recurring plan."""
+ """Free trial duration before the first recurring charge."""
unlimited_stock: Optional[bool]
- """Whether the plan has unlimited stock.
-
- When true, the stock field is ignored. Defaults to true.
- """
+ """Whether the plan has unlimited stock. When true, the stock field is ignored."""
- visibility: Optional[Visibility]
- """Visibility of a resource"""
-
-
-class CheckoutStyling(TypedDict, total=False):
- """Checkout styling overrides for this plan.
-
- Pass null to inherit from the company default.
- """
-
- background_color: Optional[str]
- """
- A hex color code for the checkout page background, applied to the order summary
- panel (e.g. #F4F4F5).
- """
-
- border_style: Optional[CheckoutShape]
- """The different border-radius styles available for checkout pages."""
-
- button_color: Optional[str]
- """A hex color code for the button color (e.g. #FF5733)."""
-
- font_family: Optional[CheckoutFont]
- """The different font families available for checkout pages."""
+ visibility: str
+ """Whether the plan is visible to customers or hidden from public view."""
class CustomField(TypedDict, total=False):
- field_type: Required[Literal["text"]]
+ id: str
+ """The ID of the custom field (if being updated)."""
+
+ field_type: Literal["text"]
"""The type of the custom field."""
- name: Required[str]
+ name: str
"""The name of the custom field."""
- id: Optional[str]
- """The ID of the custom field (if being updated)"""
-
- order: Optional[int]
+ order: int
"""The order of the field."""
placeholder: Optional[str]
- """The placeholder value of the field."""
+ """An example response displayed in the input field."""
- required: Optional[bool]
+ required: bool
"""Whether or not the field is required."""
class Image(TypedDict, total=False):
"""An image displayed on the product page to represent this plan."""
- id: Required[str]
- """The ID of an existing file object."""
+ id: str
+
+ direct_upload_id: str
class PaymentMethodConfiguration(TypedDict, total=False):
"""Explicit payment method configuration for the plan.
- When not provided, the company's defaults apply.
+ When not provided, the account's defaults apply.
"""
- disabled: Required[List[PaymentMethodTypes]]
- """An array of payment method identifiers that are explicitly disabled.
-
- Only applies if the include_platform_defaults is true.
- """
+ disabled: SequenceNotStr[str]
- enabled: Required[List[PaymentMethodTypes]]
- """An array of payment method identifiers that are explicitly enabled.
+ enabled: SequenceNotStr[str]
- This means these payment methods will be shown on checkout. Example use case is
- to only enable a specific payment method like cashapp, or extending the platform
- defaults with additional methods.
- """
-
- include_platform_defaults: Optional[bool]
- """
- Whether Whop's platform default payment method enablement settings are included
- in this configuration. The full list of default payment methods can be found in
- the documentation at docs.whop.com/payments.
- """
+ include_platform_defaults: bool
diff --git a/src/whop_sdk/types/plan_list_params.py b/src/whop_sdk/types/plan_list_params.py
index fc24663e..daaa48a7 100644
--- a/src/whop_sdk/types/plan_list_params.py
+++ b/src/whop_sdk/types/plan_list_params.py
@@ -2,56 +2,49 @@
from __future__ import annotations
-from typing import List, Union, Optional
-from datetime import datetime
-from typing_extensions import Literal, Required, Annotated, TypedDict
+from typing_extensions import Literal, Required, TypedDict
from .._types import SequenceNotStr
-from .._utils import PropertyInfo
-from .shared.direction import Direction
-from .shared.plan_type import PlanType
-from .shared.release_method import ReleaseMethod
-from .shared.visibility_filter import VisibilityFilter
__all__ = ["PlanListParams"]
class PlanListParams(TypedDict, total=False):
- company_id: Required[str]
- """The unique identifier of the company to list plans for."""
+ account_id: Required[str]
+ """The unique identifier of the account to list plans for."""
- after: Optional[str]
- """Returns the elements in the list that come after the specified cursor."""
+ after: str
+ """A cursor; returns plans after this position."""
- before: Optional[str]
- """Returns the elements in the list that come before the specified cursor."""
+ before: str
+ """A cursor; returns plans before this position."""
- created_after: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
+ created_after: str
"""Only return plans created after this timestamp."""
- created_before: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
+ created_before: str
"""Only return plans created before this timestamp."""
- direction: Optional[Direction]
- """The direction of the sort."""
+ direction: Literal["asc", "desc"]
+ """The sort direction for results. Defaults to descending."""
- first: Optional[int]
- """Returns the first _n_ elements from the list."""
+ first: int
+ """The number of plans to return (default and max 100)."""
- last: Optional[int]
- """Returns the last _n_ elements from the list."""
+ last: int
+ """The number of plans to return from the end of the range."""
- order: Optional[Literal["id", "active_members_count", "created_at", "internal_notes", "expires_at"]]
- """The ways a relation of Plans can be ordered"""
+ order: Literal["id", "active_members_count", "created_at", "internal_notes", "expiration_days"]
+ """The field to sort results by. Defaults to created_at."""
- plan_types: Optional[List[PlanType]]
+ plan_types: SequenceNotStr[str]
"""Filter to only plans matching these billing types."""
- product_ids: Optional[SequenceNotStr[str]]
+ product_ids: SequenceNotStr[str]
"""Filter to only plans belonging to these product identifiers."""
- release_methods: Optional[List[ReleaseMethod]]
+ release_methods: SequenceNotStr[str]
"""Filter to only plans matching these release methods."""
- visibilities: Optional[List[VisibilityFilter]]
+ visibilities: SequenceNotStr[str]
"""Filter to only plans matching these visibility states."""
diff --git a/src/whop_sdk/types/plan_list_response.py b/src/whop_sdk/types/plan_list_response.py
index db577cf4..28c91fa1 100644
--- a/src/whop_sdk/types/plan_list_response.py
+++ b/src/whop_sdk/types/plan_list_response.py
@@ -1,240 +1,103 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Dict, List, Optional
-from datetime import datetime
-from typing_extensions import Literal
+from typing import Optional
from .._models import BaseModel
-from .shared.currency import Currency
-from .shared.plan_type import PlanType
-from .shared.visibility import Visibility
-from .payment_method_types import PaymentMethodTypes
-from .shared.release_method import ReleaseMethod
-__all__ = ["PlanListResponse", "Company", "Invoice", "PaymentMethodConfiguration", "Product"]
-
-
-class Company(BaseModel):
- """The company that sells this plan.
-
- Null for standalone invoice plans not linked to a company.
- """
-
- id: str
- """The unique identifier for the company."""
-
- title: str
- """The display name of the company shown to customers."""
-
-
-class Invoice(BaseModel):
- """The invoice this plan was generated for.
-
- Null if the plan was not created for a specific invoice.
- """
-
- id: str
- """The unique identifier for the invoice."""
-
-
-class PaymentMethodConfiguration(BaseModel):
- """
- The explicit payment method configuration specifying which payment methods are enabled or disabled for this plan. Null if the plan uses default settings.
- """
-
- disabled: List[PaymentMethodTypes]
- """An array of payment method identifiers that are explicitly disabled.
-
- Only applies if the include_platform_defaults is true.
- """
-
- enabled: List[PaymentMethodTypes]
- """An array of payment method identifiers that are explicitly enabled.
-
- This means these payment methods will be shown on checkout. Example use case is
- to only enable a specific payment method like cashapp, or extending the platform
- defaults with additional methods.
- """
-
- include_platform_defaults: bool
- """
- Whether Whop's platform default payment method enablement settings are included
- in this configuration. The full list of default payment methods can be found in
- the documentation at docs.whop.com/payments.
- """
-
-
-class Product(BaseModel):
- """The product that this plan belongs to.
-
- Null for standalone one-off purchases not linked to a product.
- """
-
- id: str
- """The unique identifier for the product."""
-
- title: str
- """
- The display name of the product shown to customers on the product page and in
- search results.
- """
+__all__ = ["PlanListResponse"]
class PlanListResponse(BaseModel):
- """A plan defines pricing and billing terms for a checkout.
-
- Plans can optionally belong to a product, where they represent different pricing options such as one-time payments, recurring subscriptions, or free trials.
- """
-
id: str
- """The unique identifier for the plan."""
-
- adaptive_pricing_enabled: bool
- """Whether the creator has turned on adaptive pricing for this plan.
-
- Raw setting — does not check processor compatibility or feature flags.
- """
+ """Plan ID, prefixed `plan_`."""
- billing_period: Optional[int] = None
- """The number of days between each recurring charge.
+ account: Optional[object] = None
+ """Account that sells this plan; `null` for standalone invoice plans."""
- Null for one-time plans. For example, 30 for monthly or 365 for annual billing.
- """
+ adaptive_pricing_enabled: bool
+ """Whether this plan accepts local currency payments via adaptive pricing."""
- company: Optional[Company] = None
- """The company that sells this plan.
+ billing_period: Optional[float] = None
+ """Recurring billing interval in days, such as 30 for monthly or 365 for annual.
- Null for standalone invoice plans not linked to a company.
+ `null` for one-time plans.
"""
- created_at: datetime
- """The datetime the plan was created."""
+ created_at: str
+ """When the plan was created, as an ISO 8601 timestamp."""
- currency: Currency
- """The currency used for all prices on this plan (e.g., 'usd', 'eur').
-
- All monetary amounts on the plan are denominated in this currency.
- """
+ currency: str
+ """Three-letter ISO currency code for this plan's prices."""
description: Optional[str] = None
- """A text description of the plan visible to customers.
-
- Maximum 1000 characters. Null if no description is set.
- """
-
- expiration_days: Optional[int] = None
- """The number of days until the membership expires (for expiration-based plans).
+ """Customer-visible plan description."""
- For example, 365 for a one-year access pass.
- """
+ expiration_days: Optional[float] = None
+ """Access duration in days for expiration-based plans."""
initial_price: float
- """The initial purchase price in the plan's base_currency (e.g., 49.99 for $49.99).
-
- For one-time plans, this is the full price. For renewal plans, this is charged
- on top of the first renewal_price.
- """
+ """Initial purchase price in plan currency."""
internal_notes: Optional[str] = None
- """Private notes visible only to the company owner and team members.
-
- Not shown to customers. Null if no notes have been added.
- """
+ """Private notes visible only to authorized team members."""
- invoice: Optional[Invoice] = None
- """The invoice this plan was generated for.
+ invoice: Optional[object] = None
+ """Invoice this plan was generated for; `null` unless created for an invoice."""
- Null if the plan was not created for a specific invoice.
- """
+ member_count: Optional[float] = None
+ """Active memberships through this plan, when visible to the requester."""
- member_count: Optional[int] = None
- """The number of users who currently hold an active membership through this plan.
+ metadata: Optional[object] = None
+ """Custom key-value pairs stored on the plan."""
- Only visible to authorized team members.
+ payment_method_configuration: Optional[object] = None
"""
-
- metadata: Optional[Dict[str, object]] = None
- """Custom key-value pairs stored on the plan.
-
- Included in webhook payloads for payment and membership events.
+ Payment method configuration (`enabled`, `disabled`,
+ `include_platform_defaults`); `null` when plan uses default settings.
"""
- payment_method_configuration: Optional[PaymentMethodConfiguration] = None
+ plan_type: str
"""
- The explicit payment method configuration specifying which payment methods are
- enabled or disabled for this plan. Null if the plan uses default settings.
+ Billing model for this plan: `renewal` (recurring) or `one_time` (single
+ payment).
"""
- plan_type: PlanType
- """
- The billing model for this plan: 'renewal' for recurring subscriptions or
- 'one_time' for single payments.
- """
-
- product: Optional[Product] = None
- """The product that this plan belongs to.
-
- Null for standalone one-off purchases not linked to a product.
- """
+ product: Optional[object] = None
+ """Product this plan belongs to; `null` for standalone plans."""
purchase_url: str
- """
- The full URL where customers can purchase this plan directly, bypassing the
- product page.
- """
+ """URL where customers can purchase this plan directly."""
- release_method: ReleaseMethod
- """
- The method used to sell this plan: 'buy_now' for immediate purchase or
- 'waitlist' for waitlist-based access.
- """
+ release_method: str
+ """Sales method for this plan, such as `buy_now` or `waitlist`."""
renewal_price: float
- """
- The recurring price charged every billing_period in the plan's base_currency
- (e.g., 9.99 for $9.99/period). Zero for one-time plans.
- """
+ """Recurring price charged every billing period."""
- split_pay_required_payments: Optional[int] = None
- """The total number of installment payments required before the subscription
- pauses.
+ split_pay_required_payments: Optional[float] = None
+ """Installment payments required before the subscription pauses."""
- Null if split pay is not configured. Must be greater than 1.
- """
+ stock: Optional[float] = None
+ """Units available for purchase, when visible to the requester."""
- stock: Optional[int] = None
- """The number of units available for purchase.
-
- Only visible to authorized team members. Null if the requester lacks permission.
- """
-
- three_ds_level: Optional[Literal["mandate_challenge", "frictionless"]] = None
- """The 3D Secure behavior for a plan."""
+ three_ds_level: Optional[str] = None
+ """3D Secure behavior for this plan; `null` inherits account default."""
title: Optional[str] = None
- """
- The display name of the plan shown to customers on the product page and at
- checkout. Maximum 30 characters. Null if no title has been set.
- """
+ """Plan display name shown to customers."""
- trial_period_days: Optional[int] = None
- """The number of free trial days before the first charge on a renewal plan.
+ trial_period_days: Optional[float] = None
+ """Free trial days before the first renewal charge.
- Null if no trial is configured or the current user has already used a trial for
- this plan.
+ `null` if no trial is configured or the user has already used a trial for this
+ plan.
"""
unlimited_stock: bool
- """When true, the plan has unlimited stock (stock field is ignored).
+ """Whether the plan has unlimited stock."""
- When false, purchases are limited by the stock field.
- """
-
- updated_at: datetime
- """The datetime the plan was last updated."""
+ updated_at: str
+ """When the plan was last updated, as an ISO 8601 timestamp."""
- visibility: Visibility
- """Controls whether the plan is visible to customers.
-
- When set to 'hidden', the plan is only accessible via direct link.
- """
+ visibility: str
+ """Whether the plan is visible to customers or hidden from public view."""
diff --git a/src/whop_sdk/types/plan_update_params.py b/src/whop_sdk/types/plan_update_params.py
index 853a890f..bf5882af 100644
--- a/src/whop_sdk/types/plan_update_params.py
+++ b/src/whop_sdk/types/plan_update_params.py
@@ -2,17 +2,12 @@
from __future__ import annotations
-from typing import Dict, List, Iterable, Optional
-from typing_extensions import Literal, Required, TypedDict
+from typing import Iterable, Optional
+from typing_extensions import Literal, TypedDict
-from .checkout_font import CheckoutFont
-from .checkout_shape import CheckoutShape
-from .shared.currency import Currency
-from .shared.tax_type import TaxType
-from .shared.visibility import Visibility
-from .payment_method_types import PaymentMethodTypes
+from .._types import SequenceNotStr
-__all__ = ["PlanUpdateParams", "CheckoutStyling", "CustomField", "Image", "PaymentMethodConfiguration"]
+__all__ = ["PlanUpdateParams", "CustomField", "Image", "PaymentMethodConfiguration"]
class PlanUpdateParams(TypedDict, total=False):
@@ -20,73 +15,61 @@ class PlanUpdateParams(TypedDict, total=False):
"""Whether this plan accepts local currency payments via adaptive pricing."""
billing_period: Optional[int]
- """The number of days between recurring charges.
+ """Recurring billing interval in days, such as 30 for monthly or 365 for annual."""
- For example, 30 for monthly or 365 for yearly.
- """
-
- checkout_styling: Optional[CheckoutStyling]
- """Checkout styling overrides for this plan.
+ checkout_styling: Optional[object]
+ """Checkout styling overrides for this plan."""
- Pass null to remove all overrides and inherit from the company default.
- """
-
- currency: Optional[Currency]
- """The available currencies on the platform"""
+ currency: str
+ """The three-letter ISO currency code for the plan's pricing. Defaults to USD."""
custom_fields: Optional[Iterable[CustomField]]
- """An array of custom field definitions to collect from customers at checkout."""
+ """An array of custom field definitions to collect from customers at checkout.
+
+ Omitting this field clears existing custom fields.
+ """
description: Optional[str]
"""A text description of the plan displayed to customers on the product page."""
expiration_days: Optional[int]
- """The number of days until the membership expires and access is revoked.
-
- For example, 365 for one-year access.
- """
+ """Access duration in days before the membership expires."""
image: Optional[Image]
"""An image displayed on the product page to represent this plan."""
initial_price: Optional[float]
- """The amount charged on the first purchase.
-
- Provided in the plan's currency (e.g., 10.43 for $10.43).
- """
+ """Initial amount charged in the plan's currency, e.g. 10.43 for $10.43."""
internal_notes: Optional[str]
- """Private notes visible only to the business owner. Not shown to customers."""
+ """Private notes visible only to the account owner. Not shown to customers."""
legacy_payment_method_controls: Optional[bool]
"""Whether this plan uses legacy payment method controls."""
- metadata: Optional[Dict[str, object]]
+ metadata: Optional[object]
"""Custom key-value pairs to store on the plan.
- Included in webhook payloads for payment and membership events. Max 50 keys, 500
- chars per key, 5000 chars per value.
+ Included in webhook payloads for payment and membership events. Max 50 keys, 100
+ chars per key, 500 chars per string value.
"""
offer_cancel_discount: Optional[bool]
"""Whether to offer a retention discount when a customer attempts to cancel."""
- override_tax_type: Optional[TaxType]
- """
- Whether or not the tax is included in a plan's price (or if it hasn't been set
- up)
- """
+ override_tax_type: str
+ """Override the default tax classification for this specific plan."""
payment_method_configuration: Optional[PaymentMethodConfiguration]
"""Explicit payment method configuration for the plan.
- Sending null removes any custom configuration.
+ When not provided, the account's defaults apply.
"""
renewal_price: Optional[float]
- """The amount charged each billing period for recurring plans.
-
- Provided in the plan's currency (e.g., 10.43 for $10.43).
+ """
+ The amount charged each billing period for recurring plans, in the plan's
+ currency.
"""
stock: Optional[int]
@@ -96,105 +79,63 @@ class PlanUpdateParams(TypedDict, total=False):
"""
strike_through_initial_price: Optional[float]
- """A comparison price displayed with a strikethrough for the initial price.
-
- Provided in the plan's currency (e.g., 19.99 for $19.99).
- """
+ """A comparison price displayed with a strikethrough for the initial price."""
strike_through_renewal_price: Optional[float]
- """A comparison price displayed with a strikethrough for the renewal price.
-
- Provided in the plan's currency (e.g., 19.99 for $19.99).
- """
+ """A comparison price displayed with a strikethrough for the renewal price."""
- three_ds_level: Optional[Literal["mandate_challenge", "frictionless"]]
- """The 3D Secure behavior for a plan."""
+ three_ds_level: Literal["mandate_challenge", "frictionless"]
+ """3D Secure behavior for this plan. Send `null` to inherit the account default."""
title: Optional[str]
"""The display name of the plan shown to customers on the product page."""
trial_period_days: Optional[int]
- """The number of free trial days before the first charge on a recurring plan."""
+ """Free trial duration before the first recurring charge."""
unlimited_stock: Optional[bool]
"""Whether the plan has unlimited stock. When true, the stock field is ignored."""
- visibility: Optional[Visibility]
- """Visibility of a resource"""
-
-
-class CheckoutStyling(TypedDict, total=False):
- """Checkout styling overrides for this plan.
-
- Pass null to remove all overrides and inherit from the company default.
- """
-
- background_color: Optional[str]
- """
- A hex color code for the checkout page background, applied to the order summary
- panel (e.g. #F4F4F5).
- """
-
- border_style: Optional[CheckoutShape]
- """The different border-radius styles available for checkout pages."""
-
- button_color: Optional[str]
- """A hex color code for the button color (e.g. #FF5733)."""
-
- font_family: Optional[CheckoutFont]
- """The different font families available for checkout pages."""
+ visibility: str
+ """Whether the plan is visible to customers or hidden from public view."""
class CustomField(TypedDict, total=False):
- field_type: Required[Literal["text"]]
+ id: str
+ """The ID of the custom field (if being updated)."""
+
+ field_type: Literal["text"]
"""The type of the custom field."""
- name: Required[str]
+ name: str
"""The name of the custom field."""
- id: Optional[str]
- """The ID of the custom field (if being updated)"""
-
- order: Optional[int]
+ order: int
"""The order of the field."""
placeholder: Optional[str]
- """The placeholder value of the field."""
+ """An example response displayed in the input field."""
- required: Optional[bool]
+ required: bool
"""Whether or not the field is required."""
class Image(TypedDict, total=False):
"""An image displayed on the product page to represent this plan."""
- id: Required[str]
- """The ID of an existing file object."""
+ id: str
+
+ direct_upload_id: str
class PaymentMethodConfiguration(TypedDict, total=False):
"""Explicit payment method configuration for the plan.
- Sending null removes any custom configuration.
+ When not provided, the account's defaults apply.
"""
- disabled: Required[List[PaymentMethodTypes]]
- """An array of payment method identifiers that are explicitly disabled.
-
- Only applies if the include_platform_defaults is true.
- """
+ disabled: SequenceNotStr[str]
- enabled: Required[List[PaymentMethodTypes]]
- """An array of payment method identifiers that are explicitly enabled.
+ enabled: SequenceNotStr[str]
- This means these payment methods will be shown on checkout. Example use case is
- to only enable a specific payment method like cashapp, or extending the platform
- defaults with additional methods.
- """
-
- include_platform_defaults: Optional[bool]
- """
- Whether Whop's platform default payment method enablement settings are included
- in this configuration. The full list of default payment methods can be found in
- the documentation at docs.whop.com/payments.
- """
+ include_platform_defaults: bool
diff --git a/src/whop_sdk/types/product_create_params.py b/src/whop_sdk/types/product_create_params.py
index 103fbc3d..29597ede 100644
--- a/src/whop_sdk/types/product_create_params.py
+++ b/src/whop_sdk/types/product_create_params.py
@@ -2,151 +2,60 @@
from __future__ import annotations
-from typing import Dict, Iterable, Optional
-from typing_extensions import Literal, Required, TypedDict
+from typing import Optional
+from typing_extensions import Required, TypedDict
-from .._types import SequenceNotStr
-from .shared.currency import Currency
-from .shared.plan_type import PlanType
-from .shared.custom_cta import CustomCta
-from .shared.visibility import Visibility
-from .shared.release_method import ReleaseMethod
-from .shared.global_affiliate_status import GlobalAffiliateStatus
-
-__all__ = ["ProductCreateParams", "PlanOptions", "PlanOptionsCustomField"]
+__all__ = ["ProductCreateParams"]
class ProductCreateParams(TypedDict, total=False):
- company_id: Required[str]
- """The unique identifier of the company to create this product for."""
-
title: Required[str]
"""The display name of the product. Maximum 80 characters."""
collect_shipping_address: Optional[bool]
- """Whether the checkout flow collects a shipping address from the customer."""
+ """Whether to collect a shipping address at checkout."""
+
+ company_id: str
+ """The unique identifier of the company to create this product for."""
- custom_cta: Optional[CustomCta]
- """The different types of custom CTAs that can be selected."""
+ custom_cta: Optional[str]
+ """The call-to-action button label."""
custom_cta_url: Optional[str]
- """
- A URL that the call-to-action button links to instead of the default checkout
- flow.
- """
+ """A URL the call-to-action button links to."""
custom_statement_descriptor: Optional[str]
- """A custom text label that appears on the customer's bank statement.
-
- Must be 5-22 characters, contain at least one letter, and not contain <, >, \\,,
- ', or " characters.
- """
+ """Custom bank statement descriptor. Must start with WHOP\\**."""
description: Optional[str]
- """A written description of the product displayed on its product page."""
-
- experience_ids: Optional[SequenceNotStr[str]]
- """The unique identifiers of experiences to connect to this product."""
+ """A written description displayed on the product page."""
global_affiliate_percentage: Optional[float]
- """
- The commission rate as a percentage that affiliates earn through the global
- affiliate program.
- """
+ """The commission rate affiliates earn."""
- global_affiliate_status: Optional[GlobalAffiliateStatus]
- """The different statuses of the global affiliate program for a product."""
+ global_affiliate_status: str
+ """The enrollment status in the global affiliate program."""
headline: Optional[str]
- """A short marketing headline displayed prominently on the product page."""
+ """A short marketing headline for the product page."""
member_affiliate_percentage: Optional[float]
- """
- The commission rate as a percentage that members earn through the member
- affiliate program.
- """
-
- member_affiliate_status: Optional[GlobalAffiliateStatus]
- """The different statuses of the global affiliate program for a product."""
+ """The commission rate members earn."""
- metadata: Optional[Dict[str, object]]
- """Custom key-value pairs to store on the product.
+ member_affiliate_status: str
+ """The enrollment status in the member affiliate program."""
- Included in webhook payloads for payment and membership events. Max 50 keys, 500
- chars per key, 5000 chars per value.
- """
-
- plan_options: Optional[PlanOptions]
- """Configuration for an automatically generated plan to attach to this product."""
+ metadata: Optional[object]
+ """Custom key-value pairs to store on the product."""
product_tax_code_id: Optional[str]
- """The unique identifier of the tax classification code to apply to this product."""
+ """The unique identifier of the tax classification code."""
redirect_purchase_url: Optional[str]
- """A URL to redirect the customer to after completing a purchase."""
+ """A URL to redirect the customer to after purchase."""
route: Optional[str]
"""The URL slug for the product's public link."""
- send_welcome_message: Optional[bool]
- """
- Whether to send an automated welcome message via support chat when a user joins
- this product. Defaults to true.
- """
-
- visibility: Optional[Visibility]
- """Visibility of a resource"""
-
-
-class PlanOptionsCustomField(TypedDict, total=False):
- field_type: Required[Literal["text"]]
- """The type of the custom field."""
-
- name: Required[str]
- """The name of the custom field."""
-
- id: Optional[str]
- """The ID of the custom field (if being updated)"""
-
- order: Optional[int]
- """The order of the field."""
-
- placeholder: Optional[str]
- """The placeholder value of the field."""
-
- required: Optional[bool]
- """Whether or not the field is required."""
-
-
-class PlanOptions(TypedDict, total=False):
- """Configuration for an automatically generated plan to attach to this product."""
-
- base_currency: Optional[Currency]
- """The available currencies on the platform"""
-
- billing_period: Optional[int]
- """The interval at which the plan charges (renewal plans)."""
-
- custom_fields: Optional[Iterable[PlanOptionsCustomField]]
- """An array of custom field objects."""
-
- initial_price: Optional[float]
- """An additional amount charged upon first purchase.
-
- Provided as a number in the specified currency. Eg: 10.43 for $10.43 USD.
- """
-
- plan_type: Optional[PlanType]
- """The type of plan that can be attached to a product"""
-
- release_method: Optional[ReleaseMethod]
- """The methods of how a plan can be released."""
-
- renewal_price: Optional[float]
- """The amount the customer is charged every billing period.
-
- Provided as a number in the specified currency. Eg: 10.43 for $10.43 USD.
- """
-
- visibility: Optional[Visibility]
- """Visibility of a resource"""
+ visibility: str
+ """Whether the product is visible to customers."""
diff --git a/src/whop_sdk/types/product_list_params.py b/src/whop_sdk/types/product_list_params.py
index 47862a61..5b666c38 100644
--- a/src/whop_sdk/types/product_list_params.py
+++ b/src/whop_sdk/types/product_list_params.py
@@ -2,14 +2,9 @@
from __future__ import annotations
-from typing import List, Union, Optional
-from datetime import datetime
-from typing_extensions import Literal, Required, Annotated, TypedDict
+from typing_extensions import Literal, Required, TypedDict
-from .._utils import PropertyInfo
-from .shared.direction import Direction
-from .shared.access_pass_type import AccessPassType
-from .shared.visibility_filter import VisibilityFilter
+from .._types import SequenceNotStr
__all__ = ["ProductListParams"]
@@ -18,32 +13,26 @@ class ProductListParams(TypedDict, total=False):
company_id: Required[str]
"""The unique identifier of the company to list products for."""
- after: Optional[str]
- """Returns the elements in the list that come after the specified cursor."""
+ access_pass_types: SequenceNotStr[str]
+ """Filter to only products matching these types."""
- before: Optional[str]
- """Returns the elements in the list that come before the specified cursor."""
+ after: str
+ """A cursor; returns products after this position."""
- created_after: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """Only return products created after this timestamp."""
+ before: str
+ """A cursor; returns products before this position."""
- created_before: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """Only return products created before this timestamp."""
+ direction: Literal["asc", "desc"]
+ """The sort direction for results. Defaults to descending."""
- direction: Optional[Direction]
- """The direction of the sort."""
+ first: int
+ """The number of products to return (default and max 100)."""
- first: Optional[int]
- """Returns the first _n_ elements from the list."""
+ last: int
+ """The number of products to return from the end of the range."""
- last: Optional[int]
- """Returns the last _n_ elements from the list."""
+ order: str
+ """The field to sort results by. Defaults to created_at."""
- order: Optional[Literal["active_memberships_count", "created_at", "usd_gmv", "usd_gmv_30_days"]]
- """The ways a relation of AccessPasses can be ordered"""
-
- product_types: Optional[List[AccessPassType]]
- """Filter to only products matching these type classifications."""
-
- visibilities: Optional[List[VisibilityFilter]]
+ visibilities: SequenceNotStr[str]
"""Filter to only products matching these visibility states."""
diff --git a/src/whop_sdk/types/product_update_params.py b/src/whop_sdk/types/product_update_params.py
index 64a7c8c1..67e3748f 100644
--- a/src/whop_sdk/types/product_update_params.py
+++ b/src/whop_sdk/types/product_update_params.py
@@ -2,107 +2,27 @@
from __future__ import annotations
-from typing import Dict, Iterable, Optional
-from typing_extensions import Required, TypedDict
+from typing import Optional
+from typing_extensions import TypedDict
-from .shared.custom_cta import CustomCta
-from .shared.visibility import Visibility
-from .shared.global_affiliate_status import GlobalAffiliateStatus
-
-__all__ = ["ProductUpdateParams", "GalleryImage", "StorePageConfig"]
+__all__ = ["ProductUpdateParams"]
class ProductUpdateParams(TypedDict, total=False):
- collect_shipping_address: Optional[bool]
- """Whether the checkout flow collects a shipping address from the customer."""
-
- custom_cta: Optional[CustomCta]
- """The different types of custom CTAs that can be selected."""
-
- custom_cta_url: Optional[str]
- """
- A URL that the call-to-action button links to instead of the default checkout
- flow.
- """
-
- custom_statement_descriptor: Optional[str]
- """A custom text label that appears on the customer's bank statement.
-
- Must be 5-22 characters, contain at least one letter, and not contain <, >, \\,,
- ', or " characters.
- """
-
description: Optional[str]
- """A written description of the product displayed on its product page."""
-
- gallery_images: Optional[Iterable[GalleryImage]]
- """The gallery images for the product."""
-
- global_affiliate_percentage: Optional[float]
- """
- The commission rate as a percentage that affiliates earn through the global
- affiliate program.
- """
-
- global_affiliate_status: Optional[GlobalAffiliateStatus]
- """The different statuses of the global affiliate program for a product."""
+ """A written description displayed on the product page."""
headline: Optional[str]
- """A short marketing headline displayed prominently on the product page."""
-
- member_affiliate_percentage: Optional[float]
- """
- The commission rate as a percentage that members earn through the member
- affiliate program.
- """
-
- member_affiliate_status: Optional[GlobalAffiliateStatus]
- """The different statuses of the global affiliate program for a product."""
-
- metadata: Optional[Dict[str, object]]
- """Custom key-value pairs to store on the product.
+ """A short marketing headline for the product page."""
- Included in webhook payloads for payment and membership events. Max 50 keys, 500
- chars per key, 5000 chars per value.
- """
+ metadata: Optional[object]
+ """Custom key-value pairs to store on the product."""
product_tax_code_id: Optional[str]
- """The unique identifier of the tax classification code to apply to this product."""
-
- redirect_purchase_url: Optional[str]
- """A URL to redirect the customer to after completing a purchase."""
-
- route: Optional[str]
- """The URL slug for the product's public link."""
-
- send_welcome_message: Optional[bool]
- """
- Whether to send an automated welcome message via support chat when a user joins
- this product.
- """
-
- store_page_config: Optional[StorePageConfig]
- """Layout and display configuration for this product on the company's store page."""
-
- title: Optional[str]
- """The display name of the product. Maximum 80 characters."""
-
- visibility: Optional[Visibility]
- """Visibility of a resource"""
-
-
-class GalleryImage(TypedDict, total=False):
- """Input for an attachment"""
-
- id: Required[str]
- """The ID of an existing file object."""
-
-
-class StorePageConfig(TypedDict, total=False):
- """Layout and display configuration for this product on the company's store page."""
+ """The unique identifier of the tax classification code."""
- custom_cta: Optional[str]
- """Custom call-to-action text for the product's store page."""
+ title: str
+ """The display name of the product."""
- show_price: Optional[bool]
- """Whether or not to show the price on the product's store page."""
+ visibility: str
+ """Whether the product is visible to customers."""
diff --git a/src/whop_sdk/types/referrals/__init__.py b/src/whop_sdk/types/referrals/__init__.py
new file mode 100644
index 00000000..8900c156
--- /dev/null
+++ b/src/whop_sdk/types/referrals/__init__.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .business_list_params import BusinessListParams as BusinessListParams
+from .business_list_response import BusinessListResponse as BusinessListResponse
+from .business_retrieve_response import BusinessRetrieveResponse as BusinessRetrieveResponse
+from .business_list_earnings_params import BusinessListEarningsParams as BusinessListEarningsParams
+from .business_list_earnings_response import BusinessListEarningsResponse as BusinessListEarningsResponse
diff --git a/src/whop_sdk/types/referrals/business_list_earnings_params.py b/src/whop_sdk/types/referrals/business_list_earnings_params.py
new file mode 100644
index 00000000..23a618a9
--- /dev/null
+++ b/src/whop_sdk/types/referrals/business_list_earnings_params.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypedDict
+
+__all__ = ["BusinessListEarningsParams"]
+
+
+class BusinessListEarningsParams(TypedDict, total=False):
+ after: str
+
+ before: str
+
+ direction: Literal["asc", "desc"]
+ """Sort direction."""
+
+ first: int
+
+ last: int
+
+ order: Literal["created_at", "commission_amount", "transaction_amount", "payout_at"]
+ """The field to sort earnings by."""
+
+ status: Literal["awaiting_settlement", "pending", "completed", "canceled", "reversed"]
+ """Filter by earning status."""
diff --git a/src/whop_sdk/types/referrals/business_list_earnings_response.py b/src/whop_sdk/types/referrals/business_list_earnings_response.py
new file mode 100644
index 00000000..fec44b78
--- /dev/null
+++ b/src/whop_sdk/types/referrals/business_list_earnings_response.py
@@ -0,0 +1,97 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BusinessListEarningsResponse", "Account", "Product", "Resource", "ResourceAlternativePaymentMethod"]
+
+
+class Account(BaseModel):
+ """Referred account."""
+
+ id: str
+ """Referred account ID."""
+
+ logo_url: Optional[str] = None
+ """Referred account logo URL."""
+
+ route: str
+ """Referred account route."""
+
+ title: str
+ """Referred account display name."""
+
+
+class Product(BaseModel):
+ id: str
+
+ route: str
+
+ title: str
+
+
+class ResourceAlternativePaymentMethod(BaseModel):
+ image_url: Optional[str] = None
+
+ name: str
+
+
+class Resource(BaseModel):
+ """The resource that generated the affiliate earning."""
+
+ id: str
+
+ alternative_payment_method: Optional[ResourceAlternativePaymentMethod] = None
+
+ brand: Optional[str] = None
+
+ created_at: datetime
+
+ currency: str
+
+ last4: Optional[str] = None
+
+ object: Literal["receipt"]
+
+ payment_method_type: Optional[str] = None
+
+ processor: Optional[str] = None
+
+
+class BusinessListEarningsResponse(BaseModel):
+ id: Optional[str] = None
+
+ account: Optional[Account] = None
+ """Referred account."""
+
+ cancelation_reason: Optional[str] = None
+ """Why the earning was canceled or reversed, if applicable."""
+
+ commission_amount_usd: Optional[str] = None
+ """What the referrer earns, in USD. Null until the earning settles."""
+
+ created_at: datetime
+
+ object: Literal["business_referral_earning"]
+
+ payout_at: Optional[datetime] = None
+
+ payout_percentage: Optional[float] = None
+ """The referrer's share of Whop's gross profit, as a fraction (0.3 = 30%).
+
+ Null until the earning settles.
+ """
+
+ product: Optional[Product] = None
+
+ resource: Optional[Resource] = None
+ """The resource that generated the affiliate earning."""
+
+ status: Literal["awaiting_settlement", "pending", "completed", "canceled", "reversed"]
+ """Current status of the earning."""
+
+ transaction_amount_usd: str
+ """The sale amount the commission is calculated from, in USD."""
diff --git a/src/whop_sdk/types/referrals/business_list_params.py b/src/whop_sdk/types/referrals/business_list_params.py
new file mode 100644
index 00000000..e471a3d3
--- /dev/null
+++ b/src/whop_sdk/types/referrals/business_list_params.py
@@ -0,0 +1,38 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypedDict
+
+__all__ = ["BusinessListParams"]
+
+
+class BusinessListParams(TypedDict, total=False):
+ after: str
+ """Cursor to fetch the page after (from page_info.end_cursor)."""
+
+ before: str
+ """Cursor to fetch the page before (from page_info.start_cursor)."""
+
+ direction: Literal["asc", "desc"]
+ """Sort direction."""
+
+ first: int
+ """Number of business referrals to return from the start of the window."""
+
+ has_earnings: bool
+ """
+ When true, only businesses with at least one non-canceled, non-reversed earning
+ paid to the caller.
+ """
+
+ last: int
+ """Number of business referrals to return from the end of the window."""
+
+ order: Literal[
+ "created_at", "referral_started_at", "referral_expires_at", "payout_percentage", "volume_usd", "earnings_usd"
+ ]
+ """The field to sort business referrals by."""
+
+ status: Literal["active", "removed"]
+ """Filter by referral status."""
diff --git a/src/whop_sdk/types/referrals/business_list_response.py b/src/whop_sdk/types/referrals/business_list_response.py
new file mode 100644
index 00000000..b6346b1b
--- /dev/null
+++ b/src/whop_sdk/types/referrals/business_list_response.py
@@ -0,0 +1,105 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BusinessListResponse", "Account", "EarningsUsd", "User", "UserProfilePicture", "VolumeUsd"]
+
+
+class Account(BaseModel):
+ """Referred account."""
+
+ id: str
+ """Referred account ID."""
+
+ logo_url: Optional[str] = None
+ """Referred account logo URL."""
+
+ route: str
+ """Referred account route."""
+
+ title: str
+ """Referred account display name."""
+
+
+class EarningsUsd(BaseModel):
+ completed: str
+ """Commission already paid out, in USD."""
+
+ pending: str
+ """Commission scheduled but not yet paid, in USD."""
+
+ total: str
+ """Pending + completed commission, in USD."""
+
+
+class UserProfilePicture(BaseModel):
+ """The user's profile picture."""
+
+ url: str
+ """The user's profile picture URL."""
+
+
+class User(BaseModel):
+ """Owner of the referred account."""
+
+ id: str
+ """User ID, prefixed `user_`."""
+
+ name: Optional[str] = None
+ """The user's display name."""
+
+ profile_picture: UserProfilePicture
+ """The user's profile picture."""
+
+ username: str
+ """The user's unique username."""
+
+
+class VolumeUsd(BaseModel):
+ attributed: str
+ """
+ Credited GMV (awaiting_settlement + settled); excludes canceled and reversed, in
+ USD.
+ """
+
+ awaiting_settlement: str
+ """GMV awaiting settlement (commission not yet computed), in USD."""
+
+ settled: str
+ """GMV of pending + completed payments, in USD."""
+
+
+class BusinessListResponse(BaseModel):
+ id: str
+ """Business referral ID."""
+
+ account: Optional[Account] = None
+ """Referred account."""
+
+ created_at: datetime
+ """When the business referral was created."""
+
+ earnings_usd: EarningsUsd
+
+ object: Literal["business_referral"]
+
+ payout_percentage: float
+ """Referrer's share of Whop gross profit, as a fraction (0.3 = 30%)."""
+
+ referral_expires_at: Optional[datetime] = None
+ """When the referral expires."""
+
+ referral_started_at: Optional[datetime] = None
+ """When the referral became active."""
+
+ status: Literal["active", "removed"]
+ """Current referral status."""
+
+ user: Optional[User] = None
+ """Owner of the referred account."""
+
+ volume_usd: VolumeUsd
diff --git a/src/whop_sdk/types/referrals/business_retrieve_response.py b/src/whop_sdk/types/referrals/business_retrieve_response.py
new file mode 100644
index 00000000..004bd319
--- /dev/null
+++ b/src/whop_sdk/types/referrals/business_retrieve_response.py
@@ -0,0 +1,214 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = [
+ "BusinessRetrieveResponse",
+ "Account",
+ "AccountCapabilities",
+ "AccountRecommendedAction",
+ "AccountRequiredAction",
+ "EarningsUsd",
+ "User",
+ "UserProfilePicture",
+ "VolumeUsd",
+]
+
+
+class AccountCapabilities(BaseModel):
+ accept_bank_payments: Literal["active", "inactive", "pending"]
+ """Bank payins: debits, transfers, and local bank rails"""
+
+ accept_bnpl_payments: Literal["active", "inactive", "pending"]
+ """Buy-now-pay-later payins; requires approval"""
+
+ accept_card_payments: Literal["active", "inactive", "pending"]
+ """Card payins, including Apple Pay and Google Pay"""
+
+ bank_deposit: Literal["active", "inactive", "pending"]
+ """Deposits by bank wire or ACH to the account's virtual bank account"""
+
+ card_deposit: Literal["active", "inactive", "pending"]
+ """Balance top-ups by charging a stored payment method"""
+
+ card_issuing: Literal["active", "inactive", "pending"]
+ """Issuing Whop cards; requires card application approval"""
+
+ crypto_deposit: Literal["active", "inactive", "pending"]
+ """On-chain deposits to the account's crypto wallet"""
+
+ crypto_payout: Literal["active", "inactive", "pending"]
+ """On-chain payouts to a crypto wallet"""
+
+ instant_payout: Literal["active", "inactive", "pending"]
+ """Instant payouts to an eligible payout destination"""
+
+ standard_payout: Literal["active", "inactive", "pending"]
+ """Standard payouts to an external payout destination"""
+
+ transfer: Literal["active", "inactive", "pending"]
+ """Transfers to other accounts"""
+
+
+class AccountRecommendedAction(BaseModel):
+ action: Literal["apply_for_financing", "migrate_from_stripe", "accept_first_payment", "join_whop_university"]
+ """
+ The recommendation; new values may be added, so handle unknown actions
+ gracefully
+ """
+
+ blocked_capabilities: List[str]
+
+ cta: str
+ """The URL the call-to-action links to"""
+
+ cta_label: str
+ """Button label"""
+
+ description: str
+ """Supporting copy, or empty"""
+
+ icon_url: Optional[str] = None
+ """Illustration icon URL, or `null`"""
+
+ status: Literal["optional"]
+ """Always optional — never blocking"""
+
+ title: str
+ """Headline for the recommendation"""
+
+
+class AccountRequiredAction(BaseModel):
+ action: Literal["deposit_funds", "submit_information_request", "verify_identity", "connect_fulfillment_tracker"]
+ """
+ What the holder must do; new values may be added, so handle unknown actions
+ gracefully
+ """
+
+ blocked_capabilities: List[str]
+
+ cta: Optional[str] = None
+ """The URL the call-to-action links to, or null when there is no button"""
+
+ cta_label: str
+ """Button label, or empty when there is no button"""
+
+ description: str
+ """Supporting copy, or empty"""
+
+ icon_url: Optional[str] = None
+ """The URL of the action's illustration icon, or null if it has none"""
+
+ status: Literal["required", "pending"]
+ """required (act now) or pending (under review)"""
+
+ title: str
+ """Headline for the action"""
+
+
+class Account(BaseModel):
+ """Referred account."""
+
+ id: str
+ """Referred account ID."""
+
+ capabilities: Optional[AccountCapabilities] = None
+
+ logo_url: Optional[str] = None
+ """Referred account logo URL."""
+
+ recommended_actions: Optional[List[AccountRecommendedAction]] = None
+ """Optional actions that unlock capabilities or grow the referred account."""
+
+ required_actions: Optional[List[AccountRequiredAction]] = None
+ """Actions the referred account owner must take to unblock capabilities."""
+
+ route: str
+ """Referred account route."""
+
+ title: str
+ """Referred account display name."""
+
+
+class EarningsUsd(BaseModel):
+ completed: str
+ """Commission already paid out, in USD."""
+
+ pending: str
+ """Commission scheduled but not yet paid, in USD."""
+
+ total: str
+ """Pending + completed commission, in USD."""
+
+
+class UserProfilePicture(BaseModel):
+ """The user's profile picture."""
+
+ url: str
+ """The user's profile picture URL."""
+
+
+class User(BaseModel):
+ """Owner of the referred account."""
+
+ id: str
+ """User ID, prefixed `user_`."""
+
+ name: Optional[str] = None
+ """The user's display name."""
+
+ profile_picture: UserProfilePicture
+ """The user's profile picture."""
+
+ username: str
+ """The user's unique username."""
+
+
+class VolumeUsd(BaseModel):
+ attributed: str
+ """
+ Credited GMV (awaiting_settlement + settled); excludes canceled and reversed, in
+ USD.
+ """
+
+ awaiting_settlement: str
+ """GMV awaiting settlement (commission not yet computed), in USD."""
+
+ settled: str
+ """GMV of pending + completed payments, in USD."""
+
+
+class BusinessRetrieveResponse(BaseModel):
+ id: str
+ """Business referral ID."""
+
+ account: Optional[Account] = None
+ """Referred account."""
+
+ created_at: datetime
+ """When the business referral was created."""
+
+ earnings_usd: EarningsUsd
+
+ object: Literal["business_referral"]
+
+ payout_percentage: float
+ """Referrer's share of Whop gross profit, as a fraction (0.3 = 30%)."""
+
+ referral_expires_at: Optional[datetime] = None
+ """When the referral expires."""
+
+ referral_started_at: Optional[datetime] = None
+ """When the referral became active."""
+
+ status: Literal["active", "removed"]
+ """Current referral status."""
+
+ user: Optional[User] = None
+ """Owner of the referred account."""
+
+ volume_usd: VolumeUsd
diff --git a/src/whop_sdk/types/referrals/businesses/__init__.py b/src/whop_sdk/types/referrals/businesses/__init__.py
new file mode 100644
index 00000000..dc2fac39
--- /dev/null
+++ b/src/whop_sdk/types/referrals/businesses/__init__.py
@@ -0,0 +1,6 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .earning_list_params import EarningListParams as EarningListParams
+from .earning_list_response import EarningListResponse as EarningListResponse
diff --git a/src/whop_sdk/types/referrals/businesses/earning_list_params.py b/src/whop_sdk/types/referrals/businesses/earning_list_params.py
new file mode 100644
index 00000000..7992c51c
--- /dev/null
+++ b/src/whop_sdk/types/referrals/businesses/earning_list_params.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypedDict
+
+__all__ = ["EarningListParams"]
+
+
+class EarningListParams(TypedDict, total=False):
+ after: str
+
+ before: str
+
+ direction: Literal["asc", "desc"]
+ """Sort direction."""
+
+ first: int
+
+ last: int
+
+ order: Literal["created_at", "commission_amount", "transaction_amount", "payout_at"]
+ """The field to sort earnings by."""
+
+ status: Literal["awaiting_settlement", "pending", "completed", "canceled", "reversed"]
+ """Filter by earning status."""
diff --git a/src/whop_sdk/types/referrals/businesses/earning_list_response.py b/src/whop_sdk/types/referrals/businesses/earning_list_response.py
new file mode 100644
index 00000000..8ee59e51
--- /dev/null
+++ b/src/whop_sdk/types/referrals/businesses/earning_list_response.py
@@ -0,0 +1,97 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from ...._models import BaseModel
+
+__all__ = ["EarningListResponse", "Account", "Product", "Resource", "ResourceAlternativePaymentMethod"]
+
+
+class Account(BaseModel):
+ """Referred account."""
+
+ id: str
+ """Referred account ID."""
+
+ logo_url: Optional[str] = None
+ """Referred account logo URL."""
+
+ route: str
+ """Referred account route."""
+
+ title: str
+ """Referred account display name."""
+
+
+class Product(BaseModel):
+ id: str
+
+ route: str
+
+ title: str
+
+
+class ResourceAlternativePaymentMethod(BaseModel):
+ image_url: Optional[str] = None
+
+ name: str
+
+
+class Resource(BaseModel):
+ """The resource that generated the affiliate earning."""
+
+ id: str
+
+ alternative_payment_method: Optional[ResourceAlternativePaymentMethod] = None
+
+ brand: Optional[str] = None
+
+ created_at: datetime
+
+ currency: str
+
+ last4: Optional[str] = None
+
+ object: Literal["receipt"]
+
+ payment_method_type: Optional[str] = None
+
+ processor: Optional[str] = None
+
+
+class EarningListResponse(BaseModel):
+ id: Optional[str] = None
+
+ account: Optional[Account] = None
+ """Referred account."""
+
+ cancelation_reason: Optional[str] = None
+ """Why the earning was canceled or reversed, if applicable."""
+
+ commission_amount_usd: Optional[str] = None
+ """What the referrer earns, in USD. Null until the earning settles."""
+
+ created_at: datetime
+
+ object: Literal["business_referral_earning"]
+
+ payout_at: Optional[datetime] = None
+
+ payout_percentage: Optional[float] = None
+ """The referrer's share of Whop's gross profit, as a fraction (0.3 = 30%).
+
+ Null until the earning settles.
+ """
+
+ product: Optional[Product] = None
+
+ resource: Optional[Resource] = None
+ """The resource that generated the affiliate earning."""
+
+ status: Literal["awaiting_settlement", "pending", "completed", "canceled", "reversed"]
+ """Current status of the earning."""
+
+ transaction_amount_usd: str
+ """The sale amount the commission is calculated from, in USD."""
diff --git a/src/whop_sdk/types/refund_created_webhook_event.py b/src/whop_sdk/types/refund_created_webhook_event.py
index 611640f0..6ab91ee2 100644
--- a/src/whop_sdk/types/refund_created_webhook_event.py
+++ b/src/whop_sdk/types/refund_created_webhook_event.py
@@ -57,7 +57,8 @@ class DataPaymentPlan(BaseModel):
metadata: Optional[Dict[str, object]] = None
"""Custom key-value pairs stored on the plan.
- Included in webhook payloads for payment and membership events.
+ Included in webhook payloads for payment and membership events. Max 50 keys, 100
+ chars per key, 500 chars per string value.
"""
@@ -68,9 +69,10 @@ class DataPaymentProduct(BaseModel):
"""The unique identifier for the product."""
metadata: Optional[Dict[str, object]] = None
- """Custom key-value pairs stored on the product.
-
- Included in webhook payloads for payment and membership events.
+ """
+ Custom key-value pairs stored on the product and included in payment and
+ membership webhook payloads. Max 50 keys, 100 characters per key, 500 characters
+ per string value.
"""
diff --git a/src/whop_sdk/types/refund_retrieve_response.py b/src/whop_sdk/types/refund_retrieve_response.py
index e1f0ad14..94976ead 100644
--- a/src/whop_sdk/types/refund_retrieve_response.py
+++ b/src/whop_sdk/types/refund_retrieve_response.py
@@ -55,7 +55,8 @@ class PaymentPlan(BaseModel):
metadata: Optional[Dict[str, object]] = None
"""Custom key-value pairs stored on the plan.
- Included in webhook payloads for payment and membership events.
+ Included in webhook payloads for payment and membership events. Max 50 keys, 100
+ chars per key, 500 chars per string value.
"""
@@ -66,9 +67,10 @@ class PaymentProduct(BaseModel):
"""The unique identifier for the product."""
metadata: Optional[Dict[str, object]] = None
- """Custom key-value pairs stored on the product.
-
- Included in webhook payloads for payment and membership events.
+ """
+ Custom key-value pairs stored on the product and included in payment and
+ membership webhook payloads. Max 50 keys, 100 characters per key, 500 characters
+ per string value.
"""
diff --git a/src/whop_sdk/types/refund_updated_webhook_event.py b/src/whop_sdk/types/refund_updated_webhook_event.py
index 9fbd5a1a..27591ce0 100644
--- a/src/whop_sdk/types/refund_updated_webhook_event.py
+++ b/src/whop_sdk/types/refund_updated_webhook_event.py
@@ -57,7 +57,8 @@ class DataPaymentPlan(BaseModel):
metadata: Optional[Dict[str, object]] = None
"""Custom key-value pairs stored on the plan.
- Included in webhook payloads for payment and membership events.
+ Included in webhook payloads for payment and membership events. Max 50 keys, 100
+ chars per key, 500 chars per string value.
"""
@@ -68,9 +69,10 @@ class DataPaymentProduct(BaseModel):
"""The unique identifier for the product."""
metadata: Optional[Dict[str, object]] = None
- """Custom key-value pairs stored on the product.
-
- Included in webhook payloads for payment and membership events.
+ """
+ Custom key-value pairs stored on the product and included in payment and
+ membership webhook payloads. Max 50 keys, 100 characters per key, 500 characters
+ per string value.
"""
diff --git a/src/whop_sdk/types/review_list_response.py b/src/whop_sdk/types/review_list_response.py
index 5a670355..8627ff8d 100644
--- a/src/whop_sdk/types/review_list_response.py
+++ b/src/whop_sdk/types/review_list_response.py
@@ -23,7 +23,7 @@ class Attachment(BaseModel):
"""
content_type: Optional[str] = None
- """The MIME type of the uploaded file (e.g., image/jpeg, video/mp4, audio/mpeg)."""
+ """Uploaded file MIME type, such as image/jpeg, video/mp4, or audio/mpeg."""
filename: Optional[str] = None
"""The original filename of the uploaded attachment, including its file extension."""
diff --git a/src/whop_sdk/types/review_retrieve_response.py b/src/whop_sdk/types/review_retrieve_response.py
index bd1157f7..3f6b93fa 100644
--- a/src/whop_sdk/types/review_retrieve_response.py
+++ b/src/whop_sdk/types/review_retrieve_response.py
@@ -23,7 +23,7 @@ class Attachment(BaseModel):
"""
content_type: Optional[str] = None
- """The MIME type of the uploaded file (e.g., image/jpeg, video/mp4, audio/mpeg)."""
+ """Uploaded file MIME type, such as image/jpeg, video/mp4, or audio/mpeg."""
filename: Optional[str] = None
"""The original filename of the uploaded attachment, including its file extension."""
@@ -42,9 +42,7 @@ class Company(BaseModel):
"""The unique identifier for the company."""
route: str
- """
- The URL slug for the company's store page (e.g., 'pickaxe' in whop.com/pickaxe).
- """
+ """URL slug for the account's store page, e.g. `pickaxe` in whop.com/pickaxe."""
title: str
"""The display name of the company shown to customers."""
diff --git a/src/whop_sdk/types/setup_intent.py b/src/whop_sdk/types/setup_intent.py
index a79a2b76..5f3f67b4 100644
--- a/src/whop_sdk/types/setup_intent.py
+++ b/src/whop_sdk/types/setup_intent.py
@@ -188,3 +188,9 @@ class SetupIntent(BaseModel):
status: SetupIntentStatus
"""The current status of the setup intent."""
+
+ three_ds_verified: bool
+ """
+ Whether 3D Secure authentication was completed when this payment method was set
+ up.
+ """
diff --git a/src/whop_sdk/types/shared/__init__.py b/src/whop_sdk/types/shared/__init__.py
index b1c4a467..249442f1 100644
--- a/src/whop_sdk/types/shared/__init__.py
+++ b/src/whop_sdk/types/shared/__init__.py
@@ -13,7 +13,6 @@
from .reaction import Reaction as Reaction
from .shipment import Shipment as Shipment
from .tax_type import TaxType as TaxType
-from .transfer import Transfer as Transfer
from .app_build import AppBuild as AppBuild
from .direction import Direction as Direction
from .page_info import PageInfo as PageInfo
diff --git a/src/whop_sdk/types/shared/checkout_configuration.py b/src/whop_sdk/types/shared/checkout_configuration.py
index d21bcd8f..6aadc59d 100644
--- a/src/whop_sdk/types/shared/checkout_configuration.py
+++ b/src/whop_sdk/types/shared/checkout_configuration.py
@@ -55,9 +55,9 @@ class Plan(BaseModel):
"""
billing_period: Optional[int] = None
- """The number of days between each recurring charge.
-
- Null for one-time plans. For example, 30 for monthly or 365 for annual billing.
+ """
+ Number of days between recurring charges, such as 30 for monthly or 365 for
+ annual. `null` for one-time plans.
"""
currency: Currency
@@ -67,9 +67,9 @@ class Plan(BaseModel):
"""
expiration_days: Optional[int] = None
- """The number of days until the membership expires (for expiration-based plans).
-
- For example, 365 for a one-year access pass.
+ """
+ Access duration in days for expiration-based plans, such as 365 for a one-year
+ pass.
"""
initial_price: float
@@ -87,8 +87,8 @@ class Plan(BaseModel):
release_method: ReleaseMethod
"""
- The method used to sell this plan: 'buy_now' for immediate purchase or
- 'waitlist' for waitlist-based access.
+ Sales method for this plan: `buy_now` for immediate purchase or `waitlist` for
+ waitlist-based access.
"""
renewal_price: float
@@ -101,10 +101,10 @@ class Plan(BaseModel):
"""The 3D Secure behavior for a plan."""
trial_period_days: Optional[int] = None
- """The number of free trial days before the first charge on a renewal plan.
+ """Free trial days before first renewal charge.
- Null if no trial is configured or the current user has already used a trial for
- this plan.
+ `null` if no trial is configured or the user has already used a trial for this
+ plan.
"""
visibility: Visibility
@@ -125,12 +125,6 @@ class CheckoutConfiguration(BaseModel):
affiliate_code: Optional[str] = None
"""The affiliate code to use for the checkout configuration"""
- allow_promo_codes: bool
- """Whether the checkout configuration allows promo codes.
-
- When false, the promo code input is hidden and promo codes are rejected.
- """
-
company_id: str
"""The ID of the company to use for the checkout configuration"""
diff --git a/src/whop_sdk/types/shared/company.py b/src/whop_sdk/types/shared/company.py
index 764ef992..a95e9086 100644
--- a/src/whop_sdk/types/shared/company.py
+++ b/src/whop_sdk/types/shared/company.py
@@ -113,9 +113,7 @@ class Company(BaseModel):
"""
route: str
- """
- The URL slug for the company's store page (e.g., 'pickaxe' in whop.com/pickaxe).
- """
+ """URL slug for the account's store page, e.g. `pickaxe` in whop.com/pickaxe."""
send_customer_emails: bool
"""
diff --git a/src/whop_sdk/types/shared/experience.py b/src/whop_sdk/types/shared/experience.py
index c6241f91..50a1951f 100644
--- a/src/whop_sdk/types/shared/experience.py
+++ b/src/whop_sdk/types/shared/experience.py
@@ -47,9 +47,7 @@ class Company(BaseModel):
"""The unique identifier for the company."""
route: str
- """
- The URL slug for the company's store page (e.g., 'pickaxe' in whop.com/pickaxe).
- """
+ """URL slug for the account's store page, e.g. `pickaxe` in whop.com/pickaxe."""
title: str
"""The display name of the company shown to customers."""
@@ -78,9 +76,9 @@ class Product(BaseModel):
"""The unique identifier for the product."""
route: str
- """
- The URL slug used in the product's public link (e.g., 'my-product' in
- whop.com/company/my-product).
+ """URL slug in the product's public link, e.g.
+
+ `pickaxe-analytics` in whop.com/company/pickaxe-analytics.
"""
title: str
diff --git a/src/whop_sdk/types/shared/forum_post.py b/src/whop_sdk/types/shared/forum_post.py
index 7a6136d7..1bcccfe7 100644
--- a/src/whop_sdk/types/shared/forum_post.py
+++ b/src/whop_sdk/types/shared/forum_post.py
@@ -22,7 +22,7 @@ class Attachment(BaseModel):
"""
content_type: Optional[str] = None
- """The MIME type of the uploaded file (e.g., image/jpeg, video/mp4, audio/mpeg)."""
+ """Uploaded file MIME type, such as image/jpeg, video/mp4, or audio/mpeg."""
filename: Optional[str] = None
"""The original filename of the uploaded attachment, including its file extension."""
diff --git a/src/whop_sdk/types/shared/membership.py b/src/whop_sdk/types/shared/membership.py
index 4f8d3fd0..41057e14 100644
--- a/src/whop_sdk/types/shared/membership.py
+++ b/src/whop_sdk/types/shared/membership.py
@@ -53,7 +53,8 @@ class Plan(BaseModel):
metadata: Optional[Dict[str, object]] = None
"""Custom key-value pairs stored on the plan.
- Included in webhook payloads for payment and membership events.
+ Included in webhook payloads for payment and membership events. Max 50 keys, 100
+ chars per key, 500 chars per string value.
"""
@@ -64,9 +65,10 @@ class Product(BaseModel):
"""The unique identifier for the product."""
metadata: Optional[Dict[str, object]] = None
- """Custom key-value pairs stored on the product.
-
- Included in webhook payloads for payment and membership events.
+ """
+ Custom key-value pairs stored on the product and included in payment and
+ membership webhook payloads. Max 50 keys, 100 characters per key, 500 characters
+ per string value.
"""
title: str
@@ -189,7 +191,7 @@ class Membership(BaseModel):
metadata: Optional[Dict[str, object]] = None
"""
Custom key-value pairs for the membership (commonly used for software licensing,
- e.g., HWID). Max 50 keys, 500 chars per key, 5000 chars per value.
+ e.g., HWID). Max 50 keys, 100 chars per key, 500 chars per string value.
"""
payment_collection_paused: bool
diff --git a/src/whop_sdk/types/shared/payment.py b/src/whop_sdk/types/shared/payment.py
index 3c262c6d..72cd5b3c 100644
--- a/src/whop_sdk/types/shared/payment.py
+++ b/src/whop_sdk/types/shared/payment.py
@@ -36,6 +36,7 @@
"Product",
"PromoCode",
"Resolution",
+ "ShippingAddress",
"User",
]
@@ -260,7 +261,8 @@ class Plan(BaseModel):
metadata: Optional[Dict[str, object]] = None
"""Custom key-value pairs stored on the plan.
- Included in webhook payloads for payment and membership events.
+ Included in webhook payloads for payment and membership events. Max 50 keys, 100
+ chars per key, 500 chars per string value.
"""
@@ -271,15 +273,16 @@ class Product(BaseModel):
"""The unique identifier for the product."""
metadata: Optional[Dict[str, object]] = None
- """Custom key-value pairs stored on the product.
-
- Included in webhook payloads for payment and membership events.
+ """
+ Custom key-value pairs stored on the product and included in payment and
+ membership webhook payloads. Max 50 keys, 100 characters per key, 500 characters
+ per string value.
"""
route: str
- """
- The URL slug used in the product's public link (e.g., 'my-product' in
- whop.com/company/my-product).
+ """URL slug in the product's public link, e.g.
+
+ `pickaxe-analytics` in whop.com/company/pickaxe-analytics.
"""
title: str
@@ -358,6 +361,34 @@ class Resolution(BaseModel):
"""
+class ShippingAddress(BaseModel):
+ """The shipping address provided by the customer for physical goods.
+
+ Null if no shipping address was collected.
+ """
+
+ 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 User(BaseModel):
"""The user that made this payment."""
@@ -521,6 +552,20 @@ class Payment(BaseModel):
otherwise false. Used to decide if Whop can attempt the charge again.
"""
+ risk_score: Optional[int] = None
+ """
+ Whop's in-house fraud risk score for this payment, from 0 (lowest risk) to 100
+ (highest risk). Null when the payment has not been scored or scoring has not yet
+ completed.
+ """
+
+ risk_signals: Optional[Dict[str, object]] = None
+ """
+ A curated set of factors behind the risk score, grouped by category (business
+ transaction history, buyer, device). Each entry has a key, human-readable label,
+ category, and value. Null when there is no risk assessment for this payment.
+ """
+
settlement_amount: float
"""
The total amount charged to the customer for this payment, including taxes and
@@ -533,6 +578,12 @@ class Payment(BaseModel):
settlement_exchange_rate: Optional[float] = None
"""Deprecated. Always returns null."""
+ shipping_address: Optional[ShippingAddress] = None
+ """The shipping address provided by the customer for physical goods.
+
+ Null if no shipping address was collected.
+ """
+
status: Optional[ReceiptStatus] = None
"""The status of a receipt"""
@@ -554,6 +605,9 @@ class Payment(BaseModel):
tax_refunded_amount: Optional[float] = None
"""The amount of tax that has been refunded (if applicable)."""
+ three_ds_verified: bool
+ """Whether 3D Secure authentication was completed for this payment."""
+
total: Optional[float] = None
"""The total to show to the creator (excluding buyer fees)."""
diff --git a/src/whop_sdk/types/shared/plan.py b/src/whop_sdk/types/shared/plan.py
index cf775d35..7fa371ff 100644
--- a/src/whop_sdk/types/shared/plan.py
+++ b/src/whop_sdk/types/shared/plan.py
@@ -1,281 +1,225 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Dict, List, Optional
-from datetime import datetime
+from typing import List, Optional
from typing_extensions import Literal
-from .currency import Currency
-from .tax_type import TaxType
from ..._models import BaseModel
-from .plan_type import PlanType
-from .visibility import Visibility
-from .release_method import ReleaseMethod
-from ..payment_method_types import PaymentMethodTypes
-__all__ = ["Plan", "Company", "CustomField", "Invoice", "PaymentMethodConfiguration", "Product"]
-
-
-class Company(BaseModel):
- """The company that sells this plan.
-
- Null for standalone invoice plans not linked to a company.
- """
-
- id: str
- """The unique identifier for the company."""
-
- title: str
- """The display name of the company shown to customers."""
+__all__ = ["Plan", "CustomField"]
class CustomField(BaseModel):
- """An object representing a custom field for a plan."""
+ """Custom input fields collected on the checkout form."""
id: str
- """The unique identifier for the custom field."""
+ """Custom field ID."""
field_type: Literal["text"]
- """What type of input field to use."""
+ """Custom field input type."""
name: str
- """The title/header of the custom field."""
+ """Field label shown to customer at checkout."""
- order: Optional[int] = None
- """How the custom field should be ordered when rendered on the checkout page."""
+ order: float
+ """Field position on checkout form."""
placeholder: Optional[str] = None
- """An example response displayed in the input field."""
+ """Placeholder text shown in empty field."""
required: bool
- """Whether or not the custom field is required."""
-
-
-class Invoice(BaseModel):
- """The invoice this plan was generated for.
-
- Null if the plan was not created for a specific invoice.
- """
-
- id: str
- """The unique identifier for the invoice."""
-
-
-class PaymentMethodConfiguration(BaseModel):
- """
- The explicit payment method configuration specifying which payment methods are enabled or disabled for this plan. Null if the plan uses default settings.
- """
-
- disabled: List[PaymentMethodTypes]
- """An array of payment method identifiers that are explicitly disabled.
-
- Only applies if the include_platform_defaults is true.
- """
-
- enabled: List[PaymentMethodTypes]
- """An array of payment method identifiers that are explicitly enabled.
-
- This means these payment methods will be shown on checkout. Example use case is
- to only enable a specific payment method like cashapp, or extending the platform
- defaults with additional methods.
- """
-
- include_platform_defaults: bool
- """
- Whether Whop's platform default payment method enablement settings are included
- in this configuration. The full list of default payment methods can be found in
- the documentation at docs.whop.com/payments.
- """
-
-
-class Product(BaseModel):
- """The product that this plan belongs to.
-
- Null for standalone one-off purchases not linked to a product.
- """
-
- id: str
- """The unique identifier for the product."""
-
- title: str
- """
- The display name of the product shown to customers on the product page and in
- search results.
- """
+ """Whether the customer must complete this field to check out."""
class Plan(BaseModel):
- """A plan defines pricing and billing terms for a checkout.
-
- Plans can optionally belong to a product, where they represent different pricing options such as one-time payments, recurring subscriptions, or free trials.
- """
-
id: str
- """The unique identifier for the plan."""
+ """Plan ID, prefixed `plan_`."""
- adaptive_pricing_enabled: bool
- """Whether the creator has turned on adaptive pricing for this plan.
+ account: Optional[object] = None
+ """Account that sells this plan; `null` for standalone invoice plans."""
- Raw setting — does not check processor compatibility or feature flags.
- """
+ adaptive_pricing_enabled: bool
+ """Whether this plan accepts local currency payments via adaptive pricing."""
- billing_period: Optional[int] = None
- """The number of days between each recurring charge.
+ billing_period: Optional[float] = None
+ """Recurring billing interval in days, such as 30 for monthly or 365 for annual.
- Null for one-time plans. For example, 30 for monthly or 365 for annual billing.
+ `null` for one-time plans.
"""
collect_tax: bool
- """
- Whether tax is collected on purchases of this plan, based on the company's tax
- configuration.
- """
-
- company: Optional[Company] = None
- """The company that sells this plan.
-
- Null for standalone invoice plans not linked to a company.
- """
-
- created_at: datetime
- """The datetime the plan was created."""
-
- currency: Currency
- """The currency used for all prices on this plan (e.g., 'usd', 'eur').
-
- All monetary amounts on the plan are denominated in this currency.
- """
+ """Whether tax is collected on purchases of this plan."""
+
+ created_at: str
+ """When the plan was created, as an ISO 8601 timestamp."""
+
+ currency: Literal[
+ "usd",
+ "sgd",
+ "inr",
+ "aud",
+ "brl",
+ "cad",
+ "dkk",
+ "eur",
+ "nok",
+ "gbp",
+ "sek",
+ "chf",
+ "hkd",
+ "huf",
+ "jpy",
+ "mxn",
+ "myr",
+ "pln",
+ "czk",
+ "nzd",
+ "aed",
+ "eth",
+ "ape",
+ "cop",
+ "ron",
+ "thb",
+ "bgn",
+ "idr",
+ "dop",
+ "php",
+ "try",
+ "krw",
+ "twd",
+ "vnd",
+ "pkr",
+ "clp",
+ "uyu",
+ "ars",
+ "zar",
+ "dzd",
+ "tnd",
+ "mad",
+ "kes",
+ "kwd",
+ "jod",
+ "all",
+ "xcd",
+ "amd",
+ "bsd",
+ "bhd",
+ "bob",
+ "bam",
+ "khr",
+ "crc",
+ "xof",
+ "egp",
+ "etb",
+ "gmd",
+ "ghs",
+ "gtq",
+ "gyd",
+ "ils",
+ "jmd",
+ "mop",
+ "mga",
+ "mur",
+ "mdl",
+ "mnt",
+ "nad",
+ "ngn",
+ "mkd",
+ "omr",
+ "pyg",
+ "pen",
+ "qar",
+ "rwf",
+ "sar",
+ "rsd",
+ "lkr",
+ "tzs",
+ "ttd",
+ "uzs",
+ "rub",
+ "btc",
+ "cny",
+ "usdt",
+ "kzt",
+ "awg",
+ "whop_usd",
+ "xau",
+ ]
+ """Three-letter ISO currency code for this plan's prices."""
custom_fields: List[CustomField]
- """
- Custom input fields displayed on the checkout form that collect additional
- information from the buyer.
- """
description: Optional[str] = None
- """A text description of the plan visible to customers.
-
- Maximum 1000 characters. Null if no description is set.
- """
+ """Customer-visible plan description."""
- expiration_days: Optional[int] = None
- """The number of days until the membership expires (for expiration-based plans).
-
- For example, 365 for a one-year access pass.
- """
+ expiration_days: Optional[float] = None
+ """Access duration in days for expiration-based plans."""
initial_price: float
- """The initial purchase price in the plan's base_currency (e.g., 49.99 for $49.99).
-
- For one-time plans, this is the full price. For renewal plans, this is charged
- on top of the first renewal_price.
- """
+ """Initial purchase price in plan currency."""
internal_notes: Optional[str] = None
- """Private notes visible only to the company owner and team members.
+ """Private notes visible only to authorized team members."""
- Not shown to customers. Null if no notes have been added.
- """
+ invoice: Optional[object] = None
+ """Invoice this plan was generated for; `null` unless created for an invoice."""
- invoice: Optional[Invoice] = None
- """The invoice this plan was generated for.
+ member_count: Optional[float] = None
+ """Active memberships through this plan, when visible to the requester."""
- Null if the plan was not created for a specific invoice.
- """
+ metadata: Optional[object] = None
+ """Custom key-value pairs stored on the plan."""
- member_count: Optional[int] = None
- """The number of users who currently hold an active membership through this plan.
-
- Only visible to authorized team members.
+ payment_method_configuration: Optional[object] = None
"""
-
- metadata: Optional[Dict[str, object]] = None
- """Custom key-value pairs stored on the plan.
-
- Included in webhook payloads for payment and membership events.
+ Payment method configuration (`enabled`, `disabled`,
+ `include_platform_defaults`); `null` when plan uses default settings.
"""
- payment_method_configuration: Optional[PaymentMethodConfiguration] = None
+ plan_type: Literal["renewal", "one_time"]
"""
- The explicit payment method configuration specifying which payment methods are
- enabled or disabled for this plan. Null if the plan uses default settings.
+ Billing model for this plan: `renewal` (recurring) or `one_time` (single
+ payment).
"""
- plan_type: PlanType
- """
- The billing model for this plan: 'renewal' for recurring subscriptions or
- 'one_time' for single payments.
- """
-
- product: Optional[Product] = None
- """The product that this plan belongs to.
-
- Null for standalone one-off purchases not linked to a product.
- """
+ product: Optional[object] = None
+ """Product this plan belongs to; `null` for standalone plans."""
purchase_url: str
- """
- The full URL where customers can purchase this plan directly, bypassing the
- product page.
- """
+ """URL where customers can purchase this plan directly."""
- release_method: ReleaseMethod
- """
- The method used to sell this plan: 'buy_now' for immediate purchase or
- 'waitlist' for waitlist-based access.
- """
+ release_method: Literal["buy_now", "waitlist"]
+ """Sales method for this plan, such as `buy_now` or `waitlist`."""
renewal_price: float
- """
- The recurring price charged every billing_period in the plan's base_currency
- (e.g., 9.99 for $9.99/period). Zero for one-time plans.
- """
+ """Recurring price charged every billing period."""
- split_pay_required_payments: Optional[int] = None
- """The total number of installment payments required before the subscription
- pauses.
+ split_pay_required_payments: Optional[float] = None
+ """Installment payments required before the subscription pauses."""
- Null if split pay is not configured. Must be greater than 1.
- """
+ stock: Optional[float] = None
+ """Units available for purchase, when visible to the requester."""
- stock: Optional[int] = None
- """The number of units available for purchase.
-
- Only visible to authorized team members. Null if the requester lacks permission.
- """
-
- tax_type: TaxType
- """
- How tax is handled for this plan: 'inclusive' (tax included in price),
- 'exclusive' (tax added at checkout), or 'unspecified' (tax not configured).
- """
+ tax_type: Literal["inclusive", "exclusive", "unspecified"]
+ """How tax is handled for this plan."""
three_ds_level: Optional[Literal["mandate_challenge", "frictionless"]] = None
- """The 3D Secure behavior for a plan."""
+ """3D Secure behavior for this plan; `null` inherits account default."""
title: Optional[str] = None
- """
- The display name of the plan shown to customers on the product page and at
- checkout. Maximum 30 characters. Null if no title has been set.
- """
+ """Plan display name shown to customers."""
- trial_period_days: Optional[int] = None
- """The number of free trial days before the first charge on a renewal plan.
+ trial_period_days: Optional[float] = None
+ """Free trial days before the first renewal charge.
- Null if no trial is configured or the current user has already used a trial for
- this plan.
+ `null` if no trial is configured or the user has already used a trial for this
+ plan.
"""
unlimited_stock: bool
- """When true, the plan has unlimited stock (stock field is ignored).
-
- When false, purchases are limited by the stock field.
- """
+ """Whether the plan has unlimited stock."""
- updated_at: datetime
- """The datetime the plan was last updated."""
+ updated_at: str
+ """When the plan was last updated, as an ISO 8601 timestamp."""
- visibility: Visibility
- """Controls whether the plan is visible to customers.
-
- When set to 'hidden', the plan is only accessible via direct link.
- """
+ visibility: Literal["visible", "hidden", "archived", "quick_link"]
+ """Whether the plan is visible to customers or hidden from public view."""
diff --git a/src/whop_sdk/types/shared/product.py b/src/whop_sdk/types/shared/product.py
index ce6299b8..70afd71f 100644
--- a/src/whop_sdk/types/shared/product.py
+++ b/src/whop_sdk/types/shared/product.py
@@ -19,9 +19,7 @@ class Company(BaseModel):
"""The unique identifier for the company."""
route: str
- """
- The URL slug for the company's store page (e.g., 'pickaxe' in whop.com/pickaxe).
- """
+ """URL slug for the account's store page, e.g. `pickaxe` in whop.com/pickaxe."""
title: str
"""The display name of the company shown to customers."""
@@ -69,12 +67,12 @@ class ProductTaxCode(BaseModel):
"""The unique identifier for the product tax code."""
name: str
- """The human-readable name of this tax classification (e.g., 'Digital - SaaS')."""
+ """Human-readable name of this tax classification, such as 'Digital - SaaS'."""
product_type: Literal["physical", "digital", "services"]
"""
- The broad product category this tax code covers (e.g., physical goods, digital
- services).
+ Broad product category this tax code covers, such as physical goods or digital
+ services.
"""
@@ -94,10 +92,7 @@ class Product(BaseModel):
"""The datetime the product was created."""
custom_cta: CustomCta
- """
- The call-to-action button label displayed on the product's purchase page (e.g.,
- 'join', 'buy', 'subscribe').
- """
+ """Call-to-action button label shown on the product purchase page."""
custom_cta_url: Optional[str] = None
"""
@@ -106,10 +101,9 @@ class Product(BaseModel):
"""
custom_statement_descriptor: Optional[str] = None
- """
- A custom text label that appears on the customer's bank or credit card statement
- for purchases of this product. Maximum 22 characters, including the required
- prefix WHOP\\**.
+ """Custom bank statement descriptor for product purchases.
+
+ Maximum 22 characters, including required `WHOP*` prefix.
"""
description: Optional[str] = None
@@ -119,10 +113,10 @@ class Product(BaseModel):
"""
external_identifier: Optional[str] = None
- """A unique identifier used to create or update products via the API.
+ """External identifier for the product.
- When provided on product creation endpoints, an existing product with this
- identifier will be updated instead of creating a new one.
+ Providing it on a product creation endpoint updates the existing product with
+ this identifier instead of creating a new one.
"""
gallery_images: List[GalleryImage]
@@ -130,8 +124,8 @@ class Product(BaseModel):
global_affiliate_percentage: Optional[float] = None
"""
- The commission rate (as a percentage) that affiliates earn on sales through the
- Whop marketplace global affiliate program. Null if the program is not active.
+ Marketplace affiliate commission percentage for this product, or `null` if
+ program is inactive.
"""
global_affiliate_status: GlobalAffiliateStatus
@@ -145,24 +139,24 @@ class Product(BaseModel):
member_affiliate_percentage: Optional[float] = None
"""
- The commission rate (as a percentage) that existing members earn when referring
- new customers through the member affiliate program. Null if the program is not
- active.
+ Member referral commission percentage for this product, or `null` if program is
+ inactive.
"""
member_affiliate_status: GlobalAffiliateStatus
"""The enrollment status of this product in the member affiliate program."""
member_count: int
- """The number of users who currently hold an active membership to this product.
+ """Active memberships for this product.
- Returns 0 if the company has disabled public member counts.
+ Returns `0` if the account has disabled public member counts.
"""
metadata: Optional[Dict[str, object]] = None
- """Custom key-value pairs stored on the product.
-
- Included in webhook payloads for payment and membership events.
+ """
+ Custom key-value pairs stored on the product and included in payment and
+ membership webhook payloads. Max 50 keys, 100 characters per key, 500 characters
+ per string value.
"""
owner_user: OwnerUser
@@ -178,9 +172,9 @@ class Product(BaseModel):
"""The total number of published customer reviews for this product's company."""
route: str
- """
- The URL slug used in the product's public link (e.g., 'my-product' in
- whop.com/company/my-product).
+ """URL slug in the product's public link, e.g.
+
+ `pickaxe-analytics` in whop.com/company/pickaxe-analytics.
"""
title: str
diff --git a/src/whop_sdk/types/shared/product_list_item.py b/src/whop_sdk/types/shared/product_list_item.py
index af1e59d5..eb084358 100644
--- a/src/whop_sdk/types/shared/product_list_item.py
+++ b/src/whop_sdk/types/shared/product_list_item.py
@@ -22,34 +22,35 @@ class ProductListItem(BaseModel):
"""The datetime the product was created."""
external_identifier: Optional[str] = None
- """A unique identifier used to create or update products via the API.
+ """External identifier for the product.
- When provided on product creation endpoints, an existing product with this
- identifier will be updated instead of creating a new one.
+ Providing it on a product creation endpoint updates the existing product with
+ this identifier instead of creating a new one.
"""
headline: Optional[str] = None
"""A short marketing headline displayed prominently on the product's product page."""
member_count: int
- """The number of users who currently hold an active membership to this product.
+ """Active memberships for this product.
- Returns 0 if the company has disabled public member counts.
+ Returns `0` if the account has disabled public member counts.
"""
metadata: Optional[Dict[str, object]] = None
- """Custom key-value pairs stored on the product.
-
- Included in webhook payloads for payment and membership events.
+ """
+ Custom key-value pairs stored on the product and included in payment and
+ membership webhook payloads. Max 50 keys, 100 characters per key, 500 characters
+ per string value.
"""
published_reviews_count: int
"""The total number of published customer reviews for this product's company."""
route: str
- """
- The URL slug used in the product's public link (e.g., 'my-product' in
- whop.com/company/my-product).
+ """URL slug in the product's public link, e.g.
+
+ `pickaxe-analytics` in whop.com/company/pickaxe-analytics.
"""
title: str
diff --git a/src/whop_sdk/types/shared/transfer.py b/src/whop_sdk/types/shared/transfer.py
deleted file mode 100644
index 8668f9e1..00000000
--- a/src/whop_sdk/types/shared/transfer.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Dict, Union, Optional
-from datetime import datetime
-from typing_extensions import Literal, Annotated, TypeAlias
-
-from ..._utils import PropertyInfo
-from .currency import Currency
-from ..._models import BaseModel
-
-__all__ = ["Transfer", "Destination", "DestinationUser", "DestinationCompany", "Origin", "OriginUser", "OriginCompany"]
-
-
-class DestinationUser(BaseModel):
- """A user account on Whop.
-
- Contains profile information, identity details, and social connections.
- """
-
- id: str
- """The unique identifier for the user."""
-
- name: Optional[str] = None
- """The user's display name shown on their public profile."""
-
- typename: Literal["User"]
- """The typename of this object"""
-
- username: str
- """The user's unique username shown on their public profile."""
-
-
-class DestinationCompany(BaseModel):
- """A company is a seller on Whop.
-
- Companies own products, manage members, and receive payouts.
- """
-
- id: str
- """The unique identifier for the company."""
-
- route: str
- """
- The URL slug for the company's store page (e.g., 'pickaxe' in whop.com/pickaxe).
- """
-
- title: str
- """The display name of the company shown to customers."""
-
- typename: Literal["Company"]
- """The typename of this object"""
-
-
-Destination: TypeAlias = Annotated[
- Union[Optional[DestinationUser], Optional[DestinationCompany]], PropertyInfo(discriminator="typename")
-]
-
-
-class OriginUser(BaseModel):
- """A user account on Whop.
-
- Contains profile information, identity details, and social connections.
- """
-
- id: str
- """The unique identifier for the user."""
-
- name: Optional[str] = None
- """The user's display name shown on their public profile."""
-
- typename: Literal["User"]
- """The typename of this object"""
-
- username: str
- """The user's unique username shown on their public profile."""
-
-
-class OriginCompany(BaseModel):
- """A company is a seller on Whop.
-
- Companies own products, manage members, and receive payouts.
- """
-
- id: str
- """The unique identifier for the company."""
-
- route: str
- """
- The URL slug for the company's store page (e.g., 'pickaxe' in whop.com/pickaxe).
- """
-
- title: str
- """The display name of the company shown to customers."""
-
- typename: Literal["Company"]
- """The typename of this object"""
-
-
-Origin: TypeAlias = Annotated[
- Union[Optional[OriginUser], Optional[OriginCompany]], PropertyInfo(discriminator="typename")
-]
-
-
-class Transfer(BaseModel):
- """A transfer of credit between two ledger accounts."""
-
- id: str
- """The unique identifier for the credit transaction transfer."""
-
- amount: float
- """The transfer amount in the currency specified by the currency field.
-
- For example, 10.43 represents $10.43 USD.
- """
-
- created_at: datetime
- """The datetime the credit transaction transfer was created."""
-
- currency: Currency
- """The currency in which this transfer amount is denominated."""
-
- destination: Destination
- """The entity receiving the transferred funds."""
-
- destination_ledger_account_id: str
- """The unique identifier of the ledger account receiving the funds."""
-
- fee_amount: Optional[float] = None
- """The flat fee amount deducted from this transfer, in the transfer's currency.
-
- Null if no flat fee was applied.
- """
-
- metadata: Optional[Dict[str, object]] = None
- """Custom key-value pairs attached to this transfer.
-
- Maximum 50 keys, 500 characters per key, 5000 characters per value.
- """
-
- notes: Optional[str] = None
- """A free-text note attached to this transfer by the sender.
-
- Null if no note was provided.
- """
-
- origin: Origin
- """The entity that sent the transferred funds."""
-
- origin_ledger_account_id: str
- """The unique identifier of the ledger account that sent the funds."""
diff --git a/src/whop_sdk/types/shared_params/__init__.py b/src/whop_sdk/types/shared_params/__init__.py
index eb838c16..e2000124 100644
--- a/src/whop_sdk/types/shared_params/__init__.py
+++ b/src/whop_sdk/types/shared_params/__init__.py
@@ -1,10 +1,8 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .currency import Currency as Currency
-from .tax_type import TaxType as TaxType
from .direction import Direction as Direction
from .plan_type import PlanType as PlanType
-from .custom_cta import CustomCta as CustomCta
from .promo_type import PromoType as PromoType
from .visibility import Visibility as Visibility
from .access_level import AccessLevel as AccessLevel
@@ -17,10 +15,8 @@
from .receipt_status import ReceiptStatus as ReceiptStatus
from .release_method import ReleaseMethod as ReleaseMethod
from .member_statuses import MemberStatuses as MemberStatuses
-from .access_pass_type import AccessPassType as AccessPassType
from .collection_method import CollectionMethod as CollectionMethod
from .membership_status import MembershipStatus as MembershipStatus
-from .visibility_filter import VisibilityFilter as VisibilityFilter
from .app_build_statuses import AppBuildStatuses as AppBuildStatuses
from .who_can_post_types import WhoCanPostTypes as WhoCanPostTypes
from .app_build_platforms import AppBuildPlatforms as AppBuildPlatforms
diff --git a/src/whop_sdk/types/shared_params/access_pass_type.py b/src/whop_sdk/types/shared_params/access_pass_type.py
deleted file mode 100644
index 3f760c67..00000000
--- a/src/whop_sdk/types/shared_params/access_pass_type.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Literal, TypeAlias
-
-__all__ = ["AccessPassType"]
-
-AccessPassType: TypeAlias = Literal["regular", "app", "experience_upsell", "api_only"]
diff --git a/src/whop_sdk/types/shared_params/custom_cta.py b/src/whop_sdk/types/shared_params/custom_cta.py
deleted file mode 100644
index 0c2f5d19..00000000
--- a/src/whop_sdk/types/shared_params/custom_cta.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Literal, TypeAlias
-
-__all__ = ["CustomCta"]
-
-CustomCta: TypeAlias = Literal[
- "get_access",
- "join",
- "order_now",
- "shop_now",
- "call_now",
- "donate_now",
- "contact_us",
- "sign_up",
- "subscribe",
- "purchase",
- "get_offer",
- "apply_now",
- "complete_order",
-]
diff --git a/src/whop_sdk/types/shared_params/tax_type.py b/src/whop_sdk/types/shared_params/tax_type.py
deleted file mode 100644
index bae01a1a..00000000
--- a/src/whop_sdk/types/shared_params/tax_type.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Literal, TypeAlias
-
-__all__ = ["TaxType"]
-
-TaxType: TypeAlias = Literal["inclusive", "exclusive", "unspecified"]
diff --git a/src/whop_sdk/types/shared_params/visibility_filter.py b/src/whop_sdk/types/shared_params/visibility_filter.py
deleted file mode 100644
index d01e6cb1..00000000
--- a/src/whop_sdk/types/shared_params/visibility_filter.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Literal, TypeAlias
-
-__all__ = ["VisibilityFilter"]
-
-VisibilityFilter: TypeAlias = Literal[
- "visible", "hidden", "archived", "quick_link", "all", "not_quick_link", "not_archived"
-]
diff --git a/src/whop_sdk/types/social_account.py b/src/whop_sdk/types/social_account.py
new file mode 100644
index 00000000..beb53370
--- /dev/null
+++ b/src/whop_sdk/types/social_account.py
@@ -0,0 +1,36 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["SocialAccount"]
+
+
+class SocialAccount(BaseModel):
+ id: str
+ """Unique identifier for the social account."""
+
+ external_id: Optional[str] = None
+ """The platform-specific ID for this social account."""
+
+ name: Optional[str] = None
+ """The display name of the social account on the platform."""
+
+ platform: Literal["x", "instagram", "youtube", "tiktok", "facebook"]
+ """The platform the social account exists on."""
+
+ profile_picture_url: Optional[str] = None
+ """The URL where the profile picture of the social account can be accessed."""
+
+ scopes: List[str]
+
+ url: str
+ """The URL where the social account can be accessed on the platform."""
+
+ username: str
+ """The username of the social account on the platform."""
+
+ verified: bool
+ """Whether the social account is verified on the platform."""
diff --git a/src/whop_sdk/types/social_account_create_params.py b/src/whop_sdk/types/social_account_create_params.py
new file mode 100644
index 00000000..3d4f9325
--- /dev/null
+++ b/src/whop_sdk/types/social_account_create_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 List
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["SocialAccountCreateParams"]
+
+
+class SocialAccountCreateParams(TypedDict, total=False):
+ platform: Required[Literal["meta_business"]]
+ """The platform to connect the social account on."""
+
+ redirect_url: Required[str]
+ """The Whop URL to redirect the user to after they finish connecting."""
+
+ account_id: str
+ """The Account (biz\\__ identifier) to connect the social account for.
+
+ An account-scoped API key may omit this to default to its own account.
+ """
+
+ scopes: List[Literal["advertise"]]
+ """
+ Capabilities to grant for the connected social account, for example `advertise`.
+ """
diff --git a/src/whop_sdk/types/social_account_create_response.py b/src/whop_sdk/types/social_account_create_response.py
new file mode 100644
index 00000000..ee66178b
--- /dev/null
+++ b/src/whop_sdk/types/social_account_create_response.py
@@ -0,0 +1,10 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .._models import BaseModel
+
+__all__ = ["SocialAccountCreateResponse"]
+
+
+class SocialAccountCreateResponse(BaseModel):
+ authorize_url: str
+ """The OAuth authorization URL to redirect the user to."""
diff --git a/src/whop_sdk/types/social_account_delete_params.py b/src/whop_sdk/types/social_account_delete_params.py
new file mode 100644
index 00000000..cd4b58f1
--- /dev/null
+++ b/src/whop_sdk/types/social_account_delete_params.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["SocialAccountDeleteParams"]
+
+
+class SocialAccountDeleteParams(TypedDict, total=False):
+ account_id: str
+ """The Account that the social account is connected to.
+
+ Provide either this or user_id.
+ """
+
+ user_id: str
+ """The User that the social account is connected to.
+
+ Provide either this or account_id.
+ """
diff --git a/src/whop_sdk/types/social_account_delete_response.py b/src/whop_sdk/types/social_account_delete_response.py
new file mode 100644
index 00000000..a37179be
--- /dev/null
+++ b/src/whop_sdk/types/social_account_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__ = ["SocialAccountDeleteResponse"]
+
+SocialAccountDeleteResponse: TypeAlias = bool
diff --git a/src/whop_sdk/types/social_account_list_params.py b/src/whop_sdk/types/social_account_list_params.py
new file mode 100644
index 00000000..c6b97e9a
--- /dev/null
+++ b/src/whop_sdk/types/social_account_list_params.py
@@ -0,0 +1,49 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List
+from typing_extensions import Literal, TypedDict
+
+__all__ = ["SocialAccountListParams"]
+
+
+class SocialAccountListParams(TypedDict, total=False):
+ account_id: str
+ """The Account that the social accounts are connected to.
+
+ Provide either this or user_id.
+ """
+
+ after: str
+ """Cursor to fetch the page after (from page_info.end_cursor)."""
+
+ before: str
+ """Cursor to fetch the page before (from page_info.start_cursor)."""
+
+ direction: Literal["asc", "desc"]
+ """Sort direction."""
+
+ first: int
+ """The number of social accounts to return."""
+
+ last: int
+ """The number of social accounts to return from the end of the range."""
+
+ order: Literal["display_order", "created_at"]
+ """The field to sort social accounts by."""
+
+ platform: Literal["x", "instagram", "youtube", "tiktok", "facebook"]
+ """Only return social accounts for the platform that is specified."""
+
+ scopes: List[Literal["advertise"]]
+ """Only return social accounts that have these scopes."""
+
+ user_id: str
+ """The User that the social accounts are connected to.
+
+ Provide either this or account_id.
+ """
+
+ verified: bool
+ """Only return social accounts that are verified on the platform."""
diff --git a/src/whop_sdk/types/social_account_post.py b/src/whop_sdk/types/social_account_post.py
new file mode 100644
index 00000000..4e3d6df6
--- /dev/null
+++ b/src/whop_sdk/types/social_account_post.py
@@ -0,0 +1,74 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["SocialAccountPost"]
+
+
+class SocialAccountPost(BaseModel):
+ id: str
+ """The platform's own identifier for the post or media.
+
+ Use it to reference the post on an ad.
+ """
+
+ call_to_action: Optional[
+ Literal[
+ "learn_more",
+ "shop_now",
+ "sign_up",
+ "subscribe",
+ "get_started",
+ "book_now",
+ "apply_now",
+ "contact_us",
+ "download",
+ "order_now",
+ "buy_now",
+ "get_quote",
+ "message_page",
+ "whatsapp_message",
+ "instagram_message",
+ "call_now",
+ "get_directions",
+ "send_updates",
+ "get_offer",
+ "watch_more",
+ "listen_now",
+ "play_game",
+ "open_link",
+ "no_button",
+ "get_offer_view",
+ "get_event_tickets",
+ "see_menu",
+ "request_time",
+ "event_rsvp",
+ "see_details",
+ "view_instagram_profile",
+ ]
+ ] = None
+ """
+ The post's call-to-action button, for example shop_now (Facebook only; null for
+ Instagram).
+ """
+
+ destination_url: Optional[str] = None
+ """
+ The URL the post's call-to-action drives to (Facebook only; null for Instagram).
+ """
+
+ media_url: Optional[str] = None
+ """
+ The URL of the post's media — the image for image posts, the playable video file
+ for video posts. Meta signs these and they expire after roughly 24 hours, so
+ don't store them.
+ """
+
+ thumbnail_url: Optional[str] = None
+ """
+ Poster image for video posts; null for image posts, where media_url is already
+ the image. Signed and short-lived like media_url.
+ """
diff --git a/src/whop_sdk/types/social_account_posts_params.py b/src/whop_sdk/types/social_account_posts_params.py
new file mode 100644
index 00000000..1da9ce1d
--- /dev/null
+++ b/src/whop_sdk/types/social_account_posts_params.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["SocialAccountPostsParams"]
+
+
+class SocialAccountPostsParams(TypedDict, total=False):
+ account_id: Required[str]
+ """The Account (a biz\\__ identifier) the social account is connected to."""
+
+ after: str
+ """Cursor to fetch the page after (from page_info.end_cursor)."""
+
+ first: int
+ """The number of posts to return."""
+
+ post_id: str
+ """Return only the single post with this platform id, instead of the full list."""
diff --git a/src/whop_sdk/types/social_account_posts_response.py b/src/whop_sdk/types/social_account_posts_response.py
new file mode 100644
index 00000000..59fa3a0e
--- /dev/null
+++ b/src/whop_sdk/types/social_account_posts_response.py
@@ -0,0 +1,20 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from .._models import BaseModel
+from .social_account_post import SocialAccountPost
+
+__all__ = ["SocialAccountPostsResponse", "PageInfo"]
+
+
+class PageInfo(BaseModel):
+ end_cursor: Optional[str] = None
+
+ has_next_page: bool
+
+
+class SocialAccountPostsResponse(BaseModel):
+ data: List[SocialAccountPost]
+
+ page_info: PageInfo
diff --git a/src/whop_sdk/types/stat_list_response.py b/src/whop_sdk/types/stat_list_response.py
new file mode 100644
index 00000000..f8f50620
--- /dev/null
+++ b/src/whop_sdk/types/stat_list_response.py
@@ -0,0 +1,42 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["StatListResponse", "Data"]
+
+
+class Data(BaseModel):
+ description: str
+ """A short description of what the metric measures."""
+
+ key: str
+ """The metric's key. Pass it to GET /stats/{metric} to query its values."""
+
+ name: str
+ """Human-readable display name for the metric."""
+
+ properties: List[str]
+ """
+ The properties you can use with this metric — pass one as a filter
+ (property=value) to narrow the series, or as breakdown_by=property to split it.
+ """
+
+ unit: Literal["count", "currency", "percent"]
+ """
+ How to read the metric's values: count is an integer, currency is a decimal
+ amount, and percent is a number where 1.6 means 1.6%.
+ """
+
+ windows: Optional[List[str]] = None
+ """
+ Snapshot metrics only: the trailing windows you can pass as snapshot_window, for
+ example 30d. Absent on live metrics, which use from/to instead.
+ """
+
+
+class StatListResponse(BaseModel):
+ data: List[Data]
+ """The available metrics."""
diff --git a/src/whop_sdk/types/stat_retrieve_params.py b/src/whop_sdk/types/stat_retrieve_params.py
new file mode 100644
index 00000000..68417c71
--- /dev/null
+++ b/src/whop_sdk/types/stat_retrieve_params.py
@@ -0,0 +1,73 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from datetime import date
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["StatRetrieveParams"]
+
+
+class StatRetrieveParams(TypedDict, total=False):
+ account_id: Required[str]
+ """The account to measure, for example biz_AbC123."""
+
+ from_: Required[Annotated[Union[str, date], PropertyInfo(alias="from", format="iso8601")]]
+ """Start of the date range (YYYY-MM-DD)."""
+
+ to: Required[Annotated[Union[str, date], PropertyInfo(format="iso8601")]]
+ """End of the date range (YYYY-MM-DD)."""
+
+ breakdown_by: str
+ """
+ Split the metric out by one of its properties — each point gets a breakdown
+ array. For example breakdown_by=currency returns an entry for usd, an entry for
+ eur, and so on.
+ """
+
+ card_network: str
+ """Filter to a single card brand, for example visa.
+
+ A refinement of payment_method=card. Available on metrics that list
+ card_network.
+ """
+
+ convert_to: str
+ """
+ Display currency for money metrics — every amount is converted into this ISO
+ currency using the exchange rate on each period's date. Defaults to usd. Ignored
+ when you filter or break down by currency (those report the original transaction
+ currency, unconverted).
+ """
+
+ currency: str
+ """
+ Filter to transactions made in this original ISO currency, for example eur —
+ reported in that currency, not converted. Pair with breakdown_by=currency to
+ split a metric by currency. Available on metrics that list currency.
+ """
+
+ interval: Literal["hour", "day", "week", "month"]
+ """How wide each point is. Defaults to day. Snapshot metrics are day-only."""
+
+ payment_method: str
+ """Filter to a single payment method, for example card or crypto.
+
+ Available on metrics that list payment_method.
+ """
+
+ snapshot_window: Literal["30d"]
+ """Trailing window for snapshot metrics.
+
+ Only accepted by snapshot metrics (each lists its allowed windows in the
+ catalog); defaults to the metric's first supported window. Only 30d today.
+ """
+
+ time_zone: str
+ """IANA time zone to bucket the series in, for example America/New_York.
+
+ Defaults to UTC. Not accepted by snapshot metrics, which are UTC only.
+ """
diff --git a/src/whop_sdk/types/stat_retrieve_response.py b/src/whop_sdk/types/stat_retrieve_response.py
new file mode 100644
index 00000000..72d0cfda
--- /dev/null
+++ b/src/whop_sdk/types/stat_retrieve_response.py
@@ -0,0 +1,35 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from .._models import BaseModel
+
+__all__ = ["StatRetrieveResponse", "Data", "DataPoint", "DataPointBreakdown"]
+
+
+class DataPointBreakdown(BaseModel):
+ name: str
+ """The property value, for example usd or visa."""
+
+ value: Optional[float] = None
+ """The metric's value for this entry."""
+
+
+class DataPoint(BaseModel):
+ timestamp: int
+ """Unix timestamp (seconds) of the period start."""
+
+ value: Optional[float] = None
+ """The metric's value for this period, in the metric's unit."""
+
+ breakdown: Optional[List[DataPointBreakdown]] = None
+ """Present only when broken down: one entry per property value in this period."""
+
+
+class Data(BaseModel):
+ points: List[DataPoint]
+ """One entry per period, oldest first."""
+
+
+class StatRetrieveResponse(BaseModel):
+ data: Data
diff --git a/src/whop_sdk/types/swap_create_params.py b/src/whop_sdk/types/swap_create_params.py
new file mode 100644
index 00000000..ec3e05c8
--- /dev/null
+++ b/src/whop_sdk/types/swap_create_params.py
@@ -0,0 +1,37 @@
+# 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 Required, TypedDict
+
+__all__ = ["SwapCreateParams"]
+
+
+class SwapCreateParams(TypedDict, total=False):
+ account_id: Required[str]
+ """Business or user account ID (biz*\\** / user*\\**)."""
+
+ amount: Required[str]
+ """Source token amount."""
+
+ from_token: Required[str]
+ """Source token contract address or ticker symbol, such as "USDT"."""
+
+ to_token: Required[str]
+ """Destination token contract address or ticker symbol, such as "XAUT"."""
+
+ from_chain: Union[str, int, None]
+ """Source chain name or chain ID.
+
+ Defaults to the source token's chain when omitted.
+ """
+
+ slippage_bps: Optional[int]
+ """Maximum slippage tolerance in basis points."""
+
+ to_chain: Union[str, int, None]
+ """Destination chain name or chain ID.
+
+ Defaults to the destination token's chain when omitted.
+ """
diff --git a/src/whop_sdk/types/swap_create_quote_params.py b/src/whop_sdk/types/swap_create_quote_params.py
index 9fc72c96..9a1cc323 100644
--- a/src/whop_sdk/types/swap_create_quote_params.py
+++ b/src/whop_sdk/types/swap_create_quote_params.py
@@ -10,22 +10,34 @@
class SwapCreateQuoteParams(TypedDict, total=False):
amount: Required[str]
- """Input token amount."""
+ """Source token amount."""
from_token: Required[str]
- """Source token contract address."""
+ """Source token contract address or ticker symbol, such as "USDT"."""
to_token: Required[str]
- """Destination token contract address."""
+ """Destination token contract address or ticker symbol, such as "XAUT"."""
from_address: Optional[str]
+ """Source wallet address used for the quote."""
from_chain: Union[str, int, None]
+ """Source chain name or chain ID.
+
+ Defaults to the source token's chain when omitted.
+ """
metadata: Dict[str, object]
+ """Metadata to include with the quote response."""
slippage_bps: Optional[int]
+ """Maximum slippage tolerance in basis points."""
to_address: Optional[str]
+ """Destination wallet address used for the quote."""
to_chain: Union[str, int, None]
+ """Destination chain name or chain ID.
+
+ Defaults to the destination token's chain when omitted.
+ """
diff --git a/src/whop_sdk/types/swap_create_quote_response.py b/src/whop_sdk/types/swap_create_quote_response.py
index fa90b64b..8cff4e8b 100644
--- a/src/whop_sdk/types/swap_create_quote_response.py
+++ b/src/whop_sdk/types/swap_create_quote_response.py
@@ -11,29 +11,42 @@
class SwapCreateQuoteResponse(BaseModel):
amount_in: str
+ """Source token amount used for the quote."""
amount_out: str
+ """Estimated destination token amount."""
fee_bps: int
+ """Whop fee in basis points."""
from_token: Dict[str, object]
+ """Resolved source token details."""
metadata: Dict[str, object]
+ """Metadata from the request."""
object: Literal["swap_quote"]
rate: str
+ """Quoted exchange rate."""
to_token: Dict[str, builtins.object]
+ """Resolved destination token details."""
amount_out_min: Optional[str] = None
+ """Minimum destination amount after slippage."""
bridge_fee: Optional[str] = None
+ """Estimated bridge fee for cross-chain swaps."""
estimated_duration_seconds: Optional[int] = None
+ """Estimated time for the swap to complete."""
from_address: Optional[str] = None
+ """Source wallet address used for the quote."""
requires_token_approval: Optional[bool] = None
+ """Whether the source token needs approval before swapping."""
to_address: Optional[str] = None
+ """Destination wallet address used for the quote."""
diff --git a/src/whop_sdk/types/swap_create_response.py b/src/whop_sdk/types/swap_create_response.py
new file mode 100644
index 00000000..da5979b9
--- /dev/null
+++ b/src/whop_sdk/types/swap_create_response.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["SwapCreateResponse"]
+
+
+class SwapCreateResponse(BaseModel):
+ id: str
+ """Swap ID. Poll `GET /swaps/:id` for status."""
+
+ account_id: str
+ """Account ID that owns the wallet used for the swap."""
+
+ object: Literal["swap"]
+
+ status: str
+ """Initial swap status."""
+
+ amount_out_expected: Optional[str] = None
+ """Expected destination token amount."""
+
+ amount_out_min: Optional[str] = None
+ """Minimum destination amount after slippage."""
+
+ rate: Optional[str] = None
+ """Quoted exchange rate used to create the swap."""
+
+ to_chain: Optional[str] = None
+ """Destination chain for the swap."""
diff --git a/src/whop_sdk/types/swap_list_params.py b/src/whop_sdk/types/swap_list_params.py
new file mode 100644
index 00000000..8a5123a2
--- /dev/null
+++ b/src/whop_sdk/types/swap_list_params.py
@@ -0,0 +1,12 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["SwapListParams"]
+
+
+class SwapListParams(TypedDict, total=False):
+ account_id: Required[str]
+ """Business or user account ID (biz*\\** / user*\\**)."""
diff --git a/src/whop_sdk/types/swap_list_response.py b/src/whop_sdk/types/swap_list_response.py
new file mode 100644
index 00000000..ab55ffdd
--- /dev/null
+++ b/src/whop_sdk/types/swap_list_response.py
@@ -0,0 +1,32 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["SwapListResponse", "Data"]
+
+
+class Data(BaseModel):
+ id: str
+ """Swap ID."""
+
+ account_id: str
+ """Account ID that owns the wallet used for the swap."""
+
+ object: Literal["swap"]
+
+ status: str
+ """Current swap status."""
+
+ tx_hashes: List[str]
+ """On-chain transaction hashes produced by the swap."""
+
+ error: Optional[str] = None
+ """Latest error returned for a failed swap."""
+
+
+class SwapListResponse(BaseModel):
+ data: List[Data]
+ """Swaps returned for this account."""
diff --git a/src/whop_sdk/types/swap_retrieve_response.py b/src/whop_sdk/types/swap_retrieve_response.py
new file mode 100644
index 00000000..91f98537
--- /dev/null
+++ b/src/whop_sdk/types/swap_retrieve_response.py
@@ -0,0 +1,27 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["SwapRetrieveResponse"]
+
+
+class SwapRetrieveResponse(BaseModel):
+ id: str
+ """Swap ID."""
+
+ account_id: str
+ """Account ID that owns the wallet used for the swap."""
+
+ object: Literal["swap"]
+
+ status: str
+ """Current swap status."""
+
+ tx_hashes: List[str]
+ """On-chain transaction hashes produced by the swap."""
+
+ error: Optional[str] = None
+ """Latest error returned for a failed swap."""
diff --git a/src/whop_sdk/types/tax_identifier_type.py b/src/whop_sdk/types/tax_identifier_type.py
index 6b186a3c..92c4dbb9 100644
--- a/src/whop_sdk/types/tax_identifier_type.py
+++ b/src/whop_sdk/types/tax_identifier_type.py
@@ -8,6 +8,7 @@
"ad_nrt",
"ao_tin",
"ar_cuit",
+ "al_tin",
"am_tin",
"aw_tin",
"au_abn",
@@ -48,6 +49,7 @@
"et_tin",
"eu_oss_vat",
"ge_vat",
+ "gh_tin",
"de_stn",
"gb_vat",
"gn_nif",
diff --git a/src/whop_sdk/types/transfer_create_params.py b/src/whop_sdk/types/transfer_create_params.py
index f1729e58..c9e43000 100644
--- a/src/whop_sdk/types/transfer_create_params.py
+++ b/src/whop_sdk/types/transfer_create_params.py
@@ -2,50 +2,56 @@
from __future__ import annotations
-from typing import Dict, Optional
-from typing_extensions import Required, TypedDict
+from typing import Dict, Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, Required, Annotated, TypedDict
-from .shared.currency import Currency
+from .._utils import PropertyInfo
__all__ = ["TransferCreateParams"]
class TransferCreateParams(TypedDict, total=False):
amount: Required[float]
- """The amount to transfer in the specified currency.
+ """The amount to move, in the transfer currency. For example 25.00."""
- For example, 25.00 for $25.00 USD.
+ origin_id: Required[str]
+ """The account sending the funds.
+
+ A user ID (user_xxx), account ID (biz_xxx), or ledger account ID (ldgr_xxx).
"""
- currency: Required[Currency]
- """The currency of the transfer amount, such as 'usd'."""
+ currency: str
+ """Currency, such as `usd`. Required for ledger transfers."""
- destination_id: Required[str]
- """The identifier of the account receiving the funds.
+ destination_id: str
+ """The recipient.
- Accepts a user ID ('user_xxx'), company ID ('biz_xxx'), ledger account ID
- ('ldgr_xxx'), or an email address — emails without an existing Whop user trigger
- a placeholder-user signup.
+ Required for ledger and wallet*send (a user*/biz*/ldgr* ID, or — for sends — an
+ email). Omit for claim_link.
"""
- origin_id: Required[str]
- """The identifier of the account sending the funds.
+ expires_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
+ """claim_link only.
- Accepts a user ID ('user_xxx'), company ID ('biz_xxx'), or ledger account ID
- ('ldgr_xxx').
+ Link expiry as an ISO 8601 timestamp. Defaults to 24 hours from creation.
"""
idempotence_key: Optional[str]
- """A unique key to prevent duplicate transfers.
-
- Use a UUID or similar unique string.
- """
+ """Ledger transfers only. A unique key to prevent duplicate transfers."""
metadata: Optional[Dict[str, object]]
- """
- A JSON object of custom metadata to attach to the transfer for tracking
- purposes.
+ """Ledger transfers only.
+
+ Custom key-value pairs attached to the transfer. Max 50 keys, 100 chars per key,
+ 500 chars per string value.
"""
notes: Optional[str]
- """A short note describing the transfer, up to 50 characters."""
+ """Ledger transfers only. A short note describing the transfer."""
+
+ redeemable_count: int
+ """claim_link only. How many different users can claim the link. Defaults to 1."""
+
+ type: Literal["ledger", "wallet_send", "claim_link"]
+ """The kind of money movement. Defaults to ledger."""
diff --git a/src/whop_sdk/types/transfer_create_response.py b/src/whop_sdk/types/transfer_create_response.py
new file mode 100644
index 00000000..669531d8
--- /dev/null
+++ b/src/whop_sdk/types/transfer_create_response.py
@@ -0,0 +1,180 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from .._utils import PropertyInfo
+from .._models import BaseModel
+
+__all__ = [
+ "TransferCreateResponse",
+ "Transfer",
+ "TransferDestination",
+ "TransferDestinationCompany",
+ "TransferDestinationUser",
+ "TransferOrigin",
+ "TransferOriginCompany",
+ "TransferOriginUser",
+ "Send",
+ "SendDestination",
+ "SendSource",
+ "ClaimLink",
+ "ClaimLinkSource",
+]
+
+
+class TransferDestinationCompany(BaseModel):
+ id: str
+ """Account ID."""
+
+ typename: Literal["Company"]
+
+ route: Optional[str] = None
+ """Account route."""
+
+ title: Optional[str] = None
+ """Account display name."""
+
+
+class TransferDestinationUser(BaseModel):
+ id: str
+ """User ID."""
+
+ typename: Literal["User"]
+
+ name: Optional[str] = None
+ """User display name."""
+
+ username: Optional[str] = None
+ """User's username."""
+
+
+TransferDestination: TypeAlias = Annotated[
+ Union[TransferDestinationCompany, TransferDestinationUser], PropertyInfo(discriminator="typename")
+]
+
+
+class TransferOriginCompany(BaseModel):
+ id: str
+ """Account ID."""
+
+ typename: Literal["Company"]
+
+ route: Optional[str] = None
+ """Account route."""
+
+ title: Optional[str] = None
+ """Account display name."""
+
+
+class TransferOriginUser(BaseModel):
+ id: str
+ """User ID."""
+
+ typename: Literal["User"]
+
+ name: Optional[str] = None
+ """User display name."""
+
+ username: Optional[str] = None
+ """User's username."""
+
+
+TransferOrigin: TypeAlias = Annotated[
+ Union[TransferOriginCompany, TransferOriginUser], PropertyInfo(discriminator="typename")
+]
+
+
+class Transfer(BaseModel):
+ """A transfer of credit between two ledger accounts."""
+
+ id: str
+ """Transfer ID."""
+
+ amount: float
+ """Transfer amount."""
+
+ created_at: datetime
+ """When the transfer was created."""
+
+ currency: str
+ """Transfer currency."""
+
+ destination: TransferDestination
+ """Account or user receiving funds."""
+
+ destination_ledger_account_id: str
+ """Destination ledger account ID."""
+
+ origin: TransferOrigin
+ """Account or user sending funds."""
+
+ origin_ledger_account_id: str
+ """Source ledger account ID."""
+
+ fee_amount: Optional[float] = None
+ """Fee charged for the transfer."""
+
+ metadata: Optional[Dict[str, object]] = None
+ """Custom metadata attached to the transfer."""
+
+ notes: Optional[str] = None
+ """Transfer note."""
+
+
+class SendDestination(BaseModel):
+ account_id: str
+
+ address: str
+
+
+class SendSource(BaseModel):
+ account_id: str
+
+ address: str
+
+
+class Send(BaseModel):
+ """Returned for a wallet_send: an onchain USDT send to a recipient."""
+
+ amount: str
+
+ currency: str
+
+ destination: SendDestination
+
+ object: Literal["send"]
+
+ source: SendSource
+
+ tx_hash: str
+
+
+class ClaimLinkSource(BaseModel):
+ account_id: str
+
+
+class ClaimLink(BaseModel):
+ """Returned for a claim_link: a shareable URL anyone can open to claim the funds."""
+
+ id: str
+
+ amount: str
+
+ claim_url: str
+
+ currency: str
+
+ expires_at: Optional[datetime] = None
+
+ object: Literal["claim_link"]
+
+ redeemable_count: int
+
+ source: ClaimLinkSource
+
+ status: str
+
+
+TransferCreateResponse: TypeAlias = Union[Transfer, Send, ClaimLink]
diff --git a/src/whop_sdk/types/transfer_list_params.py b/src/whop_sdk/types/transfer_list_params.py
index aedb7b41..2f6bd493 100644
--- a/src/whop_sdk/types/transfer_list_params.py
+++ b/src/whop_sdk/types/transfer_list_params.py
@@ -2,49 +2,38 @@
from __future__ import annotations
-from typing import Union, Optional
-from datetime import datetime
-from typing_extensions import Literal, Annotated, TypedDict
-
-from .._utils import PropertyInfo
-from .shared.direction import Direction
+from typing_extensions import Literal, TypedDict
__all__ = ["TransferListParams"]
class TransferListParams(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."""
-
- created_after: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """Only return transfers created after this timestamp."""
+ after: str
+ """Cursor to fetch the page after (from page_info.end_cursor)."""
- created_before: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """Only return transfers created before this timestamp."""
+ before: str
+ """Cursor to fetch the page before (from page_info.start_cursor)."""
- destination_id: Optional[str]
- """Filter to transfers received by this account.
+ created_after: str
+ """Only transfers created strictly after this ISO 8601 timestamp."""
- Accepts a user, company, or ledger account ID.
- """
+ created_before: str
+ """Only transfers created strictly before this ISO 8601 timestamp."""
- direction: Optional[Direction]
- """The direction of the sort."""
+ destination_id: str
+ """Filter to transfers received by this account."""
- first: Optional[int]
- """Returns the first _n_ elements from the list."""
+ direction: Literal["asc", "desc"]
+ """Sort direction. Defaults to desc."""
- last: Optional[int]
- """Returns the last _n_ elements from the list."""
+ first: int
+ """Number of transfers to return from the start of the window."""
- order: Optional[Literal["amount", "created_at"]]
- """Which columns can be used to sort."""
+ last: int
+ """Number of transfers to return from the end of the window."""
- origin_id: Optional[str]
- """Filter to transfers sent from this account.
+ order: Literal["created_at", "amount"]
+ """Sort column. Defaults to created_at."""
- Accepts a user, company, or ledger account ID.
- """
+ origin_id: str
+ """Filter to transfers sent from this account."""
diff --git a/src/whop_sdk/types/transfer_list_response.py b/src/whop_sdk/types/transfer_list_response.py
index 7e1530a3..7f516918 100644
--- a/src/whop_sdk/types/transfer_list_response.py
+++ b/src/whop_sdk/types/transfer_list_response.py
@@ -4,7 +4,6 @@
from datetime import datetime
from .._models import BaseModel
-from .shared.currency import Currency
__all__ = ["TransferListResponse"]
@@ -13,40 +12,28 @@ class TransferListResponse(BaseModel):
"""A transfer of credit between two ledger accounts."""
id: str
- """The unique identifier for the credit transaction transfer."""
+ """Transfer ID."""
amount: float
- """The transfer amount in the currency specified by the currency field.
-
- For example, 10.43 represents $10.43 USD.
- """
+ """Transfer amount."""
created_at: datetime
- """The datetime the credit transaction transfer was created."""
+ """When the transfer was created."""
- currency: Currency
- """The currency in which this transfer amount is denominated."""
+ currency: str
+ """Transfer currency."""
destination_ledger_account_id: str
- """The unique identifier of the ledger account receiving the funds."""
+ """Destination ledger account ID."""
- fee_amount: Optional[float] = None
- """The flat fee amount deducted from this transfer, in the transfer's currency.
+ origin_ledger_account_id: str
+ """Source ledger account ID."""
- Null if no flat fee was applied.
- """
+ fee_amount: Optional[float] = None
+ """Fee charged for the transfer."""
metadata: Optional[Dict[str, object]] = None
- """Custom key-value pairs attached to this transfer.
-
- Maximum 50 keys, 500 characters per key, 5000 characters per value.
- """
+ """Custom metadata attached to the transfer."""
notes: Optional[str] = None
- """A free-text note attached to this transfer by the sender.
-
- Null if no note was provided.
- """
-
- origin_ledger_account_id: str
- """The unique identifier of the ledger account that sent the funds."""
+ """Transfer note."""
diff --git a/src/whop_sdk/types/transfer_retrieve_response.py b/src/whop_sdk/types/transfer_retrieve_response.py
new file mode 100644
index 00000000..cd41c697
--- /dev/null
+++ b/src/whop_sdk/types/transfer_retrieve_response.py
@@ -0,0 +1,113 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from .._utils import PropertyInfo
+from .._models import BaseModel
+
+__all__ = [
+ "TransferRetrieveResponse",
+ "Destination",
+ "DestinationCompany",
+ "DestinationUser",
+ "Origin",
+ "OriginCompany",
+ "OriginUser",
+]
+
+
+class DestinationCompany(BaseModel):
+ id: str
+ """Account ID."""
+
+ typename: Literal["Company"]
+
+ route: Optional[str] = None
+ """Account route."""
+
+ title: Optional[str] = None
+ """Account display name."""
+
+
+class DestinationUser(BaseModel):
+ id: str
+ """User ID."""
+
+ typename: Literal["User"]
+
+ name: Optional[str] = None
+ """User display name."""
+
+ username: Optional[str] = None
+ """User's username."""
+
+
+Destination: TypeAlias = Annotated[Union[DestinationCompany, DestinationUser], PropertyInfo(discriminator="typename")]
+
+
+class OriginCompany(BaseModel):
+ id: str
+ """Account ID."""
+
+ typename: Literal["Company"]
+
+ route: Optional[str] = None
+ """Account route."""
+
+ title: Optional[str] = None
+ """Account display name."""
+
+
+class OriginUser(BaseModel):
+ id: str
+ """User ID."""
+
+ typename: Literal["User"]
+
+ name: Optional[str] = None
+ """User display name."""
+
+ username: Optional[str] = None
+ """User's username."""
+
+
+Origin: TypeAlias = Annotated[Union[OriginCompany, OriginUser], PropertyInfo(discriminator="typename")]
+
+
+class TransferRetrieveResponse(BaseModel):
+ """A transfer of credit between two ledger accounts."""
+
+ id: str
+ """Transfer ID."""
+
+ amount: float
+ """Transfer amount."""
+
+ created_at: datetime
+ """When the transfer was created."""
+
+ currency: str
+ """Transfer currency."""
+
+ destination: Destination
+ """Account or user receiving funds."""
+
+ destination_ledger_account_id: str
+ """Destination ledger account ID."""
+
+ origin: Origin
+ """Account or user sending funds."""
+
+ origin_ledger_account_id: str
+ """Source ledger account ID."""
+
+ fee_amount: Optional[float] = None
+ """Fee charged for the transfer."""
+
+ metadata: Optional[Dict[str, object]] = None
+ """Custom metadata attached to the transfer."""
+
+ notes: Optional[str] = None
+ """Transfer note."""
diff --git a/src/whop_sdk/types/unwrap_webhook_event.py b/src/whop_sdk/types/unwrap_webhook_event.py
index dde154cc..dc6ad61b 100644
--- a/src/whop_sdk/types/unwrap_webhook_event.py
+++ b/src/whop_sdk/types/unwrap_webhook_event.py
@@ -22,7 +22,9 @@
from .payment_succeeded_webhook_event import PaymentSucceededWebhookEvent
from .withdrawal_created_webhook_event import WithdrawalCreatedWebhookEvent
from .withdrawal_updated_webhook_event import WithdrawalUpdatedWebhookEvent
+from .chat_message_created_webhook_event import ChatMessageCreatedWebhookEvent
from .membership_activated_webhook_event import MembershipActivatedWebhookEvent
+from .chat_reaction_created_webhook_event import ChatReactionCreatedWebhookEvent
from .dispute_alert_created_webhook_event import DisputeAlertCreatedWebhookEvent
from .payout_method_created_webhook_event import PayoutMethodCreatedWebhookEvent
from .setup_intent_canceled_webhook_event import SetupIntentCanceledWebhookEvent
@@ -33,9 +35,11 @@
from .identity_profile_approved_webhook_event import IdentityProfileApprovedWebhookEvent
from .identity_profile_rejected_webhook_event import IdentityProfileRejectedWebhookEvent
from .invoice_marked_uncollectible_webhook_event import InvoiceMarkedUncollectibleWebhookEvent
+from .membership_trial_ending_soon_webhook_event import MembershipTrialEndingSoonWebhookEvent
from .setup_intent_requires_action_webhook_event import SetupIntentRequiresActionWebhookEvent
from .identity_profile_needs_action_webhook_event import IdentityProfileNeedsActionWebhookEvent
from .payout_account_status_updated_webhook_event import PayoutAccountStatusUpdatedWebhookEvent
+from .ledger_account_funds_available_webhook_event import LedgerAccountFundsAvailableWebhookEvent
from .resolution_center_case_created_webhook_event import ResolutionCenterCaseCreatedWebhookEvent
from .resolution_center_case_decided_webhook_event import ResolutionCenterCaseDecidedWebhookEvent
from .resolution_center_case_updated_webhook_event import ResolutionCenterCaseUpdatedWebhookEvent
@@ -46,6 +50,8 @@
UnwrapWebhookEvent: TypeAlias = Annotated[
Union[
+ ChatMessageCreatedWebhookEvent,
+ ChatReactionCreatedWebhookEvent,
CourseLessonInteractionCompletedWebhookEvent,
DisputeCreatedWebhookEvent,
DisputeUpdatedWebhookEvent,
@@ -63,9 +69,11 @@
InvoicePaidWebhookEvent,
InvoicePastDueWebhookEvent,
InvoiceVoidedWebhookEvent,
+ LedgerAccountFundsAvailableWebhookEvent,
MembershipActivatedWebhookEvent,
MembershipCancelAtPeriodEndChangedWebhookEvent,
MembershipDeactivatedWebhookEvent,
+ MembershipTrialEndingSoonWebhookEvent,
PaymentCreatedWebhookEvent,
PaymentFailedWebhookEvent,
PaymentPendingWebhookEvent,
diff --git a/src/whop_sdk/types/user.py b/src/whop_sdk/types/user.py
index 4e52982f..5630f4b3 100644
--- a/src/whop_sdk/types/user.py
+++ b/src/whop_sdk/types/user.py
@@ -1,49 +1,75 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Optional
-from datetime import datetime
+from typing import List, Optional
from .._models import BaseModel
-__all__ = ["User", "ProfilePicture"]
+__all__ = ["User", "Balance"]
-class ProfilePicture(BaseModel):
- """The user's profile picture attachment with URL, content type, and file metadata.
+class Balance(BaseModel):
+ """User holdings (crypto and fiat), each with USD value.
- Null if using a legacy profile picture.
+ Empty when `total_usd` is `null`.
"""
- url: Optional[str] = None
- """A pre-optimized URL for rendering this attachment on the client.
+ balance: str
+ """Total amount held in native units, as a decimal string."""
- This should be used for displaying attachments in apps.
+ breakdown: object
+ """
+ Balance split into available, pending, and reserve amounts, as native-unit
+ decimal strings. On-chain crypto is entirely available; good_funds and fiat cash
+ can have pending or reserve portions.
"""
+ icon_url: Optional[str] = None
+ """Holding icon URL."""
-class User(BaseModel):
- """A user account on Whop.
+ name: str
+ """The holding's display name"""
+
+ price_usd: Optional[float] = None
+ """USD price per unit, or `null` when no exchange rate is available."""
+
+ symbol: str
+ """Holding display symbol, such as `USDT`, `cbBTC`, or `EUR`."""
+
+ value_usd: Optional[str] = None
+ """Holding USD value, or `null` when no exchange rate is available."""
- Contains profile information, identity details, and social connections.
- """
+class User(BaseModel):
id: str
- """The unique identifier for the user."""
+ """User ID, prefixed `user_`."""
+
+ balances: List[Balance]
bio: Optional[str] = None
- """A short biography written by the user, displayed on their public profile."""
+ """The user's biography"""
- created_at: datetime
- """The datetime the user was created."""
+ created_at: str
+ """When the user was created, as an ISO 8601 timestamp"""
name: Optional[str] = None
- """The user's display name shown on their public profile."""
+ """The user's display name"""
+
+ profile_picture: Optional[object] = None
+ """The user's profile picture, an object with a url"""
- profile_picture: Optional[ProfilePicture] = None
- """The user's profile picture attachment with URL, content type, and file metadata.
+ total_usd: Optional[str] = None
+ """Total USD value across the user's balances with known exchange rates.
- Null if using a legacy profile picture.
+ Computed only on `GET /users/me` self-view for callers with balance-read scope;
+ `null` otherwise.
"""
username: str
- """The user's unique username shown on their public profile."""
+ """The user's unique username"""
+
+ verification: object
+ """
+ Identity verification status for the user's `individual` (KYC) and `business`
+ (KYB) profiles. Each is `null` until created, otherwise a `status` of
+ `not_started`, `pending`, `approved`, or `rejected`.
+ """
diff --git a/src/whop_sdk/types/user_check_access_response.py b/src/whop_sdk/types/user_check_access_response.py
index 270d822a..ad8fb2fe 100644
--- a/src/whop_sdk/types/user_check_access_response.py
+++ b/src/whop_sdk/types/user_check_access_response.py
@@ -1,16 +1,13 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+from typing_extensions import Literal
+
from .._models import BaseModel
-from .shared.access_level import AccessLevel
__all__ = ["UserCheckAccessResponse"]
class UserCheckAccessResponse(BaseModel):
- """The result of a has access check for the developer API"""
-
- access_level: AccessLevel
- """The permission level of the user"""
+ access_level: Literal["no_access", "admin", "customer"]
has_access: bool
- """Whether the user has access to the resource"""
diff --git a/src/whop_sdk/types/user_list_params.py b/src/whop_sdk/types/user_list_params.py
index bce47d6c..14d3e4fa 100644
--- a/src/whop_sdk/types/user_list_params.py
+++ b/src/whop_sdk/types/user_list_params.py
@@ -2,24 +2,23 @@
from __future__ import annotations
-from typing import Optional
from typing_extensions import TypedDict
__all__ = ["UserListParams"]
class UserListParams(TypedDict, total=False):
- after: Optional[str]
- """Returns the elements in the list that come after the specified cursor."""
+ after: str
+ """A cursor; returns users after this position."""
- before: Optional[str]
- """Returns the elements in the list that come before the specified cursor."""
+ before: str
+ """A cursor; returns users before this position."""
- first: Optional[int]
- """Returns the first _n_ elements from the list."""
+ first: int
+ """The number of users to return (max 50)."""
- last: Optional[int]
- """Returns the last _n_ elements from the list."""
+ last: int
+ """The number of users to return from the end of the range."""
- query: Optional[str]
- """Search term to filter by name or username."""
+ query: str
+ """A search term to filter users by name or username."""
diff --git a/src/whop_sdk/types/user_list_response.py b/src/whop_sdk/types/user_list_response.py
deleted file mode 100644
index 1621e20c..00000000
--- a/src/whop_sdk/types/user_list_response.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-from datetime import datetime
-
-from .._models import BaseModel
-
-__all__ = ["UserListResponse", "ProfilePicture"]
-
-
-class ProfilePicture(BaseModel):
- """The user's profile picture attachment with URL, content type, and file metadata.
-
- Null if using a legacy profile picture.
- """
-
- url: Optional[str] = None
- """A pre-optimized URL for rendering this attachment on the client.
-
- This should be used for displaying attachments in apps.
- """
-
-
-class UserListResponse(BaseModel):
- """A user account on Whop.
-
- Contains profile information, identity details, and social connections.
- """
-
- id: str
- """The unique identifier for the user."""
-
- bio: Optional[str] = None
- """A short biography written by the user, displayed on their public profile."""
-
- created_at: datetime
- """The datetime the user was created."""
-
- name: Optional[str] = None
- """The user's display name shown on their public profile."""
-
- profile_picture: Optional[ProfilePicture] = None
- """The user's profile picture attachment with URL, content type, and file metadata.
-
- Null if using a legacy profile picture.
- """
-
- username: str
- """The user's unique username shown on their public profile."""
diff --git a/src/whop_sdk/types/user_retrieve_params.py b/src/whop_sdk/types/user_retrieve_params.py
index 8534761b..afb9ca68 100644
--- a/src/whop_sdk/types/user_retrieve_params.py
+++ b/src/whop_sdk/types/user_retrieve_params.py
@@ -2,15 +2,14 @@
from __future__ import annotations
-from typing import Optional
from typing_extensions import TypedDict
__all__ = ["UserRetrieveParams"]
class UserRetrieveParams(TypedDict, total=False):
- company_id: Optional[str]
+ account_id: str
"""
- When provided, returns the user's company-specific profile overrides (name,
- profile picture) instead of their global profile.
+ When set, returns the user's account-specific profile overrides for this
+ account.
"""
diff --git a/src/whop_sdk/types/user_update_me_params.py b/src/whop_sdk/types/user_update_me_params.py
new file mode 100644
index 00000000..63a6a725
--- /dev/null
+++ b/src/whop_sdk/types/user_update_me_params.py
@@ -0,0 +1,29 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["UserUpdateMeParams", "ProfilePicture"]
+
+
+class UserUpdateMeParams(TypedDict, total=False):
+ account_id: str
+ """
+ When set, updates the authenticated user's profile override for this account
+ instead of their global profile.
+ """
+
+ bio: str
+
+ name: str
+
+ profile_picture: ProfilePicture
+
+ username: str
+
+
+class ProfilePicture(TypedDict, total=False):
+ id: str
+
+ direct_upload_id: str
diff --git a/src/whop_sdk/types/user_update_params.py b/src/whop_sdk/types/user_update_params.py
index a1c8572a..c957a3c6 100644
--- a/src/whop_sdk/types/user_update_params.py
+++ b/src/whop_sdk/types/user_update_params.py
@@ -2,38 +2,25 @@
from __future__ import annotations
-from typing import Optional
-from typing_extensions import Required, TypedDict
+from typing_extensions import TypedDict
__all__ = ["UserUpdateParams", "ProfilePicture"]
class UserUpdateParams(TypedDict, total=False):
- bio: Optional[str]
- """A short biography displayed on the user's public profile."""
+ account_id: str
+ """The account whose profile override to update. Required for API key callers."""
- company_id: Optional[str]
- """
- When provided, updates the user's profile overrides for this company instead of
- the global profile. Pass name and profile_picture to set overrides, or null to
- clear them.
- """
+ bio: str
- name: Optional[str]
- """The user's display name shown on their public profile. Maximum 100 characters."""
+ name: str
- profile_picture: Optional[ProfilePicture]
- """The user's profile picture image attachment."""
+ profile_picture: ProfilePicture
- username: Optional[str]
- """The user's unique username.
-
- Alphanumeric characters and hyphens only. Maximum 42 characters.
- """
+ username: str
class ProfilePicture(TypedDict, total=False):
- """The user's profile picture image attachment."""
+ id: str
- id: Required[str]
- """The ID of an existing file object."""
+ direct_upload_id: str
diff --git a/src/whop_sdk/types/verification_create_params.py b/src/whop_sdk/types/verification_create_params.py
new file mode 100644
index 00000000..792d5488
--- /dev/null
+++ b/src/whop_sdk/types/verification_create_params.py
@@ -0,0 +1,77 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["VerificationCreateParams"]
+
+
+class VerificationCreateParams(TypedDict, total=False):
+ account_id: Required[str]
+ """The account ID to verify (biz\\__ tag)."""
+
+ address: Dict[str, object]
+ """Optional pre-fill claim. Address (line1, city, state, postal_code)."""
+
+ business_name: str
+ """Optional pre-fill claim for businesses."""
+
+ business_structure: str
+ """Optional. Business structure (e.g. llc, corporation)."""
+
+ business_website: str
+ """Optional.
+
+ Business website URL. Accepted for both individual and business verifications on
+ company accounts; persisted to the account's metadata and used to provision the
+ payout account on approval. Whop store pages are rejected.
+ """
+
+ country: str
+ """Optional pre-fill claim.
+
+ Country code; for businesses, the country of incorporation.
+ """
+
+ date_of_birth: str
+ """Optional pre-fill claim.
+
+ Seeds the Sumsub session; attested values come from Sumsub on approval.
+ """
+
+ first_name: str
+ """Optional pre-fill claim.
+
+ Seeds the Sumsub session; attested values come from Sumsub on approval.
+ """
+
+ kind: Literal["individual", "business"]
+ """The verification type. Defaults to individual."""
+
+ last_name: str
+ """Optional pre-fill claim.
+
+ Seeds the Sumsub session; attested values come from Sumsub on approval.
+ """
+
+ phone: str
+ """Optional pre-fill claim — phone number."""
+
+ place_of_incorporation: str
+ """Optional.
+
+ Place of incorporation (state/region); maps to the business address state.
+ """
+
+ restart: bool
+ """Whether to restart an in-flight verification."""
+
+ tax_identification_number: str
+ """Optional.
+
+ Tax identification number — SSN for individuals, EIN for businesses. Tokenized
+ in transit, never stored raw; stored on the profile so the payout account,
+ provisioned on approval, doesn't raise a tax-id RFI.
+ """
diff --git a/src/whop_sdk/types/verification_create_response.py b/src/whop_sdk/types/verification_create_response.py
new file mode 100644
index 00000000..7b1ed7f6
--- /dev/null
+++ b/src/whop_sdk/types/verification_create_response.py
@@ -0,0 +1,102 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["VerificationCreateResponse", "RequestedInformation", "RequestedInformationRequestedFile"]
+
+
+class RequestedInformationRequestedFile(BaseModel):
+ category: Optional[str] = None
+ """
+ Identifier to send back with the uploaded file so it routes correctly; null for
+ a generic upload.
+ """
+
+ is_optional: Optional[bool] = None
+ """Whether this slot can be left empty."""
+
+ kind: Optional[str] = None
+ """Provider-specific document kind, when applicable."""
+
+ label: Optional[str] = None
+ """Label for this upload slot (e.g. "Front of ID Document")."""
+
+ multiple: Optional[bool] = None
+ """Whether this slot accepts more than one file."""
+
+
+class RequestedInformation(BaseModel):
+ id: Optional[str] = None
+ """The requested information item id (inrqi\\__\\**). Use this when answering."""
+
+ description: Optional[str] = None
+ """Additional guidance for the field beyond the label."""
+
+ error_message: Optional[str] = None
+ """The reason a previously submitted value was rejected, or null."""
+
+ field: Optional[str] = None
+ """Stable snake_case key for the field (e.g. ssn, business_description)."""
+
+ label: Optional[str] = None
+ """Human-readable label for the field (e.g. "Social Security Number")."""
+
+ options: Optional[List[str]] = None
+ """Allowed values for a `select` field (e.g.
+
+ account_type, business_structure) — the submitted value must be one of these;
+ empty for other types.
+ """
+
+ requested_files: Optional[List[RequestedInformationRequestedFile]] = None
+ """
+ Upload slots for a files item — always at least one when type is `files`, empty
+ otherwise.
+ """
+
+ type: Optional[str] = None
+ """How to render the input: text, date, phone, address, files, or select."""
+
+
+class VerificationCreateResponse(BaseModel):
+ id: Optional[str] = None
+ """The verification ID, e.g. idpf\\__\\**"""
+
+ address: Optional[object] = None
+
+ business_name: Optional[str] = None
+
+ business_structure: Optional[str] = None
+
+ country: Optional[str] = None
+ """ISO 3166-1 alpha-2 country code (e.g.
+
+ `US`, `GB`). For individuals this is the country of citizenship or residence
+ reported by the identity provider; for businesses this is the country of
+ incorporation.
+ """
+
+ created_at: Optional[str] = None
+
+ date_of_birth: Optional[str] = None
+
+ first_name: Optional[str] = None
+
+ kind: Optional[Literal["individual", "business"]] = None
+
+ last_name: Optional[str] = None
+
+ requested_information: Optional[List[RequestedInformation]] = None
+ """
+ The outstanding information this verification still needs — payout RFIs and
+ audit RMIs, one uniform shape.
+ """
+
+ session_url: Optional[str] = None
+
+ status: Optional[Literal["not_started", "pending", "approved", "rejected", "action_required"]] = None
+
+ updated_at: Optional[str] = None
diff --git a/src/whop_sdk/types/verification_delete_response.py b/src/whop_sdk/types/verification_delete_response.py
new file mode 100644
index 00000000..3448aef4
--- /dev/null
+++ b/src/whop_sdk/types/verification_delete_response.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from .._models import BaseModel
+
+__all__ = ["VerificationDeleteResponse"]
+
+
+class VerificationDeleteResponse(BaseModel):
+ id: Optional[str] = None
+
+ deleted: Optional[bool] = None
diff --git a/src/whop_sdk/types/verification_list_params.py b/src/whop_sdk/types/verification_list_params.py
index 64ad9314..16f6863a 100644
--- a/src/whop_sdk/types/verification_list_params.py
+++ b/src/whop_sdk/types/verification_list_params.py
@@ -2,24 +2,17 @@
from __future__ import annotations
-from typing import Optional
-from typing_extensions import Required, TypedDict
+from typing_extensions import Literal, Required, TypedDict
__all__ = ["VerificationListParams"]
class VerificationListParams(TypedDict, total=False):
- payout_account_id: Required[str]
- """The unique identifier of the payout account to list verifications for."""
+ account_id: Required[str]
+ """The account ID to list verifications for (biz\\__ tag)."""
- after: Optional[str]
- """Returns the elements in the list that come after the specified cursor."""
+ direction: Literal["asc", "desc"]
+ """Sort direction."""
- 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."""
+ order: Literal["updated_at", "created_at"]
+ """The field to sort verifications by."""
diff --git a/src/whop_sdk/types/verification_list_response.py b/src/whop_sdk/types/verification_list_response.py
index 25d3f1e6..291e8248 100644
--- a/src/whop_sdk/types/verification_list_response.py
+++ b/src/whop_sdk/types/verification_list_response.py
@@ -1,30 +1,106 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Optional
+from typing import List, Optional
+from typing_extensions import Literal
from .._models import BaseModel
-from .verification_status import VerificationStatus
-from .verification_error_code import VerificationErrorCode
-__all__ = ["VerificationListResponse"]
+__all__ = ["VerificationListResponse", "Data", "DataRequestedInformation", "DataRequestedInformationRequestedFile"]
-class VerificationListResponse(BaseModel):
+class DataRequestedInformationRequestedFile(BaseModel):
+ category: Optional[str] = None
+ """
+ Identifier to send back with the uploaded file so it routes correctly; null for
+ a generic upload.
+ """
+
+ is_optional: Optional[bool] = None
+ """Whether this slot can be left empty."""
+
+ kind: Optional[str] = None
+ """Provider-specific document kind, when applicable."""
+
+ label: Optional[str] = None
+ """Label for this upload slot (e.g. "Front of ID Document")."""
+
+ multiple: Optional[bool] = None
+ """Whether this slot accepts more than one file."""
+
+
+class DataRequestedInformation(BaseModel):
+ id: Optional[str] = None
+ """The requested information item id (inrqi\\__\\**). Use this when answering."""
+
+ description: Optional[str] = None
+ """Additional guidance for the field beyond the label."""
+
+ error_message: Optional[str] = None
+ """The reason a previously submitted value was rejected, or null."""
+
+ field: Optional[str] = None
+ """Stable snake_case key for the field (e.g. ssn, business_description)."""
+
+ label: Optional[str] = None
+ """Human-readable label for the field (e.g. "Social Security Number")."""
+
+ options: Optional[List[str]] = None
+ """Allowed values for a `select` field (e.g.
+
+ account_type, business_structure) — the submitted value must be one of these;
+ empty for other types.
+ """
+
+ requested_files: Optional[List[DataRequestedInformationRequestedFile]] = None
"""
- An identity verification session used to confirm a person or entity's identity for payout account eligibility.
+ Upload slots for a files item — always at least one when type is `files`, empty
+ otherwise.
"""
- id: str
- """The numeric id of the verification record."""
+ type: Optional[str] = None
+ """How to render the input: text, date, phone, address, files, or select."""
- last_error_code: Optional[VerificationErrorCode] = None
- """An error code for a verification attempt."""
- last_error_reason: Optional[str] = None
- """A human-readable explanation of the most recent verification error.
+class Data(BaseModel):
+ id: Optional[str] = None
+ """The verification ID, e.g. idpf\\__\\**"""
- Null if no error has occurred.
+ address: Optional[object] = None
+
+ business_name: Optional[str] = None
+
+ business_structure: Optional[str] = None
+
+ country: Optional[str] = None
+ """ISO 3166-1 alpha-2 country code (e.g.
+
+ `US`, `GB`). For individuals this is the country of citizenship or residence
+ reported by the identity provider; for businesses this is the country of
+ incorporation.
"""
- status: VerificationStatus
- """The current status of this verification session."""
+ created_at: Optional[str] = None
+
+ date_of_birth: Optional[str] = None
+
+ first_name: Optional[str] = None
+
+ kind: Optional[Literal["individual", "business"]] = None
+
+ last_name: Optional[str] = None
+
+ requested_information: Optional[List[DataRequestedInformation]] = None
+ """
+ The outstanding information this verification still needs — payout RFIs and
+ audit RMIs, one uniform shape.
+ """
+
+ session_url: Optional[str] = None
+
+ status: Optional[Literal["not_started", "pending", "approved", "rejected", "action_required"]] = None
+
+ updated_at: Optional[str] = None
+
+
+class VerificationListResponse(BaseModel):
+ data: Optional[List[Data]] = None
diff --git a/src/whop_sdk/types/verification_retrieve_response.py b/src/whop_sdk/types/verification_retrieve_response.py
index 9228eef9..7ece0005 100644
--- a/src/whop_sdk/types/verification_retrieve_response.py
+++ b/src/whop_sdk/types/verification_retrieve_response.py
@@ -1,30 +1,102 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Optional
+from typing import List, Optional
+from typing_extensions import Literal
from .._models import BaseModel
-from .verification_status import VerificationStatus
-from .verification_error_code import VerificationErrorCode
-__all__ = ["VerificationRetrieveResponse"]
+__all__ = ["VerificationRetrieveResponse", "RequestedInformation", "RequestedInformationRequestedFile"]
-class VerificationRetrieveResponse(BaseModel):
+class RequestedInformationRequestedFile(BaseModel):
+ category: Optional[str] = None
+ """
+ Identifier to send back with the uploaded file so it routes correctly; null for
+ a generic upload.
+ """
+
+ is_optional: Optional[bool] = None
+ """Whether this slot can be left empty."""
+
+ kind: Optional[str] = None
+ """Provider-specific document kind, when applicable."""
+
+ label: Optional[str] = None
+ """Label for this upload slot (e.g. "Front of ID Document")."""
+
+ multiple: Optional[bool] = None
+ """Whether this slot accepts more than one file."""
+
+
+class RequestedInformation(BaseModel):
+ id: Optional[str] = None
+ """The requested information item id (inrqi\\__\\**). Use this when answering."""
+
+ description: Optional[str] = None
+ """Additional guidance for the field beyond the label."""
+
+ error_message: Optional[str] = None
+ """The reason a previously submitted value was rejected, or null."""
+
+ field: Optional[str] = None
+ """Stable snake_case key for the field (e.g. ssn, business_description)."""
+
+ label: Optional[str] = None
+ """Human-readable label for the field (e.g. "Social Security Number")."""
+
+ options: Optional[List[str]] = None
+ """Allowed values for a `select` field (e.g.
+
+ account_type, business_structure) — the submitted value must be one of these;
+ empty for other types.
+ """
+
+ requested_files: Optional[List[RequestedInformationRequestedFile]] = None
+ """
+ Upload slots for a files item — always at least one when type is `files`, empty
+ otherwise.
"""
- An identity verification session used to confirm a person or entity's identity for payout account eligibility.
+
+ type: Optional[str] = None
+ """How to render the input: text, date, phone, address, files, or select."""
+
+
+class VerificationRetrieveResponse(BaseModel):
+ id: Optional[str] = None
+ """The verification ID, e.g. idpf\\__\\**"""
+
+ address: Optional[object] = None
+
+ business_name: Optional[str] = None
+
+ business_structure: Optional[str] = None
+
+ country: Optional[str] = None
+ """ISO 3166-1 alpha-2 country code (e.g.
+
+ `US`, `GB`). For individuals this is the country of citizenship or residence
+ reported by the identity provider; for businesses this is the country of
+ incorporation.
"""
- id: str
- """The numeric id of the verification record."""
+ created_at: Optional[str] = None
+
+ date_of_birth: Optional[str] = None
- last_error_code: Optional[VerificationErrorCode] = None
- """An error code for a verification attempt."""
+ first_name: Optional[str] = None
- last_error_reason: Optional[str] = None
- """A human-readable explanation of the most recent verification error.
+ kind: Optional[Literal["individual", "business"]] = None
- Null if no error has occurred.
+ last_name: Optional[str] = None
+
+ requested_information: Optional[List[RequestedInformation]] = None
+ """
+ The outstanding information this verification still needs — payout RFIs and
+ audit RMIs, one uniform shape.
"""
- status: VerificationStatus
- """The current status of this verification session."""
+ session_url: Optional[str] = None
+
+ status: Optional[Literal["not_started", "pending", "approved", "rejected", "action_required"]] = None
+
+ updated_at: Optional[str] = None
diff --git a/src/whop_sdk/types/verification_update_params.py b/src/whop_sdk/types/verification_update_params.py
new file mode 100644
index 00000000..41b64f0a
--- /dev/null
+++ b/src/whop_sdk/types/verification_update_params.py
@@ -0,0 +1,57 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, Iterable
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["VerificationUpdateParams", "RequestedInformation"]
+
+
+class VerificationUpdateParams(TypedDict, total=False):
+ business_address: Dict[str, object]
+ """The business address."""
+
+ business_name: str
+ """The business name."""
+
+ business_structure: str
+ """The business structure."""
+
+ country: str
+ """The country code."""
+
+ date_of_birth: str
+ """The date of birth."""
+
+ first_name: str
+ """The first name on the verification."""
+
+ last_name: str
+ """The last name on the verification."""
+
+ personal_address: Dict[str, object]
+ """The personal address."""
+
+ requested_information: Iterable[RequestedInformation]
+ """Answers to requested information.
+
+ Each entry must include id and a value, address, or files payload.
+ """
+
+
+class RequestedInformation(TypedDict, total=False):
+ id: Required[str]
+ """The requested information item id (inrqi\\__\\**)."""
+
+ address: Dict[str, object]
+ """Address payload for address items."""
+
+ files: Iterable[object]
+ """File upload payload for document items."""
+
+ value: str
+ """The value for text/date/phone items."""
+
+ value_type: Literal["raw", "vault_token"]
+ """Defaults to the field's configured type."""
diff --git a/src/whop_sdk/types/verification_update_response.py b/src/whop_sdk/types/verification_update_response.py
new file mode 100644
index 00000000..3175d889
--- /dev/null
+++ b/src/whop_sdk/types/verification_update_response.py
@@ -0,0 +1,102 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["VerificationUpdateResponse", "RequestedInformation", "RequestedInformationRequestedFile"]
+
+
+class RequestedInformationRequestedFile(BaseModel):
+ category: Optional[str] = None
+ """
+ Identifier to send back with the uploaded file so it routes correctly; null for
+ a generic upload.
+ """
+
+ is_optional: Optional[bool] = None
+ """Whether this slot can be left empty."""
+
+ kind: Optional[str] = None
+ """Provider-specific document kind, when applicable."""
+
+ label: Optional[str] = None
+ """Label for this upload slot (e.g. "Front of ID Document")."""
+
+ multiple: Optional[bool] = None
+ """Whether this slot accepts more than one file."""
+
+
+class RequestedInformation(BaseModel):
+ id: Optional[str] = None
+ """The requested information item id (inrqi\\__\\**). Use this when answering."""
+
+ description: Optional[str] = None
+ """Additional guidance for the field beyond the label."""
+
+ error_message: Optional[str] = None
+ """The reason a previously submitted value was rejected, or null."""
+
+ field: Optional[str] = None
+ """Stable snake_case key for the field (e.g. ssn, business_description)."""
+
+ label: Optional[str] = None
+ """Human-readable label for the field (e.g. "Social Security Number")."""
+
+ options: Optional[List[str]] = None
+ """Allowed values for a `select` field (e.g.
+
+ account_type, business_structure) — the submitted value must be one of these;
+ empty for other types.
+ """
+
+ requested_files: Optional[List[RequestedInformationRequestedFile]] = None
+ """
+ Upload slots for a files item — always at least one when type is `files`, empty
+ otherwise.
+ """
+
+ type: Optional[str] = None
+ """How to render the input: text, date, phone, address, files, or select."""
+
+
+class VerificationUpdateResponse(BaseModel):
+ id: Optional[str] = None
+ """The verification ID, e.g. idpf\\__\\**"""
+
+ address: Optional[object] = None
+
+ business_name: Optional[str] = None
+
+ business_structure: Optional[str] = None
+
+ country: Optional[str] = None
+ """ISO 3166-1 alpha-2 country code (e.g.
+
+ `US`, `GB`). For individuals this is the country of citizenship or residence
+ reported by the identity provider; for businesses this is the country of
+ incorporation.
+ """
+
+ created_at: Optional[str] = None
+
+ date_of_birth: Optional[str] = None
+
+ first_name: Optional[str] = None
+
+ kind: Optional[Literal["individual", "business"]] = None
+
+ last_name: Optional[str] = None
+
+ requested_information: Optional[List[RequestedInformation]] = None
+ """
+ The outstanding information this verification still needs — payout RFIs and
+ audit RMIs, one uniform shape.
+ """
+
+ session_url: Optional[str] = None
+
+ status: Optional[Literal["not_started", "pending", "approved", "rejected", "action_required"]] = None
+
+ updated_at: Optional[str] = None
diff --git a/src/whop_sdk/types/wallet_balance_response.py b/src/whop_sdk/types/wallet_balance_response.py
deleted file mode 100644
index c88cc393..00000000
--- a/src/whop_sdk/types/wallet_balance_response.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List, Optional
-from typing_extensions import Literal
-
-from .._models import BaseModel
-
-__all__ = ["WalletBalanceResponse", "Token"]
-
-
-class Token(BaseModel):
- balance: str
-
- icon_url: Optional[str] = None
-
- name: str
-
- price_usd: float
-
- symbol: str
-
- token_address: Optional[str] = None
-
- value_usd: str
-
-
-class WalletBalanceResponse(BaseModel):
- object: Literal["balance"]
-
- tokens: List[Token]
-
- total_usd: str
diff --git a/src/whop_sdk/types/wallet_list_response.py b/src/whop_sdk/types/wallet_list_response.py
deleted file mode 100644
index 2527d869..00000000
--- a/src/whop_sdk/types/wallet_list_response.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List
-
-from .._models import BaseModel
-
-__all__ = ["WalletListResponse", "Wallet"]
-
-
-class Wallet(BaseModel):
- address: str
-
- balance_usd: str
-
- network: str
-
-
-class WalletListResponse(BaseModel):
- wallets: List[Wallet]
diff --git a/src/whop_sdk/types/wallet_send_params.py b/src/whop_sdk/types/wallet_send_params.py
deleted file mode 100644
index 03889c27..00000000
--- a/src/whop_sdk/types/wallet_send_params.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Required, TypedDict
-
-__all__ = ["WalletSendParams"]
-
-
-class WalletSendParams(TypedDict, total=False):
- amount: Required[str]
- """USDT amount to send."""
-
- to: Required[str]
- """Recipient user ID, business account ID, ledger account ID, or email."""
diff --git a/src/whop_sdk/types/wallet_send_response.py b/src/whop_sdk/types/wallet_send_response.py
deleted file mode 100644
index 5db26b85..00000000
--- a/src/whop_sdk/types/wallet_send_response.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing_extensions import Literal
-
-from .._models import BaseModel
-
-__all__ = ["WalletSendResponse", "Destination", "Source"]
-
-
-class Destination(BaseModel):
- account_id: str
-
- address: str
-
-
-class Source(BaseModel):
- account_id: str
-
- address: str
-
-
-class WalletSendResponse(BaseModel):
- amount: str
-
- currency: str
-
- destination: Destination
-
- object: Literal["send"]
-
- source: Source
-
- tx_hash: str
diff --git a/src/whop_sdk/types/webhook_event.py b/src/whop_sdk/types/webhook_event.py
index 3b76647a..7167e81a 100644
--- a/src/whop_sdk/types/webhook_event.py
+++ b/src/whop_sdk/types/webhook_event.py
@@ -12,6 +12,7 @@
"invoice.voided",
"membership.activated",
"membership.deactivated",
+ "membership.trial_ending_soon",
"entry.created",
"entry.approved",
"entry.denied",
@@ -19,6 +20,7 @@
"setup_intent.requires_action",
"setup_intent.succeeded",
"setup_intent.canceled",
+ "ledger_account.funds_available",
"withdrawal.created",
"withdrawal.updated",
"course_lesson_interaction.completed",
@@ -32,6 +34,8 @@
"resolution_center_case.created",
"resolution_center_case.updated",
"resolution_center_case.decided",
+ "chat.message.created",
+ "chat.reaction.created",
"payment.created",
"payment.succeeded",
"payment.failed",
diff --git a/src/whop_sdk/types/withdrawal_create_params.py b/src/whop_sdk/types/withdrawal_create_params.py
index 46d134f2..3345abab 100644
--- a/src/whop_sdk/types/withdrawal_create_params.py
+++ b/src/whop_sdk/types/withdrawal_create_params.py
@@ -24,7 +24,7 @@ class WithdrawalCreateParams(TypedDict, total=False):
"""The ID of the payout method to use for the withdrawal."""
platform_covers_fees: Optional[bool]
- """Whether the platform covers the payout fees instead of the connected account."""
+ """Whether the platform covers the payout fees."""
statement_descriptor: Optional[str]
"""Custom statement descriptor for the withdrawal.
diff --git a/tests/api_resources/referrals/__init__.py b/tests/api_resources/referrals/__init__.py
new file mode 100644
index 00000000..fd8019a9
--- /dev/null
+++ b/tests/api_resources/referrals/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/referrals/businesses/__init__.py b/tests/api_resources/referrals/businesses/__init__.py
new file mode 100644
index 00000000..fd8019a9
--- /dev/null
+++ b/tests/api_resources/referrals/businesses/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/referrals/businesses/test_earnings.py b/tests/api_resources/referrals/businesses/test_earnings.py
new file mode 100644
index 00000000..433278eb
--- /dev/null
+++ b/tests/api_resources/referrals/businesses/test_earnings.py
@@ -0,0 +1,139 @@
+# 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.referrals.businesses import EarningListResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestEarnings:
+ 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_list(self, client: Whop) -> None:
+ earning = client.referrals.businesses.earnings.list(
+ id="id",
+ )
+ assert_matches_type(SyncCursorPage[EarningListResponse], earning, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Whop) -> None:
+ earning = client.referrals.businesses.earnings.list(
+ id="id",
+ after="after",
+ before="before",
+ direction="asc",
+ first=100,
+ last=100,
+ order="created_at",
+ status="awaiting_settlement",
+ )
+ assert_matches_type(SyncCursorPage[EarningListResponse], earning, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Whop) -> None:
+ response = client.referrals.businesses.earnings.with_raw_response.list(
+ id="id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ earning = response.parse()
+ assert_matches_type(SyncCursorPage[EarningListResponse], earning, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Whop) -> None:
+ with client.referrals.businesses.earnings.with_streaming_response.list(
+ id="id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ earning = response.parse()
+ assert_matches_type(SyncCursorPage[EarningListResponse], earning, 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.referrals.businesses.earnings.with_raw_response.list(
+ id="",
+ )
+
+
+class TestAsyncEarnings:
+ 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_list(self, async_client: AsyncWhop) -> None:
+ earning = await async_client.referrals.businesses.earnings.list(
+ id="id",
+ )
+ assert_matches_type(AsyncCursorPage[EarningListResponse], earning, 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:
+ earning = await async_client.referrals.businesses.earnings.list(
+ id="id",
+ after="after",
+ before="before",
+ direction="asc",
+ first=100,
+ last=100,
+ order="created_at",
+ status="awaiting_settlement",
+ )
+ assert_matches_type(AsyncCursorPage[EarningListResponse], earning, 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.referrals.businesses.earnings.with_raw_response.list(
+ id="id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ earning = await response.parse()
+ assert_matches_type(AsyncCursorPage[EarningListResponse], earning, 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.referrals.businesses.earnings.with_streaming_response.list(
+ id="id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ earning = await response.parse()
+ assert_matches_type(AsyncCursorPage[EarningListResponse], earning, 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.referrals.businesses.earnings.with_raw_response.list(
+ id="",
+ )
diff --git a/tests/api_resources/referrals/test_businesses.py b/tests/api_resources/referrals/test_businesses.py
new file mode 100644
index 00000000..50fe7301
--- /dev/null
+++ b/tests/api_resources/referrals/test_businesses.py
@@ -0,0 +1,283 @@
+# 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.referrals import (
+ BusinessListResponse,
+ BusinessRetrieveResponse,
+ BusinessListEarningsResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestBusinesses:
+ 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_retrieve(self, client: Whop) -> None:
+ business = client.referrals.businesses.retrieve(
+ "id",
+ )
+ assert_matches_type(BusinessRetrieveResponse, business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_retrieve(self, client: Whop) -> None:
+ response = client.referrals.businesses.with_raw_response.retrieve(
+ "id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ business = response.parse()
+ assert_matches_type(BusinessRetrieveResponse, business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Whop) -> None:
+ with client.referrals.businesses.with_streaming_response.retrieve(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ business = response.parse()
+ assert_matches_type(BusinessRetrieveResponse, business, 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.referrals.businesses.with_raw_response.retrieve(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Whop) -> None:
+ business = client.referrals.businesses.list()
+ assert_matches_type(SyncCursorPage[BusinessListResponse], business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Whop) -> None:
+ business = client.referrals.businesses.list(
+ after="after",
+ before="before",
+ direction="asc",
+ first=100,
+ has_earnings=True,
+ last=100,
+ order="created_at",
+ status="active",
+ )
+ assert_matches_type(SyncCursorPage[BusinessListResponse], business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Whop) -> None:
+ response = client.referrals.businesses.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ business = response.parse()
+ assert_matches_type(SyncCursorPage[BusinessListResponse], business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Whop) -> None:
+ with client.referrals.businesses.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ business = response.parse()
+ assert_matches_type(SyncCursorPage[BusinessListResponse], business, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_earnings(self, client: Whop) -> None:
+ business = client.referrals.businesses.list_earnings()
+ assert_matches_type(SyncCursorPage[BusinessListEarningsResponse], business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_earnings_with_all_params(self, client: Whop) -> None:
+ business = client.referrals.businesses.list_earnings(
+ after="after",
+ before="before",
+ direction="asc",
+ first=100,
+ last=100,
+ order="created_at",
+ status="awaiting_settlement",
+ )
+ assert_matches_type(SyncCursorPage[BusinessListEarningsResponse], business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list_earnings(self, client: Whop) -> None:
+ response = client.referrals.businesses.with_raw_response.list_earnings()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ business = response.parse()
+ assert_matches_type(SyncCursorPage[BusinessListEarningsResponse], business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list_earnings(self, client: Whop) -> None:
+ with client.referrals.businesses.with_streaming_response.list_earnings() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ business = response.parse()
+ assert_matches_type(SyncCursorPage[BusinessListEarningsResponse], business, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncBusinesses:
+ 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_retrieve(self, async_client: AsyncWhop) -> None:
+ business = await async_client.referrals.businesses.retrieve(
+ "id",
+ )
+ assert_matches_type(BusinessRetrieveResponse, business, 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.referrals.businesses.with_raw_response.retrieve(
+ "id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ business = await response.parse()
+ assert_matches_type(BusinessRetrieveResponse, business, 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.referrals.businesses.with_streaming_response.retrieve(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ business = await response.parse()
+ assert_matches_type(BusinessRetrieveResponse, business, 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.referrals.businesses.with_raw_response.retrieve(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncWhop) -> None:
+ business = await async_client.referrals.businesses.list()
+ assert_matches_type(AsyncCursorPage[BusinessListResponse], business, 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:
+ business = await async_client.referrals.businesses.list(
+ after="after",
+ before="before",
+ direction="asc",
+ first=100,
+ has_earnings=True,
+ last=100,
+ order="created_at",
+ status="active",
+ )
+ assert_matches_type(AsyncCursorPage[BusinessListResponse], business, 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.referrals.businesses.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ business = await response.parse()
+ assert_matches_type(AsyncCursorPage[BusinessListResponse], business, 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.referrals.businesses.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ business = await response.parse()
+ assert_matches_type(AsyncCursorPage[BusinessListResponse], business, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list_earnings(self, async_client: AsyncWhop) -> None:
+ business = await async_client.referrals.businesses.list_earnings()
+ assert_matches_type(AsyncCursorPage[BusinessListEarningsResponse], business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list_earnings_with_all_params(self, async_client: AsyncWhop) -> None:
+ business = await async_client.referrals.businesses.list_earnings(
+ after="after",
+ before="before",
+ direction="asc",
+ first=100,
+ last=100,
+ order="created_at",
+ status="awaiting_settlement",
+ )
+ assert_matches_type(AsyncCursorPage[BusinessListEarningsResponse], business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_list_earnings(self, async_client: AsyncWhop) -> None:
+ response = await async_client.referrals.businesses.with_raw_response.list_earnings()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ business = await response.parse()
+ assert_matches_type(AsyncCursorPage[BusinessListEarningsResponse], business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_list_earnings(self, async_client: AsyncWhop) -> None:
+ async with async_client.referrals.businesses.with_streaming_response.list_earnings() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ business = await response.parse()
+ assert_matches_type(AsyncCursorPage[BusinessListEarningsResponse], business, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_accounts.py b/tests/api_resources/test_accounts.py
index 11810569..51d5ab34 100644
--- a/tests/api_resources/test_accounts.py
+++ b/tests/api_resources/test_accounts.py
@@ -9,10 +9,8 @@
from whop_sdk import Whop, AsyncWhop
from tests.utils import assert_matches_type
-from whop_sdk.types import (
- Account,
- AccountListResponse,
-)
+from whop_sdk.types import Account
+from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -115,18 +113,48 @@ def test_method_update_with_all_params(self, client: Whop) -> None:
affiliate_application_required=True,
affiliate_instructions="affiliate_instructions",
banner_image={"foo": "bar"},
+ business_address={
+ "city": "city",
+ "country": "country",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
business_type="business_type",
+ country="country",
description="description",
featured_affiliate_product_id="featured_affiliate_product_id",
+ home_preferences=["string"],
industry_group="industry_group",
industry_type="industry_type",
+ invoice_prefix="invoice_prefix",
logo={"foo": "bar"},
metadata={"foo": "bar"},
+ onboarding_type="onboarding_type",
+ opengraph_image={"foo": "bar"},
+ opengraph_image_variant="opengraph_image_variant",
+ other_business_description="other_business_description",
+ other_industry_description="other_industry_description",
+ product_tax_code_id="product_tax_code_id",
+ require_2fa=True,
route="route",
send_customer_emails=True,
+ show_joined_whops=True,
+ show_reviews_dtc=True,
+ show_user_directory=True,
social_links=[{"foo": "bar"}],
+ store_page_config={"foo": "bar"},
target_audience="target_audience",
+ tax_identifiers=[
+ {
+ "tax_id_type": "ad_nrt",
+ "tax_id_value": "tax_id_value",
+ }
+ ],
+ tax_remitted_by="whop",
title="title",
+ use_logo_as_opengraph_image_fallback=True,
)
assert_matches_type(Account, account, path=["response"])
@@ -168,16 +196,20 @@ def test_path_params_update(self, client: Whop) -> None:
@parametrize
def test_method_list(self, client: Whop) -> None:
account = client.accounts.list()
- assert_matches_type(AccountListResponse, account, path=["response"])
+ assert_matches_type(SyncCursorPage[Account], account, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_list_with_all_params(self, client: Whop) -> None:
account = client.accounts.list(
- page=0,
- per=0,
+ after="after",
+ before="before",
+ direction="asc",
+ first=0,
+ last=0,
+ order="created_at",
)
- assert_matches_type(AccountListResponse, account, path=["response"])
+ assert_matches_type(SyncCursorPage[Account], account, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -187,7 +219,7 @@ def test_raw_response_list(self, client: Whop) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
account = response.parse()
- assert_matches_type(AccountListResponse, account, path=["response"])
+ assert_matches_type(SyncCursorPage[Account], account, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -197,7 +229,7 @@ def test_streaming_response_list(self, client: Whop) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
account = response.parse()
- assert_matches_type(AccountListResponse, account, path=["response"])
+ assert_matches_type(SyncCursorPage[Account], account, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -330,18 +362,48 @@ async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> N
affiliate_application_required=True,
affiliate_instructions="affiliate_instructions",
banner_image={"foo": "bar"},
+ business_address={
+ "city": "city",
+ "country": "country",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
business_type="business_type",
+ country="country",
description="description",
featured_affiliate_product_id="featured_affiliate_product_id",
+ home_preferences=["string"],
industry_group="industry_group",
industry_type="industry_type",
+ invoice_prefix="invoice_prefix",
logo={"foo": "bar"},
metadata={"foo": "bar"},
+ onboarding_type="onboarding_type",
+ opengraph_image={"foo": "bar"},
+ opengraph_image_variant="opengraph_image_variant",
+ other_business_description="other_business_description",
+ other_industry_description="other_industry_description",
+ product_tax_code_id="product_tax_code_id",
+ require_2fa=True,
route="route",
send_customer_emails=True,
+ show_joined_whops=True,
+ show_reviews_dtc=True,
+ show_user_directory=True,
social_links=[{"foo": "bar"}],
+ store_page_config={"foo": "bar"},
target_audience="target_audience",
+ tax_identifiers=[
+ {
+ "tax_id_type": "ad_nrt",
+ "tax_id_value": "tax_id_value",
+ }
+ ],
+ tax_remitted_by="whop",
title="title",
+ use_logo_as_opengraph_image_fallback=True,
)
assert_matches_type(Account, account, path=["response"])
@@ -383,16 +445,20 @@ async def test_path_params_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_list(self, async_client: AsyncWhop) -> None:
account = await async_client.accounts.list()
- assert_matches_type(AccountListResponse, account, path=["response"])
+ assert_matches_type(AsyncCursorPage[Account], account, 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:
account = await async_client.accounts.list(
- page=0,
- per=0,
+ after="after",
+ before="before",
+ direction="asc",
+ first=0,
+ last=0,
+ order="created_at",
)
- assert_matches_type(AccountListResponse, account, path=["response"])
+ assert_matches_type(AsyncCursorPage[Account], account, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -402,7 +468,7 @@ async def test_raw_response_list(self, async_client: AsyncWhop) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
account = await response.parse()
- assert_matches_type(AccountListResponse, account, path=["response"])
+ assert_matches_type(AsyncCursorPage[Account], account, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -412,7 +478,7 @@ async def test_streaming_response_list(self, async_client: AsyncWhop) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
account = await response.parse()
- assert_matches_type(AccountListResponse, account, path=["response"])
+ assert_matches_type(AsyncCursorPage[Account], account, path=["response"])
assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_ad_campaigns.py b/tests/api_resources/test_ad_campaigns.py
index 4c818bf8..2abd73d5 100644
--- a/tests/api_resources/test_ad_campaigns.py
+++ b/tests/api_resources/test_ad_campaigns.py
@@ -11,9 +11,8 @@
from tests.utils import assert_matches_type
from whop_sdk.types import (
AdCampaign,
- AdCampaignListResponse,
+ AdCampaignDeleteResponse,
)
-from whop_sdk._utils import parse_datetime
from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -22,11 +21,80 @@
class TestAdCampaigns:
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:
+ ad_campaign = client.ad_campaigns.create(
+ objective="awareness",
+ platform="meta",
+ title="title",
+ )
+ assert_matches_type(AdCampaign, ad_campaign, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: Whop) -> None:
+ ad_campaign = client.ad_campaigns.create(
+ objective="awareness",
+ platform="meta",
+ title="title",
+ account_id="account_id",
+ bid_type="minimum_cost",
+ budget_amount=0,
+ budget_optimization="ad_campaign",
+ budget_type="daily",
+ desired_cost_per_result=0,
+ ends_at="ends_at",
+ special_ad_categories=["housing"],
+ starts_at="starts_at",
+ )
+ assert_matches_type(AdCampaign, ad_campaign, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Whop) -> None:
+ response = client.ad_campaigns.with_raw_response.create(
+ objective="awareness",
+ platform="meta",
+ title="title",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ad_campaign = response.parse()
+ assert_matches_type(AdCampaign, ad_campaign, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Whop) -> None:
+ with client.ad_campaigns.with_streaming_response.create(
+ objective="awareness",
+ platform="meta",
+ title="title",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ad_campaign = response.parse()
+ assert_matches_type(AdCampaign, ad_campaign, 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:
ad_campaign = client.ad_campaigns.retrieve(
- "adcamp_xxxxxxxxxxx",
+ id="id",
+ )
+ assert_matches_type(AdCampaign, ad_campaign, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_retrieve_with_all_params(self, client: Whop) -> None:
+ ad_campaign = client.ad_campaigns.retrieve(
+ id="id",
+ stats_from="stats_from",
+ stats_to="stats_to",
)
assert_matches_type(AdCampaign, ad_campaign, path=["response"])
@@ -34,7 +102,7 @@ def test_method_retrieve(self, client: Whop) -> None:
@parametrize
def test_raw_response_retrieve(self, client: Whop) -> None:
response = client.ad_campaigns.with_raw_response.retrieve(
- "adcamp_xxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -46,7 +114,7 @@ def test_raw_response_retrieve(self, client: Whop) -> None:
@parametrize
def test_streaming_response_retrieve(self, client: Whop) -> None:
with client.ad_campaigns.with_streaming_response.retrieve(
- "adcamp_xxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -61,14 +129,14 @@ def test_streaming_response_retrieve(self, client: Whop) -> None:
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.ad_campaigns.with_raw_response.retrieve(
- "",
+ id="",
)
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_update(self, client: Whop) -> None:
ad_campaign = client.ad_campaigns.update(
- id="adcamp_xxxxxxxxxxx",
+ id="id",
)
assert_matches_type(AdCampaign, ad_campaign, path=["response"])
@@ -76,8 +144,12 @@ def test_method_update(self, client: Whop) -> None:
@parametrize
def test_method_update_with_all_params(self, client: Whop) -> None:
ad_campaign = client.ad_campaigns.update(
- id="adcamp_xxxxxxxxxxx",
- budget=6.9,
+ id="id",
+ budget_amount=0,
+ ends_at="ends_at",
+ starts_at="starts_at",
+ status="active",
+ title="title",
)
assert_matches_type(AdCampaign, ad_campaign, path=["response"])
@@ -85,7 +157,7 @@ def test_method_update_with_all_params(self, client: Whop) -> None:
@parametrize
def test_raw_response_update(self, client: Whop) -> None:
response = client.ad_campaigns.with_raw_response.update(
- id="adcamp_xxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -97,7 +169,7 @@ def test_raw_response_update(self, client: Whop) -> None:
@parametrize
def test_streaming_response_update(self, client: Whop) -> None:
with client.ad_campaigns.with_streaming_response.update(
- id="adcamp_xxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -119,23 +191,27 @@ def test_path_params_update(self, client: Whop) -> None:
@parametrize
def test_method_list(self, client: Whop) -> None:
ad_campaign = client.ad_campaigns.list()
- assert_matches_type(SyncCursorPage[AdCampaignListResponse], ad_campaign, path=["response"])
+ assert_matches_type(SyncCursorPage[AdCampaign], ad_campaign, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_list_with_all_params(self, client: Whop) -> None:
ad_campaign = client.ad_campaigns.list(
+ account_id="account_id",
after="after",
before="before",
- company_id="biz_xxxxxxxxxxxxxx",
- created_after=parse_datetime("2023-12-01T05:00:00.401Z"),
- created_before=parse_datetime("2023-12-01T05:00:00.401Z"),
- first=42,
- last=42,
+ created_after="created_after",
+ created_before="created_before",
+ direction="asc",
+ first=100,
+ last=100,
+ order="created_at",
query="query",
- status="active",
+ stats_from="stats_from",
+ stats_to="stats_to",
+ status="draft",
)
- assert_matches_type(SyncCursorPage[AdCampaignListResponse], ad_campaign, path=["response"])
+ assert_matches_type(SyncCursorPage[AdCampaign], ad_campaign, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -145,7 +221,7 @@ def test_raw_response_list(self, client: Whop) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
ad_campaign = response.parse()
- assert_matches_type(SyncCursorPage[AdCampaignListResponse], ad_campaign, path=["response"])
+ assert_matches_type(SyncCursorPage[AdCampaign], ad_campaign, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -155,15 +231,57 @@ def test_streaming_response_list(self, client: Whop) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
ad_campaign = response.parse()
- assert_matches_type(SyncCursorPage[AdCampaignListResponse], ad_campaign, path=["response"])
+ assert_matches_type(SyncCursorPage[AdCampaign], ad_campaign, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_delete(self, client: Whop) -> None:
+ ad_campaign = client.ad_campaigns.delete(
+ "id",
+ )
+ assert_matches_type(AdCampaignDeleteResponse, ad_campaign, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_delete(self, client: Whop) -> None:
+ response = client.ad_campaigns.with_raw_response.delete(
+ "id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ad_campaign = response.parse()
+ assert_matches_type(AdCampaignDeleteResponse, ad_campaign, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_delete(self, client: Whop) -> None:
+ with client.ad_campaigns.with_streaming_response.delete(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ad_campaign = response.parse()
+ assert_matches_type(AdCampaignDeleteResponse, ad_campaign, 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.ad_campaigns.with_raw_response.delete(
+ "",
+ )
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_pause(self, client: Whop) -> None:
ad_campaign = client.ad_campaigns.pause(
- "adcamp_xxxxxxxxxxx",
+ "id",
)
assert_matches_type(AdCampaign, ad_campaign, path=["response"])
@@ -171,7 +289,7 @@ def test_method_pause(self, client: Whop) -> None:
@parametrize
def test_raw_response_pause(self, client: Whop) -> None:
response = client.ad_campaigns.with_raw_response.pause(
- "adcamp_xxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -183,7 +301,7 @@ def test_raw_response_pause(self, client: Whop) -> None:
@parametrize
def test_streaming_response_pause(self, client: Whop) -> None:
with client.ad_campaigns.with_streaming_response.pause(
- "adcamp_xxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -205,7 +323,7 @@ def test_path_params_pause(self, client: Whop) -> None:
@parametrize
def test_method_unpause(self, client: Whop) -> None:
ad_campaign = client.ad_campaigns.unpause(
- "adcamp_xxxxxxxxxxx",
+ "id",
)
assert_matches_type(AdCampaign, ad_campaign, path=["response"])
@@ -213,7 +331,7 @@ def test_method_unpause(self, client: Whop) -> None:
@parametrize
def test_raw_response_unpause(self, client: Whop) -> None:
response = client.ad_campaigns.with_raw_response.unpause(
- "adcamp_xxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -225,7 +343,7 @@ def test_raw_response_unpause(self, client: Whop) -> None:
@parametrize
def test_streaming_response_unpause(self, client: Whop) -> None:
with client.ad_campaigns.with_streaming_response.unpause(
- "adcamp_xxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -249,11 +367,80 @@ class TestAsyncAdCampaigns:
"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:
+ ad_campaign = await async_client.ad_campaigns.create(
+ objective="awareness",
+ platform="meta",
+ title="title",
+ )
+ assert_matches_type(AdCampaign, ad_campaign, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> None:
+ ad_campaign = await async_client.ad_campaigns.create(
+ objective="awareness",
+ platform="meta",
+ title="title",
+ account_id="account_id",
+ bid_type="minimum_cost",
+ budget_amount=0,
+ budget_optimization="ad_campaign",
+ budget_type="daily",
+ desired_cost_per_result=0,
+ ends_at="ends_at",
+ special_ad_categories=["housing"],
+ starts_at="starts_at",
+ )
+ assert_matches_type(AdCampaign, ad_campaign, 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.ad_campaigns.with_raw_response.create(
+ objective="awareness",
+ platform="meta",
+ title="title",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ad_campaign = await response.parse()
+ assert_matches_type(AdCampaign, ad_campaign, 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.ad_campaigns.with_streaming_response.create(
+ objective="awareness",
+ platform="meta",
+ title="title",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ad_campaign = await response.parse()
+ assert_matches_type(AdCampaign, ad_campaign, 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:
ad_campaign = await async_client.ad_campaigns.retrieve(
- "adcamp_xxxxxxxxxxx",
+ id="id",
+ )
+ assert_matches_type(AdCampaign, ad_campaign, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_retrieve_with_all_params(self, async_client: AsyncWhop) -> None:
+ ad_campaign = await async_client.ad_campaigns.retrieve(
+ id="id",
+ stats_from="stats_from",
+ stats_to="stats_to",
)
assert_matches_type(AdCampaign, ad_campaign, path=["response"])
@@ -261,7 +448,7 @@ async def test_method_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None:
response = await async_client.ad_campaigns.with_raw_response.retrieve(
- "adcamp_xxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -273,7 +460,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_retrieve(self, async_client: AsyncWhop) -> None:
async with async_client.ad_campaigns.with_streaming_response.retrieve(
- "adcamp_xxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -288,14 +475,14 @@ async def test_streaming_response_retrieve(self, async_client: AsyncWhop) -> Non
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.ad_campaigns.with_raw_response.retrieve(
- "",
+ id="",
)
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_method_update(self, async_client: AsyncWhop) -> None:
ad_campaign = await async_client.ad_campaigns.update(
- id="adcamp_xxxxxxxxxxx",
+ id="id",
)
assert_matches_type(AdCampaign, ad_campaign, path=["response"])
@@ -303,8 +490,12 @@ async def test_method_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> None:
ad_campaign = await async_client.ad_campaigns.update(
- id="adcamp_xxxxxxxxxxx",
- budget=6.9,
+ id="id",
+ budget_amount=0,
+ ends_at="ends_at",
+ starts_at="starts_at",
+ status="active",
+ title="title",
)
assert_matches_type(AdCampaign, ad_campaign, path=["response"])
@@ -312,7 +503,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> N
@parametrize
async def test_raw_response_update(self, async_client: AsyncWhop) -> None:
response = await async_client.ad_campaigns.with_raw_response.update(
- id="adcamp_xxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -324,7 +515,7 @@ async def test_raw_response_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_update(self, async_client: AsyncWhop) -> None:
async with async_client.ad_campaigns.with_streaming_response.update(
- id="adcamp_xxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -346,23 +537,27 @@ async def test_path_params_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_list(self, async_client: AsyncWhop) -> None:
ad_campaign = await async_client.ad_campaigns.list()
- assert_matches_type(AsyncCursorPage[AdCampaignListResponse], ad_campaign, path=["response"])
+ assert_matches_type(AsyncCursorPage[AdCampaign], ad_campaign, 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:
ad_campaign = await async_client.ad_campaigns.list(
+ account_id="account_id",
after="after",
before="before",
- company_id="biz_xxxxxxxxxxxxxx",
- created_after=parse_datetime("2023-12-01T05:00:00.401Z"),
- created_before=parse_datetime("2023-12-01T05:00:00.401Z"),
- first=42,
- last=42,
+ created_after="created_after",
+ created_before="created_before",
+ direction="asc",
+ first=100,
+ last=100,
+ order="created_at",
query="query",
- status="active",
+ stats_from="stats_from",
+ stats_to="stats_to",
+ status="draft",
)
- assert_matches_type(AsyncCursorPage[AdCampaignListResponse], ad_campaign, path=["response"])
+ assert_matches_type(AsyncCursorPage[AdCampaign], ad_campaign, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -372,7 +567,7 @@ async def test_raw_response_list(self, async_client: AsyncWhop) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
ad_campaign = await response.parse()
- assert_matches_type(AsyncCursorPage[AdCampaignListResponse], ad_campaign, path=["response"])
+ assert_matches_type(AsyncCursorPage[AdCampaign], ad_campaign, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -382,15 +577,57 @@ async def test_streaming_response_list(self, async_client: AsyncWhop) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
ad_campaign = await response.parse()
- assert_matches_type(AsyncCursorPage[AdCampaignListResponse], ad_campaign, path=["response"])
+ assert_matches_type(AsyncCursorPage[AdCampaign], ad_campaign, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncWhop) -> None:
+ ad_campaign = await async_client.ad_campaigns.delete(
+ "id",
+ )
+ assert_matches_type(AdCampaignDeleteResponse, ad_campaign, 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.ad_campaigns.with_raw_response.delete(
+ "id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ad_campaign = await response.parse()
+ assert_matches_type(AdCampaignDeleteResponse, ad_campaign, 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.ad_campaigns.with_streaming_response.delete(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ad_campaign = await response.parse()
+ assert_matches_type(AdCampaignDeleteResponse, ad_campaign, 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.ad_campaigns.with_raw_response.delete(
+ "",
+ )
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_method_pause(self, async_client: AsyncWhop) -> None:
ad_campaign = await async_client.ad_campaigns.pause(
- "adcamp_xxxxxxxxxxx",
+ "id",
)
assert_matches_type(AdCampaign, ad_campaign, path=["response"])
@@ -398,7 +635,7 @@ async def test_method_pause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_pause(self, async_client: AsyncWhop) -> None:
response = await async_client.ad_campaigns.with_raw_response.pause(
- "adcamp_xxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -410,7 +647,7 @@ async def test_raw_response_pause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_pause(self, async_client: AsyncWhop) -> None:
async with async_client.ad_campaigns.with_streaming_response.pause(
- "adcamp_xxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -432,7 +669,7 @@ async def test_path_params_pause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_unpause(self, async_client: AsyncWhop) -> None:
ad_campaign = await async_client.ad_campaigns.unpause(
- "adcamp_xxxxxxxxxxx",
+ "id",
)
assert_matches_type(AdCampaign, ad_campaign, path=["response"])
@@ -440,7 +677,7 @@ async def test_method_unpause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_unpause(self, async_client: AsyncWhop) -> None:
response = await async_client.ad_campaigns.with_raw_response.unpause(
- "adcamp_xxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -452,7 +689,7 @@ async def test_raw_response_unpause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_unpause(self, async_client: AsyncWhop) -> None:
async with async_client.ad_campaigns.with_streaming_response.unpause(
- "adcamp_xxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
diff --git a/tests/api_resources/test_ad_groups.py b/tests/api_resources/test_ad_groups.py
index ebbda82c..5d6965f6 100644
--- a/tests/api_resources/test_ad_groups.py
+++ b/tests/api_resources/test_ad_groups.py
@@ -11,10 +11,8 @@
from tests.utils import assert_matches_type
from whop_sdk.types import (
AdGroup,
- AdGroupListResponse,
AdGroupDeleteResponse,
)
-from whop_sdk._utils import parse_datetime
from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -23,11 +21,84 @@
class TestAdGroups:
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:
+ ad_group = client.ad_groups.create(
+ ad_campaign_id="ad_campaign_id",
+ )
+ assert_matches_type(AdGroup, ad_group, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: Whop) -> None:
+ ad_group = client.ad_groups.create(
+ ad_campaign_id="ad_campaign_id",
+ audiences={},
+ bid_type="minimum_cost",
+ budget_amount=0,
+ budget_type="daily",
+ conversion_event="purchase",
+ conversion_location="website",
+ demographics={},
+ desired_cost_per_result=0,
+ devices={},
+ dynamic_creative=True,
+ ends_at="ends_at",
+ frequency_cap={},
+ languages=["string"],
+ message_apps=["messenger"],
+ minimum_daily_spend=0,
+ optimization_goal="optimization_goal",
+ placements={},
+ regions={},
+ starts_at="starts_at",
+ status="active",
+ title="title",
+ )
+ assert_matches_type(AdGroup, ad_group, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Whop) -> None:
+ response = client.ad_groups.with_raw_response.create(
+ ad_campaign_id="ad_campaign_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ad_group = response.parse()
+ assert_matches_type(AdGroup, ad_group, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Whop) -> None:
+ with client.ad_groups.with_streaming_response.create(
+ ad_campaign_id="ad_campaign_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ad_group = response.parse()
+ assert_matches_type(AdGroup, ad_group, 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:
ad_group = client.ad_groups.retrieve(
- "adgrp_xxxxxxxxxxxx",
+ id="id",
+ )
+ assert_matches_type(AdGroup, ad_group, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_retrieve_with_all_params(self, client: Whop) -> None:
+ ad_group = client.ad_groups.retrieve(
+ id="id",
+ stats_from="stats_from",
+ stats_to="stats_to",
)
assert_matches_type(AdGroup, ad_group, path=["response"])
@@ -35,7 +106,7 @@ def test_method_retrieve(self, client: Whop) -> None:
@parametrize
def test_raw_response_retrieve(self, client: Whop) -> None:
response = client.ad_groups.with_raw_response.retrieve(
- "adgrp_xxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -47,7 +118,7 @@ def test_raw_response_retrieve(self, client: Whop) -> None:
@parametrize
def test_streaming_response_retrieve(self, client: Whop) -> None:
with client.ad_groups.with_streaming_response.retrieve(
- "adgrp_xxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -62,14 +133,14 @@ def test_streaming_response_retrieve(self, client: Whop) -> None:
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.ad_groups.with_raw_response.retrieve(
- "",
+ id="",
)
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_update(self, client: Whop) -> None:
ad_group = client.ad_groups.update(
- id="adgrp_xxxxxxxxxxxx",
+ id="id",
)
assert_matches_type(AdGroup, ad_group, path=["response"])
@@ -77,348 +148,27 @@ def test_method_update(self, client: Whop) -> None:
@parametrize
def test_method_update_with_all_params(self, client: Whop) -> None:
ad_group = client.ad_groups.update(
- id="adgrp_xxxxxxxxxxxx",
- budget=6.9,
+ id="id",
+ audiences={},
+ bid_type="minimum_cost",
+ budget_amount=0,
budget_type="daily",
- config={
- "bid_amount": 42,
- "bid_strategy": "lowest_cost",
- "billing_event": "impressions",
- "end_time": "end_time",
- "frequency_cap": 42,
- "frequency_cap_interval_days": 42,
- "optimization_goal": "conversions",
- "pacing": "standard",
- "start_time": "start_time",
- "targeting": {
- "age_max": 42,
- "age_min": 42,
- "countries": ["string"],
- "device_platforms": ["mobile"],
- "exclude_audience_ids": ["string"],
- "genders": ["male"],
- "include_audience_ids": ["string"],
- "interest_ids": ["string"],
- "languages": ["string"],
- "placement_type": "automatic",
- },
- },
- daily_budget=6.9,
- name="name",
- platform_config={
- "meta": {
- "android_devices": ["string"],
- "attribution_setting": "attribution_setting",
- "attribution_spec": [
- {
- "event_type": "event_type",
- "window_days": 42,
- }
- ],
- "audience_network_positions": ["string"],
- "audience_type": "audience_type",
- "bid_amount": 42,
- "bid_strategy": "LOWEST_COST_WITHOUT_CAP",
- "billing_event": "APP_INSTALLS",
- "brand_safety_content_filter_levels": ["string"],
- "budget_remaining": "budget_remaining",
- "cost_per_result_goal": 6.9,
- "created_time": "created_time",
- "daily_budget": 42,
- "daily_min_spend_target": "daily_min_spend_target",
- "daily_spend_cap": "daily_spend_cap",
- "destination_type": "UNDEFINED",
- "dsa_beneficiary": "dsa_beneficiary",
- "dsa_payor": "dsa_payor",
- "end_time": "end_time",
- "excluded_geo_locations": {
- "cities": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- "countries": ["string"],
- "location_types": ["string"],
- "regions": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- "zips": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- },
- "facebook_positions": ["string"],
- "frequency_control_count": 42,
- "frequency_control_days": 42,
- "frequency_control_type": "frequency_control_type",
- "geo_cities": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- "geo_locations": {
- "cities": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- "countries": ["string"],
- "location_types": ["string"],
- "regions": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- "zips": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- },
- "geo_regions": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- "geo_zips": ["string"],
- "instagram_actor_id": "instagram_actor_id",
- "instagram_positions": ["string"],
- "ios_devices": ["string"],
- "is_dynamic_creative": True,
- "lead_conversion_location": "website",
- "lead_form_config": {
- "name": "name",
- "privacy_policy_url": "privacy_policy_url",
- "questions": [
- {
- "type": "type",
- "conditional_questions_group_id": "conditional_questions_group_id",
- "dependent_conditional_questions": [
- {
- "type": "type",
- "inline_context": "inline_context",
- "key": "key",
- "label": "label",
- "options": [
- {
- "key": "key",
- "value": "value",
- "logic": {
- "type": "type",
- "target_end_page_index": 42,
- "target_question_index": 42,
- },
- }
- ],
- }
- ],
- "inline_context": "inline_context",
- "key": "key",
- "label": "label",
- "options": [
- {
- "key": "key",
- "value": "value",
- "logic": {
- "type": "type",
- "target_end_page_index": 42,
- "target_question_index": 42,
- },
- }
- ],
- "question_format": "question_format",
- }
- ],
- "background_image_source": "background_image_source",
- "background_image_url": "background_image_url",
- "conditional_logic_enabled": True,
- "context_card_button_text": "context_card_button_text",
- "context_card_content": ["string"],
- "context_card_style": "context_card_style",
- "context_card_title": "context_card_title",
- "custom_disclaimer_body": "custom_disclaimer_body",
- "custom_disclaimer_checkboxes": [
- {
- "key": "key",
- "text": "text",
- "is_checked_by_default": True,
- "is_required": True,
- }
- ],
- "custom_disclaimer_title": "custom_disclaimer_title",
- "form_type": "form_type",
- "messenger_enabled": True,
- "phone_verification_enabled": True,
- "privacy_policy_link_text": "privacy_policy_link_text",
- "question_page_custom_headline": "question_page_custom_headline",
- "rich_creative_headline": "rich_creative_headline",
- "rich_creative_overview": "rich_creative_overview",
- "rich_creative_url": "rich_creative_url",
- "thank_you_pages": [
- {
- "body": "body",
- "business_phone": "business_phone",
- "button_text": "button_text",
- "button_type": "button_type",
- "conditional_question_group_id": "conditional_question_group_id",
- "enable_messenger": True,
- "gated_file_url": "gated_file_url",
- "link": "link",
- "name": "name",
- "title": "title",
- }
- ],
- },
- "lead_gen_form_id": "lead_gen_form_id",
- "lifetime_budget": 42,
- "lifetime_min_spend_target": "lifetime_min_spend_target",
- "lifetime_spend_cap": "lifetime_spend_cap",
- "location_types": ["string"],
- "messenger_positions": ["string"],
- "optimization_goal": "NONE",
- "page_id": "page_id",
- "pixel_id": "pixel_id",
- "promoted_object": {
- "custom_conversion_id": "custom_conversion_id",
- "custom_event_str": "custom_event_str",
- "custom_event_type": "custom_event_type",
- "page_id": "page_id",
- "pixel_id": "pixel_id",
- "whatsapp_phone_number": "whatsapp_phone_number",
- },
- "publisher_platforms": ["string"],
- "source_adset_id": "source_adset_id",
- "start_time": "start_time",
- "status": "ACTIVE",
- "targeting_automation": {"advantage_audience": 42},
- "threads_positions": ["string"],
- "updated_time": "updated_time",
- "user_device": ["string"],
- "user_os": ["string"],
- "whatsapp_phone_number": "whatsapp_phone_number",
- "whatsapp_positions": ["string"],
- },
- "tiktok": {
- "actions": [
- {
- "action_category_ids": ["string"],
- "action_period": 42,
- "action_scene": "VIDEO_RELATED",
- "video_user_actions": ["WATCHED_TO_END"],
- }
- ],
- "age_groups": ["AGE_13_17"],
- "app_id": "app_xxxxxxxxxxxxxx",
- "attribution_event_count": "UNSET",
- "audience_ids": ["string"],
- "audience_rule": {"foo": "bar"},
- "audience_type": "NORMAL",
- "bid_price": 6.9,
- "bid_type": "BID_TYPE_NO_BID",
- "billing_event": "CPC",
- "brand_safety_type": "NO_BRAND_SAFETY",
- "budget_mode": "BUDGET_MODE_DAY",
- "carrier_ids": ["string"],
- "category_exclusion_ids": ["string"],
- "click_attribution_window": "OFF",
- "comment_disabled": True,
- "contextual_tag_ids": ["string"],
- "conversion_bid_price": 6.9,
- "creative_material_mode": "creative_material_mode",
- "dayparting": "dayparting",
- "deep_funnel_event_source": "deep_funnel_event_source",
- "deep_funnel_event_source_id": "deep_funnel_event_source_id",
- "deep_funnel_optimization_status": "ON",
- "device_model_ids": ["string"],
- "device_price_ranges": ["string"],
- "engaged_view_attribution_window": "OFF",
- "excluded_audience_ids": ["string"],
- "excluded_location_ids": ["string"],
- "frequency": 42,
- "frequency_schedule": 42,
- "gender": "GENDER_UNLIMITED",
- "identity_authorized_bc_id": "identity_authorized_bc_id",
- "identity_id": "identity_id",
- "identity_type": "identity_type",
- "instant_form_config": {
- "privacy_policy_url": "privacy_policy_url",
- "questions": [
- {
- "field_type": "field_type",
- "label": "label",
- }
- ],
- "button_text": "button_text",
- "greeting": "greeting",
- "name": "name",
- },
- "instant_form_id": "instant_form_id",
- "interest_category_ids": ["string"],
- "interest_keyword_ids": ["string"],
- "inventory_filter_enabled": True,
- "ios14_targeting": "UNSET",
- "isp_ids": ["string"],
- "languages": ["string"],
- "location_ids": ["string"],
- "min_android_version": "min_android_version",
- "min_ios_version": "min_ios_version",
- "network_types": ["string"],
- "operating_systems": ["ANDROID"],
- "operation_status": "ENABLE",
- "optimization_event": "optimization_event",
- "optimization_goal": "CLICK",
- "pacing": "PACING_MODE_SMOOTH",
- "pangle_audience_package_exclude_ids": ["string"],
- "pangle_audience_package_include_ids": ["string"],
- "pangle_block_app_ids": ["string"],
- "pixel_id": "pixel_id",
- "placement_type": "PLACEMENT_TYPE_AUTOMATIC",
- "placements": ["string"],
- "product_set_id": "product_set_id",
- "product_source": "CATALOG",
- "promotion_type": "promotion_type",
- "schedule_end_time": "schedule_end_time",
- "schedule_start_time": "schedule_start_time",
- "schedule_type": "SCHEDULE_START_END",
- "secondary_optimization_event": "secondary_optimization_event",
- "shopping_ads_retargeting_actions_days": 42,
- "shopping_ads_retargeting_type": "OFF",
- "spending_power": "ALL",
- "tiktok_subplacements": ["string"],
- "vertical_sensitivity_id": "vertical_sensitivity_id",
- "video_download_disabled": True,
- "video_user_actions": ["string"],
- "view_attribution_window": "OFF",
- },
- },
+ conversion_event="purchase",
+ conversion_location="website",
+ demographics={},
+ desired_cost_per_result=0,
+ devices={},
+ ends_at="ends_at",
+ frequency_cap={},
+ languages=["string"],
+ message_apps=["messenger"],
+ minimum_daily_spend=0,
+ optimization_goal="optimization_goal",
+ placements={},
+ regions={},
+ starts_at="starts_at",
status="active",
+ title="title",
)
assert_matches_type(AdGroup, ad_group, path=["response"])
@@ -426,7 +176,7 @@ def test_method_update_with_all_params(self, client: Whop) -> None:
@parametrize
def test_raw_response_update(self, client: Whop) -> None:
response = client.ad_groups.with_raw_response.update(
- id="adgrp_xxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -438,7 +188,7 @@ def test_raw_response_update(self, client: Whop) -> None:
@parametrize
def test_streaming_response_update(self, client: Whop) -> None:
with client.ad_groups.with_streaming_response.update(
- id="adgrp_xxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -460,25 +210,28 @@ def test_path_params_update(self, client: Whop) -> None:
@parametrize
def test_method_list(self, client: Whop) -> None:
ad_group = client.ad_groups.list()
- assert_matches_type(SyncCursorPage[AdGroupListResponse], ad_group, path=["response"])
+ assert_matches_type(SyncCursorPage[AdGroup], ad_group, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_list_with_all_params(self, client: Whop) -> None:
ad_group = client.ad_groups.list(
+ account_id="account_id",
+ ad_campaign_id="ad_campaign_id",
after="after",
before="before",
- campaign_id="campaign_id",
- company_id="biz_xxxxxxxxxxxxxx",
- created_after=parse_datetime("2023-12-01T05:00:00.401Z"),
- created_before=parse_datetime("2023-12-01T05:00:00.401Z"),
- first=42,
- include_paused=True,
- last=42,
+ created_after="created_after",
+ created_before="created_before",
+ direction="asc",
+ first=100,
+ last=100,
+ order="created_at",
query="query",
- status="active",
+ stats_from="stats_from",
+ stats_to="stats_to",
+ status="status",
)
- assert_matches_type(SyncCursorPage[AdGroupListResponse], ad_group, path=["response"])
+ assert_matches_type(SyncCursorPage[AdGroup], ad_group, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -488,7 +241,7 @@ def test_raw_response_list(self, client: Whop) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
ad_group = response.parse()
- assert_matches_type(SyncCursorPage[AdGroupListResponse], ad_group, path=["response"])
+ assert_matches_type(SyncCursorPage[AdGroup], ad_group, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -498,7 +251,7 @@ def test_streaming_response_list(self, client: Whop) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
ad_group = response.parse()
- assert_matches_type(SyncCursorPage[AdGroupListResponse], ad_group, path=["response"])
+ assert_matches_type(SyncCursorPage[AdGroup], ad_group, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -506,7 +259,7 @@ def test_streaming_response_list(self, client: Whop) -> None:
@parametrize
def test_method_delete(self, client: Whop) -> None:
ad_group = client.ad_groups.delete(
- "adgrp_xxxxxxxxxxxx",
+ "id",
)
assert_matches_type(AdGroupDeleteResponse, ad_group, path=["response"])
@@ -514,7 +267,7 @@ def test_method_delete(self, client: Whop) -> None:
@parametrize
def test_raw_response_delete(self, client: Whop) -> None:
response = client.ad_groups.with_raw_response.delete(
- "adgrp_xxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -526,7 +279,7 @@ def test_raw_response_delete(self, client: Whop) -> None:
@parametrize
def test_streaming_response_delete(self, client: Whop) -> None:
with client.ad_groups.with_streaming_response.delete(
- "adgrp_xxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -548,7 +301,7 @@ def test_path_params_delete(self, client: Whop) -> None:
@parametrize
def test_method_pause(self, client: Whop) -> None:
ad_group = client.ad_groups.pause(
- "adgrp_xxxxxxxxxxxx",
+ "id",
)
assert_matches_type(AdGroup, ad_group, path=["response"])
@@ -556,7 +309,7 @@ def test_method_pause(self, client: Whop) -> None:
@parametrize
def test_raw_response_pause(self, client: Whop) -> None:
response = client.ad_groups.with_raw_response.pause(
- "adgrp_xxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -568,7 +321,7 @@ def test_raw_response_pause(self, client: Whop) -> None:
@parametrize
def test_streaming_response_pause(self, client: Whop) -> None:
with client.ad_groups.with_streaming_response.pause(
- "adgrp_xxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -590,7 +343,7 @@ def test_path_params_pause(self, client: Whop) -> None:
@parametrize
def test_method_unpause(self, client: Whop) -> None:
ad_group = client.ad_groups.unpause(
- "adgrp_xxxxxxxxxxxx",
+ "id",
)
assert_matches_type(AdGroup, ad_group, path=["response"])
@@ -598,7 +351,7 @@ def test_method_unpause(self, client: Whop) -> None:
@parametrize
def test_raw_response_unpause(self, client: Whop) -> None:
response = client.ad_groups.with_raw_response.unpause(
- "adgrp_xxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -610,7 +363,7 @@ def test_raw_response_unpause(self, client: Whop) -> None:
@parametrize
def test_streaming_response_unpause(self, client: Whop) -> None:
with client.ad_groups.with_streaming_response.unpause(
- "adgrp_xxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -634,11 +387,84 @@ class TestAsyncAdGroups:
"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:
+ ad_group = await async_client.ad_groups.create(
+ ad_campaign_id="ad_campaign_id",
+ )
+ assert_matches_type(AdGroup, ad_group, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> None:
+ ad_group = await async_client.ad_groups.create(
+ ad_campaign_id="ad_campaign_id",
+ audiences={},
+ bid_type="minimum_cost",
+ budget_amount=0,
+ budget_type="daily",
+ conversion_event="purchase",
+ conversion_location="website",
+ demographics={},
+ desired_cost_per_result=0,
+ devices={},
+ dynamic_creative=True,
+ ends_at="ends_at",
+ frequency_cap={},
+ languages=["string"],
+ message_apps=["messenger"],
+ minimum_daily_spend=0,
+ optimization_goal="optimization_goal",
+ placements={},
+ regions={},
+ starts_at="starts_at",
+ status="active",
+ title="title",
+ )
+ assert_matches_type(AdGroup, ad_group, 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.ad_groups.with_raw_response.create(
+ ad_campaign_id="ad_campaign_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ad_group = await response.parse()
+ assert_matches_type(AdGroup, ad_group, 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.ad_groups.with_streaming_response.create(
+ ad_campaign_id="ad_campaign_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ad_group = await response.parse()
+ assert_matches_type(AdGroup, ad_group, 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:
ad_group = await async_client.ad_groups.retrieve(
- "adgrp_xxxxxxxxxxxx",
+ id="id",
+ )
+ assert_matches_type(AdGroup, ad_group, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_retrieve_with_all_params(self, async_client: AsyncWhop) -> None:
+ ad_group = await async_client.ad_groups.retrieve(
+ id="id",
+ stats_from="stats_from",
+ stats_to="stats_to",
)
assert_matches_type(AdGroup, ad_group, path=["response"])
@@ -646,7 +472,7 @@ async def test_method_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None:
response = await async_client.ad_groups.with_raw_response.retrieve(
- "adgrp_xxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -658,7 +484,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_retrieve(self, async_client: AsyncWhop) -> None:
async with async_client.ad_groups.with_streaming_response.retrieve(
- "adgrp_xxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -673,14 +499,14 @@ async def test_streaming_response_retrieve(self, async_client: AsyncWhop) -> Non
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.ad_groups.with_raw_response.retrieve(
- "",
+ id="",
)
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_method_update(self, async_client: AsyncWhop) -> None:
ad_group = await async_client.ad_groups.update(
- id="adgrp_xxxxxxxxxxxx",
+ id="id",
)
assert_matches_type(AdGroup, ad_group, path=["response"])
@@ -688,348 +514,27 @@ async def test_method_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> None:
ad_group = await async_client.ad_groups.update(
- id="adgrp_xxxxxxxxxxxx",
- budget=6.9,
+ id="id",
+ audiences={},
+ bid_type="minimum_cost",
+ budget_amount=0,
budget_type="daily",
- config={
- "bid_amount": 42,
- "bid_strategy": "lowest_cost",
- "billing_event": "impressions",
- "end_time": "end_time",
- "frequency_cap": 42,
- "frequency_cap_interval_days": 42,
- "optimization_goal": "conversions",
- "pacing": "standard",
- "start_time": "start_time",
- "targeting": {
- "age_max": 42,
- "age_min": 42,
- "countries": ["string"],
- "device_platforms": ["mobile"],
- "exclude_audience_ids": ["string"],
- "genders": ["male"],
- "include_audience_ids": ["string"],
- "interest_ids": ["string"],
- "languages": ["string"],
- "placement_type": "automatic",
- },
- },
- daily_budget=6.9,
- name="name",
- platform_config={
- "meta": {
- "android_devices": ["string"],
- "attribution_setting": "attribution_setting",
- "attribution_spec": [
- {
- "event_type": "event_type",
- "window_days": 42,
- }
- ],
- "audience_network_positions": ["string"],
- "audience_type": "audience_type",
- "bid_amount": 42,
- "bid_strategy": "LOWEST_COST_WITHOUT_CAP",
- "billing_event": "APP_INSTALLS",
- "brand_safety_content_filter_levels": ["string"],
- "budget_remaining": "budget_remaining",
- "cost_per_result_goal": 6.9,
- "created_time": "created_time",
- "daily_budget": 42,
- "daily_min_spend_target": "daily_min_spend_target",
- "daily_spend_cap": "daily_spend_cap",
- "destination_type": "UNDEFINED",
- "dsa_beneficiary": "dsa_beneficiary",
- "dsa_payor": "dsa_payor",
- "end_time": "end_time",
- "excluded_geo_locations": {
- "cities": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- "countries": ["string"],
- "location_types": ["string"],
- "regions": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- "zips": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- },
- "facebook_positions": ["string"],
- "frequency_control_count": 42,
- "frequency_control_days": 42,
- "frequency_control_type": "frequency_control_type",
- "geo_cities": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- "geo_locations": {
- "cities": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- "countries": ["string"],
- "location_types": ["string"],
- "regions": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- "zips": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- },
- "geo_regions": [
- {
- "key": "key",
- "country": "country",
- "name": "name",
- "radius": 42,
- }
- ],
- "geo_zips": ["string"],
- "instagram_actor_id": "instagram_actor_id",
- "instagram_positions": ["string"],
- "ios_devices": ["string"],
- "is_dynamic_creative": True,
- "lead_conversion_location": "website",
- "lead_form_config": {
- "name": "name",
- "privacy_policy_url": "privacy_policy_url",
- "questions": [
- {
- "type": "type",
- "conditional_questions_group_id": "conditional_questions_group_id",
- "dependent_conditional_questions": [
- {
- "type": "type",
- "inline_context": "inline_context",
- "key": "key",
- "label": "label",
- "options": [
- {
- "key": "key",
- "value": "value",
- "logic": {
- "type": "type",
- "target_end_page_index": 42,
- "target_question_index": 42,
- },
- }
- ],
- }
- ],
- "inline_context": "inline_context",
- "key": "key",
- "label": "label",
- "options": [
- {
- "key": "key",
- "value": "value",
- "logic": {
- "type": "type",
- "target_end_page_index": 42,
- "target_question_index": 42,
- },
- }
- ],
- "question_format": "question_format",
- }
- ],
- "background_image_source": "background_image_source",
- "background_image_url": "background_image_url",
- "conditional_logic_enabled": True,
- "context_card_button_text": "context_card_button_text",
- "context_card_content": ["string"],
- "context_card_style": "context_card_style",
- "context_card_title": "context_card_title",
- "custom_disclaimer_body": "custom_disclaimer_body",
- "custom_disclaimer_checkboxes": [
- {
- "key": "key",
- "text": "text",
- "is_checked_by_default": True,
- "is_required": True,
- }
- ],
- "custom_disclaimer_title": "custom_disclaimer_title",
- "form_type": "form_type",
- "messenger_enabled": True,
- "phone_verification_enabled": True,
- "privacy_policy_link_text": "privacy_policy_link_text",
- "question_page_custom_headline": "question_page_custom_headline",
- "rich_creative_headline": "rich_creative_headline",
- "rich_creative_overview": "rich_creative_overview",
- "rich_creative_url": "rich_creative_url",
- "thank_you_pages": [
- {
- "body": "body",
- "business_phone": "business_phone",
- "button_text": "button_text",
- "button_type": "button_type",
- "conditional_question_group_id": "conditional_question_group_id",
- "enable_messenger": True,
- "gated_file_url": "gated_file_url",
- "link": "link",
- "name": "name",
- "title": "title",
- }
- ],
- },
- "lead_gen_form_id": "lead_gen_form_id",
- "lifetime_budget": 42,
- "lifetime_min_spend_target": "lifetime_min_spend_target",
- "lifetime_spend_cap": "lifetime_spend_cap",
- "location_types": ["string"],
- "messenger_positions": ["string"],
- "optimization_goal": "NONE",
- "page_id": "page_id",
- "pixel_id": "pixel_id",
- "promoted_object": {
- "custom_conversion_id": "custom_conversion_id",
- "custom_event_str": "custom_event_str",
- "custom_event_type": "custom_event_type",
- "page_id": "page_id",
- "pixel_id": "pixel_id",
- "whatsapp_phone_number": "whatsapp_phone_number",
- },
- "publisher_platforms": ["string"],
- "source_adset_id": "source_adset_id",
- "start_time": "start_time",
- "status": "ACTIVE",
- "targeting_automation": {"advantage_audience": 42},
- "threads_positions": ["string"],
- "updated_time": "updated_time",
- "user_device": ["string"],
- "user_os": ["string"],
- "whatsapp_phone_number": "whatsapp_phone_number",
- "whatsapp_positions": ["string"],
- },
- "tiktok": {
- "actions": [
- {
- "action_category_ids": ["string"],
- "action_period": 42,
- "action_scene": "VIDEO_RELATED",
- "video_user_actions": ["WATCHED_TO_END"],
- }
- ],
- "age_groups": ["AGE_13_17"],
- "app_id": "app_xxxxxxxxxxxxxx",
- "attribution_event_count": "UNSET",
- "audience_ids": ["string"],
- "audience_rule": {"foo": "bar"},
- "audience_type": "NORMAL",
- "bid_price": 6.9,
- "bid_type": "BID_TYPE_NO_BID",
- "billing_event": "CPC",
- "brand_safety_type": "NO_BRAND_SAFETY",
- "budget_mode": "BUDGET_MODE_DAY",
- "carrier_ids": ["string"],
- "category_exclusion_ids": ["string"],
- "click_attribution_window": "OFF",
- "comment_disabled": True,
- "contextual_tag_ids": ["string"],
- "conversion_bid_price": 6.9,
- "creative_material_mode": "creative_material_mode",
- "dayparting": "dayparting",
- "deep_funnel_event_source": "deep_funnel_event_source",
- "deep_funnel_event_source_id": "deep_funnel_event_source_id",
- "deep_funnel_optimization_status": "ON",
- "device_model_ids": ["string"],
- "device_price_ranges": ["string"],
- "engaged_view_attribution_window": "OFF",
- "excluded_audience_ids": ["string"],
- "excluded_location_ids": ["string"],
- "frequency": 42,
- "frequency_schedule": 42,
- "gender": "GENDER_UNLIMITED",
- "identity_authorized_bc_id": "identity_authorized_bc_id",
- "identity_id": "identity_id",
- "identity_type": "identity_type",
- "instant_form_config": {
- "privacy_policy_url": "privacy_policy_url",
- "questions": [
- {
- "field_type": "field_type",
- "label": "label",
- }
- ],
- "button_text": "button_text",
- "greeting": "greeting",
- "name": "name",
- },
- "instant_form_id": "instant_form_id",
- "interest_category_ids": ["string"],
- "interest_keyword_ids": ["string"],
- "inventory_filter_enabled": True,
- "ios14_targeting": "UNSET",
- "isp_ids": ["string"],
- "languages": ["string"],
- "location_ids": ["string"],
- "min_android_version": "min_android_version",
- "min_ios_version": "min_ios_version",
- "network_types": ["string"],
- "operating_systems": ["ANDROID"],
- "operation_status": "ENABLE",
- "optimization_event": "optimization_event",
- "optimization_goal": "CLICK",
- "pacing": "PACING_MODE_SMOOTH",
- "pangle_audience_package_exclude_ids": ["string"],
- "pangle_audience_package_include_ids": ["string"],
- "pangle_block_app_ids": ["string"],
- "pixel_id": "pixel_id",
- "placement_type": "PLACEMENT_TYPE_AUTOMATIC",
- "placements": ["string"],
- "product_set_id": "product_set_id",
- "product_source": "CATALOG",
- "promotion_type": "promotion_type",
- "schedule_end_time": "schedule_end_time",
- "schedule_start_time": "schedule_start_time",
- "schedule_type": "SCHEDULE_START_END",
- "secondary_optimization_event": "secondary_optimization_event",
- "shopping_ads_retargeting_actions_days": 42,
- "shopping_ads_retargeting_type": "OFF",
- "spending_power": "ALL",
- "tiktok_subplacements": ["string"],
- "vertical_sensitivity_id": "vertical_sensitivity_id",
- "video_download_disabled": True,
- "video_user_actions": ["string"],
- "view_attribution_window": "OFF",
- },
- },
+ conversion_event="purchase",
+ conversion_location="website",
+ demographics={},
+ desired_cost_per_result=0,
+ devices={},
+ ends_at="ends_at",
+ frequency_cap={},
+ languages=["string"],
+ message_apps=["messenger"],
+ minimum_daily_spend=0,
+ optimization_goal="optimization_goal",
+ placements={},
+ regions={},
+ starts_at="starts_at",
status="active",
+ title="title",
)
assert_matches_type(AdGroup, ad_group, path=["response"])
@@ -1037,7 +542,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> N
@parametrize
async def test_raw_response_update(self, async_client: AsyncWhop) -> None:
response = await async_client.ad_groups.with_raw_response.update(
- id="adgrp_xxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -1049,7 +554,7 @@ async def test_raw_response_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_update(self, async_client: AsyncWhop) -> None:
async with async_client.ad_groups.with_streaming_response.update(
- id="adgrp_xxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -1071,25 +576,28 @@ async def test_path_params_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_list(self, async_client: AsyncWhop) -> None:
ad_group = await async_client.ad_groups.list()
- assert_matches_type(AsyncCursorPage[AdGroupListResponse], ad_group, path=["response"])
+ assert_matches_type(AsyncCursorPage[AdGroup], ad_group, 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:
ad_group = await async_client.ad_groups.list(
+ account_id="account_id",
+ ad_campaign_id="ad_campaign_id",
after="after",
before="before",
- campaign_id="campaign_id",
- company_id="biz_xxxxxxxxxxxxxx",
- created_after=parse_datetime("2023-12-01T05:00:00.401Z"),
- created_before=parse_datetime("2023-12-01T05:00:00.401Z"),
- first=42,
- include_paused=True,
- last=42,
+ created_after="created_after",
+ created_before="created_before",
+ direction="asc",
+ first=100,
+ last=100,
+ order="created_at",
query="query",
- status="active",
+ stats_from="stats_from",
+ stats_to="stats_to",
+ status="status",
)
- assert_matches_type(AsyncCursorPage[AdGroupListResponse], ad_group, path=["response"])
+ assert_matches_type(AsyncCursorPage[AdGroup], ad_group, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -1099,7 +607,7 @@ async def test_raw_response_list(self, async_client: AsyncWhop) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
ad_group = await response.parse()
- assert_matches_type(AsyncCursorPage[AdGroupListResponse], ad_group, path=["response"])
+ assert_matches_type(AsyncCursorPage[AdGroup], ad_group, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -1109,7 +617,7 @@ async def test_streaming_response_list(self, async_client: AsyncWhop) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
ad_group = await response.parse()
- assert_matches_type(AsyncCursorPage[AdGroupListResponse], ad_group, path=["response"])
+ assert_matches_type(AsyncCursorPage[AdGroup], ad_group, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -1117,7 +625,7 @@ async def test_streaming_response_list(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_delete(self, async_client: AsyncWhop) -> None:
ad_group = await async_client.ad_groups.delete(
- "adgrp_xxxxxxxxxxxx",
+ "id",
)
assert_matches_type(AdGroupDeleteResponse, ad_group, path=["response"])
@@ -1125,7 +633,7 @@ async def test_method_delete(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_delete(self, async_client: AsyncWhop) -> None:
response = await async_client.ad_groups.with_raw_response.delete(
- "adgrp_xxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -1137,7 +645,7 @@ async def test_raw_response_delete(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_delete(self, async_client: AsyncWhop) -> None:
async with async_client.ad_groups.with_streaming_response.delete(
- "adgrp_xxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -1159,7 +667,7 @@ async def test_path_params_delete(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_pause(self, async_client: AsyncWhop) -> None:
ad_group = await async_client.ad_groups.pause(
- "adgrp_xxxxxxxxxxxx",
+ "id",
)
assert_matches_type(AdGroup, ad_group, path=["response"])
@@ -1167,7 +675,7 @@ async def test_method_pause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_pause(self, async_client: AsyncWhop) -> None:
response = await async_client.ad_groups.with_raw_response.pause(
- "adgrp_xxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -1179,7 +687,7 @@ async def test_raw_response_pause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_pause(self, async_client: AsyncWhop) -> None:
async with async_client.ad_groups.with_streaming_response.pause(
- "adgrp_xxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -1201,7 +709,7 @@ async def test_path_params_pause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_unpause(self, async_client: AsyncWhop) -> None:
ad_group = await async_client.ad_groups.unpause(
- "adgrp_xxxxxxxxxxxx",
+ "id",
)
assert_matches_type(AdGroup, ad_group, path=["response"])
@@ -1209,7 +717,7 @@ async def test_method_unpause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_unpause(self, async_client: AsyncWhop) -> None:
response = await async_client.ad_groups.with_raw_response.unpause(
- "adgrp_xxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -1221,7 +729,7 @@ async def test_raw_response_unpause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_unpause(self, async_client: AsyncWhop) -> None:
async with async_client.ad_groups.with_streaming_response.unpause(
- "adgrp_xxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
diff --git a/tests/api_resources/test_ad_reports.py b/tests/api_resources/test_ad_reports.py
index a5b76624..861f56da 100644
--- a/tests/api_resources/test_ad_reports.py
+++ b/tests/api_resources/test_ad_reports.py
@@ -33,13 +33,13 @@ def test_method_retrieve_with_all_params(self, client: Whop) -> None:
ad_report = client.ad_reports.retrieve(
from_=parse_datetime("2023-12-01T05:00:00.401Z"),
to=parse_datetime("2023-12-01T05:00:00.401Z"),
- ad_campaign_id="ad_campaign_id",
- ad_group_id="ad_group_id",
- ad_id="ad_id",
+ ad_campaign_ids=["string"],
+ ad_group_ids=["string"],
+ ad_ids=["string"],
breakdown="campaign",
company_id="biz_xxxxxxxxxxxxxx",
currency="currency",
- granularity="daily",
+ granularity="hourly",
)
assert_matches_type(AdReportRetrieveResponse, ad_report, path=["response"])
@@ -92,13 +92,13 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncWhop) ->
ad_report = await async_client.ad_reports.retrieve(
from_=parse_datetime("2023-12-01T05:00:00.401Z"),
to=parse_datetime("2023-12-01T05:00:00.401Z"),
- ad_campaign_id="ad_campaign_id",
- ad_group_id="ad_group_id",
- ad_id="ad_id",
+ ad_campaign_ids=["string"],
+ ad_group_ids=["string"],
+ ad_ids=["string"],
breakdown="campaign",
company_id="biz_xxxxxxxxxxxxxx",
currency="currency",
- granularity="daily",
+ granularity="hourly",
)
assert_matches_type(AdReportRetrieveResponse, ad_report, path=["response"])
diff --git a/tests/api_resources/test_ads.py b/tests/api_resources/test_ads.py
index 0b0f229e..69bc5284 100644
--- a/tests/api_resources/test_ads.py
+++ b/tests/api_resources/test_ads.py
@@ -9,8 +9,7 @@
from whop_sdk import Whop, AsyncWhop
from tests.utils import assert_matches_type
-from whop_sdk.types import Ad, AdListResponse
-from whop_sdk._utils import parse_datetime
+from whop_sdk.types import Ad, AdDeleteResponse
from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -19,11 +18,127 @@
class TestAds:
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:
+ ad = client.ads.create()
+ assert_matches_type(Ad, ad, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: Whop) -> None:
+ ad = client.ads.create(
+ ad_group={},
+ ad_group_id="ad_group_id",
+ call_to_action="apply_now",
+ creatives=[
+ {
+ "id": "id",
+ "format": "square",
+ }
+ ],
+ descriptions=["string"],
+ headlines=["string"],
+ lead_form={
+ "completion": {
+ "button_text": "button_text",
+ "description": "description",
+ "headline": "headline",
+ "url": "url",
+ },
+ "disclaimer": {
+ "body": "body",
+ "checkboxes": [
+ {
+ "checked_by_default": True,
+ "key": "key",
+ "required": True,
+ "text": "text",
+ }
+ ],
+ "title": "title",
+ },
+ "form_type": "more_volume",
+ "intro": {
+ "description": "description",
+ "headline": "headline",
+ },
+ "name": "name",
+ "phone_verification": True,
+ "privacy_policy": {
+ "link_text": "link_text",
+ "url": "url",
+ },
+ "questions": [
+ {
+ "format": "short_answer",
+ "label": "label",
+ "options": [
+ {
+ "key": "key",
+ "logic": {
+ "action": "go_to_question",
+ "target_end_page_index": 0,
+ "target_question_index": 0,
+ },
+ "value": "value",
+ }
+ ],
+ "type": "email",
+ }
+ ],
+ },
+ messaging_config={
+ "keyword": "keyword",
+ "message": "message",
+ },
+ multi_advertiser_ads=True,
+ post_id="post_id",
+ primary_texts=["string"],
+ social_accounts=[{"id": "id"}],
+ title="title",
+ url="url",
+ url_parameters={},
+ )
+ assert_matches_type(Ad, ad, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Whop) -> None:
+ response = client.ads.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ad = response.parse()
+ assert_matches_type(Ad, ad, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Whop) -> None:
+ with client.ads.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ad = response.parse()
+ assert_matches_type(Ad, ad, 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:
ad = client.ads.retrieve(
- "ad_xxxxxxxxxxxxxxx",
+ id="id",
+ )
+ assert_matches_type(Ad, ad, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_retrieve_with_all_params(self, client: Whop) -> None:
+ ad = client.ads.retrieve(
+ id="id",
+ stats_from="stats_from",
+ stats_to="stats_to",
)
assert_matches_type(Ad, ad, path=["response"])
@@ -31,7 +146,7 @@ def test_method_retrieve(self, client: Whop) -> None:
@parametrize
def test_raw_response_retrieve(self, client: Whop) -> None:
response = client.ads.with_raw_response.retrieve(
- "ad_xxxxxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -43,7 +158,7 @@ def test_raw_response_retrieve(self, client: Whop) -> None:
@parametrize
def test_streaming_response_retrieve(self, client: Whop) -> None:
with client.ads.with_streaming_response.retrieve(
- "ad_xxxxxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -58,37 +173,155 @@ def test_streaming_response_retrieve(self, client: Whop) -> None:
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.ads.with_raw_response.retrieve(
- "",
+ id="",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_update(self, client: Whop) -> None:
+ ad = client.ads.update(
+ id="id",
+ )
+ assert_matches_type(Ad, ad, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_update_with_all_params(self, client: Whop) -> None:
+ ad = client.ads.update(
+ id="id",
+ call_to_action="apply_now",
+ creatives=[
+ {
+ "id": "id",
+ "format": "square",
+ }
+ ],
+ descriptions=["string"],
+ headlines=["string"],
+ lead_form={
+ "completion": {
+ "button_text": "button_text",
+ "description": "description",
+ "headline": "headline",
+ "url": "url",
+ },
+ "disclaimer": {
+ "body": "body",
+ "checkboxes": [
+ {
+ "checked_by_default": True,
+ "key": "key",
+ "required": True,
+ "text": "text",
+ }
+ ],
+ "title": "title",
+ },
+ "form_type": "more_volume",
+ "intro": {
+ "description": "description",
+ "headline": "headline",
+ },
+ "name": "name",
+ "phone_verification": True,
+ "privacy_policy": {
+ "link_text": "link_text",
+ "url": "url",
+ },
+ "questions": [
+ {
+ "format": "short_answer",
+ "label": "label",
+ "options": [
+ {
+ "key": "key",
+ "logic": {
+ "action": "go_to_question",
+ "target_end_page_index": 0,
+ "target_question_index": 0,
+ },
+ "value": "value",
+ }
+ ],
+ "type": "email",
+ }
+ ],
+ },
+ messaging_config={
+ "keyword": "keyword",
+ "message": "message",
+ },
+ multi_advertiser_ads=True,
+ post_id="post_id",
+ primary_texts=["string"],
+ social_accounts=[{"id": "id"}],
+ title="title",
+ url="url",
+ url_parameters={},
+ )
+ assert_matches_type(Ad, ad, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_update(self, client: Whop) -> None:
+ response = client.ads.with_raw_response.update(
+ id="id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ad = response.parse()
+ assert_matches_type(Ad, ad, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_update(self, client: Whop) -> None:
+ with client.ads.with_streaming_response.update(
+ id="id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ad = response.parse()
+ assert_matches_type(Ad, ad, 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.ads.with_raw_response.update(
+ id="",
)
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_list(self, client: Whop) -> None:
ad = client.ads.list()
- assert_matches_type(SyncCursorPage[AdListResponse], ad, path=["response"])
+ assert_matches_type(SyncCursorPage[Ad], ad, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_list_with_all_params(self, client: Whop) -> None:
ad = client.ads.list(
+ account_id="account_id",
+ ad_campaign_id="ad_campaign_id",
ad_group_id="ad_group_id",
after="after",
before="before",
- campaign_id="campaign_id",
- company_id="biz_xxxxxxxxxxxxxx",
- created_after=parse_datetime("2023-12-01T05:00:00.401Z"),
- created_before=parse_datetime("2023-12-01T05:00:00.401Z"),
- first=42,
- include_paused=True,
- last=42,
- order_by="spend",
- order_direction="asc",
+ created_after="created_after",
+ created_before="created_before",
+ direction="asc",
+ first=100,
+ last=100,
+ order="created_at",
query="query",
- stats_from=parse_datetime("2023-12-01T05:00:00.401Z"),
- stats_to=parse_datetime("2023-12-01T05:00:00.401Z"),
+ stats_from="stats_from",
+ stats_to="stats_to",
status="active",
)
- assert_matches_type(SyncCursorPage[AdListResponse], ad, path=["response"])
+ assert_matches_type(SyncCursorPage[Ad], ad, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -98,7 +331,7 @@ def test_raw_response_list(self, client: Whop) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
ad = response.parse()
- assert_matches_type(SyncCursorPage[AdListResponse], ad, path=["response"])
+ assert_matches_type(SyncCursorPage[Ad], ad, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -108,15 +341,57 @@ def test_streaming_response_list(self, client: Whop) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
ad = response.parse()
- assert_matches_type(SyncCursorPage[AdListResponse], ad, path=["response"])
+ assert_matches_type(SyncCursorPage[Ad], ad, path=["response"])
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_delete(self, client: Whop) -> None:
+ ad = client.ads.delete(
+ "id",
+ )
+ assert_matches_type(AdDeleteResponse, ad, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_delete(self, client: Whop) -> None:
+ response = client.ads.with_raw_response.delete(
+ "id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ad = response.parse()
+ assert_matches_type(AdDeleteResponse, ad, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_delete(self, client: Whop) -> None:
+ with client.ads.with_streaming_response.delete(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ad = response.parse()
+ assert_matches_type(AdDeleteResponse, ad, 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.ads.with_raw_response.delete(
+ "",
+ )
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_pause(self, client: Whop) -> None:
ad = client.ads.pause(
- "ad_xxxxxxxxxxxxxxx",
+ "id",
)
assert_matches_type(Ad, ad, path=["response"])
@@ -124,7 +399,7 @@ def test_method_pause(self, client: Whop) -> None:
@parametrize
def test_raw_response_pause(self, client: Whop) -> None:
response = client.ads.with_raw_response.pause(
- "ad_xxxxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -136,7 +411,7 @@ def test_raw_response_pause(self, client: Whop) -> None:
@parametrize
def test_streaming_response_pause(self, client: Whop) -> None:
with client.ads.with_streaming_response.pause(
- "ad_xxxxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -158,7 +433,7 @@ def test_path_params_pause(self, client: Whop) -> None:
@parametrize
def test_method_unpause(self, client: Whop) -> None:
ad = client.ads.unpause(
- "ad_xxxxxxxxxxxxxxx",
+ "id",
)
assert_matches_type(Ad, ad, path=["response"])
@@ -166,7 +441,7 @@ def test_method_unpause(self, client: Whop) -> None:
@parametrize
def test_raw_response_unpause(self, client: Whop) -> None:
response = client.ads.with_raw_response.unpause(
- "ad_xxxxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -178,7 +453,7 @@ def test_raw_response_unpause(self, client: Whop) -> None:
@parametrize
def test_streaming_response_unpause(self, client: Whop) -> None:
with client.ads.with_streaming_response.unpause(
- "ad_xxxxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -202,11 +477,127 @@ class TestAsyncAds:
"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:
+ ad = await async_client.ads.create()
+ assert_matches_type(Ad, ad, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> None:
+ ad = await async_client.ads.create(
+ ad_group={},
+ ad_group_id="ad_group_id",
+ call_to_action="apply_now",
+ creatives=[
+ {
+ "id": "id",
+ "format": "square",
+ }
+ ],
+ descriptions=["string"],
+ headlines=["string"],
+ lead_form={
+ "completion": {
+ "button_text": "button_text",
+ "description": "description",
+ "headline": "headline",
+ "url": "url",
+ },
+ "disclaimer": {
+ "body": "body",
+ "checkboxes": [
+ {
+ "checked_by_default": True,
+ "key": "key",
+ "required": True,
+ "text": "text",
+ }
+ ],
+ "title": "title",
+ },
+ "form_type": "more_volume",
+ "intro": {
+ "description": "description",
+ "headline": "headline",
+ },
+ "name": "name",
+ "phone_verification": True,
+ "privacy_policy": {
+ "link_text": "link_text",
+ "url": "url",
+ },
+ "questions": [
+ {
+ "format": "short_answer",
+ "label": "label",
+ "options": [
+ {
+ "key": "key",
+ "logic": {
+ "action": "go_to_question",
+ "target_end_page_index": 0,
+ "target_question_index": 0,
+ },
+ "value": "value",
+ }
+ ],
+ "type": "email",
+ }
+ ],
+ },
+ messaging_config={
+ "keyword": "keyword",
+ "message": "message",
+ },
+ multi_advertiser_ads=True,
+ post_id="post_id",
+ primary_texts=["string"],
+ social_accounts=[{"id": "id"}],
+ title="title",
+ url="url",
+ url_parameters={},
+ )
+ assert_matches_type(Ad, ad, 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.ads.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ad = await response.parse()
+ assert_matches_type(Ad, ad, 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.ads.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ad = await response.parse()
+ assert_matches_type(Ad, ad, 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:
ad = await async_client.ads.retrieve(
- "ad_xxxxxxxxxxxxxxx",
+ id="id",
+ )
+ assert_matches_type(Ad, ad, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_retrieve_with_all_params(self, async_client: AsyncWhop) -> None:
+ ad = await async_client.ads.retrieve(
+ id="id",
+ stats_from="stats_from",
+ stats_to="stats_to",
)
assert_matches_type(Ad, ad, path=["response"])
@@ -214,7 +605,7 @@ async def test_method_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None:
response = await async_client.ads.with_raw_response.retrieve(
- "ad_xxxxxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -226,7 +617,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_retrieve(self, async_client: AsyncWhop) -> None:
async with async_client.ads.with_streaming_response.retrieve(
- "ad_xxxxxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -241,37 +632,155 @@ async def test_streaming_response_retrieve(self, async_client: AsyncWhop) -> Non
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.ads.with_raw_response.retrieve(
- "",
+ id="",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_update(self, async_client: AsyncWhop) -> None:
+ ad = await async_client.ads.update(
+ id="id",
+ )
+ assert_matches_type(Ad, ad, 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:
+ ad = await async_client.ads.update(
+ id="id",
+ call_to_action="apply_now",
+ creatives=[
+ {
+ "id": "id",
+ "format": "square",
+ }
+ ],
+ descriptions=["string"],
+ headlines=["string"],
+ lead_form={
+ "completion": {
+ "button_text": "button_text",
+ "description": "description",
+ "headline": "headline",
+ "url": "url",
+ },
+ "disclaimer": {
+ "body": "body",
+ "checkboxes": [
+ {
+ "checked_by_default": True,
+ "key": "key",
+ "required": True,
+ "text": "text",
+ }
+ ],
+ "title": "title",
+ },
+ "form_type": "more_volume",
+ "intro": {
+ "description": "description",
+ "headline": "headline",
+ },
+ "name": "name",
+ "phone_verification": True,
+ "privacy_policy": {
+ "link_text": "link_text",
+ "url": "url",
+ },
+ "questions": [
+ {
+ "format": "short_answer",
+ "label": "label",
+ "options": [
+ {
+ "key": "key",
+ "logic": {
+ "action": "go_to_question",
+ "target_end_page_index": 0,
+ "target_question_index": 0,
+ },
+ "value": "value",
+ }
+ ],
+ "type": "email",
+ }
+ ],
+ },
+ messaging_config={
+ "keyword": "keyword",
+ "message": "message",
+ },
+ multi_advertiser_ads=True,
+ post_id="post_id",
+ primary_texts=["string"],
+ social_accounts=[{"id": "id"}],
+ title="title",
+ url="url",
+ url_parameters={},
+ )
+ assert_matches_type(Ad, ad, 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.ads.with_raw_response.update(
+ id="id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ad = await response.parse()
+ assert_matches_type(Ad, ad, 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.ads.with_streaming_response.update(
+ id="id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ad = await response.parse()
+ assert_matches_type(Ad, ad, 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.ads.with_raw_response.update(
+ id="",
)
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_method_list(self, async_client: AsyncWhop) -> None:
ad = await async_client.ads.list()
- assert_matches_type(AsyncCursorPage[AdListResponse], ad, path=["response"])
+ assert_matches_type(AsyncCursorPage[Ad], ad, 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:
ad = await async_client.ads.list(
+ account_id="account_id",
+ ad_campaign_id="ad_campaign_id",
ad_group_id="ad_group_id",
after="after",
before="before",
- campaign_id="campaign_id",
- company_id="biz_xxxxxxxxxxxxxx",
- created_after=parse_datetime("2023-12-01T05:00:00.401Z"),
- created_before=parse_datetime("2023-12-01T05:00:00.401Z"),
- first=42,
- include_paused=True,
- last=42,
- order_by="spend",
- order_direction="asc",
+ created_after="created_after",
+ created_before="created_before",
+ direction="asc",
+ first=100,
+ last=100,
+ order="created_at",
query="query",
- stats_from=parse_datetime("2023-12-01T05:00:00.401Z"),
- stats_to=parse_datetime("2023-12-01T05:00:00.401Z"),
+ stats_from="stats_from",
+ stats_to="stats_to",
status="active",
)
- assert_matches_type(AsyncCursorPage[AdListResponse], ad, path=["response"])
+ assert_matches_type(AsyncCursorPage[Ad], ad, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -281,7 +790,7 @@ async def test_raw_response_list(self, async_client: AsyncWhop) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
ad = await response.parse()
- assert_matches_type(AsyncCursorPage[AdListResponse], ad, path=["response"])
+ assert_matches_type(AsyncCursorPage[Ad], ad, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -291,15 +800,57 @@ async def test_streaming_response_list(self, async_client: AsyncWhop) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
ad = await response.parse()
- assert_matches_type(AsyncCursorPage[AdListResponse], ad, path=["response"])
+ assert_matches_type(AsyncCursorPage[Ad], ad, path=["response"])
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncWhop) -> None:
+ ad = await async_client.ads.delete(
+ "id",
+ )
+ assert_matches_type(AdDeleteResponse, ad, 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.ads.with_raw_response.delete(
+ "id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ad = await response.parse()
+ assert_matches_type(AdDeleteResponse, ad, 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.ads.with_streaming_response.delete(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ad = await response.parse()
+ assert_matches_type(AdDeleteResponse, ad, 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.ads.with_raw_response.delete(
+ "",
+ )
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_method_pause(self, async_client: AsyncWhop) -> None:
ad = await async_client.ads.pause(
- "ad_xxxxxxxxxxxxxxx",
+ "id",
)
assert_matches_type(Ad, ad, path=["response"])
@@ -307,7 +858,7 @@ async def test_method_pause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_pause(self, async_client: AsyncWhop) -> None:
response = await async_client.ads.with_raw_response.pause(
- "ad_xxxxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -319,7 +870,7 @@ async def test_raw_response_pause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_pause(self, async_client: AsyncWhop) -> None:
async with async_client.ads.with_streaming_response.pause(
- "ad_xxxxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -341,7 +892,7 @@ async def test_path_params_pause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_unpause(self, async_client: AsyncWhop) -> None:
ad = await async_client.ads.unpause(
- "ad_xxxxxxxxxxxxxxx",
+ "id",
)
assert_matches_type(Ad, ad, path=["response"])
@@ -349,7 +900,7 @@ async def test_method_unpause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_unpause(self, async_client: AsyncWhop) -> None:
response = await async_client.ads.with_raw_response.unpause(
- "ad_xxxxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -361,7 +912,7 @@ async def test_raw_response_unpause(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_unpause(self, async_client: AsyncWhop) -> None:
async with async_client.ads.with_streaming_response.unpause(
- "ad_xxxxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
diff --git a/tests/api_resources/test_audiences.py b/tests/api_resources/test_audiences.py
new file mode 100644
index 00000000..7ca8a204
--- /dev/null
+++ b/tests/api_resources/test_audiences.py
@@ -0,0 +1,319 @@
+# 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 Audience, AudienceDeleteResponse
+from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestAudiences:
+ 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:
+ audience = client.audiences.create(
+ account_id="account_id",
+ column_mapping={},
+ file_id="file_id",
+ name="name",
+ )
+ assert_matches_type(Audience, audience, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: Whop) -> None:
+ audience = client.audiences.create(
+ account_id="account_id",
+ column_mapping={
+ "country": "country",
+ "email": "email",
+ "first_name": "first_name",
+ "last_name": "last_name",
+ "phone": "phone",
+ },
+ file_id="file_id",
+ name="name",
+ )
+ assert_matches_type(Audience, audience, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Whop) -> None:
+ response = client.audiences.with_raw_response.create(
+ account_id="account_id",
+ column_mapping={},
+ file_id="file_id",
+ name="name",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ audience = response.parse()
+ assert_matches_type(Audience, audience, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Whop) -> None:
+ with client.audiences.with_streaming_response.create(
+ account_id="account_id",
+ column_mapping={},
+ file_id="file_id",
+ name="name",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ audience = response.parse()
+ assert_matches_type(Audience, audience, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Whop) -> None:
+ audience = client.audiences.list(
+ account_id="account_id",
+ )
+ assert_matches_type(SyncCursorPage[Audience], audience, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Whop) -> None:
+ audience = client.audiences.list(
+ account_id="account_id",
+ after="after",
+ audience_id="audience_id",
+ first=0,
+ )
+ assert_matches_type(SyncCursorPage[Audience], audience, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Whop) -> None:
+ response = client.audiences.with_raw_response.list(
+ account_id="account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ audience = response.parse()
+ assert_matches_type(SyncCursorPage[Audience], audience, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Whop) -> None:
+ with client.audiences.with_streaming_response.list(
+ account_id="account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ audience = response.parse()
+ assert_matches_type(SyncCursorPage[Audience], audience, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_delete(self, client: Whop) -> None:
+ audience = client.audiences.delete(
+ "audience_id",
+ )
+ assert_matches_type(AudienceDeleteResponse, audience, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_delete(self, client: Whop) -> None:
+ response = client.audiences.with_raw_response.delete(
+ "audience_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ audience = response.parse()
+ assert_matches_type(AudienceDeleteResponse, audience, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_delete(self, client: Whop) -> None:
+ with client.audiences.with_streaming_response.delete(
+ "audience_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ audience = response.parse()
+ assert_matches_type(AudienceDeleteResponse, audience, 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 `audience_id` but received ''"):
+ client.audiences.with_raw_response.delete(
+ "",
+ )
+
+
+class TestAsyncAudiences:
+ 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:
+ audience = await async_client.audiences.create(
+ account_id="account_id",
+ column_mapping={},
+ file_id="file_id",
+ name="name",
+ )
+ assert_matches_type(Audience, audience, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> None:
+ audience = await async_client.audiences.create(
+ account_id="account_id",
+ column_mapping={
+ "country": "country",
+ "email": "email",
+ "first_name": "first_name",
+ "last_name": "last_name",
+ "phone": "phone",
+ },
+ file_id="file_id",
+ name="name",
+ )
+ assert_matches_type(Audience, audience, 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.audiences.with_raw_response.create(
+ account_id="account_id",
+ column_mapping={},
+ file_id="file_id",
+ name="name",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ audience = await response.parse()
+ assert_matches_type(Audience, audience, 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.audiences.with_streaming_response.create(
+ account_id="account_id",
+ column_mapping={},
+ file_id="file_id",
+ name="name",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ audience = await response.parse()
+ assert_matches_type(Audience, audience, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncWhop) -> None:
+ audience = await async_client.audiences.list(
+ account_id="account_id",
+ )
+ assert_matches_type(AsyncCursorPage[Audience], audience, 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:
+ audience = await async_client.audiences.list(
+ account_id="account_id",
+ after="after",
+ audience_id="audience_id",
+ first=0,
+ )
+ assert_matches_type(AsyncCursorPage[Audience], audience, 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.audiences.with_raw_response.list(
+ account_id="account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ audience = await response.parse()
+ assert_matches_type(AsyncCursorPage[Audience], audience, 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.audiences.with_streaming_response.list(
+ account_id="account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ audience = await response.parse()
+ assert_matches_type(AsyncCursorPage[Audience], audience, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncWhop) -> None:
+ audience = await async_client.audiences.delete(
+ "audience_id",
+ )
+ assert_matches_type(AudienceDeleteResponse, audience, 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.audiences.with_raw_response.delete(
+ "audience_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ audience = await response.parse()
+ assert_matches_type(AudienceDeleteResponse, audience, 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.audiences.with_streaming_response.delete(
+ "audience_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ audience = await response.parse()
+ assert_matches_type(AudienceDeleteResponse, audience, 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 `audience_id` but received ''"):
+ await async_client.audiences.with_raw_response.delete(
+ "",
+ )
diff --git a/tests/api_resources/test_authorized_users.py b/tests/api_resources/test_authorized_users.py
index 007f3d47..96ad67ce 100644
--- a/tests/api_resources/test_authorized_users.py
+++ b/tests/api_resources/test_authorized_users.py
@@ -40,6 +40,15 @@ def test_method_create_with_all_params(self, client: Whop) -> None:
company_id="biz_xxxxxxxxxxxxxx",
role="owner",
user_id="user_xxxxxxxxxxxxx",
+ elevation={
+ "authenticator_data": "authenticator_data",
+ "client_data_json": "client_data_json",
+ "credential_id": "credential_id",
+ "email_code": "email_code",
+ "signature": "signature",
+ "totp_code": "totp_code",
+ "use_finance_session": True,
+ },
send_emails=True,
)
assert_matches_type(AuthorizedUser, authorized_user, path=["response"])
@@ -234,6 +243,15 @@ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> N
company_id="biz_xxxxxxxxxxxxxx",
role="owner",
user_id="user_xxxxxxxxxxxxx",
+ elevation={
+ "authenticator_data": "authenticator_data",
+ "client_data_json": "client_data_json",
+ "credential_id": "credential_id",
+ "email_code": "email_code",
+ "signature": "signature",
+ "totp_code": "totp_code",
+ "use_finance_session": True,
+ },
send_emails=True,
)
assert_matches_type(AuthorizedUser, authorized_user, path=["response"])
diff --git a/tests/api_resources/test_bounties.py b/tests/api_resources/test_bounties.py
index d76ec837..99ac9142 100644
--- a/tests/api_resources/test_bounties.py
+++ b/tests/api_resources/test_bounties.py
@@ -14,6 +14,7 @@
BountyCreateResponse,
BountyRetrieveResponse,
)
+from whop_sdk._utils import parse_datetime
from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -43,10 +44,14 @@ def test_method_create_with_all_params(self, client: Whop) -> None:
title="title",
accepted_submissions_limit=42,
allowed_country_codes=["string"],
+ business_goal_type="clipping",
experience_id="exp_xxxxxxxxxxxxxx",
origin_account_id="origin_account_id",
post_markdown_content="post_markdown_content",
post_title="post_title",
+ scheduled_frequency="once",
+ scheduled_publish_at=parse_datetime("2023-12-01T05:00:00.401Z"),
+ scheduled_timezone="scheduled_timezone",
)
assert_matches_type(BountyCreateResponse, bounty, path=["response"])
@@ -193,10 +198,14 @@ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> N
title="title",
accepted_submissions_limit=42,
allowed_country_codes=["string"],
+ business_goal_type="clipping",
experience_id="exp_xxxxxxxxxxxxxx",
origin_account_id="origin_account_id",
post_markdown_content="post_markdown_content",
post_title="post_title",
+ scheduled_frequency="once",
+ scheduled_publish_at=parse_datetime("2023-12-01T05:00:00.401Z"),
+ scheduled_timezone="scheduled_timezone",
)
assert_matches_type(BountyCreateResponse, bounty, path=["response"])
diff --git a/tests/api_resources/test_cards.py b/tests/api_resources/test_cards.py
new file mode 100644
index 00000000..9716fe1a
--- /dev/null
+++ b/tests/api_resources/test_cards.py
@@ -0,0 +1,290 @@
+# 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 (
+ CardListResponse,
+ CardCreateResponse,
+ CardRetrieveResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestCards:
+ 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:
+ card = client.cards.create()
+ assert_matches_type(CardCreateResponse, card, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: Whop) -> None:
+ card = client.cards.create(
+ account_id="account_id",
+ assigned_user_id="assigned_user_id",
+ name="name",
+ spend_limit=0,
+ spend_limit_frequency="daily",
+ transaction_limit=0,
+ user_id="user_id",
+ )
+ assert_matches_type(CardCreateResponse, card, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Whop) -> None:
+ response = client.cards.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ card = response.parse()
+ assert_matches_type(CardCreateResponse, card, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Whop) -> None:
+ with client.cards.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ card = response.parse()
+ assert_matches_type(CardCreateResponse, card, 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:
+ card = client.cards.retrieve(
+ card_id="card_id",
+ )
+ assert_matches_type(CardRetrieveResponse, card, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_retrieve_with_all_params(self, client: Whop) -> None:
+ card = client.cards.retrieve(
+ card_id="card_id",
+ account_id="account_id",
+ user_id="user_id",
+ )
+ assert_matches_type(CardRetrieveResponse, card, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_retrieve(self, client: Whop) -> None:
+ response = client.cards.with_raw_response.retrieve(
+ card_id="card_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ card = response.parse()
+ assert_matches_type(CardRetrieveResponse, card, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Whop) -> None:
+ with client.cards.with_streaming_response.retrieve(
+ card_id="card_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ card = response.parse()
+ assert_matches_type(CardRetrieveResponse, card, 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 `card_id` but received ''"):
+ client.cards.with_raw_response.retrieve(
+ card_id="",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Whop) -> None:
+ card = client.cards.list()
+ assert_matches_type(CardListResponse, card, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Whop) -> None:
+ card = client.cards.list(
+ account_id="account_id",
+ user_id="user_id",
+ )
+ assert_matches_type(CardListResponse, card, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Whop) -> None:
+ response = client.cards.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ card = response.parse()
+ assert_matches_type(CardListResponse, card, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Whop) -> None:
+ with client.cards.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ card = response.parse()
+ assert_matches_type(CardListResponse, card, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncCards:
+ 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:
+ card = await async_client.cards.create()
+ assert_matches_type(CardCreateResponse, card, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> None:
+ card = await async_client.cards.create(
+ account_id="account_id",
+ assigned_user_id="assigned_user_id",
+ name="name",
+ spend_limit=0,
+ spend_limit_frequency="daily",
+ transaction_limit=0,
+ user_id="user_id",
+ )
+ assert_matches_type(CardCreateResponse, card, 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.cards.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ card = await response.parse()
+ assert_matches_type(CardCreateResponse, card, 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.cards.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ card = await response.parse()
+ assert_matches_type(CardCreateResponse, card, 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:
+ card = await async_client.cards.retrieve(
+ card_id="card_id",
+ )
+ assert_matches_type(CardRetrieveResponse, card, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_retrieve_with_all_params(self, async_client: AsyncWhop) -> None:
+ card = await async_client.cards.retrieve(
+ card_id="card_id",
+ account_id="account_id",
+ user_id="user_id",
+ )
+ assert_matches_type(CardRetrieveResponse, card, 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.cards.with_raw_response.retrieve(
+ card_id="card_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ card = await response.parse()
+ assert_matches_type(CardRetrieveResponse, card, 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.cards.with_streaming_response.retrieve(
+ card_id="card_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ card = await response.parse()
+ assert_matches_type(CardRetrieveResponse, card, 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 `card_id` but received ''"):
+ await async_client.cards.with_raw_response.retrieve(
+ card_id="",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncWhop) -> None:
+ card = await async_client.cards.list()
+ assert_matches_type(CardListResponse, card, 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:
+ card = await async_client.cards.list(
+ account_id="account_id",
+ user_id="user_id",
+ )
+ assert_matches_type(CardListResponse, card, 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.cards.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ card = await response.parse()
+ assert_matches_type(CardListResponse, card, 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.cards.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ card = await response.parse()
+ assert_matches_type(CardListResponse, card, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_checkout_configurations.py b/tests/api_resources/test_checkout_configurations.py
index 76ccdb32..03b8452c 100644
--- a/tests/api_resources/test_checkout_configurations.py
+++ b/tests/api_resources/test_checkout_configurations.py
@@ -11,10 +11,10 @@
from tests.utils import assert_matches_type
from whop_sdk.types import (
CheckoutConfigurationListResponse,
+ CheckoutConfigurationCreateResponse,
+ CheckoutConfigurationRetrieveResponse,
)
-from whop_sdk._utils import parse_datetime
from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
-from whop_sdk.types.shared import CheckoutConfiguration
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -24,244 +24,74 @@ class TestCheckoutConfigurations:
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
- def test_method_create_overload_1(self, client: Whop) -> None:
- checkout_configuration = client.checkout_configurations.create(
- plan={
- "company_id": "biz_xxxxxxxxxxxxxx",
- "currency": "usd",
- },
- )
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ def test_method_create(self, client: Whop) -> None:
+ checkout_configuration = client.checkout_configurations.create()
+ assert_matches_type(CheckoutConfigurationCreateResponse, checkout_configuration, 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:
+ def test_method_create_with_all_params(self, client: Whop) -> None:
checkout_configuration = client.checkout_configurations.create(
+ affiliate_code="affiliate_code",
+ company_id="company_id",
+ currency="currency",
+ metadata={},
+ mode="payment",
+ payment_method_configuration={
+ "disabled": ["string"],
+ "enabled": ["string"],
+ "include_platform_defaults": True,
+ },
plan={
- "company_id": "biz_xxxxxxxxxxxxxx",
- "currency": "usd",
- "adaptive_pricing_enabled": True,
- "application_fee_amount": 6.9,
- "billing_period": 42,
- "custom_fields": [
- {
- "field_type": "text",
- "name": "name",
- "id": "id",
- "order": 42,
- "placeholder": "placeholder",
- "required": True,
- }
- ],
+ "billing_period": 0,
+ "company_id": "company_id",
+ "currency": "currency",
"description": "description",
- "expiration_days": 42,
+ "expiration_days": 0,
"force_create_new_plan": True,
- "image": {"id": "id"},
- "initial_price": 6.9,
- "internal_notes": "internal_notes",
- "override_tax_type": "inclusive",
+ "initial_price": 0,
+ "metadata": {},
+ "override_tax_type": "override_tax_type",
"payment_method_configuration": {
- "disabled": ["acss_debit"],
- "enabled": ["acss_debit"],
+ "disabled": ["string"],
+ "enabled": ["string"],
"include_platform_defaults": True,
},
- "plan_type": "renewal",
- "product": {
- "external_identifier": "external_identifier",
- "title": "title",
- "collect_shipping_address": True,
- "custom_statement_descriptor": "custom_statement_descriptor",
- "description": "description",
- "global_affiliate_percentage": 6.9,
- "global_affiliate_status": "enabled",
- "headline": "headline",
- "product_tax_code_id": "ptc_xxxxxxxxxxxxxx",
- "redirect_purchase_url": "redirect_purchase_url",
- "route": "route",
- "visibility": "visible",
- },
- "product_id": "prod_xxxxxxxxxxxxx",
- "release_method": "buy_now",
- "renewal_price": 6.9,
- "split_pay_required_payments": 42,
- "stock": 42,
+ "plan_type": "plan_type",
+ "product_id": "product_id",
+ "release_method": "release_method",
+ "renewal_price": 0,
+ "stock": 0,
"title": "title",
- "trial_period_days": 42,
- "visibility": "visible",
- },
- affiliate_code="affiliate_code",
- allow_promo_codes=True,
- checkout_styling={
- "background_color": "background_color",
- "border_style": "rounded",
- "button_color": "button_color",
- "font_family": "system",
- },
- currency="usd",
- metadata={"foo": "bar"},
- mode="payment",
- payment_method_configuration={
- "disabled": ["acss_debit"],
- "enabled": ["acss_debit"],
- "include_platform_defaults": True,
- },
- redirect_url="redirect_url",
- source_url="source_url",
- )
- assert_matches_type(CheckoutConfiguration, checkout_configuration, 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.checkout_configurations.with_raw_response.create(
- plan={
- "company_id": "biz_xxxxxxxxxxxxxx",
- "currency": "usd",
- },
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- checkout_configuration = response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, 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.checkout_configurations.with_streaming_response.create(
- plan={
- "company_id": "biz_xxxxxxxxxxxxxx",
- "currency": "usd",
- },
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- checkout_configuration = response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create_overload_2(self, client: Whop) -> None:
- checkout_configuration = client.checkout_configurations.create(
- plan_id="plan_xxxxxxxxxxxxx",
- )
- assert_matches_type(CheckoutConfiguration, checkout_configuration, 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:
- checkout_configuration = client.checkout_configurations.create(
- plan_id="plan_xxxxxxxxxxxxx",
- affiliate_code="affiliate_code",
- allow_promo_codes=True,
- checkout_styling={
- "background_color": "background_color",
- "border_style": "rounded",
- "button_color": "button_color",
- "font_family": "system",
- },
- currency="usd",
- metadata={"foo": "bar"},
- mode="payment",
- payment_method_configuration={
- "disabled": ["acss_debit"],
- "enabled": ["acss_debit"],
- "include_platform_defaults": True,
- },
- redirect_url="redirect_url",
- source_url="source_url",
- )
- assert_matches_type(CheckoutConfiguration, checkout_configuration, 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.checkout_configurations.with_raw_response.create(
- plan_id="plan_xxxxxxxxxxxxx",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- checkout_configuration = response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, 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.checkout_configurations.with_streaming_response.create(
- plan_id="plan_xxxxxxxxxxxxx",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- checkout_configuration = response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create_overload_3(self, client: Whop) -> None:
- checkout_configuration = client.checkout_configurations.create(
- company_id="biz_xxxxxxxxxxxxxx",
- mode="setup",
- )
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create_with_all_params_overload_3(self, client: Whop) -> None:
- checkout_configuration = client.checkout_configurations.create(
- company_id="biz_xxxxxxxxxxxxxx",
- mode="setup",
- allow_promo_codes=True,
- checkout_styling={
- "background_color": "background_color",
- "border_style": "rounded",
- "button_color": "button_color",
- "font_family": "system",
- },
- currency="usd",
- metadata={"foo": "bar"},
- payment_method_configuration={
- "disabled": ["acss_debit"],
- "enabled": ["acss_debit"],
- "include_platform_defaults": True,
+ "trial_period_days": 0,
+ "unlimited_stock": True,
+ "visibility": "visibility",
},
+ plan_id="plan_id",
redirect_url="redirect_url",
- source_url="source_url",
- three_ds_level="mandate_challenge",
+ three_ds_level="three_ds_level",
)
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ assert_matches_type(CheckoutConfigurationCreateResponse, checkout_configuration, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
- def test_raw_response_create_overload_3(self, client: Whop) -> None:
- response = client.checkout_configurations.with_raw_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
- mode="setup",
- )
+ def test_raw_response_create(self, client: Whop) -> None:
+ response = client.checkout_configurations.with_raw_response.create()
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
checkout_configuration = response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ assert_matches_type(CheckoutConfigurationCreateResponse, checkout_configuration, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
- def test_streaming_response_create_overload_3(self, client: Whop) -> None:
- with client.checkout_configurations.with_streaming_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
- mode="setup",
- ) as response:
+ def test_streaming_response_create(self, client: Whop) -> None:
+ with client.checkout_configurations.with_streaming_response.create() as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
checkout_configuration = response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ assert_matches_type(CheckoutConfigurationCreateResponse, checkout_configuration, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -269,33 +99,33 @@ def test_streaming_response_create_overload_3(self, client: Whop) -> None:
@parametrize
def test_method_retrieve(self, client: Whop) -> None:
checkout_configuration = client.checkout_configurations.retrieve(
- "ch_xxxxxxxxxxxxxxx",
+ "id",
)
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ assert_matches_type(CheckoutConfigurationRetrieveResponse, checkout_configuration, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_raw_response_retrieve(self, client: Whop) -> None:
response = client.checkout_configurations.with_raw_response.retrieve(
- "ch_xxxxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
checkout_configuration = response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ assert_matches_type(CheckoutConfigurationRetrieveResponse, checkout_configuration, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_streaming_response_retrieve(self, client: Whop) -> None:
with client.checkout_configurations.with_streaming_response.retrieve(
- "ch_xxxxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
checkout_configuration = response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ assert_matches_type(CheckoutConfigurationRetrieveResponse, checkout_configuration, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -311,7 +141,7 @@ def test_path_params_retrieve(self, client: Whop) -> None:
@parametrize
def test_method_list(self, client: Whop) -> None:
checkout_configuration = client.checkout_configurations.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
)
assert_matches_type(
SyncCursorPage[CheckoutConfigurationListResponse], checkout_configuration, path=["response"]
@@ -321,15 +151,14 @@ def test_method_list(self, client: Whop) -> None:
@parametrize
def test_method_list_with_all_params(self, client: Whop) -> None:
checkout_configuration = client.checkout_configurations.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
after="after",
- before="before",
- created_after=parse_datetime("2023-12-01T05:00:00.401Z"),
- created_before=parse_datetime("2023-12-01T05:00:00.401Z"),
+ created_after=0,
+ created_before=0,
direction="asc",
- first=42,
- last=42,
- plan_id="plan_xxxxxxxxxxxxx",
+ first=0,
+ order="created_at",
+ plan_id="plan_id",
)
assert_matches_type(
SyncCursorPage[CheckoutConfigurationListResponse], checkout_configuration, path=["response"]
@@ -339,7 +168,7 @@ def test_method_list_with_all_params(self, client: Whop) -> None:
@parametrize
def test_raw_response_list(self, client: Whop) -> None:
response = client.checkout_configurations.with_raw_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
)
assert response.is_closed is True
@@ -353,7 +182,7 @@ def test_raw_response_list(self, client: Whop) -> None:
@parametrize
def test_streaming_response_list(self, client: Whop) -> None:
with client.checkout_configurations.with_streaming_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -365,252 +194,124 @@ def test_streaming_response_list(self, client: Whop) -> None:
assert cast(Any, response.is_closed) is True
-
-class TestAsyncCheckoutConfigurations:
- 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:
- checkout_configuration = await async_client.checkout_configurations.create(
- plan={
- "company_id": "biz_xxxxxxxxxxxxxx",
- "currency": "usd",
- },
- )
- assert_matches_type(CheckoutConfiguration, checkout_configuration, 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:
- checkout_configuration = await async_client.checkout_configurations.create(
- plan={
- "company_id": "biz_xxxxxxxxxxxxxx",
- "currency": "usd",
- "adaptive_pricing_enabled": True,
- "application_fee_amount": 6.9,
- "billing_period": 42,
- "custom_fields": [
- {
- "field_type": "text",
- "name": "name",
- "id": "id",
- "order": 42,
- "placeholder": "placeholder",
- "required": True,
- }
- ],
- "description": "description",
- "expiration_days": 42,
- "force_create_new_plan": True,
- "image": {"id": "id"},
- "initial_price": 6.9,
- "internal_notes": "internal_notes",
- "override_tax_type": "inclusive",
- "payment_method_configuration": {
- "disabled": ["acss_debit"],
- "enabled": ["acss_debit"],
- "include_platform_defaults": True,
- },
- "plan_type": "renewal",
- "product": {
- "external_identifier": "external_identifier",
- "title": "title",
- "collect_shipping_address": True,
- "custom_statement_descriptor": "custom_statement_descriptor",
- "description": "description",
- "global_affiliate_percentage": 6.9,
- "global_affiliate_status": "enabled",
- "headline": "headline",
- "product_tax_code_id": "ptc_xxxxxxxxxxxxxx",
- "redirect_purchase_url": "redirect_purchase_url",
- "route": "route",
- "visibility": "visible",
- },
- "product_id": "prod_xxxxxxxxxxxxx",
- "release_method": "buy_now",
- "renewal_price": 6.9,
- "split_pay_required_payments": 42,
- "stock": 42,
- "title": "title",
- "trial_period_days": 42,
- "visibility": "visible",
- },
- affiliate_code="affiliate_code",
- allow_promo_codes=True,
- checkout_styling={
- "background_color": "background_color",
- "border_style": "rounded",
- "button_color": "button_color",
- "font_family": "system",
- },
- currency="usd",
- metadata={"foo": "bar"},
- mode="payment",
- payment_method_configuration={
- "disabled": ["acss_debit"],
- "enabled": ["acss_debit"],
- "include_platform_defaults": True,
- },
- redirect_url="redirect_url",
- source_url="source_url",
+ def test_method_delete(self, client: Whop) -> None:
+ checkout_configuration = client.checkout_configurations.delete(
+ "id",
)
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ assert checkout_configuration is None
@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.checkout_configurations.with_raw_response.create(
- plan={
- "company_id": "biz_xxxxxxxxxxxxxx",
- "currency": "usd",
- },
+ def test_raw_response_delete(self, client: Whop) -> None:
+ response = client.checkout_configurations.with_raw_response.delete(
+ "id",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- checkout_configuration = await response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ checkout_configuration = response.parse()
+ assert checkout_configuration is None
@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.checkout_configurations.with_streaming_response.create(
- plan={
- "company_id": "biz_xxxxxxxxxxxxxx",
- "currency": "usd",
- },
+ def test_streaming_response_delete(self, client: Whop) -> None:
+ with client.checkout_configurations.with_streaming_response.delete(
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- checkout_configuration = await response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ checkout_configuration = response.parse()
+ assert checkout_configuration is None
assert cast(Any, response.is_closed) is True
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
- async def test_method_create_overload_2(self, async_client: AsyncWhop) -> None:
- checkout_configuration = await async_client.checkout_configurations.create(
- plan_id="plan_xxxxxxxxxxxxx",
- )
- assert_matches_type(CheckoutConfiguration, checkout_configuration, 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:
- checkout_configuration = await async_client.checkout_configurations.create(
- plan_id="plan_xxxxxxxxxxxxx",
- affiliate_code="affiliate_code",
- allow_promo_codes=True,
- checkout_styling={
- "background_color": "background_color",
- "border_style": "rounded",
- "button_color": "button_color",
- "font_family": "system",
- },
- currency="usd",
- metadata={"foo": "bar"},
- mode="payment",
- payment_method_configuration={
- "disabled": ["acss_debit"],
- "enabled": ["acss_debit"],
- "include_platform_defaults": True,
- },
- redirect_url="redirect_url",
- source_url="source_url",
- )
- assert_matches_type(CheckoutConfiguration, checkout_configuration, 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.checkout_configurations.with_raw_response.create(
- plan_id="plan_xxxxxxxxxxxxx",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- checkout_configuration = await response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, 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.checkout_configurations.with_streaming_response.create(
- plan_id="plan_xxxxxxxxxxxxx",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ 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.checkout_configurations.with_raw_response.delete(
+ "",
+ )
- checkout_configuration = await response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
- assert cast(Any, response.is_closed) is True
+class TestAsyncCheckoutConfigurations:
+ 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_3(self, async_client: AsyncWhop) -> None:
- checkout_configuration = await async_client.checkout_configurations.create(
- company_id="biz_xxxxxxxxxxxxxx",
- mode="setup",
- )
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ async def test_method_create(self, async_client: AsyncWhop) -> None:
+ checkout_configuration = await async_client.checkout_configurations.create()
+ assert_matches_type(CheckoutConfigurationCreateResponse, checkout_configuration, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
- async def test_method_create_with_all_params_overload_3(self, async_client: AsyncWhop) -> None:
+ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> None:
checkout_configuration = await async_client.checkout_configurations.create(
- company_id="biz_xxxxxxxxxxxxxx",
- mode="setup",
- allow_promo_codes=True,
- checkout_styling={
- "background_color": "background_color",
- "border_style": "rounded",
- "button_color": "button_color",
- "font_family": "system",
- },
- currency="usd",
- metadata={"foo": "bar"},
+ affiliate_code="affiliate_code",
+ company_id="company_id",
+ currency="currency",
+ metadata={},
+ mode="payment",
payment_method_configuration={
- "disabled": ["acss_debit"],
- "enabled": ["acss_debit"],
+ "disabled": ["string"],
+ "enabled": ["string"],
"include_platform_defaults": True,
},
+ plan={
+ "billing_period": 0,
+ "company_id": "company_id",
+ "currency": "currency",
+ "description": "description",
+ "expiration_days": 0,
+ "force_create_new_plan": True,
+ "initial_price": 0,
+ "metadata": {},
+ "override_tax_type": "override_tax_type",
+ "payment_method_configuration": {
+ "disabled": ["string"],
+ "enabled": ["string"],
+ "include_platform_defaults": True,
+ },
+ "plan_type": "plan_type",
+ "product_id": "product_id",
+ "release_method": "release_method",
+ "renewal_price": 0,
+ "stock": 0,
+ "title": "title",
+ "trial_period_days": 0,
+ "unlimited_stock": True,
+ "visibility": "visibility",
+ },
+ plan_id="plan_id",
redirect_url="redirect_url",
- source_url="source_url",
- three_ds_level="mandate_challenge",
+ three_ds_level="three_ds_level",
)
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ assert_matches_type(CheckoutConfigurationCreateResponse, checkout_configuration, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
- async def test_raw_response_create_overload_3(self, async_client: AsyncWhop) -> None:
- response = await async_client.checkout_configurations.with_raw_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
- mode="setup",
- )
+ async def test_raw_response_create(self, async_client: AsyncWhop) -> None:
+ response = await async_client.checkout_configurations.with_raw_response.create()
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
checkout_configuration = await response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ assert_matches_type(CheckoutConfigurationCreateResponse, checkout_configuration, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
- async def test_streaming_response_create_overload_3(self, async_client: AsyncWhop) -> None:
- async with async_client.checkout_configurations.with_streaming_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
- mode="setup",
- ) as response:
+ async def test_streaming_response_create(self, async_client: AsyncWhop) -> None:
+ async with async_client.checkout_configurations.with_streaming_response.create() as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
checkout_configuration = await response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ assert_matches_type(CheckoutConfigurationCreateResponse, checkout_configuration, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -618,33 +319,33 @@ async def test_streaming_response_create_overload_3(self, async_client: AsyncWho
@parametrize
async def test_method_retrieve(self, async_client: AsyncWhop) -> None:
checkout_configuration = await async_client.checkout_configurations.retrieve(
- "ch_xxxxxxxxxxxxxxx",
+ "id",
)
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ assert_matches_type(CheckoutConfigurationRetrieveResponse, checkout_configuration, 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.checkout_configurations.with_raw_response.retrieve(
- "ch_xxxxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
checkout_configuration = await response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ assert_matches_type(CheckoutConfigurationRetrieveResponse, checkout_configuration, 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.checkout_configurations.with_streaming_response.retrieve(
- "ch_xxxxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
checkout_configuration = await response.parse()
- assert_matches_type(CheckoutConfiguration, checkout_configuration, path=["response"])
+ assert_matches_type(CheckoutConfigurationRetrieveResponse, checkout_configuration, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -660,7 +361,7 @@ async def test_path_params_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_list(self, async_client: AsyncWhop) -> None:
checkout_configuration = await async_client.checkout_configurations.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
)
assert_matches_type(
AsyncCursorPage[CheckoutConfigurationListResponse], checkout_configuration, path=["response"]
@@ -670,15 +371,14 @@ async def test_method_list(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_list_with_all_params(self, async_client: AsyncWhop) -> None:
checkout_configuration = await async_client.checkout_configurations.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
after="after",
- before="before",
- created_after=parse_datetime("2023-12-01T05:00:00.401Z"),
- created_before=parse_datetime("2023-12-01T05:00:00.401Z"),
+ created_after=0,
+ created_before=0,
direction="asc",
- first=42,
- last=42,
- plan_id="plan_xxxxxxxxxxxxx",
+ first=0,
+ order="created_at",
+ plan_id="plan_id",
)
assert_matches_type(
AsyncCursorPage[CheckoutConfigurationListResponse], checkout_configuration, path=["response"]
@@ -688,7 +388,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncWhop) -> Non
@parametrize
async def test_raw_response_list(self, async_client: AsyncWhop) -> None:
response = await async_client.checkout_configurations.with_raw_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
)
assert response.is_closed is True
@@ -702,7 +402,7 @@ async def test_raw_response_list(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_list(self, async_client: AsyncWhop) -> None:
async with async_client.checkout_configurations.with_streaming_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -713,3 +413,45 @@ async def test_streaming_response_list(self, async_client: AsyncWhop) -> None:
)
assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncWhop) -> None:
+ checkout_configuration = await async_client.checkout_configurations.delete(
+ "id",
+ )
+ assert checkout_configuration is None
+
+ @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.checkout_configurations.with_raw_response.delete(
+ "id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ checkout_configuration = await response.parse()
+ assert checkout_configuration is None
+
+ @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.checkout_configurations.with_streaming_response.delete(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ checkout_configuration = await response.parse()
+ assert checkout_configuration is None
+
+ 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.checkout_configurations.with_raw_response.delete(
+ "",
+ )
diff --git a/tests/api_resources/test_conversions.py b/tests/api_resources/test_conversions.py
index 3b63db11..e0903c3e 100644
--- a/tests/api_resources/test_conversions.py
+++ b/tests/api_resources/test_conversions.py
@@ -38,14 +38,26 @@ def test_method_create_with_all_params(self, client: Whop) -> None:
"ad_campaign_id": "ad_campaign_id",
"ad_id": "ad_id",
"ad_set_id": "ad_set_id",
+ "fbc": "fbc",
"fbclid": "fbclid",
"fbp": "fbp",
+ "fingerprint": "fingerprint",
+ "fingerprint_confidence": 6.9,
"ga": "ga",
+ "gbraid": "gbraid",
"gclid": "gclid",
"ig_sid": "ig_sid",
"ip_address": "ip_address",
+ "language": "language",
+ "li_fat_id": "li_fat_id",
+ "msclkid": "msclkid",
+ "rdt_cid": "rdt_cid",
+ "sccid": "sccid",
+ "screen_resolution": "screen_resolution",
+ "timezone": "timezone",
"ttclid": "ttclid",
"ttp": "ttp",
+ "twclid": "twclid",
"user_agent": "user_agent",
"utm_campaign": "utm_campaign",
"utm_content": "utm_content",
@@ -53,14 +65,19 @@ def test_method_create_with_all_params(self, client: Whop) -> None:
"utm_medium": "utm_medium",
"utm_source": "utm_source",
"utm_term": "utm_term",
+ "wbraid": "wbraid",
},
currency="usd",
custom_name="custom_name",
+ duration=42,
event_id="evnt_xxxxxxxxxxxxx",
event_time=parse_datetime("2023-12-01T05:00:00.401Z"),
plan_id="plan_xxxxxxxxxxxxx",
product_id="prod_xxxxxxxxxxxxx",
referrer_url="referrer_url",
+ resumed=True,
+ source="source",
+ title="title",
url="url",
user={
"anonymous_id": "anonymous_id",
@@ -72,6 +89,8 @@ def test_method_create_with_all_params(self, client: Whop) -> None:
"first_name": "first_name",
"gender": "male",
"last_name": "last_name",
+ "linked_anonymous_id": "linked_anonymous_id",
+ "linked_wuid": "linked_wuid",
"member_id": "mber_xxxxxxxxxxxxx",
"membership_id": "mem_xxxxxxxxxxxxxx",
"name": "name",
@@ -139,14 +158,26 @@ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> N
"ad_campaign_id": "ad_campaign_id",
"ad_id": "ad_id",
"ad_set_id": "ad_set_id",
+ "fbc": "fbc",
"fbclid": "fbclid",
"fbp": "fbp",
+ "fingerprint": "fingerprint",
+ "fingerprint_confidence": 6.9,
"ga": "ga",
+ "gbraid": "gbraid",
"gclid": "gclid",
"ig_sid": "ig_sid",
"ip_address": "ip_address",
+ "language": "language",
+ "li_fat_id": "li_fat_id",
+ "msclkid": "msclkid",
+ "rdt_cid": "rdt_cid",
+ "sccid": "sccid",
+ "screen_resolution": "screen_resolution",
+ "timezone": "timezone",
"ttclid": "ttclid",
"ttp": "ttp",
+ "twclid": "twclid",
"user_agent": "user_agent",
"utm_campaign": "utm_campaign",
"utm_content": "utm_content",
@@ -154,14 +185,19 @@ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> N
"utm_medium": "utm_medium",
"utm_source": "utm_source",
"utm_term": "utm_term",
+ "wbraid": "wbraid",
},
currency="usd",
custom_name="custom_name",
+ duration=42,
event_id="evnt_xxxxxxxxxxxxx",
event_time=parse_datetime("2023-12-01T05:00:00.401Z"),
plan_id="plan_xxxxxxxxxxxxx",
product_id="prod_xxxxxxxxxxxxx",
referrer_url="referrer_url",
+ resumed=True,
+ source="source",
+ title="title",
url="url",
user={
"anonymous_id": "anonymous_id",
@@ -173,6 +209,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> N
"first_name": "first_name",
"gender": "male",
"last_name": "last_name",
+ "linked_anonymous_id": "linked_anonymous_id",
+ "linked_wuid": "linked_wuid",
"member_id": "mber_xxxxxxxxxxxxx",
"membership_id": "mem_xxxxxxxxxxxxxx",
"name": "name",
diff --git a/tests/api_resources/test_deposits.py b/tests/api_resources/test_deposits.py
index 7786dbc8..e26f749e 100644
--- a/tests/api_resources/test_deposits.py
+++ b/tests/api_resources/test_deposits.py
@@ -9,7 +9,7 @@
from whop_sdk import Whop, AsyncWhop
from tests.utils import assert_matches_type
-from whop_sdk.types import DepositCreateResponse
+from whop_sdk.types import DepositListResponse, DepositCreateResponse
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -21,7 +21,6 @@ class TestDeposits:
@parametrize
def test_method_create(self, client: Whop) -> None:
deposit = client.deposits.create(
- amount=0,
destination="string",
)
assert_matches_type(DepositCreateResponse, deposit, path=["response"])
@@ -30,8 +29,8 @@ def test_method_create(self, client: Whop) -> None:
@parametrize
def test_method_create_with_all_params(self, client: Whop) -> None:
deposit = client.deposits.create(
- amount=0,
destination="string",
+ amount=0,
metadata={"foo": "bar"},
network="network",
)
@@ -41,7 +40,6 @@ def test_method_create_with_all_params(self, client: Whop) -> None:
@parametrize
def test_raw_response_create(self, client: Whop) -> None:
response = client.deposits.with_raw_response.create(
- amount=0,
destination="string",
)
@@ -54,7 +52,6 @@ def test_raw_response_create(self, client: Whop) -> None:
@parametrize
def test_streaming_response_create(self, client: Whop) -> None:
with client.deposits.with_streaming_response.create(
- amount=0,
destination="string",
) as response:
assert not response.is_closed
@@ -65,6 +62,40 @@ def test_streaming_response_create(self, client: Whop) -> None:
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Whop) -> None:
+ deposit = client.deposits.list(
+ account_id="account_id",
+ )
+ assert_matches_type(DepositListResponse, deposit, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Whop) -> None:
+ response = client.deposits.with_raw_response.list(
+ account_id="account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ deposit = response.parse()
+ assert_matches_type(DepositListResponse, deposit, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Whop) -> None:
+ with client.deposits.with_streaming_response.list(
+ account_id="account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ deposit = response.parse()
+ assert_matches_type(DepositListResponse, deposit, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
class TestAsyncDeposits:
parametrize = pytest.mark.parametrize(
@@ -75,7 +106,6 @@ class TestAsyncDeposits:
@parametrize
async def test_method_create(self, async_client: AsyncWhop) -> None:
deposit = await async_client.deposits.create(
- amount=0,
destination="string",
)
assert_matches_type(DepositCreateResponse, deposit, path=["response"])
@@ -84,8 +114,8 @@ async def test_method_create(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> None:
deposit = await async_client.deposits.create(
- amount=0,
destination="string",
+ amount=0,
metadata={"foo": "bar"},
network="network",
)
@@ -95,7 +125,6 @@ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> N
@parametrize
async def test_raw_response_create(self, async_client: AsyncWhop) -> None:
response = await async_client.deposits.with_raw_response.create(
- amount=0,
destination="string",
)
@@ -108,7 +137,6 @@ async def test_raw_response_create(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_create(self, async_client: AsyncWhop) -> None:
async with async_client.deposits.with_streaming_response.create(
- amount=0,
destination="string",
) as response:
assert not response.is_closed
@@ -118,3 +146,37 @@ async def test_streaming_response_create(self, async_client: AsyncWhop) -> None:
assert_matches_type(DepositCreateResponse, deposit, path=["response"])
assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncWhop) -> None:
+ deposit = await async_client.deposits.list(
+ account_id="account_id",
+ )
+ assert_matches_type(DepositListResponse, deposit, 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.deposits.with_raw_response.list(
+ account_id="account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ deposit = await response.parse()
+ assert_matches_type(DepositListResponse, deposit, 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.deposits.with_streaming_response.list(
+ account_id="account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ deposit = await response.parse()
+ assert_matches_type(DepositListResponse, deposit, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_events.py b/tests/api_resources/test_events.py
new file mode 100644
index 00000000..f6807a2f
--- /dev/null
+++ b/tests/api_resources/test_events.py
@@ -0,0 +1,116 @@
+# 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 EventListResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestEvents:
+ 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_list(self, client: Whop) -> None:
+ event = client.events.list(
+ person_id="person_id",
+ )
+ assert_matches_type(EventListResponse, event, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Whop) -> None:
+ event = client.events.list(
+ person_id="person_id",
+ account_id="account_id",
+ first=0,
+ from_=0,
+ to=0,
+ )
+ assert_matches_type(EventListResponse, event, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Whop) -> None:
+ response = client.events.with_raw_response.list(
+ person_id="person_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ event = response.parse()
+ assert_matches_type(EventListResponse, event, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Whop) -> None:
+ with client.events.with_streaming_response.list(
+ person_id="person_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ event = response.parse()
+ assert_matches_type(EventListResponse, event, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncEvents:
+ 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_list(self, async_client: AsyncWhop) -> None:
+ event = await async_client.events.list(
+ person_id="person_id",
+ )
+ assert_matches_type(EventListResponse, event, 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:
+ event = await async_client.events.list(
+ person_id="person_id",
+ account_id="account_id",
+ first=0,
+ from_=0,
+ to=0,
+ )
+ assert_matches_type(EventListResponse, event, 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.events.with_raw_response.list(
+ person_id="person_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ event = await response.parse()
+ assert_matches_type(EventListResponse, event, 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.events.with_streaming_response.list(
+ person_id="person_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ event = await response.parse()
+ assert_matches_type(EventListResponse, event, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_financial_activity.py b/tests/api_resources/test_financial_activity.py
new file mode 100644
index 00000000..985c2c85
--- /dev/null
+++ b/tests/api_resources/test_financial_activity.py
@@ -0,0 +1,115 @@
+# 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 FinancialActivityListResponse
+from whop_sdk._utils import parse_date, parse_datetime
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestFinancialActivity:
+ 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_list(self, client: Whop) -> None:
+ financial_activity = client.financial_activity.list()
+ assert_matches_type(FinancialActivityListResponse, financial_activity, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Whop) -> None:
+ financial_activity = client.financial_activity.list(
+ account_id="account_id",
+ available_after=parse_date("2019-12-27"),
+ available_before=parse_date("2019-12-27"),
+ currency="currency",
+ cursor="cursor",
+ limit=100,
+ line_types=["string"],
+ posted_after=parse_datetime("2019-12-27T18:11:19.117Z"),
+ posted_before=parse_datetime("2019-12-27T18:11:19.117Z"),
+ user_id="user_id",
+ )
+ assert_matches_type(FinancialActivityListResponse, financial_activity, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Whop) -> None:
+ response = client.financial_activity.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ financial_activity = response.parse()
+ assert_matches_type(FinancialActivityListResponse, financial_activity, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Whop) -> None:
+ with client.financial_activity.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ financial_activity = response.parse()
+ assert_matches_type(FinancialActivityListResponse, financial_activity, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncFinancialActivity:
+ 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_list(self, async_client: AsyncWhop) -> None:
+ financial_activity = await async_client.financial_activity.list()
+ assert_matches_type(FinancialActivityListResponse, financial_activity, 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:
+ financial_activity = await async_client.financial_activity.list(
+ account_id="account_id",
+ available_after=parse_date("2019-12-27"),
+ available_before=parse_date("2019-12-27"),
+ currency="currency",
+ cursor="cursor",
+ limit=100,
+ line_types=["string"],
+ posted_after=parse_datetime("2019-12-27T18:11:19.117Z"),
+ posted_before=parse_datetime("2019-12-27T18:11:19.117Z"),
+ user_id="user_id",
+ )
+ assert_matches_type(FinancialActivityListResponse, financial_activity, 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.financial_activity.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ financial_activity = await response.parse()
+ assert_matches_type(FinancialActivityListResponse, financial_activity, 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.financial_activity.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ financial_activity = await response.parse()
+ assert_matches_type(FinancialActivityListResponse, financial_activity, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_invoices.py b/tests/api_resources/test_invoices.py
index 30be40a0..cfd94e2e 100644
--- a/tests/api_resources/test_invoices.py
+++ b/tests/api_resources/test_invoices.py
@@ -43,7 +43,9 @@ def test_method_create_with_all_params_overload_1(self, client: Whop) -> None:
collection_method="send_invoice",
company_id="biz_xxxxxxxxxxxxxx",
plan={
+ "adaptive_pricing_enabled": True,
"billing_period": 42,
+ "currency": "usd",
"custom_fields": [
{
"field_type": "text",
@@ -159,7 +161,9 @@ def test_method_create_with_all_params_overload_2(self, client: Whop) -> None:
collection_method="send_invoice",
company_id="biz_xxxxxxxxxxxxxx",
plan={
+ "adaptive_pricing_enabled": True,
"billing_period": 42,
+ "currency": "usd",
"custom_fields": [
{
"field_type": "text",
@@ -338,7 +342,9 @@ def test_method_update_with_all_params(self, client: Whop) -> None:
member_id="mber_xxxxxxxxxxxxx",
payment_method_id="pmt_xxxxxxxxxxxxxx",
plan={
+ "adaptive_pricing_enabled": True,
"billing_period": 42,
+ "currency": "usd",
"custom_fields": [
{
"field_type": "text",
@@ -645,7 +651,9 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn
collection_method="send_invoice",
company_id="biz_xxxxxxxxxxxxxx",
plan={
+ "adaptive_pricing_enabled": True,
"billing_period": 42,
+ "currency": "usd",
"custom_fields": [
{
"field_type": "text",
@@ -761,7 +769,9 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn
collection_method="send_invoice",
company_id="biz_xxxxxxxxxxxxxx",
plan={
+ "adaptive_pricing_enabled": True,
"billing_period": 42,
+ "currency": "usd",
"custom_fields": [
{
"field_type": "text",
@@ -940,7 +950,9 @@ async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> N
member_id="mber_xxxxxxxxxxxxx",
payment_method_id="pmt_xxxxxxxxxxxxxx",
plan={
+ "adaptive_pricing_enabled": True,
"billing_period": 42,
+ "currency": "usd",
"custom_fields": [
{
"field_type": "text",
diff --git a/tests/api_resources/test_payouts.py b/tests/api_resources/test_payouts.py
new file mode 100644
index 00000000..df377533
--- /dev/null
+++ b/tests/api_resources/test_payouts.py
@@ -0,0 +1,109 @@
+# 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 PayoutListResponse
+from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestPayouts:
+ 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_list(self, client: Whop) -> None:
+ payout = client.payouts.list()
+ assert_matches_type(SyncCursorPage[PayoutListResponse], payout, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Whop) -> None:
+ payout = client.payouts.list(
+ account_id="account_id",
+ after="after",
+ before="before",
+ currency="currency",
+ first=100,
+ last=100,
+ user_id="user_id",
+ )
+ assert_matches_type(SyncCursorPage[PayoutListResponse], payout, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Whop) -> None:
+ response = client.payouts.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ payout = response.parse()
+ assert_matches_type(SyncCursorPage[PayoutListResponse], payout, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Whop) -> None:
+ with client.payouts.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ payout = response.parse()
+ assert_matches_type(SyncCursorPage[PayoutListResponse], payout, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncPayouts:
+ 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_list(self, async_client: AsyncWhop) -> None:
+ payout = await async_client.payouts.list()
+ assert_matches_type(AsyncCursorPage[PayoutListResponse], payout, 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:
+ payout = await async_client.payouts.list(
+ account_id="account_id",
+ after="after",
+ before="before",
+ currency="currency",
+ first=100,
+ last=100,
+ user_id="user_id",
+ )
+ assert_matches_type(AsyncCursorPage[PayoutListResponse], payout, 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.payouts.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ payout = await response.parse()
+ assert_matches_type(AsyncCursorPage[PayoutListResponse], payout, 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.payouts.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ payout = await response.parse()
+ assert_matches_type(AsyncCursorPage[PayoutListResponse], payout, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_people.py b/tests/api_resources/test_people.py
new file mode 100644
index 00000000..8bf092ec
--- /dev/null
+++ b/tests/api_resources/test_people.py
@@ -0,0 +1,216 @@
+# 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 PersonListResponse, PersonRetrieveResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestPeople:
+ 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_retrieve(self, client: Whop) -> None:
+ person = client.people.retrieve(
+ person_id="person_id",
+ )
+ assert_matches_type(PersonRetrieveResponse, person, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_retrieve_with_all_params(self, client: Whop) -> None:
+ person = client.people.retrieve(
+ person_id="person_id",
+ account_id="account_id",
+ from_=0,
+ to=0,
+ )
+ assert_matches_type(PersonRetrieveResponse, person, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_retrieve(self, client: Whop) -> None:
+ response = client.people.with_raw_response.retrieve(
+ person_id="person_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ person = response.parse()
+ assert_matches_type(PersonRetrieveResponse, person, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Whop) -> None:
+ with client.people.with_streaming_response.retrieve(
+ person_id="person_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ person = response.parse()
+ assert_matches_type(PersonRetrieveResponse, person, 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 `person_id` but received ''"):
+ client.people.with_raw_response.retrieve(
+ person_id="",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Whop) -> None:
+ person = client.people.list()
+ assert_matches_type(PersonListResponse, person, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Whop) -> None:
+ person = client.people.list(
+ account_id="account_id",
+ direction="asc",
+ filters="filters",
+ first=0,
+ from_=0,
+ offset=0,
+ sort="sort",
+ to=0,
+ )
+ assert_matches_type(PersonListResponse, person, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Whop) -> None:
+ response = client.people.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ person = response.parse()
+ assert_matches_type(PersonListResponse, person, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Whop) -> None:
+ with client.people.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ person = response.parse()
+ assert_matches_type(PersonListResponse, person, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncPeople:
+ 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_retrieve(self, async_client: AsyncWhop) -> None:
+ person = await async_client.people.retrieve(
+ person_id="person_id",
+ )
+ assert_matches_type(PersonRetrieveResponse, person, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_retrieve_with_all_params(self, async_client: AsyncWhop) -> None:
+ person = await async_client.people.retrieve(
+ person_id="person_id",
+ account_id="account_id",
+ from_=0,
+ to=0,
+ )
+ assert_matches_type(PersonRetrieveResponse, person, 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.people.with_raw_response.retrieve(
+ person_id="person_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ person = await response.parse()
+ assert_matches_type(PersonRetrieveResponse, person, 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.people.with_streaming_response.retrieve(
+ person_id="person_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ person = await response.parse()
+ assert_matches_type(PersonRetrieveResponse, person, 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 `person_id` but received ''"):
+ await async_client.people.with_raw_response.retrieve(
+ person_id="",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncWhop) -> None:
+ person = await async_client.people.list()
+ assert_matches_type(PersonListResponse, person, 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:
+ person = await async_client.people.list(
+ account_id="account_id",
+ direction="asc",
+ filters="filters",
+ first=0,
+ from_=0,
+ offset=0,
+ sort="sort",
+ to=0,
+ )
+ assert_matches_type(PersonListResponse, person, 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.people.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ person = await response.parse()
+ assert_matches_type(PersonListResponse, person, 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.people.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ person = await response.parse()
+ assert_matches_type(PersonListResponse, person, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_plans.py b/tests/api_resources/test_plans.py
index 1a92b368..cc6f9788 100644
--- a/tests/api_resources/test_plans.py
+++ b/tests/api_resources/test_plans.py
@@ -12,8 +12,8 @@
from whop_sdk.types import (
PlanListResponse,
PlanDeleteResponse,
+ PlanCalculateTaxResponse,
)
-from whop_sdk._utils import parse_datetime
from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
from whop_sdk.types.shared import Plan
@@ -26,70 +26,62 @@ class TestPlans:
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_create(self, client: Whop) -> None:
- plan = client.plans.create(
- company_id="biz_xxxxxxxxxxxxxx",
- product_id="prod_xxxxxxxxxxxxx",
- )
+ plan = client.plans.create()
assert_matches_type(Plan, plan, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_create_with_all_params(self, client: Whop) -> None:
plan = client.plans.create(
- company_id="biz_xxxxxxxxxxxxxx",
- product_id="prod_xxxxxxxxxxxxx",
+ account_id="account_id",
adaptive_pricing_enabled=True,
- billing_period=42,
- checkout_styling={
- "background_color": "background_color",
- "border_style": "rounded",
- "button_color": "button_color",
- "font_family": "system",
- },
- currency="usd",
+ billing_period=0,
+ checkout_styling={},
+ currency="currency",
custom_fields=[
{
+ "id": "id",
"field_type": "text",
"name": "name",
- "id": "id",
- "order": 42,
+ "order": 0,
"placeholder": "placeholder",
"required": True,
}
],
description="description",
- expiration_days=42,
- image={"id": "id"},
- initial_price=6.9,
+ expiration_days=0,
+ image={
+ "id": "id",
+ "direct_upload_id": "direct_upload_id",
+ },
+ initial_price=0,
internal_notes="internal_notes",
legacy_payment_method_controls=True,
- metadata={"foo": "bar"},
- override_tax_type="inclusive",
+ metadata={},
+ override_tax_type="override_tax_type",
payment_method_configuration={
- "disabled": ["acss_debit"],
- "enabled": ["acss_debit"],
+ "disabled": ["string"],
+ "enabled": ["string"],
"include_platform_defaults": True,
},
- plan_type="renewal",
- release_method="buy_now",
- renewal_price=6.9,
- split_pay_required_payments=42,
- stock=42,
+ plan_type="plan_type",
+ product_id="product_id",
+ release_method="release_method",
+ renewal_price=0,
+ split_pay_required_payments=0,
+ stock=0,
three_ds_level="mandate_challenge",
title="title",
- trial_period_days=42,
+ trial_period_days=0,
unlimited_stock=True,
- visibility="visible",
+ visibility="visibility",
)
assert_matches_type(Plan, plan, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_raw_response_create(self, client: Whop) -> None:
- response = client.plans.with_raw_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
- product_id="prod_xxxxxxxxxxxxx",
- )
+ response = client.plans.with_raw_response.create()
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -99,10 +91,7 @@ def test_raw_response_create(self, client: Whop) -> None:
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_streaming_response_create(self, client: Whop) -> None:
- with client.plans.with_streaming_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
- product_id="prod_xxxxxxxxxxxxx",
- ) as response:
+ with client.plans.with_streaming_response.create() as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -115,7 +104,7 @@ def test_streaming_response_create(self, client: Whop) -> None:
@parametrize
def test_method_retrieve(self, client: Whop) -> None:
plan = client.plans.retrieve(
- "plan_xxxxxxxxxxxxx",
+ "id",
)
assert_matches_type(Plan, plan, path=["response"])
@@ -123,7 +112,7 @@ def test_method_retrieve(self, client: Whop) -> None:
@parametrize
def test_raw_response_retrieve(self, client: Whop) -> None:
response = client.plans.with_raw_response.retrieve(
- "plan_xxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -135,7 +124,7 @@ def test_raw_response_retrieve(self, client: Whop) -> None:
@parametrize
def test_streaming_response_retrieve(self, client: Whop) -> None:
with client.plans.with_streaming_response.retrieve(
- "plan_xxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -157,7 +146,7 @@ def test_path_params_retrieve(self, client: Whop) -> None:
@parametrize
def test_method_update(self, client: Whop) -> None:
plan = client.plans.update(
- id="plan_xxxxxxxxxxxxx",
+ id="id",
)
assert_matches_type(Plan, plan, path=["response"])
@@ -165,49 +154,47 @@ def test_method_update(self, client: Whop) -> None:
@parametrize
def test_method_update_with_all_params(self, client: Whop) -> None:
plan = client.plans.update(
- id="plan_xxxxxxxxxxxxx",
+ id="id",
adaptive_pricing_enabled=True,
- billing_period=42,
- checkout_styling={
- "background_color": "background_color",
- "border_style": "rounded",
- "button_color": "button_color",
- "font_family": "system",
- },
- currency="usd",
+ billing_period=0,
+ checkout_styling={},
+ currency="currency",
custom_fields=[
{
+ "id": "id",
"field_type": "text",
"name": "name",
- "id": "id",
- "order": 42,
+ "order": 0,
"placeholder": "placeholder",
"required": True,
}
],
description="description",
- expiration_days=42,
- image={"id": "id"},
- initial_price=6.9,
+ expiration_days=0,
+ image={
+ "id": "id",
+ "direct_upload_id": "direct_upload_id",
+ },
+ initial_price=0,
internal_notes="internal_notes",
legacy_payment_method_controls=True,
- metadata={"foo": "bar"},
+ metadata={},
offer_cancel_discount=True,
- override_tax_type="inclusive",
+ override_tax_type="override_tax_type",
payment_method_configuration={
- "disabled": ["acss_debit"],
- "enabled": ["acss_debit"],
+ "disabled": ["string"],
+ "enabled": ["string"],
"include_platform_defaults": True,
},
- renewal_price=6.9,
- stock=42,
- strike_through_initial_price=6.9,
- strike_through_renewal_price=6.9,
+ renewal_price=0,
+ stock=0,
+ strike_through_initial_price=0,
+ strike_through_renewal_price=0,
three_ds_level="mandate_challenge",
title="title",
- trial_period_days=42,
+ trial_period_days=0,
unlimited_stock=True,
- visibility="visible",
+ visibility="visibility",
)
assert_matches_type(Plan, plan, path=["response"])
@@ -215,7 +202,7 @@ def test_method_update_with_all_params(self, client: Whop) -> None:
@parametrize
def test_raw_response_update(self, client: Whop) -> None:
response = client.plans.with_raw_response.update(
- id="plan_xxxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -227,7 +214,7 @@ def test_raw_response_update(self, client: Whop) -> None:
@parametrize
def test_streaming_response_update(self, client: Whop) -> None:
with client.plans.with_streaming_response.update(
- id="plan_xxxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -249,7 +236,7 @@ def test_path_params_update(self, client: Whop) -> None:
@parametrize
def test_method_list(self, client: Whop) -> None:
plan = client.plans.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ account_id="account_id",
)
assert_matches_type(SyncCursorPage[PlanListResponse], plan, path=["response"])
@@ -257,19 +244,19 @@ def test_method_list(self, client: Whop) -> None:
@parametrize
def test_method_list_with_all_params(self, client: Whop) -> None:
plan = client.plans.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ account_id="account_id",
after="after",
before="before",
- created_after=parse_datetime("2023-12-01T05:00:00.401Z"),
- created_before=parse_datetime("2023-12-01T05:00:00.401Z"),
+ created_after="created_after",
+ created_before="created_before",
direction="asc",
- first=42,
- last=42,
+ first=0,
+ last=0,
order="id",
- plan_types=["renewal"],
+ plan_types=["string"],
product_ids=["string"],
- release_methods=["buy_now"],
- visibilities=["visible"],
+ release_methods=["string"],
+ visibilities=["string"],
)
assert_matches_type(SyncCursorPage[PlanListResponse], plan, path=["response"])
@@ -277,7 +264,7 @@ def test_method_list_with_all_params(self, client: Whop) -> None:
@parametrize
def test_raw_response_list(self, client: Whop) -> None:
response = client.plans.with_raw_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ account_id="account_id",
)
assert response.is_closed is True
@@ -289,7 +276,7 @@ def test_raw_response_list(self, client: Whop) -> None:
@parametrize
def test_streaming_response_list(self, client: Whop) -> None:
with client.plans.with_streaming_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ account_id="account_id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -303,7 +290,7 @@ def test_streaming_response_list(self, client: Whop) -> None:
@parametrize
def test_method_delete(self, client: Whop) -> None:
plan = client.plans.delete(
- "plan_xxxxxxxxxxxxx",
+ "id",
)
assert_matches_type(PlanDeleteResponse, plan, path=["response"])
@@ -311,7 +298,7 @@ def test_method_delete(self, client: Whop) -> None:
@parametrize
def test_raw_response_delete(self, client: Whop) -> None:
response = client.plans.with_raw_response.delete(
- "plan_xxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -323,7 +310,7 @@ def test_raw_response_delete(self, client: Whop) -> None:
@parametrize
def test_streaming_response_delete(self, client: Whop) -> None:
with client.plans.with_streaming_response.delete(
- "plan_xxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -341,6 +328,71 @@ def test_path_params_delete(self, client: Whop) -> None:
"",
)
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_calculate_tax(self, client: Whop) -> None:
+ plan = client.plans.calculate_tax(
+ id="id",
+ )
+ assert_matches_type(PlanCalculateTaxResponse, plan, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_calculate_tax_with_all_params(self, client: Whop) -> None:
+ plan = client.plans.calculate_tax(
+ id="id",
+ address={
+ "country": "country",
+ "city": "city",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
+ ip_address="ip_address",
+ tax_ids=[
+ {
+ "type": "ad_nrt",
+ "value": "value",
+ }
+ ],
+ )
+ assert_matches_type(PlanCalculateTaxResponse, plan, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_calculate_tax(self, client: Whop) -> None:
+ response = client.plans.with_raw_response.calculate_tax(
+ id="id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ plan = response.parse()
+ assert_matches_type(PlanCalculateTaxResponse, plan, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_calculate_tax(self, client: Whop) -> None:
+ with client.plans.with_streaming_response.calculate_tax(
+ id="id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ plan = response.parse()
+ assert_matches_type(PlanCalculateTaxResponse, plan, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_path_params_calculate_tax(self, client: Whop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.plans.with_raw_response.calculate_tax(
+ id="",
+ )
+
class TestAsyncPlans:
parametrize = pytest.mark.parametrize(
@@ -350,70 +402,62 @@ class TestAsyncPlans:
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_method_create(self, async_client: AsyncWhop) -> None:
- plan = await async_client.plans.create(
- company_id="biz_xxxxxxxxxxxxxx",
- product_id="prod_xxxxxxxxxxxxx",
- )
+ plan = await async_client.plans.create()
assert_matches_type(Plan, plan, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> None:
plan = await async_client.plans.create(
- company_id="biz_xxxxxxxxxxxxxx",
- product_id="prod_xxxxxxxxxxxxx",
+ account_id="account_id",
adaptive_pricing_enabled=True,
- billing_period=42,
- checkout_styling={
- "background_color": "background_color",
- "border_style": "rounded",
- "button_color": "button_color",
- "font_family": "system",
- },
- currency="usd",
+ billing_period=0,
+ checkout_styling={},
+ currency="currency",
custom_fields=[
{
+ "id": "id",
"field_type": "text",
"name": "name",
- "id": "id",
- "order": 42,
+ "order": 0,
"placeholder": "placeholder",
"required": True,
}
],
description="description",
- expiration_days=42,
- image={"id": "id"},
- initial_price=6.9,
+ expiration_days=0,
+ image={
+ "id": "id",
+ "direct_upload_id": "direct_upload_id",
+ },
+ initial_price=0,
internal_notes="internal_notes",
legacy_payment_method_controls=True,
- metadata={"foo": "bar"},
- override_tax_type="inclusive",
+ metadata={},
+ override_tax_type="override_tax_type",
payment_method_configuration={
- "disabled": ["acss_debit"],
- "enabled": ["acss_debit"],
+ "disabled": ["string"],
+ "enabled": ["string"],
"include_platform_defaults": True,
},
- plan_type="renewal",
- release_method="buy_now",
- renewal_price=6.9,
- split_pay_required_payments=42,
- stock=42,
+ plan_type="plan_type",
+ product_id="product_id",
+ release_method="release_method",
+ renewal_price=0,
+ split_pay_required_payments=0,
+ stock=0,
three_ds_level="mandate_challenge",
title="title",
- trial_period_days=42,
+ trial_period_days=0,
unlimited_stock=True,
- visibility="visible",
+ visibility="visibility",
)
assert_matches_type(Plan, plan, 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.plans.with_raw_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
- product_id="prod_xxxxxxxxxxxxx",
- )
+ response = await async_client.plans.with_raw_response.create()
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -423,10 +467,7 @@ async def test_raw_response_create(self, async_client: AsyncWhop) -> None:
@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.plans.with_streaming_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
- product_id="prod_xxxxxxxxxxxxx",
- ) as response:
+ async with async_client.plans.with_streaming_response.create() as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -439,7 +480,7 @@ async def test_streaming_response_create(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_retrieve(self, async_client: AsyncWhop) -> None:
plan = await async_client.plans.retrieve(
- "plan_xxxxxxxxxxxxx",
+ "id",
)
assert_matches_type(Plan, plan, path=["response"])
@@ -447,7 +488,7 @@ async def test_method_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None:
response = await async_client.plans.with_raw_response.retrieve(
- "plan_xxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -459,7 +500,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_retrieve(self, async_client: AsyncWhop) -> None:
async with async_client.plans.with_streaming_response.retrieve(
- "plan_xxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -481,7 +522,7 @@ async def test_path_params_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_update(self, async_client: AsyncWhop) -> None:
plan = await async_client.plans.update(
- id="plan_xxxxxxxxxxxxx",
+ id="id",
)
assert_matches_type(Plan, plan, path=["response"])
@@ -489,49 +530,47 @@ async def test_method_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> None:
plan = await async_client.plans.update(
- id="plan_xxxxxxxxxxxxx",
+ id="id",
adaptive_pricing_enabled=True,
- billing_period=42,
- checkout_styling={
- "background_color": "background_color",
- "border_style": "rounded",
- "button_color": "button_color",
- "font_family": "system",
- },
- currency="usd",
+ billing_period=0,
+ checkout_styling={},
+ currency="currency",
custom_fields=[
{
+ "id": "id",
"field_type": "text",
"name": "name",
- "id": "id",
- "order": 42,
+ "order": 0,
"placeholder": "placeholder",
"required": True,
}
],
description="description",
- expiration_days=42,
- image={"id": "id"},
- initial_price=6.9,
+ expiration_days=0,
+ image={
+ "id": "id",
+ "direct_upload_id": "direct_upload_id",
+ },
+ initial_price=0,
internal_notes="internal_notes",
legacy_payment_method_controls=True,
- metadata={"foo": "bar"},
+ metadata={},
offer_cancel_discount=True,
- override_tax_type="inclusive",
+ override_tax_type="override_tax_type",
payment_method_configuration={
- "disabled": ["acss_debit"],
- "enabled": ["acss_debit"],
+ "disabled": ["string"],
+ "enabled": ["string"],
"include_platform_defaults": True,
},
- renewal_price=6.9,
- stock=42,
- strike_through_initial_price=6.9,
- strike_through_renewal_price=6.9,
+ renewal_price=0,
+ stock=0,
+ strike_through_initial_price=0,
+ strike_through_renewal_price=0,
three_ds_level="mandate_challenge",
title="title",
- trial_period_days=42,
+ trial_period_days=0,
unlimited_stock=True,
- visibility="visible",
+ visibility="visibility",
)
assert_matches_type(Plan, plan, path=["response"])
@@ -539,7 +578,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> N
@parametrize
async def test_raw_response_update(self, async_client: AsyncWhop) -> None:
response = await async_client.plans.with_raw_response.update(
- id="plan_xxxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -551,7 +590,7 @@ async def test_raw_response_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_update(self, async_client: AsyncWhop) -> None:
async with async_client.plans.with_streaming_response.update(
- id="plan_xxxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -573,7 +612,7 @@ async def test_path_params_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_list(self, async_client: AsyncWhop) -> None:
plan = await async_client.plans.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ account_id="account_id",
)
assert_matches_type(AsyncCursorPage[PlanListResponse], plan, path=["response"])
@@ -581,19 +620,19 @@ async def test_method_list(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_list_with_all_params(self, async_client: AsyncWhop) -> None:
plan = await async_client.plans.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ account_id="account_id",
after="after",
before="before",
- created_after=parse_datetime("2023-12-01T05:00:00.401Z"),
- created_before=parse_datetime("2023-12-01T05:00:00.401Z"),
+ created_after="created_after",
+ created_before="created_before",
direction="asc",
- first=42,
- last=42,
+ first=0,
+ last=0,
order="id",
- plan_types=["renewal"],
+ plan_types=["string"],
product_ids=["string"],
- release_methods=["buy_now"],
- visibilities=["visible"],
+ release_methods=["string"],
+ visibilities=["string"],
)
assert_matches_type(AsyncCursorPage[PlanListResponse], plan, path=["response"])
@@ -601,7 +640,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncWhop) -> Non
@parametrize
async def test_raw_response_list(self, async_client: AsyncWhop) -> None:
response = await async_client.plans.with_raw_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ account_id="account_id",
)
assert response.is_closed is True
@@ -613,7 +652,7 @@ async def test_raw_response_list(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_list(self, async_client: AsyncWhop) -> None:
async with async_client.plans.with_streaming_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ account_id="account_id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -627,7 +666,7 @@ async def test_streaming_response_list(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_delete(self, async_client: AsyncWhop) -> None:
plan = await async_client.plans.delete(
- "plan_xxxxxxxxxxxxx",
+ "id",
)
assert_matches_type(PlanDeleteResponse, plan, path=["response"])
@@ -635,7 +674,7 @@ async def test_method_delete(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_delete(self, async_client: AsyncWhop) -> None:
response = await async_client.plans.with_raw_response.delete(
- "plan_xxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -647,7 +686,7 @@ async def test_raw_response_delete(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_delete(self, async_client: AsyncWhop) -> None:
async with async_client.plans.with_streaming_response.delete(
- "plan_xxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -664,3 +703,68 @@ async def test_path_params_delete(self, async_client: AsyncWhop) -> None:
await async_client.plans.with_raw_response.delete(
"",
)
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_calculate_tax(self, async_client: AsyncWhop) -> None:
+ plan = await async_client.plans.calculate_tax(
+ id="id",
+ )
+ assert_matches_type(PlanCalculateTaxResponse, plan, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_calculate_tax_with_all_params(self, async_client: AsyncWhop) -> None:
+ plan = await async_client.plans.calculate_tax(
+ id="id",
+ address={
+ "country": "country",
+ "city": "city",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
+ ip_address="ip_address",
+ tax_ids=[
+ {
+ "type": "ad_nrt",
+ "value": "value",
+ }
+ ],
+ )
+ assert_matches_type(PlanCalculateTaxResponse, plan, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_calculate_tax(self, async_client: AsyncWhop) -> None:
+ response = await async_client.plans.with_raw_response.calculate_tax(
+ id="id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ plan = await response.parse()
+ assert_matches_type(PlanCalculateTaxResponse, plan, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_calculate_tax(self, async_client: AsyncWhop) -> None:
+ async with async_client.plans.with_streaming_response.calculate_tax(
+ id="id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ plan = await response.parse()
+ assert_matches_type(PlanCalculateTaxResponse, plan, 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_calculate_tax(self, async_client: AsyncWhop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.plans.with_raw_response.calculate_tax(
+ id="",
+ )
diff --git a/tests/api_resources/test_products.py b/tests/api_resources/test_products.py
index b9a1c329..99906e8b 100644
--- a/tests/api_resources/test_products.py
+++ b/tests/api_resources/test_products.py
@@ -9,10 +9,7 @@
from whop_sdk import Whop, AsyncWhop
from tests.utils import assert_matches_type
-from whop_sdk.types import (
- ProductDeleteResponse,
-)
-from whop_sdk._utils import parse_datetime
+from whop_sdk.types import ProductDeleteResponse
from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
from whop_sdk.types.shared import Product, ProductListItem
@@ -26,7 +23,6 @@ class TestProducts:
@parametrize
def test_method_create(self, client: Whop) -> None:
product = client.products.create(
- company_id="biz_xxxxxxxxxxxxxx",
title="title",
)
assert_matches_type(Product, product, path=["response"])
@@ -35,44 +31,23 @@ def test_method_create(self, client: Whop) -> None:
@parametrize
def test_method_create_with_all_params(self, client: Whop) -> None:
product = client.products.create(
- company_id="biz_xxxxxxxxxxxxxx",
title="title",
collect_shipping_address=True,
- custom_cta="get_access",
+ company_id="company_id",
+ custom_cta="custom_cta",
custom_cta_url="custom_cta_url",
custom_statement_descriptor="custom_statement_descriptor",
description="description",
- experience_ids=["string"],
- global_affiliate_percentage=6.9,
- global_affiliate_status="enabled",
+ global_affiliate_percentage=0,
+ global_affiliate_status="global_affiliate_status",
headline="headline",
- member_affiliate_percentage=6.9,
- member_affiliate_status="enabled",
- metadata={"foo": "bar"},
- plan_options={
- "base_currency": "usd",
- "billing_period": 42,
- "custom_fields": [
- {
- "field_type": "text",
- "name": "name",
- "id": "id",
- "order": 42,
- "placeholder": "placeholder",
- "required": True,
- }
- ],
- "initial_price": 6.9,
- "plan_type": "renewal",
- "release_method": "buy_now",
- "renewal_price": 6.9,
- "visibility": "visible",
- },
- product_tax_code_id="ptc_xxxxxxxxxxxxxx",
+ member_affiliate_percentage=0,
+ member_affiliate_status="member_affiliate_status",
+ metadata={},
+ product_tax_code_id="product_tax_code_id",
redirect_purchase_url="redirect_purchase_url",
route="route",
- send_welcome_message=True,
- visibility="visible",
+ visibility="visibility",
)
assert_matches_type(Product, product, path=["response"])
@@ -80,7 +55,6 @@ def test_method_create_with_all_params(self, client: Whop) -> None:
@parametrize
def test_raw_response_create(self, client: Whop) -> None:
response = client.products.with_raw_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
title="title",
)
@@ -93,7 +67,6 @@ def test_raw_response_create(self, client: Whop) -> None:
@parametrize
def test_streaming_response_create(self, client: Whop) -> None:
with client.products.with_streaming_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
title="title",
) as response:
assert not response.is_closed
@@ -108,7 +81,7 @@ def test_streaming_response_create(self, client: Whop) -> None:
@parametrize
def test_method_retrieve(self, client: Whop) -> None:
product = client.products.retrieve(
- "prod_xxxxxxxxxxxxx",
+ "id",
)
assert_matches_type(Product, product, path=["response"])
@@ -116,7 +89,7 @@ def test_method_retrieve(self, client: Whop) -> None:
@parametrize
def test_raw_response_retrieve(self, client: Whop) -> None:
response = client.products.with_raw_response.retrieve(
- "prod_xxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -128,7 +101,7 @@ def test_raw_response_retrieve(self, client: Whop) -> None:
@parametrize
def test_streaming_response_retrieve(self, client: Whop) -> None:
with client.products.with_streaming_response.retrieve(
- "prod_xxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -150,7 +123,7 @@ def test_path_params_retrieve(self, client: Whop) -> None:
@parametrize
def test_method_update(self, client: Whop) -> None:
product = client.products.update(
- id="prod_xxxxxxxxxxxxx",
+ id="id",
)
assert_matches_type(Product, product, path=["response"])
@@ -158,29 +131,13 @@ def test_method_update(self, client: Whop) -> None:
@parametrize
def test_method_update_with_all_params(self, client: Whop) -> None:
product = client.products.update(
- id="prod_xxxxxxxxxxxxx",
- collect_shipping_address=True,
- custom_cta="get_access",
- custom_cta_url="custom_cta_url",
- custom_statement_descriptor="custom_statement_descriptor",
+ id="id",
description="description",
- gallery_images=[{"id": "id"}],
- global_affiliate_percentage=6.9,
- global_affiliate_status="enabled",
headline="headline",
- member_affiliate_percentage=6.9,
- member_affiliate_status="enabled",
- metadata={"foo": "bar"},
- product_tax_code_id="ptc_xxxxxxxxxxxxxx",
- redirect_purchase_url="redirect_purchase_url",
- route="route",
- send_welcome_message=True,
- store_page_config={
- "custom_cta": "custom_cta",
- "show_price": True,
- },
+ metadata={},
+ product_tax_code_id="product_tax_code_id",
title="title",
- visibility="visible",
+ visibility="visibility",
)
assert_matches_type(Product, product, path=["response"])
@@ -188,7 +145,7 @@ def test_method_update_with_all_params(self, client: Whop) -> None:
@parametrize
def test_raw_response_update(self, client: Whop) -> None:
response = client.products.with_raw_response.update(
- id="prod_xxxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -200,7 +157,7 @@ def test_raw_response_update(self, client: Whop) -> None:
@parametrize
def test_streaming_response_update(self, client: Whop) -> None:
with client.products.with_streaming_response.update(
- id="prod_xxxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -222,7 +179,7 @@ def test_path_params_update(self, client: Whop) -> None:
@parametrize
def test_method_list(self, client: Whop) -> None:
product = client.products.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
)
assert_matches_type(SyncCursorPage[ProductListItem], product, path=["response"])
@@ -230,17 +187,15 @@ def test_method_list(self, client: Whop) -> None:
@parametrize
def test_method_list_with_all_params(self, client: Whop) -> None:
product = client.products.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
+ access_pass_types=["string"],
after="after",
before="before",
- created_after=parse_datetime("2023-12-01T05:00:00.401Z"),
- created_before=parse_datetime("2023-12-01T05:00:00.401Z"),
direction="asc",
- first=42,
- last=42,
- order="active_memberships_count",
- product_types=["regular"],
- visibilities=["visible"],
+ first=0,
+ last=0,
+ order="order",
+ visibilities=["string"],
)
assert_matches_type(SyncCursorPage[ProductListItem], product, path=["response"])
@@ -248,7 +203,7 @@ def test_method_list_with_all_params(self, client: Whop) -> None:
@parametrize
def test_raw_response_list(self, client: Whop) -> None:
response = client.products.with_raw_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
)
assert response.is_closed is True
@@ -260,7 +215,7 @@ def test_raw_response_list(self, client: Whop) -> None:
@parametrize
def test_streaming_response_list(self, client: Whop) -> None:
with client.products.with_streaming_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -274,7 +229,7 @@ def test_streaming_response_list(self, client: Whop) -> None:
@parametrize
def test_method_delete(self, client: Whop) -> None:
product = client.products.delete(
- "prod_xxxxxxxxxxxxx",
+ "id",
)
assert_matches_type(ProductDeleteResponse, product, path=["response"])
@@ -282,7 +237,7 @@ def test_method_delete(self, client: Whop) -> None:
@parametrize
def test_raw_response_delete(self, client: Whop) -> None:
response = client.products.with_raw_response.delete(
- "prod_xxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -294,7 +249,7 @@ def test_raw_response_delete(self, client: Whop) -> None:
@parametrize
def test_streaming_response_delete(self, client: Whop) -> None:
with client.products.with_streaming_response.delete(
- "prod_xxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -322,7 +277,6 @@ class TestAsyncProducts:
@parametrize
async def test_method_create(self, async_client: AsyncWhop) -> None:
product = await async_client.products.create(
- company_id="biz_xxxxxxxxxxxxxx",
title="title",
)
assert_matches_type(Product, product, path=["response"])
@@ -331,44 +285,23 @@ async def test_method_create(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> None:
product = await async_client.products.create(
- company_id="biz_xxxxxxxxxxxxxx",
title="title",
collect_shipping_address=True,
- custom_cta="get_access",
+ company_id="company_id",
+ custom_cta="custom_cta",
custom_cta_url="custom_cta_url",
custom_statement_descriptor="custom_statement_descriptor",
description="description",
- experience_ids=["string"],
- global_affiliate_percentage=6.9,
- global_affiliate_status="enabled",
+ global_affiliate_percentage=0,
+ global_affiliate_status="global_affiliate_status",
headline="headline",
- member_affiliate_percentage=6.9,
- member_affiliate_status="enabled",
- metadata={"foo": "bar"},
- plan_options={
- "base_currency": "usd",
- "billing_period": 42,
- "custom_fields": [
- {
- "field_type": "text",
- "name": "name",
- "id": "id",
- "order": 42,
- "placeholder": "placeholder",
- "required": True,
- }
- ],
- "initial_price": 6.9,
- "plan_type": "renewal",
- "release_method": "buy_now",
- "renewal_price": 6.9,
- "visibility": "visible",
- },
- product_tax_code_id="ptc_xxxxxxxxxxxxxx",
+ member_affiliate_percentage=0,
+ member_affiliate_status="member_affiliate_status",
+ metadata={},
+ product_tax_code_id="product_tax_code_id",
redirect_purchase_url="redirect_purchase_url",
route="route",
- send_welcome_message=True,
- visibility="visible",
+ visibility="visibility",
)
assert_matches_type(Product, product, path=["response"])
@@ -376,7 +309,6 @@ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> N
@parametrize
async def test_raw_response_create(self, async_client: AsyncWhop) -> None:
response = await async_client.products.with_raw_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
title="title",
)
@@ -389,7 +321,6 @@ async def test_raw_response_create(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_create(self, async_client: AsyncWhop) -> None:
async with async_client.products.with_streaming_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
title="title",
) as response:
assert not response.is_closed
@@ -404,7 +335,7 @@ async def test_streaming_response_create(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_retrieve(self, async_client: AsyncWhop) -> None:
product = await async_client.products.retrieve(
- "prod_xxxxxxxxxxxxx",
+ "id",
)
assert_matches_type(Product, product, path=["response"])
@@ -412,7 +343,7 @@ async def test_method_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None:
response = await async_client.products.with_raw_response.retrieve(
- "prod_xxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -424,7 +355,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_retrieve(self, async_client: AsyncWhop) -> None:
async with async_client.products.with_streaming_response.retrieve(
- "prod_xxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -446,7 +377,7 @@ async def test_path_params_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_update(self, async_client: AsyncWhop) -> None:
product = await async_client.products.update(
- id="prod_xxxxxxxxxxxxx",
+ id="id",
)
assert_matches_type(Product, product, path=["response"])
@@ -454,29 +385,13 @@ async def test_method_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> None:
product = await async_client.products.update(
- id="prod_xxxxxxxxxxxxx",
- collect_shipping_address=True,
- custom_cta="get_access",
- custom_cta_url="custom_cta_url",
- custom_statement_descriptor="custom_statement_descriptor",
+ id="id",
description="description",
- gallery_images=[{"id": "id"}],
- global_affiliate_percentage=6.9,
- global_affiliate_status="enabled",
headline="headline",
- member_affiliate_percentage=6.9,
- member_affiliate_status="enabled",
- metadata={"foo": "bar"},
- product_tax_code_id="ptc_xxxxxxxxxxxxxx",
- redirect_purchase_url="redirect_purchase_url",
- route="route",
- send_welcome_message=True,
- store_page_config={
- "custom_cta": "custom_cta",
- "show_price": True,
- },
+ metadata={},
+ product_tax_code_id="product_tax_code_id",
title="title",
- visibility="visible",
+ visibility="visibility",
)
assert_matches_type(Product, product, path=["response"])
@@ -484,7 +399,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> N
@parametrize
async def test_raw_response_update(self, async_client: AsyncWhop) -> None:
response = await async_client.products.with_raw_response.update(
- id="prod_xxxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -496,7 +411,7 @@ async def test_raw_response_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_update(self, async_client: AsyncWhop) -> None:
async with async_client.products.with_streaming_response.update(
- id="prod_xxxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -518,7 +433,7 @@ async def test_path_params_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_list(self, async_client: AsyncWhop) -> None:
product = await async_client.products.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
)
assert_matches_type(AsyncCursorPage[ProductListItem], product, path=["response"])
@@ -526,17 +441,15 @@ async def test_method_list(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_list_with_all_params(self, async_client: AsyncWhop) -> None:
product = await async_client.products.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
+ access_pass_types=["string"],
after="after",
before="before",
- created_after=parse_datetime("2023-12-01T05:00:00.401Z"),
- created_before=parse_datetime("2023-12-01T05:00:00.401Z"),
direction="asc",
- first=42,
- last=42,
- order="active_memberships_count",
- product_types=["regular"],
- visibilities=["visible"],
+ first=0,
+ last=0,
+ order="order",
+ visibilities=["string"],
)
assert_matches_type(AsyncCursorPage[ProductListItem], product, path=["response"])
@@ -544,7 +457,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncWhop) -> Non
@parametrize
async def test_raw_response_list(self, async_client: AsyncWhop) -> None:
response = await async_client.products.with_raw_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
)
assert response.is_closed is True
@@ -556,7 +469,7 @@ async def test_raw_response_list(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_list(self, async_client: AsyncWhop) -> None:
async with async_client.products.with_streaming_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ company_id="company_id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -570,7 +483,7 @@ async def test_streaming_response_list(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_delete(self, async_client: AsyncWhop) -> None:
product = await async_client.products.delete(
- "prod_xxxxxxxxxxxxx",
+ "id",
)
assert_matches_type(ProductDeleteResponse, product, path=["response"])
@@ -578,7 +491,7 @@ async def test_method_delete(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_delete(self, async_client: AsyncWhop) -> None:
response = await async_client.products.with_raw_response.delete(
- "prod_xxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -590,7 +503,7 @@ async def test_raw_response_delete(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_delete(self, async_client: AsyncWhop) -> None:
async with async_client.products.with_streaming_response.delete(
- "prod_xxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
diff --git a/tests/api_resources/test_social_accounts.py b/tests/api_resources/test_social_accounts.py
new file mode 100644
index 00000000..96d1c035
--- /dev/null
+++ b/tests/api_resources/test_social_accounts.py
@@ -0,0 +1,438 @@
+# 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 (
+ SocialAccount,
+ SocialAccountPostsResponse,
+ SocialAccountCreateResponse,
+ SocialAccountDeleteResponse,
+)
+from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestSocialAccounts:
+ 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:
+ social_account = client.social_accounts.create(
+ platform="meta_business",
+ redirect_url="redirect_url",
+ )
+ assert_matches_type(SocialAccountCreateResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: Whop) -> None:
+ social_account = client.social_accounts.create(
+ platform="meta_business",
+ redirect_url="redirect_url",
+ account_id="account_id",
+ scopes=["advertise"],
+ )
+ assert_matches_type(SocialAccountCreateResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Whop) -> None:
+ response = client.social_accounts.with_raw_response.create(
+ platform="meta_business",
+ redirect_url="redirect_url",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ social_account = response.parse()
+ assert_matches_type(SocialAccountCreateResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Whop) -> None:
+ with client.social_accounts.with_streaming_response.create(
+ platform="meta_business",
+ redirect_url="redirect_url",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ social_account = response.parse()
+ assert_matches_type(SocialAccountCreateResponse, social_account, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Whop) -> None:
+ social_account = client.social_accounts.list()
+ assert_matches_type(SyncCursorPage[SocialAccount], social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Whop) -> None:
+ social_account = client.social_accounts.list(
+ account_id="account_id",
+ after="after",
+ before="before",
+ direction="asc",
+ first=100,
+ last=100,
+ order="display_order",
+ platform="x",
+ scopes=["advertise"],
+ user_id="user_id",
+ verified=True,
+ )
+ assert_matches_type(SyncCursorPage[SocialAccount], social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Whop) -> None:
+ response = client.social_accounts.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ social_account = response.parse()
+ assert_matches_type(SyncCursorPage[SocialAccount], social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Whop) -> None:
+ with client.social_accounts.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ social_account = response.parse()
+ assert_matches_type(SyncCursorPage[SocialAccount], social_account, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_delete(self, client: Whop) -> None:
+ social_account = client.social_accounts.delete(
+ id="id",
+ )
+ assert_matches_type(SocialAccountDeleteResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_delete_with_all_params(self, client: Whop) -> None:
+ social_account = client.social_accounts.delete(
+ id="id",
+ account_id="account_id",
+ user_id="user_id",
+ )
+ assert_matches_type(SocialAccountDeleteResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_delete(self, client: Whop) -> None:
+ response = client.social_accounts.with_raw_response.delete(
+ id="id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ social_account = response.parse()
+ assert_matches_type(SocialAccountDeleteResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_delete(self, client: Whop) -> None:
+ with client.social_accounts.with_streaming_response.delete(
+ id="id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ social_account = response.parse()
+ assert_matches_type(SocialAccountDeleteResponse, social_account, 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.social_accounts.with_raw_response.delete(
+ id="",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_posts(self, client: Whop) -> None:
+ social_account = client.social_accounts.posts(
+ id="id",
+ account_id="account_id",
+ )
+ assert_matches_type(SocialAccountPostsResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_posts_with_all_params(self, client: Whop) -> None:
+ social_account = client.social_accounts.posts(
+ id="id",
+ account_id="account_id",
+ after="after",
+ first=100,
+ post_id="post_id",
+ )
+ assert_matches_type(SocialAccountPostsResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_posts(self, client: Whop) -> None:
+ response = client.social_accounts.with_raw_response.posts(
+ id="id",
+ account_id="account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ social_account = response.parse()
+ assert_matches_type(SocialAccountPostsResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_posts(self, client: Whop) -> None:
+ with client.social_accounts.with_streaming_response.posts(
+ id="id",
+ account_id="account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ social_account = response.parse()
+ assert_matches_type(SocialAccountPostsResponse, social_account, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_path_params_posts(self, client: Whop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.social_accounts.with_raw_response.posts(
+ id="",
+ account_id="account_id",
+ )
+
+
+class TestAsyncSocialAccounts:
+ 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:
+ social_account = await async_client.social_accounts.create(
+ platform="meta_business",
+ redirect_url="redirect_url",
+ )
+ assert_matches_type(SocialAccountCreateResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> None:
+ social_account = await async_client.social_accounts.create(
+ platform="meta_business",
+ redirect_url="redirect_url",
+ account_id="account_id",
+ scopes=["advertise"],
+ )
+ assert_matches_type(SocialAccountCreateResponse, social_account, 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.social_accounts.with_raw_response.create(
+ platform="meta_business",
+ redirect_url="redirect_url",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ social_account = await response.parse()
+ assert_matches_type(SocialAccountCreateResponse, social_account, 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.social_accounts.with_streaming_response.create(
+ platform="meta_business",
+ redirect_url="redirect_url",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ social_account = await response.parse()
+ assert_matches_type(SocialAccountCreateResponse, social_account, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncWhop) -> None:
+ social_account = await async_client.social_accounts.list()
+ assert_matches_type(AsyncCursorPage[SocialAccount], social_account, 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:
+ social_account = await async_client.social_accounts.list(
+ account_id="account_id",
+ after="after",
+ before="before",
+ direction="asc",
+ first=100,
+ last=100,
+ order="display_order",
+ platform="x",
+ scopes=["advertise"],
+ user_id="user_id",
+ verified=True,
+ )
+ assert_matches_type(AsyncCursorPage[SocialAccount], social_account, 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.social_accounts.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ social_account = await response.parse()
+ assert_matches_type(AsyncCursorPage[SocialAccount], social_account, 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.social_accounts.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ social_account = await response.parse()
+ assert_matches_type(AsyncCursorPage[SocialAccount], social_account, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncWhop) -> None:
+ social_account = await async_client.social_accounts.delete(
+ id="id",
+ )
+ assert_matches_type(SocialAccountDeleteResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_delete_with_all_params(self, async_client: AsyncWhop) -> None:
+ social_account = await async_client.social_accounts.delete(
+ id="id",
+ account_id="account_id",
+ user_id="user_id",
+ )
+ assert_matches_type(SocialAccountDeleteResponse, social_account, 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.social_accounts.with_raw_response.delete(
+ id="id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ social_account = await response.parse()
+ assert_matches_type(SocialAccountDeleteResponse, social_account, 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.social_accounts.with_streaming_response.delete(
+ id="id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ social_account = await response.parse()
+ assert_matches_type(SocialAccountDeleteResponse, social_account, 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.social_accounts.with_raw_response.delete(
+ id="",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_posts(self, async_client: AsyncWhop) -> None:
+ social_account = await async_client.social_accounts.posts(
+ id="id",
+ account_id="account_id",
+ )
+ assert_matches_type(SocialAccountPostsResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_posts_with_all_params(self, async_client: AsyncWhop) -> None:
+ social_account = await async_client.social_accounts.posts(
+ id="id",
+ account_id="account_id",
+ after="after",
+ first=100,
+ post_id="post_id",
+ )
+ assert_matches_type(SocialAccountPostsResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_posts(self, async_client: AsyncWhop) -> None:
+ response = await async_client.social_accounts.with_raw_response.posts(
+ id="id",
+ account_id="account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ social_account = await response.parse()
+ assert_matches_type(SocialAccountPostsResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_posts(self, async_client: AsyncWhop) -> None:
+ async with async_client.social_accounts.with_streaming_response.posts(
+ id="id",
+ account_id="account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ social_account = await response.parse()
+ assert_matches_type(SocialAccountPostsResponse, social_account, 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_posts(self, async_client: AsyncWhop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.social_accounts.with_raw_response.posts(
+ id="",
+ account_id="account_id",
+ )
diff --git a/tests/api_resources/test_stats.py b/tests/api_resources/test_stats.py
new file mode 100644
index 00000000..55b0d5fb
--- /dev/null
+++ b/tests/api_resources/test_stats.py
@@ -0,0 +1,227 @@
+# 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 StatListResponse, StatRetrieveResponse
+from whop_sdk._utils import parse_date
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestStats:
+ 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_retrieve(self, client: Whop) -> None:
+ stat = client.stats.retrieve(
+ metric="metric",
+ account_id="account_id",
+ from_=parse_date("2019-12-27"),
+ to=parse_date("2019-12-27"),
+ )
+ assert_matches_type(StatRetrieveResponse, stat, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_retrieve_with_all_params(self, client: Whop) -> None:
+ stat = client.stats.retrieve(
+ metric="metric",
+ account_id="account_id",
+ from_=parse_date("2019-12-27"),
+ to=parse_date("2019-12-27"),
+ breakdown_by="breakdown_by",
+ card_network="card_network",
+ convert_to="convert_to",
+ currency="currency",
+ interval="hour",
+ payment_method="payment_method",
+ snapshot_window="30d",
+ time_zone="time_zone",
+ )
+ assert_matches_type(StatRetrieveResponse, stat, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_retrieve(self, client: Whop) -> None:
+ response = client.stats.with_raw_response.retrieve(
+ metric="metric",
+ account_id="account_id",
+ from_=parse_date("2019-12-27"),
+ to=parse_date("2019-12-27"),
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ stat = response.parse()
+ assert_matches_type(StatRetrieveResponse, stat, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Whop) -> None:
+ with client.stats.with_streaming_response.retrieve(
+ metric="metric",
+ account_id="account_id",
+ from_=parse_date("2019-12-27"),
+ to=parse_date("2019-12-27"),
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ stat = response.parse()
+ assert_matches_type(StatRetrieveResponse, stat, 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 `metric` but received ''"):
+ client.stats.with_raw_response.retrieve(
+ metric="",
+ account_id="account_id",
+ from_=parse_date("2019-12-27"),
+ to=parse_date("2019-12-27"),
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Whop) -> None:
+ stat = client.stats.list()
+ assert_matches_type(StatListResponse, stat, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Whop) -> None:
+ response = client.stats.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ stat = response.parse()
+ assert_matches_type(StatListResponse, stat, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Whop) -> None:
+ with client.stats.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ stat = response.parse()
+ assert_matches_type(StatListResponse, stat, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncStats:
+ 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_retrieve(self, async_client: AsyncWhop) -> None:
+ stat = await async_client.stats.retrieve(
+ metric="metric",
+ account_id="account_id",
+ from_=parse_date("2019-12-27"),
+ to=parse_date("2019-12-27"),
+ )
+ assert_matches_type(StatRetrieveResponse, stat, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_retrieve_with_all_params(self, async_client: AsyncWhop) -> None:
+ stat = await async_client.stats.retrieve(
+ metric="metric",
+ account_id="account_id",
+ from_=parse_date("2019-12-27"),
+ to=parse_date("2019-12-27"),
+ breakdown_by="breakdown_by",
+ card_network="card_network",
+ convert_to="convert_to",
+ currency="currency",
+ interval="hour",
+ payment_method="payment_method",
+ snapshot_window="30d",
+ time_zone="time_zone",
+ )
+ assert_matches_type(StatRetrieveResponse, stat, 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.stats.with_raw_response.retrieve(
+ metric="metric",
+ account_id="account_id",
+ from_=parse_date("2019-12-27"),
+ to=parse_date("2019-12-27"),
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ stat = await response.parse()
+ assert_matches_type(StatRetrieveResponse, stat, 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.stats.with_streaming_response.retrieve(
+ metric="metric",
+ account_id="account_id",
+ from_=parse_date("2019-12-27"),
+ to=parse_date("2019-12-27"),
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ stat = await response.parse()
+ assert_matches_type(StatRetrieveResponse, stat, 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 `metric` but received ''"):
+ await async_client.stats.with_raw_response.retrieve(
+ metric="",
+ account_id="account_id",
+ from_=parse_date("2019-12-27"),
+ to=parse_date("2019-12-27"),
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncWhop) -> None:
+ stat = await async_client.stats.list()
+ assert_matches_type(StatListResponse, stat, 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.stats.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ stat = await response.parse()
+ assert_matches_type(StatListResponse, stat, 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.stats.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ stat = await response.parse()
+ assert_matches_type(StatListResponse, stat, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_swaps.py b/tests/api_resources/test_swaps.py
index 26dee794..9972efc2 100644
--- a/tests/api_resources/test_swaps.py
+++ b/tests/api_resources/test_swaps.py
@@ -9,7 +9,12 @@
from whop_sdk import Whop, AsyncWhop
from tests.utils import assert_matches_type
-from whop_sdk.types import SwapCreateQuoteResponse
+from whop_sdk.types import (
+ SwapListResponse,
+ SwapCreateResponse,
+ SwapRetrieveResponse,
+ SwapCreateQuoteResponse,
+)
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -17,6 +22,139 @@
class TestSwaps:
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:
+ swap = client.swaps.create(
+ account_id="account_id",
+ amount="amount",
+ from_token="from_token",
+ to_token="to_token",
+ )
+ assert_matches_type(SwapCreateResponse, swap, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: Whop) -> None:
+ swap = client.swaps.create(
+ account_id="account_id",
+ amount="amount",
+ from_token="from_token",
+ to_token="to_token",
+ from_chain="string",
+ slippage_bps=0,
+ to_chain="string",
+ )
+ assert_matches_type(SwapCreateResponse, swap, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Whop) -> None:
+ response = client.swaps.with_raw_response.create(
+ account_id="account_id",
+ amount="amount",
+ from_token="from_token",
+ to_token="to_token",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ swap = response.parse()
+ assert_matches_type(SwapCreateResponse, swap, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Whop) -> None:
+ with client.swaps.with_streaming_response.create(
+ account_id="account_id",
+ amount="amount",
+ from_token="from_token",
+ to_token="to_token",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ swap = response.parse()
+ assert_matches_type(SwapCreateResponse, swap, 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:
+ swap = client.swaps.retrieve(
+ "id",
+ )
+ assert_matches_type(SwapRetrieveResponse, swap, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_retrieve(self, client: Whop) -> None:
+ response = client.swaps.with_raw_response.retrieve(
+ "id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ swap = response.parse()
+ assert_matches_type(SwapRetrieveResponse, swap, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Whop) -> None:
+ with client.swaps.with_streaming_response.retrieve(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ swap = response.parse()
+ assert_matches_type(SwapRetrieveResponse, swap, 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.swaps.with_raw_response.retrieve(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Whop) -> None:
+ swap = client.swaps.list(
+ account_id="account_id",
+ )
+ assert_matches_type(SwapListResponse, swap, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Whop) -> None:
+ response = client.swaps.with_raw_response.list(
+ account_id="account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ swap = response.parse()
+ assert_matches_type(SwapListResponse, swap, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Whop) -> None:
+ with client.swaps.with_streaming_response.list(
+ account_id="account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ swap = response.parse()
+ assert_matches_type(SwapListResponse, swap, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_create_quote(self, client: Whop) -> None:
@@ -79,6 +217,139 @@ class TestAsyncSwaps:
"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:
+ swap = await async_client.swaps.create(
+ account_id="account_id",
+ amount="amount",
+ from_token="from_token",
+ to_token="to_token",
+ )
+ assert_matches_type(SwapCreateResponse, swap, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> None:
+ swap = await async_client.swaps.create(
+ account_id="account_id",
+ amount="amount",
+ from_token="from_token",
+ to_token="to_token",
+ from_chain="string",
+ slippage_bps=0,
+ to_chain="string",
+ )
+ assert_matches_type(SwapCreateResponse, swap, 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.swaps.with_raw_response.create(
+ account_id="account_id",
+ amount="amount",
+ from_token="from_token",
+ to_token="to_token",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ swap = await response.parse()
+ assert_matches_type(SwapCreateResponse, swap, 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.swaps.with_streaming_response.create(
+ account_id="account_id",
+ amount="amount",
+ from_token="from_token",
+ to_token="to_token",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ swap = await response.parse()
+ assert_matches_type(SwapCreateResponse, swap, 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:
+ swap = await async_client.swaps.retrieve(
+ "id",
+ )
+ assert_matches_type(SwapRetrieveResponse, swap, 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.swaps.with_raw_response.retrieve(
+ "id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ swap = await response.parse()
+ assert_matches_type(SwapRetrieveResponse, swap, 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.swaps.with_streaming_response.retrieve(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ swap = await response.parse()
+ assert_matches_type(SwapRetrieveResponse, swap, 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.swaps.with_raw_response.retrieve(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncWhop) -> None:
+ swap = await async_client.swaps.list(
+ account_id="account_id",
+ )
+ assert_matches_type(SwapListResponse, swap, 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.swaps.with_raw_response.list(
+ account_id="account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ swap = await response.parse()
+ assert_matches_type(SwapListResponse, swap, 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.swaps.with_streaming_response.list(
+ account_id="account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ swap = await response.parse()
+ assert_matches_type(SwapListResponse, swap, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_method_create_quote(self, async_client: AsyncWhop) -> None:
diff --git a/tests/api_resources/test_transfers.py b/tests/api_resources/test_transfers.py
index 0b2c1c1d..95586346 100644
--- a/tests/api_resources/test_transfers.py
+++ b/tests/api_resources/test_transfers.py
@@ -9,10 +9,13 @@
from whop_sdk import Whop, AsyncWhop
from tests.utils import assert_matches_type
-from whop_sdk.types import TransferListResponse
+from whop_sdk.types import (
+ TransferListResponse,
+ TransferCreateResponse,
+ TransferRetrieveResponse,
+)
from whop_sdk._utils import parse_datetime
from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
-from whop_sdk.types.shared import Transfer
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -24,56 +27,53 @@ class TestTransfers:
@parametrize
def test_method_create(self, client: Whop) -> None:
transfer = client.transfers.create(
- amount=6.9,
- currency="usd",
- destination_id="destination_id",
+ amount=0,
origin_id="origin_id",
)
- assert_matches_type(Transfer, transfer, path=["response"])
+ assert_matches_type(TransferCreateResponse, transfer, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_create_with_all_params(self, client: Whop) -> None:
transfer = client.transfers.create(
- amount=6.9,
+ amount=0,
+ origin_id="origin_id",
currency="usd",
destination_id="destination_id",
- origin_id="origin_id",
+ expires_at=parse_datetime("2019-12-27T18:11:19.117Z"),
idempotence_key="idempotence_key",
metadata={"foo": "bar"},
notes="notes",
+ redeemable_count=0,
+ type="ledger",
)
- assert_matches_type(Transfer, transfer, path=["response"])
+ assert_matches_type(TransferCreateResponse, transfer, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_raw_response_create(self, client: Whop) -> None:
response = client.transfers.with_raw_response.create(
- amount=6.9,
- currency="usd",
- destination_id="destination_id",
+ amount=0,
origin_id="origin_id",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
transfer = response.parse()
- assert_matches_type(Transfer, transfer, path=["response"])
+ assert_matches_type(TransferCreateResponse, transfer, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_streaming_response_create(self, client: Whop) -> None:
with client.transfers.with_streaming_response.create(
- amount=6.9,
- currency="usd",
- destination_id="destination_id",
+ amount=0,
origin_id="origin_id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
transfer = response.parse()
- assert_matches_type(Transfer, transfer, path=["response"])
+ assert_matches_type(TransferCreateResponse, transfer, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -81,33 +81,33 @@ def test_streaming_response_create(self, client: Whop) -> None:
@parametrize
def test_method_retrieve(self, client: Whop) -> None:
transfer = client.transfers.retrieve(
- "ctt_xxxxxxxxxxxxxx",
+ "id",
)
- assert_matches_type(Transfer, transfer, path=["response"])
+ assert_matches_type(TransferRetrieveResponse, transfer, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_raw_response_retrieve(self, client: Whop) -> None:
response = client.transfers.with_raw_response.retrieve(
- "ctt_xxxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
transfer = response.parse()
- assert_matches_type(Transfer, transfer, path=["response"])
+ assert_matches_type(TransferRetrieveResponse, transfer, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_streaming_response_retrieve(self, client: Whop) -> None:
with client.transfers.with_streaming_response.retrieve(
- "ctt_xxxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
transfer = response.parse()
- assert_matches_type(Transfer, transfer, path=["response"])
+ assert_matches_type(TransferRetrieveResponse, transfer, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -131,13 +131,13 @@ def test_method_list_with_all_params(self, client: Whop) -> None:
transfer = client.transfers.list(
after="after",
before="before",
- created_after=parse_datetime("2023-12-01T05:00:00.401Z"),
- created_before=parse_datetime("2023-12-01T05:00:00.401Z"),
+ created_after="created_after",
+ created_before="created_before",
destination_id="destination_id",
direction="asc",
- first=42,
- last=42,
- order="amount",
+ first=50,
+ last=50,
+ order="created_at",
origin_id="origin_id",
)
assert_matches_type(SyncCursorPage[TransferListResponse], transfer, path=["response"])
@@ -174,56 +174,53 @@ class TestAsyncTransfers:
@parametrize
async def test_method_create(self, async_client: AsyncWhop) -> None:
transfer = await async_client.transfers.create(
- amount=6.9,
- currency="usd",
- destination_id="destination_id",
+ amount=0,
origin_id="origin_id",
)
- assert_matches_type(Transfer, transfer, path=["response"])
+ assert_matches_type(TransferCreateResponse, transfer, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> None:
transfer = await async_client.transfers.create(
- amount=6.9,
+ amount=0,
+ origin_id="origin_id",
currency="usd",
destination_id="destination_id",
- origin_id="origin_id",
+ expires_at=parse_datetime("2019-12-27T18:11:19.117Z"),
idempotence_key="idempotence_key",
metadata={"foo": "bar"},
notes="notes",
+ redeemable_count=0,
+ type="ledger",
)
- assert_matches_type(Transfer, transfer, path=["response"])
+ assert_matches_type(TransferCreateResponse, transfer, 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.transfers.with_raw_response.create(
- amount=6.9,
- currency="usd",
- destination_id="destination_id",
+ amount=0,
origin_id="origin_id",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
transfer = await response.parse()
- assert_matches_type(Transfer, transfer, path=["response"])
+ assert_matches_type(TransferCreateResponse, transfer, 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.transfers.with_streaming_response.create(
- amount=6.9,
- currency="usd",
- destination_id="destination_id",
+ amount=0,
origin_id="origin_id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
transfer = await response.parse()
- assert_matches_type(Transfer, transfer, path=["response"])
+ assert_matches_type(TransferCreateResponse, transfer, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -231,33 +228,33 @@ async def test_streaming_response_create(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_retrieve(self, async_client: AsyncWhop) -> None:
transfer = await async_client.transfers.retrieve(
- "ctt_xxxxxxxxxxxxxx",
+ "id",
)
- assert_matches_type(Transfer, transfer, path=["response"])
+ assert_matches_type(TransferRetrieveResponse, transfer, 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.transfers.with_raw_response.retrieve(
- "ctt_xxxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
transfer = await response.parse()
- assert_matches_type(Transfer, transfer, path=["response"])
+ assert_matches_type(TransferRetrieveResponse, transfer, 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.transfers.with_streaming_response.retrieve(
- "ctt_xxxxxxxxxxxxxx",
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
transfer = await response.parse()
- assert_matches_type(Transfer, transfer, path=["response"])
+ assert_matches_type(TransferRetrieveResponse, transfer, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -281,13 +278,13 @@ async def test_method_list_with_all_params(self, async_client: AsyncWhop) -> Non
transfer = await async_client.transfers.list(
after="after",
before="before",
- created_after=parse_datetime("2023-12-01T05:00:00.401Z"),
- created_before=parse_datetime("2023-12-01T05:00:00.401Z"),
+ created_after="created_after",
+ created_before="created_before",
destination_id="destination_id",
direction="asc",
- first=42,
- last=42,
- order="amount",
+ first=50,
+ last=50,
+ order="created_at",
origin_id="origin_id",
)
assert_matches_type(AsyncCursorPage[TransferListResponse], transfer, path=["response"])
diff --git a/tests/api_resources/test_users.py b/tests/api_resources/test_users.py
index ee565217..9b0014ac 100644
--- a/tests/api_resources/test_users.py
+++ b/tests/api_resources/test_users.py
@@ -11,7 +11,6 @@
from tests.utils import assert_matches_type
from whop_sdk.types import (
User,
- UserListResponse,
UserCheckAccessResponse,
)
from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
@@ -26,7 +25,7 @@ class TestUsers:
@parametrize
def test_method_retrieve(self, client: Whop) -> None:
user = client.users.retrieve(
- id="user_xxxxxxxxxxxxx",
+ id="id",
)
assert_matches_type(User, user, path=["response"])
@@ -34,8 +33,8 @@ def test_method_retrieve(self, client: Whop) -> None:
@parametrize
def test_method_retrieve_with_all_params(self, client: Whop) -> None:
user = client.users.retrieve(
- id="user_xxxxxxxxxxxxx",
- company_id="biz_xxxxxxxxxxxxxx",
+ id="id",
+ account_id="account_id",
)
assert_matches_type(User, user, path=["response"])
@@ -43,7 +42,7 @@ def test_method_retrieve_with_all_params(self, client: Whop) -> None:
@parametrize
def test_raw_response_retrieve(self, client: Whop) -> None:
response = client.users.with_raw_response.retrieve(
- id="user_xxxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -55,7 +54,7 @@ def test_raw_response_retrieve(self, client: Whop) -> None:
@parametrize
def test_streaming_response_retrieve(self, client: Whop) -> None:
with client.users.with_streaming_response.retrieve(
- id="user_xxxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -77,7 +76,7 @@ def test_path_params_retrieve(self, client: Whop) -> None:
@parametrize
def test_method_update(self, client: Whop) -> None:
user = client.users.update(
- id="user_xxxxxxxxxxxxx",
+ id="id",
)
assert_matches_type(User, user, path=["response"])
@@ -85,11 +84,14 @@ def test_method_update(self, client: Whop) -> None:
@parametrize
def test_method_update_with_all_params(self, client: Whop) -> None:
user = client.users.update(
- id="user_xxxxxxxxxxxxx",
+ id="id",
+ account_id="account_id",
bio="bio",
- company_id="biz_xxxxxxxxxxxxxx",
name="name",
- profile_picture={"id": "id"},
+ profile_picture={
+ "id": "id",
+ "direct_upload_id": "direct_upload_id",
+ },
username="username",
)
assert_matches_type(User, user, path=["response"])
@@ -98,7 +100,7 @@ def test_method_update_with_all_params(self, client: Whop) -> None:
@parametrize
def test_raw_response_update(self, client: Whop) -> None:
response = client.users.with_raw_response.update(
- id="user_xxxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -110,7 +112,7 @@ def test_raw_response_update(self, client: Whop) -> None:
@parametrize
def test_streaming_response_update(self, client: Whop) -> None:
with client.users.with_streaming_response.update(
- id="user_xxxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -132,7 +134,7 @@ def test_path_params_update(self, client: Whop) -> None:
@parametrize
def test_method_list(self, client: Whop) -> None:
user = client.users.list()
- assert_matches_type(SyncCursorPage[UserListResponse], user, path=["response"])
+ assert_matches_type(SyncCursorPage[User], user, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -140,11 +142,11 @@ def test_method_list_with_all_params(self, client: Whop) -> None:
user = client.users.list(
after="after",
before="before",
- first=42,
- last=42,
+ first=0,
+ last=0,
query="query",
)
- assert_matches_type(SyncCursorPage[UserListResponse], user, path=["response"])
+ assert_matches_type(SyncCursorPage[User], user, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -154,7 +156,7 @@ def test_raw_response_list(self, client: Whop) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
user = response.parse()
- assert_matches_type(SyncCursorPage[UserListResponse], user, path=["response"])
+ assert_matches_type(SyncCursorPage[User], user, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -164,7 +166,7 @@ def test_streaming_response_list(self, client: Whop) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
user = response.parse()
- assert_matches_type(SyncCursorPage[UserListResponse], user, path=["response"])
+ assert_matches_type(SyncCursorPage[User], user, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -173,7 +175,7 @@ def test_streaming_response_list(self, client: Whop) -> None:
def test_method_check_access(self, client: Whop) -> None:
user = client.users.check_access(
resource_id="resource_id",
- id="user_xxxxxxxxxxxxx",
+ id="id",
)
assert_matches_type(UserCheckAccessResponse, user, path=["response"])
@@ -182,7 +184,7 @@ def test_method_check_access(self, client: Whop) -> None:
def test_raw_response_check_access(self, client: Whop) -> None:
response = client.users.with_raw_response.check_access(
resource_id="resource_id",
- id="user_xxxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -195,7 +197,7 @@ def test_raw_response_check_access(self, client: Whop) -> None:
def test_streaming_response_check_access(self, client: Whop) -> None:
with client.users.with_streaming_response.check_access(
resource_id="resource_id",
- id="user_xxxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -217,9 +219,52 @@ def test_path_params_check_access(self, client: Whop) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `resource_id` but received ''"):
client.users.with_raw_response.check_access(
resource_id="",
- id="user_xxxxxxxxxxxxx",
+ id="id",
)
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_update_me(self, client: Whop) -> None:
+ user = client.users.update_me()
+ assert_matches_type(User, user, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_update_me_with_all_params(self, client: Whop) -> None:
+ user = client.users.update_me(
+ account_id="account_id",
+ bio="bio",
+ name="name",
+ profile_picture={
+ "id": "id",
+ "direct_upload_id": "direct_upload_id",
+ },
+ username="username",
+ )
+ assert_matches_type(User, user, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_update_me(self, client: Whop) -> None:
+ response = client.users.with_raw_response.update_me()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ user = response.parse()
+ assert_matches_type(User, user, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_update_me(self, client: Whop) -> None:
+ with client.users.with_streaming_response.update_me() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ user = response.parse()
+ assert_matches_type(User, user, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
class TestAsyncUsers:
parametrize = pytest.mark.parametrize(
@@ -230,7 +275,7 @@ class TestAsyncUsers:
@parametrize
async def test_method_retrieve(self, async_client: AsyncWhop) -> None:
user = await async_client.users.retrieve(
- id="user_xxxxxxxxxxxxx",
+ id="id",
)
assert_matches_type(User, user, path=["response"])
@@ -238,8 +283,8 @@ async def test_method_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_retrieve_with_all_params(self, async_client: AsyncWhop) -> None:
user = await async_client.users.retrieve(
- id="user_xxxxxxxxxxxxx",
- company_id="biz_xxxxxxxxxxxxxx",
+ id="id",
+ account_id="account_id",
)
assert_matches_type(User, user, path=["response"])
@@ -247,7 +292,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncWhop) ->
@parametrize
async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None:
response = await async_client.users.with_raw_response.retrieve(
- id="user_xxxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -259,7 +304,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_retrieve(self, async_client: AsyncWhop) -> None:
async with async_client.users.with_streaming_response.retrieve(
- id="user_xxxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -281,7 +326,7 @@ async def test_path_params_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_update(self, async_client: AsyncWhop) -> None:
user = await async_client.users.update(
- id="user_xxxxxxxxxxxxx",
+ id="id",
)
assert_matches_type(User, user, path=["response"])
@@ -289,11 +334,14 @@ async def test_method_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> None:
user = await async_client.users.update(
- id="user_xxxxxxxxxxxxx",
+ id="id",
+ account_id="account_id",
bio="bio",
- company_id="biz_xxxxxxxxxxxxxx",
name="name",
- profile_picture={"id": "id"},
+ profile_picture={
+ "id": "id",
+ "direct_upload_id": "direct_upload_id",
+ },
username="username",
)
assert_matches_type(User, user, path=["response"])
@@ -302,7 +350,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> N
@parametrize
async def test_raw_response_update(self, async_client: AsyncWhop) -> None:
response = await async_client.users.with_raw_response.update(
- id="user_xxxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -314,7 +362,7 @@ async def test_raw_response_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_update(self, async_client: AsyncWhop) -> None:
async with async_client.users.with_streaming_response.update(
- id="user_xxxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -336,7 +384,7 @@ async def test_path_params_update(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_method_list(self, async_client: AsyncWhop) -> None:
user = await async_client.users.list()
- assert_matches_type(AsyncCursorPage[UserListResponse], user, path=["response"])
+ assert_matches_type(AsyncCursorPage[User], user, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -344,11 +392,11 @@ async def test_method_list_with_all_params(self, async_client: AsyncWhop) -> Non
user = await async_client.users.list(
after="after",
before="before",
- first=42,
- last=42,
+ first=0,
+ last=0,
query="query",
)
- assert_matches_type(AsyncCursorPage[UserListResponse], user, path=["response"])
+ assert_matches_type(AsyncCursorPage[User], user, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -358,7 +406,7 @@ async def test_raw_response_list(self, async_client: AsyncWhop) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
user = await response.parse()
- assert_matches_type(AsyncCursorPage[UserListResponse], user, path=["response"])
+ assert_matches_type(AsyncCursorPage[User], user, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -368,7 +416,7 @@ async def test_streaming_response_list(self, async_client: AsyncWhop) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
user = await response.parse()
- assert_matches_type(AsyncCursorPage[UserListResponse], user, path=["response"])
+ assert_matches_type(AsyncCursorPage[User], user, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -377,7 +425,7 @@ async def test_streaming_response_list(self, async_client: AsyncWhop) -> None:
async def test_method_check_access(self, async_client: AsyncWhop) -> None:
user = await async_client.users.check_access(
resource_id="resource_id",
- id="user_xxxxxxxxxxxxx",
+ id="id",
)
assert_matches_type(UserCheckAccessResponse, user, path=["response"])
@@ -386,7 +434,7 @@ async def test_method_check_access(self, async_client: AsyncWhop) -> None:
async def test_raw_response_check_access(self, async_client: AsyncWhop) -> None:
response = await async_client.users.with_raw_response.check_access(
resource_id="resource_id",
- id="user_xxxxxxxxxxxxx",
+ id="id",
)
assert response.is_closed is True
@@ -399,7 +447,7 @@ async def test_raw_response_check_access(self, async_client: AsyncWhop) -> None:
async def test_streaming_response_check_access(self, async_client: AsyncWhop) -> None:
async with async_client.users.with_streaming_response.check_access(
resource_id="resource_id",
- id="user_xxxxxxxxxxxxx",
+ id="id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -421,5 +469,48 @@ async def test_path_params_check_access(self, async_client: AsyncWhop) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `resource_id` but received ''"):
await async_client.users.with_raw_response.check_access(
resource_id="",
- id="user_xxxxxxxxxxxxx",
+ id="id",
)
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_update_me(self, async_client: AsyncWhop) -> None:
+ user = await async_client.users.update_me()
+ assert_matches_type(User, user, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_update_me_with_all_params(self, async_client: AsyncWhop) -> None:
+ user = await async_client.users.update_me(
+ account_id="account_id",
+ bio="bio",
+ name="name",
+ profile_picture={
+ "id": "id",
+ "direct_upload_id": "direct_upload_id",
+ },
+ username="username",
+ )
+ assert_matches_type(User, user, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_update_me(self, async_client: AsyncWhop) -> None:
+ response = await async_client.users.with_raw_response.update_me()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ user = await response.parse()
+ assert_matches_type(User, user, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_update_me(self, async_client: AsyncWhop) -> None:
+ async with async_client.users.with_streaming_response.update_me() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ user = await response.parse()
+ assert_matches_type(User, user, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_verifications.py b/tests/api_resources/test_verifications.py
index e1499aed..36804505 100644
--- a/tests/api_resources/test_verifications.py
+++ b/tests/api_resources/test_verifications.py
@@ -9,8 +9,13 @@
from whop_sdk import Whop, AsyncWhop
from tests.utils import assert_matches_type
-from whop_sdk.types import VerificationListResponse, VerificationRetrieveResponse
-from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
+from whop_sdk.types import (
+ VerificationListResponse,
+ VerificationCreateResponse,
+ VerificationDeleteResponse,
+ VerificationUpdateResponse,
+ VerificationRetrieveResponse,
+)
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -18,11 +23,66 @@
class TestVerifications:
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:
+ verification = client.verifications.create(
+ account_id="account_id",
+ )
+ assert_matches_type(VerificationCreateResponse, verification, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: Whop) -> None:
+ verification = client.verifications.create(
+ account_id="account_id",
+ address={"foo": "bar"},
+ business_name="business_name",
+ business_structure="business_structure",
+ business_website="business_website",
+ country="country",
+ date_of_birth="date_of_birth",
+ first_name="first_name",
+ kind="individual",
+ last_name="last_name",
+ phone="phone",
+ place_of_incorporation="place_of_incorporation",
+ restart=True,
+ tax_identification_number="tax_identification_number",
+ )
+ assert_matches_type(VerificationCreateResponse, verification, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Whop) -> None:
+ response = client.verifications.with_raw_response.create(
+ account_id="account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ verification = response.parse()
+ assert_matches_type(VerificationCreateResponse, verification, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Whop) -> None:
+ with client.verifications.with_streaming_response.create(
+ account_id="account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ verification = response.parse()
+ assert_matches_type(VerificationCreateResponse, verification, 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:
verification = client.verifications.retrieve(
- "verf_xxxxxxxxxxxxx",
+ "verification_id",
)
assert_matches_type(VerificationRetrieveResponse, verification, path=["response"])
@@ -30,7 +90,7 @@ def test_method_retrieve(self, client: Whop) -> None:
@parametrize
def test_raw_response_retrieve(self, client: Whop) -> None:
response = client.verifications.with_raw_response.retrieve(
- "verf_xxxxxxxxxxxxx",
+ "verification_id",
)
assert response.is_closed is True
@@ -42,7 +102,7 @@ def test_raw_response_retrieve(self, client: Whop) -> None:
@parametrize
def test_streaming_response_retrieve(self, client: Whop) -> None:
with client.verifications.with_streaming_response.retrieve(
- "verf_xxxxxxxxxxxxx",
+ "verification_id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -55,68 +115,230 @@ def test_streaming_response_retrieve(self, client: Whop) -> None:
@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 ''"):
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `verification_id` but received ''"):
client.verifications.with_raw_response.retrieve(
"",
)
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_update(self, client: Whop) -> None:
+ verification = client.verifications.update(
+ verification_id="verification_id",
+ )
+ assert_matches_type(VerificationUpdateResponse, verification, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_update_with_all_params(self, client: Whop) -> None:
+ verification = client.verifications.update(
+ verification_id="verification_id",
+ business_address={"foo": "bar"},
+ business_name="business_name",
+ business_structure="business_structure",
+ country="country",
+ date_of_birth="date_of_birth",
+ first_name="first_name",
+ last_name="last_name",
+ personal_address={"foo": "bar"},
+ requested_information=[
+ {
+ "id": "id",
+ "address": {"foo": "bar"},
+ "files": [{}],
+ "value": "value",
+ "value_type": "raw",
+ }
+ ],
+ )
+ assert_matches_type(VerificationUpdateResponse, verification, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_update(self, client: Whop) -> None:
+ response = client.verifications.with_raw_response.update(
+ verification_id="verification_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ verification = response.parse()
+ assert_matches_type(VerificationUpdateResponse, verification, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_update(self, client: Whop) -> None:
+ with client.verifications.with_streaming_response.update(
+ verification_id="verification_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ verification = response.parse()
+ assert_matches_type(VerificationUpdateResponse, verification, 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 `verification_id` but received ''"):
+ client.verifications.with_raw_response.update(
+ verification_id="",
+ )
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_list(self, client: Whop) -> None:
verification = client.verifications.list(
- payout_account_id="poact_xxxxxxxxxxxx",
+ account_id="account_id",
)
- assert_matches_type(SyncCursorPage[VerificationListResponse], verification, path=["response"])
+ assert_matches_type(VerificationListResponse, verification, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_list_with_all_params(self, client: Whop) -> None:
verification = client.verifications.list(
- payout_account_id="poact_xxxxxxxxxxxx",
- after="after",
- before="before",
- first=42,
- last=42,
+ account_id="account_id",
+ direction="asc",
+ order="updated_at",
)
- assert_matches_type(SyncCursorPage[VerificationListResponse], verification, path=["response"])
+ assert_matches_type(VerificationListResponse, verification, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_raw_response_list(self, client: Whop) -> None:
response = client.verifications.with_raw_response.list(
- payout_account_id="poact_xxxxxxxxxxxx",
+ account_id="account_id",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
verification = response.parse()
- assert_matches_type(SyncCursorPage[VerificationListResponse], verification, path=["response"])
+ assert_matches_type(VerificationListResponse, verification, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_streaming_response_list(self, client: Whop) -> None:
with client.verifications.with_streaming_response.list(
- payout_account_id="poact_xxxxxxxxxxxx",
+ account_id="account_id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
verification = response.parse()
- assert_matches_type(SyncCursorPage[VerificationListResponse], verification, path=["response"])
+ assert_matches_type(VerificationListResponse, verification, path=["response"])
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_delete(self, client: Whop) -> None:
+ verification = client.verifications.delete(
+ "verification_id",
+ )
+ assert_matches_type(VerificationDeleteResponse, verification, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_delete(self, client: Whop) -> None:
+ response = client.verifications.with_raw_response.delete(
+ "verification_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ verification = response.parse()
+ assert_matches_type(VerificationDeleteResponse, verification, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_delete(self, client: Whop) -> None:
+ with client.verifications.with_streaming_response.delete(
+ "verification_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ verification = response.parse()
+ assert_matches_type(VerificationDeleteResponse, verification, 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 `verification_id` but received ''"):
+ client.verifications.with_raw_response.delete(
+ "",
+ )
+
class TestAsyncVerifications:
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:
+ verification = await async_client.verifications.create(
+ account_id="account_id",
+ )
+ assert_matches_type(VerificationCreateResponse, verification, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> None:
+ verification = await async_client.verifications.create(
+ account_id="account_id",
+ address={"foo": "bar"},
+ business_name="business_name",
+ business_structure="business_structure",
+ business_website="business_website",
+ country="country",
+ date_of_birth="date_of_birth",
+ first_name="first_name",
+ kind="individual",
+ last_name="last_name",
+ phone="phone",
+ place_of_incorporation="place_of_incorporation",
+ restart=True,
+ tax_identification_number="tax_identification_number",
+ )
+ assert_matches_type(VerificationCreateResponse, verification, 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.verifications.with_raw_response.create(
+ account_id="account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ verification = await response.parse()
+ assert_matches_type(VerificationCreateResponse, verification, 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.verifications.with_streaming_response.create(
+ account_id="account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ verification = await response.parse()
+ assert_matches_type(VerificationCreateResponse, verification, 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:
verification = await async_client.verifications.retrieve(
- "verf_xxxxxxxxxxxxx",
+ "verification_id",
)
assert_matches_type(VerificationRetrieveResponse, verification, path=["response"])
@@ -124,7 +346,7 @@ async def test_method_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None:
response = await async_client.verifications.with_raw_response.retrieve(
- "verf_xxxxxxxxxxxxx",
+ "verification_id",
)
assert response.is_closed is True
@@ -136,7 +358,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncWhop) -> None:
@parametrize
async def test_streaming_response_retrieve(self, async_client: AsyncWhop) -> None:
async with async_client.verifications.with_streaming_response.retrieve(
- "verf_xxxxxxxxxxxxx",
+ "verification_id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -149,53 +371,160 @@ async def test_streaming_response_retrieve(self, async_client: AsyncWhop) -> Non
@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 ''"):
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `verification_id` but received ''"):
await async_client.verifications.with_raw_response.retrieve(
"",
)
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_update(self, async_client: AsyncWhop) -> None:
+ verification = await async_client.verifications.update(
+ verification_id="verification_id",
+ )
+ assert_matches_type(VerificationUpdateResponse, verification, 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:
+ verification = await async_client.verifications.update(
+ verification_id="verification_id",
+ business_address={"foo": "bar"},
+ business_name="business_name",
+ business_structure="business_structure",
+ country="country",
+ date_of_birth="date_of_birth",
+ first_name="first_name",
+ last_name="last_name",
+ personal_address={"foo": "bar"},
+ requested_information=[
+ {
+ "id": "id",
+ "address": {"foo": "bar"},
+ "files": [{}],
+ "value": "value",
+ "value_type": "raw",
+ }
+ ],
+ )
+ assert_matches_type(VerificationUpdateResponse, verification, 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.verifications.with_raw_response.update(
+ verification_id="verification_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ verification = await response.parse()
+ assert_matches_type(VerificationUpdateResponse, verification, 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.verifications.with_streaming_response.update(
+ verification_id="verification_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ verification = await response.parse()
+ assert_matches_type(VerificationUpdateResponse, verification, 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 `verification_id` but received ''"):
+ await async_client.verifications.with_raw_response.update(
+ verification_id="",
+ )
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_method_list(self, async_client: AsyncWhop) -> None:
verification = await async_client.verifications.list(
- payout_account_id="poact_xxxxxxxxxxxx",
+ account_id="account_id",
)
- assert_matches_type(AsyncCursorPage[VerificationListResponse], verification, path=["response"])
+ assert_matches_type(VerificationListResponse, verification, 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:
verification = await async_client.verifications.list(
- payout_account_id="poact_xxxxxxxxxxxx",
- after="after",
- before="before",
- first=42,
- last=42,
+ account_id="account_id",
+ direction="asc",
+ order="updated_at",
)
- assert_matches_type(AsyncCursorPage[VerificationListResponse], verification, path=["response"])
+ assert_matches_type(VerificationListResponse, verification, 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.verifications.with_raw_response.list(
- payout_account_id="poact_xxxxxxxxxxxx",
+ account_id="account_id",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
verification = await response.parse()
- assert_matches_type(AsyncCursorPage[VerificationListResponse], verification, path=["response"])
+ assert_matches_type(VerificationListResponse, verification, 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.verifications.with_streaming_response.list(
- payout_account_id="poact_xxxxxxxxxxxx",
+ account_id="account_id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
verification = await response.parse()
- assert_matches_type(AsyncCursorPage[VerificationListResponse], verification, path=["response"])
+ assert_matches_type(VerificationListResponse, verification, path=["response"])
assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncWhop) -> None:
+ verification = await async_client.verifications.delete(
+ "verification_id",
+ )
+ assert_matches_type(VerificationDeleteResponse, verification, 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.verifications.with_raw_response.delete(
+ "verification_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ verification = await response.parse()
+ assert_matches_type(VerificationDeleteResponse, verification, 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.verifications.with_streaming_response.delete(
+ "verification_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ verification = await response.parse()
+ assert_matches_type(VerificationDeleteResponse, verification, 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 `verification_id` but received ''"):
+ await async_client.verifications.with_raw_response.delete(
+ "",
+ )
diff --git a/tests/api_resources/test_wallets.py b/tests/api_resources/test_wallets.py
deleted file mode 100644
index abc5ad15..00000000
--- a/tests/api_resources/test_wallets.py
+++ /dev/null
@@ -1,264 +0,0 @@
-# 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 WalletListResponse, WalletSendResponse, WalletBalanceResponse
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestWallets:
- 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_list(self, client: Whop) -> None:
- wallet = client.wallets.list()
- assert_matches_type(WalletListResponse, wallet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_list(self, client: Whop) -> None:
- response = client.wallets.with_raw_response.list()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- wallet = response.parse()
- assert_matches_type(WalletListResponse, wallet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_list(self, client: Whop) -> None:
- with client.wallets.with_streaming_response.list() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- wallet = response.parse()
- assert_matches_type(WalletListResponse, wallet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_balance(self, client: Whop) -> None:
- wallet = client.wallets.balance(
- "account_id",
- )
- assert_matches_type(WalletBalanceResponse, wallet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_balance(self, client: Whop) -> None:
- response = client.wallets.with_raw_response.balance(
- "account_id",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- wallet = response.parse()
- assert_matches_type(WalletBalanceResponse, wallet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_balance(self, client: Whop) -> None:
- with client.wallets.with_streaming_response.balance(
- "account_id",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- wallet = response.parse()
- assert_matches_type(WalletBalanceResponse, wallet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_path_params_balance(self, client: Whop) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"):
- client.wallets.with_raw_response.balance(
- "",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_send(self, client: Whop) -> None:
- wallet = client.wallets.send(
- account_id="account_id",
- amount="amount",
- to="to",
- )
- assert_matches_type(WalletSendResponse, wallet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_send(self, client: Whop) -> None:
- response = client.wallets.with_raw_response.send(
- account_id="account_id",
- amount="amount",
- to="to",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- wallet = response.parse()
- assert_matches_type(WalletSendResponse, wallet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_send(self, client: Whop) -> None:
- with client.wallets.with_streaming_response.send(
- account_id="account_id",
- amount="amount",
- to="to",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- wallet = response.parse()
- assert_matches_type(WalletSendResponse, wallet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_path_params_send(self, client: Whop) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"):
- client.wallets.with_raw_response.send(
- account_id="",
- amount="amount",
- to="to",
- )
-
-
-class TestAsyncWallets:
- 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_list(self, async_client: AsyncWhop) -> None:
- wallet = await async_client.wallets.list()
- assert_matches_type(WalletListResponse, wallet, 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.wallets.with_raw_response.list()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- wallet = await response.parse()
- assert_matches_type(WalletListResponse, wallet, 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.wallets.with_streaming_response.list() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- wallet = await response.parse()
- assert_matches_type(WalletListResponse, wallet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_balance(self, async_client: AsyncWhop) -> None:
- wallet = await async_client.wallets.balance(
- "account_id",
- )
- assert_matches_type(WalletBalanceResponse, wallet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_balance(self, async_client: AsyncWhop) -> None:
- response = await async_client.wallets.with_raw_response.balance(
- "account_id",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- wallet = await response.parse()
- assert_matches_type(WalletBalanceResponse, wallet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_balance(self, async_client: AsyncWhop) -> None:
- async with async_client.wallets.with_streaming_response.balance(
- "account_id",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- wallet = await response.parse()
- assert_matches_type(WalletBalanceResponse, wallet, 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_balance(self, async_client: AsyncWhop) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"):
- await async_client.wallets.with_raw_response.balance(
- "",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_send(self, async_client: AsyncWhop) -> None:
- wallet = await async_client.wallets.send(
- account_id="account_id",
- amount="amount",
- to="to",
- )
- assert_matches_type(WalletSendResponse, wallet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_send(self, async_client: AsyncWhop) -> None:
- response = await async_client.wallets.with_raw_response.send(
- account_id="account_id",
- amount="amount",
- to="to",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- wallet = await response.parse()
- assert_matches_type(WalletSendResponse, wallet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_send(self, async_client: AsyncWhop) -> None:
- async with async_client.wallets.with_streaming_response.send(
- account_id="account_id",
- amount="amount",
- to="to",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- wallet = await response.parse()
- assert_matches_type(WalletSendResponse, wallet, 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_send(self, async_client: AsyncWhop) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"):
- await async_client.wallets.with_raw_response.send(
- account_id="",
- amount="amount",
- to="to",
- )
diff --git a/tests/api_resources/test_webhooks.py b/tests/api_resources/test_webhooks.py
index 61e0d357..ab622922 100644
--- a/tests/api_resources/test_webhooks.py
+++ b/tests/api_resources/test_webhooks.py
@@ -272,7 +272,7 @@ def test_method_unwrap(self, client: Whop, client_opt: str | None, method_opt: s
client = client.with_options(webhook_key=client_opt)
- data = """{"id":"msg_xxxxxxxxxxxxxxxxxxxxxxxx","api_version":"v1","data":{"id":"crsli_xxxxxxxxxxxx","completed":true,"course":{"id":"cors_xxxxxxxxxxxxx","experience":{"id":"exp_xxxxxxxxxxxxxx"},"title":"Introduction to Technical Analysis"},"created_at":"2023-12-01T05:00:00.401Z","lesson":{"id":"lesn_xxxxxxxxxxxxx","chapter":{"id":"chap_xxxxxxxxxxxxx"},"title":"Understanding Candlestick Patterns"},"user":{"id":"user_xxxxxxxxxxxxx","name":"John Doe","username":"johndoe42"}},"timestamp":"2025-01-01T00:00:00.000Z","type":"course_lesson_interaction.completed","company_id":"biz_xxxxxxxxxxxxxx"}"""
+ data = """{"id":"msg_xxxxxxxxxxxxxxxxxxxxxxxx","api_version":"v1","data":{"audience":{"type":"channel","user_ids":["user_xxxxxxxxxxxxxx"]},"channel":{"id":"feed_xxxxxxxxxxxxxx","type":"chat","experience_id":"exp_xxxxxxxxxxxxxx"},"message":{"id":"id","content":"Hey, are you available for a **quick call**?","created_at":"2023-12-01T05:00:00.401Z","is_edited":true,"is_pinned":true,"mentions":["string"],"mentions_everyone":true,"message_type":"regular","poll":{"options":[{"id":"id","text":"text"}]},"poll_votes":[{"count":42,"option_id":"option_id"}],"reaction_counts":[{"count":42,"emoji":"emoji"}],"replying_to_message_id":"replying_to_message_id","updated_at":"2023-12-01T05:00:00.401Z","user":{"id":"user_xxxxxxxxxxxxx","name":"John Doe","username":"johndoe42"},"view_count":42},"reason":"channel_message"},"timestamp":"2025-01-01T00:00:00.000Z","type":"chat.message.created","company_id":"biz_xxxxxxxxxxxxxx"}"""
msg_id = "1"
timestamp = datetime.now(tz=timezone.utc)
sig = hook.sign(msg_id=msg_id, timestamp=timestamp, data=data)
@@ -549,7 +549,7 @@ def test_method_unwrap(self, async_client: Whop, client_opt: str | None, method_
async_client = async_client.with_options(webhook_key=client_opt)
- data = """{"id":"msg_xxxxxxxxxxxxxxxxxxxxxxxx","api_version":"v1","data":{"id":"crsli_xxxxxxxxxxxx","completed":true,"course":{"id":"cors_xxxxxxxxxxxxx","experience":{"id":"exp_xxxxxxxxxxxxxx"},"title":"Introduction to Technical Analysis"},"created_at":"2023-12-01T05:00:00.401Z","lesson":{"id":"lesn_xxxxxxxxxxxxx","chapter":{"id":"chap_xxxxxxxxxxxxx"},"title":"Understanding Candlestick Patterns"},"user":{"id":"user_xxxxxxxxxxxxx","name":"John Doe","username":"johndoe42"}},"timestamp":"2025-01-01T00:00:00.000Z","type":"course_lesson_interaction.completed","company_id":"biz_xxxxxxxxxxxxxx"}"""
+ data = """{"id":"msg_xxxxxxxxxxxxxxxxxxxxxxxx","api_version":"v1","data":{"audience":{"type":"channel","user_ids":["user_xxxxxxxxxxxxxx"]},"channel":{"id":"feed_xxxxxxxxxxxxxx","type":"chat","experience_id":"exp_xxxxxxxxxxxxxx"},"message":{"id":"id","content":"Hey, are you available for a **quick call**?","created_at":"2023-12-01T05:00:00.401Z","is_edited":true,"is_pinned":true,"mentions":["string"],"mentions_everyone":true,"message_type":"regular","poll":{"options":[{"id":"id","text":"text"}]},"poll_votes":[{"count":42,"option_id":"option_id"}],"reaction_counts":[{"count":42,"emoji":"emoji"}],"replying_to_message_id":"replying_to_message_id","updated_at":"2023-12-01T05:00:00.401Z","user":{"id":"user_xxxxxxxxxxxxx","name":"John Doe","username":"johndoe42"},"view_count":42},"reason":"channel_message"},"timestamp":"2025-01-01T00:00:00.000Z","type":"chat.message.created","company_id":"biz_xxxxxxxxxxxxxx"}"""
msg_id = "1"
timestamp = datetime.now(tz=timezone.utc)
sig = hook.sign(msg_id=msg_id, timestamp=timestamp, data=data)