diff --git a/.stats.yml b/.stats.yml
index a5722ed08..330fae472 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1 +1 @@
-configured_endpoints: 226
+configured_endpoints: 271
diff --git a/README.md b/README.md
index f695ea0b2..b1c1867d2 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=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB3aG9wL21jcCJdLCJlbnYiOnsiV0hPUF9BUElfS0VZIjoiTXkgQVBJIEtleSIsIldIT1BfV0VCSE9PS19TRUNSRVQiOiJNeSBXZWJob29rIEtleSIsIldIT1BfQVBQX0lEIjoiYXBwX3h4eHh4eHh4eHh4eHh4IiwiV0hPUF9BUElfVkVSU0lPTiI6IjIwMjYtMDctMDgtMSJ9fQ)
+[](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-08-1%22%7D%7D)
> Note: You may need to set environment variables in your MCP client.
diff --git a/api.md b/api.md
index 8c7ec82dd..e33647a5f 100644
--- a/api.md
+++ b/api.md
@@ -53,7 +53,6 @@ from whop_sdk.types import (
ShipmentSubstatus,
SupportChannel,
TaxType,
- Transfer,
Visibility,
VisibilityFilter,
WhoCanCommentTypes,
@@ -68,7 +67,7 @@ from whop_sdk.types import (
Types:
```python
-from whop_sdk.types import AppType, AppListResponse
+from whop_sdk.types import AppType, AppListResponse, AppLogsResponse
```
Methods:
@@ -77,6 +76,7 @@ Methods:
- client.apps.retrieve(id) -> App
- client.apps.update(id, \*\*params) -> App
- client.apps.list(\*\*params) -> SyncCursorPage[AppListResponse]
+- client.apps.logs(id, \*\*params) -> AppLogsResponse
# Invoices
@@ -126,6 +126,81 @@ Methods:
- client.products.list(\*\*params) -> SyncCursorPage[ProductListItem]
- client.products.delete(id) -> ProductDeleteResponse
+# SocialAccounts
+
+Types:
+
+```python
+from whop_sdk.types import (
+ SocialAccount,
+ SocialAccountPost,
+ SocialAccountDeleteResponse,
+ SocialAccountConnectResponse,
+ SocialAccountPostsResponse,
+)
+```
+
+Methods:
+
+- client.social_accounts.create(\*\*params) -> SocialAccount
+- client.social_accounts.list(\*\*params) -> SyncCursorPage[SocialAccount]
+- client.social_accounts.delete(id, \*\*params) -> SocialAccountDeleteResponse
+- client.social_accounts.connect(\*\*params) -> SocialAccountConnectResponse
+- 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
+
+# Media
+
+Types:
+
+```python
+from whop_sdk.types import MediaAsset
+```
+
+Methods:
+
+- client.media.retrieve(id) -> MediaAsset
+- client.media.generate(\*\*params) -> MediaAsset
+
+# People
+
+Types:
+
+```python
+from whop_sdk.types import PersonRetrieveResponse, PersonListResponse
+```
+
+Methods:
+
+- client.people.retrieve(person_id, \*\*params) -> PersonRetrieveResponse
+- client.people.list(\*\*params) -> SyncCursorPage[PersonListResponse]
+
+# Events
+
+Types:
+
+```python
+from whop_sdk.types import EventCreateResponse, EventListResponse
+```
+
+Methods:
+
+- client.events.create(\*\*params) -> EventCreateResponse
+- client.events.list(\*\*params) -> SyncCursorPage[EventListResponse]
+
# Companies
Types:
@@ -154,6 +229,8 @@ from whop_sdk.types import (
WebhookCreateResponse,
WebhookListResponse,
WebhookDeleteResponse,
+ ChatMessageCreatedWebhookEvent,
+ ChatReactionCreatedWebhookEvent,
CourseLessonInteractionCompletedWebhookEvent,
DisputeCreatedWebhookEvent,
DisputeUpdatedWebhookEvent,
@@ -171,9 +248,11 @@ from whop_sdk.types import (
InvoicePaidWebhookEvent,
InvoicePastDueWebhookEvent,
InvoiceVoidedWebhookEvent,
+ LedgerAccountFundsAvailableWebhookEvent,
MembershipActivatedWebhookEvent,
MembershipCancelAtPeriodEndChangedWebhookEvent,
MembershipDeactivatedWebhookEvent,
+ MembershipTrialEndingSoonWebhookEvent,
PaymentCreatedWebhookEvent,
PaymentFailedWebhookEvent,
PaymentPendingWebhookEvent,
@@ -208,7 +287,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 +303,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 +340,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 +429,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 +479,16 @@ Methods:
Types:
```python
-from whop_sdk.types import User, UserListResponse, UserCheckAccessResponse
+from whop_sdk.types import User, UserBalance, 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,46 +801,173 @@ Methods:
Types:
```python
-from whop_sdk.types import Account, AccountSocialLink, AccountListResponse
+from whop_sdk.types import Account, AccountSocialLink, AccountRecommendActionsResponse
+```
+
+Methods:
+
+- client.accounts.create(\*\*params) -> Account
+- client.accounts.retrieve(account_id) -> Account
+- client.accounts.update(account_id, \*\*params) -> Account
+- client.accounts.list(\*\*params) -> SyncCursorPage[Account]
+- client.accounts.me() -> Account
+- client.accounts.recommend_actions(account_id) -> AccountRecommendActionsResponse
+
+## Preferences
+
+Types:
+
+```python
+from whop_sdk.types.accounts import PreferenceRetrieveResponse, PreferenceUpdateResponse
+```
+
+Methods:
+
+- client.accounts.preferences.retrieve(account_id) -> PreferenceRetrieveResponse
+- client.accounts.preferences.update(account_id, \*\*params) -> PreferenceUpdateResponse
+
+# FinancialActivity
+
+Types:
+
+```python
+from whop_sdk.types import FinancialActivityListResponse
```
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.me() -> Account
+- client.financial_activity.list(\*\*params) -> FinancialActivityListResponse
-# Wallets
+# 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 PayoutCreateResponse, PayoutListResponse
+```
+
+Methods:
+
+- client.payouts.create(\*\*params) -> PayoutCreateResponse
+- client.payouts.list(\*\*params) -> SyncCursorPage[PayoutListResponse]
+
+## Methods
+
+Types:
+
+```python
+from whop_sdk.types.payouts import MethodListResponse
+```
+
+Methods:
+
+- client.payouts.methods.list(\*\*params) -> SyncCursorPage[MethodListResponse]
+
+# Referrals
+
+Types:
+
+```python
+from whop_sdk.types import ReferralReferredUsersResponse
+```
+
+Methods:
+
+- client.referrals.referred_users(\*\*params) -> ReferralReferredUsersResponse
+
+## Businesses
+
+Types:
+
+```python
+from whop_sdk.types.referrals import (
+ BusinessRetrieveResponse,
+ BusinessListResponse,
+ BusinessLeaderboardResponse,
+)
+```
+
+Methods:
+
+- client.referrals.businesses.retrieve(id) -> BusinessRetrieveResponse
+- client.referrals.businesses.list(\*\*params) -> SyncCursorPage[BusinessListResponse]
+- client.referrals.businesses.leaderboard(\*\*params) -> BusinessLeaderboardResponse
+
+### Earnings
+
+Types:
+
+```python
+from whop_sdk.types.referrals.businesses import EarningListResponse
+```
+
+Methods:
+
+- client.referrals.businesses.earnings.list(id, \*\*params) -> SyncCursorPage[EarningListResponse]
+
+## Partners
+
+Types:
+
+```python
+from whop_sdk.types.referrals import PartnerCreateResponse
+```
+
+Methods:
+
+- client.referrals.partners.create() -> PartnerCreateResponse
+
+# Cards
Types:
```python
from whop_sdk.types import (
- AccountWallet,
- WalletListResponse,
- WalletBalanceResponse,
- WalletSendResponse,
+ CardCreateResponse,
+ CardRetrieveResponse,
+ CardUpdateResponse,
+ CardListResponse,
)
```
Methods:
-- client.wallets.list() -> WalletListResponse
-- client.wallets.balance(account_id) -> WalletBalanceResponse
-- client.wallets.send(account_id, \*\*params) -> WalletSendResponse
+- client.cards.create(\*\*params) -> CardCreateResponse
+- client.cards.retrieve(card_id, \*\*params) -> CardRetrieveResponse
+- client.cards.update(card_id, \*\*params) -> CardUpdateResponse
+- 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 +975,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
@@ -807,23 +1028,6 @@ Methods:
- client.fee_markups.list(\*\*params) -> SyncCursorPage[FeeMarkupListResponse]
- client.fee_markups.delete(id) -> FeeMarkupDeleteResponse
-# PayoutMethods
-
-Types:
-
-```python
-from whop_sdk.types import (
- PayoutDestinationCategory,
- PayoutMethodRetrieveResponse,
- PayoutMethodListResponse,
-)
-```
-
-Methods:
-
-- client.payout_methods.retrieve(id) -> PayoutMethodRetrieveResponse
-- client.payout_methods.list(\*\*params) -> SyncCursorPage[PayoutMethodListResponse]
-
# Verifications
Types:
@@ -832,15 +1036,19 @@ Types:
from whop_sdk.types import (
VerificationErrorCode,
VerificationStatus,
+ VerificationCreateResponse,
VerificationRetrieveResponse,
+ VerificationUpdateResponse,
VerificationListResponse,
)
```
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
# Leads
@@ -1063,19 +1271,36 @@ Methods:
- client.bounties.retrieve(id) -> BountyRetrieveResponse
- client.bounties.list(\*\*params) -> SyncCursorPage[BountyListResponse]
+# Workforce
+
+## Bounties
+
+Types:
+
+```python
+from whop_sdk.types.workforce import WorkforceBounty, WorkforceBountyListItem
+```
+
+Methods:
+
+- client.workforce.bounties.retrieve(id) -> WorkforceBounty
+- client.workforce.bounties.list(\*\*params) -> SyncCursorPage[WorkforceBountyListItem]
+
# AdCampaigns
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 +1309,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,28 +1327,19 @@ 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
-# Conversions
-
-Types:
-
-```python
-from whop_sdk.types import ConversionCreateResponse
-```
-
-Methods:
-
-- client.conversions.create(\*\*params) -> ConversionCreateResponse
-
# AdReports
Types:
diff --git a/src/whop_sdk/_client.py b/src/whop_sdk/_client.py
index 81df0bfb3..504c49098 100644
--- a/src/whop_sdk/_client.py
+++ b/src/whop_sdk/_client.py
@@ -38,19 +38,24 @@
from .resources import (
ads,
apps,
+ cards,
files,
leads,
+ media,
plans,
+ stats,
swaps,
users,
+ events,
forums,
+ people,
topups,
courses,
entries,
members,
+ payouts,
refunds,
reviews,
- wallets,
accounts,
ai_chats,
bounties,
@@ -62,15 +67,17 @@
products,
webhooks,
ad_groups,
+ audiences,
companies,
reactions,
+ referrals,
shipments,
transfers,
+ workforce,
ad_reports,
affiliates,
app_builds,
dm_members,
- conversions,
dm_channels,
experiences,
fee_markups,
@@ -87,14 +94,15 @@
verifications,
course_lessons,
dispute_alerts,
- payout_methods,
course_chapters,
course_students,
ledger_accounts,
payment_methods,
payout_accounts,
+ social_accounts,
authorized_users,
support_channels,
+ financial_activity,
checkout_configurations,
resolution_center_cases,
company_token_transactions,
@@ -102,20 +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.media import MediaResource, AsyncMediaResource
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.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
from .resources.deposits import DepositsResource, AsyncDepositsResource
@@ -126,6 +137,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
@@ -133,7 +145,6 @@
from .resources.ad_reports import AdReportsResource, AsyncAdReportsResource
from .resources.app_builds import AppBuildsResource, AsyncAppBuildsResource
from .resources.dm_members import DmMembersResource, AsyncDmMembersResource
- from .resources.conversions import ConversionsResource, AsyncConversionsResource
from .resources.dm_channels import DmChannelsResource, AsyncDmChannelsResource
from .resources.experiences import ExperiencesResource, AsyncExperiencesResource
from .resources.fee_markups import FeeMarkupsResource, AsyncFeeMarkupsResource
@@ -150,14 +161,19 @@
from .resources.verifications import VerificationsResource, AsyncVerificationsResource
from .resources.course_lessons import CourseLessonsResource, AsyncCourseLessonsResource
from .resources.dispute_alerts import DisputeAlertsResource, AsyncDisputeAlertsResource
- from .resources.payout_methods import PayoutMethodsResource, AsyncPayoutMethodsResource
from .resources.course_chapters import CourseChaptersResource, AsyncCourseChaptersResource
from .resources.course_students import CourseStudentsResource, AsyncCourseStudentsResource
from .resources.ledger_accounts import LedgerAccountsResource, AsyncLedgerAccountsResource
from .resources.payment_methods import PaymentMethodsResource, AsyncPaymentMethodsResource
from .resources.payout_accounts import PayoutAccountsResource, AsyncPayoutAccountsResource
+ from .resources.payouts.payouts import PayoutsResource, AsyncPayoutsResource
+ from .resources.social_accounts import SocialAccountsResource, AsyncSocialAccountsResource
from .resources.authorized_users import AuthorizedUsersResource, AsyncAuthorizedUsersResource
from .resources.support_channels import SupportChannelsResource, AsyncSupportChannelsResource
+ from .resources.accounts.accounts import AccountsResource, AsyncAccountsResource
+ from .resources.financial_activity import FinancialActivityResource, AsyncFinancialActivityResource
+ from .resources.referrals.referrals import ReferralsResource, AsyncReferralsResource
+ from .resources.workforce.workforce import WorkforceResource, AsyncWorkforceResource
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-08-1"
+ self.version = version
+
if base_url is None:
base_url = os.environ.get("WHOP_BASE_URL")
if base_url is None:
@@ -254,437 +277,551 @@ def __init__(
@cached_property
def apps(self) -> AppsResource:
- """Apps"""
+ """An App is software you build on Whop.
+
+ It can be a hosted web app served at `.whop.app` or an API integration installed as an experience, and it belongs to the account that owns its credentials, settings, builds, and runtime logs.
+
+ Use the Apps API to manage app configuration and, for hosted apps, read server runtime logs for console output, uncaught exceptions, and failed requests. Logs are retained for 7 days and can be filtered by build, level, time window, and message text.
+ """
from .resources.apps import AppsResource
return AppsResource(self)
@cached_property
def invoices(self) -> InvoicesResource:
- """Invoices"""
from .resources.invoices import InvoicesResource
return InvoicesResource(self)
@cached_property
def course_lesson_interactions(self) -> CourseLessonInteractionsResource:
- """Course lesson interactions"""
from .resources.course_lesson_interactions import CourseLessonInteractionsResource
return CourseLessonInteractionsResource(self)
@cached_property
def products(self) -> ProductsResource:
- """Products"""
+ """A Product is a digital good or service sold on Whop.
+
+ Products may contain plans for pricing and/or experiences for content delivery.
+
+ Use the Products API to create products, list products visible to your credentials, retrieve product details, update product metadata or merchandising fields, and delete products that should no longer be sold.
+ """
from .resources.products import ProductsResource
return ProductsResource(self)
+ @cached_property
+ def social_accounts(self) -> SocialAccountsResource:
+ """
+ A Social Account represents an external profile connected to a Whop account or user, such as a Facebook page or Instagram account. Connecting a social account lets Whop run [ads](/api-reference/beta/ads/ad) under that profile's identity and promote its existing posts.
+
+ Use the Social Accounts API to list connected accounts, create a Whop-managed Facebook page, start an OAuth connection, disconnect a social account, and list a connected profile's posts.
+ """
+ from .resources.social_accounts import SocialAccountsResource
+
+ return SocialAccountsResource(self)
+
+ @cached_property
+ def audiences(self) -> AudiencesResource:
+ """An Audience represents a customer list uploaded to Whop for ad targeting.
+
+ Audiences belong to an account and sync to supported ad platforms as custom audiences.
+
+ Use the Audiences API to create audiences from CSV uploads, monitor processing status, and list or delete audiences for an account. Created audiences are usable for targeting after processing reaches `ready` or `partial`.
+ """
+ from .resources.audiences import AudiencesResource
+
+ return AudiencesResource(self)
+
+ @cached_property
+ def media(self) -> MediaResource:
+ """
+ A Media Asset is an AI-generated image or video created from a prompt and billed from an account balance. When generation finishes, the asset includes a file that can be attached anywhere Whop accepts files.
+
+ Use the Media API to start a generation job and retrieve the asset while it processes or after it is ready.
+ """
+ from .resources.media import MediaResource
+
+ return MediaResource(self)
+
+ @cached_property
+ def people(self) -> PeopleResource:
+ """
+ A Person represents a visitor or customer of an account, assembled from [pixel events](/api-reference/beta/events/event) and purchase activity — ad clicks, storefront visits, and checkouts.
+
+ Use the People API to list the people of an account and retrieve a single person.
+ """
+ from .resources.people import PeopleResource
+
+ return PeopleResource(self)
+
+ @cached_property
+ def events(self) -> EventsResource:
+ """
+ An Event records conversion or engagement activity for an account, such as page views, purchases, or leads. Each event ties the action to the [person](/api-reference/beta/people/person) who took it, so activity can be attributed to the ads and links that drove it.
+
+ Use the Events API to send new tracking events and list the events recorded for a person.
+ """
+ from .resources.events import EventsResource
+
+ return EventsResource(self)
+
@cached_property
def companies(self) -> CompaniesResource:
- """Companies"""
from .resources.companies import CompaniesResource
return CompaniesResource(self)
@cached_property
def webhooks(self) -> WebhooksResource:
- """Webhooks"""
from .resources.webhooks import WebhooksResource
return WebhooksResource(self)
@cached_property
def plans(self) -> PlansResource:
- """Plans"""
+ """A Plan defines how customers buy a product.
+
+ It controls pricing, billing cadence, availability, tax behavior, checkout fields, and purchase visibility.
+
+ Use the Plans API to create plans for products, list existing plans, retrieve or update plan configuration, calculate tax for checkout, and delete plans that should no longer be offered.
+ """
from .resources.plans import PlansResource
return PlansResource(self)
@cached_property
def entries(self) -> EntriesResource:
- """Entries"""
from .resources.entries import EntriesResource
return EntriesResource(self)
@cached_property
def forum_posts(self) -> ForumPostsResource:
- """Forum posts"""
from .resources.forum_posts import ForumPostsResource
return ForumPostsResource(self)
@cached_property
def transfers(self) -> TransfersResource:
- """Transfers"""
+ """Transfers move value between identities on Whop.
+
+ They are used for account-to-account money movement, user payouts inside Whop, crypto transfers, and claim links depending on the destination type.
+
+ Use the Transfers API to create a transfer, list previous transfers, and retrieve a transfer by ID when reconciling money movement between accounts or users.
+ """
from .resources.transfers import TransfersResource
return TransfersResource(self)
@cached_property
def ledger_accounts(self) -> LedgerAccountsResource:
- """Ledger accounts"""
from .resources.ledger_accounts import LedgerAccountsResource
return LedgerAccountsResource(self)
@cached_property
def memberships(self) -> MembershipsResource:
- """Memberships"""
from .resources.memberships import MembershipsResource
return MembershipsResource(self)
@cached_property
def authorized_users(self) -> AuthorizedUsersResource:
- """Authorized users"""
from .resources.authorized_users import AuthorizedUsersResource
return AuthorizedUsersResource(self)
@cached_property
def app_builds(self) -> AppBuildsResource:
- """App builds"""
from .resources.app_builds import AppBuildsResource
return AppBuildsResource(self)
@cached_property
def shipments(self) -> ShipmentsResource:
- """Shipments"""
from .resources.shipments import ShipmentsResource
return ShipmentsResource(self)
@cached_property
def checkout_configurations(self) -> CheckoutConfigurationsResource:
- """Checkout configurations"""
+ """A Checkout Configuration is a reusable checkout link owned by an account.
+
+ In `payment` mode it sells a specific plan; in `setup` mode it collects and saves payment details without charging. Each configuration can also override which payment methods are accepted and how 3D Secure is enforced for that checkout.
+
+ Use the Checkout Configurations API to create checkout links for an existing or inline plan, list configurations for an account, retrieve the configuration behind a checkout URL, and delete links that should no longer be used.
+ """
from .resources.checkout_configurations import CheckoutConfigurationsResource
return CheckoutConfigurationsResource(self)
@cached_property
def messages(self) -> MessagesResource:
- """Messages"""
from .resources.messages import MessagesResource
return MessagesResource(self)
@cached_property
def chat_channels(self) -> ChatChannelsResource:
- """Chat channels"""
from .resources.chat_channels import ChatChannelsResource
return ChatChannelsResource(self)
@cached_property
def users(self) -> UsersResource:
- """Users"""
+ """A User represents a person on Whop.
+
+ Users have a public profile and can buy products, join accounts, and access experiences.
+
+ Use the Users API to search for users, retrieve or update profiles, and check whether a user has access to an account, product, or experience.
+ """
from .resources.users import UsersResource
return UsersResource(self)
@cached_property
def payments(self) -> PaymentsResource:
- """Payments"""
from .resources.payments import PaymentsResource
return PaymentsResource(self)
@cached_property
def support_channels(self) -> SupportChannelsResource:
- """Support channels"""
from .resources.support_channels import SupportChannelsResource
return SupportChannelsResource(self)
@cached_property
def experiences(self) -> ExperiencesResource:
- """Experiences"""
from .resources.experiences import ExperiencesResource
return ExperiencesResource(self)
@cached_property
def reactions(self) -> ReactionsResource:
- """Reactions"""
from .resources.reactions import ReactionsResource
return ReactionsResource(self)
@cached_property
def members(self) -> MembersResource:
- """Members"""
from .resources.members import MembersResource
return MembersResource(self)
@cached_property
def forums(self) -> ForumsResource:
- """Forums"""
from .resources.forums import ForumsResource
return ForumsResource(self)
@cached_property
def promo_codes(self) -> PromoCodesResource:
- """Promo codes"""
from .resources.promo_codes import PromoCodesResource
return PromoCodesResource(self)
@cached_property
def courses(self) -> CoursesResource:
- """Courses"""
from .resources.courses import CoursesResource
return CoursesResource(self)
@cached_property
def course_chapters(self) -> CourseChaptersResource:
- """Course chapters"""
from .resources.course_chapters import CourseChaptersResource
return CourseChaptersResource(self)
@cached_property
def course_lessons(self) -> CourseLessonsResource:
- """Course lessons"""
from .resources.course_lessons import CourseLessonsResource
return CourseLessonsResource(self)
@cached_property
def reviews(self) -> ReviewsResource:
- """Reviews"""
from .resources.reviews import ReviewsResource
return ReviewsResource(self)
@cached_property
def course_students(self) -> CourseStudentsResource:
- """Course students"""
from .resources.course_students import CourseStudentsResource
return CourseStudentsResource(self)
@cached_property
def access_tokens(self) -> AccessTokensResource:
- """Access tokens"""
from .resources.access_tokens import AccessTokensResource
return AccessTokensResource(self)
@cached_property
def notifications(self) -> NotificationsResource:
- """Notifications"""
from .resources.notifications import NotificationsResource
return NotificationsResource(self)
@cached_property
def disputes(self) -> DisputesResource:
- """Disputes"""
from .resources.disputes import DisputesResource
return DisputesResource(self)
@cached_property
def refunds(self) -> RefundsResource:
- """Refunds"""
from .resources.refunds import RefundsResource
return RefundsResource(self)
@cached_property
def withdrawals(self) -> WithdrawalsResource:
- """Withdrawals"""
from .resources.withdrawals import WithdrawalsResource
return WithdrawalsResource(self)
@cached_property
def account_links(self) -> AccountLinksResource:
- """Account links"""
from .resources.account_links import AccountLinksResource
return AccountLinksResource(self)
@cached_property
def accounts(self) -> AccountsResource:
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
from .resources.accounts import AccountsResource
return AccountsResource(self)
@cached_property
- def wallets(self) -> WalletsResource:
- from .resources.wallets import WalletsResource
+ def financial_activity(self) -> FinancialActivityResource:
+ """
+ A Ledger Activity row is a single financial event on an account's ledger — a payment, withdrawal, refund, transfer, on-chain deposit, swap, or card transaction. Each row is derived from the underlying ledger lines and carries a typed `resource` and `source` so you can present and link the event without extra lookups.
+
+ Use Ledger Activity to build a statement or transaction feed for an account or user. Reconcile against your own records with `amount` (signed, in the currency's smallest precision units) and `posted_at`, and use `available_at` to know when inflows became withdrawable.
+ """
+ from .resources.financial_activity import FinancialActivityResource
+
+ return FinancialActivityResource(self)
+
+ @cached_property
+ def stats(self) -> StatsResource:
+ """Stats represent aggregated activity for an account over time.
+
+ They help you understand revenue, transactions, disputes, members, referrals, and advertising performance across reporting periods like days, weeks, or months.
+
+ Use the Stats API to list available metrics and their filterable properties, then retrieve time-series values for a date range.
+ """
+ from .resources.stats import StatsResource
+
+ return StatsResource(self)
+
+ @cached_property
+ def payouts(self) -> PayoutsResource:
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+ from .resources.payouts import PayoutsResource
+
+ return PayoutsResource(self)
+
+ @cached_property
+ def referrals(self) -> ReferralsResource:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ from .resources.referrals import ReferralsResource
+
+ return ReferralsResource(self)
+
+ @cached_property
+ def cards(self) -> CardsResource:
+ """
+ Cards represent Whop-issued virtual payment cards that spend from an account or user balance. Cards can be assigned to cardholders and configured with spending limits for controlled spending.
+
+ Use the Cards API to issue cards, list cards for an account or user, and retrieve active card details such as the card number and CVC.
+ """
+ from .resources.cards import CardsResource
- return WalletsResource(self)
+ return CardsResource(self)
@cached_property
def swaps(self) -> SwapsResource:
+ """
+ Swaps convert value between supported tokens, chains, or wallet destinations for an account. A swap quote describes the expected output, fees, and approval requirements before you create the swap.
+
+ Use the Swaps API to quote a conversion, create the swap, list recent swaps, and retrieve status until the transaction completes.
+ """
from .resources.swaps import SwapsResource
return SwapsResource(self)
@cached_property
def deposits(self) -> DepositsResource:
+ """
+ Deposits describe ways to add funds to an account balance, including hosted deposit pages, bank deposit instructions, and supported crypto wallet addresses.
+
+ Use the Deposits API to create deposit instructions for an account and retrieve existing bank deposit activity.
+ """
from .resources.deposits import DepositsResource
return DepositsResource(self)
@cached_property
def setup_intents(self) -> SetupIntentsResource:
- """Setup intents"""
from .resources.setup_intents import SetupIntentsResource
return SetupIntentsResource(self)
@cached_property
def payment_methods(self) -> PaymentMethodsResource:
- """Payment methods"""
from .resources.payment_methods import PaymentMethodsResource
return PaymentMethodsResource(self)
@cached_property
def fee_markups(self) -> FeeMarkupsResource:
- """Fee markups"""
from .resources.fee_markups import FeeMarkupsResource
return FeeMarkupsResource(self)
@cached_property
- def payout_methods(self) -> PayoutMethodsResource:
- """Payout methods"""
- from .resources.payout_methods import PayoutMethodsResource
+ def verifications(self) -> VerificationsResource:
+ """A Verification represents an identity review for a person or business.
- return PayoutMethodsResource(self)
+ Accounts and users complete verification when Whop needs to confirm who they are before enabling payouts or compliance-sensitive workflows.
- @cached_property
- def verifications(self) -> VerificationsResource:
- """Verifications"""
+ Use the Verifications API to start or resume a hosted verification session, check review status, and submit requested details or documents. If `requested_information` contains items, submit answers with [Update Verification](/api-reference/beta/verifications/update-verification).
+ """
from .resources.verifications import VerificationsResource
return VerificationsResource(self)
@cached_property
def leads(self) -> LeadsResource:
- """Leads"""
from .resources.leads import LeadsResource
return LeadsResource(self)
@cached_property
def topups(self) -> TopupsResource:
- """Topups"""
from .resources.topups import TopupsResource
return TopupsResource(self)
@cached_property
def files(self) -> FilesResource:
- """Files"""
from .resources.files import FilesResource
return FilesResource(self)
@cached_property
def company_token_transactions(self) -> CompanyTokenTransactionsResource:
- """Company token transactions"""
from .resources.company_token_transactions import CompanyTokenTransactionsResource
return CompanyTokenTransactionsResource(self)
@cached_property
def dm_members(self) -> DmMembersResource:
- """Dm members"""
from .resources.dm_members import DmMembersResource
return DmMembersResource(self)
@cached_property
def ai_chats(self) -> AIChatsResource:
- """Ai chats"""
from .resources.ai_chats import AIChatsResource
return AIChatsResource(self)
@cached_property
def dm_channels(self) -> DmChannelsResource:
- """Dm channels"""
from .resources.dm_channels import DmChannelsResource
return DmChannelsResource(self)
@cached_property
def dispute_alerts(self) -> DisputeAlertsResource:
- """Dispute alerts"""
from .resources.dispute_alerts import DisputeAlertsResource
return DisputeAlertsResource(self)
@cached_property
def resolution_center_cases(self) -> ResolutionCenterCasesResource:
- """Resolution center cases"""
from .resources.resolution_center_cases import ResolutionCenterCasesResource
return ResolutionCenterCasesResource(self)
@cached_property
def payout_accounts(self) -> PayoutAccountsResource:
- """Payout accounts"""
from .resources.payout_accounts import PayoutAccountsResource
return PayoutAccountsResource(self)
@cached_property
def affiliates(self) -> AffiliatesResource:
- """Affiliates"""
from .resources.affiliates import AffiliatesResource
return AffiliatesResource(self)
@cached_property
def bounties(self) -> BountiesResource:
- """Bounties"""
from .resources.bounties import BountiesResource
return BountiesResource(self)
+ @cached_property
+ def workforce(self) -> WorkforceResource:
+ from .resources.workforce import WorkforceResource
+
+ return WorkforceResource(self)
+
@cached_property
def ad_campaigns(self) -> AdCampaignsResource:
- """Ad campaigns"""
+ """An Ad Campaign is the top-level container for paid ads on an ad network.
+
+ It sets the platform, objective, and budget strategy shared by its [ad groups](/api-reference/beta/ad-groups/ad-group) and ads.
+
+ Use the Ad Campaigns API to create campaigns, list campaigns for an account, retrieve or update campaign settings, and pause or resume campaign delivery.
+ """
from .resources.ad_campaigns import AdCampaignsResource
return AdCampaignsResource(self)
@cached_property
def ad_groups(self) -> AdGroupsResource:
- """Ad groups"""
+ """
+ An Ad Group sits inside an [ad campaign](/api-reference/beta/ad-campaigns/ad-campaign) and controls delivery for [ads](/api-reference/beta/ads/ad). It sets the audience, placements, schedule, budget, and optimization goal for its ads.
+
+ Use the Ad Groups API to create ad groups in campaigns, list or retrieve targeting and delivery settings, update budgets or targeting, delete groups that should stop running, and pause or resume delivery.
+ """
from .resources.ad_groups import AdGroupsResource
return AdGroupsResource(self)
@cached_property
def ads(self) -> AdsResource:
- """Ads"""
+ """
+ An Ad is the individual creative unit delivered by an [ad group](/api-reference/beta/ad-groups/ad-group). It holds the copy, creative assets, and destination URL for one ad.
+
+ Use the Ads API to list ads for an account, create ads inside ad groups, retrieve or update creative details, delete ads that should stop running, and pause or resume delivery.
+ """
from .resources.ads import AdsResource
return AdsResource(self)
- @cached_property
- def conversions(self) -> ConversionsResource:
- """Conversions"""
- from .resources.conversions import ConversionsResource
-
- return ConversionsResource(self)
-
@cached_property
def ad_reports(self) -> AdReportsResource:
- """Ad reports"""
from .resources.ad_reports import AdReportsResource
return AdReportsResource(self)
@@ -715,6 +852,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 +862,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 +899,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 +952,7 @@ class AsyncWhop(AsyncAPIClient):
api_key: str
webhook_key: str | None
app_id: str | None
+ version: str | None
def __init__(
self,
@@ -819,6 +960,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 +986,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 +1004,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-08-1"
+ self.version = version
+
if base_url is None:
base_url = os.environ.get("WHOP_BASE_URL")
if base_url is None:
@@ -888,437 +1035,551 @@ def __init__(
@cached_property
def apps(self) -> AsyncAppsResource:
- """Apps"""
+ """An App is software you build on Whop.
+
+ It can be a hosted web app served at `.whop.app` or an API integration installed as an experience, and it belongs to the account that owns its credentials, settings, builds, and runtime logs.
+
+ Use the Apps API to manage app configuration and, for hosted apps, read server runtime logs for console output, uncaught exceptions, and failed requests. Logs are retained for 7 days and can be filtered by build, level, time window, and message text.
+ """
from .resources.apps import AsyncAppsResource
return AsyncAppsResource(self)
@cached_property
def invoices(self) -> AsyncInvoicesResource:
- """Invoices"""
from .resources.invoices import AsyncInvoicesResource
return AsyncInvoicesResource(self)
@cached_property
def course_lesson_interactions(self) -> AsyncCourseLessonInteractionsResource:
- """Course lesson interactions"""
from .resources.course_lesson_interactions import AsyncCourseLessonInteractionsResource
return AsyncCourseLessonInteractionsResource(self)
@cached_property
def products(self) -> AsyncProductsResource:
- """Products"""
+ """A Product is a digital good or service sold on Whop.
+
+ Products may contain plans for pricing and/or experiences for content delivery.
+
+ Use the Products API to create products, list products visible to your credentials, retrieve product details, update product metadata or merchandising fields, and delete products that should no longer be sold.
+ """
from .resources.products import AsyncProductsResource
return AsyncProductsResource(self)
+ @cached_property
+ def social_accounts(self) -> AsyncSocialAccountsResource:
+ """
+ A Social Account represents an external profile connected to a Whop account or user, such as a Facebook page or Instagram account. Connecting a social account lets Whop run [ads](/api-reference/beta/ads/ad) under that profile's identity and promote its existing posts.
+
+ Use the Social Accounts API to list connected accounts, create a Whop-managed Facebook page, start an OAuth connection, disconnect a social account, and list a connected profile's posts.
+ """
+ from .resources.social_accounts import AsyncSocialAccountsResource
+
+ return AsyncSocialAccountsResource(self)
+
+ @cached_property
+ def audiences(self) -> AsyncAudiencesResource:
+ """An Audience represents a customer list uploaded to Whop for ad targeting.
+
+ Audiences belong to an account and sync to supported ad platforms as custom audiences.
+
+ Use the Audiences API to create audiences from CSV uploads, monitor processing status, and list or delete audiences for an account. Created audiences are usable for targeting after processing reaches `ready` or `partial`.
+ """
+ from .resources.audiences import AsyncAudiencesResource
+
+ return AsyncAudiencesResource(self)
+
+ @cached_property
+ def media(self) -> AsyncMediaResource:
+ """
+ A Media Asset is an AI-generated image or video created from a prompt and billed from an account balance. When generation finishes, the asset includes a file that can be attached anywhere Whop accepts files.
+
+ Use the Media API to start a generation job and retrieve the asset while it processes or after it is ready.
+ """
+ from .resources.media import AsyncMediaResource
+
+ return AsyncMediaResource(self)
+
+ @cached_property
+ def people(self) -> AsyncPeopleResource:
+ """
+ A Person represents a visitor or customer of an account, assembled from [pixel events](/api-reference/beta/events/event) and purchase activity — ad clicks, storefront visits, and checkouts.
+
+ Use the People API to list the people of an account and retrieve a single person.
+ """
+ from .resources.people import AsyncPeopleResource
+
+ return AsyncPeopleResource(self)
+
+ @cached_property
+ def events(self) -> AsyncEventsResource:
+ """
+ An Event records conversion or engagement activity for an account, such as page views, purchases, or leads. Each event ties the action to the [person](/api-reference/beta/people/person) who took it, so activity can be attributed to the ads and links that drove it.
+
+ Use the Events API to send new tracking events and list the events recorded for a person.
+ """
+ from .resources.events import AsyncEventsResource
+
+ return AsyncEventsResource(self)
+
@cached_property
def companies(self) -> AsyncCompaniesResource:
- """Companies"""
from .resources.companies import AsyncCompaniesResource
return AsyncCompaniesResource(self)
@cached_property
def webhooks(self) -> AsyncWebhooksResource:
- """Webhooks"""
from .resources.webhooks import AsyncWebhooksResource
return AsyncWebhooksResource(self)
@cached_property
def plans(self) -> AsyncPlansResource:
- """Plans"""
+ """A Plan defines how customers buy a product.
+
+ It controls pricing, billing cadence, availability, tax behavior, checkout fields, and purchase visibility.
+
+ Use the Plans API to create plans for products, list existing plans, retrieve or update plan configuration, calculate tax for checkout, and delete plans that should no longer be offered.
+ """
from .resources.plans import AsyncPlansResource
return AsyncPlansResource(self)
@cached_property
def entries(self) -> AsyncEntriesResource:
- """Entries"""
from .resources.entries import AsyncEntriesResource
return AsyncEntriesResource(self)
@cached_property
def forum_posts(self) -> AsyncForumPostsResource:
- """Forum posts"""
from .resources.forum_posts import AsyncForumPostsResource
return AsyncForumPostsResource(self)
@cached_property
def transfers(self) -> AsyncTransfersResource:
- """Transfers"""
+ """Transfers move value between identities on Whop.
+
+ They are used for account-to-account money movement, user payouts inside Whop, crypto transfers, and claim links depending on the destination type.
+
+ Use the Transfers API to create a transfer, list previous transfers, and retrieve a transfer by ID when reconciling money movement between accounts or users.
+ """
from .resources.transfers import AsyncTransfersResource
return AsyncTransfersResource(self)
@cached_property
def ledger_accounts(self) -> AsyncLedgerAccountsResource:
- """Ledger accounts"""
from .resources.ledger_accounts import AsyncLedgerAccountsResource
return AsyncLedgerAccountsResource(self)
@cached_property
def memberships(self) -> AsyncMembershipsResource:
- """Memberships"""
from .resources.memberships import AsyncMembershipsResource
return AsyncMembershipsResource(self)
@cached_property
def authorized_users(self) -> AsyncAuthorizedUsersResource:
- """Authorized users"""
from .resources.authorized_users import AsyncAuthorizedUsersResource
return AsyncAuthorizedUsersResource(self)
@cached_property
def app_builds(self) -> AsyncAppBuildsResource:
- """App builds"""
from .resources.app_builds import AsyncAppBuildsResource
return AsyncAppBuildsResource(self)
@cached_property
def shipments(self) -> AsyncShipmentsResource:
- """Shipments"""
from .resources.shipments import AsyncShipmentsResource
return AsyncShipmentsResource(self)
@cached_property
def checkout_configurations(self) -> AsyncCheckoutConfigurationsResource:
- """Checkout configurations"""
+ """A Checkout Configuration is a reusable checkout link owned by an account.
+
+ In `payment` mode it sells a specific plan; in `setup` mode it collects and saves payment details without charging. Each configuration can also override which payment methods are accepted and how 3D Secure is enforced for that checkout.
+
+ Use the Checkout Configurations API to create checkout links for an existing or inline plan, list configurations for an account, retrieve the configuration behind a checkout URL, and delete links that should no longer be used.
+ """
from .resources.checkout_configurations import AsyncCheckoutConfigurationsResource
return AsyncCheckoutConfigurationsResource(self)
@cached_property
def messages(self) -> AsyncMessagesResource:
- """Messages"""
from .resources.messages import AsyncMessagesResource
return AsyncMessagesResource(self)
@cached_property
def chat_channels(self) -> AsyncChatChannelsResource:
- """Chat channels"""
from .resources.chat_channels import AsyncChatChannelsResource
return AsyncChatChannelsResource(self)
@cached_property
def users(self) -> AsyncUsersResource:
- """Users"""
+ """A User represents a person on Whop.
+
+ Users have a public profile and can buy products, join accounts, and access experiences.
+
+ Use the Users API to search for users, retrieve or update profiles, and check whether a user has access to an account, product, or experience.
+ """
from .resources.users import AsyncUsersResource
return AsyncUsersResource(self)
@cached_property
def payments(self) -> AsyncPaymentsResource:
- """Payments"""
from .resources.payments import AsyncPaymentsResource
return AsyncPaymentsResource(self)
@cached_property
def support_channels(self) -> AsyncSupportChannelsResource:
- """Support channels"""
from .resources.support_channels import AsyncSupportChannelsResource
return AsyncSupportChannelsResource(self)
@cached_property
def experiences(self) -> AsyncExperiencesResource:
- """Experiences"""
from .resources.experiences import AsyncExperiencesResource
return AsyncExperiencesResource(self)
@cached_property
def reactions(self) -> AsyncReactionsResource:
- """Reactions"""
from .resources.reactions import AsyncReactionsResource
return AsyncReactionsResource(self)
@cached_property
def members(self) -> AsyncMembersResource:
- """Members"""
from .resources.members import AsyncMembersResource
return AsyncMembersResource(self)
@cached_property
def forums(self) -> AsyncForumsResource:
- """Forums"""
from .resources.forums import AsyncForumsResource
return AsyncForumsResource(self)
@cached_property
def promo_codes(self) -> AsyncPromoCodesResource:
- """Promo codes"""
from .resources.promo_codes import AsyncPromoCodesResource
return AsyncPromoCodesResource(self)
@cached_property
def courses(self) -> AsyncCoursesResource:
- """Courses"""
from .resources.courses import AsyncCoursesResource
return AsyncCoursesResource(self)
@cached_property
def course_chapters(self) -> AsyncCourseChaptersResource:
- """Course chapters"""
from .resources.course_chapters import AsyncCourseChaptersResource
return AsyncCourseChaptersResource(self)
@cached_property
def course_lessons(self) -> AsyncCourseLessonsResource:
- """Course lessons"""
from .resources.course_lessons import AsyncCourseLessonsResource
return AsyncCourseLessonsResource(self)
@cached_property
def reviews(self) -> AsyncReviewsResource:
- """Reviews"""
from .resources.reviews import AsyncReviewsResource
return AsyncReviewsResource(self)
@cached_property
def course_students(self) -> AsyncCourseStudentsResource:
- """Course students"""
from .resources.course_students import AsyncCourseStudentsResource
return AsyncCourseStudentsResource(self)
@cached_property
def access_tokens(self) -> AsyncAccessTokensResource:
- """Access tokens"""
from .resources.access_tokens import AsyncAccessTokensResource
return AsyncAccessTokensResource(self)
@cached_property
def notifications(self) -> AsyncNotificationsResource:
- """Notifications"""
from .resources.notifications import AsyncNotificationsResource
return AsyncNotificationsResource(self)
@cached_property
def disputes(self) -> AsyncDisputesResource:
- """Disputes"""
from .resources.disputes import AsyncDisputesResource
return AsyncDisputesResource(self)
@cached_property
def refunds(self) -> AsyncRefundsResource:
- """Refunds"""
from .resources.refunds import AsyncRefundsResource
return AsyncRefundsResource(self)
@cached_property
def withdrawals(self) -> AsyncWithdrawalsResource:
- """Withdrawals"""
from .resources.withdrawals import AsyncWithdrawalsResource
return AsyncWithdrawalsResource(self)
@cached_property
def account_links(self) -> AsyncAccountLinksResource:
- """Account links"""
from .resources.account_links import AsyncAccountLinksResource
return AsyncAccountLinksResource(self)
@cached_property
def accounts(self) -> AsyncAccountsResource:
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
from .resources.accounts import AsyncAccountsResource
return AsyncAccountsResource(self)
@cached_property
- def wallets(self) -> AsyncWalletsResource:
- from .resources.wallets import AsyncWalletsResource
+ def financial_activity(self) -> AsyncFinancialActivityResource:
+ """
+ A Ledger Activity row is a single financial event on an account's ledger — a payment, withdrawal, refund, transfer, on-chain deposit, swap, or card transaction. Each row is derived from the underlying ledger lines and carries a typed `resource` and `source` so you can present and link the event without extra lookups.
+
+ Use Ledger Activity to build a statement or transaction feed for an account or user. Reconcile against your own records with `amount` (signed, in the currency's smallest precision units) and `posted_at`, and use `available_at` to know when inflows became withdrawable.
+ """
+ from .resources.financial_activity import AsyncFinancialActivityResource
+
+ return AsyncFinancialActivityResource(self)
+
+ @cached_property
+ def stats(self) -> AsyncStatsResource:
+ """Stats represent aggregated activity for an account over time.
+
+ They help you understand revenue, transactions, disputes, members, referrals, and advertising performance across reporting periods like days, weeks, or months.
+
+ Use the Stats API to list available metrics and their filterable properties, then retrieve time-series values for a date range.
+ """
+ from .resources.stats import AsyncStatsResource
+
+ return AsyncStatsResource(self)
+
+ @cached_property
+ def payouts(self) -> AsyncPayoutsResource:
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+ from .resources.payouts import AsyncPayoutsResource
+
+ return AsyncPayoutsResource(self)
+
+ @cached_property
+ def referrals(self) -> AsyncReferralsResource:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ from .resources.referrals import AsyncReferralsResource
+
+ return AsyncReferralsResource(self)
+
+ @cached_property
+ def cards(self) -> AsyncCardsResource:
+ """
+ Cards represent Whop-issued virtual payment cards that spend from an account or user balance. Cards can be assigned to cardholders and configured with spending limits for controlled spending.
+
+ Use the Cards API to issue cards, list cards for an account or user, and retrieve active card details such as the card number and CVC.
+ """
+ from .resources.cards import AsyncCardsResource
- return AsyncWalletsResource(self)
+ return AsyncCardsResource(self)
@cached_property
def swaps(self) -> AsyncSwapsResource:
+ """
+ Swaps convert value between supported tokens, chains, or wallet destinations for an account. A swap quote describes the expected output, fees, and approval requirements before you create the swap.
+
+ Use the Swaps API to quote a conversion, create the swap, list recent swaps, and retrieve status until the transaction completes.
+ """
from .resources.swaps import AsyncSwapsResource
return AsyncSwapsResource(self)
@cached_property
def deposits(self) -> AsyncDepositsResource:
+ """
+ Deposits describe ways to add funds to an account balance, including hosted deposit pages, bank deposit instructions, and supported crypto wallet addresses.
+
+ Use the Deposits API to create deposit instructions for an account and retrieve existing bank deposit activity.
+ """
from .resources.deposits import AsyncDepositsResource
return AsyncDepositsResource(self)
@cached_property
def setup_intents(self) -> AsyncSetupIntentsResource:
- """Setup intents"""
from .resources.setup_intents import AsyncSetupIntentsResource
return AsyncSetupIntentsResource(self)
@cached_property
def payment_methods(self) -> AsyncPaymentMethodsResource:
- """Payment methods"""
from .resources.payment_methods import AsyncPaymentMethodsResource
return AsyncPaymentMethodsResource(self)
@cached_property
def fee_markups(self) -> AsyncFeeMarkupsResource:
- """Fee markups"""
from .resources.fee_markups import AsyncFeeMarkupsResource
return AsyncFeeMarkupsResource(self)
@cached_property
- def payout_methods(self) -> AsyncPayoutMethodsResource:
- """Payout methods"""
- from .resources.payout_methods import AsyncPayoutMethodsResource
+ def verifications(self) -> AsyncVerificationsResource:
+ """A Verification represents an identity review for a person or business.
- return AsyncPayoutMethodsResource(self)
+ Accounts and users complete verification when Whop needs to confirm who they are before enabling payouts or compliance-sensitive workflows.
- @cached_property
- def verifications(self) -> AsyncVerificationsResource:
- """Verifications"""
+ Use the Verifications API to start or resume a hosted verification session, check review status, and submit requested details or documents. If `requested_information` contains items, submit answers with [Update Verification](/api-reference/beta/verifications/update-verification).
+ """
from .resources.verifications import AsyncVerificationsResource
return AsyncVerificationsResource(self)
@cached_property
def leads(self) -> AsyncLeadsResource:
- """Leads"""
from .resources.leads import AsyncLeadsResource
return AsyncLeadsResource(self)
@cached_property
def topups(self) -> AsyncTopupsResource:
- """Topups"""
from .resources.topups import AsyncTopupsResource
return AsyncTopupsResource(self)
@cached_property
def files(self) -> AsyncFilesResource:
- """Files"""
from .resources.files import AsyncFilesResource
return AsyncFilesResource(self)
@cached_property
def company_token_transactions(self) -> AsyncCompanyTokenTransactionsResource:
- """Company token transactions"""
from .resources.company_token_transactions import AsyncCompanyTokenTransactionsResource
return AsyncCompanyTokenTransactionsResource(self)
@cached_property
def dm_members(self) -> AsyncDmMembersResource:
- """Dm members"""
from .resources.dm_members import AsyncDmMembersResource
return AsyncDmMembersResource(self)
@cached_property
def ai_chats(self) -> AsyncAIChatsResource:
- """Ai chats"""
from .resources.ai_chats import AsyncAIChatsResource
return AsyncAIChatsResource(self)
@cached_property
def dm_channels(self) -> AsyncDmChannelsResource:
- """Dm channels"""
from .resources.dm_channels import AsyncDmChannelsResource
return AsyncDmChannelsResource(self)
@cached_property
def dispute_alerts(self) -> AsyncDisputeAlertsResource:
- """Dispute alerts"""
from .resources.dispute_alerts import AsyncDisputeAlertsResource
return AsyncDisputeAlertsResource(self)
@cached_property
def resolution_center_cases(self) -> AsyncResolutionCenterCasesResource:
- """Resolution center cases"""
from .resources.resolution_center_cases import AsyncResolutionCenterCasesResource
return AsyncResolutionCenterCasesResource(self)
@cached_property
def payout_accounts(self) -> AsyncPayoutAccountsResource:
- """Payout accounts"""
from .resources.payout_accounts import AsyncPayoutAccountsResource
return AsyncPayoutAccountsResource(self)
@cached_property
def affiliates(self) -> AsyncAffiliatesResource:
- """Affiliates"""
from .resources.affiliates import AsyncAffiliatesResource
return AsyncAffiliatesResource(self)
@cached_property
def bounties(self) -> AsyncBountiesResource:
- """Bounties"""
from .resources.bounties import AsyncBountiesResource
return AsyncBountiesResource(self)
+ @cached_property
+ def workforce(self) -> AsyncWorkforceResource:
+ from .resources.workforce import AsyncWorkforceResource
+
+ return AsyncWorkforceResource(self)
+
@cached_property
def ad_campaigns(self) -> AsyncAdCampaignsResource:
- """Ad campaigns"""
+ """An Ad Campaign is the top-level container for paid ads on an ad network.
+
+ It sets the platform, objective, and budget strategy shared by its [ad groups](/api-reference/beta/ad-groups/ad-group) and ads.
+
+ Use the Ad Campaigns API to create campaigns, list campaigns for an account, retrieve or update campaign settings, and pause or resume campaign delivery.
+ """
from .resources.ad_campaigns import AsyncAdCampaignsResource
return AsyncAdCampaignsResource(self)
@cached_property
def ad_groups(self) -> AsyncAdGroupsResource:
- """Ad groups"""
+ """
+ An Ad Group sits inside an [ad campaign](/api-reference/beta/ad-campaigns/ad-campaign) and controls delivery for [ads](/api-reference/beta/ads/ad). It sets the audience, placements, schedule, budget, and optimization goal for its ads.
+
+ Use the Ad Groups API to create ad groups in campaigns, list or retrieve targeting and delivery settings, update budgets or targeting, delete groups that should stop running, and pause or resume delivery.
+ """
from .resources.ad_groups import AsyncAdGroupsResource
return AsyncAdGroupsResource(self)
@cached_property
def ads(self) -> AsyncAdsResource:
- """Ads"""
+ """
+ An Ad is the individual creative unit delivered by an [ad group](/api-reference/beta/ad-groups/ad-group). It holds the copy, creative assets, and destination URL for one ad.
+
+ Use the Ads API to list ads for an account, create ads inside ad groups, retrieve or update creative details, delete ads that should stop running, and pause or resume delivery.
+ """
from .resources.ads import AsyncAdsResource
return AsyncAdsResource(self)
- @cached_property
- def conversions(self) -> AsyncConversionsResource:
- """Conversions"""
- from .resources.conversions import AsyncConversionsResource
-
- return AsyncConversionsResource(self)
-
@cached_property
def ad_reports(self) -> AsyncAdReportsResource:
- """Ad reports"""
from .resources.ad_reports import AsyncAdReportsResource
return AsyncAdReportsResource(self)
@@ -1349,6 +1610,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 +1620,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 +1657,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,
@@ -1449,437 +1713,551 @@ def __init__(self, client: Whop) -> None:
@cached_property
def apps(self) -> apps.AppsResourceWithRawResponse:
- """Apps"""
+ """An App is software you build on Whop.
+
+ It can be a hosted web app served at `.whop.app` or an API integration installed as an experience, and it belongs to the account that owns its credentials, settings, builds, and runtime logs.
+
+ Use the Apps API to manage app configuration and, for hosted apps, read server runtime logs for console output, uncaught exceptions, and failed requests. Logs are retained for 7 days and can be filtered by build, level, time window, and message text.
+ """
from .resources.apps import AppsResourceWithRawResponse
return AppsResourceWithRawResponse(self._client.apps)
@cached_property
def invoices(self) -> invoices.InvoicesResourceWithRawResponse:
- """Invoices"""
from .resources.invoices import InvoicesResourceWithRawResponse
return InvoicesResourceWithRawResponse(self._client.invoices)
@cached_property
def course_lesson_interactions(self) -> course_lesson_interactions.CourseLessonInteractionsResourceWithRawResponse:
- """Course lesson interactions"""
from .resources.course_lesson_interactions import CourseLessonInteractionsResourceWithRawResponse
return CourseLessonInteractionsResourceWithRawResponse(self._client.course_lesson_interactions)
@cached_property
def products(self) -> products.ProductsResourceWithRawResponse:
- """Products"""
+ """A Product is a digital good or service sold on Whop.
+
+ Products may contain plans for pricing and/or experiences for content delivery.
+
+ Use the Products API to create products, list products visible to your credentials, retrieve product details, update product metadata or merchandising fields, and delete products that should no longer be sold.
+ """
from .resources.products import ProductsResourceWithRawResponse
return ProductsResourceWithRawResponse(self._client.products)
+ @cached_property
+ def social_accounts(self) -> social_accounts.SocialAccountsResourceWithRawResponse:
+ """
+ A Social Account represents an external profile connected to a Whop account or user, such as a Facebook page or Instagram account. Connecting a social account lets Whop run [ads](/api-reference/beta/ads/ad) under that profile's identity and promote its existing posts.
+
+ Use the Social Accounts API to list connected accounts, create a Whop-managed Facebook page, start an OAuth connection, disconnect a social account, and list a connected profile's posts.
+ """
+ from .resources.social_accounts import SocialAccountsResourceWithRawResponse
+
+ return SocialAccountsResourceWithRawResponse(self._client.social_accounts)
+
+ @cached_property
+ def audiences(self) -> audiences.AudiencesResourceWithRawResponse:
+ """An Audience represents a customer list uploaded to Whop for ad targeting.
+
+ Audiences belong to an account and sync to supported ad platforms as custom audiences.
+
+ Use the Audiences API to create audiences from CSV uploads, monitor processing status, and list or delete audiences for an account. Created audiences are usable for targeting after processing reaches `ready` or `partial`.
+ """
+ from .resources.audiences import AudiencesResourceWithRawResponse
+
+ return AudiencesResourceWithRawResponse(self._client.audiences)
+
+ @cached_property
+ def media(self) -> media.MediaResourceWithRawResponse:
+ """
+ A Media Asset is an AI-generated image or video created from a prompt and billed from an account balance. When generation finishes, the asset includes a file that can be attached anywhere Whop accepts files.
+
+ Use the Media API to start a generation job and retrieve the asset while it processes or after it is ready.
+ """
+ from .resources.media import MediaResourceWithRawResponse
+
+ return MediaResourceWithRawResponse(self._client.media)
+
+ @cached_property
+ def people(self) -> people.PeopleResourceWithRawResponse:
+ """
+ A Person represents a visitor or customer of an account, assembled from [pixel events](/api-reference/beta/events/event) and purchase activity — ad clicks, storefront visits, and checkouts.
+
+ Use the People API to list the people of an account and retrieve a single person.
+ """
+ from .resources.people import PeopleResourceWithRawResponse
+
+ return PeopleResourceWithRawResponse(self._client.people)
+
+ @cached_property
+ def events(self) -> events.EventsResourceWithRawResponse:
+ """
+ An Event records conversion or engagement activity for an account, such as page views, purchases, or leads. Each event ties the action to the [person](/api-reference/beta/people/person) who took it, so activity can be attributed to the ads and links that drove it.
+
+ Use the Events API to send new tracking events and list the events recorded for a person.
+ """
+ from .resources.events import EventsResourceWithRawResponse
+
+ return EventsResourceWithRawResponse(self._client.events)
+
@cached_property
def companies(self) -> companies.CompaniesResourceWithRawResponse:
- """Companies"""
from .resources.companies import CompaniesResourceWithRawResponse
return CompaniesResourceWithRawResponse(self._client.companies)
@cached_property
def webhooks(self) -> webhooks.WebhooksResourceWithRawResponse:
- """Webhooks"""
from .resources.webhooks import WebhooksResourceWithRawResponse
return WebhooksResourceWithRawResponse(self._client.webhooks)
@cached_property
def plans(self) -> plans.PlansResourceWithRawResponse:
- """Plans"""
+ """A Plan defines how customers buy a product.
+
+ It controls pricing, billing cadence, availability, tax behavior, checkout fields, and purchase visibility.
+
+ Use the Plans API to create plans for products, list existing plans, retrieve or update plan configuration, calculate tax for checkout, and delete plans that should no longer be offered.
+ """
from .resources.plans import PlansResourceWithRawResponse
return PlansResourceWithRawResponse(self._client.plans)
@cached_property
def entries(self) -> entries.EntriesResourceWithRawResponse:
- """Entries"""
from .resources.entries import EntriesResourceWithRawResponse
return EntriesResourceWithRawResponse(self._client.entries)
@cached_property
def forum_posts(self) -> forum_posts.ForumPostsResourceWithRawResponse:
- """Forum posts"""
from .resources.forum_posts import ForumPostsResourceWithRawResponse
return ForumPostsResourceWithRawResponse(self._client.forum_posts)
@cached_property
def transfers(self) -> transfers.TransfersResourceWithRawResponse:
- """Transfers"""
+ """Transfers move value between identities on Whop.
+
+ They are used for account-to-account money movement, user payouts inside Whop, crypto transfers, and claim links depending on the destination type.
+
+ Use the Transfers API to create a transfer, list previous transfers, and retrieve a transfer by ID when reconciling money movement between accounts or users.
+ """
from .resources.transfers import TransfersResourceWithRawResponse
return TransfersResourceWithRawResponse(self._client.transfers)
@cached_property
def ledger_accounts(self) -> ledger_accounts.LedgerAccountsResourceWithRawResponse:
- """Ledger accounts"""
from .resources.ledger_accounts import LedgerAccountsResourceWithRawResponse
return LedgerAccountsResourceWithRawResponse(self._client.ledger_accounts)
@cached_property
def memberships(self) -> memberships.MembershipsResourceWithRawResponse:
- """Memberships"""
from .resources.memberships import MembershipsResourceWithRawResponse
return MembershipsResourceWithRawResponse(self._client.memberships)
@cached_property
def authorized_users(self) -> authorized_users.AuthorizedUsersResourceWithRawResponse:
- """Authorized users"""
from .resources.authorized_users import AuthorizedUsersResourceWithRawResponse
return AuthorizedUsersResourceWithRawResponse(self._client.authorized_users)
@cached_property
def app_builds(self) -> app_builds.AppBuildsResourceWithRawResponse:
- """App builds"""
from .resources.app_builds import AppBuildsResourceWithRawResponse
return AppBuildsResourceWithRawResponse(self._client.app_builds)
@cached_property
def shipments(self) -> shipments.ShipmentsResourceWithRawResponse:
- """Shipments"""
from .resources.shipments import ShipmentsResourceWithRawResponse
return ShipmentsResourceWithRawResponse(self._client.shipments)
@cached_property
def checkout_configurations(self) -> checkout_configurations.CheckoutConfigurationsResourceWithRawResponse:
- """Checkout configurations"""
+ """A Checkout Configuration is a reusable checkout link owned by an account.
+
+ In `payment` mode it sells a specific plan; in `setup` mode it collects and saves payment details without charging. Each configuration can also override which payment methods are accepted and how 3D Secure is enforced for that checkout.
+
+ Use the Checkout Configurations API to create checkout links for an existing or inline plan, list configurations for an account, retrieve the configuration behind a checkout URL, and delete links that should no longer be used.
+ """
from .resources.checkout_configurations import CheckoutConfigurationsResourceWithRawResponse
return CheckoutConfigurationsResourceWithRawResponse(self._client.checkout_configurations)
@cached_property
def messages(self) -> messages.MessagesResourceWithRawResponse:
- """Messages"""
from .resources.messages import MessagesResourceWithRawResponse
return MessagesResourceWithRawResponse(self._client.messages)
@cached_property
def chat_channels(self) -> chat_channels.ChatChannelsResourceWithRawResponse:
- """Chat channels"""
from .resources.chat_channels import ChatChannelsResourceWithRawResponse
return ChatChannelsResourceWithRawResponse(self._client.chat_channels)
@cached_property
def users(self) -> users.UsersResourceWithRawResponse:
- """Users"""
+ """A User represents a person on Whop.
+
+ Users have a public profile and can buy products, join accounts, and access experiences.
+
+ Use the Users API to search for users, retrieve or update profiles, and check whether a user has access to an account, product, or experience.
+ """
from .resources.users import UsersResourceWithRawResponse
return UsersResourceWithRawResponse(self._client.users)
@cached_property
def payments(self) -> payments.PaymentsResourceWithRawResponse:
- """Payments"""
from .resources.payments import PaymentsResourceWithRawResponse
return PaymentsResourceWithRawResponse(self._client.payments)
@cached_property
def support_channels(self) -> support_channels.SupportChannelsResourceWithRawResponse:
- """Support channels"""
from .resources.support_channels import SupportChannelsResourceWithRawResponse
return SupportChannelsResourceWithRawResponse(self._client.support_channels)
@cached_property
def experiences(self) -> experiences.ExperiencesResourceWithRawResponse:
- """Experiences"""
from .resources.experiences import ExperiencesResourceWithRawResponse
return ExperiencesResourceWithRawResponse(self._client.experiences)
@cached_property
def reactions(self) -> reactions.ReactionsResourceWithRawResponse:
- """Reactions"""
from .resources.reactions import ReactionsResourceWithRawResponse
return ReactionsResourceWithRawResponse(self._client.reactions)
@cached_property
def members(self) -> members.MembersResourceWithRawResponse:
- """Members"""
from .resources.members import MembersResourceWithRawResponse
return MembersResourceWithRawResponse(self._client.members)
@cached_property
def forums(self) -> forums.ForumsResourceWithRawResponse:
- """Forums"""
from .resources.forums import ForumsResourceWithRawResponse
return ForumsResourceWithRawResponse(self._client.forums)
@cached_property
def promo_codes(self) -> promo_codes.PromoCodesResourceWithRawResponse:
- """Promo codes"""
from .resources.promo_codes import PromoCodesResourceWithRawResponse
return PromoCodesResourceWithRawResponse(self._client.promo_codes)
@cached_property
def courses(self) -> courses.CoursesResourceWithRawResponse:
- """Courses"""
from .resources.courses import CoursesResourceWithRawResponse
return CoursesResourceWithRawResponse(self._client.courses)
@cached_property
def course_chapters(self) -> course_chapters.CourseChaptersResourceWithRawResponse:
- """Course chapters"""
from .resources.course_chapters import CourseChaptersResourceWithRawResponse
return CourseChaptersResourceWithRawResponse(self._client.course_chapters)
@cached_property
def course_lessons(self) -> course_lessons.CourseLessonsResourceWithRawResponse:
- """Course lessons"""
from .resources.course_lessons import CourseLessonsResourceWithRawResponse
return CourseLessonsResourceWithRawResponse(self._client.course_lessons)
@cached_property
def reviews(self) -> reviews.ReviewsResourceWithRawResponse:
- """Reviews"""
from .resources.reviews import ReviewsResourceWithRawResponse
return ReviewsResourceWithRawResponse(self._client.reviews)
@cached_property
def course_students(self) -> course_students.CourseStudentsResourceWithRawResponse:
- """Course students"""
from .resources.course_students import CourseStudentsResourceWithRawResponse
return CourseStudentsResourceWithRawResponse(self._client.course_students)
@cached_property
def access_tokens(self) -> access_tokens.AccessTokensResourceWithRawResponse:
- """Access tokens"""
from .resources.access_tokens import AccessTokensResourceWithRawResponse
return AccessTokensResourceWithRawResponse(self._client.access_tokens)
@cached_property
def notifications(self) -> notifications.NotificationsResourceWithRawResponse:
- """Notifications"""
from .resources.notifications import NotificationsResourceWithRawResponse
return NotificationsResourceWithRawResponse(self._client.notifications)
@cached_property
def disputes(self) -> disputes.DisputesResourceWithRawResponse:
- """Disputes"""
from .resources.disputes import DisputesResourceWithRawResponse
return DisputesResourceWithRawResponse(self._client.disputes)
@cached_property
def refunds(self) -> refunds.RefundsResourceWithRawResponse:
- """Refunds"""
from .resources.refunds import RefundsResourceWithRawResponse
return RefundsResourceWithRawResponse(self._client.refunds)
@cached_property
def withdrawals(self) -> withdrawals.WithdrawalsResourceWithRawResponse:
- """Withdrawals"""
from .resources.withdrawals import WithdrawalsResourceWithRawResponse
return WithdrawalsResourceWithRawResponse(self._client.withdrawals)
@cached_property
def account_links(self) -> account_links.AccountLinksResourceWithRawResponse:
- """Account links"""
from .resources.account_links import AccountLinksResourceWithRawResponse
return AccountLinksResourceWithRawResponse(self._client.account_links)
@cached_property
def accounts(self) -> accounts.AccountsResourceWithRawResponse:
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
from .resources.accounts import 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:
+ """
+ A Ledger Activity row is a single financial event on an account's ledger — a payment, withdrawal, refund, transfer, on-chain deposit, swap, or card transaction. Each row is derived from the underlying ledger lines and carries a typed `resource` and `source` so you can present and link the event without extra lookups.
+
+ Use Ledger Activity to build a statement or transaction feed for an account or user. Reconcile against your own records with `amount` (signed, in the currency's smallest precision units) and `posted_at`, and use `available_at` to know when inflows became withdrawable.
+ """
+ from .resources.financial_activity import FinancialActivityResourceWithRawResponse
+
+ return FinancialActivityResourceWithRawResponse(self._client.financial_activity)
+
+ @cached_property
+ def stats(self) -> stats.StatsResourceWithRawResponse:
+ """Stats represent aggregated activity for an account over time.
+
+ They help you understand revenue, transactions, disputes, members, referrals, and advertising performance across reporting periods like days, weeks, or months.
+
+ Use the Stats API to list available metrics and their filterable properties, then retrieve time-series values for a date range.
+ """
+ from .resources.stats import StatsResourceWithRawResponse
+
+ return StatsResourceWithRawResponse(self._client.stats)
+
+ @cached_property
+ def payouts(self) -> payouts.PayoutsResourceWithRawResponse:
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+ from .resources.payouts import PayoutsResourceWithRawResponse
+
+ return PayoutsResourceWithRawResponse(self._client.payouts)
+
+ @cached_property
+ def referrals(self) -> referrals.ReferralsResourceWithRawResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ from .resources.referrals import ReferralsResourceWithRawResponse
+
+ return ReferralsResourceWithRawResponse(self._client.referrals)
+
+ @cached_property
+ def cards(self) -> cards.CardsResourceWithRawResponse:
+ """
+ Cards represent Whop-issued virtual payment cards that spend from an account or user balance. Cards can be assigned to cardholders and configured with spending limits for controlled spending.
+
+ Use the Cards API to issue cards, list cards for an account or user, and retrieve active card details such as the card number and CVC.
+ """
+ from .resources.cards import CardsResourceWithRawResponse
- return WalletsResourceWithRawResponse(self._client.wallets)
+ return CardsResourceWithRawResponse(self._client.cards)
@cached_property
def swaps(self) -> swaps.SwapsResourceWithRawResponse:
+ """
+ Swaps convert value between supported tokens, chains, or wallet destinations for an account. A swap quote describes the expected output, fees, and approval requirements before you create the swap.
+
+ Use the Swaps API to quote a conversion, create the swap, list recent swaps, and retrieve status until the transaction completes.
+ """
from .resources.swaps import SwapsResourceWithRawResponse
return SwapsResourceWithRawResponse(self._client.swaps)
@cached_property
def deposits(self) -> deposits.DepositsResourceWithRawResponse:
+ """
+ Deposits describe ways to add funds to an account balance, including hosted deposit pages, bank deposit instructions, and supported crypto wallet addresses.
+
+ Use the Deposits API to create deposit instructions for an account and retrieve existing bank deposit activity.
+ """
from .resources.deposits import DepositsResourceWithRawResponse
return DepositsResourceWithRawResponse(self._client.deposits)
@cached_property
def setup_intents(self) -> setup_intents.SetupIntentsResourceWithRawResponse:
- """Setup intents"""
from .resources.setup_intents import SetupIntentsResourceWithRawResponse
return SetupIntentsResourceWithRawResponse(self._client.setup_intents)
@cached_property
def payment_methods(self) -> payment_methods.PaymentMethodsResourceWithRawResponse:
- """Payment methods"""
from .resources.payment_methods import PaymentMethodsResourceWithRawResponse
return PaymentMethodsResourceWithRawResponse(self._client.payment_methods)
@cached_property
def fee_markups(self) -> fee_markups.FeeMarkupsResourceWithRawResponse:
- """Fee markups"""
from .resources.fee_markups import FeeMarkupsResourceWithRawResponse
return FeeMarkupsResourceWithRawResponse(self._client.fee_markups)
@cached_property
- def payout_methods(self) -> payout_methods.PayoutMethodsResourceWithRawResponse:
- """Payout methods"""
- from .resources.payout_methods import PayoutMethodsResourceWithRawResponse
+ def verifications(self) -> verifications.VerificationsResourceWithRawResponse:
+ """A Verification represents an identity review for a person or business.
- return PayoutMethodsResourceWithRawResponse(self._client.payout_methods)
+ Accounts and users complete verification when Whop needs to confirm who they are before enabling payouts or compliance-sensitive workflows.
- @cached_property
- def verifications(self) -> verifications.VerificationsResourceWithRawResponse:
- """Verifications"""
+ Use the Verifications API to start or resume a hosted verification session, check review status, and submit requested details or documents. If `requested_information` contains items, submit answers with [Update Verification](/api-reference/beta/verifications/update-verification).
+ """
from .resources.verifications import VerificationsResourceWithRawResponse
return VerificationsResourceWithRawResponse(self._client.verifications)
@cached_property
def leads(self) -> leads.LeadsResourceWithRawResponse:
- """Leads"""
from .resources.leads import LeadsResourceWithRawResponse
return LeadsResourceWithRawResponse(self._client.leads)
@cached_property
def topups(self) -> topups.TopupsResourceWithRawResponse:
- """Topups"""
from .resources.topups import TopupsResourceWithRawResponse
return TopupsResourceWithRawResponse(self._client.topups)
@cached_property
def files(self) -> files.FilesResourceWithRawResponse:
- """Files"""
from .resources.files import FilesResourceWithRawResponse
return FilesResourceWithRawResponse(self._client.files)
@cached_property
def company_token_transactions(self) -> company_token_transactions.CompanyTokenTransactionsResourceWithRawResponse:
- """Company token transactions"""
from .resources.company_token_transactions import CompanyTokenTransactionsResourceWithRawResponse
return CompanyTokenTransactionsResourceWithRawResponse(self._client.company_token_transactions)
@cached_property
def dm_members(self) -> dm_members.DmMembersResourceWithRawResponse:
- """Dm members"""
from .resources.dm_members import DmMembersResourceWithRawResponse
return DmMembersResourceWithRawResponse(self._client.dm_members)
@cached_property
def ai_chats(self) -> ai_chats.AIChatsResourceWithRawResponse:
- """Ai chats"""
from .resources.ai_chats import AIChatsResourceWithRawResponse
return AIChatsResourceWithRawResponse(self._client.ai_chats)
@cached_property
def dm_channels(self) -> dm_channels.DmChannelsResourceWithRawResponse:
- """Dm channels"""
from .resources.dm_channels import DmChannelsResourceWithRawResponse
return DmChannelsResourceWithRawResponse(self._client.dm_channels)
@cached_property
def dispute_alerts(self) -> dispute_alerts.DisputeAlertsResourceWithRawResponse:
- """Dispute alerts"""
from .resources.dispute_alerts import DisputeAlertsResourceWithRawResponse
return DisputeAlertsResourceWithRawResponse(self._client.dispute_alerts)
@cached_property
def resolution_center_cases(self) -> resolution_center_cases.ResolutionCenterCasesResourceWithRawResponse:
- """Resolution center cases"""
from .resources.resolution_center_cases import ResolutionCenterCasesResourceWithRawResponse
return ResolutionCenterCasesResourceWithRawResponse(self._client.resolution_center_cases)
@cached_property
def payout_accounts(self) -> payout_accounts.PayoutAccountsResourceWithRawResponse:
- """Payout accounts"""
from .resources.payout_accounts import PayoutAccountsResourceWithRawResponse
return PayoutAccountsResourceWithRawResponse(self._client.payout_accounts)
@cached_property
def affiliates(self) -> affiliates.AffiliatesResourceWithRawResponse:
- """Affiliates"""
from .resources.affiliates import AffiliatesResourceWithRawResponse
return AffiliatesResourceWithRawResponse(self._client.affiliates)
@cached_property
def bounties(self) -> bounties.BountiesResourceWithRawResponse:
- """Bounties"""
from .resources.bounties import BountiesResourceWithRawResponse
return BountiesResourceWithRawResponse(self._client.bounties)
+ @cached_property
+ def workforce(self) -> workforce.WorkforceResourceWithRawResponse:
+ from .resources.workforce import WorkforceResourceWithRawResponse
+
+ return WorkforceResourceWithRawResponse(self._client.workforce)
+
@cached_property
def ad_campaigns(self) -> ad_campaigns.AdCampaignsResourceWithRawResponse:
- """Ad campaigns"""
+ """An Ad Campaign is the top-level container for paid ads on an ad network.
+
+ It sets the platform, objective, and budget strategy shared by its [ad groups](/api-reference/beta/ad-groups/ad-group) and ads.
+
+ Use the Ad Campaigns API to create campaigns, list campaigns for an account, retrieve or update campaign settings, and pause or resume campaign delivery.
+ """
from .resources.ad_campaigns import AdCampaignsResourceWithRawResponse
return AdCampaignsResourceWithRawResponse(self._client.ad_campaigns)
@cached_property
def ad_groups(self) -> ad_groups.AdGroupsResourceWithRawResponse:
- """Ad groups"""
+ """
+ An Ad Group sits inside an [ad campaign](/api-reference/beta/ad-campaigns/ad-campaign) and controls delivery for [ads](/api-reference/beta/ads/ad). It sets the audience, placements, schedule, budget, and optimization goal for its ads.
+
+ Use the Ad Groups API to create ad groups in campaigns, list or retrieve targeting and delivery settings, update budgets or targeting, delete groups that should stop running, and pause or resume delivery.
+ """
from .resources.ad_groups import AdGroupsResourceWithRawResponse
return AdGroupsResourceWithRawResponse(self._client.ad_groups)
@cached_property
def ads(self) -> ads.AdsResourceWithRawResponse:
- """Ads"""
+ """
+ An Ad is the individual creative unit delivered by an [ad group](/api-reference/beta/ad-groups/ad-group). It holds the copy, creative assets, and destination URL for one ad.
+
+ Use the Ads API to list ads for an account, create ads inside ad groups, retrieve or update creative details, delete ads that should stop running, and pause or resume delivery.
+ """
from .resources.ads import AdsResourceWithRawResponse
return AdsResourceWithRawResponse(self._client.ads)
- @cached_property
- def conversions(self) -> conversions.ConversionsResourceWithRawResponse:
- """Conversions"""
- from .resources.conversions import ConversionsResourceWithRawResponse
-
- return ConversionsResourceWithRawResponse(self._client.conversions)
-
@cached_property
def ad_reports(self) -> ad_reports.AdReportsResourceWithRawResponse:
- """Ad reports"""
from .resources.ad_reports import AdReportsResourceWithRawResponse
return AdReportsResourceWithRawResponse(self._client.ad_reports)
@@ -1893,14 +2271,18 @@ def __init__(self, client: AsyncWhop) -> None:
@cached_property
def apps(self) -> apps.AsyncAppsResourceWithRawResponse:
- """Apps"""
+ """An App is software you build on Whop.
+
+ It can be a hosted web app served at `.whop.app` or an API integration installed as an experience, and it belongs to the account that owns its credentials, settings, builds, and runtime logs.
+
+ Use the Apps API to manage app configuration and, for hosted apps, read server runtime logs for console output, uncaught exceptions, and failed requests. Logs are retained for 7 days and can be filtered by build, level, time window, and message text.
+ """
from .resources.apps import AsyncAppsResourceWithRawResponse
return AsyncAppsResourceWithRawResponse(self._client.apps)
@cached_property
def invoices(self) -> invoices.AsyncInvoicesResourceWithRawResponse:
- """Invoices"""
from .resources.invoices import AsyncInvoicesResourceWithRawResponse
return AsyncInvoicesResourceWithRawResponse(self._client.invoices)
@@ -1909,325 +2291,433 @@ def invoices(self) -> invoices.AsyncInvoicesResourceWithRawResponse:
def course_lesson_interactions(
self,
) -> course_lesson_interactions.AsyncCourseLessonInteractionsResourceWithRawResponse:
- """Course lesson interactions"""
from .resources.course_lesson_interactions import AsyncCourseLessonInteractionsResourceWithRawResponse
return AsyncCourseLessonInteractionsResourceWithRawResponse(self._client.course_lesson_interactions)
@cached_property
def products(self) -> products.AsyncProductsResourceWithRawResponse:
- """Products"""
+ """A Product is a digital good or service sold on Whop.
+
+ Products may contain plans for pricing and/or experiences for content delivery.
+
+ Use the Products API to create products, list products visible to your credentials, retrieve product details, update product metadata or merchandising fields, and delete products that should no longer be sold.
+ """
from .resources.products import AsyncProductsResourceWithRawResponse
return AsyncProductsResourceWithRawResponse(self._client.products)
+ @cached_property
+ def social_accounts(self) -> social_accounts.AsyncSocialAccountsResourceWithRawResponse:
+ """
+ A Social Account represents an external profile connected to a Whop account or user, such as a Facebook page or Instagram account. Connecting a social account lets Whop run [ads](/api-reference/beta/ads/ad) under that profile's identity and promote its existing posts.
+
+ Use the Social Accounts API to list connected accounts, create a Whop-managed Facebook page, start an OAuth connection, disconnect a social account, and list a connected profile's posts.
+ """
+ from .resources.social_accounts import AsyncSocialAccountsResourceWithRawResponse
+
+ return AsyncSocialAccountsResourceWithRawResponse(self._client.social_accounts)
+
+ @cached_property
+ def audiences(self) -> audiences.AsyncAudiencesResourceWithRawResponse:
+ """An Audience represents a customer list uploaded to Whop for ad targeting.
+
+ Audiences belong to an account and sync to supported ad platforms as custom audiences.
+
+ Use the Audiences API to create audiences from CSV uploads, monitor processing status, and list or delete audiences for an account. Created audiences are usable for targeting after processing reaches `ready` or `partial`.
+ """
+ from .resources.audiences import AsyncAudiencesResourceWithRawResponse
+
+ return AsyncAudiencesResourceWithRawResponse(self._client.audiences)
+
+ @cached_property
+ def media(self) -> media.AsyncMediaResourceWithRawResponse:
+ """
+ A Media Asset is an AI-generated image or video created from a prompt and billed from an account balance. When generation finishes, the asset includes a file that can be attached anywhere Whop accepts files.
+
+ Use the Media API to start a generation job and retrieve the asset while it processes or after it is ready.
+ """
+ from .resources.media import AsyncMediaResourceWithRawResponse
+
+ return AsyncMediaResourceWithRawResponse(self._client.media)
+
+ @cached_property
+ def people(self) -> people.AsyncPeopleResourceWithRawResponse:
+ """
+ A Person represents a visitor or customer of an account, assembled from [pixel events](/api-reference/beta/events/event) and purchase activity — ad clicks, storefront visits, and checkouts.
+
+ Use the People API to list the people of an account and retrieve a single person.
+ """
+ from .resources.people import AsyncPeopleResourceWithRawResponse
+
+ return AsyncPeopleResourceWithRawResponse(self._client.people)
+
+ @cached_property
+ def events(self) -> events.AsyncEventsResourceWithRawResponse:
+ """
+ An Event records conversion or engagement activity for an account, such as page views, purchases, or leads. Each event ties the action to the [person](/api-reference/beta/people/person) who took it, so activity can be attributed to the ads and links that drove it.
+
+ Use the Events API to send new tracking events and list the events recorded for a person.
+ """
+ from .resources.events import AsyncEventsResourceWithRawResponse
+
+ return AsyncEventsResourceWithRawResponse(self._client.events)
+
@cached_property
def companies(self) -> companies.AsyncCompaniesResourceWithRawResponse:
- """Companies"""
from .resources.companies import AsyncCompaniesResourceWithRawResponse
return AsyncCompaniesResourceWithRawResponse(self._client.companies)
@cached_property
def webhooks(self) -> webhooks.AsyncWebhooksResourceWithRawResponse:
- """Webhooks"""
from .resources.webhooks import AsyncWebhooksResourceWithRawResponse
return AsyncWebhooksResourceWithRawResponse(self._client.webhooks)
@cached_property
def plans(self) -> plans.AsyncPlansResourceWithRawResponse:
- """Plans"""
+ """A Plan defines how customers buy a product.
+
+ It controls pricing, billing cadence, availability, tax behavior, checkout fields, and purchase visibility.
+
+ Use the Plans API to create plans for products, list existing plans, retrieve or update plan configuration, calculate tax for checkout, and delete plans that should no longer be offered.
+ """
from .resources.plans import AsyncPlansResourceWithRawResponse
return AsyncPlansResourceWithRawResponse(self._client.plans)
@cached_property
def entries(self) -> entries.AsyncEntriesResourceWithRawResponse:
- """Entries"""
from .resources.entries import AsyncEntriesResourceWithRawResponse
return AsyncEntriesResourceWithRawResponse(self._client.entries)
@cached_property
def forum_posts(self) -> forum_posts.AsyncForumPostsResourceWithRawResponse:
- """Forum posts"""
from .resources.forum_posts import AsyncForumPostsResourceWithRawResponse
return AsyncForumPostsResourceWithRawResponse(self._client.forum_posts)
@cached_property
def transfers(self) -> transfers.AsyncTransfersResourceWithRawResponse:
- """Transfers"""
+ """Transfers move value between identities on Whop.
+
+ They are used for account-to-account money movement, user payouts inside Whop, crypto transfers, and claim links depending on the destination type.
+
+ Use the Transfers API to create a transfer, list previous transfers, and retrieve a transfer by ID when reconciling money movement between accounts or users.
+ """
from .resources.transfers import AsyncTransfersResourceWithRawResponse
return AsyncTransfersResourceWithRawResponse(self._client.transfers)
@cached_property
def ledger_accounts(self) -> ledger_accounts.AsyncLedgerAccountsResourceWithRawResponse:
- """Ledger accounts"""
from .resources.ledger_accounts import AsyncLedgerAccountsResourceWithRawResponse
return AsyncLedgerAccountsResourceWithRawResponse(self._client.ledger_accounts)
@cached_property
def memberships(self) -> memberships.AsyncMembershipsResourceWithRawResponse:
- """Memberships"""
from .resources.memberships import AsyncMembershipsResourceWithRawResponse
return AsyncMembershipsResourceWithRawResponse(self._client.memberships)
@cached_property
def authorized_users(self) -> authorized_users.AsyncAuthorizedUsersResourceWithRawResponse:
- """Authorized users"""
from .resources.authorized_users import AsyncAuthorizedUsersResourceWithRawResponse
return AsyncAuthorizedUsersResourceWithRawResponse(self._client.authorized_users)
@cached_property
def app_builds(self) -> app_builds.AsyncAppBuildsResourceWithRawResponse:
- """App builds"""
from .resources.app_builds import AsyncAppBuildsResourceWithRawResponse
return AsyncAppBuildsResourceWithRawResponse(self._client.app_builds)
@cached_property
def shipments(self) -> shipments.AsyncShipmentsResourceWithRawResponse:
- """Shipments"""
from .resources.shipments import AsyncShipmentsResourceWithRawResponse
return AsyncShipmentsResourceWithRawResponse(self._client.shipments)
@cached_property
def checkout_configurations(self) -> checkout_configurations.AsyncCheckoutConfigurationsResourceWithRawResponse:
- """Checkout configurations"""
+ """A Checkout Configuration is a reusable checkout link owned by an account.
+
+ In `payment` mode it sells a specific plan; in `setup` mode it collects and saves payment details without charging. Each configuration can also override which payment methods are accepted and how 3D Secure is enforced for that checkout.
+
+ Use the Checkout Configurations API to create checkout links for an existing or inline plan, list configurations for an account, retrieve the configuration behind a checkout URL, and delete links that should no longer be used.
+ """
from .resources.checkout_configurations import AsyncCheckoutConfigurationsResourceWithRawResponse
return AsyncCheckoutConfigurationsResourceWithRawResponse(self._client.checkout_configurations)
@cached_property
def messages(self) -> messages.AsyncMessagesResourceWithRawResponse:
- """Messages"""
from .resources.messages import AsyncMessagesResourceWithRawResponse
return AsyncMessagesResourceWithRawResponse(self._client.messages)
@cached_property
def chat_channels(self) -> chat_channels.AsyncChatChannelsResourceWithRawResponse:
- """Chat channels"""
from .resources.chat_channels import AsyncChatChannelsResourceWithRawResponse
return AsyncChatChannelsResourceWithRawResponse(self._client.chat_channels)
@cached_property
def users(self) -> users.AsyncUsersResourceWithRawResponse:
- """Users"""
+ """A User represents a person on Whop.
+
+ Users have a public profile and can buy products, join accounts, and access experiences.
+
+ Use the Users API to search for users, retrieve or update profiles, and check whether a user has access to an account, product, or experience.
+ """
from .resources.users import AsyncUsersResourceWithRawResponse
return AsyncUsersResourceWithRawResponse(self._client.users)
@cached_property
def payments(self) -> payments.AsyncPaymentsResourceWithRawResponse:
- """Payments"""
from .resources.payments import AsyncPaymentsResourceWithRawResponse
return AsyncPaymentsResourceWithRawResponse(self._client.payments)
@cached_property
def support_channels(self) -> support_channels.AsyncSupportChannelsResourceWithRawResponse:
- """Support channels"""
from .resources.support_channels import AsyncSupportChannelsResourceWithRawResponse
return AsyncSupportChannelsResourceWithRawResponse(self._client.support_channels)
@cached_property
def experiences(self) -> experiences.AsyncExperiencesResourceWithRawResponse:
- """Experiences"""
from .resources.experiences import AsyncExperiencesResourceWithRawResponse
return AsyncExperiencesResourceWithRawResponse(self._client.experiences)
@cached_property
def reactions(self) -> reactions.AsyncReactionsResourceWithRawResponse:
- """Reactions"""
from .resources.reactions import AsyncReactionsResourceWithRawResponse
return AsyncReactionsResourceWithRawResponse(self._client.reactions)
@cached_property
def members(self) -> members.AsyncMembersResourceWithRawResponse:
- """Members"""
from .resources.members import AsyncMembersResourceWithRawResponse
return AsyncMembersResourceWithRawResponse(self._client.members)
@cached_property
def forums(self) -> forums.AsyncForumsResourceWithRawResponse:
- """Forums"""
from .resources.forums import AsyncForumsResourceWithRawResponse
return AsyncForumsResourceWithRawResponse(self._client.forums)
@cached_property
def promo_codes(self) -> promo_codes.AsyncPromoCodesResourceWithRawResponse:
- """Promo codes"""
from .resources.promo_codes import AsyncPromoCodesResourceWithRawResponse
return AsyncPromoCodesResourceWithRawResponse(self._client.promo_codes)
@cached_property
def courses(self) -> courses.AsyncCoursesResourceWithRawResponse:
- """Courses"""
from .resources.courses import AsyncCoursesResourceWithRawResponse
return AsyncCoursesResourceWithRawResponse(self._client.courses)
@cached_property
def course_chapters(self) -> course_chapters.AsyncCourseChaptersResourceWithRawResponse:
- """Course chapters"""
from .resources.course_chapters import AsyncCourseChaptersResourceWithRawResponse
return AsyncCourseChaptersResourceWithRawResponse(self._client.course_chapters)
@cached_property
def course_lessons(self) -> course_lessons.AsyncCourseLessonsResourceWithRawResponse:
- """Course lessons"""
from .resources.course_lessons import AsyncCourseLessonsResourceWithRawResponse
return AsyncCourseLessonsResourceWithRawResponse(self._client.course_lessons)
@cached_property
def reviews(self) -> reviews.AsyncReviewsResourceWithRawResponse:
- """Reviews"""
from .resources.reviews import AsyncReviewsResourceWithRawResponse
return AsyncReviewsResourceWithRawResponse(self._client.reviews)
@cached_property
def course_students(self) -> course_students.AsyncCourseStudentsResourceWithRawResponse:
- """Course students"""
from .resources.course_students import AsyncCourseStudentsResourceWithRawResponse
return AsyncCourseStudentsResourceWithRawResponse(self._client.course_students)
@cached_property
def access_tokens(self) -> access_tokens.AsyncAccessTokensResourceWithRawResponse:
- """Access tokens"""
from .resources.access_tokens import AsyncAccessTokensResourceWithRawResponse
return AsyncAccessTokensResourceWithRawResponse(self._client.access_tokens)
@cached_property
def notifications(self) -> notifications.AsyncNotificationsResourceWithRawResponse:
- """Notifications"""
from .resources.notifications import AsyncNotificationsResourceWithRawResponse
return AsyncNotificationsResourceWithRawResponse(self._client.notifications)
@cached_property
def disputes(self) -> disputes.AsyncDisputesResourceWithRawResponse:
- """Disputes"""
from .resources.disputes import AsyncDisputesResourceWithRawResponse
return AsyncDisputesResourceWithRawResponse(self._client.disputes)
@cached_property
def refunds(self) -> refunds.AsyncRefundsResourceWithRawResponse:
- """Refunds"""
from .resources.refunds import AsyncRefundsResourceWithRawResponse
return AsyncRefundsResourceWithRawResponse(self._client.refunds)
@cached_property
def withdrawals(self) -> withdrawals.AsyncWithdrawalsResourceWithRawResponse:
- """Withdrawals"""
from .resources.withdrawals import AsyncWithdrawalsResourceWithRawResponse
return AsyncWithdrawalsResourceWithRawResponse(self._client.withdrawals)
@cached_property
def account_links(self) -> account_links.AsyncAccountLinksResourceWithRawResponse:
- """Account links"""
from .resources.account_links import AsyncAccountLinksResourceWithRawResponse
return AsyncAccountLinksResourceWithRawResponse(self._client.account_links)
@cached_property
def accounts(self) -> accounts.AsyncAccountsResourceWithRawResponse:
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
from .resources.accounts import 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:
+ """
+ A Ledger Activity row is a single financial event on an account's ledger — a payment, withdrawal, refund, transfer, on-chain deposit, swap, or card transaction. Each row is derived from the underlying ledger lines and carries a typed `resource` and `source` so you can present and link the event without extra lookups.
+
+ Use Ledger Activity to build a statement or transaction feed for an account or user. Reconcile against your own records with `amount` (signed, in the currency's smallest precision units) and `posted_at`, and use `available_at` to know when inflows became withdrawable.
+ """
+ from .resources.financial_activity import AsyncFinancialActivityResourceWithRawResponse
+
+ return AsyncFinancialActivityResourceWithRawResponse(self._client.financial_activity)
+
+ @cached_property
+ def stats(self) -> stats.AsyncStatsResourceWithRawResponse:
+ """Stats represent aggregated activity for an account over time.
+
+ They help you understand revenue, transactions, disputes, members, referrals, and advertising performance across reporting periods like days, weeks, or months.
+
+ Use the Stats API to list available metrics and their filterable properties, then retrieve time-series values for a date range.
+ """
+ from .resources.stats import AsyncStatsResourceWithRawResponse
+
+ return AsyncStatsResourceWithRawResponse(self._client.stats)
+
+ @cached_property
+ def payouts(self) -> payouts.AsyncPayoutsResourceWithRawResponse:
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+ from .resources.payouts import AsyncPayoutsResourceWithRawResponse
- return AsyncWalletsResourceWithRawResponse(self._client.wallets)
+ return AsyncPayoutsResourceWithRawResponse(self._client.payouts)
+
+ @cached_property
+ def referrals(self) -> referrals.AsyncReferralsResourceWithRawResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ from .resources.referrals import AsyncReferralsResourceWithRawResponse
+
+ return AsyncReferralsResourceWithRawResponse(self._client.referrals)
+
+ @cached_property
+ def cards(self) -> cards.AsyncCardsResourceWithRawResponse:
+ """
+ Cards represent Whop-issued virtual payment cards that spend from an account or user balance. Cards can be assigned to cardholders and configured with spending limits for controlled spending.
+
+ Use the Cards API to issue cards, list cards for an account or user, and retrieve active card details such as the card number and CVC.
+ """
+ from .resources.cards import AsyncCardsResourceWithRawResponse
+
+ return AsyncCardsResourceWithRawResponse(self._client.cards)
@cached_property
def swaps(self) -> swaps.AsyncSwapsResourceWithRawResponse:
+ """
+ Swaps convert value between supported tokens, chains, or wallet destinations for an account. A swap quote describes the expected output, fees, and approval requirements before you create the swap.
+
+ Use the Swaps API to quote a conversion, create the swap, list recent swaps, and retrieve status until the transaction completes.
+ """
from .resources.swaps import AsyncSwapsResourceWithRawResponse
return AsyncSwapsResourceWithRawResponse(self._client.swaps)
@cached_property
def deposits(self) -> deposits.AsyncDepositsResourceWithRawResponse:
+ """
+ Deposits describe ways to add funds to an account balance, including hosted deposit pages, bank deposit instructions, and supported crypto wallet addresses.
+
+ Use the Deposits API to create deposit instructions for an account and retrieve existing bank deposit activity.
+ """
from .resources.deposits import AsyncDepositsResourceWithRawResponse
return AsyncDepositsResourceWithRawResponse(self._client.deposits)
@cached_property
def setup_intents(self) -> setup_intents.AsyncSetupIntentsResourceWithRawResponse:
- """Setup intents"""
from .resources.setup_intents import AsyncSetupIntentsResourceWithRawResponse
return AsyncSetupIntentsResourceWithRawResponse(self._client.setup_intents)
@cached_property
def payment_methods(self) -> payment_methods.AsyncPaymentMethodsResourceWithRawResponse:
- """Payment methods"""
from .resources.payment_methods import AsyncPaymentMethodsResourceWithRawResponse
return AsyncPaymentMethodsResourceWithRawResponse(self._client.payment_methods)
@cached_property
def fee_markups(self) -> fee_markups.AsyncFeeMarkupsResourceWithRawResponse:
- """Fee markups"""
from .resources.fee_markups import AsyncFeeMarkupsResourceWithRawResponse
return AsyncFeeMarkupsResourceWithRawResponse(self._client.fee_markups)
@cached_property
- def payout_methods(self) -> payout_methods.AsyncPayoutMethodsResourceWithRawResponse:
- """Payout methods"""
- from .resources.payout_methods import AsyncPayoutMethodsResourceWithRawResponse
+ def verifications(self) -> verifications.AsyncVerificationsResourceWithRawResponse:
+ """A Verification represents an identity review for a person or business.
- return AsyncPayoutMethodsResourceWithRawResponse(self._client.payout_methods)
+ Accounts and users complete verification when Whop needs to confirm who they are before enabling payouts or compliance-sensitive workflows.
- @cached_property
- def verifications(self) -> verifications.AsyncVerificationsResourceWithRawResponse:
- """Verifications"""
+ Use the Verifications API to start or resume a hosted verification session, check review status, and submit requested details or documents. If `requested_information` contains items, submit answers with [Update Verification](/api-reference/beta/verifications/update-verification).
+ """
from .resources.verifications import AsyncVerificationsResourceWithRawResponse
return AsyncVerificationsResourceWithRawResponse(self._client.verifications)
@cached_property
def leads(self) -> leads.AsyncLeadsResourceWithRawResponse:
- """Leads"""
from .resources.leads import AsyncLeadsResourceWithRawResponse
return AsyncLeadsResourceWithRawResponse(self._client.leads)
@cached_property
def topups(self) -> topups.AsyncTopupsResourceWithRawResponse:
- """Topups"""
from .resources.topups import AsyncTopupsResourceWithRawResponse
return AsyncTopupsResourceWithRawResponse(self._client.topups)
@cached_property
def files(self) -> files.AsyncFilesResourceWithRawResponse:
- """Files"""
from .resources.files import AsyncFilesResourceWithRawResponse
return AsyncFilesResourceWithRawResponse(self._client.files)
@@ -2236,98 +2726,100 @@ def files(self) -> files.AsyncFilesResourceWithRawResponse:
def company_token_transactions(
self,
) -> company_token_transactions.AsyncCompanyTokenTransactionsResourceWithRawResponse:
- """Company token transactions"""
from .resources.company_token_transactions import AsyncCompanyTokenTransactionsResourceWithRawResponse
return AsyncCompanyTokenTransactionsResourceWithRawResponse(self._client.company_token_transactions)
@cached_property
def dm_members(self) -> dm_members.AsyncDmMembersResourceWithRawResponse:
- """Dm members"""
from .resources.dm_members import AsyncDmMembersResourceWithRawResponse
return AsyncDmMembersResourceWithRawResponse(self._client.dm_members)
@cached_property
def ai_chats(self) -> ai_chats.AsyncAIChatsResourceWithRawResponse:
- """Ai chats"""
from .resources.ai_chats import AsyncAIChatsResourceWithRawResponse
return AsyncAIChatsResourceWithRawResponse(self._client.ai_chats)
@cached_property
def dm_channels(self) -> dm_channels.AsyncDmChannelsResourceWithRawResponse:
- """Dm channels"""
from .resources.dm_channels import AsyncDmChannelsResourceWithRawResponse
return AsyncDmChannelsResourceWithRawResponse(self._client.dm_channels)
@cached_property
def dispute_alerts(self) -> dispute_alerts.AsyncDisputeAlertsResourceWithRawResponse:
- """Dispute alerts"""
from .resources.dispute_alerts import AsyncDisputeAlertsResourceWithRawResponse
return AsyncDisputeAlertsResourceWithRawResponse(self._client.dispute_alerts)
@cached_property
def resolution_center_cases(self) -> resolution_center_cases.AsyncResolutionCenterCasesResourceWithRawResponse:
- """Resolution center cases"""
from .resources.resolution_center_cases import AsyncResolutionCenterCasesResourceWithRawResponse
return AsyncResolutionCenterCasesResourceWithRawResponse(self._client.resolution_center_cases)
@cached_property
def payout_accounts(self) -> payout_accounts.AsyncPayoutAccountsResourceWithRawResponse:
- """Payout accounts"""
from .resources.payout_accounts import AsyncPayoutAccountsResourceWithRawResponse
return AsyncPayoutAccountsResourceWithRawResponse(self._client.payout_accounts)
@cached_property
def affiliates(self) -> affiliates.AsyncAffiliatesResourceWithRawResponse:
- """Affiliates"""
from .resources.affiliates import AsyncAffiliatesResourceWithRawResponse
return AsyncAffiliatesResourceWithRawResponse(self._client.affiliates)
@cached_property
def bounties(self) -> bounties.AsyncBountiesResourceWithRawResponse:
- """Bounties"""
from .resources.bounties import AsyncBountiesResourceWithRawResponse
return AsyncBountiesResourceWithRawResponse(self._client.bounties)
+ @cached_property
+ def workforce(self) -> workforce.AsyncWorkforceResourceWithRawResponse:
+ from .resources.workforce import AsyncWorkforceResourceWithRawResponse
+
+ return AsyncWorkforceResourceWithRawResponse(self._client.workforce)
+
@cached_property
def ad_campaigns(self) -> ad_campaigns.AsyncAdCampaignsResourceWithRawResponse:
- """Ad campaigns"""
+ """An Ad Campaign is the top-level container for paid ads on an ad network.
+
+ It sets the platform, objective, and budget strategy shared by its [ad groups](/api-reference/beta/ad-groups/ad-group) and ads.
+
+ Use the Ad Campaigns API to create campaigns, list campaigns for an account, retrieve or update campaign settings, and pause or resume campaign delivery.
+ """
from .resources.ad_campaigns import AsyncAdCampaignsResourceWithRawResponse
return AsyncAdCampaignsResourceWithRawResponse(self._client.ad_campaigns)
@cached_property
def ad_groups(self) -> ad_groups.AsyncAdGroupsResourceWithRawResponse:
- """Ad groups"""
+ """
+ An Ad Group sits inside an [ad campaign](/api-reference/beta/ad-campaigns/ad-campaign) and controls delivery for [ads](/api-reference/beta/ads/ad). It sets the audience, placements, schedule, budget, and optimization goal for its ads.
+
+ Use the Ad Groups API to create ad groups in campaigns, list or retrieve targeting and delivery settings, update budgets or targeting, delete groups that should stop running, and pause or resume delivery.
+ """
from .resources.ad_groups import AsyncAdGroupsResourceWithRawResponse
return AsyncAdGroupsResourceWithRawResponse(self._client.ad_groups)
@cached_property
def ads(self) -> ads.AsyncAdsResourceWithRawResponse:
- """Ads"""
+ """
+ An Ad is the individual creative unit delivered by an [ad group](/api-reference/beta/ad-groups/ad-group). It holds the copy, creative assets, and destination URL for one ad.
+
+ Use the Ads API to list ads for an account, create ads inside ad groups, retrieve or update creative details, delete ads that should stop running, and pause or resume delivery.
+ """
from .resources.ads import AsyncAdsResourceWithRawResponse
return AsyncAdsResourceWithRawResponse(self._client.ads)
- @cached_property
- def conversions(self) -> conversions.AsyncConversionsResourceWithRawResponse:
- """Conversions"""
- from .resources.conversions import AsyncConversionsResourceWithRawResponse
-
- return AsyncConversionsResourceWithRawResponse(self._client.conversions)
-
@cached_property
def ad_reports(self) -> ad_reports.AsyncAdReportsResourceWithRawResponse:
- """Ad reports"""
from .resources.ad_reports import AsyncAdReportsResourceWithRawResponse
return AsyncAdReportsResourceWithRawResponse(self._client.ad_reports)
@@ -2341,14 +2833,18 @@ def __init__(self, client: Whop) -> None:
@cached_property
def apps(self) -> apps.AppsResourceWithStreamingResponse:
- """Apps"""
+ """An App is software you build on Whop.
+
+ It can be a hosted web app served at `.whop.app` or an API integration installed as an experience, and it belongs to the account that owns its credentials, settings, builds, and runtime logs.
+
+ Use the Apps API to manage app configuration and, for hosted apps, read server runtime logs for console output, uncaught exceptions, and failed requests. Logs are retained for 7 days and can be filtered by build, level, time window, and message text.
+ """
from .resources.apps import AppsResourceWithStreamingResponse
return AppsResourceWithStreamingResponse(self._client.apps)
@cached_property
def invoices(self) -> invoices.InvoicesResourceWithStreamingResponse:
- """Invoices"""
from .resources.invoices import InvoicesResourceWithStreamingResponse
return InvoicesResourceWithStreamingResponse(self._client.invoices)
@@ -2357,325 +2853,433 @@ def invoices(self) -> invoices.InvoicesResourceWithStreamingResponse:
def course_lesson_interactions(
self,
) -> course_lesson_interactions.CourseLessonInteractionsResourceWithStreamingResponse:
- """Course lesson interactions"""
from .resources.course_lesson_interactions import CourseLessonInteractionsResourceWithStreamingResponse
return CourseLessonInteractionsResourceWithStreamingResponse(self._client.course_lesson_interactions)
@cached_property
def products(self) -> products.ProductsResourceWithStreamingResponse:
- """Products"""
+ """A Product is a digital good or service sold on Whop.
+
+ Products may contain plans for pricing and/or experiences for content delivery.
+
+ Use the Products API to create products, list products visible to your credentials, retrieve product details, update product metadata or merchandising fields, and delete products that should no longer be sold.
+ """
from .resources.products import ProductsResourceWithStreamingResponse
return ProductsResourceWithStreamingResponse(self._client.products)
+ @cached_property
+ def social_accounts(self) -> social_accounts.SocialAccountsResourceWithStreamingResponse:
+ """
+ A Social Account represents an external profile connected to a Whop account or user, such as a Facebook page or Instagram account. Connecting a social account lets Whop run [ads](/api-reference/beta/ads/ad) under that profile's identity and promote its existing posts.
+
+ Use the Social Accounts API to list connected accounts, create a Whop-managed Facebook page, start an OAuth connection, disconnect a social account, and list a connected profile's posts.
+ """
+ from .resources.social_accounts import SocialAccountsResourceWithStreamingResponse
+
+ return SocialAccountsResourceWithStreamingResponse(self._client.social_accounts)
+
+ @cached_property
+ def audiences(self) -> audiences.AudiencesResourceWithStreamingResponse:
+ """An Audience represents a customer list uploaded to Whop for ad targeting.
+
+ Audiences belong to an account and sync to supported ad platforms as custom audiences.
+
+ Use the Audiences API to create audiences from CSV uploads, monitor processing status, and list or delete audiences for an account. Created audiences are usable for targeting after processing reaches `ready` or `partial`.
+ """
+ from .resources.audiences import AudiencesResourceWithStreamingResponse
+
+ return AudiencesResourceWithStreamingResponse(self._client.audiences)
+
+ @cached_property
+ def media(self) -> media.MediaResourceWithStreamingResponse:
+ """
+ A Media Asset is an AI-generated image or video created from a prompt and billed from an account balance. When generation finishes, the asset includes a file that can be attached anywhere Whop accepts files.
+
+ Use the Media API to start a generation job and retrieve the asset while it processes or after it is ready.
+ """
+ from .resources.media import MediaResourceWithStreamingResponse
+
+ return MediaResourceWithStreamingResponse(self._client.media)
+
+ @cached_property
+ def people(self) -> people.PeopleResourceWithStreamingResponse:
+ """
+ A Person represents a visitor or customer of an account, assembled from [pixel events](/api-reference/beta/events/event) and purchase activity — ad clicks, storefront visits, and checkouts.
+
+ Use the People API to list the people of an account and retrieve a single person.
+ """
+ from .resources.people import PeopleResourceWithStreamingResponse
+
+ return PeopleResourceWithStreamingResponse(self._client.people)
+
+ @cached_property
+ def events(self) -> events.EventsResourceWithStreamingResponse:
+ """
+ An Event records conversion or engagement activity for an account, such as page views, purchases, or leads. Each event ties the action to the [person](/api-reference/beta/people/person) who took it, so activity can be attributed to the ads and links that drove it.
+
+ Use the Events API to send new tracking events and list the events recorded for a person.
+ """
+ from .resources.events import EventsResourceWithStreamingResponse
+
+ return EventsResourceWithStreamingResponse(self._client.events)
+
@cached_property
def companies(self) -> companies.CompaniesResourceWithStreamingResponse:
- """Companies"""
from .resources.companies import CompaniesResourceWithStreamingResponse
return CompaniesResourceWithStreamingResponse(self._client.companies)
@cached_property
def webhooks(self) -> webhooks.WebhooksResourceWithStreamingResponse:
- """Webhooks"""
from .resources.webhooks import WebhooksResourceWithStreamingResponse
return WebhooksResourceWithStreamingResponse(self._client.webhooks)
@cached_property
def plans(self) -> plans.PlansResourceWithStreamingResponse:
- """Plans"""
+ """A Plan defines how customers buy a product.
+
+ It controls pricing, billing cadence, availability, tax behavior, checkout fields, and purchase visibility.
+
+ Use the Plans API to create plans for products, list existing plans, retrieve or update plan configuration, calculate tax for checkout, and delete plans that should no longer be offered.
+ """
from .resources.plans import PlansResourceWithStreamingResponse
return PlansResourceWithStreamingResponse(self._client.plans)
@cached_property
def entries(self) -> entries.EntriesResourceWithStreamingResponse:
- """Entries"""
from .resources.entries import EntriesResourceWithStreamingResponse
return EntriesResourceWithStreamingResponse(self._client.entries)
@cached_property
def forum_posts(self) -> forum_posts.ForumPostsResourceWithStreamingResponse:
- """Forum posts"""
from .resources.forum_posts import ForumPostsResourceWithStreamingResponse
return ForumPostsResourceWithStreamingResponse(self._client.forum_posts)
@cached_property
def transfers(self) -> transfers.TransfersResourceWithStreamingResponse:
- """Transfers"""
+ """Transfers move value between identities on Whop.
+
+ They are used for account-to-account money movement, user payouts inside Whop, crypto transfers, and claim links depending on the destination type.
+
+ Use the Transfers API to create a transfer, list previous transfers, and retrieve a transfer by ID when reconciling money movement between accounts or users.
+ """
from .resources.transfers import TransfersResourceWithStreamingResponse
return TransfersResourceWithStreamingResponse(self._client.transfers)
@cached_property
def ledger_accounts(self) -> ledger_accounts.LedgerAccountsResourceWithStreamingResponse:
- """Ledger accounts"""
from .resources.ledger_accounts import LedgerAccountsResourceWithStreamingResponse
return LedgerAccountsResourceWithStreamingResponse(self._client.ledger_accounts)
@cached_property
def memberships(self) -> memberships.MembershipsResourceWithStreamingResponse:
- """Memberships"""
from .resources.memberships import MembershipsResourceWithStreamingResponse
return MembershipsResourceWithStreamingResponse(self._client.memberships)
@cached_property
def authorized_users(self) -> authorized_users.AuthorizedUsersResourceWithStreamingResponse:
- """Authorized users"""
from .resources.authorized_users import AuthorizedUsersResourceWithStreamingResponse
return AuthorizedUsersResourceWithStreamingResponse(self._client.authorized_users)
@cached_property
def app_builds(self) -> app_builds.AppBuildsResourceWithStreamingResponse:
- """App builds"""
from .resources.app_builds import AppBuildsResourceWithStreamingResponse
return AppBuildsResourceWithStreamingResponse(self._client.app_builds)
@cached_property
def shipments(self) -> shipments.ShipmentsResourceWithStreamingResponse:
- """Shipments"""
from .resources.shipments import ShipmentsResourceWithStreamingResponse
return ShipmentsResourceWithStreamingResponse(self._client.shipments)
@cached_property
def checkout_configurations(self) -> checkout_configurations.CheckoutConfigurationsResourceWithStreamingResponse:
- """Checkout configurations"""
+ """A Checkout Configuration is a reusable checkout link owned by an account.
+
+ In `payment` mode it sells a specific plan; in `setup` mode it collects and saves payment details without charging. Each configuration can also override which payment methods are accepted and how 3D Secure is enforced for that checkout.
+
+ Use the Checkout Configurations API to create checkout links for an existing or inline plan, list configurations for an account, retrieve the configuration behind a checkout URL, and delete links that should no longer be used.
+ """
from .resources.checkout_configurations import CheckoutConfigurationsResourceWithStreamingResponse
return CheckoutConfigurationsResourceWithStreamingResponse(self._client.checkout_configurations)
@cached_property
def messages(self) -> messages.MessagesResourceWithStreamingResponse:
- """Messages"""
from .resources.messages import MessagesResourceWithStreamingResponse
return MessagesResourceWithStreamingResponse(self._client.messages)
@cached_property
def chat_channels(self) -> chat_channels.ChatChannelsResourceWithStreamingResponse:
- """Chat channels"""
from .resources.chat_channels import ChatChannelsResourceWithStreamingResponse
return ChatChannelsResourceWithStreamingResponse(self._client.chat_channels)
@cached_property
def users(self) -> users.UsersResourceWithStreamingResponse:
- """Users"""
+ """A User represents a person on Whop.
+
+ Users have a public profile and can buy products, join accounts, and access experiences.
+
+ Use the Users API to search for users, retrieve or update profiles, and check whether a user has access to an account, product, or experience.
+ """
from .resources.users import UsersResourceWithStreamingResponse
return UsersResourceWithStreamingResponse(self._client.users)
@cached_property
def payments(self) -> payments.PaymentsResourceWithStreamingResponse:
- """Payments"""
from .resources.payments import PaymentsResourceWithStreamingResponse
return PaymentsResourceWithStreamingResponse(self._client.payments)
@cached_property
def support_channels(self) -> support_channels.SupportChannelsResourceWithStreamingResponse:
- """Support channels"""
from .resources.support_channels import SupportChannelsResourceWithStreamingResponse
return SupportChannelsResourceWithStreamingResponse(self._client.support_channels)
@cached_property
def experiences(self) -> experiences.ExperiencesResourceWithStreamingResponse:
- """Experiences"""
from .resources.experiences import ExperiencesResourceWithStreamingResponse
return ExperiencesResourceWithStreamingResponse(self._client.experiences)
@cached_property
def reactions(self) -> reactions.ReactionsResourceWithStreamingResponse:
- """Reactions"""
from .resources.reactions import ReactionsResourceWithStreamingResponse
return ReactionsResourceWithStreamingResponse(self._client.reactions)
@cached_property
def members(self) -> members.MembersResourceWithStreamingResponse:
- """Members"""
from .resources.members import MembersResourceWithStreamingResponse
return MembersResourceWithStreamingResponse(self._client.members)
@cached_property
def forums(self) -> forums.ForumsResourceWithStreamingResponse:
- """Forums"""
from .resources.forums import ForumsResourceWithStreamingResponse
return ForumsResourceWithStreamingResponse(self._client.forums)
@cached_property
def promo_codes(self) -> promo_codes.PromoCodesResourceWithStreamingResponse:
- """Promo codes"""
from .resources.promo_codes import PromoCodesResourceWithStreamingResponse
return PromoCodesResourceWithStreamingResponse(self._client.promo_codes)
@cached_property
def courses(self) -> courses.CoursesResourceWithStreamingResponse:
- """Courses"""
from .resources.courses import CoursesResourceWithStreamingResponse
return CoursesResourceWithStreamingResponse(self._client.courses)
@cached_property
def course_chapters(self) -> course_chapters.CourseChaptersResourceWithStreamingResponse:
- """Course chapters"""
from .resources.course_chapters import CourseChaptersResourceWithStreamingResponse
return CourseChaptersResourceWithStreamingResponse(self._client.course_chapters)
@cached_property
def course_lessons(self) -> course_lessons.CourseLessonsResourceWithStreamingResponse:
- """Course lessons"""
from .resources.course_lessons import CourseLessonsResourceWithStreamingResponse
return CourseLessonsResourceWithStreamingResponse(self._client.course_lessons)
@cached_property
def reviews(self) -> reviews.ReviewsResourceWithStreamingResponse:
- """Reviews"""
from .resources.reviews import ReviewsResourceWithStreamingResponse
return ReviewsResourceWithStreamingResponse(self._client.reviews)
@cached_property
def course_students(self) -> course_students.CourseStudentsResourceWithStreamingResponse:
- """Course students"""
from .resources.course_students import CourseStudentsResourceWithStreamingResponse
return CourseStudentsResourceWithStreamingResponse(self._client.course_students)
@cached_property
def access_tokens(self) -> access_tokens.AccessTokensResourceWithStreamingResponse:
- """Access tokens"""
from .resources.access_tokens import AccessTokensResourceWithStreamingResponse
return AccessTokensResourceWithStreamingResponse(self._client.access_tokens)
@cached_property
def notifications(self) -> notifications.NotificationsResourceWithStreamingResponse:
- """Notifications"""
from .resources.notifications import NotificationsResourceWithStreamingResponse
return NotificationsResourceWithStreamingResponse(self._client.notifications)
@cached_property
def disputes(self) -> disputes.DisputesResourceWithStreamingResponse:
- """Disputes"""
from .resources.disputes import DisputesResourceWithStreamingResponse
return DisputesResourceWithStreamingResponse(self._client.disputes)
@cached_property
def refunds(self) -> refunds.RefundsResourceWithStreamingResponse:
- """Refunds"""
from .resources.refunds import RefundsResourceWithStreamingResponse
return RefundsResourceWithStreamingResponse(self._client.refunds)
@cached_property
def withdrawals(self) -> withdrawals.WithdrawalsResourceWithStreamingResponse:
- """Withdrawals"""
from .resources.withdrawals import WithdrawalsResourceWithStreamingResponse
return WithdrawalsResourceWithStreamingResponse(self._client.withdrawals)
@cached_property
def account_links(self) -> account_links.AccountLinksResourceWithStreamingResponse:
- """Account links"""
from .resources.account_links import AccountLinksResourceWithStreamingResponse
return AccountLinksResourceWithStreamingResponse(self._client.account_links)
@cached_property
def accounts(self) -> accounts.AccountsResourceWithStreamingResponse:
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
from .resources.accounts import 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:
+ """
+ A Ledger Activity row is a single financial event on an account's ledger — a payment, withdrawal, refund, transfer, on-chain deposit, swap, or card transaction. Each row is derived from the underlying ledger lines and carries a typed `resource` and `source` so you can present and link the event without extra lookups.
+
+ Use Ledger Activity to build a statement or transaction feed for an account or user. Reconcile against your own records with `amount` (signed, in the currency's smallest precision units) and `posted_at`, and use `available_at` to know when inflows became withdrawable.
+ """
+ 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 represent aggregated activity for an account over time.
+
+ They help you understand revenue, transactions, disputes, members, referrals, and advertising performance across reporting periods like days, weeks, or months.
+
+ Use the Stats API to list available metrics and their filterable properties, then retrieve time-series values for a date range.
+ """
+ from .resources.stats import StatsResourceWithStreamingResponse
+
+ return StatsResourceWithStreamingResponse(self._client.stats)
+
+ @cached_property
+ def payouts(self) -> payouts.PayoutsResourceWithStreamingResponse:
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+ from .resources.payouts import PayoutsResourceWithStreamingResponse
+
+ return PayoutsResourceWithStreamingResponse(self._client.payouts)
+
+ @cached_property
+ def referrals(self) -> referrals.ReferralsResourceWithStreamingResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ from .resources.referrals import ReferralsResourceWithStreamingResponse
+
+ return ReferralsResourceWithStreamingResponse(self._client.referrals)
+
+ @cached_property
+ def cards(self) -> cards.CardsResourceWithStreamingResponse:
+ """
+ Cards represent Whop-issued virtual payment cards that spend from an account or user balance. Cards can be assigned to cardholders and configured with spending limits for controlled spending.
+
+ Use the Cards API to issue cards, list cards for an account or user, and retrieve active card details such as the card number and CVC.
+ """
+ from .resources.cards import CardsResourceWithStreamingResponse
+
+ return CardsResourceWithStreamingResponse(self._client.cards)
@cached_property
def swaps(self) -> swaps.SwapsResourceWithStreamingResponse:
+ """
+ Swaps convert value between supported tokens, chains, or wallet destinations for an account. A swap quote describes the expected output, fees, and approval requirements before you create the swap.
+
+ Use the Swaps API to quote a conversion, create the swap, list recent swaps, and retrieve status until the transaction completes.
+ """
from .resources.swaps import SwapsResourceWithStreamingResponse
return SwapsResourceWithStreamingResponse(self._client.swaps)
@cached_property
def deposits(self) -> deposits.DepositsResourceWithStreamingResponse:
+ """
+ Deposits describe ways to add funds to an account balance, including hosted deposit pages, bank deposit instructions, and supported crypto wallet addresses.
+
+ Use the Deposits API to create deposit instructions for an account and retrieve existing bank deposit activity.
+ """
from .resources.deposits import DepositsResourceWithStreamingResponse
return DepositsResourceWithStreamingResponse(self._client.deposits)
@cached_property
def setup_intents(self) -> setup_intents.SetupIntentsResourceWithStreamingResponse:
- """Setup intents"""
from .resources.setup_intents import SetupIntentsResourceWithStreamingResponse
return SetupIntentsResourceWithStreamingResponse(self._client.setup_intents)
@cached_property
def payment_methods(self) -> payment_methods.PaymentMethodsResourceWithStreamingResponse:
- """Payment methods"""
from .resources.payment_methods import PaymentMethodsResourceWithStreamingResponse
return PaymentMethodsResourceWithStreamingResponse(self._client.payment_methods)
@cached_property
def fee_markups(self) -> fee_markups.FeeMarkupsResourceWithStreamingResponse:
- """Fee markups"""
from .resources.fee_markups import FeeMarkupsResourceWithStreamingResponse
return FeeMarkupsResourceWithStreamingResponse(self._client.fee_markups)
@cached_property
- def payout_methods(self) -> payout_methods.PayoutMethodsResourceWithStreamingResponse:
- """Payout methods"""
- from .resources.payout_methods import PayoutMethodsResourceWithStreamingResponse
+ def verifications(self) -> verifications.VerificationsResourceWithStreamingResponse:
+ """A Verification represents an identity review for a person or business.
- return PayoutMethodsResourceWithStreamingResponse(self._client.payout_methods)
+ Accounts and users complete verification when Whop needs to confirm who they are before enabling payouts or compliance-sensitive workflows.
- @cached_property
- def verifications(self) -> verifications.VerificationsResourceWithStreamingResponse:
- """Verifications"""
+ Use the Verifications API to start or resume a hosted verification session, check review status, and submit requested details or documents. If `requested_information` contains items, submit answers with [Update Verification](/api-reference/beta/verifications/update-verification).
+ """
from .resources.verifications import VerificationsResourceWithStreamingResponse
return VerificationsResourceWithStreamingResponse(self._client.verifications)
@cached_property
def leads(self) -> leads.LeadsResourceWithStreamingResponse:
- """Leads"""
from .resources.leads import LeadsResourceWithStreamingResponse
return LeadsResourceWithStreamingResponse(self._client.leads)
@cached_property
def topups(self) -> topups.TopupsResourceWithStreamingResponse:
- """Topups"""
from .resources.topups import TopupsResourceWithStreamingResponse
return TopupsResourceWithStreamingResponse(self._client.topups)
@cached_property
def files(self) -> files.FilesResourceWithStreamingResponse:
- """Files"""
from .resources.files import FilesResourceWithStreamingResponse
return FilesResourceWithStreamingResponse(self._client.files)
@@ -2684,98 +3288,100 @@ def files(self) -> files.FilesResourceWithStreamingResponse:
def company_token_transactions(
self,
) -> company_token_transactions.CompanyTokenTransactionsResourceWithStreamingResponse:
- """Company token transactions"""
from .resources.company_token_transactions import CompanyTokenTransactionsResourceWithStreamingResponse
return CompanyTokenTransactionsResourceWithStreamingResponse(self._client.company_token_transactions)
@cached_property
def dm_members(self) -> dm_members.DmMembersResourceWithStreamingResponse:
- """Dm members"""
from .resources.dm_members import DmMembersResourceWithStreamingResponse
return DmMembersResourceWithStreamingResponse(self._client.dm_members)
@cached_property
def ai_chats(self) -> ai_chats.AIChatsResourceWithStreamingResponse:
- """Ai chats"""
from .resources.ai_chats import AIChatsResourceWithStreamingResponse
return AIChatsResourceWithStreamingResponse(self._client.ai_chats)
@cached_property
def dm_channels(self) -> dm_channels.DmChannelsResourceWithStreamingResponse:
- """Dm channels"""
from .resources.dm_channels import DmChannelsResourceWithStreamingResponse
return DmChannelsResourceWithStreamingResponse(self._client.dm_channels)
@cached_property
def dispute_alerts(self) -> dispute_alerts.DisputeAlertsResourceWithStreamingResponse:
- """Dispute alerts"""
from .resources.dispute_alerts import DisputeAlertsResourceWithStreamingResponse
return DisputeAlertsResourceWithStreamingResponse(self._client.dispute_alerts)
@cached_property
def resolution_center_cases(self) -> resolution_center_cases.ResolutionCenterCasesResourceWithStreamingResponse:
- """Resolution center cases"""
from .resources.resolution_center_cases import ResolutionCenterCasesResourceWithStreamingResponse
return ResolutionCenterCasesResourceWithStreamingResponse(self._client.resolution_center_cases)
@cached_property
def payout_accounts(self) -> payout_accounts.PayoutAccountsResourceWithStreamingResponse:
- """Payout accounts"""
from .resources.payout_accounts import PayoutAccountsResourceWithStreamingResponse
return PayoutAccountsResourceWithStreamingResponse(self._client.payout_accounts)
@cached_property
def affiliates(self) -> affiliates.AffiliatesResourceWithStreamingResponse:
- """Affiliates"""
from .resources.affiliates import AffiliatesResourceWithStreamingResponse
return AffiliatesResourceWithStreamingResponse(self._client.affiliates)
@cached_property
def bounties(self) -> bounties.BountiesResourceWithStreamingResponse:
- """Bounties"""
from .resources.bounties import BountiesResourceWithStreamingResponse
return BountiesResourceWithStreamingResponse(self._client.bounties)
+ @cached_property
+ def workforce(self) -> workforce.WorkforceResourceWithStreamingResponse:
+ from .resources.workforce import WorkforceResourceWithStreamingResponse
+
+ return WorkforceResourceWithStreamingResponse(self._client.workforce)
+
@cached_property
def ad_campaigns(self) -> ad_campaigns.AdCampaignsResourceWithStreamingResponse:
- """Ad campaigns"""
+ """An Ad Campaign is the top-level container for paid ads on an ad network.
+
+ It sets the platform, objective, and budget strategy shared by its [ad groups](/api-reference/beta/ad-groups/ad-group) and ads.
+
+ Use the Ad Campaigns API to create campaigns, list campaigns for an account, retrieve or update campaign settings, and pause or resume campaign delivery.
+ """
from .resources.ad_campaigns import AdCampaignsResourceWithStreamingResponse
return AdCampaignsResourceWithStreamingResponse(self._client.ad_campaigns)
@cached_property
def ad_groups(self) -> ad_groups.AdGroupsResourceWithStreamingResponse:
- """Ad groups"""
+ """
+ An Ad Group sits inside an [ad campaign](/api-reference/beta/ad-campaigns/ad-campaign) and controls delivery for [ads](/api-reference/beta/ads/ad). It sets the audience, placements, schedule, budget, and optimization goal for its ads.
+
+ Use the Ad Groups API to create ad groups in campaigns, list or retrieve targeting and delivery settings, update budgets or targeting, delete groups that should stop running, and pause or resume delivery.
+ """
from .resources.ad_groups import AdGroupsResourceWithStreamingResponse
return AdGroupsResourceWithStreamingResponse(self._client.ad_groups)
@cached_property
def ads(self) -> ads.AdsResourceWithStreamingResponse:
- """Ads"""
+ """
+ An Ad is the individual creative unit delivered by an [ad group](/api-reference/beta/ad-groups/ad-group). It holds the copy, creative assets, and destination URL for one ad.
+
+ Use the Ads API to list ads for an account, create ads inside ad groups, retrieve or update creative details, delete ads that should stop running, and pause or resume delivery.
+ """
from .resources.ads import AdsResourceWithStreamingResponse
return AdsResourceWithStreamingResponse(self._client.ads)
- @cached_property
- def conversions(self) -> conversions.ConversionsResourceWithStreamingResponse:
- """Conversions"""
- from .resources.conversions import ConversionsResourceWithStreamingResponse
-
- return ConversionsResourceWithStreamingResponse(self._client.conversions)
-
@cached_property
def ad_reports(self) -> ad_reports.AdReportsResourceWithStreamingResponse:
- """Ad reports"""
from .resources.ad_reports import AdReportsResourceWithStreamingResponse
return AdReportsResourceWithStreamingResponse(self._client.ad_reports)
@@ -2789,14 +3395,18 @@ def __init__(self, client: AsyncWhop) -> None:
@cached_property
def apps(self) -> apps.AsyncAppsResourceWithStreamingResponse:
- """Apps"""
+ """An App is software you build on Whop.
+
+ It can be a hosted web app served at `.whop.app` or an API integration installed as an experience, and it belongs to the account that owns its credentials, settings, builds, and runtime logs.
+
+ Use the Apps API to manage app configuration and, for hosted apps, read server runtime logs for console output, uncaught exceptions, and failed requests. Logs are retained for 7 days and can be filtered by build, level, time window, and message text.
+ """
from .resources.apps import AsyncAppsResourceWithStreamingResponse
return AsyncAppsResourceWithStreamingResponse(self._client.apps)
@cached_property
def invoices(self) -> invoices.AsyncInvoicesResourceWithStreamingResponse:
- """Invoices"""
from .resources.invoices import AsyncInvoicesResourceWithStreamingResponse
return AsyncInvoicesResourceWithStreamingResponse(self._client.invoices)
@@ -2805,91 +3415,152 @@ def invoices(self) -> invoices.AsyncInvoicesResourceWithStreamingResponse:
def course_lesson_interactions(
self,
) -> course_lesson_interactions.AsyncCourseLessonInteractionsResourceWithStreamingResponse:
- """Course lesson interactions"""
from .resources.course_lesson_interactions import AsyncCourseLessonInteractionsResourceWithStreamingResponse
return AsyncCourseLessonInteractionsResourceWithStreamingResponse(self._client.course_lesson_interactions)
@cached_property
def products(self) -> products.AsyncProductsResourceWithStreamingResponse:
- """Products"""
+ """A Product is a digital good or service sold on Whop.
+
+ Products may contain plans for pricing and/or experiences for content delivery.
+
+ Use the Products API to create products, list products visible to your credentials, retrieve product details, update product metadata or merchandising fields, and delete products that should no longer be sold.
+ """
from .resources.products import AsyncProductsResourceWithStreamingResponse
return AsyncProductsResourceWithStreamingResponse(self._client.products)
+ @cached_property
+ def social_accounts(self) -> social_accounts.AsyncSocialAccountsResourceWithStreamingResponse:
+ """
+ A Social Account represents an external profile connected to a Whop account or user, such as a Facebook page or Instagram account. Connecting a social account lets Whop run [ads](/api-reference/beta/ads/ad) under that profile's identity and promote its existing posts.
+
+ Use the Social Accounts API to list connected accounts, create a Whop-managed Facebook page, start an OAuth connection, disconnect a social account, and list a connected profile's posts.
+ """
+ from .resources.social_accounts import AsyncSocialAccountsResourceWithStreamingResponse
+
+ return AsyncSocialAccountsResourceWithStreamingResponse(self._client.social_accounts)
+
+ @cached_property
+ def audiences(self) -> audiences.AsyncAudiencesResourceWithStreamingResponse:
+ """An Audience represents a customer list uploaded to Whop for ad targeting.
+
+ Audiences belong to an account and sync to supported ad platforms as custom audiences.
+
+ Use the Audiences API to create audiences from CSV uploads, monitor processing status, and list or delete audiences for an account. Created audiences are usable for targeting after processing reaches `ready` or `partial`.
+ """
+ from .resources.audiences import AsyncAudiencesResourceWithStreamingResponse
+
+ return AsyncAudiencesResourceWithStreamingResponse(self._client.audiences)
+
+ @cached_property
+ def media(self) -> media.AsyncMediaResourceWithStreamingResponse:
+ """
+ A Media Asset is an AI-generated image or video created from a prompt and billed from an account balance. When generation finishes, the asset includes a file that can be attached anywhere Whop accepts files.
+
+ Use the Media API to start a generation job and retrieve the asset while it processes or after it is ready.
+ """
+ from .resources.media import AsyncMediaResourceWithStreamingResponse
+
+ return AsyncMediaResourceWithStreamingResponse(self._client.media)
+
+ @cached_property
+ def people(self) -> people.AsyncPeopleResourceWithStreamingResponse:
+ """
+ A Person represents a visitor or customer of an account, assembled from [pixel events](/api-reference/beta/events/event) and purchase activity — ad clicks, storefront visits, and checkouts.
+
+ Use the People API to list the people of an account and retrieve a single person.
+ """
+ from .resources.people import AsyncPeopleResourceWithStreamingResponse
+
+ return AsyncPeopleResourceWithStreamingResponse(self._client.people)
+
+ @cached_property
+ def events(self) -> events.AsyncEventsResourceWithStreamingResponse:
+ """
+ An Event records conversion or engagement activity for an account, such as page views, purchases, or leads. Each event ties the action to the [person](/api-reference/beta/people/person) who took it, so activity can be attributed to the ads and links that drove it.
+
+ Use the Events API to send new tracking events and list the events recorded for a person.
+ """
+ from .resources.events import AsyncEventsResourceWithStreamingResponse
+
+ return AsyncEventsResourceWithStreamingResponse(self._client.events)
+
@cached_property
def companies(self) -> companies.AsyncCompaniesResourceWithStreamingResponse:
- """Companies"""
from .resources.companies import AsyncCompaniesResourceWithStreamingResponse
return AsyncCompaniesResourceWithStreamingResponse(self._client.companies)
@cached_property
def webhooks(self) -> webhooks.AsyncWebhooksResourceWithStreamingResponse:
- """Webhooks"""
from .resources.webhooks import AsyncWebhooksResourceWithStreamingResponse
return AsyncWebhooksResourceWithStreamingResponse(self._client.webhooks)
@cached_property
def plans(self) -> plans.AsyncPlansResourceWithStreamingResponse:
- """Plans"""
+ """A Plan defines how customers buy a product.
+
+ It controls pricing, billing cadence, availability, tax behavior, checkout fields, and purchase visibility.
+
+ Use the Plans API to create plans for products, list existing plans, retrieve or update plan configuration, calculate tax for checkout, and delete plans that should no longer be offered.
+ """
from .resources.plans import AsyncPlansResourceWithStreamingResponse
return AsyncPlansResourceWithStreamingResponse(self._client.plans)
@cached_property
def entries(self) -> entries.AsyncEntriesResourceWithStreamingResponse:
- """Entries"""
from .resources.entries import AsyncEntriesResourceWithStreamingResponse
return AsyncEntriesResourceWithStreamingResponse(self._client.entries)
@cached_property
def forum_posts(self) -> forum_posts.AsyncForumPostsResourceWithStreamingResponse:
- """Forum posts"""
from .resources.forum_posts import AsyncForumPostsResourceWithStreamingResponse
return AsyncForumPostsResourceWithStreamingResponse(self._client.forum_posts)
@cached_property
def transfers(self) -> transfers.AsyncTransfersResourceWithStreamingResponse:
- """Transfers"""
+ """Transfers move value between identities on Whop.
+
+ They are used for account-to-account money movement, user payouts inside Whop, crypto transfers, and claim links depending on the destination type.
+
+ Use the Transfers API to create a transfer, list previous transfers, and retrieve a transfer by ID when reconciling money movement between accounts or users.
+ """
from .resources.transfers import AsyncTransfersResourceWithStreamingResponse
return AsyncTransfersResourceWithStreamingResponse(self._client.transfers)
@cached_property
def ledger_accounts(self) -> ledger_accounts.AsyncLedgerAccountsResourceWithStreamingResponse:
- """Ledger accounts"""
from .resources.ledger_accounts import AsyncLedgerAccountsResourceWithStreamingResponse
return AsyncLedgerAccountsResourceWithStreamingResponse(self._client.ledger_accounts)
@cached_property
def memberships(self) -> memberships.AsyncMembershipsResourceWithStreamingResponse:
- """Memberships"""
from .resources.memberships import AsyncMembershipsResourceWithStreamingResponse
return AsyncMembershipsResourceWithStreamingResponse(self._client.memberships)
@cached_property
def authorized_users(self) -> authorized_users.AsyncAuthorizedUsersResourceWithStreamingResponse:
- """Authorized users"""
from .resources.authorized_users import AsyncAuthorizedUsersResourceWithStreamingResponse
return AsyncAuthorizedUsersResourceWithStreamingResponse(self._client.authorized_users)
@cached_property
def app_builds(self) -> app_builds.AsyncAppBuildsResourceWithStreamingResponse:
- """App builds"""
from .resources.app_builds import AsyncAppBuildsResourceWithStreamingResponse
return AsyncAppBuildsResourceWithStreamingResponse(self._client.app_builds)
@cached_property
def shipments(self) -> shipments.AsyncShipmentsResourceWithStreamingResponse:
- """Shipments"""
from .resources.shipments import AsyncShipmentsResourceWithStreamingResponse
return AsyncShipmentsResourceWithStreamingResponse(self._client.shipments)
@@ -2898,234 +3569,281 @@ def shipments(self) -> shipments.AsyncShipmentsResourceWithStreamingResponse:
def checkout_configurations(
self,
) -> checkout_configurations.AsyncCheckoutConfigurationsResourceWithStreamingResponse:
- """Checkout configurations"""
+ """A Checkout Configuration is a reusable checkout link owned by an account.
+
+ In `payment` mode it sells a specific plan; in `setup` mode it collects and saves payment details without charging. Each configuration can also override which payment methods are accepted and how 3D Secure is enforced for that checkout.
+
+ Use the Checkout Configurations API to create checkout links for an existing or inline plan, list configurations for an account, retrieve the configuration behind a checkout URL, and delete links that should no longer be used.
+ """
from .resources.checkout_configurations import AsyncCheckoutConfigurationsResourceWithStreamingResponse
return AsyncCheckoutConfigurationsResourceWithStreamingResponse(self._client.checkout_configurations)
@cached_property
def messages(self) -> messages.AsyncMessagesResourceWithStreamingResponse:
- """Messages"""
from .resources.messages import AsyncMessagesResourceWithStreamingResponse
return AsyncMessagesResourceWithStreamingResponse(self._client.messages)
@cached_property
def chat_channels(self) -> chat_channels.AsyncChatChannelsResourceWithStreamingResponse:
- """Chat channels"""
from .resources.chat_channels import AsyncChatChannelsResourceWithStreamingResponse
return AsyncChatChannelsResourceWithStreamingResponse(self._client.chat_channels)
@cached_property
def users(self) -> users.AsyncUsersResourceWithStreamingResponse:
- """Users"""
+ """A User represents a person on Whop.
+
+ Users have a public profile and can buy products, join accounts, and access experiences.
+
+ Use the Users API to search for users, retrieve or update profiles, and check whether a user has access to an account, product, or experience.
+ """
from .resources.users import AsyncUsersResourceWithStreamingResponse
return AsyncUsersResourceWithStreamingResponse(self._client.users)
@cached_property
def payments(self) -> payments.AsyncPaymentsResourceWithStreamingResponse:
- """Payments"""
from .resources.payments import AsyncPaymentsResourceWithStreamingResponse
return AsyncPaymentsResourceWithStreamingResponse(self._client.payments)
@cached_property
def support_channels(self) -> support_channels.AsyncSupportChannelsResourceWithStreamingResponse:
- """Support channels"""
from .resources.support_channels import AsyncSupportChannelsResourceWithStreamingResponse
return AsyncSupportChannelsResourceWithStreamingResponse(self._client.support_channels)
@cached_property
def experiences(self) -> experiences.AsyncExperiencesResourceWithStreamingResponse:
- """Experiences"""
from .resources.experiences import AsyncExperiencesResourceWithStreamingResponse
return AsyncExperiencesResourceWithStreamingResponse(self._client.experiences)
@cached_property
def reactions(self) -> reactions.AsyncReactionsResourceWithStreamingResponse:
- """Reactions"""
from .resources.reactions import AsyncReactionsResourceWithStreamingResponse
return AsyncReactionsResourceWithStreamingResponse(self._client.reactions)
@cached_property
def members(self) -> members.AsyncMembersResourceWithStreamingResponse:
- """Members"""
from .resources.members import AsyncMembersResourceWithStreamingResponse
return AsyncMembersResourceWithStreamingResponse(self._client.members)
@cached_property
def forums(self) -> forums.AsyncForumsResourceWithStreamingResponse:
- """Forums"""
from .resources.forums import AsyncForumsResourceWithStreamingResponse
return AsyncForumsResourceWithStreamingResponse(self._client.forums)
@cached_property
def promo_codes(self) -> promo_codes.AsyncPromoCodesResourceWithStreamingResponse:
- """Promo codes"""
from .resources.promo_codes import AsyncPromoCodesResourceWithStreamingResponse
return AsyncPromoCodesResourceWithStreamingResponse(self._client.promo_codes)
@cached_property
def courses(self) -> courses.AsyncCoursesResourceWithStreamingResponse:
- """Courses"""
from .resources.courses import AsyncCoursesResourceWithStreamingResponse
return AsyncCoursesResourceWithStreamingResponse(self._client.courses)
@cached_property
def course_chapters(self) -> course_chapters.AsyncCourseChaptersResourceWithStreamingResponse:
- """Course chapters"""
from .resources.course_chapters import AsyncCourseChaptersResourceWithStreamingResponse
return AsyncCourseChaptersResourceWithStreamingResponse(self._client.course_chapters)
@cached_property
def course_lessons(self) -> course_lessons.AsyncCourseLessonsResourceWithStreamingResponse:
- """Course lessons"""
from .resources.course_lessons import AsyncCourseLessonsResourceWithStreamingResponse
return AsyncCourseLessonsResourceWithStreamingResponse(self._client.course_lessons)
@cached_property
def reviews(self) -> reviews.AsyncReviewsResourceWithStreamingResponse:
- """Reviews"""
from .resources.reviews import AsyncReviewsResourceWithStreamingResponse
return AsyncReviewsResourceWithStreamingResponse(self._client.reviews)
@cached_property
def course_students(self) -> course_students.AsyncCourseStudentsResourceWithStreamingResponse:
- """Course students"""
from .resources.course_students import AsyncCourseStudentsResourceWithStreamingResponse
return AsyncCourseStudentsResourceWithStreamingResponse(self._client.course_students)
@cached_property
def access_tokens(self) -> access_tokens.AsyncAccessTokensResourceWithStreamingResponse:
- """Access tokens"""
from .resources.access_tokens import AsyncAccessTokensResourceWithStreamingResponse
return AsyncAccessTokensResourceWithStreamingResponse(self._client.access_tokens)
@cached_property
def notifications(self) -> notifications.AsyncNotificationsResourceWithStreamingResponse:
- """Notifications"""
from .resources.notifications import AsyncNotificationsResourceWithStreamingResponse
return AsyncNotificationsResourceWithStreamingResponse(self._client.notifications)
@cached_property
def disputes(self) -> disputes.AsyncDisputesResourceWithStreamingResponse:
- """Disputes"""
from .resources.disputes import AsyncDisputesResourceWithStreamingResponse
return AsyncDisputesResourceWithStreamingResponse(self._client.disputes)
@cached_property
def refunds(self) -> refunds.AsyncRefundsResourceWithStreamingResponse:
- """Refunds"""
from .resources.refunds import AsyncRefundsResourceWithStreamingResponse
return AsyncRefundsResourceWithStreamingResponse(self._client.refunds)
@cached_property
def withdrawals(self) -> withdrawals.AsyncWithdrawalsResourceWithStreamingResponse:
- """Withdrawals"""
from .resources.withdrawals import AsyncWithdrawalsResourceWithStreamingResponse
return AsyncWithdrawalsResourceWithStreamingResponse(self._client.withdrawals)
@cached_property
def account_links(self) -> account_links.AsyncAccountLinksResourceWithStreamingResponse:
- """Account links"""
from .resources.account_links import AsyncAccountLinksResourceWithStreamingResponse
return AsyncAccountLinksResourceWithStreamingResponse(self._client.account_links)
@cached_property
def accounts(self) -> accounts.AsyncAccountsResourceWithStreamingResponse:
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
from .resources.accounts import 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:
+ """
+ A Ledger Activity row is a single financial event on an account's ledger — a payment, withdrawal, refund, transfer, on-chain deposit, swap, or card transaction. Each row is derived from the underlying ledger lines and carries a typed `resource` and `source` so you can present and link the event without extra lookups.
- return AsyncWalletsResourceWithStreamingResponse(self._client.wallets)
+ Use Ledger Activity to build a statement or transaction feed for an account or user. Reconcile against your own records with `amount` (signed, in the currency's smallest precision units) and `posted_at`, and use `available_at` to know when inflows became withdrawable.
+ """
+ from .resources.financial_activity import AsyncFinancialActivityResourceWithStreamingResponse
+
+ return AsyncFinancialActivityResourceWithStreamingResponse(self._client.financial_activity)
+
+ @cached_property
+ def stats(self) -> stats.AsyncStatsResourceWithStreamingResponse:
+ """Stats represent aggregated activity for an account over time.
+
+ They help you understand revenue, transactions, disputes, members, referrals, and advertising performance across reporting periods like days, weeks, or months.
+
+ Use the Stats API to list available metrics and their filterable properties, then retrieve time-series values for a date range.
+ """
+ from .resources.stats import AsyncStatsResourceWithStreamingResponse
+
+ return AsyncStatsResourceWithStreamingResponse(self._client.stats)
+
+ @cached_property
+ def payouts(self) -> payouts.AsyncPayoutsResourceWithStreamingResponse:
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+ from .resources.payouts import AsyncPayoutsResourceWithStreamingResponse
+
+ return AsyncPayoutsResourceWithStreamingResponse(self._client.payouts)
+
+ @cached_property
+ def referrals(self) -> referrals.AsyncReferralsResourceWithStreamingResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ from .resources.referrals import AsyncReferralsResourceWithStreamingResponse
+
+ return AsyncReferralsResourceWithStreamingResponse(self._client.referrals)
+
+ @cached_property
+ def cards(self) -> cards.AsyncCardsResourceWithStreamingResponse:
+ """
+ Cards represent Whop-issued virtual payment cards that spend from an account or user balance. Cards can be assigned to cardholders and configured with spending limits for controlled spending.
+
+ Use the Cards API to issue cards, list cards for an account or user, and retrieve active card details such as the card number and CVC.
+ """
+ from .resources.cards import AsyncCardsResourceWithStreamingResponse
+
+ return AsyncCardsResourceWithStreamingResponse(self._client.cards)
@cached_property
def swaps(self) -> swaps.AsyncSwapsResourceWithStreamingResponse:
+ """
+ Swaps convert value between supported tokens, chains, or wallet destinations for an account. A swap quote describes the expected output, fees, and approval requirements before you create the swap.
+
+ Use the Swaps API to quote a conversion, create the swap, list recent swaps, and retrieve status until the transaction completes.
+ """
from .resources.swaps import AsyncSwapsResourceWithStreamingResponse
return AsyncSwapsResourceWithStreamingResponse(self._client.swaps)
@cached_property
def deposits(self) -> deposits.AsyncDepositsResourceWithStreamingResponse:
+ """
+ Deposits describe ways to add funds to an account balance, including hosted deposit pages, bank deposit instructions, and supported crypto wallet addresses.
+
+ Use the Deposits API to create deposit instructions for an account and retrieve existing bank deposit activity.
+ """
from .resources.deposits import AsyncDepositsResourceWithStreamingResponse
return AsyncDepositsResourceWithStreamingResponse(self._client.deposits)
@cached_property
def setup_intents(self) -> setup_intents.AsyncSetupIntentsResourceWithStreamingResponse:
- """Setup intents"""
from .resources.setup_intents import AsyncSetupIntentsResourceWithStreamingResponse
return AsyncSetupIntentsResourceWithStreamingResponse(self._client.setup_intents)
@cached_property
def payment_methods(self) -> payment_methods.AsyncPaymentMethodsResourceWithStreamingResponse:
- """Payment methods"""
from .resources.payment_methods import AsyncPaymentMethodsResourceWithStreamingResponse
return AsyncPaymentMethodsResourceWithStreamingResponse(self._client.payment_methods)
@cached_property
def fee_markups(self) -> fee_markups.AsyncFeeMarkupsResourceWithStreamingResponse:
- """Fee markups"""
from .resources.fee_markups import AsyncFeeMarkupsResourceWithStreamingResponse
return AsyncFeeMarkupsResourceWithStreamingResponse(self._client.fee_markups)
@cached_property
- def payout_methods(self) -> payout_methods.AsyncPayoutMethodsResourceWithStreamingResponse:
- """Payout methods"""
- from .resources.payout_methods import AsyncPayoutMethodsResourceWithStreamingResponse
+ def verifications(self) -> verifications.AsyncVerificationsResourceWithStreamingResponse:
+ """A Verification represents an identity review for a person or business.
- return AsyncPayoutMethodsResourceWithStreamingResponse(self._client.payout_methods)
+ Accounts and users complete verification when Whop needs to confirm who they are before enabling payouts or compliance-sensitive workflows.
- @cached_property
- def verifications(self) -> verifications.AsyncVerificationsResourceWithStreamingResponse:
- """Verifications"""
+ Use the Verifications API to start or resume a hosted verification session, check review status, and submit requested details or documents. If `requested_information` contains items, submit answers with [Update Verification](/api-reference/beta/verifications/update-verification).
+ """
from .resources.verifications import AsyncVerificationsResourceWithStreamingResponse
return AsyncVerificationsResourceWithStreamingResponse(self._client.verifications)
@cached_property
def leads(self) -> leads.AsyncLeadsResourceWithStreamingResponse:
- """Leads"""
from .resources.leads import AsyncLeadsResourceWithStreamingResponse
return AsyncLeadsResourceWithStreamingResponse(self._client.leads)
@cached_property
def topups(self) -> topups.AsyncTopupsResourceWithStreamingResponse:
- """Topups"""
from .resources.topups import AsyncTopupsResourceWithStreamingResponse
return AsyncTopupsResourceWithStreamingResponse(self._client.topups)
@cached_property
def files(self) -> files.AsyncFilesResourceWithStreamingResponse:
- """Files"""
from .resources.files import AsyncFilesResourceWithStreamingResponse
return AsyncFilesResourceWithStreamingResponse(self._client.files)
@@ -3134,35 +3852,30 @@ def files(self) -> files.AsyncFilesResourceWithStreamingResponse:
def company_token_transactions(
self,
) -> company_token_transactions.AsyncCompanyTokenTransactionsResourceWithStreamingResponse:
- """Company token transactions"""
from .resources.company_token_transactions import AsyncCompanyTokenTransactionsResourceWithStreamingResponse
return AsyncCompanyTokenTransactionsResourceWithStreamingResponse(self._client.company_token_transactions)
@cached_property
def dm_members(self) -> dm_members.AsyncDmMembersResourceWithStreamingResponse:
- """Dm members"""
from .resources.dm_members import AsyncDmMembersResourceWithStreamingResponse
return AsyncDmMembersResourceWithStreamingResponse(self._client.dm_members)
@cached_property
def ai_chats(self) -> ai_chats.AsyncAIChatsResourceWithStreamingResponse:
- """Ai chats"""
from .resources.ai_chats import AsyncAIChatsResourceWithStreamingResponse
return AsyncAIChatsResourceWithStreamingResponse(self._client.ai_chats)
@cached_property
def dm_channels(self) -> dm_channels.AsyncDmChannelsResourceWithStreamingResponse:
- """Dm channels"""
from .resources.dm_channels import AsyncDmChannelsResourceWithStreamingResponse
return AsyncDmChannelsResourceWithStreamingResponse(self._client.dm_channels)
@cached_property
def dispute_alerts(self) -> dispute_alerts.AsyncDisputeAlertsResourceWithStreamingResponse:
- """Dispute alerts"""
from .resources.dispute_alerts import AsyncDisputeAlertsResourceWithStreamingResponse
return AsyncDisputeAlertsResourceWithStreamingResponse(self._client.dispute_alerts)
@@ -3171,63 +3884,70 @@ def dispute_alerts(self) -> dispute_alerts.AsyncDisputeAlertsResourceWithStreami
def resolution_center_cases(
self,
) -> resolution_center_cases.AsyncResolutionCenterCasesResourceWithStreamingResponse:
- """Resolution center cases"""
from .resources.resolution_center_cases import AsyncResolutionCenterCasesResourceWithStreamingResponse
return AsyncResolutionCenterCasesResourceWithStreamingResponse(self._client.resolution_center_cases)
@cached_property
def payout_accounts(self) -> payout_accounts.AsyncPayoutAccountsResourceWithStreamingResponse:
- """Payout accounts"""
from .resources.payout_accounts import AsyncPayoutAccountsResourceWithStreamingResponse
return AsyncPayoutAccountsResourceWithStreamingResponse(self._client.payout_accounts)
@cached_property
def affiliates(self) -> affiliates.AsyncAffiliatesResourceWithStreamingResponse:
- """Affiliates"""
from .resources.affiliates import AsyncAffiliatesResourceWithStreamingResponse
return AsyncAffiliatesResourceWithStreamingResponse(self._client.affiliates)
@cached_property
def bounties(self) -> bounties.AsyncBountiesResourceWithStreamingResponse:
- """Bounties"""
from .resources.bounties import AsyncBountiesResourceWithStreamingResponse
return AsyncBountiesResourceWithStreamingResponse(self._client.bounties)
+ @cached_property
+ def workforce(self) -> workforce.AsyncWorkforceResourceWithStreamingResponse:
+ from .resources.workforce import AsyncWorkforceResourceWithStreamingResponse
+
+ return AsyncWorkforceResourceWithStreamingResponse(self._client.workforce)
+
@cached_property
def ad_campaigns(self) -> ad_campaigns.AsyncAdCampaignsResourceWithStreamingResponse:
- """Ad campaigns"""
+ """An Ad Campaign is the top-level container for paid ads on an ad network.
+
+ It sets the platform, objective, and budget strategy shared by its [ad groups](/api-reference/beta/ad-groups/ad-group) and ads.
+
+ Use the Ad Campaigns API to create campaigns, list campaigns for an account, retrieve or update campaign settings, and pause or resume campaign delivery.
+ """
from .resources.ad_campaigns import AsyncAdCampaignsResourceWithStreamingResponse
return AsyncAdCampaignsResourceWithStreamingResponse(self._client.ad_campaigns)
@cached_property
def ad_groups(self) -> ad_groups.AsyncAdGroupsResourceWithStreamingResponse:
- """Ad groups"""
+ """
+ An Ad Group sits inside an [ad campaign](/api-reference/beta/ad-campaigns/ad-campaign) and controls delivery for [ads](/api-reference/beta/ads/ad). It sets the audience, placements, schedule, budget, and optimization goal for its ads.
+
+ Use the Ad Groups API to create ad groups in campaigns, list or retrieve targeting and delivery settings, update budgets or targeting, delete groups that should stop running, and pause or resume delivery.
+ """
from .resources.ad_groups import AsyncAdGroupsResourceWithStreamingResponse
return AsyncAdGroupsResourceWithStreamingResponse(self._client.ad_groups)
@cached_property
def ads(self) -> ads.AsyncAdsResourceWithStreamingResponse:
- """Ads"""
+ """
+ An Ad is the individual creative unit delivered by an [ad group](/api-reference/beta/ad-groups/ad-group). It holds the copy, creative assets, and destination URL for one ad.
+
+ Use the Ads API to list ads for an account, create ads inside ad groups, retrieve or update creative details, delete ads that should stop running, and pause or resume delivery.
+ """
from .resources.ads import AsyncAdsResourceWithStreamingResponse
return AsyncAdsResourceWithStreamingResponse(self._client.ads)
- @cached_property
- def conversions(self) -> conversions.AsyncConversionsResourceWithStreamingResponse:
- """Conversions"""
- from .resources.conversions import AsyncConversionsResourceWithStreamingResponse
-
- return AsyncConversionsResourceWithStreamingResponse(self._client.conversions)
-
@cached_property
def ad_reports(self) -> ad_reports.AsyncAdReportsResourceWithStreamingResponse:
- """Ad reports"""
from .resources.ad_reports import AsyncAdReportsResourceWithStreamingResponse
return AsyncAdReportsResourceWithStreamingResponse(self._client.ad_reports)
diff --git a/src/whop_sdk/resources/__init__.py b/src/whop_sdk/resources/__init__.py
index 6cd6f052c..9718e9c5a 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,
@@ -32,6 +40,14 @@
LeadsResourceWithStreamingResponse,
AsyncLeadsResourceWithStreamingResponse,
)
+from .media import (
+ MediaResource,
+ AsyncMediaResource,
+ MediaResourceWithRawResponse,
+ AsyncMediaResourceWithRawResponse,
+ MediaResourceWithStreamingResponse,
+ AsyncMediaResourceWithStreamingResponse,
+)
from .plans import (
PlansResource,
AsyncPlansResource,
@@ -40,6 +56,14 @@
PlansResourceWithStreamingResponse,
AsyncPlansResourceWithStreamingResponse,
)
+from .stats import (
+ StatsResource,
+ AsyncStatsResource,
+ StatsResourceWithRawResponse,
+ AsyncStatsResourceWithRawResponse,
+ StatsResourceWithStreamingResponse,
+ AsyncStatsResourceWithStreamingResponse,
+)
from .swaps import (
SwapsResource,
AsyncSwapsResource,
@@ -56,6 +80,14 @@
UsersResourceWithStreamingResponse,
AsyncUsersResourceWithStreamingResponse,
)
+from .events import (
+ EventsResource,
+ AsyncEventsResource,
+ EventsResourceWithRawResponse,
+ AsyncEventsResourceWithRawResponse,
+ EventsResourceWithStreamingResponse,
+ AsyncEventsResourceWithStreamingResponse,
+)
from .forums import (
ForumsResource,
AsyncForumsResource,
@@ -64,6 +96,14 @@
ForumsResourceWithStreamingResponse,
AsyncForumsResourceWithStreamingResponse,
)
+from .people import (
+ PeopleResource,
+ AsyncPeopleResource,
+ PeopleResourceWithRawResponse,
+ AsyncPeopleResourceWithRawResponse,
+ PeopleResourceWithStreamingResponse,
+ AsyncPeopleResourceWithStreamingResponse,
+)
from .topups import (
TopupsResource,
AsyncTopupsResource,
@@ -96,6 +136,14 @@
MembersResourceWithStreamingResponse,
AsyncMembersResourceWithStreamingResponse,
)
+from .payouts import (
+ PayoutsResource,
+ AsyncPayoutsResource,
+ PayoutsResourceWithRawResponse,
+ AsyncPayoutsResourceWithRawResponse,
+ PayoutsResourceWithStreamingResponse,
+ AsyncPayoutsResourceWithStreamingResponse,
+)
from .refunds import (
RefundsResource,
AsyncRefundsResource,
@@ -112,14 +160,6 @@
ReviewsResourceWithStreamingResponse,
AsyncReviewsResourceWithStreamingResponse,
)
-from .wallets import (
- WalletsResource,
- AsyncWalletsResource,
- WalletsResourceWithRawResponse,
- AsyncWalletsResourceWithRawResponse,
- WalletsResourceWithStreamingResponse,
- AsyncWalletsResourceWithStreamingResponse,
-)
from .accounts import (
AccountsResource,
AsyncAccountsResource,
@@ -208,6 +248,14 @@
AdGroupsResourceWithStreamingResponse,
AsyncAdGroupsResourceWithStreamingResponse,
)
+from .audiences import (
+ AudiencesResource,
+ AsyncAudiencesResource,
+ AudiencesResourceWithRawResponse,
+ AsyncAudiencesResourceWithRawResponse,
+ AudiencesResourceWithStreamingResponse,
+ AsyncAudiencesResourceWithStreamingResponse,
+)
from .companies import (
CompaniesResource,
AsyncCompaniesResource,
@@ -224,6 +272,14 @@
ReactionsResourceWithStreamingResponse,
AsyncReactionsResourceWithStreamingResponse,
)
+from .referrals import (
+ ReferralsResource,
+ AsyncReferralsResource,
+ ReferralsResourceWithRawResponse,
+ AsyncReferralsResourceWithRawResponse,
+ ReferralsResourceWithStreamingResponse,
+ AsyncReferralsResourceWithStreamingResponse,
+)
from .shipments import (
ShipmentsResource,
AsyncShipmentsResource,
@@ -240,6 +296,14 @@
TransfersResourceWithStreamingResponse,
AsyncTransfersResourceWithStreamingResponse,
)
+from .workforce import (
+ WorkforceResource,
+ AsyncWorkforceResource,
+ WorkforceResourceWithRawResponse,
+ AsyncWorkforceResourceWithRawResponse,
+ WorkforceResourceWithStreamingResponse,
+ AsyncWorkforceResourceWithStreamingResponse,
+)
from .ad_reports import (
AdReportsResource,
AsyncAdReportsResource,
@@ -272,14 +336,6 @@
DmMembersResourceWithStreamingResponse,
AsyncDmMembersResourceWithStreamingResponse,
)
-from .conversions import (
- ConversionsResource,
- AsyncConversionsResource,
- ConversionsResourceWithRawResponse,
- AsyncConversionsResourceWithRawResponse,
- ConversionsResourceWithStreamingResponse,
- AsyncConversionsResourceWithStreamingResponse,
-)
from .dm_channels import (
DmChannelsResource,
AsyncDmChannelsResource,
@@ -408,14 +464,6 @@
DisputeAlertsResourceWithStreamingResponse,
AsyncDisputeAlertsResourceWithStreamingResponse,
)
-from .payout_methods import (
- PayoutMethodsResource,
- AsyncPayoutMethodsResource,
- PayoutMethodsResourceWithRawResponse,
- AsyncPayoutMethodsResourceWithRawResponse,
- PayoutMethodsResourceWithStreamingResponse,
- AsyncPayoutMethodsResourceWithStreamingResponse,
-)
from .course_chapters import (
CourseChaptersResource,
AsyncCourseChaptersResource,
@@ -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,36 @@
"AsyncProductsResourceWithRawResponse",
"ProductsResourceWithStreamingResponse",
"AsyncProductsResourceWithStreamingResponse",
+ "SocialAccountsResource",
+ "AsyncSocialAccountsResource",
+ "SocialAccountsResourceWithRawResponse",
+ "AsyncSocialAccountsResourceWithRawResponse",
+ "SocialAccountsResourceWithStreamingResponse",
+ "AsyncSocialAccountsResourceWithStreamingResponse",
+ "AudiencesResource",
+ "AsyncAudiencesResource",
+ "AudiencesResourceWithRawResponse",
+ "AsyncAudiencesResourceWithRawResponse",
+ "AudiencesResourceWithStreamingResponse",
+ "AsyncAudiencesResourceWithStreamingResponse",
+ "MediaResource",
+ "AsyncMediaResource",
+ "MediaResourceWithRawResponse",
+ "AsyncMediaResourceWithRawResponse",
+ "MediaResourceWithStreamingResponse",
+ "AsyncMediaResourceWithStreamingResponse",
+ "PeopleResource",
+ "AsyncPeopleResource",
+ "PeopleResourceWithRawResponse",
+ "AsyncPeopleResourceWithRawResponse",
+ "PeopleResourceWithStreamingResponse",
+ "AsyncPeopleResourceWithStreamingResponse",
+ "EventsResource",
+ "AsyncEventsResource",
+ "EventsResourceWithRawResponse",
+ "AsyncEventsResourceWithRawResponse",
+ "EventsResourceWithStreamingResponse",
+ "AsyncEventsResourceWithStreamingResponse",
"CompaniesResource",
"AsyncCompaniesResource",
"CompaniesResourceWithRawResponse",
@@ -734,12 +828,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",
@@ -770,12 +888,6 @@
"AsyncFeeMarkupsResourceWithRawResponse",
"FeeMarkupsResourceWithStreamingResponse",
"AsyncFeeMarkupsResourceWithStreamingResponse",
- "PayoutMethodsResource",
- "AsyncPayoutMethodsResource",
- "PayoutMethodsResourceWithRawResponse",
- "AsyncPayoutMethodsResourceWithRawResponse",
- "PayoutMethodsResourceWithStreamingResponse",
- "AsyncPayoutMethodsResourceWithStreamingResponse",
"VerificationsResource",
"AsyncVerificationsResource",
"VerificationsResourceWithRawResponse",
@@ -854,6 +966,12 @@
"AsyncBountiesResourceWithRawResponse",
"BountiesResourceWithStreamingResponse",
"AsyncBountiesResourceWithStreamingResponse",
+ "WorkforceResource",
+ "AsyncWorkforceResource",
+ "WorkforceResourceWithRawResponse",
+ "AsyncWorkforceResourceWithRawResponse",
+ "WorkforceResourceWithStreamingResponse",
+ "AsyncWorkforceResourceWithStreamingResponse",
"AdCampaignsResource",
"AsyncAdCampaignsResource",
"AdCampaignsResourceWithRawResponse",
@@ -872,12 +990,6 @@
"AsyncAdsResourceWithRawResponse",
"AdsResourceWithStreamingResponse",
"AsyncAdsResourceWithStreamingResponse",
- "ConversionsResource",
- "AsyncConversionsResource",
- "ConversionsResourceWithRawResponse",
- "AsyncConversionsResourceWithRawResponse",
- "ConversionsResourceWithStreamingResponse",
- "AsyncConversionsResourceWithStreamingResponse",
"AdReportsResource",
"AsyncAdReportsResource",
"AdReportsResourceWithRawResponse",
diff --git a/src/whop_sdk/resources/access_tokens.py b/src/whop_sdk/resources/access_tokens.py
index 1ebde1681..ec9b78326 100644
--- a/src/whop_sdk/resources/access_tokens.py
+++ b/src/whop_sdk/resources/access_tokens.py
@@ -25,8 +25,6 @@
class AccessTokensResource(SyncAPIResource):
- """Access tokens"""
-
@cached_property
def with_raw_response(self) -> AccessTokensResourceWithRawResponse:
"""
@@ -108,8 +106,6 @@ def create(
class AsyncAccessTokensResource(AsyncAPIResource):
- """Access tokens"""
-
@cached_property
def with_raw_response(self) -> AsyncAccessTokensResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/account_links.py b/src/whop_sdk/resources/account_links.py
index ccfe5cd7f..e362e3fb2 100644
--- a/src/whop_sdk/resources/account_links.py
+++ b/src/whop_sdk/resources/account_links.py
@@ -24,8 +24,6 @@
class AccountLinksResource(SyncAPIResource):
- """Account links"""
-
@cached_property
def with_raw_response(self) -> AccountLinksResourceWithRawResponse:
"""
@@ -103,8 +101,6 @@ def create(
class AsyncAccountLinksResource(AsyncAPIResource):
- """Account links"""
-
@cached_property
def with_raw_response(self) -> AsyncAccountLinksResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/accounts/__init__.py b/src/whop_sdk/resources/accounts/__init__.py
new file mode 100644
index 000000000..1e217b23c
--- /dev/null
+++ b/src/whop_sdk/resources/accounts/__init__.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .accounts import (
+ AccountsResource,
+ AsyncAccountsResource,
+ AccountsResourceWithRawResponse,
+ AsyncAccountsResourceWithRawResponse,
+ AccountsResourceWithStreamingResponse,
+ AsyncAccountsResourceWithStreamingResponse,
+)
+from .preferences import (
+ PreferencesResource,
+ AsyncPreferencesResource,
+ PreferencesResourceWithRawResponse,
+ AsyncPreferencesResourceWithRawResponse,
+ PreferencesResourceWithStreamingResponse,
+ AsyncPreferencesResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "PreferencesResource",
+ "AsyncPreferencesResource",
+ "PreferencesResourceWithRawResponse",
+ "AsyncPreferencesResourceWithRawResponse",
+ "PreferencesResourceWithStreamingResponse",
+ "AsyncPreferencesResourceWithStreamingResponse",
+ "AccountsResource",
+ "AsyncAccountsResource",
+ "AccountsResourceWithRawResponse",
+ "AsyncAccountsResourceWithRawResponse",
+ "AccountsResourceWithStreamingResponse",
+ "AsyncAccountsResourceWithStreamingResponse",
+]
diff --git a/src/whop_sdk/resources/accounts.py b/src/whop_sdk/resources/accounts/accounts.py
similarity index 52%
rename from src/whop_sdk/resources/accounts.py
rename to src/whop_sdk/resources/accounts/accounts.py
index 16264fbde..1ad48bf4b 100644
--- a/src/whop_sdk/resources/accounts.py
+++ b/src/whop_sdk/resources/accounts/accounts.py
@@ -3,28 +3,53 @@
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 .._utils import path_template, maybe_transform, async_maybe_transform
-from .._compat import cached_property
-from .._resource import SyncAPIResource, AsyncAPIResource
-from .._response import (
+from ...types import account_list_params, account_create_params, account_update_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
+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.account import Account
-from ..types.account_list_response import AccountListResponse
+from .preferences import (
+ PreferencesResource,
+ AsyncPreferencesResource,
+ PreferencesResourceWithRawResponse,
+ AsyncPreferencesResourceWithRawResponse,
+ PreferencesResourceWithStreamingResponse,
+ AsyncPreferencesResourceWithStreamingResponse,
+)
+from ...pagination import SyncCursorPage, AsyncCursorPage
+from ..._base_client import AsyncPaginator, make_request_options
+from ...types.account import Account
+from ...types.account_recommend_actions_response import AccountRecommendActionsResponse
__all__ = ["AccountsResource", "AsyncAccountsResource"]
class AccountsResource(SyncAPIResource):
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
+
+ @cached_property
+ def preferences(self) -> PreferencesResource:
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
+ return PreferencesResource(self._client)
+
@cached_property
def with_raw_response(self) -> AccountsResourceWithRawResponse:
"""
@@ -49,6 +74,7 @@ def create(
*,
email: str | Omit = omit,
metadata: Dict[str, object] | 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,
@@ -59,7 +85,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
@@ -67,6 +95,9 @@ def create(
metadata: Arbitrary key/value metadata to store on the account.
+ title: The display name of the account. Defaults to `metadata.external_id` or the
+ owner's email when omitted.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -81,6 +112,7 @@ def create(
{
"email": email,
"metadata": metadata,
+ "title": title,
},
account_create_params.AccountCreateParams,
),
@@ -131,18 +163,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 +213,75 @@ 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.
+ See the available
+ [product categories](https://docs.numeral.com/essentials/product-categories).
+
+ 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 +299,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 +341,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 +361,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 +381,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 +391,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(
@@ -297,8 +426,58 @@ def me(
cast_to=Account,
)
+ def recommend_actions(
+ 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,
+ ) -> AccountRecommendActionsResponse:
+ """
+ Lists the recommended actions computed for the account — the same set embedded
+ on the account resource, served on their own so a caller can fetch just the
+ recommendations.
+
+ 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("/accounts/{account_id}/recommend_actions", account_id=account_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AccountRecommendActionsResponse,
+ )
+
class AsyncAccountsResource(AsyncAPIResource):
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
+
+ @cached_property
+ def preferences(self) -> AsyncPreferencesResource:
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
+ return AsyncPreferencesResource(self._client)
+
@cached_property
def with_raw_response(self) -> AsyncAccountsResourceWithRawResponse:
"""
@@ -323,6 +502,7 @@ async def create(
*,
email: str | Omit = omit,
metadata: Dict[str, object] | 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,
@@ -333,7 +513,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
@@ -341,6 +523,9 @@ async def create(
metadata: Arbitrary key/value metadata to store on the account.
+ title: The display name of the account. Defaults to `metadata.external_id` or the
+ owner's email when omitted.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -355,6 +540,7 @@ async def create(
{
"email": email,
"metadata": metadata,
+ "title": title,
},
account_create_params.AccountCreateParams,
),
@@ -405,18 +591,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 +641,75 @@ 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.
+
+ country: Country where the account is located.
+
+ description: Account promotional description.
+
+ featured_affiliate_product_id: The ID of the product to feature for affiliates. Pass `null` to clear.
- description: A promotional description for the account.
+ home_preferences: Public account home page preferences.
- featured_affiliate_product_id: The ID of the product to feature for affiliates. Pass null to clear.
+ industry_group: Account industry group.
- industry_group: The industry group the account belongs to.
+ industry_type: Specific industry vertical for the account.
- industry_type: The specific industry vertical the account operates in.
+ 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.
+ See the available
+ [product categories](https://docs.numeral.com/essentials/product-categories).
+
+ 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 +727,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 +766,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 +789,17 @@ async def list(
its connected accounts.
Args:
- page: The page number to retrieve
+ after: A cursor; returns accounts after this position.
+
+ 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.
- per: The number of resources to return per page. There is a limit of 50 results per
- page.
+ order: The field to sort accounts by.
extra_headers: Send extra headers
@@ -531,22 +809,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(
@@ -571,6 +854,41 @@ async def me(
cast_to=Account,
)
+ async def recommend_actions(
+ 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,
+ ) -> AccountRecommendActionsResponse:
+ """
+ Lists the recommended actions computed for the account — the same set embedded
+ on the account resource, served on their own so a caller can fetch just the
+ recommendations.
+
+ 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("/accounts/{account_id}/recommend_actions", account_id=account_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AccountRecommendActionsResponse,
+ )
+
class AccountsResourceWithRawResponse:
def __init__(self, accounts: AccountsResource) -> None:
@@ -591,6 +909,18 @@ def __init__(self, accounts: AccountsResource) -> None:
self.me = to_raw_response_wrapper(
accounts.me,
)
+ self.recommend_actions = to_raw_response_wrapper(
+ accounts.recommend_actions,
+ )
+
+ @cached_property
+ def preferences(self) -> PreferencesResourceWithRawResponse:
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
+ return PreferencesResourceWithRawResponse(self._accounts.preferences)
class AsyncAccountsResourceWithRawResponse:
@@ -612,6 +942,18 @@ def __init__(self, accounts: AsyncAccountsResource) -> None:
self.me = async_to_raw_response_wrapper(
accounts.me,
)
+ self.recommend_actions = async_to_raw_response_wrapper(
+ accounts.recommend_actions,
+ )
+
+ @cached_property
+ def preferences(self) -> AsyncPreferencesResourceWithRawResponse:
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
+ return AsyncPreferencesResourceWithRawResponse(self._accounts.preferences)
class AccountsResourceWithStreamingResponse:
@@ -633,6 +975,18 @@ def __init__(self, accounts: AccountsResource) -> None:
self.me = to_streamed_response_wrapper(
accounts.me,
)
+ self.recommend_actions = to_streamed_response_wrapper(
+ accounts.recommend_actions,
+ )
+
+ @cached_property
+ def preferences(self) -> PreferencesResourceWithStreamingResponse:
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
+ return PreferencesResourceWithStreamingResponse(self._accounts.preferences)
class AsyncAccountsResourceWithStreamingResponse:
@@ -654,3 +1008,15 @@ def __init__(self, accounts: AsyncAccountsResource) -> None:
self.me = async_to_streamed_response_wrapper(
accounts.me,
)
+ self.recommend_actions = async_to_streamed_response_wrapper(
+ accounts.recommend_actions,
+ )
+
+ @cached_property
+ def preferences(self) -> AsyncPreferencesResourceWithStreamingResponse:
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
+ return AsyncPreferencesResourceWithStreamingResponse(self._accounts.preferences)
diff --git a/src/whop_sdk/resources/accounts/preferences.py b/src/whop_sdk/resources/accounts/preferences.py
new file mode 100644
index 000000000..1a53bc8e9
--- /dev/null
+++ b/src/whop_sdk/resources/accounts/preferences.py
@@ -0,0 +1,288 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+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.accounts import preference_update_params
+from ...types.accounts.preference_update_response import PreferenceUpdateResponse
+from ...types.accounts.preference_retrieve_response import PreferenceRetrieveResponse
+
+__all__ = ["PreferencesResource", "AsyncPreferencesResource"]
+
+
+class PreferencesResource(SyncAPIResource):
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
+
+ @cached_property
+ def with_raw_response(self) -> PreferencesResourceWithRawResponse:
+ """
+ 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 PreferencesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> PreferencesResourceWithStreamingResponse:
+ """
+ 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 PreferencesResourceWithStreamingResponse(self)
+
+ def retrieve(
+ 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,
+ ) -> PreferenceRetrieveResponse:
+ """
+ Retrieves the account's preferences: a singleton settings document keyed by
+ preference name.
+
+ 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("/accounts/{account_id}/preferences", account_id=account_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=PreferenceRetrieveResponse,
+ )
+
+ def update(
+ self,
+ account_id: str,
+ *,
+ ads_payment_methods: preference_update_params.AdsPaymentMethods | 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,
+ ) -> PreferenceUpdateResponse:
+ """Updates the account's preferences.
+
+ Each top-level key present in the body is
+ replaced as a whole; omitted keys are left untouched. `ads_payment_methods`
+ always requires a `primary` entry. `backup` is optional when the primary is
+ `platform_balance` — omitting it removes any configured card — while a `card`
+ primary requires a `platform_balance` backup. A `platform_balance` entry may
+ omit `id` to use the account's default Whop balance. Changing which funding
+ sources are configured requires a user token, while account API keys may only
+ swap `primary` and `backup`.
+
+ Args:
+ ads_payment_methods: How the account pays for Whop Ads spend. `primary` is charged first; `backup`
+ covers the charge when the primary fails.
+
+ 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._patch(
+ path_template("/accounts/{account_id}/preferences", account_id=account_id),
+ body=maybe_transform(
+ {"ads_payment_methods": ads_payment_methods}, preference_update_params.PreferenceUpdateParams
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=PreferenceUpdateResponse,
+ )
+
+
+class AsyncPreferencesResource(AsyncAPIResource):
+ """
+ An Account represents a person or business on Whop that can have its own profile, wallet, and account-scoped settings. Use accounts for customers, creators, merchants, sellers, or connected businesses your integration supports.
+
+ Use the Accounts API to create accounts, list accounts visible to your credentials, retrieve or update an account, and retrieve the account associated with the current API key.
+ """
+
+ @cached_property
+ def with_raw_response(self) -> AsyncPreferencesResourceWithRawResponse:
+ """
+ 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 AsyncPreferencesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncPreferencesResourceWithStreamingResponse:
+ """
+ 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 AsyncPreferencesResourceWithStreamingResponse(self)
+
+ async def retrieve(
+ 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,
+ ) -> PreferenceRetrieveResponse:
+ """
+ Retrieves the account's preferences: a singleton settings document keyed by
+ preference name.
+
+ 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("/accounts/{account_id}/preferences", account_id=account_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=PreferenceRetrieveResponse,
+ )
+
+ async def update(
+ self,
+ account_id: str,
+ *,
+ ads_payment_methods: preference_update_params.AdsPaymentMethods | 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,
+ ) -> PreferenceUpdateResponse:
+ """Updates the account's preferences.
+
+ Each top-level key present in the body is
+ replaced as a whole; omitted keys are left untouched. `ads_payment_methods`
+ always requires a `primary` entry. `backup` is optional when the primary is
+ `platform_balance` — omitting it removes any configured card — while a `card`
+ primary requires a `platform_balance` backup. A `platform_balance` entry may
+ omit `id` to use the account's default Whop balance. Changing which funding
+ sources are configured requires a user token, while account API keys may only
+ swap `primary` and `backup`.
+
+ Args:
+ ads_payment_methods: How the account pays for Whop Ads spend. `primary` is charged first; `backup`
+ covers the charge when the primary fails.
+
+ 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._patch(
+ path_template("/accounts/{account_id}/preferences", account_id=account_id),
+ body=await async_maybe_transform(
+ {"ads_payment_methods": ads_payment_methods}, preference_update_params.PreferenceUpdateParams
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=PreferenceUpdateResponse,
+ )
+
+
+class PreferencesResourceWithRawResponse:
+ def __init__(self, preferences: PreferencesResource) -> None:
+ self._preferences = preferences
+
+ self.retrieve = to_raw_response_wrapper(
+ preferences.retrieve,
+ )
+ self.update = to_raw_response_wrapper(
+ preferences.update,
+ )
+
+
+class AsyncPreferencesResourceWithRawResponse:
+ def __init__(self, preferences: AsyncPreferencesResource) -> None:
+ self._preferences = preferences
+
+ self.retrieve = async_to_raw_response_wrapper(
+ preferences.retrieve,
+ )
+ self.update = async_to_raw_response_wrapper(
+ preferences.update,
+ )
+
+
+class PreferencesResourceWithStreamingResponse:
+ def __init__(self, preferences: PreferencesResource) -> None:
+ self._preferences = preferences
+
+ self.retrieve = to_streamed_response_wrapper(
+ preferences.retrieve,
+ )
+ self.update = to_streamed_response_wrapper(
+ preferences.update,
+ )
+
+
+class AsyncPreferencesResourceWithStreamingResponse:
+ def __init__(self, preferences: AsyncPreferencesResource) -> None:
+ self._preferences = preferences
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ preferences.retrieve,
+ )
+ self.update = async_to_streamed_response_wrapper(
+ preferences.update,
+ )
diff --git a/src/whop_sdk/resources/ad_campaigns.py b/src/whop_sdk/resources/ad_campaigns.py
index 3cbade585..c42f6f0e6 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,14 +26,18 @@
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"""
+ """An Ad Campaign is the top-level container for paid ads on an ad network.
+
+ It sets the platform, objective, and budget strategy shared by its [ad groups](/api-reference/beta/ad-groups/ad-group) and ads.
+
+ Use the Ad Campaigns API to create campaigns, list campaigns for an account, retrieve or update campaign settings, and pause or resume campaign delivery.
+ """
@cached_property
def with_raw_response(self) -> AdCampaignsResourceWithRawResponse:
@@ -49,10 +58,104 @@ 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,
+ 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,
@@ -61,13 +164,15 @@ 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.
+
+ time_zone: IANA timezone the stats window is interpreted in. Defaults to UTC.
- Args:
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -81,7 +186,18 @@ 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,
+ "time_zone": time_zone,
+ },
+ ad_campaign_retrieve_params.AdCampaignRetrieveParams,
+ ),
),
cast_to=AdCampaign,
)
@@ -90,7 +206,13 @@ def update(
self,
id: str,
*,
- budget: Optional[float] | 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,
+ 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 +221,32 @@ 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, bid strategy,
+ and — before launch — budget optimization), and launches a draft campaign by
+ setting status to active. Objective, budget type, special ad categories and
+ desired cost per result are fixed at creation and cannot be changed.
- Required permissions:
+ Args:
+ bid_type: CBO bid strategy: minimum_cost (lowest cost), average_target (cost cap), or
+ maximum_target (bid cap). Switching to minimum_cost clears the cap amounts
+ stored on the campaign's ad groups. CBO only.
- - `ad_campaign:update`
+ budget_amount: The campaign budget, in the account's currency. Interpreted as daily or lifetime
+ per the campaign's existing budget type.
- Args:
- budget: The campaign budget in dollars. The interpretation (daily or lifetime) follows
- the campaign's existing budget type.
+ budget_optimization: Which level owns the budget — the campaign (CBO) or each ad group (ABO). Only
+ changeable before the campaign is live on Meta; switching to ad_campaign
+ requires budget_amount in the same request, and switching to ad_group clears the
+ campaign budget.
+
+ ends_at: Campaign schedule end (ISO 8601). CBO only.
+
+ 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 +260,18 @@ 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(
+ {
+ "bid_type": bid_type,
+ "budget_amount": budget_amount,
+ "budget_optimization": budget_optimization,
+ "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 +281,80 @@ 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",
+ "reach",
+ "clicks",
+ "unique_clicks",
+ "frequency",
+ "click_through_rate",
+ "results",
+ "cost_per_mille",
+ "cost_per_click",
+ "cost_per_result",
+ "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,
+ 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,
- ) -> 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).
- 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. results, cost_per_result and return_on_ad_spend rank by the same
+ Whop pixel-attributed values the response reports.
- 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.
+
+ time_zone: IANA timezone (e.g. America/New_York) the stats window is interpreted in. Bare
+ stats_from/stats_to dates resolve to day boundaries on this clock. Defaults to
+ UTC.
extra_headers: Send extra headers
@@ -184,7 +366,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 +374,28 @@ 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,
+ "time_zone": time_zone,
},
ad_campaign_list_params.AdCampaignListParams,
),
),
- model=AdCampaignListResponse,
+ model=AdCampaign,
)
- def pause(
+ def delete(
self,
id: str,
*,
@@ -218,13 +405,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.
- 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 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 +476,6 @@ def unpause(
"""
Resumes a paused ad campaign.
- Required permissions:
-
- - `ad_campaign:update`
-
Args:
extra_headers: Send extra headers
@@ -284,7 +497,12 @@ def unpause(
class AsyncAdCampaignsResource(AsyncAPIResource):
- """Ad campaigns"""
+ """An Ad Campaign is the top-level container for paid ads on an ad network.
+
+ It sets the platform, objective, and budget strategy shared by its [ad groups](/api-reference/beta/ad-groups/ad-group) and ads.
+
+ Use the Ad Campaigns API to create campaigns, list campaigns for an account, retrieve or update campaign settings, and pause or resume campaign delivery.
+ """
@cached_property
def with_raw_response(self) -> AsyncAdCampaignsResourceWithRawResponse:
@@ -305,10 +523,104 @@ 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,
+ 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,
@@ -317,13 +629,15 @@ 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.
+
+ Args:
+ stats_from: Start of the stats window.
- Required permissions:
+ stats_to: End of the stats window.
- - `ad_campaign:basic:read`
+ time_zone: IANA timezone the stats window is interpreted in. Defaults to UTC.
- Args:
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -337,7 +651,18 @@ 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,
+ "time_zone": time_zone,
+ },
+ ad_campaign_retrieve_params.AdCampaignRetrieveParams,
+ ),
),
cast_to=AdCampaign,
)
@@ -346,7 +671,13 @@ async def update(
self,
id: str,
*,
- budget: Optional[float] | 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,
+ 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 +686,32 @@ 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, bid strategy,
+ and — before launch — budget optimization), and launches a draft campaign by
+ setting status to active. Objective, budget type, special ad categories and
+ desired cost per result are fixed at creation and cannot be changed.
- Required permissions:
+ Args:
+ bid_type: CBO bid strategy: minimum_cost (lowest cost), average_target (cost cap), or
+ maximum_target (bid cap). Switching to minimum_cost clears the cap amounts
+ stored on the campaign's ad groups. CBO only.
- - `ad_campaign:update`
+ budget_amount: The campaign budget, in the account's currency. Interpreted as daily or lifetime
+ per the campaign's existing budget type.
- Args:
- budget: The campaign budget in dollars. The interpretation (daily or lifetime) follows
- the campaign's existing budget type.
+ budget_optimization: Which level owns the budget — the campaign (CBO) or each ad group (ABO). Only
+ changeable before the campaign is live on Meta; switching to ad_campaign
+ requires budget_amount in the same request, and switching to ad_group clears the
+ campaign budget.
+
+ ends_at: Campaign schedule end (ISO 8601). CBO only.
+
+ 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 +725,18 @@ 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(
+ {
+ "bid_type": bid_type,
+ "budget_amount": budget_amount,
+ "budget_optimization": budget_optimization,
+ "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 +746,80 @@ 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",
+ "reach",
+ "clicks",
+ "unique_clicks",
+ "frequency",
+ "click_through_rate",
+ "results",
+ "cost_per_mille",
+ "cost_per_click",
+ "cost_per_result",
+ "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,
+ 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,
- ) -> 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).
+
+ created_after: Only return campaigns created after this timestamp.
+
+ created_before: Only return campaigns created before this timestamp.
- before: Returns the elements in the list that come before the specified cursor.
+ direction: The sort direction. Defaults to desc.
- company_id: The unique identifier of the company to list ad campaigns for.
+ first: The number of campaigns to return.
- created_after: Only return ad campaigns created after this timestamp.
+ last: The number of campaigns to return from the end of the range.
- created_before: Only return ad campaigns created before this timestamp.
+ 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. results, cost_per_result and return_on_ad_spend rank by the same
+ Whop pixel-attributed values the response reports.
- first: Returns the first _n_ elements from the list.
+ query: Filter campaigns by a title or ID substring.
- last: Returns the last _n_ elements from the list.
+ stats_from: Start of the stats window. Defaults to all-time.
- query: Case-insensitive substring match against the campaign title.
+ stats_to: End of the stats window. Defaults to now.
- status: The status of an ad campaign.
+ status: Only return campaigns with this status.
+
+ time_zone: IANA timezone (e.g. America/New_York) the stats window is interpreted in. Bare
+ stats_from/stats_to dates resolve to day boundaries on this clock. Defaults to
+ UTC.
extra_headers: Send extra headers
@@ -440,7 +831,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 +839,28 @@ 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,
+ "time_zone": time_zone,
},
ad_campaign_list_params.AdCampaignListParams,
),
),
- model=AdCampaignListResponse,
+ model=AdCampaign,
)
- async def pause(
+ async def delete(
self,
id: str,
*,
@@ -474,13 +870,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 +941,6 @@ async def unpause(
"""
Resumes a paused ad campaign.
- Required permissions:
-
- - `ad_campaign:update`
-
Args:
extra_headers: Send extra headers
@@ -543,6 +965,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 +977,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 +992,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 +1004,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 +1019,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 +1031,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 +1046,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 +1058,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 25cdded6c..866283395 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,16 +21,17 @@
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"""
+ """
+ An Ad Group sits inside an [ad campaign](/api-reference/beta/ad-campaigns/ad-campaign) and controls delivery for [ads](/api-reference/beta/ads/ad). It sets the audience, placements, schedule, budget, and optimization goal for its ads.
+
+ Use the Ad Groups API to create ad groups in campaigns, list or retrieve targeting and delivery settings, update budgets or targeting, delete groups that should stop running, and pause or resume delivery.
+ """
@cached_property
def with_raw_response(self) -> AdGroupsResourceWithRawResponse:
@@ -51,10 +52,188 @@ 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 }. Omit positions to
+ target all of a platform's.
+
+ Valid positions per platform:
+
+ - `facebook`: `feed`, `right_hand_column`, `marketplace`, `search`,
+ `profile_feed`, `notification`, `story`, `instream_video`, `facebook_reels`,
+ `facebook_reels_overlay`, `biz_disco_feed`
+ - `instagram`: `stream`, `story`, `explore`, `explore_home`, `reels`,
+ `profile_feed`, `profile_reels`, `ig_search`
+ - `messenger`: `story`
+ - `audience_network`: `classic`, `rewarded_video`
+ - `threads`: `threads_stream`
+ - `whatsapp`: `status`
+
+ 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,
+ 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,
@@ -63,13 +242,15 @@ 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.
+
+ time_zone: IANA timezone the stats window is interpreted in. Defaults to UTC.
- Args:
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -83,7 +264,18 @@ 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,
+ "time_zone": time_zone,
+ },
+ ad_group_retrieve_params.AdGroupRetrieveParams,
+ ),
),
cast_to=AdGroup,
)
@@ -92,13 +284,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 +342,70 @@ def update(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdGroup:
- """
- Updates an existing ad group.
-
- Required permissions:
+ """Updates an ad group's editable fields.
- - `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.
- budget_type: The budget type for an ad campaign or ad group.
+ 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.
- config: Unified ad group configuration (bidding, optimization, targeting).
+ demographics: Demographic targeting: { automatic, minimum_age, maximum_age, gender }.
- daily_budget: Daily budget in dollars.
+ desired_cost_per_result: Target/cap cost for average_target / maximum_target.
- name: Human-readable ad group name.
+ devices: Device targeting: { platforms, operating_systems: [{ os, minimum_version }] }.
- platform_config: Platform-specific ad group configuration.
+ ends_at: Schedule end, ISO 8601.
- status: The status of an external ad group.
+ 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 }. Omit positions to
+ target all of a platform's.
+
+ Valid positions per platform:
+
+ - `facebook`: `feed`, `right_hand_column`, `marketplace`, `search`,
+ `profile_feed`, `notification`, `story`, `instream_video`, `facebook_reels`,
+ `facebook_reels_overlay`, `biz_disco_feed`
+ - `instagram`: `stream`, `story`, `explore`, `explore_home`, `reels`,
+ `profile_feed`, `profile_reels`, `ig_search`
+ - `messenger`: `story`
+ - `audience_network`: `classic`, `rewarded_video`
+ - `threads`: `threads_stream`
+ - `whatsapp`: `status`
+
+ 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 +421,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 +453,82 @@ 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",
+ "reach",
+ "clicks",
+ "unique_clicks",
+ "frequency",
+ "click_through_rate",
+ "results",
+ "cost_per_mille",
+ "cost_per_click",
+ "cost_per_result",
+ "return_on_ad_spend",
+ ]
+ | Omit = omit,
+ query: str | Omit = omit,
+ stats_from: str | Omit = omit,
+ stats_to: str | Omit = omit,
+ status: str | 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,
- ) -> 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.
- include_paused: When false, excludes paused ad groups so pagination matches the dashboard's
- hide-paused toggle.
+ first: The number of ad groups to return.
- last: Returns the last _n_ elements from the list.
+ last: The number of ad groups to return from the end of the range.
- query: Case-insensitive substring match against the ad group name.
+ 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. results, cost_per_result and return_on_ad_spend rank by the same
+ Whop pixel-attributed values the response reports.
- status: The status of an external ad group.
+ query: Filter ad groups by a title or ID substring.
+
+ stats_from: Start of the stats window. Defaults to all-time.
+
+ stats_to: End of the stats window. Defaults to now.
+
+ status: Filter to a status (active, paused, in_review, rejected).
+
+ time_zone: IANA timezone (e.g. America/New_York) the stats window is interpreted in. Bare
+ stats_from/stats_to dates resolve to day boundaries on this clock. Defaults to
+ UTC.
extra_headers: Send extra headers
@@ -222,7 +540,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 +548,26 @@ 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,
+ "time_zone": time_zone,
},
ad_group_list_params.AdGroupListParams,
),
),
- model=AdGroupListResponse,
+ model=AdGroup,
)
def delete(
@@ -259,12 +581,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 +616,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 +649,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,7 +672,11 @@ def unpause(
class AsyncAdGroupsResource(AsyncAPIResource):
- """Ad groups"""
+ """
+ An Ad Group sits inside an [ad campaign](/api-reference/beta/ad-campaigns/ad-campaign) and controls delivery for [ads](/api-reference/beta/ads/ad). It sets the audience, placements, schedule, budget, and optimization goal for its ads.
+
+ Use the Ad Groups API to create ad groups in campaigns, list or retrieve targeting and delivery settings, update budgets or targeting, delete groups that should stop running, and pause or resume delivery.
+ """
@cached_property
def with_raw_response(self) -> AsyncAdGroupsResourceWithRawResponse:
@@ -384,10 +697,188 @@ 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 }. Omit positions to
+ target all of a platform's.
+
+ Valid positions per platform:
+
+ - `facebook`: `feed`, `right_hand_column`, `marketplace`, `search`,
+ `profile_feed`, `notification`, `story`, `instream_video`, `facebook_reels`,
+ `facebook_reels_overlay`, `biz_disco_feed`
+ - `instagram`: `stream`, `story`, `explore`, `explore_home`, `reels`,
+ `profile_feed`, `profile_reels`, `ig_search`
+ - `messenger`: `story`
+ - `audience_network`: `classic`, `rewarded_video`
+ - `threads`: `threads_stream`
+ - `whatsapp`: `status`
+
+ 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,
+ 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,
@@ -396,13 +887,15 @@ 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.
+
+ time_zone: IANA timezone the stats window is interpreted in. Defaults to UTC.
- Args:
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -416,7 +909,18 @@ 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,
+ "time_zone": time_zone,
+ },
+ ad_group_retrieve_params.AdGroupRetrieveParams,
+ ),
),
cast_to=AdGroup,
)
@@ -425,13 +929,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 +987,70 @@ async def update(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdGroup:
- """
- Updates an existing ad group.
-
- Required permissions:
+ """Updates an ad group's editable fields.
- - `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.
+
+ demographics: Demographic targeting: { automatic, minimum_age, maximum_age, gender }.
- budget_type: The budget type for an ad campaign or ad group.
+ desired_cost_per_result: Target/cap cost for average_target / maximum_target.
- config: Unified ad group configuration (bidding, optimization, targeting).
+ devices: Device targeting: { platforms, operating_systems: [{ os, minimum_version }] }.
- daily_budget: Daily budget in dollars.
+ ends_at: Schedule end, ISO 8601.
- name: Human-readable ad group name.
+ frequency_cap: { maximum_impressions, per_days } — only valid for reach optimization.
- platform_config: Platform-specific ad group configuration.
+ languages: Languages to target as ISO 639 codes (e.g. en, es). Empty/omitted = all
+ languages.
- status: The status of an external ad group.
+ 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 }. Omit positions to
+ target all of a platform's.
+
+ Valid positions per platform:
+
+ - `facebook`: `feed`, `right_hand_column`, `marketplace`, `search`,
+ `profile_feed`, `notification`, `story`, `instream_video`, `facebook_reels`,
+ `facebook_reels_overlay`, `biz_disco_feed`
+ - `instagram`: `stream`, `story`, `explore`, `explore_home`, `reels`,
+ `profile_feed`, `profile_reels`, `ig_search`
+ - `messenger`: `story`
+ - `audience_network`: `classic`, `rewarded_video`
+ - `threads`: `threads_stream`
+ - `whatsapp`: `status`
+
+ 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 +1066,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 +1098,82 @@ 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",
+ "reach",
+ "clicks",
+ "unique_clicks",
+ "frequency",
+ "click_through_rate",
+ "results",
+ "cost_per_mille",
+ "cost_per_click",
+ "cost_per_result",
+ "return_on_ad_spend",
+ ]
+ | Omit = omit,
+ query: str | Omit = omit,
+ stats_from: str | Omit = omit,
+ stats_to: str | Omit = omit,
+ status: str | 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,
- ) -> 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. results, cost_per_result and return_on_ad_spend rank by the same
+ Whop pixel-attributed values the response reports.
- 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).
+
+ time_zone: IANA timezone (e.g. America/New_York) the stats window is interpreted in. Bare
+ stats_from/stats_to dates resolve to day boundaries on this clock. Defaults to
+ UTC.
extra_headers: Send extra headers
@@ -555,7 +1185,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 +1193,26 @@ 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,
+ "time_zone": time_zone,
},
ad_group_list_params.AdGroupListParams,
),
),
- model=AdGroupListResponse,
+ model=AdGroup,
)
async def delete(
@@ -592,12 +1226,9 @@ async def delete(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AdGroupDeleteResponse:
- """
- Soft-deletes an ad group.
+ """Deletes an ad group.
- Required permissions:
-
- - `ad_campaign:update`
+ Returns true on success.
Args:
extra_headers: Send extra headers
@@ -630,12 +1261,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 +1294,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 +1320,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 +1347,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 +1374,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 +1401,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 1c8cbd811..3da18cff4 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
@@ -27,8 +27,6 @@
class AdReportsResource(SyncAPIResource):
- """Ad reports"""
-
@cached_property
def with_raw_response(self) -> AdReportsResourceWithRawResponse:
"""
@@ -53,9 +51,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 +65,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 +82,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 +121,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,
@@ -139,8 +137,6 @@ def retrieve(
class AsyncAdReportsResource(AsyncAPIResource):
- """Ad reports"""
-
@cached_property
def with_raw_response(self) -> AsyncAdReportsResourceWithRawResponse:
"""
@@ -165,9 +161,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 +175,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 +192,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 +231,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 fc6351c61..6d6caf2c4 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,15 +21,17 @@
)
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"""
+ """
+ An Ad is the individual creative unit delivered by an [ad group](/api-reference/beta/ad-groups/ad-group). It holds the copy, creative assets, and destination URL for one ad.
+
+ Use the Ads API to list ads for an account, create ads inside ad groups, retrieve or update creative details, delete ads that should stop running, and pause or resume delivery.
+ """
@cached_property
def with_raw_response(self) -> AdsResourceWithRawResponse:
@@ -51,10 +52,153 @@ 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,
+ lead_form_id: str | Omit = omit,
+ messaging_config: ad_create_params.MessagingConfig | Omit = omit,
+ multi_advertiser_ads: bool | Omit = omit,
+ post_id: str | Omit = omit,
+ post_source: Literal["facebook", "instagram"] | 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 creative assets. Each entry is an uploaded file id with an optional
+ format; omit format for the original 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). Mutually exclusive with
+ lead_form_id.
+
+ lead_form_id: Use an existing Meta instant form instead of creating one — the form's Meta id,
+ from a form already on the ad's Facebook page. Only allowed when the ad group's
+ conversion_location is an instant-form destination. Mutually exclusive with
+ lead_form.
+
+ 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. Pair with post_source.
+
+ post_source: Which network post_id refers to — facebook (a page post) or instagram (a media
+ id). Authoritative; when omitted the source is inferred from the id shape.
+
+ 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,
+ "lead_form_id": lead_form_id,
+ "messaging_config": messaging_config,
+ "multi_advertiser_ads": multi_advertiser_ads,
+ "post_id": post_id,
+ "post_source": post_source,
+ "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,
+ 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,
@@ -63,13 +207,15 @@ 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.
+
+ time_zone: IANA timezone the stats window is interpreted in. Defaults to UTC.
- Args:
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -83,80 +229,238 @@ 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,
+ "time_zone": time_zone,
+ },
+ 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,
+ lead_form_id: str | Omit = omit,
+ messaging_config: ad_update_params.MessagingConfig | Omit = omit,
+ multi_advertiser_ads: bool | Omit = omit,
+ post_id: str | Omit = omit,
+ post_source: Literal["facebook", "instagram"] | 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 creative assets. Each entry is an uploaded file id with an optional
+ format; omit format for the original 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). Mutually exclusive with
+ lead_form_id.
+
+ lead_form_id: Use an existing Meta instant form instead of creating one — the form's Meta id,
+ from a form already on the ad's Facebook page. Only allowed when the ad group's
+ conversion_location is an instant-form destination. Mutually exclusive with
+ lead_form. Replaces a stored lead_form.
+
+ 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.
- Required permissions:
+ post_id: Promote an existing post instead of uploading creatives — a Facebook post or
+ Instagram media id. Mutually exclusive with creatives. Pair with post_source.
- - `ad_campaign:basic:read`
+ post_source: Which network post_id refers to — facebook (a page post) or instagram (a media
+ id). Authoritative; when omitted the source is inferred from the id shape.
+
+ 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
+
+ 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,
+ "lead_form_id": lead_form_id,
+ "messaging_config": messaging_config,
+ "multi_advertiser_ads": multi_advertiser_ads,
+ "post_id": post_id,
+ "post_source": post_source,
+ "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",
+ "reach",
+ "clicks",
+ "unique_clicks",
+ "frequency",
+ "click_through_rate",
+ "results",
+ "cost_per_mille",
+ "cost_per_click",
+ "cost_per_result",
+ "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,
+ 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,
+ ) -> 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. results, cost_per_result and return_on_ad_spend rank by the same
+ Whop pixel-attributed values the response reports.
- 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: Only return ads with this status.
- status: The status of an external ad.
+ time_zone: IANA timezone (e.g. America/New_York) the stats window is interpreted in. Bare
+ stats_from/stats_to dates resolve to day boundaries on this clock. Defaults to
+ UTC.
extra_headers: Send extra headers
@@ -168,7 +472,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,27 +480,61 @@ 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,
"status": status,
+ "time_zone": time_zone,
},
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 +549,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 +584,6 @@ def unpause(
"""
Resumes a paused ad.
- Required permissions:
-
- - `ad_campaign:update`
- - `ad_campaign:basic:read`
-
Args:
extra_headers: Send extra headers
@@ -277,7 +605,11 @@ def unpause(
class AsyncAdsResource(AsyncAPIResource):
- """Ads"""
+ """
+ An Ad is the individual creative unit delivered by an [ad group](/api-reference/beta/ad-groups/ad-group). It holds the copy, creative assets, and destination URL for one ad.
+
+ Use the Ads API to list ads for an account, create ads inside ad groups, retrieve or update creative details, delete ads that should stop running, and pause or resume delivery.
+ """
@cached_property
def with_raw_response(self) -> AsyncAdsResourceWithRawResponse:
@@ -298,10 +630,153 @@ 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,
+ lead_form_id: str | Omit = omit,
+ messaging_config: ad_create_params.MessagingConfig | Omit = omit,
+ multi_advertiser_ads: bool | Omit = omit,
+ post_id: str | Omit = omit,
+ post_source: Literal["facebook", "instagram"] | 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 creative assets. Each entry is an uploaded file id with an optional
+ format; omit format for the original 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). Mutually exclusive with
+ lead_form_id.
+
+ lead_form_id: Use an existing Meta instant form instead of creating one — the form's Meta id,
+ from a form already on the ad's Facebook page. Only allowed when the ad group's
+ conversion_location is an instant-form destination. Mutually exclusive with
+ lead_form.
+
+ 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. Pair with post_source.
+
+ post_source: Which network post_id refers to — facebook (a page post) or instagram (a media
+ id). Authoritative; when omitted the source is inferred from the id shape.
+
+ 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,
+ "lead_form_id": lead_form_id,
+ "messaging_config": messaging_config,
+ "multi_advertiser_ads": multi_advertiser_ads,
+ "post_id": post_id,
+ "post_source": post_source,
+ "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,
+ 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,
@@ -310,13 +785,15 @@ 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.
+
+ time_zone: IANA timezone the stats window is interpreted in. Defaults to UTC.
- Args:
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -330,80 +807,238 @@ 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,
+ "time_zone": time_zone,
+ },
+ 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,
+ lead_form_id: str | Omit = omit,
+ messaging_config: ad_update_params.MessagingConfig | Omit = omit,
+ multi_advertiser_ads: bool | Omit = omit,
+ post_id: str | Omit = omit,
+ post_source: Literal["facebook", "instagram"] | 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 creative assets. Each entry is an uploaded file id with an optional
+ format; omit format for the original 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). Mutually exclusive with
+ lead_form_id.
+
+ lead_form_id: Use an existing Meta instant form instead of creating one — the form's Meta id,
+ from a form already on the ad's Facebook page. Only allowed when the ad group's
+ conversion_location is an instant-form destination. Mutually exclusive with
+ lead_form. Replaces a stored lead_form.
+
+ 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. Pair with post_source.
+
+ post_source: Which network post_id refers to — facebook (a page post) or instagram (a media
+ id). Authoritative; when omitted the source is inferred from the id shape.
+
+ 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.
- Required permissions:
+ url_parameters: Query parameters appended to the destination URL, as a string-to-string map.
- - `ad_campaign:basic:read`
+ 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._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,
+ "lead_form_id": lead_form_id,
+ "messaging_config": messaging_config,
+ "multi_advertiser_ads": multi_advertiser_ads,
+ "post_id": post_id,
+ "post_source": post_source,
+ "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",
+ "reach",
+ "clicks",
+ "unique_clicks",
+ "frequency",
+ "click_through_rate",
+ "results",
+ "cost_per_mille",
+ "cost_per_click",
+ "cost_per_result",
+ "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,
+ 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,
+ ) -> 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. results, cost_per_result and return_on_ad_spend rank by the same
+ Whop pixel-attributed values the response reports.
- 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: Only return ads with this status.
- status: The status of an external ad.
+ time_zone: IANA timezone (e.g. America/New_York) the stats window is interpreted in. Bare
+ stats_from/stats_to dates resolve to day boundaries on this clock. Defaults to
+ UTC.
extra_headers: Send extra headers
@@ -415,7 +1050,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,27 +1058,61 @@ 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,
"status": status,
+ "time_zone": time_zone,
},
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 +1127,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 +1162,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 +1186,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 +1213,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 +1240,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 +1267,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/affiliates/affiliates.py b/src/whop_sdk/resources/affiliates/affiliates.py
index 75b951ecb..9415c9439 100644
--- a/src/whop_sdk/resources/affiliates/affiliates.py
+++ b/src/whop_sdk/resources/affiliates/affiliates.py
@@ -39,11 +39,8 @@
class AffiliatesResource(SyncAPIResource):
- """Affiliates"""
-
@cached_property
def overrides(self) -> OverridesResource:
- """Affiliates"""
return OverridesResource(self._client)
@cached_property
@@ -305,11 +302,8 @@ def unarchive(
class AsyncAffiliatesResource(AsyncAPIResource):
- """Affiliates"""
-
@cached_property
def overrides(self) -> AsyncOverridesResource:
- """Affiliates"""
return AsyncOverridesResource(self._client)
@cached_property
@@ -592,7 +586,6 @@ def __init__(self, affiliates: AffiliatesResource) -> None:
@cached_property
def overrides(self) -> OverridesResourceWithRawResponse:
- """Affiliates"""
return OverridesResourceWithRawResponse(self._affiliates.overrides)
@@ -618,7 +611,6 @@ def __init__(self, affiliates: AsyncAffiliatesResource) -> None:
@cached_property
def overrides(self) -> AsyncOverridesResourceWithRawResponse:
- """Affiliates"""
return AsyncOverridesResourceWithRawResponse(self._affiliates.overrides)
@@ -644,7 +636,6 @@ def __init__(self, affiliates: AffiliatesResource) -> None:
@cached_property
def overrides(self) -> OverridesResourceWithStreamingResponse:
- """Affiliates"""
return OverridesResourceWithStreamingResponse(self._affiliates.overrides)
@@ -670,5 +661,4 @@ def __init__(self, affiliates: AsyncAffiliatesResource) -> None:
@cached_property
def overrides(self) -> AsyncOverridesResourceWithStreamingResponse:
- """Affiliates"""
return AsyncOverridesResourceWithStreamingResponse(self._affiliates.overrides)
diff --git a/src/whop_sdk/resources/affiliates/overrides.py b/src/whop_sdk/resources/affiliates/overrides.py
index 351eab61d..3ee1c17bc 100644
--- a/src/whop_sdk/resources/affiliates/overrides.py
+++ b/src/whop_sdk/resources/affiliates/overrides.py
@@ -42,8 +42,6 @@
class OverridesResource(SyncAPIResource):
- """Affiliates"""
-
@cached_property
def with_raw_response(self) -> OverridesResourceWithRawResponse:
"""
@@ -409,8 +407,6 @@ def delete(
class AsyncOverridesResource(AsyncAPIResource):
- """Affiliates"""
-
@cached_property
def with_raw_response(self) -> AsyncOverridesResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/ai_chats.py b/src/whop_sdk/resources/ai_chats.py
index eac7df786..28bb7e3ff 100644
--- a/src/whop_sdk/resources/ai_chats.py
+++ b/src/whop_sdk/resources/ai_chats.py
@@ -29,8 +29,6 @@
class AIChatsResource(SyncAPIResource):
- """Ai chats"""
-
@cached_property
def with_raw_response(self) -> AIChatsResourceWithRawResponse:
"""
@@ -303,8 +301,6 @@ def delete(
class AsyncAIChatsResource(AsyncAPIResource):
- """Ai chats"""
-
@cached_property
def with_raw_response(self) -> AsyncAIChatsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/app_builds.py b/src/whop_sdk/resources/app_builds.py
index 4ba62adfa..6b4860664 100644
--- a/src/whop_sdk/resources/app_builds.py
+++ b/src/whop_sdk/resources/app_builds.py
@@ -30,8 +30,6 @@
class AppBuildsResource(SyncAPIResource):
- """App builds"""
-
@cached_property
def with_raw_response(self) -> AppBuildsResourceWithRawResponse:
"""
@@ -79,7 +77,7 @@ def create(
Args:
attachment: The build file to upload. For iOS and Android, this should be a .zip archive
containing a main_js_bundle.hbc file and an optional assets folder. For web,
- this should be a JavaScript file.
+ this should be a JavaScript file or a .zip archive of the hosted site.
checksum: A client-generated checksum of the build file, used to verify file integrity
when unpacked on a device.
@@ -278,8 +276,6 @@ def promote(
class AsyncAppBuildsResource(AsyncAPIResource):
- """App builds"""
-
@cached_property
def with_raw_response(self) -> AsyncAppBuildsResourceWithRawResponse:
"""
@@ -327,7 +323,7 @@ async def create(
Args:
attachment: The build file to upload. For iOS and Android, this should be a .zip archive
containing a main_js_bundle.hbc file and an optional assets folder. For web,
- this should be a JavaScript file.
+ this should be a JavaScript file or a .zip archive of the hosted site.
checksum: A client-generated checksum of the build file, used to verify file integrity
when unpacked on a device.
diff --git a/src/whop_sdk/resources/apps.py b/src/whop_sdk/resources/apps.py
index b83942a11..4ebfc759f 100644
--- a/src/whop_sdk/resources/apps.py
+++ b/src/whop_sdk/resources/apps.py
@@ -2,12 +2,13 @@
from __future__ import annotations
-from typing import List, Optional
+from typing import Dict, List, Union, Optional
+from datetime import datetime
from typing_extensions import Literal
import httpx
-from ..types import AppType, app_list_params, app_create_params, app_update_params
+from ..types import AppType, app_list_params, app_logs_params, app_create_params, app_update_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
@@ -24,6 +25,7 @@
from ..types.shared.app import App
from ..types.shared.direction import Direction
from ..types.app_list_response import AppListResponse
+from ..types.app_logs_response import AppLogsResponse
from ..types.shared.app_statuses import AppStatuses
from ..types.shared.app_view_type import AppViewType
@@ -31,7 +33,12 @@
class AppsResource(SyncAPIResource):
- """Apps"""
+ """An App is software you build on Whop.
+
+ It can be a hosted web app served at `.whop.app` or an API integration installed as an experience, and it belongs to the account that owns its credentials, settings, builds, and runtime logs.
+
+ Use the Apps API to manage app configuration and, for hosted apps, read server runtime logs for console output, uncaught exceptions, and failed requests. Logs are retained for 7 days and can be filtered by build, level, time window, and message text.
+ """
@cached_property
def with_raw_response(self) -> AppsResourceWithRawResponse:
@@ -60,6 +67,7 @@ def create(
base_url: Optional[str] | Omit = omit,
icon: Optional[app_create_params.Icon] | Omit = omit,
redirect_uris: Optional[SequenceNotStr[str]] | Omit = omit,
+ route: 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,
@@ -76,6 +84,7 @@ def create(
- `developer:create_app`
- `developer:manage_api_key`
+ - `developer:update_app`
Args:
company_id: The unique identifier of the company to create the app for, starting with
@@ -91,6 +100,9 @@ def create(
redirect_uris: The whitelisted OAuth callback URLs that users are redirected to after
authorizing the app.
+ route: The unique subdomain route where the app's hosted web builds are served, such as
+ 'myapp' for myapp.whop.app.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -108,6 +120,7 @@ def create(
"base_url": base_url,
"icon": icon,
"redirect_uris": redirect_uris,
+ "route": route,
},
app_create_params.AppCreateParams,
),
@@ -134,6 +147,7 @@ def retrieve(
Required permissions:
- `developer:manage_api_key`
+ - `developer:update_app`
Args:
extra_headers: Send extra headers
@@ -171,6 +185,8 @@ def update(
openapi_path: Optional[str] | Omit = omit,
redirect_uris: Optional[SequenceNotStr[str]] | Omit = omit,
required_scopes: Optional[List[Literal["read_user"]]] | Omit = omit,
+ route: Optional[str] | Omit = omit,
+ secrets: Optional[Dict[str, object]] | Omit = omit,
skills_path: Optional[str] | Omit = omit,
status: Optional[AppStatuses] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -220,6 +236,14 @@ def update(
required_scopes: The permission scopes the app will request from users when they install it.
+ route: The unique subdomain route where the app's hosted web builds are served, such as
+ 'myapp' for myapp.whop.app.
+
+ secrets: Secrets to add or overwrite on the app, as an object of string values (e.g.
+ {"MAIL_API_KEY": "..."}). Keys not included are left untouched. Pass null or an
+ empty string as the value to delete a secret. Secrets are encrypted at rest and
+ injected into the app's hosted server runtime as environment bindings.
+
skills_path: The URL path to the skills directory of the app, such as '/assets/skills/'.
status: The status of an experience interface
@@ -251,6 +275,8 @@ def update(
"openapi_path": openapi_path,
"redirect_uris": redirect_uris,
"required_scopes": required_scopes,
+ "route": route,
+ "secrets": secrets,
"skills_path": skills_path,
"status": status,
},
@@ -363,9 +389,90 @@ def list(
model=AppListResponse,
)
+ def logs(
+ self,
+ id: str,
+ *,
+ after: str | Omit = omit,
+ app_build_id: str | Omit = omit,
+ before: str | Omit = omit,
+ created_after: Union[str, datetime] | Omit = omit,
+ created_before: Union[str, datetime] | Omit = omit,
+ first: int | Omit = omit,
+ level: Literal["log", "debug", "info", "warn", "error"] | 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,
+ ) -> AppLogsResponse:
+ """
+ Lists a hosted app's server runtime logs, most recent first: console output,
+ uncaught exceptions, and failed-request summaries captured on whop.app hosting.
+ Logs are retained for 7 days.
+
+ Args:
+ after: A cursor for fetching logs after a previous page.
+
+ app_build_id: Only return logs from this build.
+
+ before: A cursor for fetching logs before a later page.
+
+ created_after: Start of the time window as an ISO 8601 timestamp. Defaults to 7 days before
+ created_before.
+
+ created_before: End of the time window as an ISO 8601 timestamp. Defaults to now.
+
+ first: The number of log lines to return (max 500).
+
+ level: Only return console lines of this level.
+
+ query: Only return logs whose message contains this text (case-insensitive).
+
+ 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("/apps/{id}/logs", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "after": after,
+ "app_build_id": app_build_id,
+ "before": before,
+ "created_after": created_after,
+ "created_before": created_before,
+ "first": first,
+ "level": level,
+ "query": query,
+ },
+ app_logs_params.AppLogsParams,
+ ),
+ ),
+ cast_to=AppLogsResponse,
+ )
+
class AsyncAppsResource(AsyncAPIResource):
- """Apps"""
+ """An App is software you build on Whop.
+
+ It can be a hosted web app served at `.whop.app` or an API integration installed as an experience, and it belongs to the account that owns its credentials, settings, builds, and runtime logs.
+
+ Use the Apps API to manage app configuration and, for hosted apps, read server runtime logs for console output, uncaught exceptions, and failed requests. Logs are retained for 7 days and can be filtered by build, level, time window, and message text.
+ """
@cached_property
def with_raw_response(self) -> AsyncAppsResourceWithRawResponse:
@@ -394,6 +501,7 @@ async def create(
base_url: Optional[str] | Omit = omit,
icon: Optional[app_create_params.Icon] | Omit = omit,
redirect_uris: Optional[SequenceNotStr[str]] | Omit = omit,
+ route: 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,
@@ -410,6 +518,7 @@ async def create(
- `developer:create_app`
- `developer:manage_api_key`
+ - `developer:update_app`
Args:
company_id: The unique identifier of the company to create the app for, starting with
@@ -425,6 +534,9 @@ async def create(
redirect_uris: The whitelisted OAuth callback URLs that users are redirected to after
authorizing the app.
+ route: The unique subdomain route where the app's hosted web builds are served, such as
+ 'myapp' for myapp.whop.app.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -442,6 +554,7 @@ async def create(
"base_url": base_url,
"icon": icon,
"redirect_uris": redirect_uris,
+ "route": route,
},
app_create_params.AppCreateParams,
),
@@ -468,6 +581,7 @@ async def retrieve(
Required permissions:
- `developer:manage_api_key`
+ - `developer:update_app`
Args:
extra_headers: Send extra headers
@@ -505,6 +619,8 @@ async def update(
openapi_path: Optional[str] | Omit = omit,
redirect_uris: Optional[SequenceNotStr[str]] | Omit = omit,
required_scopes: Optional[List[Literal["read_user"]]] | Omit = omit,
+ route: Optional[str] | Omit = omit,
+ secrets: Optional[Dict[str, object]] | Omit = omit,
skills_path: Optional[str] | Omit = omit,
status: Optional[AppStatuses] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -554,6 +670,14 @@ async def update(
required_scopes: The permission scopes the app will request from users when they install it.
+ route: The unique subdomain route where the app's hosted web builds are served, such as
+ 'myapp' for myapp.whop.app.
+
+ secrets: Secrets to add or overwrite on the app, as an object of string values (e.g.
+ {"MAIL_API_KEY": "..."}). Keys not included are left untouched. Pass null or an
+ empty string as the value to delete a secret. Secrets are encrypted at rest and
+ injected into the app's hosted server runtime as environment bindings.
+
skills_path: The URL path to the skills directory of the app, such as '/assets/skills/'.
status: The status of an experience interface
@@ -585,6 +709,8 @@ async def update(
"openapi_path": openapi_path,
"redirect_uris": redirect_uris,
"required_scopes": required_scopes,
+ "route": route,
+ "secrets": secrets,
"skills_path": skills_path,
"status": status,
},
@@ -697,6 +823,82 @@ def list(
model=AppListResponse,
)
+ async def logs(
+ self,
+ id: str,
+ *,
+ after: str | Omit = omit,
+ app_build_id: str | Omit = omit,
+ before: str | Omit = omit,
+ created_after: Union[str, datetime] | Omit = omit,
+ created_before: Union[str, datetime] | Omit = omit,
+ first: int | Omit = omit,
+ level: Literal["log", "debug", "info", "warn", "error"] | 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,
+ ) -> AppLogsResponse:
+ """
+ Lists a hosted app's server runtime logs, most recent first: console output,
+ uncaught exceptions, and failed-request summaries captured on whop.app hosting.
+ Logs are retained for 7 days.
+
+ Args:
+ after: A cursor for fetching logs after a previous page.
+
+ app_build_id: Only return logs from this build.
+
+ before: A cursor for fetching logs before a later page.
+
+ created_after: Start of the time window as an ISO 8601 timestamp. Defaults to 7 days before
+ created_before.
+
+ created_before: End of the time window as an ISO 8601 timestamp. Defaults to now.
+
+ first: The number of log lines to return (max 500).
+
+ level: Only return console lines of this level.
+
+ query: Only return logs whose message contains this text (case-insensitive).
+
+ 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("/apps/{id}/logs", 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(
+ {
+ "after": after,
+ "app_build_id": app_build_id,
+ "before": before,
+ "created_after": created_after,
+ "created_before": created_before,
+ "first": first,
+ "level": level,
+ "query": query,
+ },
+ app_logs_params.AppLogsParams,
+ ),
+ ),
+ cast_to=AppLogsResponse,
+ )
+
class AppsResourceWithRawResponse:
def __init__(self, apps: AppsResource) -> None:
@@ -714,6 +916,9 @@ def __init__(self, apps: AppsResource) -> None:
self.list = to_raw_response_wrapper(
apps.list,
)
+ self.logs = to_raw_response_wrapper(
+ apps.logs,
+ )
class AsyncAppsResourceWithRawResponse:
@@ -732,6 +937,9 @@ def __init__(self, apps: AsyncAppsResource) -> None:
self.list = async_to_raw_response_wrapper(
apps.list,
)
+ self.logs = async_to_raw_response_wrapper(
+ apps.logs,
+ )
class AppsResourceWithStreamingResponse:
@@ -750,6 +958,9 @@ def __init__(self, apps: AppsResource) -> None:
self.list = to_streamed_response_wrapper(
apps.list,
)
+ self.logs = to_streamed_response_wrapper(
+ apps.logs,
+ )
class AsyncAppsResourceWithStreamingResponse:
@@ -768,3 +979,6 @@ def __init__(self, apps: AsyncAppsResource) -> None:
self.list = async_to_streamed_response_wrapper(
apps.list,
)
+ self.logs = async_to_streamed_response_wrapper(
+ apps.logs,
+ )
diff --git a/src/whop_sdk/resources/audiences.py b/src/whop_sdk/resources/audiences.py
new file mode 100644
index 000000000..1f2705e19
--- /dev/null
+++ b/src/whop_sdk/resources/audiences.py
@@ -0,0 +1,425 @@
+# 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):
+ """An Audience represents a customer list uploaded to Whop for ad targeting.
+
+ Audiences belong to an account and sync to supported ad platforms as custom audiences.
+
+ Use the Audiences API to create audiences from CSV uploads, monitor processing status, and list or delete audiences for an account. Created audiences are usable for targeting after processing reaches `ready` or `partial`.
+ """
+
+ @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):
+ """An Audience represents a customer list uploaded to Whop for ad targeting.
+
+ Audiences belong to an account and sync to supported ad platforms as custom audiences.
+
+ Use the Audiences API to create audiences from CSV uploads, monitor processing status, and list or delete audiences for an account. Created audiences are usable for targeting after processing reaches `ready` or `partial`.
+ """
+
+ @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 0519e3e2b..4c2bf0b32 100644
--- a/src/whop_sdk/resources/authorized_users.py
+++ b/src/whop_sdk/resources/authorized_users.py
@@ -29,8 +29,6 @@
class AuthorizedUsersResource(SyncAPIResource):
- """Authorized users"""
-
@cached_property
def with_raw_response(self) -> AuthorizedUsersResourceWithRawResponse:
"""
@@ -56,6 +54,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 +80,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 +99,7 @@ def create(
"company_id": company_id,
"role": role,
"user_id": user_id,
+ "elevation": elevation,
"send_emails": send_emails,
},
authorized_user_create_params.AuthorizedUserCreateParams,
@@ -277,8 +279,6 @@ def delete(
class AsyncAuthorizedUsersResource(AsyncAPIResource):
- """Authorized users"""
-
@cached_property
def with_raw_response(self) -> AsyncAuthorizedUsersResourceWithRawResponse:
"""
@@ -304,6 +304,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 +330,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 +349,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 ea3966952..e467feb79 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
@@ -30,8 +31,6 @@
class BountiesResource(SyncAPIResource):
- """Bounties"""
-
@cached_property
def with_raw_response(self) -> BountiesResourceWithRawResponse:
"""
@@ -60,10 +59,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 +86,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 +96,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 +117,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 +143,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 +202,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,
@@ -243,8 +266,6 @@ def list(
class AsyncBountiesResource(AsyncAPIResource):
- """Bounties"""
-
@cached_property
def with_raw_response(self) -> AsyncBountiesResourceWithRawResponse:
"""
@@ -273,10 +294,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 +321,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 +331,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 +352,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 +378,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 +437,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 000000000..aa8a8f449
--- /dev/null
+++ b/src/whop_sdk/resources/cards.py
@@ -0,0 +1,684 @@
+# 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_update_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_update_response import CardUpdateResponse
+from ..types.card_retrieve_response import CardRetrieveResponse
+
+__all__ = ["CardsResource", "AsyncCardsResource"]
+
+
+class CardsResource(SyncAPIResource):
+ """
+ Cards represent Whop-issued virtual payment cards that spend from an account or user balance. Cards can be assigned to cardholders and configured with spending limits for controlled spending.
+
+ Use the Cards API to issue cards, list cards for an account or user, and retrieve active card details such as the card number and CVC.
+ """
+
+ @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 update(
+ self,
+ card_id: str,
+ *,
+ account_id: str | Omit = omit,
+ billing: card_update_params.Billing | Omit = omit,
+ canceled: bool | Omit = omit,
+ frozen: bool | Omit = omit,
+ name: str | Omit = omit,
+ pin: str | Omit = omit,
+ remove_limit: bool | 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,
+ ) -> CardUpdateResponse:
+ """Updates an issued card.
+
+ All fields are optional; only the fields you pass are
+ changed. Updates the card name, billing address, and spending limits in one
+ call, sets a new PIN, freezes or unfreezes the card, or cancels it. Pass
+ canceled: true alone to cancel the card — cancellation is permanent and a
+ canceled card cannot be uncanceled. Pass exactly one of account*id (a biz*
+ identifier) or user*id (a user* identifier). Assigned cardholders without the
+ payout:account:update scope can update the PIN and freeze state of their own
+ card. The PIN can only be changed on a card assigned to the acting user. Returns
+ the updated card resource.
+
+ Args:
+ account_id: The owning account ID (a biz\\__ identifier). Provide this or user_id.
+
+ billing: New billing address. Requires line1, city, region, postal_code, and
+ country_code.
+
+ canceled: Pass `true` to permanently cancel the card. A canceled card cannot be
+ uncanceled. Cannot be combined with other fields.
+
+ frozen: Pass `true` to freeze the card, `false` to unfreeze it.
+
+ name: A display name for the card.
+
+ pin: New 4-digit PIN. Can only be set on a card assigned to the acting user.
+
+ remove_limit: Pass `true` to remove the spending limit (make the card unlimited).
+
+ 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
+ """
+ if not card_id:
+ raise ValueError(f"Expected a non-empty value for `card_id` but received {card_id!r}")
+ return self._patch(
+ path_template("/cards/{card_id}", card_id=card_id),
+ body=maybe_transform(
+ {
+ "account_id": account_id,
+ "billing": billing,
+ "canceled": canceled,
+ "frozen": frozen,
+ "name": name,
+ "pin": pin,
+ "remove_limit": remove_limit,
+ "spend_limit": spend_limit,
+ "spend_limit_frequency": spend_limit_frequency,
+ "transaction_limit": transaction_limit,
+ "user_id": user_id,
+ },
+ card_update_params.CardUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=CardUpdateResponse,
+ )
+
+ 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):
+ """
+ Cards represent Whop-issued virtual payment cards that spend from an account or user balance. Cards can be assigned to cardholders and configured with spending limits for controlled spending.
+
+ Use the Cards API to issue cards, list cards for an account or user, and retrieve active card details such as the card number and CVC.
+ """
+
+ @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 update(
+ self,
+ card_id: str,
+ *,
+ account_id: str | Omit = omit,
+ billing: card_update_params.Billing | Omit = omit,
+ canceled: bool | Omit = omit,
+ frozen: bool | Omit = omit,
+ name: str | Omit = omit,
+ pin: str | Omit = omit,
+ remove_limit: bool | 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,
+ ) -> CardUpdateResponse:
+ """Updates an issued card.
+
+ All fields are optional; only the fields you pass are
+ changed. Updates the card name, billing address, and spending limits in one
+ call, sets a new PIN, freezes or unfreezes the card, or cancels it. Pass
+ canceled: true alone to cancel the card — cancellation is permanent and a
+ canceled card cannot be uncanceled. Pass exactly one of account*id (a biz*
+ identifier) or user*id (a user* identifier). Assigned cardholders without the
+ payout:account:update scope can update the PIN and freeze state of their own
+ card. The PIN can only be changed on a card assigned to the acting user. Returns
+ the updated card resource.
+
+ Args:
+ account_id: The owning account ID (a biz\\__ identifier). Provide this or user_id.
+
+ billing: New billing address. Requires line1, city, region, postal_code, and
+ country_code.
+
+ canceled: Pass `true` to permanently cancel the card. A canceled card cannot be
+ uncanceled. Cannot be combined with other fields.
+
+ frozen: Pass `true` to freeze the card, `false` to unfreeze it.
+
+ name: A display name for the card.
+
+ pin: New 4-digit PIN. Can only be set on a card assigned to the acting user.
+
+ remove_limit: Pass `true` to remove the spending limit (make the card unlimited).
+
+ 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
+ """
+ if not card_id:
+ raise ValueError(f"Expected a non-empty value for `card_id` but received {card_id!r}")
+ return await self._patch(
+ path_template("/cards/{card_id}", card_id=card_id),
+ body=await async_maybe_transform(
+ {
+ "account_id": account_id,
+ "billing": billing,
+ "canceled": canceled,
+ "frozen": frozen,
+ "name": name,
+ "pin": pin,
+ "remove_limit": remove_limit,
+ "spend_limit": spend_limit,
+ "spend_limit_frequency": spend_limit_frequency,
+ "transaction_limit": transaction_limit,
+ "user_id": user_id,
+ },
+ card_update_params.CardUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=CardUpdateResponse,
+ )
+
+ 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.update = to_raw_response_wrapper(
+ cards.update,
+ )
+ 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.update = async_to_raw_response_wrapper(
+ cards.update,
+ )
+ 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.update = to_streamed_response_wrapper(
+ cards.update,
+ )
+ 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.update = async_to_streamed_response_wrapper(
+ cards.update,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ cards.list,
+ )
diff --git a/src/whop_sdk/resources/chat_channels.py b/src/whop_sdk/resources/chat_channels.py
index 0c2ad4727..ef5da1a13 100644
--- a/src/whop_sdk/resources/chat_channels.py
+++ b/src/whop_sdk/resources/chat_channels.py
@@ -28,8 +28,6 @@
class ChatChannelsResource(SyncAPIResource):
- """Chat channels"""
-
@cached_property
def with_raw_response(self) -> ChatChannelsResourceWithRawResponse:
"""
@@ -226,8 +224,6 @@ def list(
class AsyncChatChannelsResource(AsyncAPIResource):
- """Chat channels"""
-
@cached_property
def with_raw_response(self) -> AsyncChatChannelsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/checkout_configurations.py b/src/whop_sdk/resources/checkout_configurations.py
index b2e70eeb7..9bba37db3 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,16 +20,20 @@
)
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"""
+ """A Checkout Configuration is a reusable checkout link owned by an account.
+
+ In `payment` mode it sells a specific plan; in `setup` mode it collects and saves payment details without charging. Each configuration can also override which payment methods are accepted and how 3D Secure is enforced for that checkout.
+
+ Use the Checkout Configurations API to create checkout links for an existing or inline plan, list configurations for an account, retrieve the configuration behind a checkout URL, and delete links that should no longer be used.
+ """
@cached_property
def with_raw_response(self) -> CheckoutConfigurationsResourceWithRawResponse:
@@ -51,136 +54,53 @@ 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
- ]
+ 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[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:
+ ) -> CheckoutConfigurationCreateResponse:
"""
- Creates a new checkout configuration
-
- Required permissions:
-
- - `checkout_configuration:create`
- - `plan:create`
- - `access_pass:create`
- - `access_pass:update`
- - `checkout_configuration:basic:read`
+ Creates a reusable checkout configuration for an existing or inline plan.
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:
+ affiliate_code: Affiliate code to apply to the checkout.
- - `checkout_configuration:create`
- - `plan:create`
- - `access_pass:create`
- - `access_pass:update`
- - `checkout_configuration:basic:read`
+ company_id: Account ID, prefixed `biz_`.
- Args:
- plan_id: The unique identifier of an existing plan to use for this checkout
- configuration.
+ currency: Currency used for setup-mode payment method availability.
- affiliate_code: An affiliate tracking code to attribute the checkout to a specific affiliate.
+ metadata: Custom key-value metadata copied to payments and memberships.
- allow_promo_codes: Whether the checkout should show the promo code input field and accept promo
- codes. Defaults to true.
+ mode: Checkout mode: `payment` collects payment for a plan now; `setup` saves payment
+ details without charging. Defaults to `payment`.
- checkout_styling: Checkout styling overrides for this session. Overrides plan and company
+ payment_method_configuration: Payment method overrides for this checkout. `null` uses the plan or platform
defaults.
- currency: The available currencies on the platform
-
- metadata: Custom key-value metadata to attach to the checkout configuration.
+ plan: Plan attributes used to create or find a plan for this checkout configuration.
+ Mutually exclusive with `plan_id`.
- 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_id: Existing plan ID, prefixed `plan_`. Mutually exclusive with `plan`.
- redirect_url: The URL to redirect the user to after checkout is completed.
+ redirect_url: URL customers are sent to after checkout.
- source_url: The URL of the page where the checkout is being initiated from.
+ three_ds_level: 3D Secure behavior for this checkout.
extra_headers: Send extra headers
@@ -190,131 +110,19 @@ def create(
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
- ]
- | Omit = omit,
- redirect_url: Optional[str] | Omit = omit,
- source_url: Optional[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:
- """
- Creates a new checkout configuration
-
- Required permissions:
-
- - `checkout_configuration:create`
- - `plan:create`
- - `access_pass:create`
- - `access_pass:update`
- - `checkout_configuration:basic:read`
-
- Args:
- company_id: The unique identifier of the company to create the checkout configuration for.
- Only required in setup mode.
-
- 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.
-
- three_ds_level: The 3D Secure behavior for a plan.
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- ...
-
- @required_args(["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 +130,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 +143,11 @@ 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`
+ This endpoint is public so a checkout
+ page can load from the configuration URL.
Args:
extra_headers: Send extra headers
@@ -359,21 +165,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 +187,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`
+ Lists checkout configurations for an account.
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: Account ID, prefixed `biz_`.
- before: Returns the elements in the list that come before the specified cursor.
+ after: Cursor for the next page of results.
- created_after: Only return checkout configurations created after this timestamp.
+ created_after: Only return checkout configurations created after this Unix timestamp.
- created_before: Only return checkout configurations created before this timestamp.
+ created_before: Only return checkout configurations created before this Unix timestamp.
- direction: The direction of the sort.
+ direction: Sort direction. Defaults to `desc`.
- first: Returns the first _n_ elements from the list.
+ first: Number of checkout configurations to return.
- last: Returns the last _n_ elements from the list.
+ order: Field used to sort checkout configurations.
- plan_id: Filter checkout configurations to only those associated with this plan
- identifier.
+ plan_id: Only return checkout configurations for this plan ID, prefixed `plan_`.
extra_headers: Send extra headers
@@ -429,12 +226,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 +239,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 so its checkout URL can no longer be used.
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 +262,92 @@ 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
+ 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,
+ )
- 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.
+class AsyncCheckoutConfigurationsResource(AsyncAPIResource):
+ """A Checkout Configuration is a reusable checkout link owned by an account.
- redirect_url: The URL to redirect the user to after checkout is completed.
+ In `payment` mode it sells a specific plan; in `setup` mode it collects and saves payment details without charging. Each configuration can also override which payment methods are accepted and how 3D Secure is enforced for that checkout.
- source_url: The URL of the page where the checkout is being initiated from.
+ Use the Checkout Configurations API to create checkout links for an existing or inline plan, list configurations for an account, retrieve the configuration behind a checkout URL, and delete links that should no longer be used.
+ """
- extra_headers: Send extra headers
+ @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:
+ ) -> CheckoutConfigurationCreateResponse:
"""
- Creates a new checkout configuration
-
- Required permissions:
-
- - `checkout_configuration:create`
- - `plan:create`
- - `access_pass:create`
- - `access_pass:update`
- - `checkout_configuration:basic:read`
+ Creates a reusable checkout configuration for an existing or inline plan.
Args:
- company_id: The unique identifier of the company to create the checkout configuration for.
- Only required in setup mode.
+ affiliate_code: Affiliate code to apply to the checkout.
- allow_promo_codes: Whether the checkout should show the promo code input field and accept promo
- codes. Defaults to true.
+ company_id: Account ID, prefixed `biz_`.
- checkout_styling: Checkout styling overrides for this session. Overrides plan and company
- defaults.
+ currency: Currency used for setup-mode payment method availability.
- currency: The available currencies on the platform
+ metadata: Custom key-value metadata copied to payments and memberships.
- metadata: Custom key-value metadata to attach to the checkout configuration.
+ mode: Checkout mode: `payment` collects payment for a plan now; `setup` saves payment
+ details without charging. 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.
+ payment_method_configuration: Payment method overrides for this checkout. `null` uses the plan or platform
+ defaults.
- redirect_url: The URL to redirect the user to after checkout is completed.
+ plan: Plan attributes used to create or find a plan for this checkout configuration.
+ Mutually exclusive with `plan_id`.
- source_url: The URL of the page where the checkout is being initiated from.
+ plan_id: Existing plan ID, prefixed `plan_`. Mutually exclusive with `plan`.
- three_ds_level: The 3D Secure behavior for a plan.
+ redirect_url: URL customers are sent to after checkout.
+
+ three_ds_level: 3D Secure behavior for this checkout.
extra_headers: Send extra headers
@@ -676,60 +357,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 +377,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 +390,11 @@ 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`
+ This endpoint is public so a checkout
+ page can load from the configuration URL.
Args:
extra_headers: Send extra headers
@@ -774,21 +412,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 +434,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`
+ Lists checkout configurations for an account.
Args:
- company_id: The unique identifier of the company to list checkout configurations for.
+ company_id: Account ID, prefixed `biz_`.
- after: Returns the elements in the list that come after the specified cursor.
+ after: Cursor for the next page of results.
- before: Returns the elements in the list that come before the specified cursor.
+ created_after: Only return checkout configurations created after this Unix timestamp.
- created_after: Only return checkout configurations created after this timestamp.
+ created_before: Only return checkout configurations created before this Unix timestamp.
- created_before: Only return checkout configurations created before this timestamp.
+ direction: Sort direction. Defaults to `desc`.
- direction: The direction of the sort.
+ first: Number of checkout configurations to return.
- first: Returns the first _n_ elements from the list.
+ order: Field used to sort checkout configurations.
- last: Returns the last _n_ elements from the list.
-
- plan_id: Filter checkout configurations to only those associated with this plan
- identifier.
+ plan_id: Only return checkout configurations for this plan ID, prefixed `plan_`.
extra_headers: Send extra headers
@@ -844,12 +473,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 +486,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 so its checkout URL can no longer be used.
+
+ 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 +534,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 +552,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 +570,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 +588,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/companies.py b/src/whop_sdk/resources/companies.py
index adf32dd47..45b8e2a76 100644
--- a/src/whop_sdk/resources/companies.py
+++ b/src/whop_sdk/resources/companies.py
@@ -35,8 +35,6 @@
class CompaniesResource(SyncAPIResource):
- """Companies"""
-
@cached_property
def with_raw_response(self) -> CompaniesResourceWithRawResponse:
"""
@@ -403,8 +401,6 @@ def create_api_key(
class AsyncCompaniesResource(AsyncAPIResource):
- """Companies"""
-
@cached_property
def with_raw_response(self) -> AsyncCompaniesResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/company_token_transactions.py b/src/whop_sdk/resources/company_token_transactions.py
index 77c4566fb..2b3cbddcc 100644
--- a/src/whop_sdk/resources/company_token_transactions.py
+++ b/src/whop_sdk/resources/company_token_transactions.py
@@ -32,8 +32,6 @@
class CompanyTokenTransactionsResource(SyncAPIResource):
- """Company token transactions"""
-
@cached_property
def with_raw_response(self) -> CompanyTokenTransactionsResourceWithRawResponse:
"""
@@ -367,8 +365,6 @@ def list(
class AsyncCompanyTokenTransactionsResource(AsyncAPIResource):
- """Company token transactions"""
-
@cached_property
def with_raw_response(self) -> AsyncCompanyTokenTransactionsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/conversions.py b/src/whop_sdk/resources/conversions.py
deleted file mode 100644
index a3dd62595..000000000
--- a/src/whop_sdk/resources/conversions.py
+++ /dev/null
@@ -1,324 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Union, Optional
-from datetime import datetime
-from typing_extensions import Literal
-
-import httpx
-
-from ..types import conversion_create_params
-from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from .._utils import maybe_transform, async_maybe_transform
-from .._compat import cached_property
-from .._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.shared.currency import Currency
-from ..types.conversion_create_response import ConversionCreateResponse
-
-__all__ = ["ConversionsResource", "AsyncConversionsResource"]
-
-
-class ConversionsResource(SyncAPIResource):
- """Conversions"""
-
- @cached_property
- def with_raw_response(self) -> ConversionsResourceWithRawResponse:
- """
- 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 ConversionsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> ConversionsResourceWithStreamingResponse:
- """
- 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 ConversionsResourceWithStreamingResponse(self)
-
- def create(
- self,
- *,
- company_id: str,
- event_name: Literal["lead", "submit_application", "contact", "complete_registration", "schedule", "custom"],
- action_source: Optional[
- Literal[
- "email",
- "website",
- "app",
- "phone_call",
- "chat",
- "physical_store",
- "system_generated",
- "business_messaging",
- "other",
- ]
- ]
- | Omit = omit,
- context: Optional[conversion_create_params.Context] | Omit = omit,
- currency: Optional[Currency] | Omit = omit,
- custom_name: Optional[str] | 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,
- url: Optional[str] | Omit = omit,
- user: Optional[conversion_create_params.User] | Omit = omit,
- value: Optional[float] | 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,
- ) -> ConversionCreateResponse:
- """
- Track a conversion or engagement event for a company.
-
- Required permissions:
-
- - `event:create`
-
- Args:
- company_id: The company to associate with this event.
-
- event_name: The type of event.
-
- action_source: The channel where an event originated
-
- context: Tracking and attribution context.
-
- currency: The available currencies on the platform
-
- custom_name: Custom event name when event_name is 'custom'.
-
- event_id: Client-provided identifier for deduplication. Generated if omitted.
-
- event_time: When the event occurred. Defaults to now.
-
- plan_id: The plan associated with the event.
-
- product_id: The product associated with the event.
-
- referrer_url: The referring URL.
-
- url: The URL where the event occurred.
-
- user: User identity and profile data.
-
- value: Monetary value associated with the event.
-
- 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(
- "/conversions",
- body=maybe_transform(
- {
- "company_id": company_id,
- "event_name": event_name,
- "action_source": action_source,
- "context": context,
- "currency": currency,
- "custom_name": custom_name,
- "event_id": event_id,
- "event_time": event_time,
- "plan_id": plan_id,
- "product_id": product_id,
- "referrer_url": referrer_url,
- "url": url,
- "user": user,
- "value": value,
- },
- conversion_create_params.ConversionCreateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=ConversionCreateResponse,
- )
-
-
-class AsyncConversionsResource(AsyncAPIResource):
- """Conversions"""
-
- @cached_property
- def with_raw_response(self) -> AsyncConversionsResourceWithRawResponse:
- """
- 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 AsyncConversionsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncConversionsResourceWithStreamingResponse:
- """
- 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 AsyncConversionsResourceWithStreamingResponse(self)
-
- async def create(
- self,
- *,
- company_id: str,
- event_name: Literal["lead", "submit_application", "contact", "complete_registration", "schedule", "custom"],
- action_source: Optional[
- Literal[
- "email",
- "website",
- "app",
- "phone_call",
- "chat",
- "physical_store",
- "system_generated",
- "business_messaging",
- "other",
- ]
- ]
- | Omit = omit,
- context: Optional[conversion_create_params.Context] | Omit = omit,
- currency: Optional[Currency] | Omit = omit,
- custom_name: Optional[str] | 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,
- url: Optional[str] | Omit = omit,
- user: Optional[conversion_create_params.User] | Omit = omit,
- value: Optional[float] | 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,
- ) -> ConversionCreateResponse:
- """
- Track a conversion or engagement event for a company.
-
- Required permissions:
-
- - `event:create`
-
- Args:
- company_id: The company to associate with this event.
-
- event_name: The type of event.
-
- action_source: The channel where an event originated
-
- context: Tracking and attribution context.
-
- currency: The available currencies on the platform
-
- custom_name: Custom event name when event_name is 'custom'.
-
- event_id: Client-provided identifier for deduplication. Generated if omitted.
-
- event_time: When the event occurred. Defaults to now.
-
- plan_id: The plan associated with the event.
-
- product_id: The product associated with the event.
-
- referrer_url: The referring URL.
-
- url: The URL where the event occurred.
-
- user: User identity and profile data.
-
- value: Monetary value associated with the event.
-
- 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(
- "/conversions",
- body=await async_maybe_transform(
- {
- "company_id": company_id,
- "event_name": event_name,
- "action_source": action_source,
- "context": context,
- "currency": currency,
- "custom_name": custom_name,
- "event_id": event_id,
- "event_time": event_time,
- "plan_id": plan_id,
- "product_id": product_id,
- "referrer_url": referrer_url,
- "url": url,
- "user": user,
- "value": value,
- },
- conversion_create_params.ConversionCreateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=ConversionCreateResponse,
- )
-
-
-class ConversionsResourceWithRawResponse:
- def __init__(self, conversions: ConversionsResource) -> None:
- self._conversions = conversions
-
- self.create = to_raw_response_wrapper(
- conversions.create,
- )
-
-
-class AsyncConversionsResourceWithRawResponse:
- def __init__(self, conversions: AsyncConversionsResource) -> None:
- self._conversions = conversions
-
- self.create = async_to_raw_response_wrapper(
- conversions.create,
- )
-
-
-class ConversionsResourceWithStreamingResponse:
- def __init__(self, conversions: ConversionsResource) -> None:
- self._conversions = conversions
-
- self.create = to_streamed_response_wrapper(
- conversions.create,
- )
-
-
-class AsyncConversionsResourceWithStreamingResponse:
- def __init__(self, conversions: AsyncConversionsResource) -> None:
- self._conversions = conversions
-
- self.create = async_to_streamed_response_wrapper(
- conversions.create,
- )
diff --git a/src/whop_sdk/resources/course_chapters.py b/src/whop_sdk/resources/course_chapters.py
index 181a02a34..41c7ea17e 100644
--- a/src/whop_sdk/resources/course_chapters.py
+++ b/src/whop_sdk/resources/course_chapters.py
@@ -27,8 +27,6 @@
class CourseChaptersResource(SyncAPIResource):
- """Course chapters"""
-
@cached_property
def with_raw_response(self) -> CourseChaptersResourceWithRawResponse:
"""
@@ -276,8 +274,6 @@ def delete(
class AsyncCourseChaptersResource(AsyncAPIResource):
- """Course chapters"""
-
@cached_property
def with_raw_response(self) -> AsyncCourseChaptersResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/course_lesson_interactions.py b/src/whop_sdk/resources/course_lesson_interactions.py
index 6a699713f..0b19bcebd 100644
--- a/src/whop_sdk/resources/course_lesson_interactions.py
+++ b/src/whop_sdk/resources/course_lesson_interactions.py
@@ -26,8 +26,6 @@
class CourseLessonInteractionsResource(SyncAPIResource):
- """Course lesson interactions"""
-
@cached_property
def with_raw_response(self) -> CourseLessonInteractionsResourceWithRawResponse:
"""
@@ -164,8 +162,6 @@ def list(
class AsyncCourseLessonInteractionsResource(AsyncAPIResource):
- """Course lesson interactions"""
-
@cached_property
def with_raw_response(self) -> AsyncCourseLessonInteractionsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/course_lessons.py b/src/whop_sdk/resources/course_lessons.py
index 6032fc40e..443134bee 100644
--- a/src/whop_sdk/resources/course_lessons.py
+++ b/src/whop_sdk/resources/course_lessons.py
@@ -41,8 +41,6 @@
class CourseLessonsResource(SyncAPIResource):
- """Course lessons"""
-
@cached_property
def with_raw_response(self) -> CourseLessonsResourceWithRawResponse:
"""
@@ -495,8 +493,6 @@ def submit_assessment(
class AsyncCourseLessonsResource(AsyncAPIResource):
- """Course lessons"""
-
@cached_property
def with_raw_response(self) -> AsyncCourseLessonsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/course_students.py b/src/whop_sdk/resources/course_students.py
index e11e25d56..a7c111a0a 100644
--- a/src/whop_sdk/resources/course_students.py
+++ b/src/whop_sdk/resources/course_students.py
@@ -26,8 +26,6 @@
class CourseStudentsResource(SyncAPIResource):
- """Course students"""
-
@cached_property
def with_raw_response(self) -> CourseStudentsResourceWithRawResponse:
"""
@@ -156,8 +154,6 @@ def list(
class AsyncCourseStudentsResource(AsyncAPIResource):
- """Course students"""
-
@cached_property
def with_raw_response(self) -> AsyncCourseStudentsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/courses.py b/src/whop_sdk/resources/courses.py
index 4a2c29f46..f8957ca59 100644
--- a/src/whop_sdk/resources/courses.py
+++ b/src/whop_sdk/resources/courses.py
@@ -29,8 +29,6 @@
class CoursesResource(SyncAPIResource):
- """Courses"""
-
@cached_property
def with_raw_response(self) -> CoursesResourceWithRawResponse:
"""
@@ -361,8 +359,6 @@ def delete(
class AsyncCoursesResource(AsyncAPIResource):
- """Courses"""
-
@cached_property
def with_raw_response(self) -> AsyncCoursesResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/deposits.py b/src/whop_sdk/resources/deposits.py
index 9d32c93dc..2fc95d3a6 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,12 +18,19 @@
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"]
class DepositsResource(SyncAPIResource):
+ """
+ Deposits describe ways to add funds to an account balance, including hosted deposit pages, bank deposit instructions, and supported crypto wallet addresses.
+
+ Use the Deposits API to create deposit instructions for an account and retrieve existing bank deposit activity.
+ """
+
@cached_property
def with_raw_response(self) -> DepositsResourceWithRawResponse:
"""
@@ -46,8 +53,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 +66,19 @@ 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. A caller authenticated as a user can additionally resolve their own user
+ account.
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.
- network: Optional destination network override.
+ metadata: Metadata to include with the deposit response.
+
+ network: Destination network override.
extra_headers: Send extra headers
@@ -83,8 +92,8 @@ def create(
"/deposits",
body=maybe_transform(
{
- "amount": amount,
"destination": destination,
+ "amount": amount,
"metadata": metadata,
"network": network,
},
@@ -96,8 +105,53 @@ 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):
+ """
+ Deposits describe ways to add funds to an account balance, including hosted deposit pages, bank deposit instructions, and supported crypto wallet addresses.
+
+ Use the Deposits API to create deposit instructions for an account and retrieve existing bank deposit activity.
+ """
+
@cached_property
def with_raw_response(self) -> AsyncDepositsResourceWithRawResponse:
"""
@@ -120,8 +174,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 +187,19 @@ 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. A caller authenticated as a user can additionally resolve their own user
+ account.
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 +213,8 @@ async def create(
"/deposits",
body=await async_maybe_transform(
{
- "amount": amount,
"destination": destination,
+ "amount": amount,
"metadata": metadata,
"network": network,
},
@@ -170,6 +226,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 +273,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 +285,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 +297,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 +309,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/dispute_alerts.py b/src/whop_sdk/resources/dispute_alerts.py
index 9daeac7f9..7bfc7a651 100644
--- a/src/whop_sdk/resources/dispute_alerts.py
+++ b/src/whop_sdk/resources/dispute_alerts.py
@@ -28,8 +28,6 @@
class DisputeAlertsResource(SyncAPIResource):
- """Dispute alerts"""
-
@cached_property
def with_raw_response(self) -> DisputeAlertsResourceWithRawResponse:
"""
@@ -171,8 +169,6 @@ def list(
class AsyncDisputeAlertsResource(AsyncAPIResource):
- """Dispute alerts"""
-
@cached_property
def with_raw_response(self) -> AsyncDisputeAlertsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/disputes.py b/src/whop_sdk/resources/disputes.py
index 9095384da..81cfc21f3 100644
--- a/src/whop_sdk/resources/disputes.py
+++ b/src/whop_sdk/resources/disputes.py
@@ -28,8 +28,6 @@
class DisputesResource(SyncAPIResource):
- """Disputes"""
-
@cached_property
def with_raw_response(self) -> DisputesResourceWithRawResponse:
"""
@@ -330,8 +328,6 @@ def update_evidence(
class AsyncDisputesResource(AsyncAPIResource):
- """Disputes"""
-
@cached_property
def with_raw_response(self) -> AsyncDisputesResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/dm_channels.py b/src/whop_sdk/resources/dm_channels.py
index 4247fa1c4..1bae5de2a 100644
--- a/src/whop_sdk/resources/dm_channels.py
+++ b/src/whop_sdk/resources/dm_channels.py
@@ -27,8 +27,6 @@
class DmChannelsResource(SyncAPIResource):
- """Dm channels"""
-
@cached_property
def with_raw_response(self) -> DmChannelsResourceWithRawResponse:
"""
@@ -284,8 +282,6 @@ def delete(
class AsyncDmChannelsResource(AsyncAPIResource):
- """Dm channels"""
-
@cached_property
def with_raw_response(self) -> AsyncDmChannelsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/dm_members.py b/src/whop_sdk/resources/dm_members.py
index bea07a5ff..be2de9bb9 100644
--- a/src/whop_sdk/resources/dm_members.py
+++ b/src/whop_sdk/resources/dm_members.py
@@ -35,8 +35,6 @@
class DmMembersResource(SyncAPIResource):
- """Dm members"""
-
@cached_property
def with_raw_response(self) -> DmMembersResourceWithRawResponse:
"""
@@ -299,8 +297,6 @@ def delete(
class AsyncDmMembersResource(AsyncAPIResource):
- """Dm members"""
-
@cached_property
def with_raw_response(self) -> AsyncDmMembersResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/entries.py b/src/whop_sdk/resources/entries.py
index 95f40eb85..68473548d 100644
--- a/src/whop_sdk/resources/entries.py
+++ b/src/whop_sdk/resources/entries.py
@@ -31,8 +31,6 @@
class EntriesResource(SyncAPIResource):
- """Entries"""
-
@cached_property
def with_raw_response(self) -> EntriesResourceWithRawResponse:
"""
@@ -263,8 +261,6 @@ def deny(
class AsyncEntriesResource(AsyncAPIResource):
- """Entries"""
-
@cached_property
def with_raw_response(self) -> AsyncEntriesResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/events.py b/src/whop_sdk/resources/events.py
new file mode 100644
index 000000000..b13412db9
--- /dev/null
+++ b/src/whop_sdk/resources/events.py
@@ -0,0 +1,719 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+import httpx
+
+from ..types import event_list_params, event_create_params
+from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from .._utils import maybe_transform, async_maybe_transform
+from .._compat import cached_property
+from .._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.event_list_response import EventListResponse
+from ..types.event_create_response import EventCreateResponse
+
+__all__ = ["EventsResource", "AsyncEventsResource"]
+
+
+class EventsResource(SyncAPIResource):
+ """
+ An Event records conversion or engagement activity for an account, such as page views, purchases, or leads. Each event ties the action to the [person](/api-reference/beta/people/person) who took it, so activity can be attributed to the ads and links that drove it.
+
+ Use the Events API to send new tracking events and list the events recorded for a person.
+ """
+
+ @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 create(
+ self,
+ *,
+ account_id: str,
+ event_name: Literal[
+ "lead",
+ "submit_application",
+ "contact",
+ "complete_registration",
+ "schedule",
+ "view_content",
+ "add_to_cart",
+ "custom",
+ "page",
+ ],
+ action_source: Optional[
+ Literal[
+ "email",
+ "website",
+ "app",
+ "phone_call",
+ "chat",
+ "physical_store",
+ "system_generated",
+ "business_messaging",
+ "other",
+ ]
+ ]
+ | Omit = omit,
+ context: Optional[event_create_params.Context] | Omit = omit,
+ currency: Optional[
+ 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",
+ ]
+ ]
+ | 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[event_create_params.User] | Omit = omit,
+ value: Optional[float] | 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,
+ ) -> EventCreateResponse:
+ """
+ Tracks a conversion or engagement event for an account.
+
+ Args:
+ account_id: The account to associate with this event.
+
+ event_name: The type of conversion or engagement event
+
+ action_source: The channel where an event originated
+
+ context: Tracking and attribution context.
+
+ currency: The available currencies on the platform
+
+ 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.
+
+ event_time: When the event occurred. Defaults to now.
+
+ plan_id: The plan associated with the event.
+
+ product_id: The product associated with the event.
+
+ 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.
+
+ value: Monetary value associated with the event.
+
+ 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(
+ "/events",
+ body=maybe_transform(
+ {
+ "account_id": account_id,
+ "event_name": event_name,
+ "action_source": action_source,
+ "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,
+ },
+ event_create_params.EventCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=EventCreateResponse,
+ )
+
+ def list(
+ self,
+ *,
+ person_id: str,
+ account_id: str | Omit = omit,
+ after: str | Omit = omit,
+ before: 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,
+ ) -> SyncCursorPage[EventListResponse]:
+ """Lists pixel events for a person, most recent first.
+
+ Events are shaped like the
+ POST /events 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.
+
+ after: A cursor for fetching events after a previous page.
+
+ before: A cursor for fetching events before a later page.
+
+ 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_api_list(
+ "/events",
+ page=SyncCursorPage[EventListResponse],
+ 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,
+ "after": after,
+ "before": before,
+ "first": first,
+ "from_": from_,
+ "to": to,
+ },
+ event_list_params.EventListParams,
+ ),
+ ),
+ model=EventListResponse,
+ )
+
+
+class AsyncEventsResource(AsyncAPIResource):
+ """
+ An Event records conversion or engagement activity for an account, such as page views, purchases, or leads. Each event ties the action to the [person](/api-reference/beta/people/person) who took it, so activity can be attributed to the ads and links that drove it.
+
+ Use the Events API to send new tracking events and list the events recorded for a person.
+ """
+
+ @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 create(
+ self,
+ *,
+ account_id: str,
+ event_name: Literal[
+ "lead",
+ "submit_application",
+ "contact",
+ "complete_registration",
+ "schedule",
+ "view_content",
+ "add_to_cart",
+ "custom",
+ "page",
+ ],
+ action_source: Optional[
+ Literal[
+ "email",
+ "website",
+ "app",
+ "phone_call",
+ "chat",
+ "physical_store",
+ "system_generated",
+ "business_messaging",
+ "other",
+ ]
+ ]
+ | Omit = omit,
+ context: Optional[event_create_params.Context] | Omit = omit,
+ currency: Optional[
+ 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",
+ ]
+ ]
+ | 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[event_create_params.User] | Omit = omit,
+ value: Optional[float] | 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,
+ ) -> EventCreateResponse:
+ """
+ Tracks a conversion or engagement event for an account.
+
+ Args:
+ account_id: The account to associate with this event.
+
+ event_name: The type of conversion or engagement event
+
+ action_source: The channel where an event originated
+
+ context: Tracking and attribution context.
+
+ currency: The available currencies on the platform
+
+ 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.
+
+ event_time: When the event occurred. Defaults to now.
+
+ plan_id: The plan associated with the event.
+
+ product_id: The product associated with the event.
+
+ 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.
+
+ value: Monetary value associated with the event.
+
+ 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(
+ "/events",
+ body=await async_maybe_transform(
+ {
+ "account_id": account_id,
+ "event_name": event_name,
+ "action_source": action_source,
+ "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,
+ },
+ event_create_params.EventCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=EventCreateResponse,
+ )
+
+ def list(
+ self,
+ *,
+ person_id: str,
+ account_id: str | Omit = omit,
+ after: str | Omit = omit,
+ before: 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,
+ ) -> AsyncPaginator[EventListResponse, AsyncCursorPage[EventListResponse]]:
+ """Lists pixel events for a person, most recent first.
+
+ Events are shaped like the
+ POST /events 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.
+
+ after: A cursor for fetching events after a previous page.
+
+ before: A cursor for fetching events before a later page.
+
+ 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_api_list(
+ "/events",
+ page=AsyncCursorPage[EventListResponse],
+ 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,
+ "after": after,
+ "before": before,
+ "first": first,
+ "from_": from_,
+ "to": to,
+ },
+ event_list_params.EventListParams,
+ ),
+ ),
+ model=EventListResponse,
+ )
+
+
+class EventsResourceWithRawResponse:
+ def __init__(self, events: EventsResource) -> None:
+ self._events = events
+
+ self.create = to_raw_response_wrapper(
+ events.create,
+ )
+ self.list = to_raw_response_wrapper(
+ events.list,
+ )
+
+
+class AsyncEventsResourceWithRawResponse:
+ def __init__(self, events: AsyncEventsResource) -> None:
+ self._events = events
+
+ self.create = async_to_raw_response_wrapper(
+ events.create,
+ )
+ self.list = async_to_raw_response_wrapper(
+ events.list,
+ )
+
+
+class EventsResourceWithStreamingResponse:
+ def __init__(self, events: EventsResource) -> None:
+ self._events = events
+
+ self.create = to_streamed_response_wrapper(
+ events.create,
+ )
+ self.list = to_streamed_response_wrapper(
+ events.list,
+ )
+
+
+class AsyncEventsResourceWithStreamingResponse:
+ def __init__(self, events: AsyncEventsResource) -> None:
+ self._events = events
+
+ self.create = async_to_streamed_response_wrapper(
+ events.create,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ events.list,
+ )
diff --git a/src/whop_sdk/resources/experiences.py b/src/whop_sdk/resources/experiences.py
index 8aab342b3..b8444bdef 100644
--- a/src/whop_sdk/resources/experiences.py
+++ b/src/whop_sdk/resources/experiences.py
@@ -36,8 +36,6 @@
class ExperiencesResource(SyncAPIResource):
- """Experiences"""
-
@cached_property
def with_raw_response(self) -> ExperiencesResourceWithRawResponse:
"""
@@ -460,8 +458,6 @@ def duplicate(
class AsyncExperiencesResource(AsyncAPIResource):
- """Experiences"""
-
@cached_property
def with_raw_response(self) -> AsyncExperiencesResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/fee_markups.py b/src/whop_sdk/resources/fee_markups.py
index e54cebbdd..63eb13e92 100644
--- a/src/whop_sdk/resources/fee_markups.py
+++ b/src/whop_sdk/resources/fee_markups.py
@@ -28,8 +28,6 @@
class FeeMarkupsResource(SyncAPIResource):
- """Fee markups"""
-
@cached_property
def with_raw_response(self) -> FeeMarkupsResourceWithRawResponse:
"""
@@ -221,8 +219,6 @@ def delete(
class AsyncFeeMarkupsResource(AsyncAPIResource):
- """Fee markups"""
-
@cached_property
def with_raw_response(self) -> AsyncFeeMarkupsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/files.py b/src/whop_sdk/resources/files.py
index 925b8f2bb..e12ed9602 100644
--- a/src/whop_sdk/resources/files.py
+++ b/src/whop_sdk/resources/files.py
@@ -26,8 +26,6 @@
class FilesResource(SyncAPIResource):
- """Files"""
-
@cached_property
def with_raw_response(self) -> FilesResourceWithRawResponse:
"""
@@ -128,8 +126,6 @@ def retrieve(
class AsyncFilesResource(AsyncAPIResource):
- """Files"""
-
@cached_property
def with_raw_response(self) -> AsyncFilesResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/financial_activity.py b/src/whop_sdk/resources/financial_activity.py
new file mode 100644
index 000000000..041d8987f
--- /dev/null
+++ b/src/whop_sdk/resources/financial_activity.py
@@ -0,0 +1,306 @@
+# 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):
+ """
+ A Ledger Activity row is a single financial event on an account's ledger — a payment, withdrawal, refund, transfer, on-chain deposit, swap, or card transaction. Each row is derived from the underlying ledger lines and carries a typed `resource` and `source` so you can present and link the event without extra lookups.
+
+ Use Ledger Activity to build a statement or transaction feed for an account or user. Reconcile against your own records with `amount` (signed, in the currency's smallest precision units) and `posted_at`, and use `available_at` to know when inflows became withdrawable.
+ """
+
+ @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,
+ include_owned_accounts: bool | 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. Pass `include_owned_accounts=true` with your own `user_id` to
+ aggregate your personal ledger and the businesses you own into one feed; each
+ row then carries the owning `account`.
+
+ 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.
+
+ include_owned_accounts: When true, aggregates the authenticated user's personal ledger with the
+ businesses they own (owner role with balance read) into one feed. Requires
+ user_id to be the authenticated user; cannot be combined with account_id or the
+ settlement-date filters. Each returned row includes the owning `account`.
+
+ 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,
+ "include_owned_accounts": include_owned_accounts,
+ "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):
+ """
+ A Ledger Activity row is a single financial event on an account's ledger — a payment, withdrawal, refund, transfer, on-chain deposit, swap, or card transaction. Each row is derived from the underlying ledger lines and carries a typed `resource` and `source` so you can present and link the event without extra lookups.
+
+ Use Ledger Activity to build a statement or transaction feed for an account or user. Reconcile against your own records with `amount` (signed, in the currency's smallest precision units) and `posted_at`, and use `available_at` to know when inflows became withdrawable.
+ """
+
+ @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,
+ include_owned_accounts: bool | 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. Pass `include_owned_accounts=true` with your own `user_id` to
+ aggregate your personal ledger and the businesses you own into one feed; each
+ row then carries the owning `account`.
+
+ 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.
+
+ include_owned_accounts: When true, aggregates the authenticated user's personal ledger with the
+ businesses they own (owner role with balance read) into one feed. Requires
+ user_id to be the authenticated user; cannot be combined with account_id or the
+ settlement-date filters. Each returned row includes the owning `account`.
+
+ 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,
+ "include_owned_accounts": include_owned_accounts,
+ "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/forum_posts.py b/src/whop_sdk/resources/forum_posts.py
index 0f99f5f7e..549c5dae0 100644
--- a/src/whop_sdk/resources/forum_posts.py
+++ b/src/whop_sdk/resources/forum_posts.py
@@ -33,8 +33,6 @@
class ForumPostsResource(SyncAPIResource):
- """Forum posts"""
-
@cached_property
def with_raw_response(self) -> ForumPostsResourceWithRawResponse:
"""
@@ -338,8 +336,6 @@ def list(
class AsyncForumPostsResource(AsyncAPIResource):
- """Forum posts"""
-
@cached_property
def with_raw_response(self) -> AsyncForumPostsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/forums.py b/src/whop_sdk/resources/forums.py
index 89aac58e2..93844933e 100644
--- a/src/whop_sdk/resources/forums.py
+++ b/src/whop_sdk/resources/forums.py
@@ -29,8 +29,6 @@
class ForumsResource(SyncAPIResource):
- """Forums"""
-
@cached_property
def with_raw_response(self) -> ForumsResourceWithRawResponse:
"""
@@ -223,8 +221,6 @@ def list(
class AsyncForumsResource(AsyncAPIResource):
- """Forums"""
-
@cached_property
def with_raw_response(self) -> AsyncForumsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/invoices.py b/src/whop_sdk/resources/invoices.py
index 017067eae..cf146f2ae 100644
--- a/src/whop_sdk/resources/invoices.py
+++ b/src/whop_sdk/resources/invoices.py
@@ -35,8 +35,6 @@
class InvoicesResource(SyncAPIResource):
- """Invoices"""
-
@cached_property
def with_raw_response(self) -> InvoicesResourceWithRawResponse:
"""
@@ -700,8 +698,6 @@ def void(
class AsyncInvoicesResource(AsyncAPIResource):
- """Invoices"""
-
@cached_property
def with_raw_response(self) -> AsyncInvoicesResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/leads.py b/src/whop_sdk/resources/leads.py
index c3fa6be35..d4ad5904d 100644
--- a/src/whop_sdk/resources/leads.py
+++ b/src/whop_sdk/resources/leads.py
@@ -27,8 +27,6 @@
class LeadsResource(SyncAPIResource):
- """Leads"""
-
@cached_property
def with_raw_response(self) -> LeadsResourceWithRawResponse:
"""
@@ -290,8 +288,6 @@ def list(
class AsyncLeadsResource(AsyncAPIResource):
- """Leads"""
-
@cached_property
def with_raw_response(self) -> AsyncLeadsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/ledger_accounts.py b/src/whop_sdk/resources/ledger_accounts.py
index 9857bfa65..778e7023d 100644
--- a/src/whop_sdk/resources/ledger_accounts.py
+++ b/src/whop_sdk/resources/ledger_accounts.py
@@ -21,8 +21,6 @@
class LedgerAccountsResource(SyncAPIResource):
- """Ledger accounts"""
-
@cached_property
def with_raw_response(self) -> LedgerAccountsResourceWithRawResponse:
"""
@@ -82,8 +80,6 @@ def retrieve(
class AsyncLedgerAccountsResource(AsyncAPIResource):
- """Ledger accounts"""
-
@cached_property
def with_raw_response(self) -> AsyncLedgerAccountsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/media.py b/src/whop_sdk/resources/media.py
new file mode 100644
index 000000000..e7151b06f
--- /dev/null
+++ b/src/whop_sdk/resources/media.py
@@ -0,0 +1,323 @@
+# 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 media_generate_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
+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.media_asset import MediaAsset
+
+__all__ = ["MediaResource", "AsyncMediaResource"]
+
+
+class MediaResource(SyncAPIResource):
+ """
+ A Media Asset is an AI-generated image or video created from a prompt and billed from an account balance. When generation finishes, the asset includes a file that can be attached anywhere Whop accepts files.
+
+ Use the Media API to start a generation job and retrieve the asset while it processes or after it is ready.
+ """
+
+ @cached_property
+ def with_raw_response(self) -> MediaResourceWithRawResponse:
+ """
+ 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 MediaResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> MediaResourceWithStreamingResponse:
+ """
+ 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 MediaResourceWithStreamingResponse(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,
+ ) -> MediaAsset:
+ """Retrieves a media asset by ID.
+
+ Poll this while the asset is `processing`.
+
+ 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("/media/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=MediaAsset,
+ )
+
+ def generate(
+ self,
+ *,
+ prompt: str,
+ type: Literal["video", "image"],
+ account_id: str | Omit = omit,
+ duration_seconds: Literal[5, 10, 15] | Omit = omit,
+ reference_media: SequenceNotStr[str] | Omit = omit,
+ resolution: Literal["480p", "720p", "1080p", "4k"] | 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,
+ ) -> MediaAsset:
+ """Starts an AI media generation job billed from the account's balance.
+
+ Generation
+ is asynchronous — poll `GET /media/{id}` until the asset is `ready`, then use
+ `file.id` anywhere attachments are accepted.
+
+ Args:
+ prompt: What to generate. Up to 2,000 characters.
+
+ type: The kind of media to generate.
+
+ account_id: Account ID, prefixed `biz_`. Defaults to the account the API key belongs to.
+
+ duration_seconds: Video length in seconds. Video only; defaults to 5.
+
+ reference_media: Optional reference image file IDs (`file_` prefixed), up to 4. For video, a
+ single reference seeds the opening frame; multiple references guide subject and
+ style instead.
+
+ resolution: Video resolution. Video only; defaults to `1080p`. `1080p` is not supported by
+ Seedance 2.0 Fast or Mini; `4k` is only supported by Seedance 2.0.
+
+ 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(
+ "/media/generate",
+ body=maybe_transform(
+ {
+ "prompt": prompt,
+ "type": type,
+ "account_id": account_id,
+ "duration_seconds": duration_seconds,
+ "reference_media": reference_media,
+ "resolution": resolution,
+ },
+ media_generate_params.MediaGenerateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=MediaAsset,
+ )
+
+
+class AsyncMediaResource(AsyncAPIResource):
+ """
+ A Media Asset is an AI-generated image or video created from a prompt and billed from an account balance. When generation finishes, the asset includes a file that can be attached anywhere Whop accepts files.
+
+ Use the Media API to start a generation job and retrieve the asset while it processes or after it is ready.
+ """
+
+ @cached_property
+ def with_raw_response(self) -> AsyncMediaResourceWithRawResponse:
+ """
+ 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 AsyncMediaResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncMediaResourceWithStreamingResponse:
+ """
+ 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 AsyncMediaResourceWithStreamingResponse(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,
+ ) -> MediaAsset:
+ """Retrieves a media asset by ID.
+
+ Poll this while the asset is `processing`.
+
+ 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("/media/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=MediaAsset,
+ )
+
+ async def generate(
+ self,
+ *,
+ prompt: str,
+ type: Literal["video", "image"],
+ account_id: str | Omit = omit,
+ duration_seconds: Literal[5, 10, 15] | Omit = omit,
+ reference_media: SequenceNotStr[str] | Omit = omit,
+ resolution: Literal["480p", "720p", "1080p", "4k"] | 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,
+ ) -> MediaAsset:
+ """Starts an AI media generation job billed from the account's balance.
+
+ Generation
+ is asynchronous — poll `GET /media/{id}` until the asset is `ready`, then use
+ `file.id` anywhere attachments are accepted.
+
+ Args:
+ prompt: What to generate. Up to 2,000 characters.
+
+ type: The kind of media to generate.
+
+ account_id: Account ID, prefixed `biz_`. Defaults to the account the API key belongs to.
+
+ duration_seconds: Video length in seconds. Video only; defaults to 5.
+
+ reference_media: Optional reference image file IDs (`file_` prefixed), up to 4. For video, a
+ single reference seeds the opening frame; multiple references guide subject and
+ style instead.
+
+ resolution: Video resolution. Video only; defaults to `1080p`. `1080p` is not supported by
+ Seedance 2.0 Fast or Mini; `4k` is only supported by Seedance 2.0.
+
+ 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(
+ "/media/generate",
+ body=await async_maybe_transform(
+ {
+ "prompt": prompt,
+ "type": type,
+ "account_id": account_id,
+ "duration_seconds": duration_seconds,
+ "reference_media": reference_media,
+ "resolution": resolution,
+ },
+ media_generate_params.MediaGenerateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=MediaAsset,
+ )
+
+
+class MediaResourceWithRawResponse:
+ def __init__(self, media: MediaResource) -> None:
+ self._media = media
+
+ self.retrieve = to_raw_response_wrapper(
+ media.retrieve,
+ )
+ self.generate = to_raw_response_wrapper(
+ media.generate,
+ )
+
+
+class AsyncMediaResourceWithRawResponse:
+ def __init__(self, media: AsyncMediaResource) -> None:
+ self._media = media
+
+ self.retrieve = async_to_raw_response_wrapper(
+ media.retrieve,
+ )
+ self.generate = async_to_raw_response_wrapper(
+ media.generate,
+ )
+
+
+class MediaResourceWithStreamingResponse:
+ def __init__(self, media: MediaResource) -> None:
+ self._media = media
+
+ self.retrieve = to_streamed_response_wrapper(
+ media.retrieve,
+ )
+ self.generate = to_streamed_response_wrapper(
+ media.generate,
+ )
+
+
+class AsyncMediaResourceWithStreamingResponse:
+ def __init__(self, media: AsyncMediaResource) -> None:
+ self._media = media
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ media.retrieve,
+ )
+ self.generate = async_to_streamed_response_wrapper(
+ media.generate,
+ )
diff --git a/src/whop_sdk/resources/members.py b/src/whop_sdk/resources/members.py
index c90408381..5fa0c041a 100644
--- a/src/whop_sdk/resources/members.py
+++ b/src/whop_sdk/resources/members.py
@@ -32,8 +32,6 @@
class MembersResource(SyncAPIResource):
- """Members"""
-
@cached_property
def with_raw_response(self) -> MembersResourceWithRawResponse:
"""
@@ -210,8 +208,6 @@ def list(
class AsyncMembersResource(AsyncAPIResource):
- """Members"""
-
@cached_property
def with_raw_response(self) -> AsyncMembersResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/memberships.py b/src/whop_sdk/resources/memberships.py
index 3d2616e09..2c4c39e73 100644
--- a/src/whop_sdk/resources/memberships.py
+++ b/src/whop_sdk/resources/memberships.py
@@ -37,8 +37,6 @@
class MembershipsResource(SyncAPIResource):
- """Memberships"""
-
@cached_property
def with_raw_response(self) -> MembershipsResourceWithRawResponse:
"""
@@ -467,8 +465,6 @@ def uncancel(
class AsyncMembershipsResource(AsyncAPIResource):
- """Memberships"""
-
@cached_property
def with_raw_response(self) -> AsyncMembershipsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/messages.py b/src/whop_sdk/resources/messages.py
index a9755f139..51e664a25 100644
--- a/src/whop_sdk/resources/messages.py
+++ b/src/whop_sdk/resources/messages.py
@@ -28,8 +28,6 @@
class MessagesResource(SyncAPIResource):
- """Messages"""
-
@cached_property
def with_raw_response(self) -> MessagesResourceWithRawResponse:
"""
@@ -315,8 +313,6 @@ def delete(
class AsyncMessagesResource(AsyncAPIResource):
- """Messages"""
-
@cached_property
def with_raw_response(self) -> AsyncMessagesResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/notifications.py b/src/whop_sdk/resources/notifications.py
index eaf1c066e..f1eff29a4 100644
--- a/src/whop_sdk/resources/notifications.py
+++ b/src/whop_sdk/resources/notifications.py
@@ -25,8 +25,6 @@
class NotificationsResource(SyncAPIResource):
- """Notifications"""
-
@cached_property
def with_raw_response(self) -> NotificationsResourceWithRawResponse:
"""
@@ -210,8 +208,6 @@ def create(
class AsyncNotificationsResource(AsyncAPIResource):
- """Notifications"""
-
@cached_property
def with_raw_response(self) -> AsyncNotificationsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/payment_methods.py b/src/whop_sdk/resources/payment_methods.py
index 0b6ff1f17..6c7594579 100644
--- a/src/whop_sdk/resources/payment_methods.py
+++ b/src/whop_sdk/resources/payment_methods.py
@@ -28,8 +28,6 @@
class PaymentMethodsResource(SyncAPIResource):
- """Payment methods"""
-
@cached_property
def with_raw_response(self) -> PaymentMethodsResourceWithRawResponse:
"""
@@ -196,8 +194,6 @@ def list(
class AsyncPaymentMethodsResource(AsyncAPIResource):
- """Payment methods"""
-
@cached_property
def with_raw_response(self) -> AsyncPaymentMethodsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/payments.py b/src/whop_sdk/resources/payments.py
index 06c0c5a0a..d15a395dc 100644
--- a/src/whop_sdk/resources/payments.py
+++ b/src/whop_sdk/resources/payments.py
@@ -34,8 +34,6 @@
class PaymentsResource(SyncAPIResource):
- """Payments"""
-
@cached_property
def with_raw_response(self) -> PaymentsResourceWithRawResponse:
"""
@@ -64,6 +62,7 @@ def create(
payment_method_id: str,
plan: payment_create_params.CreatePaymentInputWithPlanPlan,
metadata: Optional[Dict[str, object]] | Omit = omit,
+ promo_code_id: 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,
@@ -105,6 +104,10 @@ def create(
metadata: Custom metadata to attach to the payment.
+ promo_code_id: The ID of an active promo code to apply to this payment. The promo code must
+ belong to the company and be valid for the plan being purchased. The plan must
+ be attached to a product — promo codes are not eligible for one-off purchases.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -124,6 +127,7 @@ def create(
payment_method_id: str,
plan_id: str,
metadata: Optional[Dict[str, object]] | Omit = omit,
+ promo_code_id: 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,
@@ -165,6 +169,10 @@ def create(
metadata: Custom metadata to attach to the payment.
+ promo_code_id: The ID of an active promo code to apply to this payment. The promo code must
+ belong to the company and be valid for the plan being purchased. The plan must
+ be attached to a product — promo codes are not eligible for one-off purchases.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -187,6 +195,7 @@ def create(
payment_method_id: str,
plan: payment_create_params.CreatePaymentInputWithPlanPlan | Omit = omit,
metadata: Optional[Dict[str, object]] | Omit = omit,
+ promo_code_id: Optional[str] | 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.
@@ -204,6 +213,7 @@ def create(
"payment_method_id": payment_method_id,
"plan": plan,
"metadata": metadata,
+ "promo_code_id": promo_code_id,
"plan_id": plan_id,
},
payment_create_params.PaymentCreateParams,
@@ -603,8 +613,6 @@ def void(
class AsyncPaymentsResource(AsyncAPIResource):
- """Payments"""
-
@cached_property
def with_raw_response(self) -> AsyncPaymentsResourceWithRawResponse:
"""
@@ -633,6 +641,7 @@ async def create(
payment_method_id: str,
plan: payment_create_params.CreatePaymentInputWithPlanPlan,
metadata: Optional[Dict[str, object]] | Omit = omit,
+ promo_code_id: 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,
@@ -674,6 +683,10 @@ async def create(
metadata: Custom metadata to attach to the payment.
+ promo_code_id: The ID of an active promo code to apply to this payment. The promo code must
+ belong to the company and be valid for the plan being purchased. The plan must
+ be attached to a product — promo codes are not eligible for one-off purchases.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -693,6 +706,7 @@ async def create(
payment_method_id: str,
plan_id: str,
metadata: Optional[Dict[str, object]] | Omit = omit,
+ promo_code_id: 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,
@@ -734,6 +748,10 @@ async def create(
metadata: Custom metadata to attach to the payment.
+ promo_code_id: The ID of an active promo code to apply to this payment. The promo code must
+ belong to the company and be valid for the plan being purchased. The plan must
+ be attached to a product — promo codes are not eligible for one-off purchases.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -756,6 +774,7 @@ async def create(
payment_method_id: str,
plan: payment_create_params.CreatePaymentInputWithPlanPlan | Omit = omit,
metadata: Optional[Dict[str, object]] | Omit = omit,
+ promo_code_id: Optional[str] | 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.
@@ -773,6 +792,7 @@ async def create(
"payment_method_id": payment_method_id,
"plan": plan,
"metadata": metadata,
+ "promo_code_id": promo_code_id,
"plan_id": plan_id,
},
payment_create_params.PaymentCreateParams,
diff --git a/src/whop_sdk/resources/payout_accounts.py b/src/whop_sdk/resources/payout_accounts.py
index a6d57c30a..085edc957 100644
--- a/src/whop_sdk/resources/payout_accounts.py
+++ b/src/whop_sdk/resources/payout_accounts.py
@@ -21,8 +21,6 @@
class PayoutAccountsResource(SyncAPIResource):
- """Payout accounts"""
-
@cached_property
def with_raw_response(self) -> PayoutAccountsResourceWithRawResponse:
"""
@@ -81,8 +79,6 @@ def retrieve(
class AsyncPayoutAccountsResource(AsyncAPIResource):
- """Payout accounts"""
-
@cached_property
def with_raw_response(self) -> AsyncPayoutAccountsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/payout_methods.py b/src/whop_sdk/resources/payout_methods.py
deleted file mode 100644
index b5fc96f44..000000000
--- a/src/whop_sdk/resources/payout_methods.py
+++ /dev/null
@@ -1,321 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Optional
-
-import httpx
-
-from ..types import payout_method_list_params
-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.payout_method_list_response import PayoutMethodListResponse
-from ..types.payout_method_retrieve_response import PayoutMethodRetrieveResponse
-
-__all__ = ["PayoutMethodsResource", "AsyncPayoutMethodsResource"]
-
-
-class PayoutMethodsResource(SyncAPIResource):
- """Payout methods"""
-
- @cached_property
- def with_raw_response(self) -> PayoutMethodsResourceWithRawResponse:
- """
- 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 PayoutMethodsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> PayoutMethodsResourceWithStreamingResponse:
- """
- 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 PayoutMethodsResourceWithStreamingResponse(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,
- ) -> PayoutMethodRetrieveResponse:
- """
- Retrieves the details of an existing payout method.
-
- Required permissions:
-
- - `payout:destination:read`
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return self._get(
- path_template("/payout_methods/{id}", id=id),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=PayoutMethodRetrieveResponse,
- )
-
- def list(
- self,
- *,
- company_id: str,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[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[PayoutMethodListResponse]:
- """
- Returns a list of active payout methods configured for a company, ordered by
- most recently created.
-
- Required permissions:
-
- - `payout:destination:read`
-
- Args:
- company_id: The unique identifier of the company to list payout methods 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.
-
- first: Returns the first _n_ elements from the list.
-
- last: Returns the last _n_ elements from the 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
- """
- return self._get_api_list(
- "/payout_methods",
- page=SyncCursorPage[PayoutMethodListResponse],
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "company_id": company_id,
- "after": after,
- "before": before,
- "first": first,
- "last": last,
- },
- payout_method_list_params.PayoutMethodListParams,
- ),
- ),
- model=PayoutMethodListResponse,
- )
-
-
-class AsyncPayoutMethodsResource(AsyncAPIResource):
- """Payout methods"""
-
- @cached_property
- def with_raw_response(self) -> AsyncPayoutMethodsResourceWithRawResponse:
- """
- 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 AsyncPayoutMethodsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncPayoutMethodsResourceWithStreamingResponse:
- """
- 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 AsyncPayoutMethodsResourceWithStreamingResponse(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,
- ) -> PayoutMethodRetrieveResponse:
- """
- Retrieves the details of an existing payout method.
-
- Required permissions:
-
- - `payout:destination:read`
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return await self._get(
- path_template("/payout_methods/{id}", id=id),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=PayoutMethodRetrieveResponse,
- )
-
- def list(
- self,
- *,
- company_id: str,
- after: Optional[str] | Omit = omit,
- before: Optional[str] | Omit = omit,
- first: Optional[int] | Omit = omit,
- last: Optional[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[PayoutMethodListResponse, AsyncCursorPage[PayoutMethodListResponse]]:
- """
- Returns a list of active payout methods configured for a company, ordered by
- most recently created.
-
- Required permissions:
-
- - `payout:destination:read`
-
- Args:
- company_id: The unique identifier of the company to list payout methods 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.
-
- first: Returns the first _n_ elements from the list.
-
- last: Returns the last _n_ elements from the 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
- """
- return self._get_api_list(
- "/payout_methods",
- page=AsyncCursorPage[PayoutMethodListResponse],
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "company_id": company_id,
- "after": after,
- "before": before,
- "first": first,
- "last": last,
- },
- payout_method_list_params.PayoutMethodListParams,
- ),
- ),
- model=PayoutMethodListResponse,
- )
-
-
-class PayoutMethodsResourceWithRawResponse:
- def __init__(self, payout_methods: PayoutMethodsResource) -> None:
- self._payout_methods = payout_methods
-
- self.retrieve = to_raw_response_wrapper(
- payout_methods.retrieve,
- )
- self.list = to_raw_response_wrapper(
- payout_methods.list,
- )
-
-
-class AsyncPayoutMethodsResourceWithRawResponse:
- def __init__(self, payout_methods: AsyncPayoutMethodsResource) -> None:
- self._payout_methods = payout_methods
-
- self.retrieve = async_to_raw_response_wrapper(
- payout_methods.retrieve,
- )
- self.list = async_to_raw_response_wrapper(
- payout_methods.list,
- )
-
-
-class PayoutMethodsResourceWithStreamingResponse:
- def __init__(self, payout_methods: PayoutMethodsResource) -> None:
- self._payout_methods = payout_methods
-
- self.retrieve = to_streamed_response_wrapper(
- payout_methods.retrieve,
- )
- self.list = to_streamed_response_wrapper(
- payout_methods.list,
- )
-
-
-class AsyncPayoutMethodsResourceWithStreamingResponse:
- def __init__(self, payout_methods: AsyncPayoutMethodsResource) -> None:
- self._payout_methods = payout_methods
-
- self.retrieve = async_to_streamed_response_wrapper(
- payout_methods.retrieve,
- )
- self.list = async_to_streamed_response_wrapper(
- payout_methods.list,
- )
diff --git a/src/whop_sdk/resources/payouts/__init__.py b/src/whop_sdk/resources/payouts/__init__.py
new file mode 100644
index 000000000..51c0fd9e3
--- /dev/null
+++ b/src/whop_sdk/resources/payouts/__init__.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .methods import (
+ MethodsResource,
+ AsyncMethodsResource,
+ MethodsResourceWithRawResponse,
+ AsyncMethodsResourceWithRawResponse,
+ MethodsResourceWithStreamingResponse,
+ AsyncMethodsResourceWithStreamingResponse,
+)
+from .payouts import (
+ PayoutsResource,
+ AsyncPayoutsResource,
+ PayoutsResourceWithRawResponse,
+ AsyncPayoutsResourceWithRawResponse,
+ PayoutsResourceWithStreamingResponse,
+ AsyncPayoutsResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "MethodsResource",
+ "AsyncMethodsResource",
+ "MethodsResourceWithRawResponse",
+ "AsyncMethodsResourceWithRawResponse",
+ "MethodsResourceWithStreamingResponse",
+ "AsyncMethodsResourceWithStreamingResponse",
+ "PayoutsResource",
+ "AsyncPayoutsResource",
+ "PayoutsResourceWithRawResponse",
+ "AsyncPayoutsResourceWithRawResponse",
+ "PayoutsResourceWithStreamingResponse",
+ "AsyncPayoutsResourceWithStreamingResponse",
+]
diff --git a/src/whop_sdk/resources/payouts/methods.py b/src/whop_sdk/resources/payouts/methods.py
new file mode 100644
index 000000000..f3f9ea1d3
--- /dev/null
+++ b/src/whop_sdk/resources/payouts/methods.py
@@ -0,0 +1,294 @@
+# 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 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.payouts import method_list_params
+from ...types.payouts.method_list_response import MethodListResponse
+
+__all__ = ["MethodsResource", "AsyncMethodsResource"]
+
+
+class MethodsResource(SyncAPIResource):
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+
+ @cached_property
+ def with_raw_response(self) -> MethodsResourceWithRawResponse:
+ """
+ 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 MethodsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> MethodsResourceWithStreamingResponse:
+ """
+ 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 MethodsResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ after: str | Omit = omit,
+ amount: float | Omit = omit,
+ before: str | Omit = omit,
+ currency: str | Omit = omit,
+ first: int | Omit = omit,
+ include_available: bool | Omit = omit,
+ last: int | Omit = omit,
+ status: Literal["created", "active", "broken"] | 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[MethodListResponse]:
+ """
+ Lists the saved payout methods (bank accounts, digital wallets, crypto
+ addresses) that an account or user can withdraw to, most recently added first.
+ Pass exactly one of account*id (a biz* identifier) or user*id (a user*
+ identifier). Pass an amount to additionally get a fee and delivery quote per
+ method for withdrawing that amount.
+
+ 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).
+
+ amount: Optional withdrawal amount in whole currency units, for example `250.00`. When
+ provided, each method includes a quote with the estimated fee, amount received,
+ and delivery date for that amount.
+
+ before: Cursor to fetch the page before (from page_info.start_cursor).
+
+ currency: Currency code of the amount, for example `usd`. Only meaningful with amount.
+
+ first: Number of payout methods to return from the start of the window. Capped at 25
+ when an amount is provided.
+
+ include_available: When true, the response also carries available_destinations — payout rails the
+ account could add as a new payout method, with per-currency quotes when an
+ amount is provided.
+
+ last: Number of payout methods to return from the end of the window.
+
+ status: Optional status filter. `created` means saved but unused, `active` means a
+ payout through it succeeded, `broken` means the last payout failed and the
+ method needs fixing.
+
+ 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/methods",
+ page=SyncCursorPage[MethodListResponse],
+ 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,
+ "amount": amount,
+ "before": before,
+ "currency": currency,
+ "first": first,
+ "include_available": include_available,
+ "last": last,
+ "status": status,
+ "user_id": user_id,
+ },
+ method_list_params.MethodListParams,
+ ),
+ ),
+ model=MethodListResponse,
+ )
+
+
+class AsyncMethodsResource(AsyncAPIResource):
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+
+ @cached_property
+ def with_raw_response(self) -> AsyncMethodsResourceWithRawResponse:
+ """
+ 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 AsyncMethodsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncMethodsResourceWithStreamingResponse:
+ """
+ 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 AsyncMethodsResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ after: str | Omit = omit,
+ amount: float | Omit = omit,
+ before: str | Omit = omit,
+ currency: str | Omit = omit,
+ first: int | Omit = omit,
+ include_available: bool | Omit = omit,
+ last: int | Omit = omit,
+ status: Literal["created", "active", "broken"] | 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[MethodListResponse, AsyncCursorPage[MethodListResponse]]:
+ """
+ Lists the saved payout methods (bank accounts, digital wallets, crypto
+ addresses) that an account or user can withdraw to, most recently added first.
+ Pass exactly one of account*id (a biz* identifier) or user*id (a user*
+ identifier). Pass an amount to additionally get a fee and delivery quote per
+ method for withdrawing that amount.
+
+ 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).
+
+ amount: Optional withdrawal amount in whole currency units, for example `250.00`. When
+ provided, each method includes a quote with the estimated fee, amount received,
+ and delivery date for that amount.
+
+ before: Cursor to fetch the page before (from page_info.start_cursor).
+
+ currency: Currency code of the amount, for example `usd`. Only meaningful with amount.
+
+ first: Number of payout methods to return from the start of the window. Capped at 25
+ when an amount is provided.
+
+ include_available: When true, the response also carries available_destinations — payout rails the
+ account could add as a new payout method, with per-currency quotes when an
+ amount is provided.
+
+ last: Number of payout methods to return from the end of the window.
+
+ status: Optional status filter. `created` means saved but unused, `active` means a
+ payout through it succeeded, `broken` means the last payout failed and the
+ method needs fixing.
+
+ 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/methods",
+ page=AsyncCursorPage[MethodListResponse],
+ 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,
+ "amount": amount,
+ "before": before,
+ "currency": currency,
+ "first": first,
+ "include_available": include_available,
+ "last": last,
+ "status": status,
+ "user_id": user_id,
+ },
+ method_list_params.MethodListParams,
+ ),
+ ),
+ model=MethodListResponse,
+ )
+
+
+class MethodsResourceWithRawResponse:
+ def __init__(self, methods: MethodsResource) -> None:
+ self._methods = methods
+
+ self.list = to_raw_response_wrapper(
+ methods.list,
+ )
+
+
+class AsyncMethodsResourceWithRawResponse:
+ def __init__(self, methods: AsyncMethodsResource) -> None:
+ self._methods = methods
+
+ self.list = async_to_raw_response_wrapper(
+ methods.list,
+ )
+
+
+class MethodsResourceWithStreamingResponse:
+ def __init__(self, methods: MethodsResource) -> None:
+ self._methods = methods
+
+ self.list = to_streamed_response_wrapper(
+ methods.list,
+ )
+
+
+class AsyncMethodsResourceWithStreamingResponse:
+ def __init__(self, methods: AsyncMethodsResource) -> None:
+ self._methods = methods
+
+ self.list = async_to_streamed_response_wrapper(
+ methods.list,
+ )
diff --git a/src/whop_sdk/resources/payouts/payouts.py b/src/whop_sdk/resources/payouts/payouts.py
new file mode 100644
index 000000000..9ea1a73bd
--- /dev/null
+++ b/src/whop_sdk/resources/payouts/payouts.py
@@ -0,0 +1,451 @@
+# 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, payout_create_params
+from .methods import (
+ MethodsResource,
+ AsyncMethodsResource,
+ MethodsResourceWithRawResponse,
+ AsyncMethodsResourceWithRawResponse,
+ MethodsResourceWithStreamingResponse,
+ AsyncMethodsResourceWithStreamingResponse,
+)
+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 ...pagination import SyncCursorPage, AsyncCursorPage
+from ..._base_client import AsyncPaginator, make_request_options
+from ...types.payout_list_response import PayoutListResponse
+from ...types.payout_create_response import PayoutCreateResponse
+
+__all__ = ["PayoutsResource", "AsyncPayoutsResource"]
+
+
+class PayoutsResource(SyncAPIResource):
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+
+ @cached_property
+ def methods(self) -> MethodsResource:
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+ return MethodsResource(self._client)
+
+ @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 create(
+ self,
+ *,
+ account_id: str,
+ amount: float,
+ payout_method_id: str,
+ currency: str | Omit = omit,
+ idempotency_key: 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,
+ ) -> PayoutCreateResponse:
+ """Creates a payout from a stablecoin account to a saved payout method.
+
+ The
+ account's funds move from its stablecoin balance to an external bank account,
+ wallet, or crypto address. Accounts that pay out from a fiat balance use POST
+ /withdrawals. Requires the payouts API to be enabled for the account; contact
+ support to enable it. The payout settles asynchronously; poll GET /payouts for
+ the entry whose payout_request_id matches this payout's id.
+
+ Args:
+ account_id: The account to pay out from (a biz\\__ identifier).
+
+ amount: The amount to pay out in the specified currency.
+
+ payout_method_id: The saved payout method to deliver to (a potk\\__ identifier).
+
+ currency: The payout currency. Defaults to usd.
+
+ idempotency_key: A client-generated key that makes retries safe. Retrying with the same key
+ returns the original payout instead of creating a second one.
+
+ 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(
+ "/payouts",
+ body=maybe_transform(
+ {
+ "account_id": account_id,
+ "amount": amount,
+ "payout_method_id": payout_method_id,
+ "currency": currency,
+ "idempotency_key": idempotency_key,
+ },
+ payout_create_params.PayoutCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=PayoutCreateResponse,
+ )
+
+ 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):
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+
+ @cached_property
+ def methods(self) -> AsyncMethodsResource:
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+ return AsyncMethodsResource(self._client)
+
+ @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)
+
+ async def create(
+ self,
+ *,
+ account_id: str,
+ amount: float,
+ payout_method_id: str,
+ currency: str | Omit = omit,
+ idempotency_key: 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,
+ ) -> PayoutCreateResponse:
+ """Creates a payout from a stablecoin account to a saved payout method.
+
+ The
+ account's funds move from its stablecoin balance to an external bank account,
+ wallet, or crypto address. Accounts that pay out from a fiat balance use POST
+ /withdrawals. Requires the payouts API to be enabled for the account; contact
+ support to enable it. The payout settles asynchronously; poll GET /payouts for
+ the entry whose payout_request_id matches this payout's id.
+
+ Args:
+ account_id: The account to pay out from (a biz\\__ identifier).
+
+ amount: The amount to pay out in the specified currency.
+
+ payout_method_id: The saved payout method to deliver to (a potk\\__ identifier).
+
+ currency: The payout currency. Defaults to usd.
+
+ idempotency_key: A client-generated key that makes retries safe. Retrying with the same key
+ returns the original payout instead of creating a second one.
+
+ 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(
+ "/payouts",
+ body=await async_maybe_transform(
+ {
+ "account_id": account_id,
+ "amount": amount,
+ "payout_method_id": payout_method_id,
+ "currency": currency,
+ "idempotency_key": idempotency_key,
+ },
+ payout_create_params.PayoutCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=PayoutCreateResponse,
+ )
+
+ 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.create = to_raw_response_wrapper(
+ payouts.create,
+ )
+ self.list = to_raw_response_wrapper(
+ payouts.list,
+ )
+
+ @cached_property
+ def methods(self) -> MethodsResourceWithRawResponse:
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+ return MethodsResourceWithRawResponse(self._payouts.methods)
+
+
+class AsyncPayoutsResourceWithRawResponse:
+ def __init__(self, payouts: AsyncPayoutsResource) -> None:
+ self._payouts = payouts
+
+ self.create = async_to_raw_response_wrapper(
+ payouts.create,
+ )
+ self.list = async_to_raw_response_wrapper(
+ payouts.list,
+ )
+
+ @cached_property
+ def methods(self) -> AsyncMethodsResourceWithRawResponse:
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+ return AsyncMethodsResourceWithRawResponse(self._payouts.methods)
+
+
+class PayoutsResourceWithStreamingResponse:
+ def __init__(self, payouts: PayoutsResource) -> None:
+ self._payouts = payouts
+
+ self.create = to_streamed_response_wrapper(
+ payouts.create,
+ )
+ self.list = to_streamed_response_wrapper(
+ payouts.list,
+ )
+
+ @cached_property
+ def methods(self) -> MethodsResourceWithStreamingResponse:
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+ return MethodsResourceWithStreamingResponse(self._payouts.methods)
+
+
+class AsyncPayoutsResourceWithStreamingResponse:
+ def __init__(self, payouts: AsyncPayoutsResource) -> None:
+ self._payouts = payouts
+
+ self.create = async_to_streamed_response_wrapper(
+ payouts.create,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ payouts.list,
+ )
+
+ @cached_property
+ def methods(self) -> AsyncMethodsResourceWithStreamingResponse:
+ """
+ Payouts represent money sent from an account or user balance to an external destination, such as a bank account, wallet, or other saved payout method.
+
+ Use the Payouts API to create payouts from stablecoin accounts, list payout history for accounts or users, monitor payout statuses, and show expected arrival details for funds leaving Whop.
+ """
+ return AsyncMethodsResourceWithStreamingResponse(self._payouts.methods)
diff --git a/src/whop_sdk/resources/people.py b/src/whop_sdk/resources/people.py
new file mode 100644
index 000000000..d97fb979a
--- /dev/null
+++ b/src/whop_sdk/resources/people.py
@@ -0,0 +1,393 @@
+# 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 ..pagination import SyncCursorPage, AsyncCursorPage
+from .._base_client import AsyncPaginator, make_request_options
+from ..types.person_list_response import PersonListResponse
+from ..types.person_retrieve_response import PersonRetrieveResponse
+
+__all__ = ["PeopleResource", "AsyncPeopleResource"]
+
+
+class PeopleResource(SyncAPIResource):
+ """
+ A Person represents a visitor or customer of an account, assembled from [pixel events](/api-reference/beta/events/event) and purchase activity — ad clicks, storefront visits, and checkouts.
+
+ Use the People API to list the people of an account and retrieve a single person.
+ """
+
+ @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,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ filters: str | Omit = omit,
+ first: int | Omit = omit,
+ from_: 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,
+ ) -> SyncCursorPage[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.
+
+ after: A cursor for fetching people after a previous page.
+
+ before: A cursor for fetching people before a later page.
+
+ 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 100).
+
+ from_: Start of the time range as a Unix timestamp. Defaults to 366 days before `to`.
+
+ 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_api_list(
+ "/people",
+ page=SyncCursorPage[PersonListResponse],
+ 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,
+ "filters": filters,
+ "first": first,
+ "from_": from_,
+ "sort": sort,
+ "to": to,
+ },
+ person_list_params.PersonListParams,
+ ),
+ ),
+ model=PersonListResponse,
+ )
+
+
+class AsyncPeopleResource(AsyncAPIResource):
+ """
+ A Person represents a visitor or customer of an account, assembled from [pixel events](/api-reference/beta/events/event) and purchase activity — ad clicks, storefront visits, and checkouts.
+
+ Use the People API to list the people of an account and retrieve a single person.
+ """
+
+ @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,
+ )
+
+ def list(
+ self,
+ *,
+ account_id: str | Omit = omit,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ direction: Literal["asc", "desc"] | Omit = omit,
+ filters: str | Omit = omit,
+ first: int | Omit = omit,
+ from_: 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,
+ ) -> AsyncPaginator[PersonListResponse, AsyncCursorPage[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.
+
+ after: A cursor for fetching people after a previous page.
+
+ before: A cursor for fetching people before a later page.
+
+ 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 100).
+
+ from_: Start of the time range as a Unix timestamp. Defaults to 366 days before `to`.
+
+ 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_api_list(
+ "/people",
+ page=AsyncCursorPage[PersonListResponse],
+ 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,
+ "filters": filters,
+ "first": first,
+ "from_": from_,
+ "sort": sort,
+ "to": to,
+ },
+ person_list_params.PersonListParams,
+ ),
+ ),
+ model=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 e351bc6fc..f8ccd7879 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,21 +21,20 @@
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"""
+ """A Plan defines how customers buy a product.
+
+ It controls pricing, billing cadence, availability, tax behavior, checkout fields, and purchase visibility.
+
+ Use the Plans API to create plans for products, list existing plans, retrieve or update plan configuration, calculate tax for checkout, and delete plans that should no longer be offered.
+ """
@cached_property
def with_raw_response(self) -> PlansResourceWithRawResponse:
@@ -60,12 +58,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 +70,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 +96,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 +168,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 +184,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 +217,6 @@ def retrieve(
"""
Retrieves the details of an existing plan.
- Required permissions:
-
- - `plan:basic:read`
-
Args:
extra_headers: Send extra headers
@@ -259,8 +242,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 +251,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 +275,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 +380,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 +401,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 +449,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 +485,6 @@ def delete(
Existing memberships on this plan will
not be affected.
- Required permissions:
-
- - `plan:delete`
-
Args:
extra_headers: Send extra headers
@@ -542,9 +504,66 @@ 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:
+ """
+ Previews tax for a plan before checkout, based on the buyer's location.
+
+ Args:
+ address: Buyer billing address used for tax calculation. Provide either `address.country`
+ or `ip_address`; include state and postal code when available for more accurate
+ results.
+
+ ip_address: Buyer IP address used to infer location when no billing address is provided.
+
+ tax_ids: Optional buyer tax ID for B2B exemptions. At most one entry is supported.
+
+ 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):
- """Plans"""
+ """A Plan defines how customers buy a product.
+
+ It controls pricing, billing cadence, availability, tax behavior, checkout fields, and purchase visibility.
+
+ Use the Plans API to create plans for products, list existing plans, retrieve or update plan configuration, calculate tax for checkout, and delete plans that should no longer be offered.
+ """
@cached_property
def with_raw_response(self) -> AsyncPlansResourceWithRawResponse:
@@ -568,12 +587,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 +599,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 +625,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.
+
+ 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
@@ -689,8 +697,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 +713,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 +746,6 @@ async def retrieve(
"""
Retrieves the details of an existing plan.
- Required permissions:
-
- - `plan:basic:read`
-
Args:
extra_headers: Send extra headers
@@ -767,8 +771,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 +780,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 +804,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 +909,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 +930,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 +978,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 +1014,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 +1033,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:
+ """
+ Previews tax for a plan before checkout, based on the buyer's location.
+
+ Args:
+ address: Buyer billing address used for tax calculation. Provide either `address.country`
+ or `ip_address`; include state and postal code when available for more accurate
+ results.
+
+ ip_address: Buyer IP address used to infer location when no billing address is provided.
+
+ tax_ids: Optional buyer tax ID for B2B exemptions. At most one entry is supported.
+
+ 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 +1105,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 +1129,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 +1153,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 +1177,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 505de8e19..20ce4953f 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,20 +21,19 @@
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"]
class ProductsResource(SyncAPIResource):
- """Products"""
+ """A Product is a digital good or service sold on Whop.
+
+ Products may contain plans for pricing and/or experiences for content delivery.
+
+ Use the Products API to create products, list products visible to your credentials, retrieve product details, update product metadata or merchandising fields, and delete products that should no longer be sold.
+ """
@cached_property
def with_raw_response(self) -> ProductsResourceWithRawResponse:
@@ -59,26 +57,24 @@ 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 +82,47 @@ 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. See the available
+ [product categories](https://docs.numeral.com/essentials/product-categories).
- 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,21 +136,19 @@ 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,
@@ -197,12 +174,10 @@ def retrieve(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Product:
- """
- Retrieves the details of an existing product.
+ """Retrieves the details of an existing product.
- Required permissions:
-
- - `access_pass:basic:read`
+ This endpoint is publicly
+ accessible.
Args:
extra_headers: Send extra headers
@@ -227,25 +202,13 @@ 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 +217,24 @@ 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 displayed on the product page.
- description: A written description of the product displayed on its product page.
+ headline: A short marketing headline for the product page.
- gallery_images: The gallery images for the product.
+ metadata: Custom key-value pairs to store on the product.
- global_affiliate_percentage: The commission rate as a percentage that affiliates earn through the global
- affiliate program.
-
- global_affiliate_status: The different statuses of the global affiliate program for a product.
-
- headline: A short marketing headline displayed prominently on the product page.
-
- 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.
+ product_tax_code_id: The unique identifier of the tax classification code. See the available
+ [product categories](https://docs.numeral.com/essentials/product-categories).
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.
+ title: The display name of the product.
- visibility: Visibility of a resource
+ visibility: Whether the product is visible to customers.
extra_headers: Send extra headers
@@ -322,23 +250,11 @@ 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 +270,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 +286,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 +326,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 +352,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
@@ -477,7 +378,12 @@ def delete(
class AsyncProductsResource(AsyncAPIResource):
- """Products"""
+ """A Product is a digital good or service sold on Whop.
+
+ Products may contain plans for pricing and/or experiences for content delivery.
+
+ Use the Products API to create products, list products visible to your credentials, retrieve product details, update product metadata or merchandising fields, and delete products that should no longer be sold.
+ """
@cached_property
def with_raw_response(self) -> AsyncProductsResourceWithRawResponse:
@@ -501,26 +407,24 @@ 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 +432,47 @@ 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. See the available
+ [product categories](https://docs.numeral.com/essentials/product-categories).
- 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,21 +486,19 @@ 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,
@@ -639,12 +524,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.
+ """Retrieves the details of an existing product.
- Required permissions:
-
- - `access_pass:basic:read`
+ This endpoint is publicly
+ accessible.
Args:
extra_headers: Send extra headers
@@ -669,25 +552,13 @@ 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 +567,24 @@ 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 displayed on the product page.
- description: A written description of the product displayed on its product page.
+ headline: A short marketing headline for the product page.
- gallery_images: The gallery images for the product.
+ metadata: Custom key-value pairs to store on the product.
- global_affiliate_percentage: The commission rate as a percentage that affiliates earn through the global
- affiliate program.
-
- global_affiliate_status: The different statuses of the global affiliate program for a product.
-
- headline: A short marketing headline displayed prominently on the product page.
-
- 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.
+ product_tax_code_id: The unique identifier of the tax classification code. See the available
+ [product categories](https://docs.numeral.com/essentials/product-categories).
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.
+ title: The display name of the product.
- visibility: Visibility of a resource
+ visibility: Whether the product is visible to customers.
extra_headers: Send extra headers
@@ -764,23 +600,11 @@ 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 +620,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 +636,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 +676,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 +702,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/promo_codes.py b/src/whop_sdk/resources/promo_codes.py
index 8952c7375..7d893047b 100644
--- a/src/whop_sdk/resources/promo_codes.py
+++ b/src/whop_sdk/resources/promo_codes.py
@@ -31,8 +31,6 @@
class PromoCodesResource(SyncAPIResource):
- """Promo codes"""
-
@cached_property
def with_raw_response(self) -> PromoCodesResourceWithRawResponse:
"""
@@ -327,8 +325,6 @@ def delete(
class AsyncPromoCodesResource(AsyncAPIResource):
- """Promo codes"""
-
@cached_property
def with_raw_response(self) -> AsyncPromoCodesResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/reactions.py b/src/whop_sdk/resources/reactions.py
index 9444f6223..243ceafe4 100644
--- a/src/whop_sdk/resources/reactions.py
+++ b/src/whop_sdk/resources/reactions.py
@@ -27,8 +27,6 @@
class ReactionsResource(SyncAPIResource):
- """Reactions"""
-
@cached_property
def with_raw_response(self) -> ReactionsResourceWithRawResponse:
"""
@@ -254,8 +252,6 @@ def delete(
class AsyncReactionsResource(AsyncAPIResource):
- """Reactions"""
-
@cached_property
def with_raw_response(self) -> AsyncReactionsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/referrals/__init__.py b/src/whop_sdk/resources/referrals/__init__.py
new file mode 100644
index 000000000..0cd35d41b
--- /dev/null
+++ b/src/whop_sdk/resources/referrals/__init__.py
@@ -0,0 +1,47 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .partners import (
+ PartnersResource,
+ AsyncPartnersResource,
+ PartnersResourceWithRawResponse,
+ AsyncPartnersResourceWithRawResponse,
+ PartnersResourceWithStreamingResponse,
+ AsyncPartnersResourceWithStreamingResponse,
+)
+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",
+ "PartnersResource",
+ "AsyncPartnersResource",
+ "PartnersResourceWithRawResponse",
+ "AsyncPartnersResourceWithRawResponse",
+ "PartnersResourceWithStreamingResponse",
+ "AsyncPartnersResourceWithStreamingResponse",
+ "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 000000000..bd5fa65b8
--- /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 000000000..add29525a
--- /dev/null
+++ b/src/whop_sdk/resources/referrals/businesses/businesses.py
@@ -0,0 +1,560 @@
+# 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, 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.referrals import business_list_params, business_leaderboard_params
+from ....types.referrals.business_list_response import BusinessListResponse
+from ....types.referrals.business_retrieve_response import BusinessRetrieveResponse
+from ....types.referrals.business_leaderboard_response import BusinessLeaderboardResponse
+
+__all__ = ["BusinessesResource", "AsyncBusinessesResource"]
+
+
+class BusinessesResource(SyncAPIResource):
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+
+ @cached_property
+ def earnings(self) -> EarningsResource:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ 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("/partners/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,
+ created_after: str | Omit = omit,
+ created_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,
+ referred_user_id: str | Omit = omit,
+ referred_username: str | Omit = omit,
+ status: Literal["active", "removed"] | Omit = omit,
+ tier: Literal["first", "second"] | 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).
+
+ created_after: Only return business referrals created after this timestamp.
+
+ created_before: Only return business referrals created before this timestamp.
+
+ direction: Sort direction.
+
+ first: Number of business referrals to return from the start of the window.
+
+ has_earnings: When true, only businesses with pending or completed earnings 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.
+
+ referred_user_id: Filter to referrals attributed to this user. For first-tier referrals, this is
+ the referred account owner; for second-tier referrals, this is the partner you
+ recruited.
+
+ referred_username: Filter by the referred user's exact username. Ignored when `referred_user_id` is
+ present.
+
+ status: Filter by referral status.
+
+ tier: Filter to only first-tier referrals or only second-tier referrals.
+
+ 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(
+ "/partners/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,
+ "created_after": created_after,
+ "created_before": created_before,
+ "direction": direction,
+ "first": first,
+ "has_earnings": has_earnings,
+ "last": last,
+ "order": order,
+ "referred_user_id": referred_user_id,
+ "referred_username": referred_username,
+ "status": status,
+ "tier": tier,
+ },
+ business_list_params.BusinessListParams,
+ ),
+ ),
+ model=BusinessListResponse,
+ )
+
+ def leaderboard(
+ self,
+ *,
+ period: Literal["day", "month", "year", "last_30_days", "all_time"] | 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,
+ ) -> BusinessLeaderboardResponse:
+ """
+ Ranks referrers by business referral earnings — all-time by default, or over the
+ current day, month, year, or trailing 30 days — and includes the caller's own
+ standing.
+
+ Args:
+ period: Time window for the rankings. `day`, `month`, and `year` count earnings since
+ the start of the current calendar day, month, or year; `last_30_days` counts
+ earnings over the trailing 30 days; `all_time` ranks lifetime earnings.
+
+ 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(
+ "/partners/leaderboard",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"period": period}, business_leaderboard_params.BusinessLeaderboardParams),
+ ),
+ cast_to=BusinessLeaderboardResponse,
+ )
+
+
+class AsyncBusinessesResource(AsyncAPIResource):
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+
+ @cached_property
+ def earnings(self) -> AsyncEarningsResource:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ 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("/partners/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,
+ created_after: str | Omit = omit,
+ created_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,
+ referred_user_id: str | Omit = omit,
+ referred_username: str | Omit = omit,
+ status: Literal["active", "removed"] | Omit = omit,
+ tier: Literal["first", "second"] | 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).
+
+ created_after: Only return business referrals created after this timestamp.
+
+ created_before: Only return business referrals created before this timestamp.
+
+ direction: Sort direction.
+
+ first: Number of business referrals to return from the start of the window.
+
+ has_earnings: When true, only businesses with pending or completed earnings 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.
+
+ referred_user_id: Filter to referrals attributed to this user. For first-tier referrals, this is
+ the referred account owner; for second-tier referrals, this is the partner you
+ recruited.
+
+ referred_username: Filter by the referred user's exact username. Ignored when `referred_user_id` is
+ present.
+
+ status: Filter by referral status.
+
+ tier: Filter to only first-tier referrals or only second-tier referrals.
+
+ 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(
+ "/partners/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,
+ "created_after": created_after,
+ "created_before": created_before,
+ "direction": direction,
+ "first": first,
+ "has_earnings": has_earnings,
+ "last": last,
+ "order": order,
+ "referred_user_id": referred_user_id,
+ "referred_username": referred_username,
+ "status": status,
+ "tier": tier,
+ },
+ business_list_params.BusinessListParams,
+ ),
+ ),
+ model=BusinessListResponse,
+ )
+
+ async def leaderboard(
+ self,
+ *,
+ period: Literal["day", "month", "year", "last_30_days", "all_time"] | 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,
+ ) -> BusinessLeaderboardResponse:
+ """
+ Ranks referrers by business referral earnings — all-time by default, or over the
+ current day, month, year, or trailing 30 days — and includes the caller's own
+ standing.
+
+ Args:
+ period: Time window for the rankings. `day`, `month`, and `year` count earnings since
+ the start of the current calendar day, month, or year; `last_30_days` counts
+ earnings over the trailing 30 days; `all_time` ranks lifetime earnings.
+
+ 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(
+ "/partners/leaderboard",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {"period": period}, business_leaderboard_params.BusinessLeaderboardParams
+ ),
+ ),
+ cast_to=BusinessLeaderboardResponse,
+ )
+
+
+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.leaderboard = to_raw_response_wrapper(
+ businesses.leaderboard,
+ )
+
+ @cached_property
+ def earnings(self) -> EarningsResourceWithRawResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ 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.leaderboard = async_to_raw_response_wrapper(
+ businesses.leaderboard,
+ )
+
+ @cached_property
+ def earnings(self) -> AsyncEarningsResourceWithRawResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ 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.leaderboard = to_streamed_response_wrapper(
+ businesses.leaderboard,
+ )
+
+ @cached_property
+ def earnings(self) -> EarningsResourceWithStreamingResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ 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.leaderboard = async_to_streamed_response_wrapper(
+ businesses.leaderboard,
+ )
+
+ @cached_property
+ def earnings(self) -> AsyncEarningsResourceWithStreamingResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ 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 000000000..ba88c6f73
--- /dev/null
+++ b/src/whop_sdk/resources/referrals/businesses/earnings.py
@@ -0,0 +1,256 @@
+# 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):
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+
+ @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,
+ 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", "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:
+ created_after: Only return earnings created after this timestamp.
+
+ created_before: Only return earnings created before this timestamp.
+
+ 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("/partners/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,
+ "created_after": created_after,
+ "created_before": created_before,
+ "direction": direction,
+ "first": first,
+ "last": last,
+ "order": order,
+ "status": status,
+ },
+ earning_list_params.EarningListParams,
+ ),
+ ),
+ model=EarningListResponse,
+ )
+
+
+class AsyncEarningsResource(AsyncAPIResource):
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+
+ @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,
+ 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", "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:
+ created_after: Only return earnings created after this timestamp.
+
+ created_before: Only return earnings created before this timestamp.
+
+ 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("/partners/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,
+ "created_after": created_after,
+ "created_before": created_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/partners.py b/src/whop_sdk/resources/referrals/partners.py
new file mode 100644
index 000000000..d210ea4ac
--- /dev/null
+++ b/src/whop_sdk/resources/referrals/partners.py
@@ -0,0 +1,155 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ..._types import Body, Query, Headers, NotGiven, not_given
+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.referrals.partner_create_response import PartnerCreateResponse
+
+__all__ = ["PartnersResource", "AsyncPartnersResource"]
+
+
+class PartnersResource(SyncAPIResource):
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+
+ @cached_property
+ def with_raw_response(self) -> PartnersResourceWithRawResponse:
+ """
+ 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 PartnersResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> PartnersResourceWithStreamingResponse:
+ """
+ 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 PartnersResourceWithStreamingResponse(self)
+
+ def create(
+ 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,
+ ) -> PartnerCreateResponse:
+ """
+ Enrolls the calling user in the Whop partner program, making their business
+ referrals eligible for earnings. Idempotent — enrolling again keeps the original
+ enrollment time.
+ """
+ return self._post(
+ "/partners",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=PartnerCreateResponse,
+ )
+
+
+class AsyncPartnersResource(AsyncAPIResource):
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+
+ @cached_property
+ def with_raw_response(self) -> AsyncPartnersResourceWithRawResponse:
+ """
+ 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 AsyncPartnersResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncPartnersResourceWithStreamingResponse:
+ """
+ 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 AsyncPartnersResourceWithStreamingResponse(self)
+
+ async def create(
+ 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,
+ ) -> PartnerCreateResponse:
+ """
+ Enrolls the calling user in the Whop partner program, making their business
+ referrals eligible for earnings. Idempotent — enrolling again keeps the original
+ enrollment time.
+ """
+ return await self._post(
+ "/partners",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=PartnerCreateResponse,
+ )
+
+
+class PartnersResourceWithRawResponse:
+ def __init__(self, partners: PartnersResource) -> None:
+ self._partners = partners
+
+ self.create = to_raw_response_wrapper(
+ partners.create,
+ )
+
+
+class AsyncPartnersResourceWithRawResponse:
+ def __init__(self, partners: AsyncPartnersResource) -> None:
+ self._partners = partners
+
+ self.create = async_to_raw_response_wrapper(
+ partners.create,
+ )
+
+
+class PartnersResourceWithStreamingResponse:
+ def __init__(self, partners: PartnersResource) -> None:
+ self._partners = partners
+
+ self.create = to_streamed_response_wrapper(
+ partners.create,
+ )
+
+
+class AsyncPartnersResourceWithStreamingResponse:
+ def __init__(self, partners: AsyncPartnersResource) -> None:
+ self._partners = partners
+
+ self.create = async_to_streamed_response_wrapper(
+ partners.create,
+ )
diff --git a/src/whop_sdk/resources/referrals/referrals.py b/src/whop_sdk/resources/referrals/referrals.py
new file mode 100644
index 000000000..b69889f54
--- /dev/null
+++ b/src/whop_sdk/resources/referrals/referrals.py
@@ -0,0 +1,363 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ...types import referral_referred_users_params
+from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ..._utils import maybe_transform, async_maybe_transform
+from .partners import (
+ PartnersResource,
+ AsyncPartnersResource,
+ PartnersResourceWithRawResponse,
+ AsyncPartnersResourceWithRawResponse,
+ PartnersResourceWithStreamingResponse,
+ AsyncPartnersResourceWithStreamingResponse,
+)
+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 .businesses.businesses import (
+ BusinessesResource,
+ AsyncBusinessesResource,
+ BusinessesResourceWithRawResponse,
+ AsyncBusinessesResourceWithRawResponse,
+ BusinessesResourceWithStreamingResponse,
+ AsyncBusinessesResourceWithStreamingResponse,
+)
+from ...types.referral_referred_users_response import ReferralReferredUsersResponse
+
+__all__ = ["ReferralsResource", "AsyncReferralsResource"]
+
+
+class ReferralsResource(SyncAPIResource):
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+
+ @cached_property
+ def businesses(self) -> BusinessesResource:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ return BusinessesResource(self._client)
+
+ @cached_property
+ def partners(self) -> PartnersResource:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ return PartnersResource(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)
+
+ def referred_users(
+ self,
+ *,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ first: int | Omit = omit,
+ has_businesses: bool | Omit = omit,
+ has_earning_businesses: bool | Omit = omit,
+ last: 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,
+ ) -> ReferralReferredUsersResponse:
+ """
+ Lists the users the caller referred onto Whop (newest first), each with the
+ second-tier earnings the caller has made from that user's businesses.
+
+ 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).
+
+ first: Number of referred users to return from the start of the window.
+
+ has_businesses: When true, only referred users who brought at least one business onto Whop.
+
+ has_earning_businesses: When true, only referred users with at least one business that has generated
+ earnings.
+
+ last: Number of referred users to return from the end of the window.
+
+ 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(
+ "/partners/referred_users",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "after": after,
+ "before": before,
+ "first": first,
+ "has_businesses": has_businesses,
+ "has_earning_businesses": has_earning_businesses,
+ "last": last,
+ },
+ referral_referred_users_params.ReferralReferredUsersParams,
+ ),
+ ),
+ cast_to=ReferralReferredUsersResponse,
+ )
+
+
+class AsyncReferralsResource(AsyncAPIResource):
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+
+ @cached_property
+ def businesses(self) -> AsyncBusinessesResource:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ return AsyncBusinessesResource(self._client)
+
+ @cached_property
+ def partners(self) -> AsyncPartnersResource:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ return AsyncPartnersResource(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)
+
+ async def referred_users(
+ self,
+ *,
+ after: str | Omit = omit,
+ before: str | Omit = omit,
+ first: int | Omit = omit,
+ has_businesses: bool | Omit = omit,
+ has_earning_businesses: bool | Omit = omit,
+ last: 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,
+ ) -> ReferralReferredUsersResponse:
+ """
+ Lists the users the caller referred onto Whop (newest first), each with the
+ second-tier earnings the caller has made from that user's businesses.
+
+ 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).
+
+ first: Number of referred users to return from the start of the window.
+
+ has_businesses: When true, only referred users who brought at least one business onto Whop.
+
+ has_earning_businesses: When true, only referred users with at least one business that has generated
+ earnings.
+
+ last: Number of referred users to return from the end of the window.
+
+ 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(
+ "/partners/referred_users",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "after": after,
+ "before": before,
+ "first": first,
+ "has_businesses": has_businesses,
+ "has_earning_businesses": has_earning_businesses,
+ "last": last,
+ },
+ referral_referred_users_params.ReferralReferredUsersParams,
+ ),
+ ),
+ cast_to=ReferralReferredUsersResponse,
+ )
+
+
+class ReferralsResourceWithRawResponse:
+ def __init__(self, referrals: ReferralsResource) -> None:
+ self._referrals = referrals
+
+ self.referred_users = to_raw_response_wrapper(
+ referrals.referred_users,
+ )
+
+ @cached_property
+ def businesses(self) -> BusinessesResourceWithRawResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ return BusinessesResourceWithRawResponse(self._referrals.businesses)
+
+ @cached_property
+ def partners(self) -> PartnersResourceWithRawResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ return PartnersResourceWithRawResponse(self._referrals.partners)
+
+
+class AsyncReferralsResourceWithRawResponse:
+ def __init__(self, referrals: AsyncReferralsResource) -> None:
+ self._referrals = referrals
+
+ self.referred_users = async_to_raw_response_wrapper(
+ referrals.referred_users,
+ )
+
+ @cached_property
+ def businesses(self) -> AsyncBusinessesResourceWithRawResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ return AsyncBusinessesResourceWithRawResponse(self._referrals.businesses)
+
+ @cached_property
+ def partners(self) -> AsyncPartnersResourceWithRawResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ return AsyncPartnersResourceWithRawResponse(self._referrals.partners)
+
+
+class ReferralsResourceWithStreamingResponse:
+ def __init__(self, referrals: ReferralsResource) -> None:
+ self._referrals = referrals
+
+ self.referred_users = to_streamed_response_wrapper(
+ referrals.referred_users,
+ )
+
+ @cached_property
+ def businesses(self) -> BusinessesResourceWithStreamingResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ return BusinessesResourceWithStreamingResponse(self._referrals.businesses)
+
+ @cached_property
+ def partners(self) -> PartnersResourceWithStreamingResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ return PartnersResourceWithStreamingResponse(self._referrals.partners)
+
+
+class AsyncReferralsResourceWithStreamingResponse:
+ def __init__(self, referrals: AsyncReferralsResource) -> None:
+ self._referrals = referrals
+
+ self.referred_users = async_to_streamed_response_wrapper(
+ referrals.referred_users,
+ )
+
+ @cached_property
+ def businesses(self) -> AsyncBusinessesResourceWithStreamingResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ return AsyncBusinessesResourceWithStreamingResponse(self._referrals.businesses)
+
+ @cached_property
+ def partners(self) -> AsyncPartnersResourceWithStreamingResponse:
+ """
+ The Referrals API covers your Whop partner activity: the users you referred onto Whop, the businesses you referred and the earnings generated from their processing volume, and the partner leaderboard.
+
+ Use it to enroll as a Whop partner, list the users you referred, list your referred businesses and review their earnings, and see the partner leaderboard.
+ """
+ return AsyncPartnersResourceWithStreamingResponse(self._referrals.partners)
diff --git a/src/whop_sdk/resources/refunds.py b/src/whop_sdk/resources/refunds.py
index 5f56bdca7..7aa67e77e 100644
--- a/src/whop_sdk/resources/refunds.py
+++ b/src/whop_sdk/resources/refunds.py
@@ -28,8 +28,6 @@
class RefundsResource(SyncAPIResource):
- """Refunds"""
-
@cached_property
def with_raw_response(self) -> RefundsResourceWithRawResponse:
"""
@@ -177,8 +175,6 @@ def list(
class AsyncRefundsResource(AsyncAPIResource):
- """Refunds"""
-
@cached_property
def with_raw_response(self) -> AsyncRefundsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/resolution_center_cases.py b/src/whop_sdk/resources/resolution_center_cases.py
index 90eb6a477..8ab23c887 100644
--- a/src/whop_sdk/resources/resolution_center_cases.py
+++ b/src/whop_sdk/resources/resolution_center_cases.py
@@ -29,8 +29,6 @@
class ResolutionCenterCasesResource(SyncAPIResource):
- """Resolution center cases"""
-
@cached_property
def with_raw_response(self) -> ResolutionCenterCasesResourceWithRawResponse:
"""
@@ -169,8 +167,6 @@ def list(
class AsyncResolutionCenterCasesResource(AsyncAPIResource):
- """Resolution center cases"""
-
@cached_property
def with_raw_response(self) -> AsyncResolutionCenterCasesResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/reviews.py b/src/whop_sdk/resources/reviews.py
index b6dca5f60..0ac1ea34c 100644
--- a/src/whop_sdk/resources/reviews.py
+++ b/src/whop_sdk/resources/reviews.py
@@ -27,8 +27,6 @@
class ReviewsResource(SyncAPIResource):
- """Reviews"""
-
@cached_property
def with_raw_response(self) -> ReviewsResourceWithRawResponse:
"""
@@ -159,8 +157,6 @@ def list(
class AsyncReviewsResource(AsyncAPIResource):
- """Reviews"""
-
@cached_property
def with_raw_response(self) -> AsyncReviewsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/setup_intents.py b/src/whop_sdk/resources/setup_intents.py
index 4285c4d0d..4c3b154bb 100644
--- a/src/whop_sdk/resources/setup_intents.py
+++ b/src/whop_sdk/resources/setup_intents.py
@@ -28,8 +28,6 @@
class SetupIntentsResource(SyncAPIResource):
- """Setup intents"""
-
@cached_property
def with_raw_response(self) -> SetupIntentsResourceWithRawResponse:
"""
@@ -169,8 +167,6 @@ def list(
class AsyncSetupIntentsResource(AsyncAPIResource):
- """Setup intents"""
-
@cached_property
def with_raw_response(self) -> AsyncSetupIntentsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/shipments.py b/src/whop_sdk/resources/shipments.py
index 41067ad49..5a4eda54f 100644
--- a/src/whop_sdk/resources/shipments.py
+++ b/src/whop_sdk/resources/shipments.py
@@ -26,8 +26,6 @@
class ShipmentsResource(SyncAPIResource):
- """Shipments"""
-
@cached_property
def with_raw_response(self) -> ShipmentsResourceWithRawResponse:
"""
@@ -215,8 +213,6 @@ def list(
class AsyncShipmentsResource(AsyncAPIResource):
- """Shipments"""
-
@cached_property
def with_raw_response(self) -> AsyncShipmentsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/social_accounts.py b/src/whop_sdk/resources/social_accounts.py
new file mode 100644
index 000000000..a1628e32a
--- /dev/null
+++ b/src/whop_sdk/resources/social_accounts.py
@@ -0,0 +1,758 @@
+# 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,
+ social_account_connect_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_delete_response import SocialAccountDeleteResponse
+from ..types.social_account_connect_response import SocialAccountConnectResponse
+
+__all__ = ["SocialAccountsResource", "AsyncSocialAccountsResource"]
+
+
+class SocialAccountsResource(SyncAPIResource):
+ """
+ A Social Account represents an external profile connected to a Whop account or user, such as a Facebook page or Instagram account. Connecting a social account lets Whop run [ads](/api-reference/beta/ads/ad) under that profile's identity and promote its existing posts.
+
+ Use the Social Accounts API to list connected accounts, create a Whop-managed Facebook page, start an OAuth connection, disconnect a social account, and list a connected profile's posts.
+ """
+
+ @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["facebook"],
+ 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> SocialAccount:
+ """
+ Creates or returns a Whop-managed Facebook page for an account.
+
+ Args:
+ platform: The platform to create the social account on.
+
+ account_id: The Account (biz\\__ identifier) to create the social account for. An
+ account-scoped API key may omit this to default to its own account.
+
+ 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,
+ "account_id": account_id,
+ },
+ 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=SocialAccount,
+ )
+
+ 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.
+
+ 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 without deleting the
+ underlying platform account.
+
+ 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 connect(
+ self,
+ *,
+ platform: Literal["meta_business"],
+ account_id: str | Omit = omit,
+ redirect_url: 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,
+ ) -> SocialAccountConnectResponse:
+ """
+ Starts an OAuth connection flow and returns an authorize_url where the user can
+ connect a social account.
+
+ Args:
+ platform: The platform to connect the social account on. Today, the supported option is
+ `meta_business`.
+
+ 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.
+
+ redirect_url: The Whop URL to redirect the user to after they finish connecting.
+
+ scopes: Capabilities to grant for the connected social account. Use `advertise` when
+ connecting a Meta Business account for ads.
+
+ 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/connect",
+ body=maybe_transform(
+ {
+ "platform": platform,
+ "account_id": account_id,
+ "redirect_url": redirect_url,
+ "scopes": scopes,
+ },
+ social_account_connect_params.SocialAccountConnectParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SocialAccountConnectResponse,
+ )
+
+ 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 Facebook page or Instagram account.
+
+ 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):
+ """
+ A Social Account represents an external profile connected to a Whop account or user, such as a Facebook page or Instagram account. Connecting a social account lets Whop run [ads](/api-reference/beta/ads/ad) under that profile's identity and promote its existing posts.
+
+ Use the Social Accounts API to list connected accounts, create a Whop-managed Facebook page, start an OAuth connection, disconnect a social account, and list a connected profile's posts.
+ """
+
+ @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["facebook"],
+ 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> SocialAccount:
+ """
+ Creates or returns a Whop-managed Facebook page for an account.
+
+ Args:
+ platform: The platform to create the social account on.
+
+ account_id: The Account (biz\\__ identifier) to create the social account for. An
+ account-scoped API key may omit this to default to its own account.
+
+ 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,
+ "account_id": account_id,
+ },
+ 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=SocialAccount,
+ )
+
+ 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.
+
+ 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 without deleting the
+ underlying platform account.
+
+ 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 connect(
+ self,
+ *,
+ platform: Literal["meta_business"],
+ account_id: str | Omit = omit,
+ redirect_url: 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,
+ ) -> SocialAccountConnectResponse:
+ """
+ Starts an OAuth connection flow and returns an authorize_url where the user can
+ connect a social account.
+
+ Args:
+ platform: The platform to connect the social account on. Today, the supported option is
+ `meta_business`.
+
+ 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.
+
+ redirect_url: The Whop URL to redirect the user to after they finish connecting.
+
+ scopes: Capabilities to grant for the connected social account. Use `advertise` when
+ connecting a Meta Business account for ads.
+
+ 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/connect",
+ body=await async_maybe_transform(
+ {
+ "platform": platform,
+ "account_id": account_id,
+ "redirect_url": redirect_url,
+ "scopes": scopes,
+ },
+ social_account_connect_params.SocialAccountConnectParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SocialAccountConnectResponse,
+ )
+
+ 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 Facebook page or Instagram account.
+
+ 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.connect = to_raw_response_wrapper(
+ social_accounts.connect,
+ )
+ 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.connect = async_to_raw_response_wrapper(
+ social_accounts.connect,
+ )
+ 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.connect = to_streamed_response_wrapper(
+ social_accounts.connect,
+ )
+ 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.connect = async_to_streamed_response_wrapper(
+ social_accounts.connect,
+ )
+ 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 000000000..eb091fda1
--- /dev/null
+++ b/src/whop_sdk/resources/stats.py
@@ -0,0 +1,498 @@
+# 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, SequenceNotStr, 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 represent aggregated activity for an account over time.
+
+ They help you understand revenue, transactions, disputes, members, referrals, and advertising performance across reporting periods like days, weeks, or months.
+
+ Use the Stats API to list available metrics and their filterable properties, then retrieve time-series values for a date range.
+ """
+
+ @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,
+ *,
+ from_: Union[str, date],
+ to: Union[str, date],
+ access_level: str | Omit = omit,
+ account_id: str | Omit = omit,
+ ad_campaign_ids: SequenceNotStr[str] | Omit = omit,
+ ad_group_ids: SequenceNotStr[str] | Omit = omit,
+ ad_ids: SequenceNotStr[str] | Omit = omit,
+ breakdown_by: str | Omit = omit,
+ card_network: str | Omit = omit,
+ category: str | Omit = omit,
+ convert_to: str | Omit = omit,
+ currency: str | Omit = omit,
+ fee_type: str | Omit = omit,
+ interval: Literal["hour", "day", "week", "month", "year"] | Omit = omit,
+ most_recent_action: str | Omit = omit,
+ payment_method: str | Omit = omit,
+ product: str | Omit = omit,
+ referred_user_id: str | Omit = omit,
+ segment: str | Omit = omit,
+ snapshot_window: Literal["30d"] | Omit = omit,
+ source: str | Omit = omit,
+ status: str | 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:
+ from_: Start of the date range (YYYY-MM-DD).
+
+ to: End of the date range (YYYY-MM-DD).
+
+ access_level: Filter to a single access level. Pair with breakdown_by=access_level. Available
+ on metrics that list access_level.
+
+ account_id: The account this query concerns, for example biz_AbC123.
+
+ ad_campaign_ids: Ad campaign ids (adcamp\\__...) to scope the report to; stats are summed across
+ them. Available on metrics that list ad_campaign_ids.
+
+ ad_group_ids: Ad group ids (adgrp\\__...) to scope the report to; stats are summed across them.
+ Available on metrics that list ad_group_ids.
+
+ ad_ids: Ad ids (ad\\__...) to scope the report to; stats are summed across them. Available
+ on metrics that list ad_ids.
+
+ 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.
+
+ category: Filter to a single balance-activity category, for example payments. Pair with
+ breakdown_by=category to split the activity. Available on metrics that list
+ category.
+
+ 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. For the
+ ads metrics (ad_spend, ad_report), pass the account's ads reporting currency to
+ match the ad entity endpoints. 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.
+
+ fee_type: Filter to a single fee type. Pair with breakdown_by=fee_type to split fees by
+ type. Available on metrics that list fee_type.
+
+ interval: How wide each point is. Defaults to day. Snapshot metrics are day-only.
+
+ most_recent_action: Filter to a single most-recent member action. Pair with
+ breakdown_by=most_recent_action. Available on metrics that list
+ most_recent_action.
+
+ payment_method: Filter to a single payment method, for example card or crypto. Available on
+ metrics that list payment_method.
+
+ product: Filter to a single product (access pass id), for example prod_AbC123. Pair with
+ breakdown_by=product. Available on metrics that list product.
+
+ referred_user_id: Filter a referral metric to the businesses attributed to one person you
+ referred, for example user_AbC123. Available on metrics that list
+ referred_user_id.
+
+ segment: Filter to a single wallet-balance segment, for example available. Pair with
+ breakdown_by=segment to split the balance. Available on metrics that list
+ segment.
+
+ 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.
+
+ source: Filter to a single GMV source, for example payments. Pair with
+ breakdown_by=source to split by source. Available on metrics that list source.
+
+ status: Filter to a single membership status. Pair with breakdown_by=status. Available
+ on metrics that list status.
+
+ 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(
+ {
+ "from_": from_,
+ "to": to,
+ "access_level": access_level,
+ "account_id": account_id,
+ "ad_campaign_ids": ad_campaign_ids,
+ "ad_group_ids": ad_group_ids,
+ "ad_ids": ad_ids,
+ "breakdown_by": breakdown_by,
+ "card_network": card_network,
+ "category": category,
+ "convert_to": convert_to,
+ "currency": currency,
+ "fee_type": fee_type,
+ "interval": interval,
+ "most_recent_action": most_recent_action,
+ "payment_method": payment_method,
+ "product": product,
+ "referred_user_id": referred_user_id,
+ "segment": segment,
+ "snapshot_window": snapshot_window,
+ "source": source,
+ "status": status,
+ "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 represent aggregated activity for an account over time.
+
+ They help you understand revenue, transactions, disputes, members, referrals, and advertising performance across reporting periods like days, weeks, or months.
+
+ Use the Stats API to list available metrics and their filterable properties, then retrieve time-series values for a date range.
+ """
+
+ @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,
+ *,
+ from_: Union[str, date],
+ to: Union[str, date],
+ access_level: str | Omit = omit,
+ account_id: str | Omit = omit,
+ ad_campaign_ids: SequenceNotStr[str] | Omit = omit,
+ ad_group_ids: SequenceNotStr[str] | Omit = omit,
+ ad_ids: SequenceNotStr[str] | Omit = omit,
+ breakdown_by: str | Omit = omit,
+ card_network: str | Omit = omit,
+ category: str | Omit = omit,
+ convert_to: str | Omit = omit,
+ currency: str | Omit = omit,
+ fee_type: str | Omit = omit,
+ interval: Literal["hour", "day", "week", "month", "year"] | Omit = omit,
+ most_recent_action: str | Omit = omit,
+ payment_method: str | Omit = omit,
+ product: str | Omit = omit,
+ referred_user_id: str | Omit = omit,
+ segment: str | Omit = omit,
+ snapshot_window: Literal["30d"] | Omit = omit,
+ source: str | Omit = omit,
+ status: str | 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:
+ from_: Start of the date range (YYYY-MM-DD).
+
+ to: End of the date range (YYYY-MM-DD).
+
+ access_level: Filter to a single access level. Pair with breakdown_by=access_level. Available
+ on metrics that list access_level.
+
+ account_id: The account this query concerns, for example biz_AbC123.
+
+ ad_campaign_ids: Ad campaign ids (adcamp\\__...) to scope the report to; stats are summed across
+ them. Available on metrics that list ad_campaign_ids.
+
+ ad_group_ids: Ad group ids (adgrp\\__...) to scope the report to; stats are summed across them.
+ Available on metrics that list ad_group_ids.
+
+ ad_ids: Ad ids (ad\\__...) to scope the report to; stats are summed across them. Available
+ on metrics that list ad_ids.
+
+ 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.
+
+ category: Filter to a single balance-activity category, for example payments. Pair with
+ breakdown_by=category to split the activity. Available on metrics that list
+ category.
+
+ 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. For the
+ ads metrics (ad_spend, ad_report), pass the account's ads reporting currency to
+ match the ad entity endpoints. 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.
+
+ fee_type: Filter to a single fee type. Pair with breakdown_by=fee_type to split fees by
+ type. Available on metrics that list fee_type.
+
+ interval: How wide each point is. Defaults to day. Snapshot metrics are day-only.
+
+ most_recent_action: Filter to a single most-recent member action. Pair with
+ breakdown_by=most_recent_action. Available on metrics that list
+ most_recent_action.
+
+ payment_method: Filter to a single payment method, for example card or crypto. Available on
+ metrics that list payment_method.
+
+ product: Filter to a single product (access pass id), for example prod_AbC123. Pair with
+ breakdown_by=product. Available on metrics that list product.
+
+ referred_user_id: Filter a referral metric to the businesses attributed to one person you
+ referred, for example user_AbC123. Available on metrics that list
+ referred_user_id.
+
+ segment: Filter to a single wallet-balance segment, for example available. Pair with
+ breakdown_by=segment to split the balance. Available on metrics that list
+ segment.
+
+ 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.
+
+ source: Filter to a single GMV source, for example payments. Pair with
+ breakdown_by=source to split by source. Available on metrics that list source.
+
+ status: Filter to a single membership status. Pair with breakdown_by=status. Available
+ on metrics that list status.
+
+ 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(
+ {
+ "from_": from_,
+ "to": to,
+ "access_level": access_level,
+ "account_id": account_id,
+ "ad_campaign_ids": ad_campaign_ids,
+ "ad_group_ids": ad_group_ids,
+ "ad_ids": ad_ids,
+ "breakdown_by": breakdown_by,
+ "card_network": card_network,
+ "category": category,
+ "convert_to": convert_to,
+ "currency": currency,
+ "fee_type": fee_type,
+ "interval": interval,
+ "most_recent_action": most_recent_action,
+ "payment_method": payment_method,
+ "product": product,
+ "referred_user_id": referred_user_id,
+ "segment": segment,
+ "snapshot_window": snapshot_window,
+ "source": source,
+ "status": status,
+ "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/support_channels.py b/src/whop_sdk/resources/support_channels.py
index 3e8a5579b..db5bc8c7f 100644
--- a/src/whop_sdk/resources/support_channels.py
+++ b/src/whop_sdk/resources/support_channels.py
@@ -28,8 +28,6 @@
class SupportChannelsResource(SyncAPIResource):
- """Support channels"""
-
@cached_property
def with_raw_response(self) -> SupportChannelsResourceWithRawResponse:
"""
@@ -225,8 +223,6 @@ def list(
class AsyncSupportChannelsResource(AsyncAPIResource):
- """Support channels"""
-
@cached_property
def with_raw_response(self) -> AsyncSupportChannelsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/swaps.py b/src/whop_sdk/resources/swaps.py
index a79eabbe5..f53ab32f8 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,12 +18,21 @@
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"]
class SwapsResource(SyncAPIResource):
+ """
+ Swaps convert value between supported tokens, chains, or wallet destinations for an account. A swap quote describes the expected output, fees, and approval requirements before you create the swap.
+
+ Use the Swaps API to quote a conversion, create the swap, list recent swaps, and retrieve status until the transaction completes.
+ """
+
@cached_property
def with_raw_response(self) -> SwapsResourceWithRawResponse:
"""
@@ -43,6 +52,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 +215,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
@@ -105,6 +267,12 @@ def create_quote(
class AsyncSwapsResource(AsyncAPIResource):
+ """
+ Swaps convert value between supported tokens, chains, or wallet destinations for an account. A swap quote describes the expected output, fees, and approval requirements before you create the swap.
+
+ Use the Swaps API to quote a conversion, create the swap, list recent swaps, and retrieve status until the transaction completes.
+ """
+
@cached_property
def with_raw_response(self) -> AsyncSwapsResourceWithRawResponse:
"""
@@ -124,6 +292,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 +455,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 +510,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 +528,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 +546,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 +564,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/topups.py b/src/whop_sdk/resources/topups.py
index 8dd556586..858cd8915 100644
--- a/src/whop_sdk/resources/topups.py
+++ b/src/whop_sdk/resources/topups.py
@@ -23,8 +23,6 @@
class TopupsResource(SyncAPIResource):
- """Topups"""
-
@cached_property
def with_raw_response(self) -> TopupsResourceWithRawResponse:
"""
@@ -103,8 +101,6 @@ def create(
class AsyncTopupsResource(AsyncAPIResource):
- """Topups"""
-
@cached_property
def with_raw_response(self) -> AsyncTopupsResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/transfers.py b/src/whop_sdk/resources/transfers.py
index 806984ba5..72209dde0 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,16 +21,20 @@
)
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"""
+ """Transfers move value between identities on Whop.
+
+ They are used for account-to-account money movement, user payouts inside Whop, crypto transfers, and claim links depending on the destination type.
+
+ Use the Transfers API to create a transfer, list previous transfers, and retrieve a transfer by ID when reconciling money movement between accounts or users.
+ """
@cached_property
def with_raw_response(self) -> TransfersResourceWithRawResponse:
@@ -55,48 +59,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.
+ ) -> TransferCreateResponse:
+ """Moves funds out of an account.
- Required permissions:
-
- - `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 +116,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 +154,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 +174,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 +197,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,7 +260,12 @@ def list(
class AsyncTransfersResource(AsyncAPIResource):
- """Transfers"""
+ """Transfers move value between identities on Whop.
+
+ They are used for account-to-account money movement, user payouts inside Whop, crypto transfers, and claim links depending on the destination type.
+
+ Use the Transfers API to create a transfer, list previous transfers, and retrieve a transfer by ID when reconciling money movement between accounts or users.
+ """
@cached_property
def with_raw_response(self) -> AsyncTransfersResourceWithRawResponse:
@@ -276,48 +290,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.
+ ) -> TransferCreateResponse:
+ """Moves funds out of an account.
- Required permissions:
-
- - `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 +347,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 +385,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 +405,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 +428,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 e0ce27c0a..0c2647980 100644
--- a/src/whop_sdk/resources/users.py
+++ b/src/whop_sdk/resources/users.py
@@ -2,11 +2,11 @@
from __future__ import annotations
-from typing import Optional
+from typing_extensions import Literal
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,14 +20,18 @@
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"""
+ """A User represents a person on Whop.
+
+ Users have a public profile and can buy products, join accounts, and access experiences.
+
+ Use the Users API to search for users, retrieve or update profiles, and check whether a user has access to an account, product, or experience.
+ """
@cached_property
def with_raw_response(self) -> UsersResourceWithRawResponse:
@@ -52,7 +56,12 @@ def retrieve(
self,
id: str,
*,
- company_id: Optional[str] | Omit = omit,
+ account_id: str | Omit = omit,
+ from_: str | Omit = omit,
+ include_balance_history: bool | Omit = omit,
+ interval: Literal["hour", "day", "week", "month"] | Omit = omit,
+ time_zone: str | Omit = omit,
+ 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,11 +70,27 @@ 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.
+
+ from_: Balance-history window start, ISO 8601 date or datetime. Defaults to 30 days
+ ago. Only used with `include_balance_history`.
+
+ include_balance_history: On `GET /users/me`, also compute the caller's balance history (opt-in; runs a
+ heavier query). Ignored for other users and for callers without balance-read
+ scope.
+
+ interval: Balance-history point granularity. Defaults to `day`. Only used with
+ `include_balance_history`.
+
+ time_zone: IANA time zone the balance-history points are bucketed in. Defaults to `UTC`.
+ Only used with `include_balance_history`.
+
+ to: Balance-history window end, ISO 8601 date or datetime. Defaults to now. Only
+ used with `include_balance_history`.
extra_headers: Send extra headers
@@ -84,7 +109,17 @@ 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,
+ "from_": from_,
+ "include_balance_history": include_balance_history,
+ "interval": interval,
+ "time_zone": time_zone,
+ "to": to,
+ },
+ user_retrieve_params.UserRetrieveParams,
+ ),
),
cast_to=User,
)
@@ -93,11 +128,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 +140,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.
+ """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
@@ -141,7 +163,6 @@ def update(
body=maybe_transform(
{
"bio": bio,
- "company_id": company_id,
"name": name,
"profile_picture": profile_picture,
"username": username,
@@ -149,7 +170,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 +182,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 +220,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 +237,7 @@ def list(
user_list_params.UserListParams,
),
),
- model=UserListResponse,
+ model=User,
)
def check_access(
@@ -227,8 +253,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,9 +277,66 @@ 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.
+
+ 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):
- """Users"""
+ """A User represents a person on Whop.
+
+ Users have a public profile and can buy products, join accounts, and access experiences.
+
+ Use the Users API to search for users, retrieve or update profiles, and check whether a user has access to an account, product, or experience.
+ """
@cached_property
def with_raw_response(self) -> AsyncUsersResourceWithRawResponse:
@@ -278,7 +361,12 @@ async def retrieve(
self,
id: str,
*,
- company_id: Optional[str] | Omit = omit,
+ account_id: str | Omit = omit,
+ from_: str | Omit = omit,
+ include_balance_history: bool | Omit = omit,
+ interval: Literal["hour", "day", "week", "month"] | Omit = omit,
+ time_zone: str | Omit = omit,
+ 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,
@@ -287,11 +375,27 @@ 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.
+
+ from_: Balance-history window start, ISO 8601 date or datetime. Defaults to 30 days
+ ago. Only used with `include_balance_history`.
+
+ include_balance_history: On `GET /users/me`, also compute the caller's balance history (opt-in; runs a
+ heavier query). Ignored for other users and for callers without balance-read
+ scope.
+
+ interval: Balance-history point granularity. Defaults to `day`. Only used with
+ `include_balance_history`.
+
+ time_zone: IANA time zone the balance-history points are bucketed in. Defaults to `UTC`.
+ Only used with `include_balance_history`.
+
+ to: Balance-history window end, ISO 8601 date or datetime. Defaults to now. Only
+ used with `include_balance_history`.
extra_headers: Send extra headers
@@ -310,7 +414,17 @@ 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,
+ "from_": from_,
+ "include_balance_history": include_balance_history,
+ "interval": interval,
+ "time_zone": time_zone,
+ "to": to,
+ },
+ user_retrieve_params.UserRetrieveParams,
+ ),
),
cast_to=User,
)
@@ -319,11 +433,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 +445,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.
-
- 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
@@ -367,7 +468,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 +475,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 +487,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 +525,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 +542,7 @@ def list(
user_list_params.UserListParams,
),
),
- model=UserListResponse,
+ model=User,
)
async def check_access(
@@ -453,8 +558,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 +582,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 +651,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 +672,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 +693,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 +714,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 4fce0869f..784cbbe16 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, overload
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, required_args, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -17,16 +18,22 @@
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_update_response import VerificationUpdateResponse
from ..types.verification_retrieve_response import VerificationRetrieveResponse
__all__ = ["VerificationsResource", "AsyncVerificationsResource"]
class VerificationsResource(SyncAPIResource):
- """Verifications"""
+ """A Verification represents an identity review for a person or business.
+
+ Accounts and users complete verification when Whop needs to confirm who they are before enabling payouts or compliance-sensitive workflows.
+
+ Use the Verifications API to start or resume a hosted verification session, check review status, and submit requested details or documents. If `requested_information` contains items, submit answers with [Update Verification](/api-reference/beta/verifications/update-verification).
+ """
@cached_property
def with_raw_response(self) -> VerificationsResourceWithRawResponse:
@@ -47,25 +54,133 @@ def with_streaming_response(self) -> VerificationsResourceWithStreamingResponse:
"""
return VerificationsResourceWithStreamingResponse(self)
- def retrieve(
+ @overload
+ def create(
self,
- id: str,
*,
+ account_id: str,
+ address: verification_create_params.CreateIndividualVerificationAddress | 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,
+ document_type: Literal["ID_CARD", "PASSPORT", "DRIVERS", "RESIDENCE_PERMIT"] | Omit = omit,
+ documents: Dict[str, str] | Omit = omit,
+ first_name: str | Omit = omit,
+ kind: Literal["individual"] | Omit = omit,
+ last_name: str | Omit = omit,
+ phone: str | 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.
+ Starts a hosted verification session for an account or user, or returns the
+ active session when one already exists. Any fields you include in the request
+ body are used to prefill the session. Send `documents` (with `document_type`) to
+ instead verify the person from identity documents included in this request — no
+ hosted session involved. If the account already has an `approved` verification
+ the request is rejected; unlink it first to start a new one.
+
+ Args:
+ account_id: Account or user ID whose identity you want to verify. Use a `biz_` account ID
+ for account verifications, or the caller's `user_` ID for personal verification.
+
+ business_name: Legal business name for a sole proprietor or single-member LLC.
+
+ business_structure: Entity type for sole proprietors, such as `single_member_llc`. Supported values
+ vary by country of incorporation — see
+ [Business structures](/developer/verification/business-structures).
+
+ business_website: Business website URL. Whop store pages are not accepted.
+
+ country: Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`.
- Required permissions:
+ date_of_birth: Formatted as `YYYY-MM-DD`.
- - `payout:account:read`
+ document_type: Identity document being sent. Providing it (with `documents`) verifies from
+ uploaded documents instead of a hosted session, and determines the expected
+ `documents` keys: cards and licenses need front and back, passports only the
+ photo page.
+
+ documents: Identity document files, keyed by slot (`id_card_front`, `id_card_back`,
+ `selfie`, …) with each value the file's raw bytes base64-encoded. Providing them
+ verifies the person from these documents instead of a hosted session —
+ individual verifications only, and the request must also carry `document_type`,
+ `first_name`, `last_name`, `date_of_birth`, `country`, `phone`,
+ `tax_identification_number`, and an `address` with `line1`, `city`, `state`, and
+ `postal_code`. JPEG, PNG, and PDF are accepted (selfies must be images), up to
+ 5MB per file before encoding. Send the complete set — a missing or rejected file
+ fails the whole request and nothing is submitted; review starts automatically
+ once every document is accepted.
+
+ kind: Verification type. Defaults to `individual`.
+
+ tax_identification_number: SSN or ITIN. Tokenized in transit and never stored raw.
+
+ 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,
+ *,
+ account_id: str,
+ address: verification_create_params.CreateBusinessVerificationAddress | Omit = omit,
+ business_name: str | Omit = omit,
+ business_structure: str | Omit = omit,
+ business_website: str | Omit = omit,
+ country: str | Omit = omit,
+ kind: Literal["business"] | Omit = omit,
+ place_of_incorporation: str | 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,
+ ) -> VerificationCreateResponse:
+ """
+ Starts a hosted verification session for an account or user, or returns the
+ active session when one already exists. Any fields you include in the request
+ body are used to prefill the session. Send `documents` (with `document_type`) to
+ instead verify the person from identity documents included in this request — no
+ hosted session involved. If the account already has an `approved` verification
+ the request is rejected; unlink it first to start a new one.
Args:
+ account_id: Account or user ID whose identity you want to verify. Use a `biz_` account ID
+ for account verifications, or the caller's `user_` ID for personal verification.
+
+ business_name: Legal business name.
+
+ business_structure: Legal entity structure of the business, such as `private_corporation` or
+ `sole_proprietorship`. Supported values vary by country of incorporation — see
+ [Business structures](/developer/verification/business-structures).
+
+ business_website: Business website URL. Whop store pages are not accepted.
+
+ country: Country of incorporation as a two-letter ISO 3166-1 country code.
+
+ kind: Must be `business` to start a KYB verification.
+
+ place_of_incorporation: State or region where the business is incorporated.
+
+ tax_identification_number: EIN. Tokenized in transit and never stored raw.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -74,49 +189,185 @@ 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}")
+ ...
+
+ @required_args(["account_id"])
+ def create(
+ self,
+ *,
+ account_id: str,
+ address: verification_create_params.CreateIndividualVerificationAddress
+ | verification_create_params.CreateBusinessVerificationAddress
+ | 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,
+ document_type: Literal["ID_CARD", "PASSPORT", "DRIVERS", "RESIDENCE_PERMIT"] | Omit = omit,
+ documents: Dict[str, str] | Omit = omit,
+ first_name: str | Omit = omit,
+ kind: Literal["individual"] | Literal["business"] | Omit = omit,
+ last_name: str | Omit = omit,
+ phone: str | Omit = omit,
+ tax_identification_number: str | Omit = omit,
+ place_of_incorporation: 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,
+ ) -> VerificationCreateResponse:
+ 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,
+ "document_type": document_type,
+ "documents": documents,
+ "first_name": first_name,
+ "kind": kind,
+ "last_name": last_name,
+ "phone": phone,
+ "tax_identification_number": tax_identification_number,
+ "place_of_incorporation": place_of_incorporation,
+ },
+ 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,
+ )
+
+ 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:
+ """
+ Returns verifications for an account, including their status and any required
+ actions.
+
+ 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._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(
+ @overload
+ 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,
+ country: str | Omit = omit,
+ date_of_birth: str | Omit = omit,
+ first_name: str | Omit = omit,
+ last_name: str | Omit = omit,
+ personal_address: verification_update_params.UpdateIndividualVerificationPersonalAddress | Omit = omit,
+ requested_information: Iterable[verification_update_params.UpdateIndividualVerificationRequestedInformation]
+ | 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 editable profile details or submits answers for items returned in
+ `requested_information`. Once a verification is `approved` its profile details
+ are locked and can no longer be edited.
+
+ Args:
+ country: Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`.
+
+ date_of_birth: Formatted as `YYYY-MM-DD`.
- Required permissions:
+ personal_address: Personal address for the individual.
- - `payout:account:read`
+ requested_information: Answers to items returned in `requested_information`. Each entry must include
+ the requested item `id` and exactly one answer payload matching the item's
+ `type`: `value` for `text`, `date`, or `phone`; `address` for `address`; `files`
+ for `files`.
+
+ 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 update(
+ self,
+ verification_id: str,
+ *,
+ business_address: verification_update_params.UpdateBusinessVerificationBusinessAddress | Omit = omit,
+ business_name: str | Omit = omit,
+ business_structure: str | Omit = omit,
+ country: str | Omit = omit,
+ requested_information: Iterable[verification_update_params.UpdateBusinessVerificationRequestedInformation]
+ | 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,
+ ) -> VerificationUpdateResponse:
+ """
+ Updates editable profile details or submits answers for items returned in
+ `requested_information`. Once a verification is `approved` its profile details
+ are locked and can no longer be edited.
Args:
- payout_account_id: The unique identifier of the payout account to list verifications for.
+ business_address: Business address.
- after: Returns the elements in the list that come after the specified cursor.
+ business_name: Legal business name.
- before: Returns the elements in the list that come before the specified cursor.
+ business_structure: Legal entity structure of the business, such as `private_corporation` or
+ `sole_proprietorship`. Supported values vary by country of incorporation — see
+ [Business structures](/developer/verification/business-structures).
- first: Returns the first _n_ elements from the list.
+ country: Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`.
- last: Returns the last _n_ elements from the list.
+ requested_information: Answers to items returned in `requested_information`. Each entry must include
+ the requested item `id` and exactly one answer payload matching the item's
+ `type`: `value` for `text`, `date`, or `phone`; `address` for `address`; `files`
+ for `files`.
extra_headers: Send extra headers
@@ -126,9 +377,89 @@ def list(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return self._get_api_list(
+ ...
+
+ def update(
+ self,
+ verification_id: str,
+ *,
+ country: str | Omit = omit,
+ date_of_birth: str | Omit = omit,
+ first_name: str | Omit = omit,
+ last_name: str | Omit = omit,
+ personal_address: verification_update_params.UpdateIndividualVerificationPersonalAddress | Omit = omit,
+ requested_information: Iterable[verification_update_params.UpdateIndividualVerificationRequestedInformation]
+ | Iterable[verification_update_params.UpdateBusinessVerificationRequestedInformation]
+ | Omit = omit,
+ business_address: verification_update_params.UpdateBusinessVerificationBusinessAddress | Omit = omit,
+ business_name: str | Omit = omit,
+ business_structure: 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,
+ ) -> VerificationUpdateResponse:
+ 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(
+ {
+ "country": country,
+ "date_of_birth": date_of_birth,
+ "first_name": first_name,
+ "last_name": last_name,
+ "personal_address": personal_address,
+ "requested_information": requested_information,
+ "business_address": business_address,
+ "business_name": business_name,
+ "business_structure": business_structure,
+ },
+ 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:
+ """
+ Returns verifications for an account, including their status and any required
+ actions.
+
+ Args:
+ account_id: Account or user ID whose verifications you want to list. Use a `biz_` account
+ ID, or the caller's `user_` ID for personal verifications.
+
+ direction: Sort direction for returned verifications.
+
+ order: Field used to sort returned verifications.
+
+ 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,21 +467,24 @@ 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,
)
class AsyncVerificationsResource(AsyncAPIResource):
- """Verifications"""
+ """A Verification represents an identity review for a person or business.
+
+ Accounts and users complete verification when Whop needs to confirm who they are before enabling payouts or compliance-sensitive workflows.
+
+ Use the Verifications API to start or resume a hosted verification session, check review status, and submit requested details or documents. If `requested_information` contains items, submit answers with [Update Verification](/api-reference/beta/verifications/update-verification).
+ """
@cached_property
def with_raw_response(self) -> AsyncVerificationsResourceWithRawResponse:
@@ -171,23 +505,218 @@ def with_streaming_response(self) -> AsyncVerificationsResourceWithStreamingResp
"""
return AsyncVerificationsResourceWithStreamingResponse(self)
- async def retrieve(
+ @overload
+ async def create(
self,
- id: str,
*,
+ account_id: str,
+ address: verification_create_params.CreateIndividualVerificationAddress | 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,
+ document_type: Literal["ID_CARD", "PASSPORT", "DRIVERS", "RESIDENCE_PERMIT"] | Omit = omit,
+ documents: Dict[str, str] | Omit = omit,
+ first_name: str | Omit = omit,
+ kind: Literal["individual"] | Omit = omit,
+ last_name: str | Omit = omit,
+ phone: str | 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.
+ Starts a hosted verification session for an account or user, or returns the
+ active session when one already exists. Any fields you include in the request
+ body are used to prefill the session. Send `documents` (with `document_type`) to
+ instead verify the person from identity documents included in this request — no
+ hosted session involved. If the account already has an `approved` verification
+ the request is rejected; unlink it first to start a new one.
- Required permissions:
+ Args:
+ account_id: Account or user ID whose identity you want to verify. Use a `biz_` account ID
+ for account verifications, or the caller's `user_` ID for personal verification.
- - `payout:account:read`
+ business_name: Legal business name for a sole proprietor or single-member LLC.
+
+ business_structure: Entity type for sole proprietors, such as `single_member_llc`. Supported values
+ vary by country of incorporation — see
+ [Business structures](/developer/verification/business-structures).
+
+ business_website: Business website URL. Whop store pages are not accepted.
+
+ country: Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`.
+
+ date_of_birth: Formatted as `YYYY-MM-DD`.
+
+ document_type: Identity document being sent. Providing it (with `documents`) verifies from
+ uploaded documents instead of a hosted session, and determines the expected
+ `documents` keys: cards and licenses need front and back, passports only the
+ photo page.
+
+ documents: Identity document files, keyed by slot (`id_card_front`, `id_card_back`,
+ `selfie`, …) with each value the file's raw bytes base64-encoded. Providing them
+ verifies the person from these documents instead of a hosted session —
+ individual verifications only, and the request must also carry `document_type`,
+ `first_name`, `last_name`, `date_of_birth`, `country`, `phone`,
+ `tax_identification_number`, and an `address` with `line1`, `city`, `state`, and
+ `postal_code`. JPEG, PNG, and PDF are accepted (selfies must be images), up to
+ 5MB per file before encoding. Send the complete set — a missing or rejected file
+ fails the whole request and nothing is submitted; review starts automatically
+ once every document is accepted.
+
+ kind: Verification type. Defaults to `individual`.
+
+ tax_identification_number: SSN or ITIN. Tokenized in transit and never stored raw.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ ...
+
+ @overload
+ async def create(
+ self,
+ *,
+ account_id: str,
+ address: verification_create_params.CreateBusinessVerificationAddress | Omit = omit,
+ business_name: str | Omit = omit,
+ business_structure: str | Omit = omit,
+ business_website: str | Omit = omit,
+ country: str | Omit = omit,
+ kind: Literal["business"] | Omit = omit,
+ place_of_incorporation: str | 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,
+ ) -> VerificationCreateResponse:
+ """
+ Starts a hosted verification session for an account or user, or returns the
+ active session when one already exists. Any fields you include in the request
+ body are used to prefill the session. Send `documents` (with `document_type`) to
+ instead verify the person from identity documents included in this request — no
+ hosted session involved. If the account already has an `approved` verification
+ the request is rejected; unlink it first to start a new one.
+
+ Args:
+ account_id: Account or user ID whose identity you want to verify. Use a `biz_` account ID
+ for account verifications, or the caller's `user_` ID for personal verification.
+
+ business_name: Legal business name.
+
+ business_structure: Legal entity structure of the business, such as `private_corporation` or
+ `sole_proprietorship`. Supported values vary by country of incorporation — see
+ [Business structures](/developer/verification/business-structures).
+
+ business_website: Business website URL. Whop store pages are not accepted.
+
+ country: Country of incorporation as a two-letter ISO 3166-1 country code.
+
+ kind: Must be `business` to start a KYB verification.
+
+ place_of_incorporation: State or region where the business is incorporated.
+
+ tax_identification_number: EIN. Tokenized in transit and never stored raw.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ ...
+
+ @required_args(["account_id"])
+ async def create(
+ self,
+ *,
+ account_id: str,
+ address: verification_create_params.CreateIndividualVerificationAddress
+ | verification_create_params.CreateBusinessVerificationAddress
+ | 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,
+ document_type: Literal["ID_CARD", "PASSPORT", "DRIVERS", "RESIDENCE_PERMIT"] | Omit = omit,
+ documents: Dict[str, str] | Omit = omit,
+ first_name: str | Omit = omit,
+ kind: Literal["individual"] | Literal["business"] | Omit = omit,
+ last_name: str | Omit = omit,
+ phone: str | Omit = omit,
+ tax_identification_number: str | Omit = omit,
+ place_of_incorporation: 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,
+ ) -> VerificationCreateResponse:
+ 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,
+ "document_type": document_type,
+ "documents": documents,
+ "first_name": first_name,
+ "kind": kind,
+ "last_name": last_name,
+ "phone": phone,
+ "tax_identification_number": tax_identification_number,
+ "place_of_incorporation": place_of_incorporation,
+ },
+ 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:
+ """
+ Returns verifications for an account, including their status and any required
+ actions.
Args:
extra_headers: Send extra headers
@@ -198,49 +727,100 @@ 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(
+ @overload
+ 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,
+ country: str | Omit = omit,
+ date_of_birth: str | Omit = omit,
+ first_name: str | Omit = omit,
+ last_name: str | Omit = omit,
+ personal_address: verification_update_params.UpdateIndividualVerificationPersonalAddress | Omit = omit,
+ requested_information: Iterable[verification_update_params.UpdateIndividualVerificationRequestedInformation]
+ | 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 editable profile details or submits answers for items returned in
+ `requested_information`. Once a verification is `approved` its profile details
+ are locked and can no longer be edited.
+
+ Args:
+ country: Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`.
+
+ date_of_birth: Formatted as `YYYY-MM-DD`.
- Required permissions:
+ personal_address: Personal address for the individual.
- - `payout:account:read`
+ requested_information: Answers to items returned in `requested_information`. Each entry must include
+ the requested item `id` and exactly one answer payload matching the item's
+ `type`: `value` for `text`, `date`, or `phone`; `address` for `address`; `files`
+ for `files`.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ ...
+
+ @overload
+ async def update(
+ self,
+ verification_id: str,
+ *,
+ business_address: verification_update_params.UpdateBusinessVerificationBusinessAddress | Omit = omit,
+ business_name: str | Omit = omit,
+ business_structure: str | Omit = omit,
+ country: str | Omit = omit,
+ requested_information: Iterable[verification_update_params.UpdateBusinessVerificationRequestedInformation]
+ | 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,
+ ) -> VerificationUpdateResponse:
+ """
+ Updates editable profile details or submits answers for items returned in
+ `requested_information`. Once a verification is `approved` its profile details
+ are locked and can no longer be edited.
Args:
- payout_account_id: The unique identifier of the payout account to list verifications for.
+ business_address: Business address.
- after: Returns the elements in the list that come after the specified cursor.
+ business_name: Legal business name.
- before: Returns the elements in the list that come before the specified cursor.
+ business_structure: Legal entity structure of the business, such as `private_corporation` or
+ `sole_proprietorship`. Supported values vary by country of incorporation — see
+ [Business structures](/developer/verification/business-structures).
- first: Returns the first _n_ elements from the list.
+ country: Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`.
- last: Returns the last _n_ elements from the list.
+ requested_information: Answers to items returned in `requested_information`. Each entry must include
+ the requested item `id` and exactly one answer payload matching the item's
+ `type`: `value` for `text`, `date`, or `phone`; `address` for `address`; `files`
+ for `files`.
extra_headers: Send extra headers
@@ -250,26 +830,104 @@ def list(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return self._get_api_list(
+ ...
+
+ async def update(
+ self,
+ verification_id: str,
+ *,
+ country: str | Omit = omit,
+ date_of_birth: str | Omit = omit,
+ first_name: str | Omit = omit,
+ last_name: str | Omit = omit,
+ personal_address: verification_update_params.UpdateIndividualVerificationPersonalAddress | Omit = omit,
+ requested_information: Iterable[verification_update_params.UpdateIndividualVerificationRequestedInformation]
+ | Iterable[verification_update_params.UpdateBusinessVerificationRequestedInformation]
+ | Omit = omit,
+ business_address: verification_update_params.UpdateBusinessVerificationBusinessAddress | Omit = omit,
+ business_name: str | Omit = omit,
+ business_structure: 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,
+ ) -> VerificationUpdateResponse:
+ 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(
+ {
+ "country": country,
+ "date_of_birth": date_of_birth,
+ "first_name": first_name,
+ "last_name": last_name,
+ "personal_address": personal_address,
+ "requested_information": requested_information,
+ "business_address": business_address,
+ "business_name": business_name,
+ "business_structure": business_structure,
+ },
+ 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,
+ )
+
+ 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:
+ """
+ Returns verifications for an account, including their status and any required
+ actions.
+
+ Args:
+ account_id: Account or user ID whose verifications you want to list. Use a `biz_` account
+ ID, or the caller's `user_` ID for personal verifications.
+
+ direction: Sort direction for returned verifications.
+
+ order: Field used to sort returned verifications.
+
+ 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(
"/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,
)
@@ -277,9 +935,15 @@ 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,
)
@@ -289,9 +953,15 @@ 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,
)
@@ -301,9 +971,15 @@ 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,
)
@@ -313,9 +989,15 @@ 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,
)
diff --git a/src/whop_sdk/resources/wallets.py b/src/whop_sdk/resources/wallets.py
deleted file mode 100644
index 42e8018d7..000000000
--- 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/webhooks.py b/src/whop_sdk/resources/webhooks.py
index 161f06b5b..30041448d 100644
--- a/src/whop_sdk/resources/webhooks.py
+++ b/src/whop_sdk/resources/webhooks.py
@@ -34,8 +34,6 @@
class WebhooksResource(SyncAPIResource):
- """Webhooks"""
-
@cached_property
def with_raw_response(self) -> WebhooksResourceWithRawResponse:
"""
@@ -348,8 +346,6 @@ def unwrap(self, payload: str, *, headers: Mapping[str, str], key: str | bytes |
class AsyncWebhooksResource(AsyncAPIResource):
- """Webhooks"""
-
@cached_property
def with_raw_response(self) -> AsyncWebhooksResourceWithRawResponse:
"""
diff --git a/src/whop_sdk/resources/withdrawals.py b/src/whop_sdk/resources/withdrawals.py
index 0eb7bde94..bcc58c479 100644
--- a/src/whop_sdk/resources/withdrawals.py
+++ b/src/whop_sdk/resources/withdrawals.py
@@ -29,8 +29,6 @@
class WithdrawalsResource(SyncAPIResource):
- """Withdrawals"""
-
@cached_property
def with_raw_response(self) -> WithdrawalsResourceWithRawResponse:
"""
@@ -83,7 +81,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.
@@ -231,8 +229,6 @@ def list(
class AsyncWithdrawalsResource(AsyncAPIResource):
- """Withdrawals"""
-
@cached_property
def with_raw_response(self) -> AsyncWithdrawalsResourceWithRawResponse:
"""
@@ -285,7 +281,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/resources/workforce/__init__.py b/src/whop_sdk/resources/workforce/__init__.py
new file mode 100644
index 000000000..484e9b235
--- /dev/null
+++ b/src/whop_sdk/resources/workforce/__init__.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .bounties import (
+ BountiesResource,
+ AsyncBountiesResource,
+ BountiesResourceWithRawResponse,
+ AsyncBountiesResourceWithRawResponse,
+ BountiesResourceWithStreamingResponse,
+ AsyncBountiesResourceWithStreamingResponse,
+)
+from .workforce import (
+ WorkforceResource,
+ AsyncWorkforceResource,
+ WorkforceResourceWithRawResponse,
+ AsyncWorkforceResourceWithRawResponse,
+ WorkforceResourceWithStreamingResponse,
+ AsyncWorkforceResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "BountiesResource",
+ "AsyncBountiesResource",
+ "BountiesResourceWithRawResponse",
+ "AsyncBountiesResourceWithRawResponse",
+ "BountiesResourceWithStreamingResponse",
+ "AsyncBountiesResourceWithStreamingResponse",
+ "WorkforceResource",
+ "AsyncWorkforceResource",
+ "WorkforceResourceWithRawResponse",
+ "AsyncWorkforceResourceWithRawResponse",
+ "WorkforceResourceWithStreamingResponse",
+ "AsyncWorkforceResourceWithStreamingResponse",
+]
diff --git a/src/whop_sdk/resources/workforce/bounties.py b/src/whop_sdk/resources/workforce/bounties.py
new file mode 100644
index 000000000..f4345a5bc
--- /dev/null
+++ b/src/whop_sdk/resources/workforce/bounties.py
@@ -0,0 +1,387 @@
+# 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.workforce import bounty_list_params
+from ...types.workforce.workforce_bounty import WorkforceBounty
+from ...types.workforce.workforce_bounty_list_item import WorkforceBountyListItem
+
+__all__ = ["BountiesResource", "AsyncBountiesResource"]
+
+
+class BountiesResource(SyncAPIResource):
+ """A Workforce Bounty is a paid task posted by an account or user.
+
+ The reward is held in escrow when the bounty publishes, workers submit proof of completed work, and each accepted submission is paid out until every winner slot fills.
+
+ Use the Workforce Bounties API to list an account's bounties for reporting or dashboards, list the bounties a user can work or has participated in, and retrieve a single bounty by ID.
+ """
+
+ @cached_property
+ def with_raw_response(self) -> BountiesResourceWithRawResponse:
+ """
+ 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 BountiesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> BountiesResourceWithStreamingResponse:
+ """
+ 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 BountiesResourceWithStreamingResponse(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,
+ ) -> WorkforceBounty:
+ """Retrieves one workforce bounty by ID.
+
+ The bounty must be visible to the
+ credential; bounties outside the caller's scope return 404.
+
+ 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("/workforce/bounties/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=WorkforceBounty,
+ )
+
+ def list(
+ self,
+ *,
+ 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", "gross_paid_out_amount"] | Omit = omit,
+ query: str | Omit = omit,
+ status: Literal["scheduled", "open", "closed", "completed", "canceled"] | 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[WorkforceBountyListItem]:
+ """Lists workforce bounties visible to the credential.
+
+ Account API keys return the
+ account's bounties, scheduled drafts included; user tokens return the bounties
+ the user can see and work. Pass account_id to view one account's bounties as a
+ team member (or a connected account of the caller's), or user_id (your own) to
+ list the bounties you participated in.
+
+ Args:
+ account_id: Scope the list to this account (`biz_` tag). Requires read access to the
+ account; account API keys may pass their own account or a connected account.
+
+ after: Cursor to paginate forwards from.
+
+ before: Cursor to paginate backwards from.
+
+ created_after: Only bounties created after this ISO 8601 timestamp.
+
+ created_before: Only bounties created before this ISO 8601 timestamp.
+
+ direction: Sort direction.
+
+ first: Number of bounties to return from the start of the window.
+
+ last: Number of bounties to return from the end of the window.
+
+ order: Sort field.
+
+ query: Substring match on the bounty title or ID.
+
+ status: Filter by lifecycle state.
+
+ user_id: List the bounties this user participated in (`user_` tag). Must be the
+ authenticated 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_api_list(
+ "/workforce/bounties",
+ page=SyncCursorPage[WorkforceBountyListItem],
+ 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,
+ "created_after": created_after,
+ "created_before": created_before,
+ "direction": direction,
+ "first": first,
+ "last": last,
+ "order": order,
+ "query": query,
+ "status": status,
+ "user_id": user_id,
+ },
+ bounty_list_params.BountyListParams,
+ ),
+ ),
+ model=WorkforceBountyListItem,
+ )
+
+
+class AsyncBountiesResource(AsyncAPIResource):
+ """A Workforce Bounty is a paid task posted by an account or user.
+
+ The reward is held in escrow when the bounty publishes, workers submit proof of completed work, and each accepted submission is paid out until every winner slot fills.
+
+ Use the Workforce Bounties API to list an account's bounties for reporting or dashboards, list the bounties a user can work or has participated in, and retrieve a single bounty by ID.
+ """
+
+ @cached_property
+ def with_raw_response(self) -> AsyncBountiesResourceWithRawResponse:
+ """
+ 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 AsyncBountiesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncBountiesResourceWithStreamingResponse:
+ """
+ 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 AsyncBountiesResourceWithStreamingResponse(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,
+ ) -> WorkforceBounty:
+ """Retrieves one workforce bounty by ID.
+
+ The bounty must be visible to the
+ credential; bounties outside the caller's scope return 404.
+
+ 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("/workforce/bounties/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=WorkforceBounty,
+ )
+
+ def list(
+ self,
+ *,
+ 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", "gross_paid_out_amount"] | Omit = omit,
+ query: str | Omit = omit,
+ status: Literal["scheduled", "open", "closed", "completed", "canceled"] | 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[WorkforceBountyListItem, AsyncCursorPage[WorkforceBountyListItem]]:
+ """Lists workforce bounties visible to the credential.
+
+ Account API keys return the
+ account's bounties, scheduled drafts included; user tokens return the bounties
+ the user can see and work. Pass account_id to view one account's bounties as a
+ team member (or a connected account of the caller's), or user_id (your own) to
+ list the bounties you participated in.
+
+ Args:
+ account_id: Scope the list to this account (`biz_` tag). Requires read access to the
+ account; account API keys may pass their own account or a connected account.
+
+ after: Cursor to paginate forwards from.
+
+ before: Cursor to paginate backwards from.
+
+ created_after: Only bounties created after this ISO 8601 timestamp.
+
+ created_before: Only bounties created before this ISO 8601 timestamp.
+
+ direction: Sort direction.
+
+ first: Number of bounties to return from the start of the window.
+
+ last: Number of bounties to return from the end of the window.
+
+ order: Sort field.
+
+ query: Substring match on the bounty title or ID.
+
+ status: Filter by lifecycle state.
+
+ user_id: List the bounties this user participated in (`user_` tag). Must be the
+ authenticated 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_api_list(
+ "/workforce/bounties",
+ page=AsyncCursorPage[WorkforceBountyListItem],
+ 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,
+ "created_after": created_after,
+ "created_before": created_before,
+ "direction": direction,
+ "first": first,
+ "last": last,
+ "order": order,
+ "query": query,
+ "status": status,
+ "user_id": user_id,
+ },
+ bounty_list_params.BountyListParams,
+ ),
+ ),
+ model=WorkforceBountyListItem,
+ )
+
+
+class BountiesResourceWithRawResponse:
+ def __init__(self, bounties: BountiesResource) -> None:
+ self._bounties = bounties
+
+ self.retrieve = to_raw_response_wrapper(
+ bounties.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ bounties.list,
+ )
+
+
+class AsyncBountiesResourceWithRawResponse:
+ def __init__(self, bounties: AsyncBountiesResource) -> None:
+ self._bounties = bounties
+
+ self.retrieve = async_to_raw_response_wrapper(
+ bounties.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ bounties.list,
+ )
+
+
+class BountiesResourceWithStreamingResponse:
+ def __init__(self, bounties: BountiesResource) -> None:
+ self._bounties = bounties
+
+ self.retrieve = to_streamed_response_wrapper(
+ bounties.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ bounties.list,
+ )
+
+
+class AsyncBountiesResourceWithStreamingResponse:
+ def __init__(self, bounties: AsyncBountiesResource) -> None:
+ self._bounties = bounties
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ bounties.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ bounties.list,
+ )
diff --git a/src/whop_sdk/resources/workforce/workforce.py b/src/whop_sdk/resources/workforce/workforce.py
new file mode 100644
index 000000000..485b0c71e
--- /dev/null
+++ b/src/whop_sdk/resources/workforce/workforce.py
@@ -0,0 +1,138 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .bounties import (
+ BountiesResource,
+ AsyncBountiesResource,
+ BountiesResourceWithRawResponse,
+ AsyncBountiesResourceWithRawResponse,
+ BountiesResourceWithStreamingResponse,
+ AsyncBountiesResourceWithStreamingResponse,
+)
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+
+__all__ = ["WorkforceResource", "AsyncWorkforceResource"]
+
+
+class WorkforceResource(SyncAPIResource):
+ @cached_property
+ def bounties(self) -> BountiesResource:
+ """A Workforce Bounty is a paid task posted by an account or user.
+
+ The reward is held in escrow when the bounty publishes, workers submit proof of completed work, and each accepted submission is paid out until every winner slot fills.
+
+ Use the Workforce Bounties API to list an account's bounties for reporting or dashboards, list the bounties a user can work or has participated in, and retrieve a single bounty by ID.
+ """
+ return BountiesResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> WorkforceResourceWithRawResponse:
+ """
+ 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 WorkforceResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> WorkforceResourceWithStreamingResponse:
+ """
+ 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 WorkforceResourceWithStreamingResponse(self)
+
+
+class AsyncWorkforceResource(AsyncAPIResource):
+ @cached_property
+ def bounties(self) -> AsyncBountiesResource:
+ """A Workforce Bounty is a paid task posted by an account or user.
+
+ The reward is held in escrow when the bounty publishes, workers submit proof of completed work, and each accepted submission is paid out until every winner slot fills.
+
+ Use the Workforce Bounties API to list an account's bounties for reporting or dashboards, list the bounties a user can work or has participated in, and retrieve a single bounty by ID.
+ """
+ return AsyncBountiesResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AsyncWorkforceResourceWithRawResponse:
+ """
+ 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 AsyncWorkforceResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncWorkforceResourceWithStreamingResponse:
+ """
+ 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 AsyncWorkforceResourceWithStreamingResponse(self)
+
+
+class WorkforceResourceWithRawResponse:
+ def __init__(self, workforce: WorkforceResource) -> None:
+ self._workforce = workforce
+
+ @cached_property
+ def bounties(self) -> BountiesResourceWithRawResponse:
+ """A Workforce Bounty is a paid task posted by an account or user.
+
+ The reward is held in escrow when the bounty publishes, workers submit proof of completed work, and each accepted submission is paid out until every winner slot fills.
+
+ Use the Workforce Bounties API to list an account's bounties for reporting or dashboards, list the bounties a user can work or has participated in, and retrieve a single bounty by ID.
+ """
+ return BountiesResourceWithRawResponse(self._workforce.bounties)
+
+
+class AsyncWorkforceResourceWithRawResponse:
+ def __init__(self, workforce: AsyncWorkforceResource) -> None:
+ self._workforce = workforce
+
+ @cached_property
+ def bounties(self) -> AsyncBountiesResourceWithRawResponse:
+ """A Workforce Bounty is a paid task posted by an account or user.
+
+ The reward is held in escrow when the bounty publishes, workers submit proof of completed work, and each accepted submission is paid out until every winner slot fills.
+
+ Use the Workforce Bounties API to list an account's bounties for reporting or dashboards, list the bounties a user can work or has participated in, and retrieve a single bounty by ID.
+ """
+ return AsyncBountiesResourceWithRawResponse(self._workforce.bounties)
+
+
+class WorkforceResourceWithStreamingResponse:
+ def __init__(self, workforce: WorkforceResource) -> None:
+ self._workforce = workforce
+
+ @cached_property
+ def bounties(self) -> BountiesResourceWithStreamingResponse:
+ """A Workforce Bounty is a paid task posted by an account or user.
+
+ The reward is held in escrow when the bounty publishes, workers submit proof of completed work, and each accepted submission is paid out until every winner slot fills.
+
+ Use the Workforce Bounties API to list an account's bounties for reporting or dashboards, list the bounties a user can work or has participated in, and retrieve a single bounty by ID.
+ """
+ return BountiesResourceWithStreamingResponse(self._workforce.bounties)
+
+
+class AsyncWorkforceResourceWithStreamingResponse:
+ def __init__(self, workforce: AsyncWorkforceResource) -> None:
+ self._workforce = workforce
+
+ @cached_property
+ def bounties(self) -> AsyncBountiesResourceWithStreamingResponse:
+ """A Workforce Bounty is a paid task posted by an account or user.
+
+ The reward is held in escrow when the bounty publishes, workers submit proof of completed work, and each accepted submission is paid out until every winner slot fills.
+
+ Use the Workforce Bounties API to list an account's bounties for reporting or dashboards, list the bounties a user can work or has participated in, and retrieve a single bounty by ID.
+ """
+ return AsyncBountiesResourceWithStreamingResponse(self._workforce.bounties)
diff --git a/src/whop_sdk/types/__init__.py b/src/whop_sdk/types/__init__.py
index c41c9b9b3..e3d761b18 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
@@ -84,68 +84,83 @@
from .ad_campaign import AdCampaign as AdCampaign
from .api_version import APIVersion as APIVersion
from .card_brands import CardBrands as CardBrands
+from .media_asset import MediaAsset as MediaAsset
from .lesson_types import LessonTypes as LessonTypes
from .setup_intent import SetupIntent as SetupIntent
+from .user_balance import UserBalance as UserBalance
from .checkout_font import CheckoutFont as CheckoutFont
from .granularities import Granularities as Granularities
from .refund_status import RefundStatus as RefundStatus
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 .app_logs_params import AppLogsParams as AppLogsParams
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_logs_response import AppLogsResponse as AppLogsResponse
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 .card_update_params import CardUpdateParams as CardUpdateParams
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_create_params import EventCreateParams as EventCreateParams
+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 +169,27 @@
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 .card_update_response import CardUpdateResponse as CardUpdateResponse
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_create_params import PayoutCreateParams as PayoutCreateParams
+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 +197,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,11 +214,14 @@
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 .event_create_response import EventCreateResponse as EventCreateResponse
from .invoice_create_params import InvoiceCreateParams as InvoiceCreateParams
from .invoice_update_params import InvoiceUpdateParams as InvoiceUpdateParams
from .invoice_void_response import InvoiceVoidResponse as InvoiceVoidResponse
+from .media_generate_params import MediaGenerateParams as MediaGenerateParams
from .message_create_params import MessageCreateParams as MessageCreateParams
from .message_list_response import MessageListResponse as MessageListResponse
from .message_update_params import MessageUpdateParams as MessageUpdateParams
@@ -208,12 +232,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 +249,16 @@
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 .payout_create_response import PayoutCreateResponse as PayoutCreateResponse
+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,13 +279,13 @@
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
from .dm_channel_create_params import DmChannelCreateParams as DmChannelCreateParams
from .dm_channel_list_response import DmChannelListResponse as DmChannelListResponse
from .dm_channel_update_params import DmChannelUpdateParams as DmChannelUpdateParams
@@ -274,6 +305,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 +313,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
@@ -292,13 +325,12 @@
from .course_lesson_list_params import CourseLessonListParams as CourseLessonListParams
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
from .chat_channel_list_response import ChatChannelListResponse as ChatChannelListResponse
from .chat_channel_update_params import ChatChannelUpdateParams as ChatChannelUpdateParams
-from .conversion_create_response import ConversionCreateResponse as ConversionCreateResponse
from .course_chapter_list_params import CourseChapterListParams as CourseChapterListParams
from .course_student_list_params import CourseStudentListParams as CourseStudentListParams
from .dm_channel_delete_response import DmChannelDeleteResponse as DmChannelDeleteResponse
@@ -314,9 +346,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
@@ -326,8 +364,8 @@
from .entry_created_webhook_event import EntryCreatedWebhookEvent as EntryCreatedWebhookEvent
from .entry_deleted_webhook_event import EntryDeletedWebhookEvent as EntryDeletedWebhookEvent
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 +382,10 @@
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_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,31 +397,41 @@
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_connect_params import SocialAccountConnectParams as SocialAccountConnectParams
+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 .referral_referred_users_params import ReferralReferredUsersParams as ReferralReferredUsersParams
+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
from .dispute_alert_retrieve_response import DisputeAlertRetrieveResponse as DisputeAlertRetrieveResponse
from .membership_add_free_days_params import MembershipAddFreeDaysParams as MembershipAddFreeDaysParams
from .payment_succeeded_webhook_event import PaymentSucceededWebhookEvent as PaymentSucceededWebhookEvent
-from .payout_method_retrieve_response import PayoutMethodRetrieveResponse as PayoutMethodRetrieveResponse
+from .social_account_connect_response import SocialAccountConnectResponse as SocialAccountConnectResponse
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 .referral_referred_users_response import ReferralReferredUsersResponse as ReferralReferredUsersResponse
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 .account_recommend_actions_response import AccountRecommendActionsResponse as AccountRecommendActionsResponse
+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 +448,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 +472,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 +496,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 +508,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 6a1d00635..de63b7743 100644
--- a/src/whop_sdk/types/account.py
+++ b/src/whop_sdk/types/account.py
@@ -1,61 +1,344 @@
# 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):
+ """
+ Deprecated: use the `GET /accounts/{account_id}/recommend_actions` endpoint instead. Optional actions that unlock capabilities or grow the account, same shape as `required_actions`. Computed only on `retrieve` and `me`; `null` otherwise.
+ """
+
+ action: Literal[
+ "theme_business",
+ "create_product",
+ "create_plan",
+ "verify_identity",
+ "connect_affiliate_program",
+ "create_promotion",
+ "setup_tracking_pixel",
+ "migrate_from_stripe",
+ "accept_first_payment",
+ "launch_first_ad",
+ "invite_team_member",
+ "enable_tax_collection",
+ "create_card",
+ "join_whop_university",
+ "apply_for_financing",
+ ]
+ """
+ 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`"""
+
+ impact_score: Optional[int] = None
+ """
+ Estimated revenue impact from 0-100, comparable across accounts, or `null` when
+ not ranked
+ """
+
+ reasoning: Optional[str] = None
+ """Why this action was recommended for this account, 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
+ """
+ DEPRECATED: Use the `GET /accounts/{account_id}/recommend_actions` endpoint
+ instead.
+ """
+
+ 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_create_params.py b/src/whop_sdk/types/account_create_params.py
index ea089d85d..1f36fe39f 100644
--- a/src/whop_sdk/types/account_create_params.py
+++ b/src/whop_sdk/types/account_create_params.py
@@ -17,3 +17,9 @@ class AccountCreateParams(TypedDict, total=False):
metadata: Dict[str, object]
"""Arbitrary key/value metadata to store on the account."""
+
+ title: str
+ """The display name of the account.
+
+ Defaults to `metadata.external_id` or the owner's email when omitted.
+ """
diff --git a/src/whop_sdk/types/account_list_params.py b/src/whop_sdk/types/account_list_params.py
index 3462edcac..1b9cd3b97 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 d4250efb6..000000000
--- 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_recommend_actions_response.py b/src/whop_sdk/types/account_recommend_actions_response.py
new file mode 100644
index 000000000..3ad015e10
--- /dev/null
+++ b/src/whop_sdk/types/account_recommend_actions_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 typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["AccountRecommendActionsResponse", "Data"]
+
+
+class Data(BaseModel):
+ action: Literal[
+ "theme_business",
+ "create_product",
+ "create_plan",
+ "verify_identity",
+ "connect_affiliate_program",
+ "create_promotion",
+ "setup_tracking_pixel",
+ "migrate_from_stripe",
+ "accept_first_payment",
+ "launch_first_ad",
+ "invite_team_member",
+ "enable_tax_collection",
+ "create_card",
+ "join_whop_university",
+ "apply_for_financing",
+ ]
+ """
+ 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`"""
+
+ impact_score: Optional[int] = None
+ """
+ Estimated revenue impact from 0-100, comparable across accounts, or `null` when
+ not ranked
+ """
+
+ reasoning: Optional[str] = None
+ """Why this action was recommended for this account, or `null`"""
+
+ status: Literal["optional"]
+ """Always optional — never blocking"""
+
+ title: str
+ """Headline for the recommendation"""
+
+
+class AccountRecommendActionsResponse(BaseModel):
+ data: List[Data]
diff --git a/src/whop_sdk/types/account_update_params.py b/src/whop_sdk/types/account_update_params.py
index 1efb814cc..8bd3c4f12 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,222 @@ 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.
+
+ See the available
+ [product categories](https://docs.numeral.com/essentials/product-categories).
+ """
+
+ 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 0f32e70dc..000000000
--- 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/accounts/__init__.py b/src/whop_sdk/types/accounts/__init__.py
new file mode 100644
index 000000000..dca1b4f64
--- /dev/null
+++ b/src/whop_sdk/types/accounts/__init__.py
@@ -0,0 +1,7 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .preference_update_params import PreferenceUpdateParams as PreferenceUpdateParams
+from .preference_update_response import PreferenceUpdateResponse as PreferenceUpdateResponse
+from .preference_retrieve_response import PreferenceRetrieveResponse as PreferenceRetrieveResponse
diff --git a/src/whop_sdk/types/accounts/preference_retrieve_response.py b/src/whop_sdk/types/accounts/preference_retrieve_response.py
new file mode 100644
index 000000000..f98fb38ec
--- /dev/null
+++ b/src/whop_sdk/types/accounts/preference_retrieve_response.py
@@ -0,0 +1,50 @@
+# 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__ = ["PreferenceRetrieveResponse", "AdsPaymentMethods", "AdsPaymentMethodsBackup", "AdsPaymentMethodsPrimary"]
+
+
+class AdsPaymentMethodsBackup(BaseModel):
+ id: str
+ """
+ The funding source ID: a Whop balance (`ldgr_`) for `platform_balance`, or a
+ payment method (`payt_`) for `card`.
+ """
+
+ type: Literal["platform_balance", "card"]
+ """The funding source kind: a Whop balance or a saved card."""
+
+
+class AdsPaymentMethodsPrimary(BaseModel):
+ id: str
+ """
+ The funding source ID: a Whop balance (`ldgr_`) for `platform_balance`, or a
+ payment method (`payt_`) for `card`.
+ """
+
+ type: Literal["platform_balance", "card"]
+ """The funding source kind: a Whop balance or a saved card."""
+
+
+class AdsPaymentMethods(BaseModel):
+ """How the account pays for Whop Ads spend.
+
+ `primary` is charged first; `backup` covers the charge when the primary fails. `null` until ads billing has been configured.
+ """
+
+ backup: Optional[AdsPaymentMethodsBackup] = None
+
+ primary: Optional[AdsPaymentMethodsPrimary] = None
+
+
+class PreferenceRetrieveResponse(BaseModel):
+ ads_payment_methods: Optional[AdsPaymentMethods] = None
+ """How the account pays for Whop Ads spend.
+
+ `primary` is charged first; `backup` covers the charge when the primary fails.
+ `null` until ads billing has been configured.
+ """
diff --git a/src/whop_sdk/types/accounts/preference_update_params.py b/src/whop_sdk/types/accounts/preference_update_params.py
new file mode 100644
index 000000000..241fc7390
--- /dev/null
+++ b/src/whop_sdk/types/accounts/preference_update_params.py
@@ -0,0 +1,58 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["PreferenceUpdateParams", "AdsPaymentMethods", "AdsPaymentMethodsPrimary", "AdsPaymentMethodsBackup"]
+
+
+class PreferenceUpdateParams(TypedDict, total=False):
+ ads_payment_methods: AdsPaymentMethods
+ """How the account pays for Whop Ads spend.
+
+ `primary` is charged first; `backup` covers the charge when the primary fails.
+ """
+
+
+class AdsPaymentMethodsPrimary(TypedDict, total=False):
+ type: Required[Literal["platform_balance", "card"]]
+ """The funding source kind."""
+
+ id: str
+ """
+ The funding source ID: a Whop balance (`ldgr_`) for `platform_balance`, or a
+ payment method (`payt_`) for `card`. Optional for `platform_balance` — defaults
+ to the account's default Whop balance. Required for `card`.
+ """
+
+
+class AdsPaymentMethodsBackup(TypedDict, total=False):
+ """
+ Optional when the primary is `platform_balance`; omitting it removes any configured card. Required (as `platform_balance`) when the primary is `card`.
+ """
+
+ type: Required[Literal["platform_balance", "card"]]
+ """The funding source kind."""
+
+ id: str
+ """
+ The funding source ID: a Whop balance (`ldgr_`) for `platform_balance`, or a
+ payment method (`payt_`) for `card`. Optional for `platform_balance` — defaults
+ to the account's default Whop balance. Required for `card`.
+ """
+
+
+class AdsPaymentMethods(TypedDict, total=False):
+ """How the account pays for Whop Ads spend.
+
+ `primary` is charged first; `backup` covers the charge when the primary fails.
+ """
+
+ primary: Required[AdsPaymentMethodsPrimary]
+
+ backup: AdsPaymentMethodsBackup
+ """
+ Optional when the primary is `platform_balance`; omitting it removes any
+ configured card. Required (as `platform_balance`) when the primary is `card`.
+ """
diff --git a/src/whop_sdk/types/accounts/preference_update_response.py b/src/whop_sdk/types/accounts/preference_update_response.py
new file mode 100644
index 000000000..e2974468b
--- /dev/null
+++ b/src/whop_sdk/types/accounts/preference_update_response.py
@@ -0,0 +1,50 @@
+# 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__ = ["PreferenceUpdateResponse", "AdsPaymentMethods", "AdsPaymentMethodsBackup", "AdsPaymentMethodsPrimary"]
+
+
+class AdsPaymentMethodsBackup(BaseModel):
+ id: str
+ """
+ The funding source ID: a Whop balance (`ldgr_`) for `platform_balance`, or a
+ payment method (`payt_`) for `card`.
+ """
+
+ type: Literal["platform_balance", "card"]
+ """The funding source kind: a Whop balance or a saved card."""
+
+
+class AdsPaymentMethodsPrimary(BaseModel):
+ id: str
+ """
+ The funding source ID: a Whop balance (`ldgr_`) for `platform_balance`, or a
+ payment method (`payt_`) for `card`.
+ """
+
+ type: Literal["platform_balance", "card"]
+ """The funding source kind: a Whop balance or a saved card."""
+
+
+class AdsPaymentMethods(BaseModel):
+ """How the account pays for Whop Ads spend.
+
+ `primary` is charged first; `backup` covers the charge when the primary fails. `null` until ads billing has been configured.
+ """
+
+ backup: Optional[AdsPaymentMethodsBackup] = None
+
+ primary: Optional[AdsPaymentMethodsPrimary] = None
+
+
+class PreferenceUpdateResponse(BaseModel):
+ ads_payment_methods: Optional[AdsPaymentMethods] = None
+ """How the account pays for Whop Ads spend.
+
+ `primary` is charged first; `backup` covers the charge when the primary fails.
+ `null` until ads billing has been configured.
+ """
diff --git a/src/whop_sdk/types/ad.py b/src/whop_sdk/types/ad.py
index e2a1a0bd5..6753244a4 100644
--- a/src/whop_sdk/types/ad.py
+++ b/src/whop_sdk/types/ad.py
@@ -1,52 +1,392 @@
# 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", "CreativeCrop", "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 CreativeCrop(BaseModel):
+ """The saved crop window for this creative, in source image pixels.
+
+ Null for the original asset or a format that has not been cropped.
+ """
+
+ height: float
+ """Height of the crop window in source pixels."""
+
+ width: float
+ """Width of the crop window in source pixels."""
+
+ x: float
+ """Left edge of the crop window in source pixels."""
+
+ y: float
+ """Top edge of the crop window in source pixels."""
+
+
+class Creative(BaseModel):
+ """The creative assets used by this ad.
+
+ The original asset has a null format; square, vertical, and horizontal entries are placement-specific variants.
+ """
id: str
- """The unique identifier for this ad."""
+ """The creative attachment's file id."""
+
+ crop: Optional[CreativeCrop] = None
+ """The saved crop window for this creative, in source image pixels.
+
+ Null for the original asset or a format that has not been cropped.
+ """
+
+ format: Optional[Literal["square", "vertical", "horizontal"]] = None
+ """The placement variant this asset covers, or null for the original 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
+ """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.
+ """
+
+ 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.
+ """
- created_at: datetime
- """When the ad was created."""
+ 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.
+ """
- platform: AdCampaignPlatform
- """The external ad platform this ad is running on (e.g., meta, tiktok)."""
+ created_at: str
+ """When the ad was created, as an ISO 8601 timestamp."""
- status: ExternalAdStatus
- """Current delivery status of the ad."""
+ creatives: List[Creative]
+
+ custom_conversions: float
+ """
+ Whop pixel-attributed custom (merchant-defined) conversion events, last-click,
+ across all custom event names.
+ """
+
+ custom_event_counts: object
+ """
+ Whop pixel-attributed custom conversions broken out by merchant-defined event
+ name, last-click, as a { event_name => count } map over the stats window. Empty
+ when no named custom events are attributed. Custom events fired without a name
+ are counted in custom_conversions but omitted here, so these values sum to at
+ most custom_conversions.
+ """
+
+ delivery_status: Literal[
+ "rejected",
+ "in_review",
+ "draft",
+ "campaign_paused",
+ "ad_group_paused",
+ "paused",
+ "processing",
+ "issues",
+ "learning_limited",
+ "learning",
+ "active",
+ ]
+ """The current delivery state, mirroring the Delivery column in the ads dashboard.
+
+ When several states apply at once, the highest-precedence one is returned.
+ """
+
+ 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.
+ """
+
+ lead_form_id: Optional[str] = None
+ """The Meta lead form the ad uses.
+
+ Set when the ad references an existing form via lead_form_id, or once a form
+ built from lead_form has been created on Meta at launch.
+ """
+
+ 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.
+ """
+
+ post_source: Optional[Literal["facebook", "instagram"]] = None
+ """
+ Which network post_id refers to — facebook (a page post) or instagram (a media
+ id) — or null when the ad uses uploaded creatives.
+ """
+
+ post_thumbnail_url: Optional[str] = None
+ """Preview image of the existing post this ad promotes.
+
+ Null for ads that use uploaded creatives, or until the post's media has been
+ fetched from the network.
+ """
+
+ 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.
+ """
+
+ results: Optional[float] = None
+ """The Whop pixel-attributed count behind result_event.
+
+ When a campaign's ad groups optimize different goals there is no single
+ result_event (it is null), and this is instead the sum of each ad group's own
+ attributed results. Null when nothing Whop-attributable is being optimized for.
+ """
+
+ return_on_ad_spend: float
+ """
+ Purchase value divided by spend, both in USD (a currency-neutral ratio); 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 d3eee5ddb..000000000
--- 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 6d2011572..d0c7307fd 100644
--- a/src/whop_sdk/types/ad_campaign.py
+++ b/src/whop_sdk/types/ad_campaign.py
@@ -1,108 +1,272 @@
# 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)."""
+
+ budget_type: Optional[Literal["daily", "lifetime"]] = None
+ """Whether the budget is spent per day or over the campaign's lifetime."""
- bid_strategy: Optional[Literal["lowest_cost", "bid_cap", "cost_cap"]] = None
- """The bidding strategy used to optimize spend for this campaign."""
+ click_through_rate: float
+ """Clicks divided by impressions, between 0 and 1."""
- budget_optimization: Optional[bool] = None
+ 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.
+ """
- special_categories: Optional[List[str]] = None
+ cost_per_mille: float
+ """Spend per 1,000 impressions; 0 when there are no impressions."""
+
+ 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.
+ """
+
+ custom_event_counts: object
+ """
+ Whop pixel-attributed custom conversions broken out by merchant-defined event
+ name, last-click, as a { event_name => count } map over the stats window. Empty
+ when no named custom events are attributed. Custom events fired without a name
+ are counted in custom_conversions but omitted here, so these values sum to at
+ most custom_conversions.
+ """
+
+ delivery_status: Literal[
+ "payment_failed",
+ "all_ads_rejected",
+ "draft",
+ "no_ad_groups",
+ "no_ads",
+ "paused",
+ "processing",
+ "issues",
+ "scheduled",
+ "completed",
+ "ad_groups_off",
+ "active",
+ ]
+ """The current delivery state, mirroring the Delivery column in the ads dashboard.
+
+ When several states apply at once, the highest-precedence one is returned.
+ """
+
+ frequency: Optional[float] = None
+ """Platform-reported impressions divided by reach."""
- budget_type: Optional[AdBudgetType] = None
- """The budget type for an ad campaign or ad group."""
+ impressions: float
+ """The number of impressions."""
- created_at: datetime
- """When the ad campaign was created."""
+ issues: List[Issue]
- created_by_user: CreatedByUser
- """The user who created this ad campaign."""
+ leads: float
+ """Whop pixel-attributed leads, last-click."""
- meta_config: Optional[MetaConfig] = None
- """Meta-specific campaign configuration (objective, budget mode, etc.).
+ objective: Optional[Literal["awareness", "traffic", "engagement", "leads", "sales"]] = None
+ """The goal the campaign optimizes toward."""
+
+ optimization_goal: Optional[str] = None
+ """The specific event the campaign optimizes for.
- Null for non-Meta campaigns.
+ If the campaign is CBO, then all ad groups will have the same optimization goal,
+ which will be returned here.
"""
- platform: AdCampaignPlatform
- """The external ad platform this campaign is running on (e.g., meta, tiktok)."""
+ 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.
+ """
+
+ result_event_name: Optional[str] = None
+ """
+ The merchant-defined event name when result_event is custom; null for the
+ standard events.
+ """
- status: AdCampaignStatus
- """Current status of the campaign (active, paused, or inactive)."""
+ results: Optional[float] = None
+ """The Whop pixel-attributed count behind result_event.
+
+ When a campaign's ad groups optimize different goals there is no single
+ result_event (it is null), and this is instead the sum of each ad group's own
+ attributed results. Null when nothing Whop-attributable is being optimized for.
+ """
+
+ return_on_ad_spend: float
+ """
+ Purchase value divided by spend, both in USD (a currency-neutral ratio); 0 when
+ there is no spend.
+ """
+
+ schedules: float
+ """Whop pixel-attributed schedule events, last-click."""
+
+ special_ad_categories: List[Literal["housing", "employment", "financial_products", "politics"]]
+
+ 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 000000000..1cb7db216
--- /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 000000000..359d45423
--- /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 ab696839e..c3eeb9a28 100644
--- a/src/whop_sdk/types/ad_campaign_list_params.py
+++ b/src/whop_sdk/types/ad_campaign_list_params.py
@@ -2,40 +2,78 @@
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."""
+
+ first: int
+ """The number of campaigns to return."""
+
+ last: int
+ """The number of campaigns to return from the end of the range."""
- before: Optional[str]
- """Returns the elements in the list that come before the specified cursor."""
+ order: Literal[
+ "created_at",
+ "updated_at",
+ "spend",
+ "impressions",
+ "reach",
+ "clicks",
+ "unique_clicks",
+ "frequency",
+ "click_through_rate",
+ "results",
+ "cost_per_mille",
+ "cost_per_click",
+ "cost_per_result",
+ "return_on_ad_spend",
+ ]
+ """The field to sort by.
- company_id: Optional[str]
- """The unique identifier of the company to list ad campaigns for."""
+ 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.
+ results, cost_per_result and return_on_ad_spend rank by the same Whop
+ pixel-attributed values the response reports.
+ """
- created_after: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """Only return ad campaigns created after this timestamp."""
+ query: str
+ """Filter campaigns by a title or ID substring."""
- created_before: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """Only return ad campaigns created before this timestamp."""
+ stats_from: str
+ """Start of the stats window. Defaults to all-time."""
- first: Optional[int]
- """Returns the first _n_ elements from the list."""
+ stats_to: str
+ """End of the stats window. Defaults to now."""
- last: Optional[int]
- """Returns the last _n_ elements from the list."""
+ status: Literal["draft", "active", "paused", "payment_failed"]
+ """Only return campaigns with this status."""
- query: Optional[str]
- """Case-insensitive substring match against the campaign title."""
+ time_zone: str
+ """IANA timezone (e.g.
- status: Optional[AdCampaignStatus]
- """The status of an ad campaign."""
+ America/New_York) the stats window is interpreted in. Bare stats_from/stats_to
+ dates resolve to day boundaries on this clock. Defaults to UTC.
+ """
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 7123408d9..000000000
--- 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 1e8411302..000000000
--- 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 000000000..00c87db91
--- /dev/null
+++ b/src/whop_sdk/types/ad_campaign_retrieve_params.py
@@ -0,0 +1,18 @@
+# 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."""
+
+ time_zone: str
+ """IANA timezone the stats window is interpreted in. Defaults to UTC."""
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 ddfbdf4e5..000000000
--- 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 7c476aeab..f901c3d79 100644
--- a/src/whop_sdk/types/ad_campaign_update_params.py
+++ b/src/whop_sdk/types/ad_campaign_update_params.py
@@ -2,16 +2,44 @@
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.
+ 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). Switching to minimum_cost clears the cap amounts
+ stored on the campaign's ad groups. CBO only.
+ """
+
+ budget_amount: float
+ """The campaign budget, in the account's currency.
+
+ Interpreted as daily or lifetime per the campaign's existing budget type.
+ """
+
+ budget_optimization: Literal["ad_campaign", "ad_group"]
+ """Which level owns the budget — the campaign (CBO) or each ad group (ABO).
- The interpretation (daily or lifetime) follows the campaign's existing budget
- type.
+ Only changeable before the campaign is live on Meta; switching to ad_campaign
+ requires budget_amount in the same request, and switching to ad_group clears the
+ campaign budget.
"""
+
+ 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 000000000..d20731d30
--- /dev/null
+++ b/src/whop_sdk/types/ad_create_params.py
@@ -0,0 +1,312 @@
+# 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",
+ "CreativeCrop",
+ "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 creative assets.
+
+ Each entry is an uploaded file id with an optional format; omit format for the
+ original 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). Mutually exclusive with lead_form_id.
+ """
+
+ lead_form_id: str
+ """
+ Use an existing Meta instant form instead of creating one — the form's Meta id,
+ from a form already on the ad's Facebook page. Only allowed when the ad group's
+ conversion_location is an instant-form destination. Mutually exclusive with
+ lead_form.
+ """
+
+ 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. Pair with post_source.
+ """
+
+ post_source: Literal["facebook", "instagram"]
+ """
+ Which network post_id refers to — facebook (a page post) or instagram (a media
+ id). Authoritative; when omitted the source is inferred from the id shape.
+ """
+
+ 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 CreativeCrop(TypedDict, total=False):
+ """The saved crop window for this creative, in source image pixels.
+
+ Omit it for the original asset or for a format that has not been cropped.
+ """
+
+ height: float
+
+ width: float
+
+ x: float
+
+ y: float
+
+
+class Creative(TypedDict, total=False):
+ id: str
+
+ crop: CreativeCrop
+ """The saved crop window for this creative, in source image pixels.
+
+ Omit it for the original asset or for a format that has not been cropped.
+ """
+
+ 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). Mutually exclusive with lead_form_id.
+ """
+
+ 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 000000000..7bb789722
--- /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 384dbf5fc..ed811e22f 100644
--- a/src/whop_sdk/types/ad_group.py
+++ b/src/whop_sdk/types/ad_group.py
@@ -1,49 +1,343 @@
# 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 and its descendant ads.
+
+ 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.
+ """
+
+ 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.
+ """
+
+ created_at: str
+ """When the ad group was created, ISO 8601."""
- budget: Optional[float] = None
- """Budget amount 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."""
+ custom_event_counts: object
+ """
+ Whop pixel-attributed custom conversions broken out by merchant-defined event
+ name, last-click, as a { event_name => count } map over the stats window. Empty
+ when no named custom events are attributed. Custom events fired without a name
+ are counted in custom_conversions but omitted here, so these values sum to at
+ most custom_conversions.
+ """
- created_at: datetime
- """When the ad group was created."""
+ delivery_status: Literal[
+ "all_ads_rejected",
+ "rejected",
+ "draft",
+ "no_ads",
+ "campaign_paused",
+ "paused",
+ "processing",
+ "issues",
+ "scheduled",
+ "completed",
+ "ads_off",
+ "learning_limited",
+ "learning",
+ "active",
+ ]
+ """The current delivery state, mirroring the Delivery column in the ads dashboard.
- platform: AdCampaignPlatform
- """The external ad platform this ad group is running on (e.g., meta, tiktok)."""
+ When several states apply at once, the highest-precedence one is returned.
+ """
- status: AdGroupStatus
- """Current operational status of the ad group."""
+ demographics: object
+ """Demographic targeting: automatic (Advantage+), age range, gender."""
+
+ 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.
+ """
+
+ results: Optional[float] = None
+ """The Whop pixel-attributed count behind result_event.
+
+ When a campaign's ad groups optimize different goals there is no single
+ result_event (it is null), and this is instead the sum of each ad group's own
+ attributed results. Null when nothing Whop-attributable is being optimized for.
+ """
+
+ return_on_ad_spend: float
+ """
+ Purchase value divided by spend, both in USD (a currency-neutral ratio); 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 000000000..642231a8e
--- /dev/null
+++ b/src/whop_sdk/types/ad_group_create_params.py
@@ -0,0 +1,145 @@
+# 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 }.
+
+ Omit positions to target all of a platform's.
+
+ Valid positions per platform:
+
+ - `facebook`: `feed`, `right_hand_column`, `marketplace`, `search`,
+ `profile_feed`, `notification`, `story`, `instream_video`, `facebook_reels`,
+ `facebook_reels_overlay`, `biz_disco_feed`
+ - `instagram`: `stream`, `story`, `explore`, `explore_home`, `reels`,
+ `profile_feed`, `profile_reels`, `ig_search`
+ - `messenger`: `story`
+ - `audience_network`: `classic`, `rewarded_video`
+ - `threads`: `threads_stream`
+ - `whatsapp`: `status`
+ """
+
+ 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 9bda52fb8..8f3b5be39 100644
--- a/src/whop_sdk/types/ad_group_list_params.py
+++ b/src/whop_sdk/types/ad_group_list_params.py
@@ -2,49 +2,78 @@
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",
+ "reach",
+ "clicks",
+ "unique_clicks",
+ "frequency",
+ "click_through_rate",
+ "results",
+ "cost_per_mille",
+ "cost_per_click",
+ "cost_per_result",
+ "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.
+ results, cost_per_result and return_on_ad_spend rank by the same Whop
+ pixel-attributed values the response reports.
"""
- 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)."""
+
+ time_zone: str
+ """IANA timezone (e.g.
+
+ America/New_York) the stats window is interpreted in. Bare stats_from/stats_to
+ dates resolve to day boundaries on this clock. Defaults to UTC.
+ """
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 dac018545..000000000
--- 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 000000000..7a4912ab5
--- /dev/null
+++ b/src/whop_sdk/types/ad_group_retrieve_params.py
@@ -0,0 +1,18 @@
+# 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."""
+
+ time_zone: str
+ """IANA timezone the stats window is interpreted in. Defaults to UTC."""
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 625dbfdae..000000000
--- 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 97f6403e7..44cf90823 100644
--- a/src/whop_sdk/types/ad_group_update_params.py
+++ b/src/whop_sdk/types/ad_group_update_params.py
@@ -2,1220 +2,135 @@
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.
- """
-
- attribution_spec: Optional[Iterable[PlatformConfigMetaAttributionSpec]]
- """Conversion attribution windows."""
-
- audience_network_positions: Optional[SequenceNotStr[str]]
-
- audience_type: Optional[str]
- """Audience type for retargeting."""
-
- bid_amount: Optional[int]
- """Bid amount in cents."""
-
- 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[
- Literal[
- "APP_INSTALLS",
- "CLICKS",
- "IMPRESSIONS",
- "LINK_CLICKS",
- "NONE",
- "OFFER_CLAIMS",
- "PAGE_LIKES",
- "POST_ENGAGEMENT",
- "THRUPLAY",
- "PURCHASE",
- "LISTING_INTERACTION",
- ]
- ]
- """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.
-
- 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).
- """
-
- 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.
+ Incompatible with demographics.automatic (Advantage+).
"""
- daily_budget: Optional[int]
- """Daily budget in cents."""
-
- daily_min_spend_target: Optional[str]
- """Represents textual data as UTF-8 character sequences.
+ bid_type: Literal["minimum_cost", "average_target", "maximum_target"]
+ """Bid strategy."""
- 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.
+ budget_amount: float
+ """Ad-set budget in dollars (ABO only; omit under CBO)."""
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
+ budget_type: Literal["daily", "lifetime"]
+ """Whether the budget is daily or lifetime."""
- destination_type: Optional[
+ conversion_event: Union[
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",
- ]
- ]
- """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.
- """
-
- end_time: Optional[str]
- """End time (ISO8601). Required for lifetime budgets."""
-
- excluded_geo_locations: Optional[PlatformConfigMetaExcludedGeoLocations]
- """Geo locations to exclude."""
-
- facebook_positions: Optional[SequenceNotStr[str]]
- """Facebook ad placements (feed, reels, stories, etc.)."""
-
- frequency_control_count: Optional[int]
- """Represents non-fractional signed whole numeric values.
-
- Int can represent values between -(2^31) and 2^31 - 1.
- """
-
- frequency_control_days: Optional[int]
- """Represents non-fractional signed whole numeric values.
-
- Int can represent values between -(2^31) and 2^31 - 1.
- """
-
- frequency_control_type: 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_cities: Optional[Iterable[PlatformConfigMetaGeoCity]]
-
- geo_locations: Optional[PlatformConfigMetaGeoLocations]
- """Geo targeting (countries, regions, cities, zips)."""
-
- geo_regions: Optional[Iterable[PlatformConfigMetaGeoRegion]]
-
- geo_zips: Optional[SequenceNotStr[str]]
-
- instagram_actor_id: Optional[str]
- """Instagram account ID for this ad set."""
-
- 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"]
+ "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.
- 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.
+ A standard event, or any custom pixel event name.
"""
- 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",
- ]
+ conversion_location: Literal[
+ "website",
+ "profile",
+ "messaging",
+ "on_ad",
+ "instant_forms",
+ "instant_forms_and_messenger",
+ "website_and_instant_forms",
]
- """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.
"""
-
- 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.
+ 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.
"""
- start_time: Optional[str]
- """Represents textual data as UTF-8 character sequences.
+ demographics: object
+ """Demographic targeting: { automatic, minimum_age, maximum_age, gender }."""
- This type is most often used by GraphQL to represent free-form human-readable
- text.
- """
+ desired_cost_per_result: float
+ """Target/cap cost for average_target / maximum_target."""
- status: Optional[Literal["ACTIVE", "PAUSED"]]
+ devices: object
+ """Device targeting: { platforms, operating_systems: [{ os, minimum_version }] }."""
- targeting_automation: Optional[PlatformConfigMetaTargetingAutomation]
- """Advantage+ audience expansion settings."""
+ ends_at: str
+ """Schedule end, ISO 8601."""
- threads_positions: Optional[SequenceNotStr[str]]
+ frequency_cap: object
+ """{ maximum_impressions, per_days } — only valid for reach optimization."""
- updated_time: Optional[str]
- """Represents textual data as UTF-8 character sequences.
+ languages: SequenceNotStr[str]
+ """Languages to target as ISO 639 codes (e.g.
- This type is most often used by GraphQL to represent free-form human-readable
- text.
+ en, es). Empty/omitted = all languages.
"""
- user_device: Optional[SequenceNotStr[str]]
+ message_apps: List[Literal["messenger", "instagram", "whatsapp"]]
+ """Required when conversion_location is messaging: which apps to message on.
- 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.
+ Combinations map to the matching Meta destination.
"""
- whatsapp_positions: Optional[SequenceNotStr[str]]
-
+ minimum_daily_spend: float
+ """Daily spend floor within the budget."""
-class PlatformConfigTiktokAction(TypedDict, total=False):
- """A single TikTok behavioral targeting entry.
+ optimization_goal: str
+ """What the ad group optimizes for (e.g. conversions, link_clicks, reach)."""
- 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."""
+ placements: object
+ """'automatic' (Advantage+) or a list of { platform, positions }.
- action_period: Optional[int]
- """Lookback window in days. TikTok accepts 7, 15, 30, 60, 90, or 180."""
+ Omit positions to target all of a platform's.
- action_scene: Optional[Literal["VIDEO_RELATED", "CREATOR_RELATED", "HASHTAG_RELATED", "LIVE_RELATED"]]
- """The category of TikTok content a behavioral targeting rule applies to.
+ Valid positions per platform:
- See docs/tiktok_api/ad_group.md § actions.
+ - `facebook`: `feed`, `right_hand_column`, `marketplace`, `search`,
+ `profile_feed`, `notification`, `story`, `instream_video`, `facebook_reels`,
+ `facebook_reels_overlay`, `biz_disco_feed`
+ - `instagram`: `stream`, `story`, `explore`, `explore_home`, `reels`,
+ `profile_feed`, `profile_reels`, `ig_search`
+ - `messenger`: `story`
+ - `audience_network`: `classic`, `rewarded_video`
+ - `threads`: `threads_stream`
+ - `whatsapp`: `status`
"""
- video_user_actions: Optional[
- List[Literal["WATCHED_TO_END", "LIKED", "COMMENTED", "SHARED", "FOLLOWED", "PROFILE_VISITED"]]
- ]
+ regions: object
"""
- Specific video interactions (WATCHED_TO_END, LIKED, COMMENTED, SHARED, FOLLOWED,
- PROFILE_VISITED).
+ 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."""
-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."""
-
- 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 f89c77d21..05325f997 100644
--- a/src/whop_sdk/types/ad_list_params.py
+++ b/src/whop_sdk/types/ad_list_params.py
@@ -2,74 +2,84 @@
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",
+ "reach",
+ "clicks",
+ "unique_clicks",
+ "frequency",
+ "click_through_rate",
+ "results",
+ "cost_per_mille",
+ "cost_per_click",
+ "cost_per_result",
+ "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.
+ results, cost_per_result and return_on_ad_spend rank by the same Whop
+ pixel-attributed values the response reports.
"""
- last: Optional[int]
- """Returns the last _n_ elements from the list."""
+ query: str
+ """Filter ads by a title or ID substring."""
- order_by: Optional[Literal["spend", "roas"]]
- """Columns that the listAds query can sort by."""
+ stats_from: str
+ """Start of the stats window. Defaults to all-time."""
- order_direction: Optional[Direction]
- """The direction of the sort."""
+ stats_to: str
+ """End of the stats window. Defaults to now."""
- query: Optional[str]
- """Case-insensitive substring match against the ad title or tag."""
+ status: Literal["active", "paused", "in_review", "rejected"]
+ """Only return ads with this status."""
- stats_from: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """Start of the stats date range used when order_by is a stats column."""
+ time_zone: str
+ """IANA timezone (e.g.
- stats_to: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """End of the stats date range used when order_by is a stats column."""
-
- status: Optional[ExternalAdStatus]
- """The status of an external ad."""
+ America/New_York) the stats window is interpreted in. Bare stats_from/stats_to
+ dates resolve to day boundaries on this clock. Defaults to UTC.
+ """
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 f6a13bac7..000000000
--- 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 9a7795233..2b66d9347 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 56bf2ef4d..7157cbef9 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 000000000..f276f5bcb
--- /dev/null
+++ b/src/whop_sdk/types/ad_retrieve_params.py
@@ -0,0 +1,18 @@
+# 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."""
+
+ time_zone: str
+ """IANA timezone the stats window is interpreted in. Defaults to UTC."""
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 000000000..63938f13e
--- /dev/null
+++ b/src/whop_sdk/types/ad_update_params.py
@@ -0,0 +1,302 @@
+# 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",
+ "CreativeCrop",
+ "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 creative assets.
+
+ Each entry is an uploaded file id with an optional format; omit format for the
+ original 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). Mutually exclusive with lead_form_id.
+ """
+
+ lead_form_id: str
+ """
+ Use an existing Meta instant form instead of creating one — the form's Meta id,
+ from a form already on the ad's Facebook page. Only allowed when the ad group's
+ conversion_location is an instant-form destination. Mutually exclusive with
+ lead_form. Replaces a stored lead_form.
+ """
+
+ 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. Pair with post_source.
+ """
+
+ post_source: Literal["facebook", "instagram"]
+ """
+ Which network post_id refers to — facebook (a page post) or instagram (a media
+ id). Authoritative; when omitted the source is inferred from the id shape.
+ """
+
+ 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 CreativeCrop(TypedDict, total=False):
+ """The saved crop window for this creative, in source image pixels.
+
+ Omit it for the original asset or for a format that has not been cropped.
+ """
+
+ height: float
+
+ width: float
+
+ x: float
+
+ y: float
+
+
+class Creative(TypedDict, total=False):
+ id: str
+
+ crop: CreativeCrop
+ """The saved crop window for this creative, in source image pixels.
+
+ Omit it for the original asset or for a format that has not been cropped.
+ """
+
+ 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). Mutually exclusive with lead_form_id.
+ """
+
+ 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/app_build_create_params.py b/src/whop_sdk/types/app_build_create_params.py
index 8ea1d54a6..48caa8eb0 100644
--- a/src/whop_sdk/types/app_build_create_params.py
+++ b/src/whop_sdk/types/app_build_create_params.py
@@ -17,7 +17,7 @@ class AppBuildCreateParams(TypedDict, total=False):
For iOS and Android, this should be a .zip archive containing a
main_js_bundle.hbc file and an optional assets folder. For web, this should be a
- JavaScript file.
+ JavaScript file or a .zip archive of the hosted site.
"""
checksum: Required[str]
@@ -49,7 +49,7 @@ class AppBuildCreateParams(TypedDict, total=False):
class Attachment(TypedDict, total=False):
"""The build file to upload.
- For iOS and Android, this should be a .zip archive containing a main_js_bundle.hbc file and an optional assets folder. For web, this should be a JavaScript file.
+ For iOS and Android, this should be a .zip archive containing a main_js_bundle.hbc file and an optional assets folder. For web, this should be a JavaScript file or a .zip archive of the hosted site.
"""
id: Required[str]
diff --git a/src/whop_sdk/types/app_create_params.py b/src/whop_sdk/types/app_create_params.py
index 127aba6be..f7094f844 100644
--- a/src/whop_sdk/types/app_create_params.py
+++ b/src/whop_sdk/types/app_create_params.py
@@ -37,6 +37,12 @@ class AppCreateParams(TypedDict, total=False):
authorizing the app.
"""
+ route: Optional[str]
+ """
+ The unique subdomain route where the app's hosted web builds are served, such as
+ 'myapp' for myapp.whop.app.
+ """
+
class Icon(TypedDict, total=False):
"""The icon image for the app in PNG, JPEG, or GIF format."""
diff --git a/src/whop_sdk/types/app_list_response.py b/src/whop_sdk/types/app_list_response.py
index 8a0da2ed4..8197af360 100644
--- a/src/whop_sdk/types/app_list_response.py
+++ b/src/whop_sdk/types/app_list_response.py
@@ -104,6 +104,12 @@ class AppListResponse(BaseModel):
not configured.
"""
+ hosted_url: Optional[str] = None
+ """The full canonical URL where this app's hosted web build is served.
+
+ Null if the app has not claimed a route.
+ """
+
icon: Optional[Icon] = None
"""
The icon image for this app, displayed on the app store, product pages,
@@ -130,6 +136,12 @@ class AppListResponse(BaseModel):
'https://myapp.apps.whop.com'). Null if no proxy domain is configured.
"""
+ route: Optional[str] = None
+ """
+ The unique subdomain route where this app's hosted web builds are served, such
+ as 'myapp' for myapp.whop.app. Null if the app has not claimed a route.
+ """
+
skills_path: Optional[str] = None
"""
The URL path template for a specific view of this app, appended to the base
diff --git a/src/whop_sdk/types/app_logs_params.py b/src/whop_sdk/types/app_logs_params.py
new file mode 100644
index 000000000..10822305b
--- /dev/null
+++ b/src/whop_sdk/types/app_logs_params.py
@@ -0,0 +1,40 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from datetime import datetime
+from typing_extensions import Literal, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["AppLogsParams"]
+
+
+class AppLogsParams(TypedDict, total=False):
+ after: str
+ """A cursor for fetching logs after a previous page."""
+
+ app_build_id: str
+ """Only return logs from this build."""
+
+ before: str
+ """A cursor for fetching logs before a later page."""
+
+ created_after: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]
+ """Start of the time window as an ISO 8601 timestamp.
+
+ Defaults to 7 days before created_before.
+ """
+
+ created_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]
+ """End of the time window as an ISO 8601 timestamp. Defaults to now."""
+
+ first: int
+ """The number of log lines to return (max 500)."""
+
+ level: Literal["log", "debug", "info", "warn", "error"]
+ """Only return console lines of this level."""
+
+ query: str
+ """Only return logs whose message contains this text (case-insensitive)."""
diff --git a/src/whop_sdk/types/app_logs_response.py b/src/whop_sdk/types/app_logs_response.py
new file mode 100644
index 000000000..7c7c5646a
--- /dev/null
+++ b/src/whop_sdk/types/app_logs_response.py
@@ -0,0 +1,57 @@
+# 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__ = ["AppLogsResponse", "Data", "PageInfo"]
+
+
+class Data(BaseModel):
+ app_build_id: str
+
+ app_id: str
+
+ created_at: datetime
+
+ level: str
+
+ message: str
+
+ request_id: str
+
+ source: Literal["console", "exception", "request"]
+
+ cpu_time_ms: Optional[int] = None
+
+ outcome: Optional[str] = None
+
+ request_method: Optional[str] = None
+
+ request_path: Optional[str] = None
+
+ response_status: Optional[int] = None
+
+ stack: Optional[str] = None
+
+ truncated: Optional[bool] = None
+
+ wall_time_ms: Optional[int] = None
+
+
+class PageInfo(BaseModel):
+ has_next_page: bool
+
+ has_previous_page: bool
+
+ end_cursor: Optional[str] = None
+
+ start_cursor: Optional[str] = None
+
+
+class AppLogsResponse(BaseModel):
+ data: List[Data]
+
+ page_info: PageInfo
diff --git a/src/whop_sdk/types/app_update_params.py b/src/whop_sdk/types/app_update_params.py
index 8320361c9..f2574fe15 100644
--- a/src/whop_sdk/types/app_update_params.py
+++ b/src/whop_sdk/types/app_update_params.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-from typing import List, Optional
+from typing import Dict, List, Optional
from typing_extensions import Literal, Required, TypedDict
from .._types import SequenceNotStr
@@ -66,6 +66,20 @@ class AppUpdateParams(TypedDict, total=False):
required_scopes: Optional[List[Literal["read_user"]]]
"""The permission scopes the app will request from users when they install it."""
+ route: Optional[str]
+ """
+ The unique subdomain route where the app's hosted web builds are served, such as
+ 'myapp' for myapp.whop.app.
+ """
+
+ secrets: Optional[Dict[str, object]]
+ """Secrets to add or overwrite on the app, as an object of string values (e.g.
+
+ {"MAIL_API_KEY": "..."}). Keys not included are left untouched. Pass null or an
+ empty string as the value to delete a secret. Secrets are encrypted at rest and
+ injected into the app's hosted server runtime as environment bindings.
+ """
+
skills_path: Optional[str]
"""The URL path to the skills directory of the app, such as '/assets/skills/'."""
diff --git a/src/whop_sdk/types/audience.py b/src/whop_sdk/types/audience.py
new file mode 100644
index 000000000..ed7b5c259
--- /dev/null
+++ b/src/whop_sdk/types/audience.py
@@ -0,0 +1,67 @@
+# 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", "MatchRate"]
+
+
+class MatchRate(BaseModel):
+ """Estimated match rates by ad platform.
+
+ Empty when the audience was not sent to a supported platform.
+ """
+
+ lower_bound: Optional[float] = None
+ """Lower bound of the estimated match rate percentage. `null` until available."""
+
+ platform: Literal["meta"]
+ """The ad platform that provided the match-rate estimate."""
+
+ status: Optional[Literal["calculating", "available", "unavailable"]] = None
+ """Availability of the estimated match rate."""
+
+ upper_bound: Optional[float] = None
+ """Upper bound of the estimated match rate percentage. `null` until available."""
+
+
+class Audience(BaseModel):
+ id: str
+ """Audience ID, prefixed `adaud_`."""
+
+ created_at: str
+ """When the audience was created, as an ISO 8601 timestamp."""
+
+ error_message: Optional[str] = None
+ """Processing error message. `null` unless processing is partial or failed."""
+
+ match_rates: List[MatchRate]
+
+ 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: str
+ """When the audience was last updated, as an ISO 8601 timestamp."""
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 000000000..b33e1550f
--- /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 000000000..6d8b59788
--- /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 000000000..898c54061
--- /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 b2b538a58..853bb2197 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 de0e0fdb0..edc77eb92 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 94c4f5e4f..45e80b8a1 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 cb80eaba5..08aa2311c 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 0117a1ba5..fcb7c54a2 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 d9df060a5..56ffc09da 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 bd4345a79..322a32215 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 000000000..082ca095a
--- /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 000000000..9f4db74ce
--- /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 000000000..2487fd2e5
--- /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 000000000..69ed575fc
--- /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 000000000..b325260c1
--- /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 000000000..9e1cb9e08
--- /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/card_update_params.py b/src/whop_sdk/types/card_update_params.py
new file mode 100644
index 000000000..ee3704b4a
--- /dev/null
+++ b/src/whop_sdk/types/card_update_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_extensions import Literal, Required, TypedDict
+
+__all__ = ["CardUpdateParams", "Billing"]
+
+
+class CardUpdateParams(TypedDict, total=False):
+ account_id: str
+ """The owning account ID (a biz\\__ identifier). Provide this or user_id."""
+
+ billing: Billing
+ """New billing address.
+
+ Requires line1, city, region, postal_code, and country_code.
+ """
+
+ canceled: bool
+ """Pass `true` to permanently cancel the card.
+
+ A canceled card cannot be uncanceled. Cannot be combined with other fields.
+ """
+
+ frozen: bool
+ """Pass `true` to freeze the card, `false` to unfreeze it."""
+
+ name: str
+ """A display name for the card."""
+
+ pin: str
+ """New 4-digit PIN. Can only be set on a card assigned to the acting user."""
+
+ remove_limit: bool
+ """Pass `true` to remove the spending limit (make the card unlimited)."""
+
+ 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."""
+
+
+class Billing(TypedDict, total=False):
+ """New billing address.
+
+ Requires line1, city, region, postal_code, and country_code.
+ """
+
+ city: Required[str]
+ """Billing city."""
+
+ country_code: Required[str]
+ """Billing country code, ISO 3166-1 alpha-2."""
+
+ line1: Required[str]
+ """Street address line 1."""
+
+ postal_code: Required[str]
+ """Billing postal code."""
+
+ region: Required[str]
+ """Billing region or state."""
+
+ line2: str
+ """Street address line 2."""
diff --git a/src/whop_sdk/types/card_update_response.py b/src/whop_sdk/types/card_update_response.py
new file mode 100644
index 000000000..7666ad726
--- /dev/null
+++ b/src/whop_sdk/types/card_update_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__ = ["CardUpdateResponse", "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 CardUpdateResponse(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 000000000..6f5c64931
--- /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 000000000..fe79585c7
--- /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 de81ec089..72f67e70d 100644
--- a/src/whop_sdk/types/checkout_configuration_create_params.py
+++ b/src/whop_sdk/types/checkout_configuration_create_params.py
@@ -2,539 +2,149 @@
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."""
+from typing import Optional
+from typing_extensions import Literal, TypedDict
- id: Optional[str]
- """The ID of the custom field (if being updated)"""
+from .._types import SequenceNotStr
- order: Optional[int]
- """The order of the field."""
+__all__ = ["CheckoutConfigurationCreateParams", "PaymentMethodConfiguration", "Plan", "PlanPaymentMethodConfiguration"]
- placeholder: Optional[str]
- """The placeholder value of the field."""
- required: Optional[bool]
- """Whether or not the field is required."""
-
-
-class CreateCheckoutSessionInputModePaymentWithPlanPlanImage(TypedDict, total=False):
- """An image for the plan. This will be visible on the product page to customers."""
+class CheckoutConfigurationCreateParams(TypedDict, total=False):
+ affiliate_code: Optional[str]
+ """Affiliate code to apply to the checkout."""
- id: Required[str]
- """The ID of an existing file object."""
+ company_id: str
+ """Account ID, prefixed `biz_`."""
+ currency: Optional[str]
+ """Currency used for setup-mode payment method availability."""
-class CreateCheckoutSessionInputModePaymentWithPlanPlanPaymentMethodConfiguration(TypedDict, total=False):
- """The explicit payment method configuration for the plan.
+ metadata: Optional[object]
+ """Custom key-value metadata copied to payments and memberships."""
- If not provided, the platform or company's defaults will apply.
+ mode: Literal["payment", "setup"]
"""
-
- disabled: Required[List[PaymentMethodTypes]]
- """An array of payment method identifiers that are explicitly disabled.
-
- Only applies if the include_platform_defaults is true.
+ Checkout mode: `payment` collects payment for a plan now; `setup` saves payment
+ details without charging. Defaults to `payment`.
"""
- enabled: Required[List[PaymentMethodTypes]]
- """An array of payment method identifiers that are explicitly enabled.
+ payment_method_configuration: Optional[PaymentMethodConfiguration]
+ """Payment method overrides for this checkout.
- 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.
+ `null` uses the plan or platform defaults.
"""
- 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.
+ plan: Optional[Plan]
+ """Plan attributes used to create or find a plan for this checkout configuration.
- We will use the product external identifier to find or create an existing product.
+ Mutually exclusive with `plan_id`.
"""
- external_identifier: Required[str]
- """A unique ID used to find or create a product.
+ plan_id: Optional[str]
+ """Existing plan ID, prefixed `plan_`. Mutually exclusive with `plan`."""
- 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.
- """
+ redirect_url: Optional[str]
+ """URL customers are sent to after checkout."""
- title: Required[str]
- """The title of the product."""
+ three_ds_level: Optional[str]
+ """3D Secure behavior for this checkout."""
- collect_shipping_address: Optional[bool]
- """Whether or not to collect shipping information at checkout from the customer."""
- custom_statement_descriptor: Optional[str]
- """The custom statement descriptor for the product i.e.
+class PaymentMethodConfiguration(TypedDict, total=False):
+ """Payment method overrides for this checkout.
- WHOP\\**SPORTS, must be between 5 and 22 characters, contain at least one letter,
- and not contain any of the following characters: <, >, \\,, ', "
+ `null` uses the plan or platform defaults.
"""
- 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."""
-
- global_affiliate_status: Optional[GlobalAffiliateStatus]
- """The different statuses of the global affiliate program for a product."""
-
- headline: Optional[str]
- """The headline of the product."""
-
- product_tax_code_id: Optional[str]
- """The ID of the product tax code to apply to this product."""
+ disabled: SequenceNotStr[str]
+ """Payment methods explicitly disabled for checkout."""
- redirect_purchase_url: Optional[str]
- """The URL to redirect the customer to after a purchase."""
+ enabled: SequenceNotStr[str]
+ """Payment methods explicitly enabled for checkout."""
- route: Optional[str]
- """The route of the product."""
+ include_platform_defaults: bool
+ """Whether platform default payment methods are included."""
- visibility: Optional[Visibility]
- """Visibility of a resource"""
+class PlanPaymentMethodConfiguration(TypedDict, total=False):
+ """Payment method overrides for the inline plan. `null` uses platform defaults."""
-class CreateCheckoutSessionInputModePaymentWithPlanPlan(TypedDict, total=False):
- """
- The plan attributes to create a new plan inline for this checkout configuration.
- """
+ disabled: SequenceNotStr[str]
+ """Payment methods explicitly disabled for this plan."""
- company_id: Required[str]
- """The company the plan should be created for."""
+ enabled: SequenceNotStr[str]
+ """Payment methods explicitly enabled for this plan."""
- currency: Required[Currency]
- """The respective currency identifier for the plan."""
+ include_platform_defaults: bool
+ """Whether platform default payment methods are included."""
- 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 used to create or find a plan 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).
+ """Recurring billing interval in days, such as 30 for monthly or 365 for annual."""
+
+ company_id: Optional[str]
+ """Account ID for the inline plan, prefixed `biz_`.
- For example, 30 for monthly billing.
+ Defaults to the account resolved from the request.
"""
- custom_fields: Optional[Iterable[CreateCheckoutSessionInputModePaymentWithPlanPlanCustomField]]
- """An array of custom field objects."""
+ currency: Optional[str]
+ """Three-letter ISO currency code for the plan's prices."""
description: Optional[str]
- """The description of the plan."""
+ """Customer-visible plan description."""
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.
- """
+ """Access duration in days for expiration-based plans."""
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."""
+ """Whether to create a new plan instead of reusing a matching one."""
initial_price: Optional[float]
- """An additional amount charged upon first purchase.
+ """Initial purchase price in the plan currency."""
- Provided as a number in dollars (e.g., 10.00 for $10.00).
- """
+ metadata: Optional[object]
+ """Custom key-value metadata stored on the plan."""
- internal_notes: Optional[str]
- """A personal description or notes section for the business."""
+ override_tax_type: Optional[str]
+ """Tax classification override 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 overrides for the inline plan. `null` uses platform defaults."""
- 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[str]
"""
-
- 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.
+ Billing model for the plan: `renewal` (recurring) or `one_time` (single
+ payment).
"""
product_id: Optional[str]
- """The product the plan is related to. Either this or product is required."""
+ """Product ID the inline plan should belong to, prefixed `prod_`."""
- release_method: Optional[ReleaseMethod]
- """The methods of how a plan can be released."""
+ release_method: Optional[str]
+ """Sales method for the plan, such as `buy_now` or `waitlist`."""
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."""
+ """Recurring price charged each billing period."""
stock: Optional[int]
- """The number of units available for purchase.
-
- If not provided, stock is unlimited.
- """
+ """Units available for purchase."""
title: Optional[str]
- """The title of the plan. This will be visible on the product page to customers."""
+ """Plan display name 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.
- """
+ """Free trial days before the first renewal 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 from public view."""
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 000000000..b818ea72f
--- /dev/null
+++ b/src/whop_sdk/types/checkout_configuration_create_response.py
@@ -0,0 +1,126 @@
+# 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__ = ["CheckoutConfigurationCreateResponse", "PaymentMethodConfiguration", "Plan"]
+
+
+class PaymentMethodConfiguration(BaseModel):
+ """Payment method overrides for this checkout.
+
+ `null` when it uses the plan or platform defaults.
+ """
+
+ disabled: Optional[List[str]] = None
+ """Payment methods explicitly disabled for checkout."""
+
+ enabled: Optional[List[str]] = None
+ """Payment methods explicitly enabled for checkout."""
+
+ include_platform_defaults: Optional[bool] = None
+ """Whether platform default payment methods are included."""
+
+
+class Plan(BaseModel):
+ """Plan used for payment checkout. `null` in setup mode."""
+
+ id: str
+ """Plan ID, prefixed `plan_`."""
+
+ adaptive_pricing_enabled: bool
+ """Whether this plan accepts local currency payments via adaptive pricing."""
+
+ billing_period: Optional[int] = None
+ """Recurring billing interval in days, such as 30 for monthly or 365 for annual.
+
+ `null` for one-time plans.
+ """
+
+ currency: str
+ """Three-letter ISO currency code for the plan's prices."""
+
+ expiration_days: Optional[int] = None
+ """Access duration in days for expiration-based plans."""
+
+ initial_price: float
+ """Initial purchase price in the plan currency."""
+
+ plan_type: str
+ """
+ Billing model for the plan: `renewal` (recurring) or `one_time` (single
+ payment).
+ """
+
+ release_method: str
+ """Sales method for the plan, such as `buy_now` or `waitlist`."""
+
+ renewal_price: float
+ """Recurring price charged each billing period."""
+
+ three_ds_level: Optional[str] = None
+ """3D Secure behavior for this plan, or `null` to use the account default."""
+
+ trial_period_days: Optional[int] = None
+ """Free trial days before the first renewal charge."""
+
+ visibility: str
+ """Whether the plan is visible to customers or hidden from public view."""
+
+
+class CheckoutConfigurationCreateResponse(BaseModel):
+ id: str
+ """Checkout configuration ID, prefixed `ch_`."""
+
+ company_id: str
+ """Account ID, prefixed `biz_`."""
+
+ created_at: str
+ """When the checkout configuration was created, as an ISO 8601 timestamp."""
+
+ mode: Literal["payment", "setup"]
+ """
+ Checkout mode: `payment` collects payment now; `setup` saves payment details for
+ later.
+ """
+
+ updated_at: str
+ """When the checkout configuration was last updated, as an ISO 8601 timestamp."""
+
+ affiliate_code: Optional[str] = None
+ """Affiliate code applied at checkout, or `null` when none is set."""
+
+ currency: Optional[str] = None
+ """
+ Currency used for setup-mode payment method availability; defaults to `usd` when
+ omitted.
+ """
+
+ metadata: Optional[object] = None
+ """Custom key-value metadata copied to payments and memberships.
+
+ `null` without the `checkout_configuration:basic:read` scope.
+ """
+
+ payment_method_configuration: Optional[PaymentMethodConfiguration] = None
+ """Payment method overrides for this checkout.
+
+ `null` when it uses the plan or platform defaults.
+ """
+
+ plan: Optional[Plan] = None
+ """Plan used for payment checkout. `null` in setup mode."""
+
+ purchase_url: Optional[str] = None
+ """Checkout URL you can send to customers."""
+
+ redirect_url: Optional[str] = None
+ """
+ URL customers are sent to after checkout, or `null` when no redirect is
+ configured.
+ """
+
+ three_ds_level: Optional[str] = None
+ """3D Secure behavior for this checkout, or `null` to use the account default."""
diff --git a/src/whop_sdk/types/checkout_configuration_list_params.py b/src/whop_sdk/types/checkout_configuration_list_params.py
index b2770334f..73f45fb93 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."""
+ """Account ID, prefixed `biz_`."""
- before: Optional[str]
- """Returns the elements in the list that come before the specified cursor."""
+ after: str
+ """Cursor for the next page of results."""
- created_after: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """Only return checkout configurations created after this timestamp."""
+ created_after: int
+ """Only return checkout 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
+ """Only return checkout configurations created before this Unix timestamp."""
- direction: Optional[Direction]
- """The direction of the sort."""
+ direction: Literal["asc", "desc"]
+ """Sort direction. Defaults to `desc`."""
- first: Optional[int]
- """Returns the first _n_ elements from the list."""
+ first: int
+ """Number of checkout configurations to return."""
- last: Optional[int]
- """Returns the last _n_ elements from the list."""
+ order: Literal["created_at"]
+ """Field used to sort checkout configurations."""
- plan_id: Optional[str]
- """
- Filter checkout configurations to only those associated with this plan
- identifier.
- """
+ plan_id: str
+ """Only return checkout configurations for this plan ID, prefixed `plan_`."""
diff --git a/src/whop_sdk/types/checkout_configuration_list_response.py b/src/whop_sdk/types/checkout_configuration_list_response.py
index be80192b7..c9485c2d8 100644
--- a/src/whop_sdk/types/checkout_configuration_list_response.py
+++ b/src/whop_sdk/types/checkout_configuration_list_response.py
@@ -1,163 +1,126 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Dict, List, Optional
+from typing import List, 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.
+ """Payment method overrides for this checkout.
- This currently only works in 'setup' mode. Use the plan's payment_method_configuration for payment method.
+ `null` when it uses the plan or platform defaults.
"""
- disabled: List[PaymentMethodTypes]
- """An array of payment method identifiers that are explicitly disabled.
+ disabled: Optional[List[str]] = None
+ """Payment methods explicitly disabled for checkout."""
- Only applies if the include_platform_defaults is true.
- """
-
- enabled: List[PaymentMethodTypes]
- """An array of payment method identifiers that are explicitly enabled.
+ enabled: Optional[List[str]] = None
+ """Payment methods explicitly enabled for checkout."""
- 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.
- """
+ include_platform_defaults: Optional[bool] = None
+ """Whether platform default payment methods are included."""
class Plan(BaseModel):
- """The plan to use for the checkout configuration"""
+ """Plan used for payment checkout. `null` in setup mode."""
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.
-
- Raw setting — does not check processor compatibility or feature flags.
- """
+ """Whether this plan accepts local currency payments via adaptive pricing."""
billing_period: Optional[int] = None
- """The number of days between each recurring charge.
+ """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.
"""
- 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 the plan's prices."""
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."""
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 the plan currency."""
- plan_type: PlanType
+ plan_type: str
"""
- The billing model for this plan: 'renewal' for recurring subscriptions or
- 'one_time' for single payments.
+ Billing model for the plan: `renewal` (recurring) or `one_time` (single
+ payment).
"""
- 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 the 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 each billing period."""
- 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, or `null` to use the account default."""
trial_period_days: Optional[int] = None
- """The number of free trial days before the first charge on a renewal plan.
+ """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.
- """
+ visibility: str
+ """Whether the plan is visible to customers or hidden from public view."""
- visibility: Visibility
- """Controls whether the plan is visible to customers.
- When set to 'hidden', the plan is only accessible via direct link.
- """
+class CheckoutConfigurationListResponse(BaseModel):
+ id: str
+ """Checkout configuration ID, prefixed `ch_`."""
+ company_id: str
+ """Account ID, prefixed `biz_`."""
-class CheckoutConfigurationListResponse(BaseModel):
+ created_at: str
+ """When the checkout configuration was created, as an ISO 8601 timestamp."""
+
+ mode: Literal["payment", "setup"]
"""
- 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.
+ Checkout mode: `payment` collects payment now; `setup` saves payment details for
+ later.
"""
- id: str
- """The unique identifier for the checkout session."""
+ updated_at: str
+ """When the checkout configuration was last updated, as an ISO 8601 timestamp."""
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.
+ """Affiliate code applied at checkout, or `null` when none is set."""
- When false, the promo code input is hidden and promo codes are rejected.
+ currency: Optional[str] = None
+ """
+ Currency used for setup-mode payment method availability; defaults to `usd` when
+ omitted.
"""
- company_id: str
- """The ID of the company to use for the checkout configuration"""
-
- currency: Optional[Currency] = None
- """The available currencies on the platform"""
-
- metadata: Optional[Dict[str, object]] = None
- """The metadata to use for the checkout configuration"""
+ metadata: Optional[object] = None
+ """Custom key-value metadata copied to payments and memberships.
- mode: CheckoutModes
- """The mode of the checkout session."""
+ `null` without the `checkout_configuration:basic:read` scope.
+ """
payment_method_configuration: Optional[PaymentMethodConfiguration] = None
- """The explicit payment method configuration for the session, if any.
+ """Payment method overrides for this checkout.
- This currently only works in 'setup' mode. Use the plan's
- payment_method_configuration for payment method.
+ `null` when it uses the plan or platform defaults.
"""
plan: Optional[Plan] = None
- """The plan to use for the checkout configuration"""
+ """Plan used for payment checkout. `null` in setup mode."""
- purchase_url: str
- """A URL you can send to customers to complete a checkout.
+ purchase_url: Optional[str] = None
+ """Checkout URL you can send to customers."""
- It looks like `/checkout/plan_xxxx?session={id}`
+ redirect_url: Optional[str] = None
+ """
+ URL customers are sent to after checkout, or `null` when no redirect is
+ configured.
"""
- redirect_url: Optional[str] = None
- """The URL to redirect the user to after the checkout configuration is created"""
+ three_ds_level: Optional[str] = None
+ """3D Secure behavior for this checkout, or `null` to use the account default."""
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 000000000..351ef5b3b
--- /dev/null
+++ b/src/whop_sdk/types/checkout_configuration_retrieve_response.py
@@ -0,0 +1,126 @@
+# 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__ = ["CheckoutConfigurationRetrieveResponse", "PaymentMethodConfiguration", "Plan"]
+
+
+class PaymentMethodConfiguration(BaseModel):
+ """Payment method overrides for this checkout.
+
+ `null` when it uses the plan or platform defaults.
+ """
+
+ disabled: Optional[List[str]] = None
+ """Payment methods explicitly disabled for checkout."""
+
+ enabled: Optional[List[str]] = None
+ """Payment methods explicitly enabled for checkout."""
+
+ include_platform_defaults: Optional[bool] = None
+ """Whether platform default payment methods are included."""
+
+
+class Plan(BaseModel):
+ """Plan used for payment checkout. `null` in setup mode."""
+
+ id: str
+ """Plan ID, prefixed `plan_`."""
+
+ adaptive_pricing_enabled: bool
+ """Whether this plan accepts local currency payments via adaptive pricing."""
+
+ billing_period: Optional[int] = None
+ """Recurring billing interval in days, such as 30 for monthly or 365 for annual.
+
+ `null` for one-time plans.
+ """
+
+ currency: str
+ """Three-letter ISO currency code for the plan's prices."""
+
+ expiration_days: Optional[int] = None
+ """Access duration in days for expiration-based plans."""
+
+ initial_price: float
+ """Initial purchase price in the plan currency."""
+
+ plan_type: str
+ """
+ Billing model for the plan: `renewal` (recurring) or `one_time` (single
+ payment).
+ """
+
+ release_method: str
+ """Sales method for the plan, such as `buy_now` or `waitlist`."""
+
+ renewal_price: float
+ """Recurring price charged each billing period."""
+
+ three_ds_level: Optional[str] = None
+ """3D Secure behavior for this plan, or `null` to use the account default."""
+
+ trial_period_days: Optional[int] = None
+ """Free trial days before the first renewal charge."""
+
+ visibility: str
+ """Whether the plan is visible to customers or hidden from public view."""
+
+
+class CheckoutConfigurationRetrieveResponse(BaseModel):
+ id: str
+ """Checkout configuration ID, prefixed `ch_`."""
+
+ company_id: str
+ """Account ID, prefixed `biz_`."""
+
+ created_at: str
+ """When the checkout configuration was created, as an ISO 8601 timestamp."""
+
+ mode: Literal["payment", "setup"]
+ """
+ Checkout mode: `payment` collects payment now; `setup` saves payment details for
+ later.
+ """
+
+ updated_at: str
+ """When the checkout configuration was last updated, as an ISO 8601 timestamp."""
+
+ affiliate_code: Optional[str] = None
+ """Affiliate code applied at checkout, or `null` when none is set."""
+
+ currency: Optional[str] = None
+ """
+ Currency used for setup-mode payment method availability; defaults to `usd` when
+ omitted.
+ """
+
+ metadata: Optional[object] = None
+ """Custom key-value metadata copied to payments and memberships.
+
+ `null` without the `checkout_configuration:basic:read` scope.
+ """
+
+ payment_method_configuration: Optional[PaymentMethodConfiguration] = None
+ """Payment method overrides for this checkout.
+
+ `null` when it uses the plan or platform defaults.
+ """
+
+ plan: Optional[Plan] = None
+ """Plan used for payment checkout. `null` in setup mode."""
+
+ purchase_url: Optional[str] = None
+ """Checkout URL you can send to customers."""
+
+ redirect_url: Optional[str] = None
+ """
+ URL customers are sent to after checkout, or `null` when no redirect is
+ configured.
+ """
+
+ three_ds_level: Optional[str] = None
+ """3D Secure behavior for this checkout, or `null` to use the account default."""
diff --git a/src/whop_sdk/types/company_list_response.py b/src/whop_sdk/types/company_list_response.py
index 52d0916e5..351ebd626 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
deleted file mode 100644
index e833dba07..000000000
--- a/src/whop_sdk/types/conversion_create_params.py
+++ /dev/null
@@ -1,183 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Union, Optional
-from datetime import datetime
-from typing_extensions import Literal, Required, Annotated, TypedDict
-
-from .._utils import PropertyInfo
-from .shared.currency import Currency
-
-__all__ = ["ConversionCreateParams", "Context", "User"]
-
-
-class ConversionCreateParams(TypedDict, total=False):
- company_id: Required[str]
- """The company to associate with this event."""
-
- event_name: Required[
- Literal["lead", "submit_application", "contact", "complete_registration", "schedule", "custom"]
- ]
- """The type of event."""
-
- action_source: Optional[
- Literal[
- "email",
- "website",
- "app",
- "phone_call",
- "chat",
- "physical_store",
- "system_generated",
- "business_messaging",
- "other",
- ]
- ]
- """The channel where an event originated"""
-
- context: Optional[Context]
- """Tracking and attribution context."""
-
- currency: Optional[Currency]
- """The available currencies on the platform"""
-
- custom_name: Optional[str]
- """Custom event name when event_name is 'custom'."""
-
- event_id: Optional[str]
- """Client-provided identifier for deduplication. Generated if omitted."""
-
- event_time: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
- """When the event occurred. Defaults to now."""
-
- plan_id: Optional[str]
- """The plan associated with the event."""
-
- product_id: Optional[str]
- """The product associated with the event."""
-
- referrer_url: Optional[str]
- """The referring URL."""
-
- url: Optional[str]
- """The URL where the event occurred."""
-
- user: Optional[User]
- """User identity and profile data."""
-
- value: Optional[float]
- """Monetary value associated with the event."""
-
-
-class Context(TypedDict, total=False):
- """Tracking and attribution context."""
-
- ad_campaign_id: Optional[str]
- """Ad campaign ID."""
-
- ad_id: Optional[str]
- """Ad ID."""
-
- ad_set_id: Optional[str]
- """Ad set ID."""
-
- fbclid: Optional[str]
- """Facebook click ID."""
-
- fbp: Optional[str]
- """Facebook browser pixel ID."""
-
- ga: Optional[str]
- """Google Analytics client ID."""
-
- gclid: Optional[str]
- """Google click ID."""
-
- ig_sid: Optional[str]
- """Instagram session ID."""
-
- ip_address: Optional[str]
- """IP address."""
-
- ttclid: Optional[str]
- """TikTok click ID."""
-
- ttp: Optional[str]
- """TikTok pixel ID."""
-
- user_agent: Optional[str]
- """Browser user agent string."""
-
- utm_campaign: Optional[str]
- """UTM campaign parameter."""
-
- utm_content: Optional[str]
- """UTM content parameter."""
-
- utm_id: Optional[str]
- """UTM ID parameter."""
-
- utm_medium: Optional[str]
- """UTM medium parameter."""
-
- utm_source: Optional[str]
- """UTM source parameter."""
-
- utm_term: Optional[str]
- """UTM term parameter."""
-
-
-class User(TypedDict, total=False):
- """User identity and profile data."""
-
- anonymous_id: Optional[str]
- """An anonymous identifier for the user."""
-
- birthdate: Optional[str]
- """Date of birth (YYYY-MM-DD)."""
-
- city: Optional[str]
- """City."""
-
- country: Optional[str]
- """Country."""
-
- email: Optional[str]
- """Email address."""
-
- external_id: Optional[str]
- """An external identifier for the user."""
-
- first_name: Optional[str]
- """First name."""
-
- gender: Optional[Literal["male", "female"]]
- """Gender"""
-
- last_name: Optional[str]
- """Last name."""
-
- member_id: Optional[str]
- """The Whop member ID."""
-
- membership_id: Optional[str]
- """The Whop membership ID."""
-
- name: Optional[str]
- """Full display name."""
-
- phone: Optional[str]
- """Phone number."""
-
- postal_code: Optional[str]
- """Postal code."""
-
- state: Optional[str]
- """State or region."""
-
- user_id: Optional[str]
- """The Whop user ID."""
-
- username: Optional[str]
- """Username."""
diff --git a/src/whop_sdk/types/conversion_create_response.py b/src/whop_sdk/types/conversion_create_response.py
deleted file mode 100644
index eeef3e895..000000000
--- a/src/whop_sdk/types/conversion_create_response.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from .._models import BaseModel
-
-__all__ = ["ConversionCreateResponse"]
-
-
-class ConversionCreateResponse(BaseModel):
- """A tracked conversion event"""
-
- id: str
- """The unique identifier for the conversion"""
diff --git a/src/whop_sdk/types/course.py b/src/whop_sdk/types/course.py
index 514fd9852..38ea821df 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 29c44d563..7178c72b6 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 6f6da8193..2487a3a85 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 f0221451b..7e2d351c9 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 000000000..4b74a28d8
--- /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 000000000..a6a3cf907
--- /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 b093b0c26..c34af93fb 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_create_params.py b/src/whop_sdk/types/event_create_params.py
new file mode 100644
index 000000000..b1d091825
--- /dev/null
+++ b/src/whop_sdk/types/event_create_params.py
@@ -0,0 +1,348 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["EventCreateParams", "Context", "User"]
+
+
+class EventCreateParams(TypedDict, total=False):
+ account_id: Required[str]
+ """The account to associate with this event."""
+
+ event_name: Required[
+ Literal[
+ "lead",
+ "submit_application",
+ "contact",
+ "complete_registration",
+ "schedule",
+ "view_content",
+ "add_to_cart",
+ "custom",
+ "page",
+ ]
+ ]
+ """The type of conversion or engagement event"""
+
+ action_source: Optional[
+ Literal[
+ "email",
+ "website",
+ "app",
+ "phone_call",
+ "chat",
+ "physical_store",
+ "system_generated",
+ "business_messaging",
+ "other",
+ ]
+ ]
+ """The channel where an event originated"""
+
+ context: Optional[Context]
+ """Tracking and attribution context."""
+
+ currency: Optional[
+ 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",
+ ]
+ ]
+ """The available currencies on the platform"""
+
+ custom_name: Optional[str]
+ """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."""
+
+ event_time: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
+ """When the event occurred. Defaults to now."""
+
+ plan_id: Optional[str]
+ """The plan associated with the event."""
+
+ product_id: Optional[str]
+ """The product associated with the event."""
+
+ 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."""
+
+ user: Optional[User]
+ """User identity and profile data."""
+
+ value: Optional[float]
+ """Monetary value associated with the event."""
+
+
+class Context(TypedDict, total=False):
+ """Tracking and attribution context."""
+
+ ad_campaign_id: Optional[str]
+ """Ad campaign ID."""
+
+ ad_id: Optional[str]
+ """Ad ID."""
+
+ 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."""
+
+ ig_sid: Optional[str]
+ """Instagram session ID."""
+
+ 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."""
+
+ utm_campaign: Optional[str]
+ """UTM campaign parameter."""
+
+ utm_content: Optional[str]
+ """UTM content parameter."""
+
+ utm_id: Optional[str]
+ """UTM ID parameter."""
+
+ utm_medium: Optional[str]
+ """UTM medium parameter."""
+
+ utm_source: Optional[str]
+ """UTM source parameter."""
+
+ 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."""
+
+ anonymous_id: Optional[str]
+ """An anonymous identifier for the user."""
+
+ birthdate: Optional[str]
+ """Date of birth (YYYY-MM-DD)."""
+
+ city: Optional[str]
+ """City."""
+
+ country: Optional[str]
+ """Country."""
+
+ email: Optional[str]
+ """Email address."""
+
+ external_id: Optional[str]
+ """An external identifier for the user."""
+
+ first_name: Optional[str]
+ """First name."""
+
+ gender: Optional[Literal["male", "female"]]
+ """Gender"""
+
+ 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."""
+
+ membership_id: Optional[str]
+ """The Whop membership ID."""
+
+ name: Optional[str]
+ """Full display name."""
+
+ phone: Optional[str]
+ """Phone number."""
+
+ postal_code: Optional[str]
+ """Postal code."""
+
+ state: Optional[str]
+ """State or region."""
+
+ user_id: Optional[str]
+ """The Whop user ID."""
+
+ username: Optional[str]
+ """Username."""
diff --git a/src/whop_sdk/types/event_create_response.py b/src/whop_sdk/types/event_create_response.py
new file mode 100644
index 000000000..cfabb2086
--- /dev/null
+++ b/src/whop_sdk/types/event_create_response.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .._models import BaseModel
+
+__all__ = ["EventCreateResponse"]
+
+
+class EventCreateResponse(BaseModel):
+ id: str
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 000000000..f2c872e62
--- /dev/null
+++ b/src/whop_sdk/types/event_list_params.py
@@ -0,0 +1,36 @@
+# 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.
+ """
+
+ after: str
+ """A cursor for fetching events after a previous page."""
+
+ before: str
+ """A cursor for fetching events before a later page."""
+
+ 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 000000000..72d6c5a58
--- /dev/null
+++ b/src/whop_sdk/types/event_list_response.py
@@ -0,0 +1,87 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from .._models import BaseModel
+
+__all__ = ["EventListResponse", "Context", "Question", "User"]
+
+
+class Context(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 Question(BaseModel):
+ id: Optional[str] = None
+
+ answer: Optional[str] = None
+
+ key: Optional[str] = None
+
+ options: Optional[List[str]] = None
+
+ question: Optional[str] = None
+
+ type: Optional[str] = None
+
+
+class User(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 EventListResponse(BaseModel):
+ id: str
+
+ event_id: str
+
+ event_name: str
+
+ event_time: int
+
+ context: Optional[Context] = None
+
+ currency: Optional[str] = None
+
+ custom_name: Optional[str] = None
+
+ path: Optional[str] = None
+
+ questions: Optional[List[Question]] = None
+
+ referrer_url: Optional[str] = None
+
+ total_usd_amount: Optional[float] = None
+
+ url: Optional[str] = None
+
+ user: Optional[User] = None
+
+ value: Optional[float] = None
diff --git a/src/whop_sdk/types/experience_list_response.py b/src/whop_sdk/types/experience_list_response.py
index 3380a7520..9b0cf573c 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 1fa978847..000000000
--- 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 000000000..a0d8961f4
--- /dev/null
+++ b/src/whop_sdk/types/financial_activity_list_params.py
@@ -0,0 +1,64 @@
+# 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."""
+
+ include_owned_accounts: bool
+ """
+ When true, aggregates the authenticated user's personal ledger with the
+ businesses they own (owner role with balance read) into one feed. Requires
+ user_id to be the authenticated user; cannot be combined with account_id or the
+ settlement-date filters. Each returned row includes the owning `account`.
+ """
+
+ 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 000000000..5cf991190
--- /dev/null
+++ b/src/whop_sdk/types/financial_activity_list_response.py
@@ -0,0 +1,475 @@
+# 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",
+ "DataResourceUnionMember3",
+ "DataResourceUnionMember3Owner",
+ "DataResourceUnionMember3OwnerUnionMember0",
+ "DataResourceUnionMember3OwnerUnionMember1",
+ "DataResourceUnionMember4",
+ "DataResourceUnionMember4Bank",
+ "DataResourceUnionMember4Card",
+ "DataResourceUnionMember5",
+ "DataResourceUnionMember6",
+ "DataSource",
+ "DataSourcePayoutDestination",
+ "DataAccount",
+ "DataAccountUnionMember0",
+ "DataAccountUnionMember1",
+ "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 DataResourceUnionMember2(BaseModel):
+ id: str
+ """Bounty ID."""
+
+ object: Literal["bounty"]
+
+ status: str
+ """Bounty lifecycle status."""
+
+ title: str
+ """Bounty title."""
+
+
+class DataResourceUnionMember3OwnerUnionMember0(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 DataResourceUnionMember3OwnerUnionMember1(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."""
+
+
+DataResourceUnionMember3Owner: TypeAlias = Union[
+ DataResourceUnionMember3OwnerUnionMember0, DataResourceUnionMember3OwnerUnionMember1, None
+]
+
+
+class DataResourceUnionMember3(BaseModel):
+ id: str
+ """Ledger account ID."""
+
+ object: Literal["ledger_account"]
+
+ owner: Optional[DataResourceUnionMember3Owner] = None
+
+
+class DataResourceUnionMember4Bank(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 DataResourceUnionMember4Card(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 DataResourceUnionMember4(BaseModel):
+ id: str
+ """Payment method ID."""
+
+ bank: Optional[DataResourceUnionMember4Bank] = None
+
+ card: Optional[DataResourceUnionMember4Card] = 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 DataResourceUnionMember5(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 DataResourceUnionMember6(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,
+ DataResourceUnionMember6,
+ 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)."""
+
+ reason: Optional[str] = None
+ """Transfer reason on transfer sources, for example pool_top_up or bounty_return."""
+
+ 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 DataAccountUnionMember0(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 DataAccountUnionMember1(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."""
+
+
+DataAccount: TypeAlias = Union[DataAccountUnionMember0, DataAccountUnionMember1]
+
+
+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."""
+
+ account: Optional[DataAccount] = None
+ """The viewer account that owns this row's ledger.
+
+ Present only when the response aggregates owned accounts
+ (include_owned_accounts=true); omitted otherwise.
+ """
+
+ ledger_account_id: Optional[str] = None
+ """The ledger account (a ldgr\\__ identifier) this row belongs to.
+
+ Present only when the response aggregates owned accounts
+ (include_owned_accounts=true); omitted otherwise. Pair it with `account` to
+ scope drawers and dashboard links to the owning business.
+ """
+
+
+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 4cbd70833..6c3fd981f 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 1a1991667..62928b01b 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 f498efd80..f03229ccd 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 83b882528..47bdd4ac9 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 d61885209..473ef563f 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 23b9a859a..03cc54546 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 8ff9b3373..ea92792c9 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 ba46184f7..88d81f554 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 000000000..7ceef5863
--- /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 fcaeeed07..86b90d833 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 a962bd3ed..121e82050 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/media_asset.py b/src/whop_sdk/types/media_asset.py
new file mode 100644
index 000000000..f16c19142
--- /dev/null
+++ b/src/whop_sdk/types/media_asset.py
@@ -0,0 +1,87 @@
+# 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__ = ["MediaAsset", "File", "Generation"]
+
+
+class File(BaseModel):
+ """The produced file, usable anywhere attachments are accepted.
+
+ `null` until the asset is `ready`.
+ """
+
+ id: str
+ """File ID, prefixed `file_`."""
+
+ url: str
+ """CDN URL for downloading the file."""
+
+
+class Generation(BaseModel):
+ """The inputs the asset was generated from."""
+
+ duration_seconds: Optional[float] = None
+ """Requested video length in seconds. `null` for images."""
+
+ prompt: str
+ """What the asset was generated from."""
+
+ reference_media: List[str]
+
+ resolution: Optional[Literal["480p", "720p", "1080p", "4k"]] = None
+ """Requested video resolution.
+
+ `null` for images. `1080p` is not supported by Seedance 2.0 Fast or Mini; `4k`
+ is only supported by Seedance 2.0.
+ """
+
+
+class MediaAsset(BaseModel):
+ id: str
+ """Media asset ID, prefixed `media_`."""
+
+ amount_charged: Optional[float] = None
+ """USD amount charged to the account's balance for this generation.
+
+ `null` if the generation wasn't billed.
+ """
+
+ completed_at: Optional[str] = None
+ """ISO 8601 timestamp when the asset reached a terminal state.
+
+ `null` while `processing`.
+ """
+
+ created_at: str
+ """ISO 8601 timestamp when the generation was requested."""
+
+ currency: str
+ """Currency of `amount_charged`. Always `usd`."""
+
+ error_message: Optional[str] = None
+ """Why generation failed. `null` unless status is `failed`."""
+
+ file: Optional[File] = None
+ """The produced file, usable anywhere attachments are accepted.
+
+ `null` until the asset is `ready`.
+ """
+
+ generation: Generation
+ """The inputs the asset was generated from."""
+
+ media_type: Literal["video", "image"]
+ """The kind of media this asset holds."""
+
+ source: Literal["generated"]
+ """How the asset was created. Always `generated`."""
+
+ status: Literal["processing", "ready", "failed"]
+ """
+ Lifecycle state: `processing` while generation runs, `ready` when the file is
+ available, `failed` when generation failed and the charge was refunded.
+ """
diff --git a/src/whop_sdk/types/media_generate_params.py b/src/whop_sdk/types/media_generate_params.py
new file mode 100644
index 000000000..6d532dfa0
--- /dev/null
+++ b/src/whop_sdk/types/media_generate_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_extensions import Literal, Required, TypedDict
+
+from .._types import SequenceNotStr
+
+__all__ = ["MediaGenerateParams"]
+
+
+class MediaGenerateParams(TypedDict, total=False):
+ prompt: Required[str]
+ """What to generate. Up to 2,000 characters."""
+
+ type: Required[Literal["video", "image"]]
+ """The kind of media to generate."""
+
+ account_id: str
+ """Account ID, prefixed `biz_`. Defaults to the account the API key belongs to."""
+
+ duration_seconds: Literal[5, 10, 15]
+ """Video length in seconds. Video only; defaults to 5."""
+
+ reference_media: SequenceNotStr[str]
+ """Optional reference image file IDs (`file_` prefixed), up to 4.
+
+ For video, a single reference seeds the opening frame; multiple references guide
+ subject and style instead.
+ """
+
+ resolution: Literal["480p", "720p", "1080p", "4k"]
+ """Video resolution.
+
+ Video only; defaults to `1080p`. `1080p` is not supported by Seedance 2.0 Fast
+ or Mini; `4k` is only supported by Seedance 2.0.
+ """
diff --git a/src/whop_sdk/types/membership_list_response.py b/src/whop_sdk/types/membership_list_response.py
index 89bccb93f..77034358d 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 000000000..fc6d3b8e2
--- /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_create_params.py b/src/whop_sdk/types/payment_create_params.py
index 3335e5f5e..6312b1402 100644
--- a/src/whop_sdk/types/payment_create_params.py
+++ b/src/whop_sdk/types/payment_create_params.py
@@ -38,6 +38,14 @@ class CreatePaymentInputWithPlan(TypedDict, total=False):
metadata: Optional[Dict[str, object]]
"""Custom metadata to attach to the payment."""
+ promo_code_id: Optional[str]
+ """The ID of an active promo code to apply to this payment.
+
+ The promo code must belong to the company and be valid for the plan being
+ purchased. The plan must be attached to a product — promo codes are not eligible
+ for one-off purchases.
+ """
+
class CreatePaymentInputWithPlanPlanProduct(TypedDict, total=False):
"""Pass this object to create a new product for this plan.
@@ -183,5 +191,13 @@ class CreatePaymentInputWithPlanID(TypedDict, total=False):
metadata: Optional[Dict[str, object]]
"""Custom metadata to attach to the payment."""
+ promo_code_id: Optional[str]
+ """The ID of an active promo code to apply to this payment.
+
+ The promo code must belong to the company and be valid for the plan being
+ purchased. The plan must be attached to a product — promo codes are not eligible
+ for one-off purchases.
+ """
+
PaymentCreateParams: TypeAlias = Union[CreatePaymentInputWithPlan, CreatePaymentInputWithPlanID]
diff --git a/src/whop_sdk/types/payment_list_response.py b/src/whop_sdk/types/payment_list_response.py
index 44a2275d6..7199461b4 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_create_params.py b/src/whop_sdk/types/payout_create_params.py
new file mode 100644
index 000000000..58531a94d
--- /dev/null
+++ b/src/whop_sdk/types/payout_create_params.py
@@ -0,0 +1,28 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["PayoutCreateParams"]
+
+
+class PayoutCreateParams(TypedDict, total=False):
+ account_id: Required[str]
+ """The account to pay out from (a biz\\__ identifier)."""
+
+ amount: Required[float]
+ """The amount to pay out in the specified currency."""
+
+ payout_method_id: Required[str]
+ """The saved payout method to deliver to (a potk\\__ identifier)."""
+
+ currency: str
+ """The payout currency. Defaults to usd."""
+
+ idempotency_key: str
+ """A client-generated key that makes retries safe.
+
+ Retrying with the same key returns the original payout instead of creating a
+ second one.
+ """
diff --git a/src/whop_sdk/types/payout_create_response.py b/src/whop_sdk/types/payout_create_response.py
new file mode 100644
index 000000000..639b0c672
--- /dev/null
+++ b/src/whop_sdk/types/payout_create_response.py
@@ -0,0 +1,72 @@
+# 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__ = ["PayoutCreateResponse", "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 PayoutCreateResponse(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.
+
+ Null until the payout settles.
+ """
+
+ 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. Null until the payout settles."""
+
+ 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", "in_transit", "completed", "failed", "canceled"]
+ """Current payout status, in the same vocabulary as GET /payouts."""
diff --git a/src/whop_sdk/types/payout_destination_category.py b/src/whop_sdk/types/payout_destination_category.py
deleted file mode 100644
index 03879408a..000000000
--- a/src/whop_sdk/types/payout_destination_category.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing_extensions import Literal, TypeAlias
-
-__all__ = ["PayoutDestinationCategory"]
-
-PayoutDestinationCategory: TypeAlias = Literal[
- "crypto", "rtp", "next_day_bank", "bank_wire", "digital_wallet", "unknown"
-]
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 000000000..e3b0e4e78
--- /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 000000000..b0dc6be4a
--- /dev/null
+++ b/src/whop_sdk/types/payout_list_response.py
@@ -0,0 +1,76 @@
+# 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_request_id: Optional[str] = None
+ """The ID returned by POST /payouts when this payout was requested.
+
+ Match it to the settled payout in GET /payouts. Null for payouts not created by
+ POST /payouts.
+ """
+
+ 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/payout_method_created_webhook_event.py b/src/whop_sdk/types/payout_method_created_webhook_event.py
index 13b1a36a7..0b8a4ad36 100644
--- a/src/whop_sdk/types/payout_method_created_webhook_event.py
+++ b/src/whop_sdk/types/payout_method_created_webhook_event.py
@@ -5,7 +5,6 @@
from typing_extensions import Literal
from .._models import BaseModel
-from .payout_destination_category import PayoutDestinationCategory
__all__ = ["PayoutMethodCreatedWebhookEvent", "Data", "DataCompany", "DataDestination"]
@@ -26,7 +25,7 @@ class DataDestination(BaseModel):
Null if not yet configured.
"""
- category: PayoutDestinationCategory
+ category: Literal["crypto", "rtp", "next_day_bank", "bank_wire", "digital_wallet", "unknown"]
"""The category of the payout destination"""
country_code: str
diff --git a/src/whop_sdk/types/payout_method_list_params.py b/src/whop_sdk/types/payout_method_list_params.py
deleted file mode 100644
index ab2308e64..000000000
--- a/src/whop_sdk/types/payout_method_list_params.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Optional
-from typing_extensions import Required, TypedDict
-
-__all__ = ["PayoutMethodListParams"]
-
-
-class PayoutMethodListParams(TypedDict, total=False):
- company_id: Required[str]
- """The unique identifier of the company to list payout methods for."""
-
- after: Optional[str]
- """Returns the elements in the list that come after the specified cursor."""
-
- before: Optional[str]
- """Returns the elements in the list that come before the specified cursor."""
-
- first: Optional[int]
- """Returns the first _n_ elements from the list."""
-
- last: Optional[int]
- """Returns the last _n_ elements from the list."""
diff --git a/src/whop_sdk/types/payout_method_list_response.py b/src/whop_sdk/types/payout_method_list_response.py
deleted file mode 100644
index 9a285dd86..000000000
--- a/src/whop_sdk/types/payout_method_list_response.py
+++ /dev/null
@@ -1,89 +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 .payout_destination_category import PayoutDestinationCategory
-
-__all__ = ["PayoutMethodListResponse", "Company", "Destination"]
-
-
-class Company(BaseModel):
- """The company associated with this payout destination.
-
- Null if not linked to a specific company.
- """
-
- id: str
- """The unique identifier for the company."""
-
-
-class Destination(BaseModel):
- """The payout destination configuration linked to this token.
-
- Null if not yet configured.
- """
-
- category: PayoutDestinationCategory
- """The category of the payout destination"""
-
- country_code: str
- """The country code of the payout destination"""
-
- name: str
- """The name of the payer associated with the payout destination"""
-
-
-class PayoutMethodListResponse(BaseModel):
- """
- A configured payout destination where a user receives earned funds, such as a bank account or digital wallet.
- """
-
- id: str
- """The unique identifier for the payout token."""
-
- account_reference: Optional[str] = None
- """
- A masked identifier for the payout destination, such as the last four digits of
- a bank account or an email address. Null if no reference is available.
- """
-
- company: Optional[Company] = None
- """The company associated with this payout destination.
-
- Null if not linked to a specific company.
- """
-
- created_at: datetime
- """The datetime the payout token was created."""
-
- currency: str
- """
- The three-letter ISO currency code that payouts are delivered in for this
- destination.
- """
-
- destination: Optional[Destination] = None
- """The payout destination configuration linked to this token.
-
- Null if not yet configured.
- """
-
- institution_name: Optional[str] = None
- """The name of the bank or financial institution receiving payouts.
-
- Null if not applicable or not provided.
- """
-
- is_default: bool
- """
- Whether this is the default payout destination for the associated payout
- account.
- """
-
- nickname: Optional[str] = None
- """A user-defined label to help identify this payout destination.
-
- Not sent to the provider. Null if no nickname has been set.
- """
diff --git a/src/whop_sdk/types/payout_method_retrieve_response.py b/src/whop_sdk/types/payout_method_retrieve_response.py
deleted file mode 100644
index 426236117..000000000
--- a/src/whop_sdk/types/payout_method_retrieve_response.py
+++ /dev/null
@@ -1,89 +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 .payout_destination_category import PayoutDestinationCategory
-
-__all__ = ["PayoutMethodRetrieveResponse", "Company", "Destination"]
-
-
-class Company(BaseModel):
- """The company associated with this payout destination.
-
- Null if not linked to a specific company.
- """
-
- id: str
- """The unique identifier for the company."""
-
-
-class Destination(BaseModel):
- """The payout destination configuration linked to this token.
-
- Null if not yet configured.
- """
-
- category: PayoutDestinationCategory
- """The category of the payout destination"""
-
- country_code: str
- """The country code of the payout destination"""
-
- name: str
- """The name of the payer associated with the payout destination"""
-
-
-class PayoutMethodRetrieveResponse(BaseModel):
- """
- A configured payout destination where a user receives earned funds, such as a bank account or digital wallet.
- """
-
- id: str
- """The unique identifier for the payout token."""
-
- account_reference: Optional[str] = None
- """
- A masked identifier for the payout destination, such as the last four digits of
- a bank account or an email address. Null if no reference is available.
- """
-
- company: Optional[Company] = None
- """The company associated with this payout destination.
-
- Null if not linked to a specific company.
- """
-
- created_at: datetime
- """The datetime the payout token was created."""
-
- currency: str
- """
- The three-letter ISO currency code that payouts are delivered in for this
- destination.
- """
-
- destination: Optional[Destination] = None
- """The payout destination configuration linked to this token.
-
- Null if not yet configured.
- """
-
- institution_name: Optional[str] = None
- """The name of the bank or financial institution receiving payouts.
-
- Null if not applicable or not provided.
- """
-
- is_default: bool
- """
- Whether this is the default payout destination for the associated payout
- account.
- """
-
- nickname: Optional[str] = None
- """A user-defined label to help identify this payout destination.
-
- Not sent to the provider. Null if no nickname has been set.
- """
diff --git a/src/whop_sdk/types/payouts/__init__.py b/src/whop_sdk/types/payouts/__init__.py
new file mode 100644
index 000000000..26a31a19a
--- /dev/null
+++ b/src/whop_sdk/types/payouts/__init__.py
@@ -0,0 +1,6 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .method_list_params import MethodListParams as MethodListParams
+from .method_list_response import MethodListResponse as MethodListResponse
diff --git a/src/whop_sdk/types/payouts/method_list_params.py b/src/whop_sdk/types/payouts/method_list_params.py
new file mode 100644
index 000000000..5081e3538
--- /dev/null
+++ b/src/whop_sdk/types/payouts/method_list_params.py
@@ -0,0 +1,54 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypedDict
+
+__all__ = ["MethodListParams"]
+
+
+class MethodListParams(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)."""
+
+ amount: float
+ """Optional withdrawal amount in whole currency units, for example `250.00`.
+
+ When provided, each method includes a quote with the estimated fee, amount
+ received, and delivery date for that amount.
+ """
+
+ before: str
+ """Cursor to fetch the page before (from page_info.start_cursor)."""
+
+ currency: str
+ """Currency code of the amount, for example `usd`. Only meaningful with amount."""
+
+ first: int
+ """Number of payout methods to return from the start of the window.
+
+ Capped at 25 when an amount is provided.
+ """
+
+ include_available: bool
+ """
+ When true, the response also carries available_destinations — payout rails the
+ account could add as a new payout method, with per-currency quotes when an
+ amount is provided.
+ """
+
+ last: int
+ """Number of payout methods to return from the end of the window."""
+
+ status: Literal["created", "active", "broken"]
+ """Optional status filter.
+
+ `created` means saved but unused, `active` means a payout through it succeeded,
+ `broken` means the last payout failed and the method needs fixing.
+ """
+
+ user_id: str
+ """The owning user ID (a user\\__ identifier). Provide this or account_id."""
diff --git a/src/whop_sdk/types/payouts/method_list_response.py b/src/whop_sdk/types/payouts/method_list_response.py
new file mode 100644
index 000000000..80088375d
--- /dev/null
+++ b/src/whop_sdk/types/payouts/method_list_response.py
@@ -0,0 +1,139 @@
+# 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__ = ["MethodListResponse", "PayoutDestination", "Quote", "QuoteInstant", "QuoteStandard"]
+
+
+class PayoutDestination(BaseModel):
+ """The payout rail this method delivers through."""
+
+ delivery_type: str
+ """How funds are delivered, for example `bank_deposit`."""
+
+ icon_url: Optional[str] = None
+ """Payout destination icon URL."""
+
+ name: Optional[str] = None
+ """Payout destination display name."""
+
+ supports_instant_delivery: bool
+
+ supports_standard_delivery: bool
+
+
+class QuoteInstant(BaseModel):
+ """Instant-delivery estimate.
+
+ Null if the method does not support instant delivery, instant delivery is unavailable for the account, or the amount does not cover the fee.
+ """
+
+ estimated_arrival: datetime
+ """Estimated time the funds become available."""
+
+ fee: float
+ """Total fee charged, in the withdrawal currency."""
+
+ total_received: float
+ """Amount delivered after fees, in the withdrawal currency."""
+
+
+class QuoteStandard(BaseModel):
+ """Standard-delivery estimate.
+
+ Null if the method does not support standard delivery, or the amount does not cover the fee.
+ """
+
+ estimated_arrival: datetime
+ """Estimated time the funds become available."""
+
+ fee: float
+ """Total fee charged, in the withdrawal currency."""
+
+ total_received: float
+ """Amount delivered after fees, in the withdrawal currency."""
+
+
+class Quote(BaseModel):
+ """
+ Fee and delivery estimate for withdrawing the requested amount through this method. Null unless an amount was provided, or when the estimate is unavailable.
+ """
+
+ amount: float
+ """The withdrawal amount the quote is for."""
+
+ currency: str
+ """Currency of the quoted amount."""
+
+ exchange_rate: float
+ """Exchange rate from the withdrawal currency to the destination currency."""
+
+ instant: Optional[QuoteInstant] = None
+ """Instant-delivery estimate.
+
+ Null if the method does not support instant delivery, instant delivery is
+ unavailable for the account, or the amount does not cover the fee.
+ """
+
+ max_limit: Optional[float] = None
+ """Maximum withdrawal amount for this method, in the withdrawal currency."""
+
+ min_limit: float
+ """Minimum withdrawal amount for this method, in the withdrawal currency."""
+
+ standard: Optional[QuoteStandard] = None
+ """Standard-delivery estimate.
+
+ Null if the method does not support standard delivery, or the amount does not
+ cover the fee.
+ """
+
+
+class MethodListResponse(BaseModel):
+ id: str
+ """Payout method ID."""
+
+ account_reference: Optional[str] = None
+ """
+ Masked identifier for the destination, such as the last four digits of a bank
+ account.
+ """
+
+ created_at: datetime
+ """When the payout method was added."""
+
+ destination_currency: str
+ """Currency payouts are delivered in for this method."""
+
+ institution_name: Optional[str] = None
+ """Name of the bank or institution receiving payouts."""
+
+ is_default: bool
+ """Whether this is the default payout method for the account."""
+
+ nickname: Optional[str] = None
+ """User-defined label for the payout method."""
+
+ object: Literal["payout_method"]
+
+ payer_name: Optional[str] = None
+ """Display name of the payout rail, such as `ACH Bank Deposit`."""
+
+ payout_destination: Optional[PayoutDestination] = None
+ """The payout rail this method delivers through."""
+
+ quote: Optional[Quote] = None
+ """
+ Fee and delivery estimate for withdrawing the requested amount through this
+ method. Null unless an amount was provided, or when the estimate is unavailable.
+ """
+
+ status: Literal["created", "active", "broken"]
+ """
+ Lifecycle status: `created` means saved but unused, `active` means a payout
+ succeeded through it, `broken` means the last payout failed.
+ """
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 000000000..5f8e899c2
--- /dev/null
+++ b/src/whop_sdk/types/person_list_params.py
@@ -0,0 +1,45 @@
+# 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.
+ """
+
+ after: str
+ """A cursor for fetching people after a previous page."""
+
+ before: str
+ """A cursor for fetching people before a later page."""
+
+ 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 100)."""
+
+ from_: Annotated[int, PropertyInfo(alias="from")]
+ """Start of the time range as a Unix timestamp. Defaults to 366 days before `to`."""
+
+ 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 000000000..4106dc08e
--- /dev/null
+++ b/src/whop_sdk/types/person_list_response.py
@@ -0,0 +1,63 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from .._models import BaseModel
+
+__all__ = ["PersonListResponse", "AdSet", "Ad", "Campaign"]
+
+
+class AdSet(BaseModel):
+ id: str
+
+ name: Optional[str] = None
+
+ thumbnail_url: Optional[str] = None
+
+
+class Ad(BaseModel):
+ id: str
+
+ name: Optional[str] = None
+
+ thumbnail_url: Optional[str] = None
+
+
+class Campaign(BaseModel):
+ id: str
+
+ name: Optional[str] = None
+
+ thumbnail_url: Optional[str] = None
+
+
+class PersonListResponse(BaseModel):
+ id: str
+
+ account_id: str
+
+ first_seen_at: int
+
+ last_seen_at: int
+
+ person_id: str
+
+ purchase_count: int
+
+ ad_sets: Optional[List[AdSet]] = None
+
+ ads: Optional[List[Ad]] = None
+
+ aov: Optional[float] = None
+
+ campaigns: Optional[List[Campaign]] = None
+
+ email: Optional[str] = None
+
+ has_failed_payment: Optional[bool] = None
+
+ ltv: Optional[float] = None
+
+ name: Optional[str] = None
+
+ phone: Optional[str] = None
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 000000000..eb58b6dbc
--- /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 000000000..63da01d8d
--- /dev/null
+++ b/src/whop_sdk/types/person_retrieve_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__ = ["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
+
+ account_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 000000000..d75a16946
--- /dev/null
+++ b/src/whop_sdk/types/plan_calculate_tax_params.py
@@ -0,0 +1,168 @@
+# 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]
+ """Buyer billing address used for tax calculation.
+
+ Provide either `address.country` or `ip_address`; include state and postal code
+ when available for more accurate results.
+ """
+
+ ip_address: str
+ """Buyer IP address used to infer location when no billing address is provided."""
+
+ tax_ids: Optional[Iterable[TaxID]]
+ """Optional buyer tax ID for B2B exemptions. At most one entry is supported."""
+
+
+class Address(TypedDict, total=False):
+ """Buyer billing address used for tax calculation.
+
+ Provide either `address.country` or `ip_address`; include state and postal code when available for more accurate results.
+ """
+
+ country: Required[str]
+ """ISO 3166-1 alpha-2 country code, such as `US`, `DE`, or `GB`."""
+
+ city: Optional[str]
+ """City name."""
+
+ line1: Optional[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, such as `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, such as `eu_vat` for an EU VAT number."""
+
+ value: str
+ """Tax ID value, 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 000000000..f1c5e9104
--- /dev/null
+++ b/src/whop_sdk/types/plan_calculate_tax_response.py
@@ -0,0 +1,42 @@
+# 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
+ """Three-letter ISO 4217 currency code for the returned amounts."""
+
+ status: Literal["calculated", "not_calculated"]
+ """Whether Whop calculated tax for this preview.
+
+ `not_calculated` means no tax could be determined, so `tax_amount` is 0 and
+ `total` equals `subtotal`.
+ """
+
+ subtotal: int
+ """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
+ includes tax and equals the total.
+ """
+
+ tax_amount: int
+ """Calculated tax amount in the currency's smallest unit.
+
+ For exclusive tax, this is added on top of the subtotal; for inclusive tax, it
+ is the portion of the subtotal that is tax.
+ """
+
+ tax_behavior: Literal["exclusive", "inclusive"]
+ """
+ Whether tax is added on top of the plan price or already included in it for this
+ buyer's location.
+ """
+
+ total: int
+ """Amount the buyer would pay 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 34e9edc19..86d546947 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 fc24663e4..daaa48a7a 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 db577cf46..28c91fa1b 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 853a890f5..bf5882af2 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 103fbc3d6..0a89dd579 100644
--- a/src/whop_sdk/types/product_create_params.py
+++ b/src/whop_sdk/types/product_create_params.py
@@ -2,88 +2,61 @@
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.
+
+ See the available
+ [product categories](https://docs.numeral.com/essentials/product-categories).
+ """
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."""
@@ -94,59 +67,5 @@ class ProductCreateParams(TypedDict, total=False):
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 47862a61b..5b666c388 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 64a7c8c11..e5e05c501 100644
--- a/src/whop_sdk/types/product_update_params.py
+++ b/src/whop_sdk/types/product_update_params.py
@@ -2,78 +2,28 @@
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."""
+ """The unique identifier of the tax classification code.
- route: Optional[str]
- """The URL slug for the product's public link."""
+ See the available
+ [product categories](https://docs.numeral.com/essentials/product-categories).
+ """
send_welcome_message: Optional[bool]
"""
@@ -81,28 +31,8 @@ class ProductUpdateParams(TypedDict, total=False):
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."""
-
- 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/referral_referred_users_params.py b/src/whop_sdk/types/referral_referred_users_params.py
new file mode 100644
index 000000000..fe9315684
--- /dev/null
+++ b/src/whop_sdk/types/referral_referred_users_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__ = ["ReferralReferredUsersParams"]
+
+
+class ReferralReferredUsersParams(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)."""
+
+ first: int
+ """Number of referred users to return from the start of the window."""
+
+ has_businesses: bool
+ """When true, only referred users who brought at least one business onto Whop."""
+
+ has_earning_businesses: bool
+ """
+ When true, only referred users with at least one business that has generated
+ earnings.
+ """
+
+ last: int
+ """Number of referred users to return from the end of the window."""
diff --git a/src/whop_sdk/types/referral_referred_users_response.py b/src/whop_sdk/types/referral_referred_users_response.py
new file mode 100644
index 000000000..5d7dfc019
--- /dev/null
+++ b/src/whop_sdk/types/referral_referred_users_response.py
@@ -0,0 +1,49 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from .._models import BaseModel
+
+__all__ = ["ReferralReferredUsersResponse", "Data", "DataUser", "DataUserProfilePicture", "PageInfo"]
+
+
+class DataUserProfilePicture(BaseModel):
+ url: Optional[str] = None
+
+
+class DataUser(BaseModel):
+ id: str
+
+ username: str
+
+ city: Optional[str] = None
+
+ country: Optional[str] = None
+
+ name: Optional[str] = None
+
+ profile_picture: Optional[DataUserProfilePicture] = None
+
+
+class Data(BaseModel):
+ total_earnings_usd: str
+
+ total_volume_usd: str
+
+ user: DataUser
+
+
+class PageInfo(BaseModel):
+ end_cursor: Optional[str] = None
+
+ has_next_page: bool
+
+ has_previous_page: bool
+
+ start_cursor: Optional[str] = None
+
+
+class ReferralReferredUsersResponse(BaseModel):
+ data: List[Data]
+
+ page_info: PageInfo
diff --git a/src/whop_sdk/types/referrals/__init__.py b/src/whop_sdk/types/referrals/__init__.py
new file mode 100644
index 000000000..b2d288619
--- /dev/null
+++ b/src/whop_sdk/types/referrals/__init__.py
@@ -0,0 +1,10 @@
+# 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 .partner_create_response import PartnerCreateResponse as PartnerCreateResponse
+from .business_retrieve_response import BusinessRetrieveResponse as BusinessRetrieveResponse
+from .business_leaderboard_params import BusinessLeaderboardParams as BusinessLeaderboardParams
+from .business_leaderboard_response import BusinessLeaderboardResponse as BusinessLeaderboardResponse
diff --git a/src/whop_sdk/types/referrals/business_leaderboard_params.py b/src/whop_sdk/types/referrals/business_leaderboard_params.py
new file mode 100644
index 000000000..76c17d8e8
--- /dev/null
+++ b/src/whop_sdk/types/referrals/business_leaderboard_params.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypedDict
+
+__all__ = ["BusinessLeaderboardParams"]
+
+
+class BusinessLeaderboardParams(TypedDict, total=False):
+ period: Literal["day", "month", "year", "last_30_days", "all_time"]
+ """Time window for the rankings.
+
+ `day`, `month`, and `year` count earnings since the start of the current
+ calendar day, month, or year; `last_30_days` counts earnings over the trailing
+ 30 days; `all_time` ranks lifetime earnings.
+ """
diff --git a/src/whop_sdk/types/referrals/business_leaderboard_response.py b/src/whop_sdk/types/referrals/business_leaderboard_response.py
new file mode 100644
index 000000000..16b646afb
--- /dev/null
+++ b/src/whop_sdk/types/referrals/business_leaderboard_response.py
@@ -0,0 +1,150 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+
+from ..._models import BaseModel
+
+__all__ = [
+ "BusinessLeaderboardResponse",
+ "Leader",
+ "LeaderUser",
+ "LeaderUserProfilePicture",
+ "Me",
+ "MeUser",
+ "MeUserProfilePicture",
+]
+
+
+class LeaderUserProfilePicture(BaseModel):
+ """The user's profile picture. Present only on the caller's own entry."""
+
+ url: str
+ """The user's profile picture URL."""
+
+
+class LeaderUser(BaseModel):
+ """The ranked referrer.
+
+ Identity fields (id, name, username, profile_picture) are returned only on the caller's own entry; other referrers expose coarse location only.
+ """
+
+ city: Optional[str] = None
+ """The city where the referrer is located, derived from their IP address.
+
+ Null if location sharing is disabled.
+ """
+
+ country: Optional[str] = None
+ """The country where the referrer is located, derived from their IP address.
+
+ Null if location sharing is disabled.
+ """
+
+ id: Optional[str] = None
+ """User ID, prefixed `user_`. Present only on the caller's own entry."""
+
+ name: Optional[str] = None
+ """The user's display name. Present only on the caller's own entry."""
+
+ profile_picture: Optional[LeaderUserProfilePicture] = None
+ """The user's profile picture. Present only on the caller's own entry."""
+
+ username: Optional[str] = None
+ """The user's unique username. Present only on the caller's own entry."""
+
+
+class Leader(BaseModel):
+ first_referral_started_at: datetime
+ """When the referrer's earliest business referral became active."""
+
+ rank: int
+ """1-based leaderboard position."""
+
+ total_earnings_usd: str
+ """
+ The referrer's pending + completed earnings across all referred businesses, in
+ USD.
+ """
+
+ total_volume_usd: str
+ """Credited GMV across all the referrer's referred businesses, in USD."""
+
+ user: Optional[LeaderUser] = None
+ """The ranked referrer.
+
+ Identity fields (id, name, username, profile_picture) are returned only on the
+ caller's own entry; other referrers expose coarse location only.
+ """
+
+
+class MeUserProfilePicture(BaseModel):
+ """The user's profile picture. Present only on the caller's own entry."""
+
+ url: str
+ """The user's profile picture URL."""
+
+
+class MeUser(BaseModel):
+ """The ranked referrer.
+
+ Identity fields (id, name, username, profile_picture) are returned only on the caller's own entry; other referrers expose coarse location only.
+ """
+
+ city: Optional[str] = None
+ """The city where the referrer is located, derived from their IP address.
+
+ Null if location sharing is disabled.
+ """
+
+ country: Optional[str] = None
+ """The country where the referrer is located, derived from their IP address.
+
+ Null if location sharing is disabled.
+ """
+
+ id: Optional[str] = None
+ """User ID, prefixed `user_`. Present only on the caller's own entry."""
+
+ name: Optional[str] = None
+ """The user's display name. Present only on the caller's own entry."""
+
+ profile_picture: Optional[MeUserProfilePicture] = None
+ """The user's profile picture. Present only on the caller's own entry."""
+
+ username: Optional[str] = None
+ """The user's unique username. Present only on the caller's own entry."""
+
+
+class Me(BaseModel):
+ """The caller's own standing; null when the caller has no referral earnings."""
+
+ first_referral_started_at: datetime
+ """When the referrer's earliest business referral became active."""
+
+ rank: int
+ """1-based leaderboard position."""
+
+ total_earnings_usd: str
+ """
+ The referrer's pending + completed earnings across all referred businesses, in
+ USD.
+ """
+
+ total_volume_usd: str
+ """Credited GMV across all the referrer's referred businesses, in USD."""
+
+ user: Optional[MeUser] = None
+ """The ranked referrer.
+
+ Identity fields (id, name, username, profile_picture) are returned only on the
+ caller's own entry; other referrers expose coarse location only.
+ """
+
+
+class BusinessLeaderboardResponse(BaseModel):
+ leaders: List[Leader]
+ """The top referrers by total earnings, best first."""
+
+ me: Optional[Me] = None
+ """The caller's own standing; null when the caller has no referral earnings."""
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 000000000..a6970ad33
--- /dev/null
+++ b/src/whop_sdk/types/referrals/business_list_params.py
@@ -0,0 +1,60 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_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)."""
+
+ created_after: str
+ """Only return business referrals created after this timestamp."""
+
+ created_before: str
+ """Only return business referrals created before this timestamp."""
+
+ 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 pending or completed earnings 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."""
+
+ referred_user_id: str
+ """Filter to referrals attributed to this user.
+
+ For first-tier referrals, this is the referred account owner; for second-tier
+ referrals, this is the partner you recruited.
+ """
+
+ referred_username: str
+ """Filter by the referred user's exact username.
+
+ Ignored when `referred_user_id` is present.
+ """
+
+ status: Literal["active", "removed"]
+ """Filter by referral status."""
+
+ tier: Literal["first", "second"]
+ """Filter to only first-tier referrals or only second-tier referrals."""
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 000000000..ea1874b18
--- /dev/null
+++ b/src/whop_sdk/types/referrals/business_list_response.py
@@ -0,0 +1,155 @@
+# 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",
+ "FirstTierPartner",
+ "FirstTierPartnerProfilePicture",
+ "Owner",
+ "OwnerProfilePicture",
+ "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 FirstTierPartnerProfilePicture(BaseModel):
+ """The user's profile picture."""
+
+ url: str
+ """The user's profile picture URL."""
+
+
+class FirstTierPartner(BaseModel):
+ """The partner who referred the business owner onto Whop (first tier).
+
+ Null if there is no active first-tier partner.
+ """
+
+ id: str
+ """User ID, prefixed `user_`."""
+
+ name: Optional[str] = None
+ """The user's display name."""
+
+ profile_picture: FirstTierPartnerProfilePicture
+ """The user's profile picture."""
+
+ username: str
+ """The user's unique username."""
+
+
+class OwnerProfilePicture(BaseModel):
+ """The user's profile picture."""
+
+ url: str
+ """The user's profile picture URL."""
+
+
+class Owner(BaseModel):
+ """The owner of the referred business."""
+
+ id: str
+ """User ID, prefixed `user_`."""
+
+ name: Optional[str] = None
+ """The user's display name."""
+
+ profile_picture: OwnerProfilePicture
+ """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
+
+ first_tier_partner: Optional[FirstTierPartner] = None
+ """The partner who referred the business owner onto Whop (first tier).
+
+ Null if there is no active first-tier partner.
+ """
+
+ my_partner_tier: Literal["first", "second"]
+ """
+ Which tier the caller earns on for this business: `first` (they referred the
+ owner) or `second` (they referred the first-tier partner).
+ """
+
+ object: Literal["business_referral"]
+
+ owner: Optional[Owner] = None
+ """The owner of the referred business."""
+
+ payout_percentage: float
+ """Referrer's share of Whop gross profit, as a fraction (0.3 = 30%).
+
+ Second-tier referrals earn a flat 0.1.
+ """
+
+ 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."""
+
+ 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 000000000..a13a81ed1
--- /dev/null
+++ b/src/whop_sdk/types/referrals/business_retrieve_response.py
@@ -0,0 +1,282 @@
+# 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",
+ "FirstTierPartner",
+ "FirstTierPartnerProfilePicture",
+ "Owner",
+ "OwnerProfilePicture",
+ "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[
+ "theme_business",
+ "create_product",
+ "create_plan",
+ "verify_identity",
+ "connect_affiliate_program",
+ "create_promotion",
+ "setup_tracking_pixel",
+ "migrate_from_stripe",
+ "accept_first_payment",
+ "launch_first_ad",
+ "invite_team_member",
+ "enable_tax_collection",
+ "create_card",
+ "join_whop_university",
+ "apply_for_financing",
+ ]
+ """
+ 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`"""
+
+ impact_score: Optional[int] = None
+ """
+ Estimated revenue impact from 0-100, comparable across accounts, or `null` when
+ not ranked
+ """
+
+ reasoning: Optional[str] = None
+ """Why this action was recommended for this account, 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 FirstTierPartnerProfilePicture(BaseModel):
+ """The user's profile picture."""
+
+ url: str
+ """The user's profile picture URL."""
+
+
+class FirstTierPartner(BaseModel):
+ """The partner who referred the business owner onto Whop (first tier).
+
+ Null if there is no active first-tier partner.
+ """
+
+ id: str
+ """User ID, prefixed `user_`."""
+
+ name: Optional[str] = None
+ """The user's display name."""
+
+ profile_picture: FirstTierPartnerProfilePicture
+ """The user's profile picture."""
+
+ username: str
+ """The user's unique username."""
+
+
+class OwnerProfilePicture(BaseModel):
+ """The user's profile picture."""
+
+ url: str
+ """The user's profile picture URL."""
+
+
+class Owner(BaseModel):
+ """The owner of the referred business."""
+
+ id: str
+ """User ID, prefixed `user_`."""
+
+ name: Optional[str] = None
+ """The user's display name."""
+
+ profile_picture: OwnerProfilePicture
+ """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
+
+ first_tier_partner: Optional[FirstTierPartner] = None
+ """The partner who referred the business owner onto Whop (first tier).
+
+ Null if there is no active first-tier partner.
+ """
+
+ my_partner_tier: Literal["first", "second"]
+ """
+ Which tier the caller earns on for this business: `first` (they referred the
+ owner) or `second` (they referred the first-tier partner).
+ """
+
+ object: Literal["business_referral"]
+
+ owner: Optional[Owner] = None
+ """The owner of the referred business."""
+
+ payout_percentage: float
+ """Referrer's share of Whop gross profit, as a fraction (0.3 = 30%).
+
+ Second-tier referrals earn a flat 0.1.
+ """
+
+ 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."""
+
+ 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 000000000..dc2fac398
--- /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 000000000..2b5188b2c
--- /dev/null
+++ b/src/whop_sdk/types/referrals/businesses/earning_list_params.py
@@ -0,0 +1,32 @@
+# 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
+
+ created_after: str
+ """Only return earnings created after this timestamp."""
+
+ created_before: str
+ """Only return earnings created before this timestamp."""
+
+ 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 000000000..7af57c7fc
--- /dev/null
+++ b/src/whop_sdk/types/referrals/businesses/earning_list_response.py
@@ -0,0 +1,132 @@
+# 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__ = [
+ "EarningListResponse",
+ "Account",
+ "FinancialActivity",
+ "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 FinancialActivity(BaseModel):
+ amount: str
+ """Line amount in its native currency."""
+
+ amount_usd: str
+ """Line amount in USD."""
+
+ category: Optional[str] = None
+ """Fee or cost category of the line."""
+
+ created_at: Optional[datetime] = None
+
+ currency: str
+ """Currency of the native amount."""
+
+ type: Literal["income", "expense"]
+ """Whether the line is income Whop collected or a cost Whop paid."""
+
+
+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
+
+ financial_activity: Optional[List[FinancialActivity]] = None
+ """Income and cost lines behind this earning's commission.
+
+ Null for earnings settled before this data was recorded.
+ """
+
+ 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."""
+
+ second_tier: bool
+ """Whether this earning is a second-tier (grandparent) commission."""
+
+ 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/partner_create_response.py b/src/whop_sdk/types/referrals/partner_create_response.py
new file mode 100644
index 000000000..2d8cabc53
--- /dev/null
+++ b/src/whop_sdk/types/referrals/partner_create_response.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from datetime import datetime
+
+from ..._models import BaseModel
+
+__all__ = ["PartnerCreateResponse"]
+
+
+class PartnerCreateResponse(BaseModel):
+ referral_link: str
+ """
+ The caller's referral link — businesses that sign up through it are attributed
+ to the caller.
+ """
+
+ whop_partner_enabled_at: datetime
+ """When the caller became a Whop partner."""
diff --git a/src/whop_sdk/types/refund_created_webhook_event.py b/src/whop_sdk/types/refund_created_webhook_event.py
index 611640f08..6ab91ee20 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 e1f0ad14d..94976ead1 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 9fbd5a1a1..27591ce0c 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/result_label_keys.py b/src/whop_sdk/types/result_label_keys.py
index 4a4d4657c..bfa078e22 100644
--- a/src/whop_sdk/types/result_label_keys.py
+++ b/src/whop_sdk/types/result_label_keys.py
@@ -26,7 +26,17 @@
"registrations",
"content_views",
"searches",
+ "adds_to_cart",
+ "adds_to_wishlist",
+ "adds_of_payment_info",
+ "checkouts_initiated",
"website_schedules",
"website_submit_applications",
+ "website_trials_started",
+ "website_subscriptions",
+ "website_contacts",
+ "website_donations",
+ "website_find_locations",
+ "website_product_customizations",
"custom",
]
diff --git a/src/whop_sdk/types/review_list_response.py b/src/whop_sdk/types/review_list_response.py
index 5a670355e..8627ff8d1 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 bd1157f7c..3f6b93fad 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 a79a2b76f..5f3f67b4d 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 b1c4a4677..249442f19 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/app.py b/src/whop_sdk/types/shared/app.py
index 90828995f..036cd6b48 100644
--- a/src/whop_sdk/types/shared/app.py
+++ b/src/whop_sdk/types/shared/app.py
@@ -1,11 +1,12 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import List, Optional
+from typing import Dict, List, Optional
from datetime import datetime
from ..._models import BaseModel
from ..app_type import AppType
from .app_statuses import AppStatuses
+from .app_build_statuses import AppBuildStatuses
__all__ = [
"App",
@@ -13,6 +14,7 @@
"Company",
"Creator",
"Icon",
+ "ProductionWebBuild",
"RequestedPermission",
"RequestedPermissionPermissionAction",
"Stats",
@@ -70,6 +72,28 @@ class Icon(BaseModel):
"""
+class ProductionWebBuild(BaseModel):
+ """The approved app build currently served to users on web.
+
+ Null if no production build is deployed for web.
+ """
+
+ id: str
+ """The unique identifier for the app build."""
+
+ checksum: str
+ """
+ A SHA-256 hash of the uploaded build file, generated by the client and used to
+ verify file integrity.
+ """
+
+ file_url: str
+ """A URL to download the app build as a .zip archive."""
+
+ status: AppBuildStatuses
+ """The current review status of this build."""
+
+
class RequestedPermissionPermissionAction(BaseModel):
"""The action that the app will request off of users when a user installs the app."""
@@ -192,6 +216,12 @@ class App(BaseModel):
not configured.
"""
+ hosted_url: Optional[str] = None
+ """The full canonical URL where this app's hosted web build is served.
+
+ Null if the app has not claimed a route.
+ """
+
icon: Optional[Icon] = None
"""
The icon image for this app, displayed on the app store, product pages,
@@ -218,6 +248,12 @@ class App(BaseModel):
'https://myapp.apps.whop.com'). Null if no proxy domain is configured.
"""
+ production_web_build: Optional[ProductionWebBuild] = None
+ """The approved app build currently served to users on web.
+
+ Null if no production build is deployed for web.
+ """
+
redirect_uris: List[str]
"""
The whitelisted OAuth callback URLs that users are redirected to after
@@ -230,6 +266,19 @@ class App(BaseModel):
required and optional permissions with justifications.
"""
+ route: Optional[str] = None
+ """
+ The unique subdomain route where this app's hosted web builds are served, such
+ as 'myapp' for myapp.whop.app. Null if the app has not claimed a route.
+ """
+
+ secrets: Optional[Dict[str, object]] = None
+ """The app's secrets as an object of string values.
+
+ Encrypted at rest and injected into the app's hosted server runtime as
+ environment bindings. Requires the 'developer:update_app' permission.
+ """
+
skills_path: Optional[str] = None
"""
The URL path template for a specific view of this app, appended to the base
diff --git a/src/whop_sdk/types/shared/checkout_configuration.py b/src/whop_sdk/types/shared/checkout_configuration.py
index d21bcd8ff..6aadc59d9 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 764ef9928..a95e9086e 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 c6241f91d..50a1951fd 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 7a6136d7f..1bcccfe76 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 4f8d3fd06..41057e146 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 3c262c6d4..3f5056acb 100644
--- a/src/whop_sdk/types/shared/payment.py
+++ b/src/whop_sdk/types/shared/payment.py
@@ -8,6 +8,7 @@
from ..._models import BaseModel
from .promo_type import PromoType
from ..card_brands import CardBrands
+from ..refund_status import RefundStatus
from .receipt_status import ReceiptStatus
from ..billing_reasons import BillingReasons
from ..dispute_statuses import DisputeStatuses
@@ -35,7 +36,9 @@
"Plan",
"Product",
"PromoCode",
+ "Refund",
"Resolution",
+ "ShippingAddress",
"User",
]
@@ -260,7 +263,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 +275,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
@@ -316,6 +321,33 @@ class PromoCode(BaseModel):
"""The type (% or flat amount) of the promo."""
+class Refund(BaseModel):
+ """
+ A refund represents a full or partial reversal of a payment, including the amount, status, and payment provider.
+ """
+
+ id: str
+ """The unique identifier for the refund."""
+
+ amount: float
+ """
+ The refunded amount as a decimal in the specified currency, such as 10.43 for
+ $10.43 USD.
+ """
+
+ created_at: datetime
+ """The datetime the refund was created."""
+
+ currency: Currency
+ """The three-letter ISO currency code for the refunded amount."""
+
+ status: RefundStatus
+ """
+ The current processing status of the refund, such as pending, succeeded, or
+ failed.
+ """
+
+
class Resolution(BaseModel):
"""
A resolution center case is a dispute or support case between a user and a company, tracking the issue, status, and outcome.
@@ -358,6 +390,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."""
@@ -507,6 +567,12 @@ class Payment(BaseModel):
refunded_at: Optional[datetime] = None
"""When the payment was refunded (if applicable)."""
+ refunds: List[Refund]
+ """
+ The refunds issued against this payment, newest first, including failed and
+ canceled refund attempts. Limited to the 100 most recent.
+ """
+
resolutions: Optional[List[Resolution]] = None
"""The resolution center cases opened by the customer on this payment.
@@ -521,6 +587,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 +613,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 +640,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 cf775d352..7fa371ffe 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 ce6299b89..70afd71fb 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 af1e59d58..eb084358b 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 8668f9e1a..000000000
--- 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 eb838c16f..e20001244 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 3f760c67a..000000000
--- 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 0c2f5d19d..000000000
--- 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 bae01a1ab..000000000
--- 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 d01e6cb16..000000000
--- 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 000000000..b8b4af4b4
--- /dev/null
+++ b/src/whop_sdk/types/social_account.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__ = ["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: Optional[str] = None
+ """The URL where the social account can be accessed on the platform.
+
+ Null while a Whop-owned page is still being provisioned.
+ """
+
+ username: Optional[str] = None
+ """The username of the social account on the platform.
+
+ Null while a Whop-owned page is still being provisioned.
+ """
+
+ verified: bool
+ """Whether the social account is verified on the platform."""
diff --git a/src/whop_sdk/types/social_account_connect_params.py b/src/whop_sdk/types/social_account_connect_params.py
new file mode 100644
index 000000000..b36d9b190
--- /dev/null
+++ b/src/whop_sdk/types/social_account_connect_params.py
@@ -0,0 +1,31 @@
+# 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__ = ["SocialAccountConnectParams"]
+
+
+class SocialAccountConnectParams(TypedDict, total=False):
+ platform: Required[Literal["meta_business"]]
+ """The platform to connect the social account on.
+
+ Today, the supported option is `meta_business`.
+ """
+
+ 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.
+ """
+
+ redirect_url: str
+ """The Whop URL to redirect the user to after they finish connecting."""
+
+ scopes: List[Literal["advertise"]]
+ """Capabilities to grant for the connected social account.
+
+ Use `advertise` when connecting a Meta Business account for ads.
+ """
diff --git a/src/whop_sdk/types/social_account_connect_response.py b/src/whop_sdk/types/social_account_connect_response.py
new file mode 100644
index 000000000..37bf998cb
--- /dev/null
+++ b/src/whop_sdk/types/social_account_connect_response.py
@@ -0,0 +1,10 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .._models import BaseModel
+
+__all__ = ["SocialAccountConnectResponse"]
+
+
+class SocialAccountConnectResponse(BaseModel):
+ authorize_url: str
+ """The OAuth authorization URL to redirect the user to."""
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 000000000..994b37740
--- /dev/null
+++ b/src/whop_sdk/types/social_account_create_params.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["SocialAccountCreateParams"]
+
+
+class SocialAccountCreateParams(TypedDict, total=False):
+ platform: Required[Literal["facebook"]]
+ """The platform to create the social account on."""
+
+ account_id: str
+ """The Account (biz\\__ identifier) to create the social account for.
+
+ An account-scoped API key may omit this to default to its own account.
+ """
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 000000000..cd4b58f14
--- /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 000000000..a37179be1
--- /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 000000000..c6b97e9ab
--- /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 000000000..4e3d6df61
--- /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 000000000..1da9ce1dc
--- /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 000000000..59fa3a0ec
--- /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 000000000..f8f506202
--- /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 000000000..78e285448
--- /dev/null
+++ b/src/whop_sdk/types/stat_retrieve_params.py
@@ -0,0 +1,154 @@
+# 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 .._types import SequenceNotStr
+from .._utils import PropertyInfo
+
+__all__ = ["StatRetrieveParams"]
+
+
+class StatRetrieveParams(TypedDict, total=False):
+ 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)."""
+
+ access_level: str
+ """Filter to a single access level.
+
+ Pair with breakdown_by=access_level. Available on metrics that list
+ access_level.
+ """
+
+ account_id: str
+ """The account this query concerns, for example biz_AbC123."""
+
+ ad_campaign_ids: SequenceNotStr[str]
+ """
+ Ad campaign ids (adcamp\\__...) to scope the report to; stats are summed across
+ them. Available on metrics that list ad_campaign_ids.
+ """
+
+ ad_group_ids: SequenceNotStr[str]
+ """Ad group ids (adgrp\\__...) to scope the report to; stats are summed across them.
+
+ Available on metrics that list ad_group_ids.
+ """
+
+ ad_ids: SequenceNotStr[str]
+ """Ad ids (ad\\__...) to scope the report to; stats are summed across them.
+
+ Available on metrics that list ad_ids.
+ """
+
+ 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.
+ """
+
+ category: str
+ """Filter to a single balance-activity category, for example payments.
+
+ Pair with breakdown_by=category to split the activity. Available on metrics that
+ list category.
+ """
+
+ 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. For the
+ ads metrics (ad_spend, ad_report), pass the account's ads reporting currency to
+ match the ad entity endpoints. 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.
+ """
+
+ fee_type: str
+ """Filter to a single fee type.
+
+ Pair with breakdown_by=fee_type to split fees by type. Available on metrics that
+ list fee_type.
+ """
+
+ interval: Literal["hour", "day", "week", "month", "year"]
+ """How wide each point is. Defaults to day. Snapshot metrics are day-only."""
+
+ most_recent_action: str
+ """Filter to a single most-recent member action.
+
+ Pair with breakdown_by=most_recent_action. Available on metrics that list
+ most_recent_action.
+ """
+
+ payment_method: str
+ """Filter to a single payment method, for example card or crypto.
+
+ Available on metrics that list payment_method.
+ """
+
+ product: str
+ """Filter to a single product (access pass id), for example prod_AbC123.
+
+ Pair with breakdown_by=product. Available on metrics that list product.
+ """
+
+ referred_user_id: str
+ """
+ Filter a referral metric to the businesses attributed to one person you
+ referred, for example user_AbC123. Available on metrics that list
+ referred_user_id.
+ """
+
+ segment: str
+ """Filter to a single wallet-balance segment, for example available.
+
+ Pair with breakdown_by=segment to split the balance. Available on metrics that
+ list segment.
+ """
+
+ 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.
+ """
+
+ source: str
+ """Filter to a single GMV source, for example payments.
+
+ Pair with breakdown_by=source to split by source. Available on metrics that list
+ source.
+ """
+
+ status: str
+ """Filter to a single membership status.
+
+ Pair with breakdown_by=status. Available on metrics that list status.
+ """
+
+ 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 000000000..d2b849d65
--- /dev/null
+++ b/src/whop_sdk/types/stat_retrieve_response.py
@@ -0,0 +1,41 @@
+# 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."""
+
+ currency: Optional[str] = None
+ """ISO currency the values are denominated in.
+
+ Present for currency-unit metrics: the convert_to currency, or usd.
+ """
+
+
+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 000000000..ec3e05c85
--- /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 9fc72c960..9a1cc323c 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 fa90b64b4..8cff4e8b2 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 000000000..da5979b9a
--- /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 000000000..8a5123a29
--- /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 000000000..ab55ffdd6
--- /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 000000000..91f98537a
--- /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 6b186a3c1..92c4dbb94 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 f1729e588..c9e43000b 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 000000000..669531d82
--- /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 aedb7b413..2f6bd493c 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 7e1530a3d..7f516918b 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 000000000..cd41c697b
--- /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 dde154cca..dc6ad61bd 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 4e52982fd..786864a0c 100644
--- a/src/whop_sdk/types/user.py
+++ b/src/whop_sdk/types/user.py
@@ -1,49 +1,170 @@
# 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
+from .user_balance import UserBalance
-__all__ = ["User", "ProfilePicture"]
+__all__ = [
+ "User",
+ "BalanceHistory",
+ "BalanceHistoryData",
+ "EarningsUsd",
+ "EarningsUsdOwnedAccounts",
+ "EarningsUsdPersonal",
+ "EarningsUsdTotal",
+]
-class ProfilePicture(BaseModel):
- """The user's profile picture attachment with URL, content type, and file metadata.
+class BalanceHistoryData(BaseModel):
+ """Cumulative balance points over the requested window, oldest first."""
- Null if using a legacy profile picture.
+ t: int
+ """Point timestamp, in Unix seconds."""
+
+ v: float
+ """Cumulative wallet balance at this point, in USD."""
+
+
+class BalanceHistory(BaseModel):
+ """
+ The user's cumulative wallet balance over time (USD `{ t, v }` points plus last/min/max), for the balance chart. Opt in with `include_balance_history=true` on `GET /users/me`; populated only for callers with balance-read scope and `null` otherwise. A user with no wallet activity returns an empty series.
"""
- url: Optional[str] = None
- """A pre-optimized URL for rendering this attachment on the client.
+ data: List[BalanceHistoryData]
+
+ last: float
+ """Value of the most recent point, in USD."""
+
+ max: float
+ """Maximum value across the window, in USD."""
+
+ min: float
+ """Minimum value across the window, in USD."""
+
+
+class EarningsUsdOwnedAccounts(BaseModel):
+ """Gross income from accounts the user owns or is owner-authorized on."""
+
+ last_24_hours: str
+ """Gross income in USD over the last 24 hours."""
+
+ last_30_days: str
+ """Gross income in USD over the last 30 days."""
+
+ last_7_days: str
+ """Gross income in USD over the last 7 days."""
+
+ lifetime: str
+ """All-time gross income in USD."""
- This should be used for displaying attachments in apps.
+
+class EarningsUsdPersonal(BaseModel):
+ """Gross income from the user's personal wallet."""
+
+ last_24_hours: str
+ """Gross income in USD over the last 24 hours."""
+
+ last_30_days: str
+ """Gross income in USD over the last 30 days."""
+
+ last_7_days: str
+ """Gross income in USD over the last 7 days."""
+
+ lifetime: str
+ """All-time gross income in USD."""
+
+
+class EarningsUsdTotal(BaseModel):
+ """
+ Gross income from the user's personal wallet plus accounts they own or are owner-authorized on.
"""
+ last_24_hours: str
+ """Gross income in USD over the last 24 hours."""
+
+ last_30_days: str
+ """Gross income in USD over the last 30 days."""
+
+ last_7_days: str
+ """Gross income in USD over the last 7 days."""
+
+ lifetime: str
+ """All-time gross income in USD."""
-class User(BaseModel):
- """A user account on Whop.
- Contains profile information, identity details, and social connections.
+class EarningsUsd(BaseModel):
+ """The user's gross USD income over time.
+
+ Populated only on single-user self reads for callers with balance-read scope; `null` otherwise.
+ """
+
+ first_earned_at: Optional[str] = None
+ """The first time the user earned gross income, as an ISO 8601 timestamp."""
+
+ owned_accounts: EarningsUsdOwnedAccounts
+ """Gross income from accounts the user owns or is owner-authorized on."""
+
+ personal: EarningsUsdPersonal
+ """Gross income from the user's personal wallet."""
+
+ total: EarningsUsdTotal
"""
+ Gross income from the user's personal wallet plus accounts they own or are
+ owner-authorized on.
+ """
+
+class User(BaseModel):
id: str
- """The unique identifier for the user."""
+ """User ID, prefixed `user_`."""
+
+ balance: Optional[UserBalance] = None
+ """
+ The user's balance: personal cash + crypto + in-flight treasury deposits, plus
+ account balances for accounts they own. Computed only on `GET /users/me`
+ self-view for callers with balance-read scope; `null` otherwise.
+ """
+
+ balance_history: Optional[BalanceHistory] = None
+ """
+ The user's cumulative wallet balance over time (USD `{ t, v }` points plus
+ last/min/max), for the balance chart. Opt in with `include_balance_history=true`
+ on `GET /users/me`; populated only for callers with balance-read scope and
+ `null` otherwise. A user with no wallet activity returns an empty series.
+ """
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"""
+
+ earnings_usd: Optional[EarningsUsd] = None
+ """The user's gross USD income over time.
+
+ Populated only on single-user self reads for callers with balance-read scope;
+ `null` otherwise.
+ """
name: Optional[str] = None
- """The user's display name shown on their public profile."""
+ """The user's display name"""
- profile_picture: Optional[ProfilePicture] = None
- """The user's profile picture attachment with URL, content type, and file metadata.
+ profile_picture: Optional[object] = None
+ """The user's profile picture, an object with a url"""
- Null if using a legacy profile picture.
+ username: str
+ """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`.
"""
- username: str
- """The user's unique username shown on their public profile."""
+ whop_partner_enabled_at: Optional[str] = None
+ """When the user became an enrolled Whop Partner, as an ISO 8601 timestamp.
+
+ `null` if never enrolled.
+ """
diff --git a/src/whop_sdk/types/user_balance.py b/src/whop_sdk/types/user_balance.py
new file mode 100644
index 000000000..eb6032238
--- /dev/null
+++ b/src/whop_sdk/types/user_balance.py
@@ -0,0 +1,100 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from .._models import BaseModel
+
+__all__ = ["UserBalance", "Business", "Cash", "Crypto"]
+
+
+class Business(BaseModel):
+ """Account balances for accounts the user owns, highest balance first.
+
+ Excludes accounts with no balance.
+ """
+
+ id: str
+ """The account ID, which looks like biz\\__******\\********."""
+
+ balance_usd: str
+ """The account's total balance in USD."""
+
+ logo_url: Optional[str] = None
+ """The account's logo URL."""
+
+ name: Optional[str] = None
+ """The account's display name."""
+
+
+class Cash(BaseModel):
+ """Per-currency fiat cash balances."""
+
+ balance: float
+ """Available balance in the native currency."""
+
+ balance_usd: float
+ """Available balance converted to USD."""
+
+ currency: str
+ """Lowercase ISO currency code, such as `usd` or `eur`."""
+
+ pending_balance_usd: float
+ """Pending balance converted to USD."""
+
+ reserve_balance_usd: float
+ """Reserved balance converted to USD."""
+
+ total_withdrawable_balance: float
+ """Withdrawable amount in the native currency."""
+
+
+class Crypto(BaseModel):
+ """Per-token crypto holdings in the ledger's own wallet."""
+
+ balance: str
+ """Amount held in native token units, as a decimal string."""
+
+ icon_url: Optional[str] = None
+ """Token icon URL."""
+
+ name: Optional[str] = None
+ """The token's display name."""
+
+ price_usd: Optional[float] = None
+ """USD price per token, or `null` when unknown."""
+
+ symbol: str
+ """Token display symbol, such as `USDT`, `XAUT`, or `cbBTC`."""
+
+ value_usd: float
+ """Holding USD value."""
+
+
+class UserBalance(BaseModel):
+ businesses: List[Business]
+
+ businesses_total_usd: str
+ """Combined USD balance across every account the user owns."""
+
+ cash: List[Cash]
+
+ cash_usd: str
+ """Fiat cash in USD, including pending and reserve."""
+
+ crypto: List[Crypto]
+
+ crypto_usd: str
+ """Crypto holdings in USD."""
+
+ pending_usd: str
+ """Pending funds in USD: fiat pending + in-flight treasury deposits."""
+
+ total_usd: str
+ """
+ The user's personal balance in USD: cash (available + pending + reserve) +
+ crypto + in-flight treasury deposits. Excludes account balances (see
+ businesses_total_usd).
+ """
+
+ treasury_pending_usd: str
+ """Balance-to-wallet USDT0 withdrawals still in flight, in USD."""
diff --git a/src/whop_sdk/types/user_check_access_response.py b/src/whop_sdk/types/user_check_access_response.py
index 270d822ae..ad8fb2fe4 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 bce47d6c1..14d3e4fa3 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 1621e20c2..000000000
--- 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 8534761ba..0e47fe37a 100644
--- a/src/whop_sdk/types/user_retrieve_params.py
+++ b/src/whop_sdk/types/user_retrieve_params.py
@@ -2,15 +2,47 @@
from __future__ import annotations
-from typing import Optional
-from typing_extensions import TypedDict
+from typing_extensions import Literal, Annotated, TypedDict
+
+from .._utils import PropertyInfo
__all__ = ["UserRetrieveParams"]
class UserRetrieveParams(TypedDict, total=False):
- company_id: Optional[str]
+ account_id: str
+ """
+ When set, returns the user's account-specific profile overrides for this
+ account.
+ """
+
+ from_: Annotated[str, PropertyInfo(alias="from")]
+ """Balance-history window start, ISO 8601 date or datetime.
+
+ Defaults to 30 days ago. Only used with `include_balance_history`.
+ """
+
+ include_balance_history: bool
+ """
+ On `GET /users/me`, also compute the caller's balance history (opt-in; runs a
+ heavier query). Ignored for other users and for callers without balance-read
+ scope.
"""
- When provided, returns the user's company-specific profile overrides (name,
- profile picture) instead of their global profile.
+
+ interval: Literal["hour", "day", "week", "month"]
+ """Balance-history point granularity.
+
+ Defaults to `day`. Only used with `include_balance_history`.
+ """
+
+ time_zone: str
+ """IANA time zone the balance-history points are bucketed in.
+
+ Defaults to `UTC`. Only used with `include_balance_history`.
+ """
+
+ to: str
+ """Balance-history window end, ISO 8601 date or datetime.
+
+ Defaults to now. Only used with `include_balance_history`.
"""
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 000000000..63a6a7255
--- /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 a1c8572a8..c957a3c61 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 000000000..3ff4e62ea
--- /dev/null
+++ b/src/whop_sdk/types/verification_create_params.py
@@ -0,0 +1,155 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, Union
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
+
+__all__ = [
+ "VerificationCreateParams",
+ "CreateIndividualVerification",
+ "CreateIndividualVerificationAddress",
+ "CreateBusinessVerification",
+ "CreateBusinessVerificationAddress",
+]
+
+
+class CreateIndividualVerification(TypedDict, total=False):
+ account_id: Required[str]
+ """Account or user ID whose identity you want to verify.
+
+ Use a `biz_` account ID for account verifications, or the caller's `user_` ID
+ for personal verification.
+ """
+
+ address: CreateIndividualVerificationAddress
+
+ business_name: str
+ """Legal business name for a sole proprietor or single-member LLC."""
+
+ business_structure: str
+ """Entity type for sole proprietors, such as `single_member_llc`.
+
+ Supported values vary by country of incorporation — see
+ [Business structures](/developer/verification/business-structures).
+ """
+
+ business_website: str
+ """Business website URL. Whop store pages are not accepted."""
+
+ country: str
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ date_of_birth: str
+ """Formatted as `YYYY-MM-DD`."""
+
+ document_type: Literal["ID_CARD", "PASSPORT", "DRIVERS", "RESIDENCE_PERMIT"]
+ """Identity document being sent.
+
+ Providing it (with `documents`) verifies from uploaded documents instead of a
+ hosted session, and determines the expected `documents` keys: cards and licenses
+ need front and back, passports only the photo page.
+ """
+
+ documents: Dict[str, str]
+ """
+ Identity document files, keyed by slot (`id_card_front`, `id_card_back`,
+ `selfie`, …) with each value the file's raw bytes base64-encoded. Providing them
+ verifies the person from these documents instead of a hosted session —
+ individual verifications only, and the request must also carry `document_type`,
+ `first_name`, `last_name`, `date_of_birth`, `country`, `phone`,
+ `tax_identification_number`, and an `address` with `line1`, `city`, `state`, and
+ `postal_code`. JPEG, PNG, and PDF are accepted (selfies must be images), up to
+ 5MB per file before encoding. Send the complete set — a missing or rejected file
+ fails the whole request and nothing is submitted; review starts automatically
+ once every document is accepted.
+ """
+
+ first_name: str
+
+ kind: Literal["individual"]
+ """Verification type. Defaults to `individual`."""
+
+ last_name: str
+
+ phone: str
+
+ tax_identification_number: str
+ """SSN or ITIN. Tokenized in transit and never stored raw."""
+
+
+class CreateIndividualVerificationAddress(TypedDict, total=False):
+ city: str
+
+ country: str
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ line1: str
+ """First line of the street address."""
+
+ line2: str
+ """Second line of the street address."""
+
+ postal_code: str
+ """Postal or ZIP code."""
+
+ state: str
+ """State, province, or region code, for example `CA`."""
+
+
+class CreateBusinessVerification(TypedDict, total=False):
+ account_id: Required[str]
+ """Account or user ID whose identity you want to verify.
+
+ Use a `biz_` account ID for account verifications, or the caller's `user_` ID
+ for personal verification.
+ """
+
+ address: CreateBusinessVerificationAddress
+
+ business_name: str
+ """Legal business name."""
+
+ business_structure: str
+ """
+ Legal entity structure of the business, such as `private_corporation` or
+ `sole_proprietorship`. Supported values vary by country of incorporation — see
+ [Business structures](/developer/verification/business-structures).
+ """
+
+ business_website: str
+ """Business website URL. Whop store pages are not accepted."""
+
+ country: str
+ """Country of incorporation as a two-letter ISO 3166-1 country code."""
+
+ kind: Literal["business"]
+ """Must be `business` to start a KYB verification."""
+
+ place_of_incorporation: str
+ """State or region where the business is incorporated."""
+
+ tax_identification_number: str
+ """EIN. Tokenized in transit and never stored raw."""
+
+
+class CreateBusinessVerificationAddress(TypedDict, total=False):
+ city: str
+
+ country: str
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ line1: str
+ """First line of the street address."""
+
+ line2: str
+ """Second line of the street address."""
+
+ postal_code: str
+ """Postal or ZIP code."""
+
+ state: str
+ """State, province, or region code, for example `CA`."""
+
+
+VerificationCreateParams: TypeAlias = Union[CreateIndividualVerification, CreateBusinessVerification]
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 000000000..88fee99d8
--- /dev/null
+++ b/src/whop_sdk/types/verification_create_response.py
@@ -0,0 +1,184 @@
+# 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",
+ "Address",
+ "RequestedInformation",
+ "RequestedInformationRequestedFile",
+ "RequiredDocument",
+]
+
+
+class Address(BaseModel):
+ """Address on the verification profile. `null` when no address is set."""
+
+ city: Optional[str] = None
+
+ country: Optional[str] = None
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ line1: Optional[str] = None
+ """First line of the street address."""
+
+ line2: Optional[str] = None
+ """Second line of the street address."""
+
+ postal_code: Optional[str] = None
+ """Postal or ZIP code."""
+
+ state: Optional[str] = None
+ """State, province, or region code, for example `CA`."""
+
+
+class RequestedInformationRequestedFile(BaseModel):
+ category: Optional[str] = None
+ """
+ File category to include with the uploaded file so Whop can route the document
+ correctly. `null` for a generic upload.
+ """
+
+ is_optional: Optional[bool] = None
+ """Whether this slot can be left empty."""
+
+ kind: Optional[str] = None
+ """Specific document type requested, such as `Bank Statement`.
+
+ `null` for standard identity and business document uploads.
+ """
+
+ label: Optional[str] = None
+ """Label for this upload slot, such as `Front of ID Document`."""
+
+ multiple: Optional[bool] = None
+ """Whether this slot accepts more than one file."""
+
+
+class RequestedInformation(BaseModel):
+ id: Optional[str] = None
+ """Requested information item ID, prefixed `inrqi_`.
+
+ Include this ID when submitting an answer.
+ """
+
+ description: Optional[str] = None
+ """Additional instructions for this requested item, or `null`."""
+
+ error_message: Optional[str] = None
+ """Reason a previously submitted value was rejected.
+
+ `null` if no submitted value has been rejected.
+ """
+
+ field: Optional[str] = None
+ """Stable field key, such as `ssn` or `business_description`."""
+
+ label: Optional[str] = None
+ """Human-readable label for the field, such as `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
+ """Document upload slots for this item.
+
+ Present when `type` is `files`; upload one file for each required slot and
+ include the slot's `category` when submitting the answer.
+ """
+
+ type: Optional[str] = None
+ """
+ Input type expected for this item: `text`, `date`, `phone`, `address`, `files`,
+ or `select`.
+ """
+
+
+class RequiredDocument(BaseModel):
+ document: Optional[str] = None
+ """Document slot key, such as `id_card_front`, `id_card_back`, or `selfie`."""
+
+ rejection_reason: Optional[str] = None
+ """
+ Why the previous submission was rejected, when the provider requested new
+ documents or declined the verification.
+ """
+
+ status: Optional[Literal["pending_upload", "submitted"]] = None
+ """
+ `pending_upload` until the document has been relayed for review; `submitted`
+ afterwards.
+ """
+
+
+class VerificationCreateResponse(BaseModel):
+ id: Optional[str] = None
+ """Verification profile ID, prefixed `idpf_`."""
+
+ address: Optional[Address] = None
+ """Address on the verification profile. `null` when no address is set."""
+
+ business_name: Optional[str] = None
+ """Legal business name."""
+
+ business_structure: Optional[str] = None
+ """
+ Legal entity structure of the business, such as `private_corporation` or
+ `sole_proprietorship`. Supported values vary by country of incorporation — see
+ [Business structures](/developer/verification/business-structures).
+ """
+
+ country: Optional[str] = None
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ created_at: Optional[str] = None
+ """When the verification profile was created, as an ISO 8601 timestamp."""
+
+ date_of_birth: Optional[str] = None
+ """Formatted as `YYYY-MM-DD`."""
+
+ first_name: Optional[str] = None
+
+ kind: Optional[Literal["individual", "business"]] = None
+
+ last_name: Optional[str] = None
+
+ requested_information: Optional[List[RequestedInformation]] = None
+ """Fields or documents Whop still needs before review can continue.
+
+ Submit answers with the Update Verification endpoint.
+ """
+
+ required_documents: Optional[List[RequiredDocument]] = None
+ """Documents for a document-upload verification and their progress.
+
+ Present only on verifications created by sending `documents`. `pending_upload`
+ documents were not accepted yet — send the full set again with another Create
+ Verification call.
+ """
+
+ session_url: Optional[str] = None
+ """Hosted verification session URL for the user to complete identity checks.
+
+ Expires 7 days after creation.
+ """
+
+ status: Optional[Literal["not_started", "pending", "approved", "rejected", "action_required"]] = None
+ """Current verification state.
+
+ `not_started` before any session has been created; `pending` while a session is
+ in progress; `action_required` when items in `requested_information` need
+ answers before review can continue; `approved` once verification succeeds;
+ `rejected` if it fails. Call the Create Verification endpoint again to start a
+ new session.
+ """
+
+ updated_at: Optional[str] = None
+ """When the verification profile was last updated, as an ISO 8601 timestamp."""
diff --git a/src/whop_sdk/types/verification_list_params.py b/src/whop_sdk/types/verification_list_params.py
index 64ad9314c..bbbe1258f 100644
--- a/src/whop_sdk/types/verification_list_params.py
+++ b/src/whop_sdk/types/verification_list_params.py
@@ -2,24 +2,20 @@
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]
+ """Account or user ID whose verifications you want to list.
- after: Optional[str]
- """Returns the elements in the list that come after the specified cursor."""
+ Use a `biz_` account ID, or the caller's `user_` ID for personal verifications.
+ """
- before: Optional[str]
- """Returns the elements in the list that come before the specified cursor."""
+ direction: Literal["asc", "desc"]
+ """Sort direction for returned verifications."""
- 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"]
+ """Field used to sort returned verifications."""
diff --git a/src/whop_sdk/types/verification_list_response.py b/src/whop_sdk/types/verification_list_response.py
index 25d3f1e6d..a4bd15b2a 100644
--- a/src/whop_sdk/types/verification_list_response.py
+++ b/src/whop_sdk/types/verification_list_response.py
@@ -1,30 +1,189 @@
# 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",
+ "DataAddress",
+ "DataRequestedInformation",
+ "DataRequestedInformationRequestedFile",
+ "DataRequiredDocument",
+]
-class VerificationListResponse(BaseModel):
+class DataAddress(BaseModel):
+ """Address on the verification profile. `null` when no address is set."""
+
+ city: Optional[str] = None
+
+ country: Optional[str] = None
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ line1: Optional[str] = None
+ """First line of the street address."""
+
+ line2: Optional[str] = None
+ """Second line of the street address."""
+
+ postal_code: Optional[str] = None
+ """Postal or ZIP code."""
+
+ state: Optional[str] = None
+ """State, province, or region code, for example `CA`."""
+
+
+class DataRequestedInformationRequestedFile(BaseModel):
+ category: Optional[str] = None
"""
- An identity verification session used to confirm a person or entity's identity for payout account eligibility.
+ File category to include with the uploaded file so Whop can route the document
+ correctly. `null` for a generic upload.
"""
- id: str
- """The numeric id of the verification record."""
+ is_optional: Optional[bool] = None
+ """Whether this slot can be left empty."""
- last_error_code: Optional[VerificationErrorCode] = None
- """An error code for a verification attempt."""
+ kind: Optional[str] = None
+ """Specific document type requested, such as `Bank Statement`.
+
+ `null` for standard identity and business document uploads.
+ """
+
+ label: Optional[str] = None
+ """Label for this upload slot, such as `Front of ID Document`."""
+
+ multiple: Optional[bool] = None
+ """Whether this slot accepts more than one file."""
- last_error_reason: Optional[str] = None
- """A human-readable explanation of the most recent verification error.
- Null if no error has occurred.
+class DataRequestedInformation(BaseModel):
+ id: Optional[str] = None
+ """Requested information item ID, prefixed `inrqi_`.
+
+ Include this ID when submitting an answer.
"""
- status: VerificationStatus
- """The current status of this verification session."""
+ description: Optional[str] = None
+ """Additional instructions for this requested item, or `null`."""
+
+ error_message: Optional[str] = None
+ """Reason a previously submitted value was rejected.
+
+ `null` if no submitted value has been rejected.
+ """
+
+ field: Optional[str] = None
+ """Stable field key, such as `ssn` or `business_description`."""
+
+ label: Optional[str] = None
+ """Human-readable label for the field, such as `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
+ """Document upload slots for this item.
+
+ Present when `type` is `files`; upload one file for each required slot and
+ include the slot's `category` when submitting the answer.
+ """
+
+ type: Optional[str] = None
+ """
+ Input type expected for this item: `text`, `date`, `phone`, `address`, `files`,
+ or `select`.
+ """
+
+
+class DataRequiredDocument(BaseModel):
+ document: Optional[str] = None
+ """Document slot key, such as `id_card_front`, `id_card_back`, or `selfie`."""
+
+ rejection_reason: Optional[str] = None
+ """
+ Why the previous submission was rejected, when the provider requested new
+ documents or declined the verification.
+ """
+
+ status: Optional[Literal["pending_upload", "submitted"]] = None
+ """
+ `pending_upload` until the document has been relayed for review; `submitted`
+ afterwards.
+ """
+
+
+class Data(BaseModel):
+ id: Optional[str] = None
+ """Verification profile ID, prefixed `idpf_`."""
+
+ address: Optional[DataAddress] = None
+ """Address on the verification profile. `null` when no address is set."""
+
+ business_name: Optional[str] = None
+ """Legal business name."""
+
+ business_structure: Optional[str] = None
+ """
+ Legal entity structure of the business, such as `private_corporation` or
+ `sole_proprietorship`. Supported values vary by country of incorporation — see
+ [Business structures](/developer/verification/business-structures).
+ """
+
+ country: Optional[str] = None
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ created_at: Optional[str] = None
+ """When the verification profile was created, as an ISO 8601 timestamp."""
+
+ date_of_birth: Optional[str] = None
+ """Formatted as `YYYY-MM-DD`."""
+
+ first_name: Optional[str] = None
+
+ kind: Optional[Literal["individual", "business"]] = None
+
+ last_name: Optional[str] = None
+
+ requested_information: Optional[List[DataRequestedInformation]] = None
+ """Fields or documents Whop still needs before review can continue.
+
+ Submit answers with the Update Verification endpoint.
+ """
+
+ required_documents: Optional[List[DataRequiredDocument]] = None
+ """Documents for a document-upload verification and their progress.
+
+ Present only on verifications created by sending `documents`. `pending_upload`
+ documents were not accepted yet — send the full set again with another Create
+ Verification call.
+ """
+
+ session_url: Optional[str] = None
+ """Hosted verification session URL for the user to complete identity checks.
+
+ Expires 7 days after creation.
+ """
+
+ status: Optional[Literal["not_started", "pending", "approved", "rejected", "action_required"]] = None
+ """Current verification state.
+
+ `not_started` before any session has been created; `pending` while a session is
+ in progress; `action_required` when items in `requested_information` need
+ answers before review can continue; `approved` once verification succeeds;
+ `rejected` if it fails. Call the Create Verification endpoint again to start a
+ new session.
+ """
+
+ updated_at: Optional[str] = None
+ """When the verification profile was last updated, as an ISO 8601 timestamp."""
+
+
+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 9228eef9c..34a17388a 100644
--- a/src/whop_sdk/types/verification_retrieve_response.py
+++ b/src/whop_sdk/types/verification_retrieve_response.py
@@ -1,30 +1,184 @@
# 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",
+ "Address",
+ "RequestedInformation",
+ "RequestedInformationRequestedFile",
+ "RequiredDocument",
+]
+
+
+class Address(BaseModel):
+ """Address on the verification profile. `null` when no address is set."""
+
+ city: Optional[str] = None
+
+ country: Optional[str] = None
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ line1: Optional[str] = None
+ """First line of the street address."""
+
+ line2: Optional[str] = None
+ """Second line of the street address."""
+
+ postal_code: Optional[str] = None
+ """Postal or ZIP code."""
+
+ state: Optional[str] = None
+ """State, province, or region code, for example `CA`."""
+
+
+class RequestedInformationRequestedFile(BaseModel):
+ category: Optional[str] = None
+ """
+ File category to include with the uploaded file so Whop can route the document
+ correctly. `null` for a generic upload.
+ """
+
+ is_optional: Optional[bool] = None
+ """Whether this slot can be left empty."""
+
+ kind: Optional[str] = None
+ """Specific document type requested, such as `Bank Statement`.
+
+ `null` for standard identity and business document uploads.
+ """
+
+ label: Optional[str] = None
+ """Label for this upload slot, such as `Front of ID Document`."""
+
+ multiple: Optional[bool] = None
+ """Whether this slot accepts more than one file."""
+
+
+class RequestedInformation(BaseModel):
+ id: Optional[str] = None
+ """Requested information item ID, prefixed `inrqi_`.
+
+ Include this ID when submitting an answer.
+ """
+
+ description: Optional[str] = None
+ """Additional instructions for this requested item, or `null`."""
+
+ error_message: Optional[str] = None
+ """Reason a previously submitted value was rejected.
+
+ `null` if no submitted value has been rejected.
+ """
+
+ field: Optional[str] = None
+ """Stable field key, such as `ssn` or `business_description`."""
+
+ label: Optional[str] = None
+ """Human-readable label for the field, such as `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
+ """Document upload slots for this item.
+
+ Present when `type` is `files`; upload one file for each required slot and
+ include the slot's `category` when submitting the answer.
+ """
+
+ type: Optional[str] = None
+ """
+ Input type expected for this item: `text`, `date`, `phone`, `address`, `files`,
+ or `select`.
+ """
+
+
+class RequiredDocument(BaseModel):
+ document: Optional[str] = None
+ """Document slot key, such as `id_card_front`, `id_card_back`, or `selfie`."""
+
+ rejection_reason: Optional[str] = None
+ """
+ Why the previous submission was rejected, when the provider requested new
+ documents or declined the verification.
+ """
+
+ status: Optional[Literal["pending_upload", "submitted"]] = None
+ """
+ `pending_upload` until the document has been relayed for review; `submitted`
+ afterwards.
+ """
class VerificationRetrieveResponse(BaseModel):
+ id: Optional[str] = None
+ """Verification profile ID, prefixed `idpf_`."""
+
+ address: Optional[Address] = None
+ """Address on the verification profile. `null` when no address is set."""
+
+ business_name: Optional[str] = None
+ """Legal business name."""
+
+ business_structure: Optional[str] = None
"""
- An identity verification session used to confirm a person or entity's identity for payout account eligibility.
+ Legal entity structure of the business, such as `private_corporation` or
+ `sole_proprietorship`. Supported values vary by country of incorporation — see
+ [Business structures](/developer/verification/business-structures).
"""
- id: str
- """The numeric id of the verification record."""
+ country: Optional[str] = None
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ created_at: Optional[str] = None
+ """When the verification profile was created, as an ISO 8601 timestamp."""
+
+ date_of_birth: Optional[str] = None
+ """Formatted as `YYYY-MM-DD`."""
+
+ first_name: Optional[str] = None
+
+ kind: Optional[Literal["individual", "business"]] = None
+
+ last_name: Optional[str] = None
+
+ requested_information: Optional[List[RequestedInformation]] = None
+ """Fields or documents Whop still needs before review can continue.
- last_error_code: Optional[VerificationErrorCode] = None
- """An error code for a verification attempt."""
+ Submit answers with the Update Verification endpoint.
+ """
+
+ required_documents: Optional[List[RequiredDocument]] = None
+ """Documents for a document-upload verification and their progress.
+
+ Present only on verifications created by sending `documents`. `pending_upload`
+ documents were not accepted yet — send the full set again with another Create
+ Verification call.
+ """
+
+ session_url: Optional[str] = None
+ """Hosted verification session URL for the user to complete identity checks.
+
+ Expires 7 days after creation.
+ """
- last_error_reason: Optional[str] = None
- """A human-readable explanation of the most recent verification error.
+ status: Optional[Literal["not_started", "pending", "approved", "rejected", "action_required"]] = None
+ """Current verification state.
- Null if no error has occurred.
+ `not_started` before any session has been created; `pending` while a session is
+ in progress; `action_required` when items in `requested_information` need
+ answers before review can continue; `approved` once verification succeeds;
+ `rejected` if it fails. Call the Create Verification endpoint again to start a
+ new session.
"""
- status: VerificationStatus
- """The current status of this verification session."""
+ updated_at: Optional[str] = None
+ """When the verification profile was last updated, as an ISO 8601 timestamp."""
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 000000000..dbf59bf8e
--- /dev/null
+++ b/src/whop_sdk/types/verification_update_params.py
@@ -0,0 +1,226 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Iterable
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
+
+__all__ = [
+ "VerificationUpdateParams",
+ "UpdateIndividualVerification",
+ "UpdateIndividualVerificationPersonalAddress",
+ "UpdateIndividualVerificationRequestedInformation",
+ "UpdateIndividualVerificationRequestedInformationAddress",
+ "UpdateIndividualVerificationRequestedInformationFile",
+ "UpdateBusinessVerification",
+ "UpdateBusinessVerificationBusinessAddress",
+ "UpdateBusinessVerificationRequestedInformation",
+ "UpdateBusinessVerificationRequestedInformationAddress",
+ "UpdateBusinessVerificationRequestedInformationFile",
+]
+
+
+class UpdateIndividualVerification(TypedDict, total=False):
+ country: str
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ date_of_birth: str
+ """Formatted as `YYYY-MM-DD`."""
+
+ first_name: str
+
+ last_name: str
+
+ personal_address: UpdateIndividualVerificationPersonalAddress
+ """Personal address for the individual."""
+
+ requested_information: Iterable[UpdateIndividualVerificationRequestedInformation]
+ """Answers to items returned in `requested_information`.
+
+ Each entry must include the requested item `id` and exactly one answer payload
+ matching the item's `type`: `value` for `text`, `date`, or `phone`; `address`
+ for `address`; `files` for `files`.
+ """
+
+
+class UpdateIndividualVerificationPersonalAddress(TypedDict, total=False):
+ """Personal address for the individual."""
+
+ city: str
+
+ country: str
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ line1: str
+ """First line of the street address."""
+
+ line2: str
+ """Second line of the street address."""
+
+ postal_code: str
+ """Postal or ZIP code."""
+
+ state: str
+ """State, province, or region code, for example `CA`."""
+
+
+class UpdateIndividualVerificationRequestedInformationAddress(TypedDict, total=False):
+ """Address payload for `address` items."""
+
+ city: str
+
+ country: str
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ line1: str
+ """First line of the street address."""
+
+ line2: str
+ """Second line of the street address."""
+
+ postal_code: str
+ """Postal or ZIP code."""
+
+ state: str
+ """State, province, or region code, for example `CA`."""
+
+
+class UpdateIndividualVerificationRequestedInformationFile(TypedDict, total=False):
+ attachment_id: str
+ """Existing attachment ID, when reusing an already attached document."""
+
+ category: str
+ """Requested file category copied from `requested_files.category`."""
+
+ direct_upload_id: str
+ """Direct upload ID for the uploaded document."""
+
+ kind: str
+ """Requested document kind copied from `requested_files.kind`."""
+
+
+class UpdateIndividualVerificationRequestedInformation(TypedDict, total=False):
+ id: Required[str]
+ """Requested information item ID, prefixed `inrqi_`."""
+
+ address: UpdateIndividualVerificationRequestedInformationAddress
+ """Address payload for `address` items."""
+
+ files: Iterable[UpdateIndividualVerificationRequestedInformationFile]
+ """Uploaded file payloads for `files` items.
+
+ Each file should include a `direct_upload_id` from the upload flow, plus the
+ requested file `category` and `kind` when provided.
+ """
+
+ value: str
+ """Answer value for `text`, `date`, or `phone` items."""
+
+ value_type: Literal["raw", "vault_token"]
+ """Whether `value` is raw input or a vault token."""
+
+
+class UpdateBusinessVerification(TypedDict, total=False):
+ business_address: UpdateBusinessVerificationBusinessAddress
+ """Business address."""
+
+ business_name: str
+ """Legal business name."""
+
+ business_structure: str
+ """
+ Legal entity structure of the business, such as `private_corporation` or
+ `sole_proprietorship`. Supported values vary by country of incorporation — see
+ [Business structures](/developer/verification/business-structures).
+ """
+
+ country: str
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ requested_information: Iterable[UpdateBusinessVerificationRequestedInformation]
+ """Answers to items returned in `requested_information`.
+
+ Each entry must include the requested item `id` and exactly one answer payload
+ matching the item's `type`: `value` for `text`, `date`, or `phone`; `address`
+ for `address`; `files` for `files`.
+ """
+
+
+class UpdateBusinessVerificationBusinessAddress(TypedDict, total=False):
+ """Business address."""
+
+ city: str
+
+ country: str
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ line1: str
+ """First line of the street address."""
+
+ line2: str
+ """Second line of the street address."""
+
+ postal_code: str
+ """Postal or ZIP code."""
+
+ state: str
+ """State, province, or region code, for example `CA`."""
+
+
+class UpdateBusinessVerificationRequestedInformationAddress(TypedDict, total=False):
+ """Address payload for `address` items."""
+
+ city: str
+
+ country: str
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ line1: str
+ """First line of the street address."""
+
+ line2: str
+ """Second line of the street address."""
+
+ postal_code: str
+ """Postal or ZIP code."""
+
+ state: str
+ """State, province, or region code, for example `CA`."""
+
+
+class UpdateBusinessVerificationRequestedInformationFile(TypedDict, total=False):
+ attachment_id: str
+ """Existing attachment ID, when reusing an already attached document."""
+
+ category: str
+ """Requested file category copied from `requested_files.category`."""
+
+ direct_upload_id: str
+ """Direct upload ID for the uploaded document."""
+
+ kind: str
+ """Requested document kind copied from `requested_files.kind`."""
+
+
+class UpdateBusinessVerificationRequestedInformation(TypedDict, total=False):
+ id: Required[str]
+ """Requested information item ID, prefixed `inrqi_`."""
+
+ address: UpdateBusinessVerificationRequestedInformationAddress
+ """Address payload for `address` items."""
+
+ files: Iterable[UpdateBusinessVerificationRequestedInformationFile]
+ """Uploaded file payloads for `files` items.
+
+ Each file should include a `direct_upload_id` from the upload flow, plus the
+ requested file `category` and `kind` when provided.
+ """
+
+ value: str
+ """Answer value for `text`, `date`, or `phone` items."""
+
+ value_type: Literal["raw", "vault_token"]
+ """Whether `value` is raw input or a vault token."""
+
+
+VerificationUpdateParams: TypeAlias = Union[UpdateIndividualVerification, UpdateBusinessVerification]
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 000000000..f8c92a533
--- /dev/null
+++ b/src/whop_sdk/types/verification_update_response.py
@@ -0,0 +1,184 @@
+# 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",
+ "Address",
+ "RequestedInformation",
+ "RequestedInformationRequestedFile",
+ "RequiredDocument",
+]
+
+
+class Address(BaseModel):
+ """Address on the verification profile. `null` when no address is set."""
+
+ city: Optional[str] = None
+
+ country: Optional[str] = None
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ line1: Optional[str] = None
+ """First line of the street address."""
+
+ line2: Optional[str] = None
+ """Second line of the street address."""
+
+ postal_code: Optional[str] = None
+ """Postal or ZIP code."""
+
+ state: Optional[str] = None
+ """State, province, or region code, for example `CA`."""
+
+
+class RequestedInformationRequestedFile(BaseModel):
+ category: Optional[str] = None
+ """
+ File category to include with the uploaded file so Whop can route the document
+ correctly. `null` for a generic upload.
+ """
+
+ is_optional: Optional[bool] = None
+ """Whether this slot can be left empty."""
+
+ kind: Optional[str] = None
+ """Specific document type requested, such as `Bank Statement`.
+
+ `null` for standard identity and business document uploads.
+ """
+
+ label: Optional[str] = None
+ """Label for this upload slot, such as `Front of ID Document`."""
+
+ multiple: Optional[bool] = None
+ """Whether this slot accepts more than one file."""
+
+
+class RequestedInformation(BaseModel):
+ id: Optional[str] = None
+ """Requested information item ID, prefixed `inrqi_`.
+
+ Include this ID when submitting an answer.
+ """
+
+ description: Optional[str] = None
+ """Additional instructions for this requested item, or `null`."""
+
+ error_message: Optional[str] = None
+ """Reason a previously submitted value was rejected.
+
+ `null` if no submitted value has been rejected.
+ """
+
+ field: Optional[str] = None
+ """Stable field key, such as `ssn` or `business_description`."""
+
+ label: Optional[str] = None
+ """Human-readable label for the field, such as `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
+ """Document upload slots for this item.
+
+ Present when `type` is `files`; upload one file for each required slot and
+ include the slot's `category` when submitting the answer.
+ """
+
+ type: Optional[str] = None
+ """
+ Input type expected for this item: `text`, `date`, `phone`, `address`, `files`,
+ or `select`.
+ """
+
+
+class RequiredDocument(BaseModel):
+ document: Optional[str] = None
+ """Document slot key, such as `id_card_front`, `id_card_back`, or `selfie`."""
+
+ rejection_reason: Optional[str] = None
+ """
+ Why the previous submission was rejected, when the provider requested new
+ documents or declined the verification.
+ """
+
+ status: Optional[Literal["pending_upload", "submitted"]] = None
+ """
+ `pending_upload` until the document has been relayed for review; `submitted`
+ afterwards.
+ """
+
+
+class VerificationUpdateResponse(BaseModel):
+ id: Optional[str] = None
+ """Verification profile ID, prefixed `idpf_`."""
+
+ address: Optional[Address] = None
+ """Address on the verification profile. `null` when no address is set."""
+
+ business_name: Optional[str] = None
+ """Legal business name."""
+
+ business_structure: Optional[str] = None
+ """
+ Legal entity structure of the business, such as `private_corporation` or
+ `sole_proprietorship`. Supported values vary by country of incorporation — see
+ [Business structures](/developer/verification/business-structures).
+ """
+
+ country: Optional[str] = None
+ """Two-letter ISO 3166-1 country code, for example `US`, `DE`, or `GB`."""
+
+ created_at: Optional[str] = None
+ """When the verification profile was created, as an ISO 8601 timestamp."""
+
+ date_of_birth: Optional[str] = None
+ """Formatted as `YYYY-MM-DD`."""
+
+ first_name: Optional[str] = None
+
+ kind: Optional[Literal["individual", "business"]] = None
+
+ last_name: Optional[str] = None
+
+ requested_information: Optional[List[RequestedInformation]] = None
+ """Fields or documents Whop still needs before review can continue.
+
+ Submit answers with the Update Verification endpoint.
+ """
+
+ required_documents: Optional[List[RequiredDocument]] = None
+ """Documents for a document-upload verification and their progress.
+
+ Present only on verifications created by sending `documents`. `pending_upload`
+ documents were not accepted yet — send the full set again with another Create
+ Verification call.
+ """
+
+ session_url: Optional[str] = None
+ """Hosted verification session URL for the user to complete identity checks.
+
+ Expires 7 days after creation.
+ """
+
+ status: Optional[Literal["not_started", "pending", "approved", "rejected", "action_required"]] = None
+ """Current verification state.
+
+ `not_started` before any session has been created; `pending` while a session is
+ in progress; `action_required` when items in `requested_information` need
+ answers before review can continue; `approved` once verification succeeds;
+ `rejected` if it fails. Call the Create Verification endpoint again to start a
+ new session.
+ """
+
+ updated_at: Optional[str] = None
+ """When the verification profile was last updated, as an ISO 8601 timestamp."""
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 c88cc393c..000000000
--- 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 2527d8699..000000000
--- 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 03889c279..000000000
--- 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 5db26b85c..000000000
--- 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 3b76647a0..7167e81ad 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.py b/src/whop_sdk/types/withdrawal.py
index 38e90dcae..bc3c3c95d 100644
--- a/src/whop_sdk/types/withdrawal.py
+++ b/src/whop_sdk/types/withdrawal.py
@@ -117,6 +117,7 @@ class Withdrawal(BaseModel):
"missing_phone_number",
"missing_remittance_info",
"payee_name_invalid",
+ "beneficiary_name_mismatch",
"receiving_account_locked",
"rejected_by_compliance",
"rtp_not_supported",
diff --git a/src/whop_sdk/types/withdrawal_create_params.py b/src/whop_sdk/types/withdrawal_create_params.py
index 46d134f2b..3345ababf 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/src/whop_sdk/types/workforce/__init__.py b/src/whop_sdk/types/workforce/__init__.py
new file mode 100644
index 000000000..278888380
--- /dev/null
+++ b/src/whop_sdk/types/workforce/__init__.py
@@ -0,0 +1,7 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .workforce_bounty import WorkforceBounty as WorkforceBounty
+from .bounty_list_params import BountyListParams as BountyListParams
+from .workforce_bounty_list_item import WorkforceBountyListItem as WorkforceBountyListItem
diff --git a/src/whop_sdk/types/workforce/bounty_list_params.py b/src/whop_sdk/types/workforce/bounty_list_params.py
new file mode 100644
index 000000000..43fc3015b
--- /dev/null
+++ b/src/whop_sdk/types/workforce/bounty_list_params.py
@@ -0,0 +1,52 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypedDict
+
+__all__ = ["BountyListParams"]
+
+
+class BountyListParams(TypedDict, total=False):
+ account_id: str
+ """Scope the list to this account (`biz_` tag).
+
+ Requires read access to the account; account API keys may pass their own account
+ or a connected account.
+ """
+
+ after: str
+ """Cursor to paginate forwards from."""
+
+ before: str
+ """Cursor to paginate backwards from."""
+
+ created_after: str
+ """Only bounties created after this ISO 8601 timestamp."""
+
+ created_before: str
+ """Only bounties created before this ISO 8601 timestamp."""
+
+ direction: Literal["asc", "desc"]
+ """Sort direction."""
+
+ first: int
+ """Number of bounties to return from the start of the window."""
+
+ last: int
+ """Number of bounties to return from the end of the window."""
+
+ order: Literal["created_at", "gross_paid_out_amount"]
+ """Sort field."""
+
+ query: str
+ """Substring match on the bounty title or ID."""
+
+ status: Literal["scheduled", "open", "closed", "completed", "canceled"]
+ """Filter by lifecycle state."""
+
+ user_id: str
+ """List the bounties this user participated in (`user_` tag).
+
+ Must be the authenticated user.
+ """
diff --git a/src/whop_sdk/types/workforce/workforce_bounty.py b/src/whop_sdk/types/workforce/workforce_bounty.py
new file mode 100644
index 000000000..0293c1225
--- /dev/null
+++ b/src/whop_sdk/types/workforce/workforce_bounty.py
@@ -0,0 +1,159 @@
+# 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__ = ["WorkforceBounty", "FundingAccount", "Poster", "PosterProfilePicture"]
+
+
+class FundingAccount(BaseModel):
+ """
+ The account whose balance funds the bounty pool, or `null` when a user funds it personally. May differ from the account hosting `experience_id`.
+ """
+
+ id: str
+ """Account ID, prefixed `biz_`."""
+
+ title: str
+ """Account display name."""
+
+
+class PosterProfilePicture(BaseModel):
+ """
+ Avatar wrapper; its `url` is always present, using a generated placeholder when the user set no picture.
+ """
+
+ url: str
+ """Avatar image URL.
+
+ Always present — a generated placeholder when the user set no picture.
+ """
+
+
+class Poster(BaseModel):
+ """The user who posted the bounty."""
+
+ id: str
+ """User ID, prefixed `user_`."""
+
+ name: Optional[str] = None
+ """Display name."""
+
+ profile_picture: PosterProfilePicture
+ """
+ Avatar wrapper; its `url` is always present, using a generated placeholder when
+ the user set no picture.
+ """
+
+ username: str
+ """Public username."""
+
+
+class WorkforceBounty(BaseModel):
+ id: str
+ """Bounty ID, prefixed `bnty_`."""
+
+ accepted_submissions_count: int
+ """Submissions accepted so far."""
+
+ accepted_submissions_limit: int
+ """Number of submissions that can be accepted (winner slots)."""
+
+ allowed_country_codes: List[str]
+
+ budget_amount: float
+ """
+ Total gross budget committed to the bounty: `gross_reward_amount` times
+ `accepted_submissions_limit`.
+ """
+
+ business_goal_type: Optional[
+ Literal["clipping", "post_engagement", "owned_account_growth", "ugc_content", "local_activation", "other"]
+ ] = None
+ """What the poster wants the work to achieve."""
+
+ created_at: str
+ """When the bounty was created, as an ISO 8601 timestamp."""
+
+ currency: str
+ """Currency for all amounts on the bounty, as a lowercase ISO 4217 code."""
+
+ description: str
+ """Full task instructions shown to workers."""
+
+ experience_id: Optional[str] = None
+ """Experience the bounty is hosted in, prefixed `exp_`.
+
+ Null for platform-wide bounties; may belong to a different account than the
+ funder.
+ """
+
+ funding_account: Optional[FundingAccount] = None
+ """
+ The account whose balance funds the bounty pool, or `null` when a user funds it
+ personally. May differ from the account hosting `experience_id`.
+ """
+
+ gross_paid_out_amount: float
+ """
+ Gross amount paid out from the bounty pool across accepted submissions — worker
+ payouts, platform fees, and affiliate shares together. Tips and reviewer rewards
+ are excluded.
+ """
+
+ gross_reward_amount: float
+ """
+ Gross bounty-pool amount allocated per accepted submission, in whole currency
+ units.
+ """
+
+ poster: Poster
+ """The user who posted the bounty."""
+
+ scheduled_frequency: Optional[Literal["once", "hourly", "daily", "weekly", "monthly"]] = None
+ """How often the schedule creates a new bounty.
+
+ Each occurrence is a separate bounty; the original is not republished.
+ """
+
+ scheduled_publish_at: Optional[str] = None
+ """When a scheduled bounty will publish, as an ISO 8601 timestamp.
+
+ Null once published, for bounties that were never scheduled, and for terminally
+ failed drafts parked for manual rescheduling.
+ """
+
+ spots_remaining: int
+ """
+ Unfilled winner capacity: `accepted_submissions_limit` minus
+ `accepted_submissions_count`, clamped to zero. Not a signal that the bounty
+ currently accepts new claims.
+ """
+
+ status: Literal["scheduled", "open", "closed", "completed", "canceled"]
+ """Lifecycle state.
+
+ `scheduled` bounties are unpublished drafts, visible to their poster and the
+ account's authorized managers; `open` bounties accept new submissions; `closed`
+ bounties are live but no longer accept new submissions; `completed` bounties
+ paid out every winner slot; `canceled` bounties ended before filling their
+ slots.
+ """
+
+ submissions_closed_at: Optional[str] = None
+ """When new submissions were explicitly stopped, as an ISO 8601 timestamp.
+
+ Null when submissions were never explicitly stopped — including closed or
+ completed bounties that simply filled every winner slot.
+ """
+
+ title: str
+ """Short name of the task shown to workers."""
+
+ unresolved_submissions_count: int
+ """Submissions still awaiting an outcome: in progress or pending review."""
+
+ updated_at: str
+ """When the bounty was last updated, as an ISO 8601 timestamp."""
diff --git a/src/whop_sdk/types/workforce/workforce_bounty_list_item.py b/src/whop_sdk/types/workforce/workforce_bounty_list_item.py
new file mode 100644
index 000000000..29ee656d4
--- /dev/null
+++ b/src/whop_sdk/types/workforce/workforce_bounty_list_item.py
@@ -0,0 +1,156 @@
+# 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__ = ["WorkforceBountyListItem", "FundingAccount", "Poster", "PosterProfilePicture"]
+
+
+class FundingAccount(BaseModel):
+ """
+ The account whose balance funds the bounty pool, or `null` when a user funds it personally. May differ from the account hosting `experience_id`.
+ """
+
+ id: str
+ """Account ID, prefixed `biz_`."""
+
+ title: str
+ """Account display name."""
+
+
+class PosterProfilePicture(BaseModel):
+ """
+ Avatar wrapper; its `url` is always present, using a generated placeholder when the user set no picture.
+ """
+
+ url: str
+ """Avatar image URL.
+
+ Always present — a generated placeholder when the user set no picture.
+ """
+
+
+class Poster(BaseModel):
+ """The user who posted the bounty."""
+
+ id: str
+ """User ID, prefixed `user_`."""
+
+ name: Optional[str] = None
+ """Display name."""
+
+ profile_picture: PosterProfilePicture
+ """
+ Avatar wrapper; its `url` is always present, using a generated placeholder when
+ the user set no picture.
+ """
+
+ username: str
+ """Public username."""
+
+
+class WorkforceBountyListItem(BaseModel):
+ id: str
+ """Bounty ID, prefixed `bnty_`."""
+
+ accepted_submissions_count: int
+ """Submissions accepted so far."""
+
+ accepted_submissions_limit: int
+ """Number of submissions that can be accepted (winner slots)."""
+
+ allowed_country_codes: List[str]
+
+ budget_amount: float
+ """
+ Total gross budget committed to the bounty: `gross_reward_amount` times
+ `accepted_submissions_limit`.
+ """
+
+ business_goal_type: Optional[
+ Literal["clipping", "post_engagement", "owned_account_growth", "ugc_content", "local_activation", "other"]
+ ] = None
+ """What the poster wants the work to achieve."""
+
+ created_at: str
+ """When the bounty was created, as an ISO 8601 timestamp."""
+
+ currency: str
+ """Currency for all amounts on the bounty, as a lowercase ISO 4217 code."""
+
+ experience_id: Optional[str] = None
+ """Experience the bounty is hosted in, prefixed `exp_`.
+
+ Null for platform-wide bounties; may belong to a different account than the
+ funder.
+ """
+
+ funding_account: Optional[FundingAccount] = None
+ """
+ The account whose balance funds the bounty pool, or `null` when a user funds it
+ personally. May differ from the account hosting `experience_id`.
+ """
+
+ gross_paid_out_amount: float
+ """
+ Gross amount paid out from the bounty pool across accepted submissions — worker
+ payouts, platform fees, and affiliate shares together. Tips and reviewer rewards
+ are excluded.
+ """
+
+ gross_reward_amount: float
+ """
+ Gross bounty-pool amount allocated per accepted submission, in whole currency
+ units.
+ """
+
+ poster: Poster
+ """The user who posted the bounty."""
+
+ scheduled_frequency: Optional[Literal["once", "hourly", "daily", "weekly", "monthly"]] = None
+ """How often the schedule creates a new bounty.
+
+ Each occurrence is a separate bounty; the original is not republished.
+ """
+
+ scheduled_publish_at: Optional[str] = None
+ """When a scheduled bounty will publish, as an ISO 8601 timestamp.
+
+ Null once published, for bounties that were never scheduled, and for terminally
+ failed drafts parked for manual rescheduling.
+ """
+
+ spots_remaining: int
+ """
+ Unfilled winner capacity: `accepted_submissions_limit` minus
+ `accepted_submissions_count`, clamped to zero. Not a signal that the bounty
+ currently accepts new claims.
+ """
+
+ status: Literal["scheduled", "open", "closed", "completed", "canceled"]
+ """Lifecycle state.
+
+ `scheduled` bounties are unpublished drafts, visible to their poster and the
+ account's authorized managers; `open` bounties accept new submissions; `closed`
+ bounties are live but no longer accept new submissions; `completed` bounties
+ paid out every winner slot; `canceled` bounties ended before filling their
+ slots.
+ """
+
+ submissions_closed_at: Optional[str] = None
+ """When new submissions were explicitly stopped, as an ISO 8601 timestamp.
+
+ Null when submissions were never explicitly stopped — including closed or
+ completed bounties that simply filled every winner slot.
+ """
+
+ title: str
+ """Short name of the task shown to workers."""
+
+ unresolved_submissions_count: int
+ """Submissions still awaiting an outcome: in progress or pending review."""
+
+ updated_at: str
+ """When the bounty was last updated, as an ISO 8601 timestamp."""
diff --git a/tests/api_resources/accounts/__init__.py b/tests/api_resources/accounts/__init__.py
new file mode 100644
index 000000000..fd8019a9a
--- /dev/null
+++ b/tests/api_resources/accounts/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/accounts/test_preferences.py b/tests/api_resources/accounts/test_preferences.py
new file mode 100644
index 000000000..b391c7081
--- /dev/null
+++ b/tests/api_resources/accounts/test_preferences.py
@@ -0,0 +1,228 @@
+# 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.accounts import PreferenceUpdateResponse, PreferenceRetrieveResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestPreferences:
+ 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:
+ preference = client.accounts.preferences.retrieve(
+ "account_id",
+ )
+ assert_matches_type(PreferenceRetrieveResponse, preference, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_retrieve(self, client: Whop) -> None:
+ response = client.accounts.preferences.with_raw_response.retrieve(
+ "account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ preference = response.parse()
+ assert_matches_type(PreferenceRetrieveResponse, preference, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Whop) -> None:
+ with client.accounts.preferences.with_streaming_response.retrieve(
+ "account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ preference = response.parse()
+ assert_matches_type(PreferenceRetrieveResponse, preference, 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 `account_id` but received ''"):
+ client.accounts.preferences.with_raw_response.retrieve(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_update(self, client: Whop) -> None:
+ preference = client.accounts.preferences.update(
+ account_id="account_id",
+ )
+ assert_matches_type(PreferenceUpdateResponse, preference, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_update_with_all_params(self, client: Whop) -> None:
+ preference = client.accounts.preferences.update(
+ account_id="account_id",
+ ads_payment_methods={
+ "primary": {
+ "type": "platform_balance",
+ "id": "id",
+ },
+ "backup": {
+ "type": "platform_balance",
+ "id": "id",
+ },
+ },
+ )
+ assert_matches_type(PreferenceUpdateResponse, preference, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_update(self, client: Whop) -> None:
+ response = client.accounts.preferences.with_raw_response.update(
+ account_id="account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ preference = response.parse()
+ assert_matches_type(PreferenceUpdateResponse, preference, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_update(self, client: Whop) -> None:
+ with client.accounts.preferences.with_streaming_response.update(
+ account_id="account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ preference = response.parse()
+ assert_matches_type(PreferenceUpdateResponse, preference, 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 `account_id` but received ''"):
+ client.accounts.preferences.with_raw_response.update(
+ account_id="",
+ )
+
+
+class TestAsyncPreferences:
+ 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:
+ preference = await async_client.accounts.preferences.retrieve(
+ "account_id",
+ )
+ assert_matches_type(PreferenceRetrieveResponse, preference, 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.accounts.preferences.with_raw_response.retrieve(
+ "account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ preference = await response.parse()
+ assert_matches_type(PreferenceRetrieveResponse, preference, 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.accounts.preferences.with_streaming_response.retrieve(
+ "account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ preference = await response.parse()
+ assert_matches_type(PreferenceRetrieveResponse, preference, 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 `account_id` but received ''"):
+ await async_client.accounts.preferences.with_raw_response.retrieve(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_update(self, async_client: AsyncWhop) -> None:
+ preference = await async_client.accounts.preferences.update(
+ account_id="account_id",
+ )
+ assert_matches_type(PreferenceUpdateResponse, preference, 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:
+ preference = await async_client.accounts.preferences.update(
+ account_id="account_id",
+ ads_payment_methods={
+ "primary": {
+ "type": "platform_balance",
+ "id": "id",
+ },
+ "backup": {
+ "type": "platform_balance",
+ "id": "id",
+ },
+ },
+ )
+ assert_matches_type(PreferenceUpdateResponse, preference, 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.accounts.preferences.with_raw_response.update(
+ account_id="account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ preference = await response.parse()
+ assert_matches_type(PreferenceUpdateResponse, preference, 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.accounts.preferences.with_streaming_response.update(
+ account_id="account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ preference = await response.parse()
+ assert_matches_type(PreferenceUpdateResponse, preference, 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 `account_id` but received ''"):
+ await async_client.accounts.preferences.with_raw_response.update(
+ account_id="",
+ )
diff --git a/tests/api_resources/payouts/__init__.py b/tests/api_resources/payouts/__init__.py
new file mode 100644
index 000000000..fd8019a9a
--- /dev/null
+++ b/tests/api_resources/payouts/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/payouts/test_methods.py b/tests/api_resources/payouts/test_methods.py
new file mode 100644
index 000000000..4d7540f0e
--- /dev/null
+++ b/tests/api_resources/payouts/test_methods.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.pagination import SyncCursorPage, AsyncCursorPage
+from whop_sdk.types.payouts import MethodListResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestMethods:
+ 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:
+ method = client.payouts.methods.list()
+ assert_matches_type(SyncCursorPage[MethodListResponse], method, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Whop) -> None:
+ method = client.payouts.methods.list(
+ account_id="account_id",
+ after="after",
+ amount=0,
+ before="before",
+ currency="currency",
+ first=100,
+ include_available=True,
+ last=100,
+ status="created",
+ user_id="user_id",
+ )
+ assert_matches_type(SyncCursorPage[MethodListResponse], method, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Whop) -> None:
+ response = client.payouts.methods.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ method = response.parse()
+ assert_matches_type(SyncCursorPage[MethodListResponse], method, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Whop) -> None:
+ with client.payouts.methods.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ method = response.parse()
+ assert_matches_type(SyncCursorPage[MethodListResponse], method, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncMethods:
+ 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:
+ method = await async_client.payouts.methods.list()
+ assert_matches_type(AsyncCursorPage[MethodListResponse], method, 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:
+ method = await async_client.payouts.methods.list(
+ account_id="account_id",
+ after="after",
+ amount=0,
+ before="before",
+ currency="currency",
+ first=100,
+ include_available=True,
+ last=100,
+ status="created",
+ user_id="user_id",
+ )
+ assert_matches_type(AsyncCursorPage[MethodListResponse], method, 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.methods.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ method = await response.parse()
+ assert_matches_type(AsyncCursorPage[MethodListResponse], method, 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.methods.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ method = await response.parse()
+ assert_matches_type(AsyncCursorPage[MethodListResponse], method, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/referrals/__init__.py b/tests/api_resources/referrals/__init__.py
new file mode 100644
index 000000000..fd8019a9a
--- /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 000000000..fd8019a9a
--- /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 000000000..165365c85
--- /dev/null
+++ b/tests/api_resources/referrals/businesses/test_earnings.py
@@ -0,0 +1,143 @@
+# 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",
+ created_after="created_after",
+ created_before="created_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",
+ created_after="created_after",
+ created_before="created_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 000000000..64ab321da
--- /dev/null
+++ b/tests/api_resources/referrals/test_businesses.py
@@ -0,0 +1,281 @@
+# 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,
+ BusinessLeaderboardResponse,
+)
+
+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",
+ created_after="created_after",
+ created_before="created_before",
+ direction="asc",
+ first=100,
+ has_earnings=True,
+ last=100,
+ order="created_at",
+ referred_user_id="referred_user_id",
+ referred_username="referred_username",
+ status="active",
+ tier="first",
+ )
+ 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_leaderboard(self, client: Whop) -> None:
+ business = client.referrals.businesses.leaderboard()
+ assert_matches_type(BusinessLeaderboardResponse, business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_leaderboard_with_all_params(self, client: Whop) -> None:
+ business = client.referrals.businesses.leaderboard(
+ period="day",
+ )
+ assert_matches_type(BusinessLeaderboardResponse, business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_leaderboard(self, client: Whop) -> None:
+ response = client.referrals.businesses.with_raw_response.leaderboard()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ business = response.parse()
+ assert_matches_type(BusinessLeaderboardResponse, business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_leaderboard(self, client: Whop) -> None:
+ with client.referrals.businesses.with_streaming_response.leaderboard() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ business = response.parse()
+ assert_matches_type(BusinessLeaderboardResponse, 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",
+ created_after="created_after",
+ created_before="created_before",
+ direction="asc",
+ first=100,
+ has_earnings=True,
+ last=100,
+ order="created_at",
+ referred_user_id="referred_user_id",
+ referred_username="referred_username",
+ status="active",
+ tier="first",
+ )
+ 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_leaderboard(self, async_client: AsyncWhop) -> None:
+ business = await async_client.referrals.businesses.leaderboard()
+ assert_matches_type(BusinessLeaderboardResponse, business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_leaderboard_with_all_params(self, async_client: AsyncWhop) -> None:
+ business = await async_client.referrals.businesses.leaderboard(
+ period="day",
+ )
+ assert_matches_type(BusinessLeaderboardResponse, business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_leaderboard(self, async_client: AsyncWhop) -> None:
+ response = await async_client.referrals.businesses.with_raw_response.leaderboard()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ business = await response.parse()
+ assert_matches_type(BusinessLeaderboardResponse, business, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_leaderboard(self, async_client: AsyncWhop) -> None:
+ async with async_client.referrals.businesses.with_streaming_response.leaderboard() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ business = await response.parse()
+ assert_matches_type(BusinessLeaderboardResponse, business, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/referrals/test_partners.py b/tests/api_resources/referrals/test_partners.py
new file mode 100644
index 000000000..80642315a
--- /dev/null
+++ b/tests/api_resources/referrals/test_partners.py
@@ -0,0 +1,80 @@
+# 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.referrals import PartnerCreateResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestPartners:
+ 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:
+ partner = client.referrals.partners.create()
+ assert_matches_type(PartnerCreateResponse, partner, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Whop) -> None:
+ response = client.referrals.partners.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ partner = response.parse()
+ assert_matches_type(PartnerCreateResponse, partner, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Whop) -> None:
+ with client.referrals.partners.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ partner = response.parse()
+ assert_matches_type(PartnerCreateResponse, partner, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncPartners:
+ 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:
+ partner = await async_client.referrals.partners.create()
+ assert_matches_type(PartnerCreateResponse, partner, 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.referrals.partners.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ partner = await response.parse()
+ assert_matches_type(PartnerCreateResponse, partner, 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.referrals.partners.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ partner = await response.parse()
+ assert_matches_type(PartnerCreateResponse, partner, 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 118105695..e22daca0d 100644
--- a/tests/api_resources/test_accounts.py
+++ b/tests/api_resources/test_accounts.py
@@ -11,8 +11,9 @@
from tests.utils import assert_matches_type
from whop_sdk.types import (
Account,
- AccountListResponse,
+ AccountRecommendActionsResponse,
)
+from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -32,6 +33,7 @@ def test_method_create_with_all_params(self, client: Whop) -> None:
account = client.accounts.create(
email="email",
metadata={"foo": "bar"},
+ title="title",
)
assert_matches_type(Account, account, path=["response"])
@@ -115,18 +117,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 +200,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 +223,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 +233,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
@@ -229,6 +265,48 @@ def test_streaming_response_me(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_recommend_actions(self, client: Whop) -> None:
+ account = client.accounts.recommend_actions(
+ "account_id",
+ )
+ assert_matches_type(AccountRecommendActionsResponse, account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_recommend_actions(self, client: Whop) -> None:
+ response = client.accounts.with_raw_response.recommend_actions(
+ "account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ account = response.parse()
+ assert_matches_type(AccountRecommendActionsResponse, account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_recommend_actions(self, client: Whop) -> None:
+ with client.accounts.with_streaming_response.recommend_actions(
+ "account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ account = response.parse()
+ assert_matches_type(AccountRecommendActionsResponse, 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_recommend_actions(self, client: Whop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"):
+ client.accounts.with_raw_response.recommend_actions(
+ "",
+ )
+
class TestAsyncAccounts:
parametrize = pytest.mark.parametrize(
@@ -247,6 +325,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> N
account = await async_client.accounts.create(
email="email",
metadata={"foo": "bar"},
+ title="title",
)
assert_matches_type(Account, account, path=["response"])
@@ -330,18 +409,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 +492,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 +515,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 +525,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
@@ -443,3 +556,45 @@ async def test_streaming_response_me(self, async_client: AsyncWhop) -> None:
assert_matches_type(Account, 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_recommend_actions(self, async_client: AsyncWhop) -> None:
+ account = await async_client.accounts.recommend_actions(
+ "account_id",
+ )
+ assert_matches_type(AccountRecommendActionsResponse, account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_recommend_actions(self, async_client: AsyncWhop) -> None:
+ response = await async_client.accounts.with_raw_response.recommend_actions(
+ "account_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ account = await response.parse()
+ assert_matches_type(AccountRecommendActionsResponse, account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_recommend_actions(self, async_client: AsyncWhop) -> None:
+ async with async_client.accounts.with_streaming_response.recommend_actions(
+ "account_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ account = await response.parse()
+ assert_matches_type(AccountRecommendActionsResponse, 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_recommend_actions(self, async_client: AsyncWhop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"):
+ await async_client.accounts.with_raw_response.recommend_actions(
+ "",
+ )
diff --git a/tests/api_resources/test_ad_campaigns.py b/tests/api_resources/test_ad_campaigns.py
index 4c818bf86..0881a4040 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,81 @@
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",
+ time_zone="time_zone",
)
assert_matches_type(AdCampaign, ad_campaign, path=["response"])
@@ -34,7 +103,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 +115,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 +130,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 +145,14 @@ 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",
+ bid_type="minimum_cost",
+ budget_amount=0,
+ budget_optimization="ad_campaign",
+ ends_at="ends_at",
+ starts_at="starts_at",
+ status="active",
+ title="title",
)
assert_matches_type(AdCampaign, ad_campaign, path=["response"])
@@ -85,7 +160,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 +172,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 +194,28 @@ 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",
+ time_zone="time_zone",
)
- 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 +225,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 +235,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 +293,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 +305,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 +327,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 +335,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 +347,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 +371,81 @@ 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",
+ time_zone="time_zone",
)
assert_matches_type(AdCampaign, ad_campaign, path=["response"])
@@ -261,7 +453,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 +465,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 +480,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 +495,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:
ad_campaign = await async_client.ad_campaigns.update(
- id="adcamp_xxxxxxxxxxx",
- budget=6.9,
+ id="id",
+ bid_type="minimum_cost",
+ budget_amount=0,
+ budget_optimization="ad_campaign",
+ ends_at="ends_at",
+ starts_at="starts_at",
+ status="active",
+ title="title",
)
assert_matches_type(AdCampaign, ad_campaign, path=["response"])
@@ -312,7 +510,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 +522,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 +544,28 @@ 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",
+ time_zone="time_zone",
)
- 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 +575,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 +585,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 +643,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 +655,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 +677,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 +685,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 +697,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 ebbda82c6..b4be54ee2 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,85 @@
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",
+ time_zone="time_zone",
)
assert_matches_type(AdGroup, ad_group, path=["response"])
@@ -35,7 +107,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 +119,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 +134,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 +149,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 +177,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 +189,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 +211,29 @@ 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",
+ time_zone="time_zone",
)
- 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 +243,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 +253,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 +261,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 +269,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 +281,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 +303,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 +311,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 +323,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 +345,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 +353,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 +365,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 +389,85 @@ 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",
+ time_zone="time_zone",
)
assert_matches_type(AdGroup, ad_group, path=["response"])
@@ -646,7 +475,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 +487,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 +502,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 +517,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 +545,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 +557,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 +579,29 @@ 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",
+ time_zone="time_zone",
)
- 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 +611,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 +621,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 +629,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 +637,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 +649,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 +671,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 +679,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 +691,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 +713,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 +721,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 +733,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 a5b76624f..861f56dae 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 0b0f229e2..803a3b27c 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,136 @@
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",
+ "crop": {
+ "height": 0,
+ "width": 0,
+ "x": 0,
+ "y": 0,
+ },
+ "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",
+ }
+ ],
+ },
+ lead_form_id="lead_form_id",
+ messaging_config={
+ "keyword": "keyword",
+ "message": "message",
+ },
+ multi_advertiser_ads=True,
+ post_id="post_id",
+ post_source="facebook",
+ 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",
+ time_zone="time_zone",
)
assert_matches_type(Ad, ad, path=["response"])
@@ -31,7 +155,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 +167,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 +182,164 @@ 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",
+ "crop": {
+ "height": 0,
+ "width": 0,
+ "x": 0,
+ "y": 0,
+ },
+ "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",
+ }
+ ],
+ },
+ lead_form_id="lead_form_id",
+ messaging_config={
+ "keyword": "keyword",
+ "message": "message",
+ },
+ multi_advertiser_ads=True,
+ post_id="post_id",
+ post_source="facebook",
+ 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",
+ time_zone="time_zone",
)
- 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 +349,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 +359,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 +417,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 +429,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 +451,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 +459,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 +471,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 +495,136 @@ 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",
+ "crop": {
+ "height": 0,
+ "width": 0,
+ "x": 0,
+ "y": 0,
+ },
+ "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",
+ }
+ ],
+ },
+ lead_form_id="lead_form_id",
+ messaging_config={
+ "keyword": "keyword",
+ "message": "message",
+ },
+ multi_advertiser_ads=True,
+ post_id="post_id",
+ post_source="facebook",
+ 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",
+ time_zone="time_zone",
)
assert_matches_type(Ad, ad, path=["response"])
@@ -214,7 +632,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 +644,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 +659,164 @@ 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",
+ "crop": {
+ "height": 0,
+ "width": 0,
+ "x": 0,
+ "y": 0,
+ },
+ "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",
+ }
+ ],
+ },
+ lead_form_id="lead_form_id",
+ messaging_config={
+ "keyword": "keyword",
+ "message": "message",
+ },
+ multi_advertiser_ads=True,
+ post_id="post_id",
+ post_source="facebook",
+ 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",
+ time_zone="time_zone",
)
- 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 +826,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 +836,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 +894,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 +906,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 +928,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 +936,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 +948,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_apps.py b/tests/api_resources/test_apps.py
index 042e705a4..18440b16f 100644
--- a/tests/api_resources/test_apps.py
+++ b/tests/api_resources/test_apps.py
@@ -9,7 +9,11 @@
from whop_sdk import Whop, AsyncWhop
from tests.utils import assert_matches_type
-from whop_sdk.types import AppListResponse
+from whop_sdk.types import (
+ AppListResponse,
+ AppLogsResponse,
+)
+from whop_sdk._utils import parse_datetime
from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
from whop_sdk.types.shared import App
@@ -37,6 +41,7 @@ def test_method_create_with_all_params(self, client: Whop) -> None:
base_url="base_url",
icon={"id": "id"},
redirect_uris=["string"],
+ route="route",
)
assert_matches_type(App, app, path=["response"])
@@ -136,6 +141,8 @@ def test_method_update_with_all_params(self, client: Whop) -> None:
openapi_path="openapi_path",
redirect_uris=["string"],
required_scopes=["read_user"],
+ route="route",
+ secrets={"foo": "bar"},
skills_path="skills_path",
status="live",
)
@@ -221,6 +228,64 @@ def test_streaming_response_list(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_logs(self, client: Whop) -> None:
+ app = client.apps.logs(
+ id="id",
+ )
+ assert_matches_type(AppLogsResponse, app, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_logs_with_all_params(self, client: Whop) -> None:
+ app = client.apps.logs(
+ id="id",
+ after="after",
+ app_build_id="app_build_id",
+ before="before",
+ created_after=parse_datetime("2019-12-27T18:11:19.117Z"),
+ created_before=parse_datetime("2019-12-27T18:11:19.117Z"),
+ first=0,
+ level="log",
+ query="query",
+ )
+ assert_matches_type(AppLogsResponse, app, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_logs(self, client: Whop) -> None:
+ response = client.apps.with_raw_response.logs(
+ id="id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ app = response.parse()
+ assert_matches_type(AppLogsResponse, app, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_logs(self, client: Whop) -> None:
+ with client.apps.with_streaming_response.logs(
+ id="id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ app = response.parse()
+ assert_matches_type(AppLogsResponse, app, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_path_params_logs(self, client: Whop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.apps.with_raw_response.logs(
+ id="",
+ )
+
class TestAsyncApps:
parametrize = pytest.mark.parametrize(
@@ -245,6 +310,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncWhop) -> N
base_url="base_url",
icon={"id": "id"},
redirect_uris=["string"],
+ route="route",
)
assert_matches_type(App, app, path=["response"])
@@ -344,6 +410,8 @@ async def test_method_update_with_all_params(self, async_client: AsyncWhop) -> N
openapi_path="openapi_path",
redirect_uris=["string"],
required_scopes=["read_user"],
+ route="route",
+ secrets={"foo": "bar"},
skills_path="skills_path",
status="live",
)
@@ -428,3 +496,61 @@ async def test_streaming_response_list(self, async_client: AsyncWhop) -> None:
assert_matches_type(AsyncCursorPage[AppListResponse], app, path=["response"])
assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_logs(self, async_client: AsyncWhop) -> None:
+ app = await async_client.apps.logs(
+ id="id",
+ )
+ assert_matches_type(AppLogsResponse, app, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_logs_with_all_params(self, async_client: AsyncWhop) -> None:
+ app = await async_client.apps.logs(
+ id="id",
+ after="after",
+ app_build_id="app_build_id",
+ before="before",
+ created_after=parse_datetime("2019-12-27T18:11:19.117Z"),
+ created_before=parse_datetime("2019-12-27T18:11:19.117Z"),
+ first=0,
+ level="log",
+ query="query",
+ )
+ assert_matches_type(AppLogsResponse, app, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_logs(self, async_client: AsyncWhop) -> None:
+ response = await async_client.apps.with_raw_response.logs(
+ id="id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ app = await response.parse()
+ assert_matches_type(AppLogsResponse, app, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_logs(self, async_client: AsyncWhop) -> None:
+ async with async_client.apps.with_streaming_response.logs(
+ id="id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ app = await response.parse()
+ assert_matches_type(AppLogsResponse, app, 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_logs(self, async_client: AsyncWhop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.apps.with_raw_response.logs(
+ id="",
+ )
diff --git a/tests/api_resources/test_audiences.py b/tests/api_resources/test_audiences.py
new file mode 100644
index 000000000..7ca8a2042
--- /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 007f3d47e..96ad67ce5 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 d76ec837a..99ac91423 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 000000000..f0dfc2556
--- /dev/null
+++ b/tests/api_resources/test_cards.py
@@ -0,0 +1,427 @@
+# 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,
+ CardUpdateResponse,
+ 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_update(self, client: Whop) -> None:
+ card = client.cards.update(
+ card_id="card_id",
+ )
+ assert_matches_type(CardUpdateResponse, card, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_update_with_all_params(self, client: Whop) -> None:
+ card = client.cards.update(
+ card_id="card_id",
+ account_id="account_id",
+ billing={
+ "city": "city",
+ "country_code": "country_code",
+ "line1": "line1",
+ "postal_code": "postal_code",
+ "region": "region",
+ "line2": "line2",
+ },
+ canceled=True,
+ frozen=True,
+ name="name",
+ pin="pin",
+ remove_limit=True,
+ spend_limit=0,
+ spend_limit_frequency="daily",
+ transaction_limit=0,
+ user_id="user_id",
+ )
+ assert_matches_type(CardUpdateResponse, card, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_update(self, client: Whop) -> None:
+ response = client.cards.with_raw_response.update(
+ 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(CardUpdateResponse, card, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_update(self, client: Whop) -> None:
+ with client.cards.with_streaming_response.update(
+ 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(CardUpdateResponse, 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_update(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.update(
+ 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_update(self, async_client: AsyncWhop) -> None:
+ card = await async_client.cards.update(
+ card_id="card_id",
+ )
+ assert_matches_type(CardUpdateResponse, card, 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:
+ card = await async_client.cards.update(
+ card_id="card_id",
+ account_id="account_id",
+ billing={
+ "city": "city",
+ "country_code": "country_code",
+ "line1": "line1",
+ "postal_code": "postal_code",
+ "region": "region",
+ "line2": "line2",
+ },
+ canceled=True,
+ frozen=True,
+ name="name",
+ pin="pin",
+ remove_limit=True,
+ spend_limit=0,
+ spend_limit_frequency="daily",
+ transaction_limit=0,
+ user_id="user_id",
+ )
+ assert_matches_type(CardUpdateResponse, card, 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.cards.with_raw_response.update(
+ 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(CardUpdateResponse, card, 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.cards.with_streaming_response.update(
+ 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(CardUpdateResponse, 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_update(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.update(
+ 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 76ccdb328..ac52fa965 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="biz_xxxxxxxxxxxxxx",
+ 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,
+ "trial_period_days": 0,
+ "unlimited_stock": True,
+ "visibility": "visibility",
},
- 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",
+ 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_2(self, client: Whop) -> None:
- response = client.checkout_configurations.with_raw_response.create(
- plan_id="plan_xxxxxxxxxxxxx",
- )
+ 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_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,
- },
- redirect_url="redirect_url",
- source_url="source_url",
- three_ds_level="mandate_challenge",
- )
- assert_matches_type(CheckoutConfiguration, 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",
- )
-
- 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_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"])
+ 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(
+ "",
+ )
- @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"
- 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(
+ affiliate_code="affiliate_code",
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"},
+ 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_xxxxxxxxxxxxx",
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
deleted file mode 100644
index 3b63db114..000000000
--- a/tests/api_resources/test_conversions.py
+++ /dev/null
@@ -1,215 +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 ConversionCreateResponse
-from whop_sdk._utils import parse_datetime
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestConversions:
- 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:
- conversion = client.conversions.create(
- company_id="biz_xxxxxxxxxxxxxx",
- event_name="lead",
- )
- assert_matches_type(ConversionCreateResponse, conversion, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create_with_all_params(self, client: Whop) -> None:
- conversion = client.conversions.create(
- company_id="biz_xxxxxxxxxxxxxx",
- event_name="lead",
- action_source="email",
- context={
- "ad_campaign_id": "ad_campaign_id",
- "ad_id": "ad_id",
- "ad_set_id": "ad_set_id",
- "fbclid": "fbclid",
- "fbp": "fbp",
- "ga": "ga",
- "gclid": "gclid",
- "ig_sid": "ig_sid",
- "ip_address": "ip_address",
- "ttclid": "ttclid",
- "ttp": "ttp",
- "user_agent": "user_agent",
- "utm_campaign": "utm_campaign",
- "utm_content": "utm_content",
- "utm_id": "utm_id",
- "utm_medium": "utm_medium",
- "utm_source": "utm_source",
- "utm_term": "utm_term",
- },
- currency="usd",
- custom_name="custom_name",
- 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",
- url="url",
- user={
- "anonymous_id": "anonymous_id",
- "birthdate": "1990-01-15",
- "city": "city",
- "country": "country",
- "email": "email",
- "external_id": "external_id",
- "first_name": "first_name",
- "gender": "male",
- "last_name": "last_name",
- "member_id": "mber_xxxxxxxxxxxxx",
- "membership_id": "mem_xxxxxxxxxxxxxx",
- "name": "name",
- "phone": "phone",
- "postal_code": "postal_code",
- "state": "state",
- "user_id": "user_xxxxxxxxxxxxx",
- "username": "username",
- },
- value=6.9,
- )
- assert_matches_type(ConversionCreateResponse, conversion, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_create(self, client: Whop) -> None:
- response = client.conversions.with_raw_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
- event_name="lead",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- conversion = response.parse()
- assert_matches_type(ConversionCreateResponse, conversion, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_create(self, client: Whop) -> None:
- with client.conversions.with_streaming_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
- event_name="lead",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- conversion = response.parse()
- assert_matches_type(ConversionCreateResponse, conversion, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
-
-class TestAsyncConversions:
- 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:
- conversion = await async_client.conversions.create(
- company_id="biz_xxxxxxxxxxxxxx",
- event_name="lead",
- )
- assert_matches_type(ConversionCreateResponse, conversion, 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:
- conversion = await async_client.conversions.create(
- company_id="biz_xxxxxxxxxxxxxx",
- event_name="lead",
- action_source="email",
- context={
- "ad_campaign_id": "ad_campaign_id",
- "ad_id": "ad_id",
- "ad_set_id": "ad_set_id",
- "fbclid": "fbclid",
- "fbp": "fbp",
- "ga": "ga",
- "gclid": "gclid",
- "ig_sid": "ig_sid",
- "ip_address": "ip_address",
- "ttclid": "ttclid",
- "ttp": "ttp",
- "user_agent": "user_agent",
- "utm_campaign": "utm_campaign",
- "utm_content": "utm_content",
- "utm_id": "utm_id",
- "utm_medium": "utm_medium",
- "utm_source": "utm_source",
- "utm_term": "utm_term",
- },
- currency="usd",
- custom_name="custom_name",
- 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",
- url="url",
- user={
- "anonymous_id": "anonymous_id",
- "birthdate": "1990-01-15",
- "city": "city",
- "country": "country",
- "email": "email",
- "external_id": "external_id",
- "first_name": "first_name",
- "gender": "male",
- "last_name": "last_name",
- "member_id": "mber_xxxxxxxxxxxxx",
- "membership_id": "mem_xxxxxxxxxxxxxx",
- "name": "name",
- "phone": "phone",
- "postal_code": "postal_code",
- "state": "state",
- "user_id": "user_xxxxxxxxxxxxx",
- "username": "username",
- },
- value=6.9,
- )
- assert_matches_type(ConversionCreateResponse, conversion, 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.conversions.with_raw_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
- event_name="lead",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- conversion = await response.parse()
- assert_matches_type(ConversionCreateResponse, conversion, 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.conversions.with_streaming_response.create(
- company_id="biz_xxxxxxxxxxxxxx",
- event_name="lead",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- conversion = await response.parse()
- assert_matches_type(ConversionCreateResponse, conversion, path=["response"])
-
- assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_deposits.py b/tests/api_resources/test_deposits.py
index 7786dbc83..e26f749e3 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 000000000..c727e5214
--- /dev/null
+++ b/tests/api_resources/test_events.py
@@ -0,0 +1,350 @@
+# 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, EventCreateResponse
+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")
+
+
+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_create(self, client: Whop) -> None:
+ event = client.events.create(
+ account_id="account_id",
+ event_name="lead",
+ )
+ assert_matches_type(EventCreateResponse, event, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: Whop) -> None:
+ event = client.events.create(
+ account_id="account_id",
+ event_name="lead",
+ action_source="email",
+ context={
+ "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",
+ "utm_id": "utm_id",
+ "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",
+ "birthdate": "1990-01-15",
+ "city": "city",
+ "country": "country",
+ "email": "email",
+ "external_id": "external_id",
+ "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",
+ "phone": "phone",
+ "postal_code": "postal_code",
+ "state": "state",
+ "user_id": "user_xxxxxxxxxxxxx",
+ "username": "username",
+ },
+ value=6.9,
+ )
+ assert_matches_type(EventCreateResponse, event, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Whop) -> None:
+ response = client.events.with_raw_response.create(
+ account_id="account_id",
+ event_name="lead",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ event = response.parse()
+ assert_matches_type(EventCreateResponse, event, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Whop) -> None:
+ with client.events.with_streaming_response.create(
+ account_id="account_id",
+ event_name="lead",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ event = response.parse()
+ assert_matches_type(EventCreateResponse, event, 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:
+ event = client.events.list(
+ person_id="person_id",
+ )
+ assert_matches_type(SyncCursorPage[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",
+ after="after",
+ before="before",
+ first=0,
+ from_=0,
+ to=0,
+ )
+ assert_matches_type(SyncCursorPage[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(SyncCursorPage[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(SyncCursorPage[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_create(self, async_client: AsyncWhop) -> None:
+ event = await async_client.events.create(
+ account_id="account_id",
+ event_name="lead",
+ )
+ assert_matches_type(EventCreateResponse, event, 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:
+ event = await async_client.events.create(
+ account_id="account_id",
+ event_name="lead",
+ action_source="email",
+ context={
+ "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",
+ "utm_id": "utm_id",
+ "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",
+ "birthdate": "1990-01-15",
+ "city": "city",
+ "country": "country",
+ "email": "email",
+ "external_id": "external_id",
+ "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",
+ "phone": "phone",
+ "postal_code": "postal_code",
+ "state": "state",
+ "user_id": "user_xxxxxxxxxxxxx",
+ "username": "username",
+ },
+ value=6.9,
+ )
+ assert_matches_type(EventCreateResponse, event, 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.events.with_raw_response.create(
+ account_id="account_id",
+ event_name="lead",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ event = await response.parse()
+ assert_matches_type(EventCreateResponse, event, 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.events.with_streaming_response.create(
+ account_id="account_id",
+ event_name="lead",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ event = await response.parse()
+ assert_matches_type(EventCreateResponse, event, 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:
+ event = await async_client.events.list(
+ person_id="person_id",
+ )
+ assert_matches_type(AsyncCursorPage[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",
+ after="after",
+ before="before",
+ first=0,
+ from_=0,
+ to=0,
+ )
+ assert_matches_type(AsyncCursorPage[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(AsyncCursorPage[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(AsyncCursorPage[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 000000000..d28a93497
--- /dev/null
+++ b/tests/api_resources/test_financial_activity.py
@@ -0,0 +1,117 @@
+# 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",
+ include_owned_accounts=True,
+ 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",
+ include_owned_accounts=True,
+ 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 30be40a0e..cfd94e2ed 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_media.py b/tests/api_resources/test_media.py
new file mode 100644
index 000000000..a23e118ec
--- /dev/null
+++ b/tests/api_resources/test_media.py
@@ -0,0 +1,208 @@
+# 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 MediaAsset
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestMedia:
+ 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:
+ media = client.media.retrieve(
+ "id",
+ )
+ assert_matches_type(MediaAsset, media, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_retrieve(self, client: Whop) -> None:
+ response = client.media.with_raw_response.retrieve(
+ "id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ media = response.parse()
+ assert_matches_type(MediaAsset, media, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Whop) -> None:
+ with client.media.with_streaming_response.retrieve(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ media = response.parse()
+ assert_matches_type(MediaAsset, media, 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.media.with_raw_response.retrieve(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_generate(self, client: Whop) -> None:
+ media = client.media.generate(
+ prompt="prompt",
+ type="video",
+ )
+ assert_matches_type(MediaAsset, media, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_generate_with_all_params(self, client: Whop) -> None:
+ media = client.media.generate(
+ prompt="prompt",
+ type="video",
+ account_id="account_id",
+ duration_seconds=5,
+ reference_media=["string"],
+ resolution="480p",
+ )
+ assert_matches_type(MediaAsset, media, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_generate(self, client: Whop) -> None:
+ response = client.media.with_raw_response.generate(
+ prompt="prompt",
+ type="video",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ media = response.parse()
+ assert_matches_type(MediaAsset, media, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_generate(self, client: Whop) -> None:
+ with client.media.with_streaming_response.generate(
+ prompt="prompt",
+ type="video",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ media = response.parse()
+ assert_matches_type(MediaAsset, media, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncMedia:
+ 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:
+ media = await async_client.media.retrieve(
+ "id",
+ )
+ assert_matches_type(MediaAsset, media, 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.media.with_raw_response.retrieve(
+ "id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ media = await response.parse()
+ assert_matches_type(MediaAsset, media, 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.media.with_streaming_response.retrieve(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ media = await response.parse()
+ assert_matches_type(MediaAsset, media, 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.media.with_raw_response.retrieve(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_generate(self, async_client: AsyncWhop) -> None:
+ media = await async_client.media.generate(
+ prompt="prompt",
+ type="video",
+ )
+ assert_matches_type(MediaAsset, media, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_generate_with_all_params(self, async_client: AsyncWhop) -> None:
+ media = await async_client.media.generate(
+ prompt="prompt",
+ type="video",
+ account_id="account_id",
+ duration_seconds=5,
+ reference_media=["string"],
+ resolution="480p",
+ )
+ assert_matches_type(MediaAsset, media, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_generate(self, async_client: AsyncWhop) -> None:
+ response = await async_client.media.with_raw_response.generate(
+ prompt="prompt",
+ type="video",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ media = await response.parse()
+ assert_matches_type(MediaAsset, media, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_generate(self, async_client: AsyncWhop) -> None:
+ async with async_client.media.with_streaming_response.generate(
+ prompt="prompt",
+ type="video",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ media = await response.parse()
+ assert_matches_type(MediaAsset, media, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_payments.py b/tests/api_resources/test_payments.py
index fcdf8af84..9ebd8a978 100644
--- a/tests/api_resources/test_payments.py
+++ b/tests/api_resources/test_payments.py
@@ -72,6 +72,7 @@ def test_method_create_with_all_params_overload_1(self, client: Whop) -> None:
"visibility": "visible",
},
metadata={"foo": "bar"},
+ promo_code_id="promo_xxxxxxxxxxxx",
)
assert_matches_type(Payment, payment, path=["response"])
@@ -127,6 +128,7 @@ def test_method_create_with_all_params_overload_2(self, client: Whop) -> None:
payment_method_id="pmt_xxxxxxxxxxxxxx",
plan_id="plan_xxxxxxxxxxxxx",
metadata={"foo": "bar"},
+ promo_code_id="promo_xxxxxxxxxxxx",
)
assert_matches_type(Payment, payment, path=["response"])
@@ -503,6 +505,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn
"visibility": "visible",
},
metadata={"foo": "bar"},
+ promo_code_id="promo_xxxxxxxxxxxx",
)
assert_matches_type(Payment, payment, path=["response"])
@@ -558,6 +561,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn
payment_method_id="pmt_xxxxxxxxxxxxxx",
plan_id="plan_xxxxxxxxxxxxx",
metadata={"foo": "bar"},
+ promo_code_id="promo_xxxxxxxxxxxx",
)
assert_matches_type(Payment, payment, path=["response"])
diff --git a/tests/api_resources/test_payouts.py b/tests/api_resources/test_payouts.py
new file mode 100644
index 000000000..4c8bdd306
--- /dev/null
+++ b/tests/api_resources/test_payouts.py
@@ -0,0 +1,213 @@
+# 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, PayoutCreateResponse
+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_create(self, client: Whop) -> None:
+ payout = client.payouts.create(
+ account_id="account_id",
+ amount=0,
+ payout_method_id="payout_method_id",
+ )
+ assert_matches_type(PayoutCreateResponse, payout, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: Whop) -> None:
+ payout = client.payouts.create(
+ account_id="account_id",
+ amount=0,
+ payout_method_id="payout_method_id",
+ currency="currency",
+ idempotency_key="idempotency_key",
+ )
+ assert_matches_type(PayoutCreateResponse, payout, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Whop) -> None:
+ response = client.payouts.with_raw_response.create(
+ account_id="account_id",
+ amount=0,
+ payout_method_id="payout_method_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ payout = response.parse()
+ assert_matches_type(PayoutCreateResponse, payout, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Whop) -> None:
+ with client.payouts.with_streaming_response.create(
+ account_id="account_id",
+ amount=0,
+ payout_method_id="payout_method_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ payout = response.parse()
+ assert_matches_type(PayoutCreateResponse, payout, 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:
+ 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_create(self, async_client: AsyncWhop) -> None:
+ payout = await async_client.payouts.create(
+ account_id="account_id",
+ amount=0,
+ payout_method_id="payout_method_id",
+ )
+ assert_matches_type(PayoutCreateResponse, payout, 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:
+ payout = await async_client.payouts.create(
+ account_id="account_id",
+ amount=0,
+ payout_method_id="payout_method_id",
+ currency="currency",
+ idempotency_key="idempotency_key",
+ )
+ assert_matches_type(PayoutCreateResponse, payout, 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.payouts.with_raw_response.create(
+ account_id="account_id",
+ amount=0,
+ payout_method_id="payout_method_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ payout = await response.parse()
+ assert_matches_type(PayoutCreateResponse, payout, 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.payouts.with_streaming_response.create(
+ account_id="account_id",
+ amount=0,
+ payout_method_id="payout_method_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ payout = await response.parse()
+ assert_matches_type(PayoutCreateResponse, payout, 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:
+ 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 000000000..d45c667a2
--- /dev/null
+++ b/tests/api_resources/test_people.py
@@ -0,0 +1,219 @@
+# 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
+from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
+
+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(SyncCursorPage[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",
+ after="after",
+ before="before",
+ direction="asc",
+ filters="filters",
+ first=0,
+ from_=0,
+ sort="sort",
+ to=0,
+ )
+ assert_matches_type(SyncCursorPage[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(SyncCursorPage[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(SyncCursorPage[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(AsyncCursorPage[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",
+ after="after",
+ before="before",
+ direction="asc",
+ filters="filters",
+ first=0,
+ from_=0,
+ sort="sort",
+ to=0,
+ )
+ assert_matches_type(AsyncCursorPage[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(AsyncCursorPage[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(AsyncCursorPage[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 1a92b3681..e159a1e1f 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": "DE",
+ "city": "city",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "10115",
+ "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": "DE",
+ "city": "city",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "10115",
+ "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 b9a1c3294..ad8287c13 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,24 @@ 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 +56,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 +68,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 +82,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 +90,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 +102,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 +124,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 +132,14 @@ 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",
+ metadata={},
+ product_tax_code_id="product_tax_code_id",
send_welcome_message=True,
- store_page_config={
- "custom_cta": "custom_cta",
- "show_price": True,
- },
title="title",
- visibility="visible",
+ visibility="visibility",
)
assert_matches_type(Product, product, path=["response"])
@@ -188,7 +147,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 +159,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 +181,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 +189,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 +205,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 +217,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 +231,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 +239,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 +251,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 +279,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 +287,24 @@ 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 +312,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 +324,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 +338,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 +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.products.with_raw_response.retrieve(
- "prod_xxxxxxxxxxxxx",
+ "id",
)
assert response.is_closed is True
@@ -424,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.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 +380,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 +388,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:
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",
+ metadata={},
+ product_tax_code_id="product_tax_code_id",
send_welcome_message=True,
- store_page_config={
- "custom_cta": "custom_cta",
- "show_price": True,
- },
title="title",
- visibility="visible",
+ visibility="visibility",
)
assert_matches_type(Product, product, path=["response"])
@@ -484,7 +403,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 +415,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 +437,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 +445,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 +461,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 +473,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 +487,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 +495,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 +507,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_referrals.py b/tests/api_resources/test_referrals.py
new file mode 100644
index 000000000..0bcbc2c09
--- /dev/null
+++ b/tests/api_resources/test_referrals.py
@@ -0,0 +1,106 @@
+# 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 ReferralReferredUsersResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestReferrals:
+ 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_referred_users(self, client: Whop) -> None:
+ referral = client.referrals.referred_users()
+ assert_matches_type(ReferralReferredUsersResponse, referral, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_referred_users_with_all_params(self, client: Whop) -> None:
+ referral = client.referrals.referred_users(
+ after="after",
+ before="before",
+ first=100,
+ has_businesses=True,
+ has_earning_businesses=True,
+ last=100,
+ )
+ assert_matches_type(ReferralReferredUsersResponse, referral, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_referred_users(self, client: Whop) -> None:
+ response = client.referrals.with_raw_response.referred_users()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ referral = response.parse()
+ assert_matches_type(ReferralReferredUsersResponse, referral, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_referred_users(self, client: Whop) -> None:
+ with client.referrals.with_streaming_response.referred_users() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ referral = response.parse()
+ assert_matches_type(ReferralReferredUsersResponse, referral, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncReferrals:
+ 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_referred_users(self, async_client: AsyncWhop) -> None:
+ referral = await async_client.referrals.referred_users()
+ assert_matches_type(ReferralReferredUsersResponse, referral, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_referred_users_with_all_params(self, async_client: AsyncWhop) -> None:
+ referral = await async_client.referrals.referred_users(
+ after="after",
+ before="before",
+ first=100,
+ has_businesses=True,
+ has_earning_businesses=True,
+ last=100,
+ )
+ assert_matches_type(ReferralReferredUsersResponse, referral, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_referred_users(self, async_client: AsyncWhop) -> None:
+ response = await async_client.referrals.with_raw_response.referred_users()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ referral = await response.parse()
+ assert_matches_type(ReferralReferredUsersResponse, referral, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_referred_users(self, async_client: AsyncWhop) -> None:
+ async with async_client.referrals.with_streaming_response.referred_users() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ referral = await response.parse()
+ assert_matches_type(ReferralReferredUsersResponse, referral, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_social_accounts.py b/tests/api_resources/test_social_accounts.py
new file mode 100644
index 000000000..d1565c2aa
--- /dev/null
+++ b/tests/api_resources/test_social_accounts.py
@@ -0,0 +1,518 @@
+# 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,
+ SocialAccountDeleteResponse,
+ SocialAccountConnectResponse,
+)
+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="facebook",
+ )
+ assert_matches_type(SocialAccount, 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="facebook",
+ account_id="account_id",
+ )
+ assert_matches_type(SocialAccount, 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="facebook",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ social_account = response.parse()
+ assert_matches_type(SocialAccount, 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="facebook",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ social_account = response.parse()
+ assert_matches_type(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_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_connect(self, client: Whop) -> None:
+ social_account = client.social_accounts.connect(
+ platform="meta_business",
+ )
+ assert_matches_type(SocialAccountConnectResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_connect_with_all_params(self, client: Whop) -> None:
+ social_account = client.social_accounts.connect(
+ platform="meta_business",
+ account_id="account_id",
+ redirect_url="redirect_url",
+ scopes=["advertise"],
+ )
+ assert_matches_type(SocialAccountConnectResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_connect(self, client: Whop) -> None:
+ response = client.social_accounts.with_raw_response.connect(
+ platform="meta_business",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ social_account = response.parse()
+ assert_matches_type(SocialAccountConnectResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_connect(self, client: Whop) -> None:
+ with client.social_accounts.with_streaming_response.connect(
+ platform="meta_business",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ social_account = response.parse()
+ assert_matches_type(SocialAccountConnectResponse, 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_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="facebook",
+ )
+ assert_matches_type(SocialAccount, 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="facebook",
+ account_id="account_id",
+ )
+ assert_matches_type(SocialAccount, 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="facebook",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ social_account = await response.parse()
+ assert_matches_type(SocialAccount, 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="facebook",
+ ) 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(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_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_connect(self, async_client: AsyncWhop) -> None:
+ social_account = await async_client.social_accounts.connect(
+ platform="meta_business",
+ )
+ assert_matches_type(SocialAccountConnectResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_connect_with_all_params(self, async_client: AsyncWhop) -> None:
+ social_account = await async_client.social_accounts.connect(
+ platform="meta_business",
+ account_id="account_id",
+ redirect_url="redirect_url",
+ scopes=["advertise"],
+ )
+ assert_matches_type(SocialAccountConnectResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_connect(self, async_client: AsyncWhop) -> None:
+ response = await async_client.social_accounts.with_raw_response.connect(
+ platform="meta_business",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ social_account = await response.parse()
+ assert_matches_type(SocialAccountConnectResponse, social_account, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_connect(self, async_client: AsyncWhop) -> None:
+ async with async_client.social_accounts.with_streaming_response.connect(
+ platform="meta_business",
+ ) 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(SocialAccountConnectResponse, 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_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 000000000..a089e5d76
--- /dev/null
+++ b/tests/api_resources/test_stats.py
@@ -0,0 +1,243 @@
+# 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",
+ 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",
+ from_=parse_date("2019-12-27"),
+ to=parse_date("2019-12-27"),
+ access_level="access_level",
+ account_id="account_id",
+ ad_campaign_ids=["string"],
+ ad_group_ids=["string"],
+ ad_ids=["string"],
+ breakdown_by="breakdown_by",
+ card_network="card_network",
+ category="category",
+ convert_to="convert_to",
+ currency="currency",
+ fee_type="fee_type",
+ interval="hour",
+ most_recent_action="most_recent_action",
+ payment_method="payment_method",
+ product="product",
+ referred_user_id="referred_user_id",
+ segment="segment",
+ snapshot_window="30d",
+ source="source",
+ status="status",
+ 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",
+ 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",
+ 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="",
+ 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",
+ 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",
+ from_=parse_date("2019-12-27"),
+ to=parse_date("2019-12-27"),
+ access_level="access_level",
+ account_id="account_id",
+ ad_campaign_ids=["string"],
+ ad_group_ids=["string"],
+ ad_ids=["string"],
+ breakdown_by="breakdown_by",
+ card_network="card_network",
+ category="category",
+ convert_to="convert_to",
+ currency="currency",
+ fee_type="fee_type",
+ interval="hour",
+ most_recent_action="most_recent_action",
+ payment_method="payment_method",
+ product="product",
+ referred_user_id="referred_user_id",
+ segment="segment",
+ snapshot_window="30d",
+ source="source",
+ status="status",
+ 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",
+ 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",
+ 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="",
+ 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 26dee7949..9972efc25 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 0b2c1c1dd..95586346f 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 ee5652170..0bff98c40 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,13 @@ 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",
+ from_="from",
+ include_balance_history=True,
+ interval="hour",
+ time_zone="time_zone",
+ to="to",
)
assert_matches_type(User, user, path=["response"])
@@ -43,7 +47,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 +59,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 +81,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 +89,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 +105,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 +117,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 +139,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 +147,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 +161,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 +171,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 +180,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 +189,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 +202,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 +224,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 +280,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 +288,13 @@ 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",
+ from_="from",
+ include_balance_history=True,
+ interval="hour",
+ time_zone="time_zone",
+ to="to",
)
assert_matches_type(User, user, path=["response"])
@@ -247,7 +302,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 +314,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 +336,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 +344,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 +360,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 +372,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 +394,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 +402,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 +416,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 +426,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 +435,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 +444,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 +457,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 +479,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 e1499aedc..50fc15ae8 100644
--- a/tests/api_resources/test_verifications.py
+++ b/tests/api_resources/test_verifications.py
@@ -9,8 +9,12 @@
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,
+ VerificationUpdateResponse,
+ VerificationRetrieveResponse,
+)
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -18,11 +22,130 @@
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_overload_1(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_overload_1(self, client: Whop) -> None:
+ verification = client.verifications.create(
+ account_id="account_id",
+ address={
+ "city": "city",
+ "country": "country",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
+ business_name="business_name",
+ business_structure="business_structure",
+ business_website="business_website",
+ country="country",
+ date_of_birth="date_of_birth",
+ document_type="ID_CARD",
+ documents={"foo": "string"},
+ first_name="first_name",
+ kind="individual",
+ last_name="last_name",
+ phone="phone",
+ 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_overload_1(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_overload_1(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_create_overload_2(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_overload_2(self, client: Whop) -> None:
+ verification = client.verifications.create(
+ account_id="account_id",
+ address={
+ "city": "city",
+ "country": "country",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
+ business_name="business_name",
+ business_structure="business_structure",
+ business_website="business_website",
+ country="country",
+ kind="business",
+ place_of_incorporation="place_of_incorporation",
+ 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_overload_2(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_overload_2(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 +153,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 +165,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,54 +178,221 @@ 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_overload_1(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_overload_1(self, client: Whop) -> None:
+ verification = client.verifications.update(
+ verification_id="verification_id",
+ country="country",
+ date_of_birth="date_of_birth",
+ first_name="first_name",
+ last_name="last_name",
+ personal_address={
+ "city": "city",
+ "country": "country",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
+ requested_information=[
+ {
+ "id": "id",
+ "address": {
+ "city": "city",
+ "country": "country",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
+ "files": [
+ {
+ "attachment_id": "attachment_id",
+ "category": "category",
+ "direct_upload_id": "direct_upload_id",
+ "kind": "kind",
+ }
+ ],
+ "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_overload_1(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_overload_1(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_overload_1(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_update_overload_2(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_overload_2(self, client: Whop) -> None:
+ verification = client.verifications.update(
+ verification_id="verification_id",
+ business_address={
+ "city": "city",
+ "country": "country",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
+ business_name="business_name",
+ business_structure="business_structure",
+ country="country",
+ requested_information=[
+ {
+ "id": "id",
+ "address": {
+ "city": "city",
+ "country": "country",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
+ "files": [
+ {
+ "attachment_id": "attachment_id",
+ "category": "category",
+ "direct_upload_id": "direct_upload_id",
+ "kind": "kind",
+ }
+ ],
+ "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_overload_2(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_overload_2(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_overload_2(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
@@ -112,11 +402,130 @@ class TestAsyncVerifications:
"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:
+ 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_overload_1(self, async_client: AsyncWhop) -> None:
+ verification = await async_client.verifications.create(
+ account_id="account_id",
+ address={
+ "city": "city",
+ "country": "country",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
+ business_name="business_name",
+ business_structure="business_structure",
+ business_website="business_website",
+ country="country",
+ date_of_birth="date_of_birth",
+ document_type="ID_CARD",
+ documents={"foo": "string"},
+ first_name="first_name",
+ kind="individual",
+ last_name="last_name",
+ phone="phone",
+ 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_overload_1(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_overload_1(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_create_overload_2(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_overload_2(self, async_client: AsyncWhop) -> None:
+ verification = await async_client.verifications.create(
+ account_id="account_id",
+ address={
+ "city": "city",
+ "country": "country",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
+ business_name="business_name",
+ business_structure="business_structure",
+ business_website="business_website",
+ country="country",
+ kind="business",
+ place_of_incorporation="place_of_incorporation",
+ 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_overload_2(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_overload_2(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 +533,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 +545,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 +558,220 @@ 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_overload_1(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_overload_1(self, async_client: AsyncWhop) -> None:
+ verification = await async_client.verifications.update(
+ verification_id="verification_id",
+ country="country",
+ date_of_birth="date_of_birth",
+ first_name="first_name",
+ last_name="last_name",
+ personal_address={
+ "city": "city",
+ "country": "country",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
+ requested_information=[
+ {
+ "id": "id",
+ "address": {
+ "city": "city",
+ "country": "country",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
+ "files": [
+ {
+ "attachment_id": "attachment_id",
+ "category": "category",
+ "direct_upload_id": "direct_upload_id",
+ "kind": "kind",
+ }
+ ],
+ "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_overload_1(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_overload_1(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_overload_1(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_update_overload_2(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_overload_2(self, async_client: AsyncWhop) -> None:
+ verification = await async_client.verifications.update(
+ verification_id="verification_id",
+ business_address={
+ "city": "city",
+ "country": "country",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
+ business_name="business_name",
+ business_structure="business_structure",
+ country="country",
+ requested_information=[
+ {
+ "id": "id",
+ "address": {
+ "city": "city",
+ "country": "country",
+ "line1": "line1",
+ "line2": "line2",
+ "postal_code": "postal_code",
+ "state": "state",
+ },
+ "files": [
+ {
+ "attachment_id": "attachment_id",
+ "category": "category",
+ "direct_upload_id": "direct_upload_id",
+ "kind": "kind",
+ }
+ ],
+ "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_overload_2(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_overload_2(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_overload_2(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
diff --git a/tests/api_resources/test_wallets.py b/tests/api_resources/test_wallets.py
deleted file mode 100644
index abc5ad157..000000000
--- 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 61e0d357e..ab6229222 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)
diff --git a/tests/api_resources/workforce/__init__.py b/tests/api_resources/workforce/__init__.py
new file mode 100644
index 000000000..fd8019a9a
--- /dev/null
+++ b/tests/api_resources/workforce/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/test_payout_methods.py b/tests/api_resources/workforce/test_bounties.py
similarity index 56%
rename from tests/api_resources/test_payout_methods.py
rename to tests/api_resources/workforce/test_bounties.py
index 5d1e24fdf..ba719a6ef 100644
--- a/tests/api_resources/test_payout_methods.py
+++ b/tests/api_resources/workforce/test_bounties.py
@@ -9,46 +9,46 @@
from whop_sdk import Whop, AsyncWhop
from tests.utils import assert_matches_type
-from whop_sdk.types import PayoutMethodListResponse, PayoutMethodRetrieveResponse
from whop_sdk.pagination import SyncCursorPage, AsyncCursorPage
+from whop_sdk.types.workforce import WorkforceBounty, WorkforceBountyListItem
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-class TestPayoutMethods:
+class TestBounties:
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:
- payout_method = client.payout_methods.retrieve(
- "potk_xxxxxxxxxxxxx",
+ bounty = client.workforce.bounties.retrieve(
+ "id",
)
- assert_matches_type(PayoutMethodRetrieveResponse, payout_method, path=["response"])
+ assert_matches_type(WorkforceBounty, bounty, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_raw_response_retrieve(self, client: Whop) -> None:
- response = client.payout_methods.with_raw_response.retrieve(
- "potk_xxxxxxxxxxxxx",
+ response = client.workforce.bounties.with_raw_response.retrieve(
+ "id",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- payout_method = response.parse()
- assert_matches_type(PayoutMethodRetrieveResponse, payout_method, path=["response"])
+ bounty = response.parse()
+ assert_matches_type(WorkforceBounty, bounty, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_streaming_response_retrieve(self, client: Whop) -> None:
- with client.payout_methods.with_streaming_response.retrieve(
- "potk_xxxxxxxxxxxxx",
+ with client.workforce.bounties.with_streaming_response.retrieve(
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- payout_method = response.parse()
- assert_matches_type(PayoutMethodRetrieveResponse, payout_method, path=["response"])
+ bounty = response.parse()
+ assert_matches_type(WorkforceBounty, bounty, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -56,58 +56,59 @@ def test_streaming_response_retrieve(self, client: Whop) -> None:
@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.payout_methods.with_raw_response.retrieve(
+ client.workforce.bounties.with_raw_response.retrieve(
"",
)
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_list(self, client: Whop) -> None:
- payout_method = client.payout_methods.list(
- company_id="biz_xxxxxxxxxxxxxx",
- )
- assert_matches_type(SyncCursorPage[PayoutMethodListResponse], payout_method, path=["response"])
+ bounty = client.workforce.bounties.list()
+ assert_matches_type(SyncCursorPage[WorkforceBountyListItem], bounty, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_list_with_all_params(self, client: Whop) -> None:
- payout_method = client.payout_methods.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ bounty = client.workforce.bounties.list(
+ account_id="account_id",
after="after",
before="before",
- first=42,
- last=42,
+ created_after="created_after",
+ created_before="created_before",
+ direction="asc",
+ first=100,
+ last=100,
+ order="created_at",
+ query="query",
+ status="scheduled",
+ user_id="user_id",
)
- assert_matches_type(SyncCursorPage[PayoutMethodListResponse], payout_method, path=["response"])
+ assert_matches_type(SyncCursorPage[WorkforceBountyListItem], bounty, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_raw_response_list(self, client: Whop) -> None:
- response = client.payout_methods.with_raw_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
- )
+ response = client.workforce.bounties.with_raw_response.list()
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- payout_method = response.parse()
- assert_matches_type(SyncCursorPage[PayoutMethodListResponse], payout_method, path=["response"])
+ bounty = response.parse()
+ assert_matches_type(SyncCursorPage[WorkforceBountyListItem], bounty, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_streaming_response_list(self, client: Whop) -> None:
- with client.payout_methods.with_streaming_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
- ) as response:
+ with client.workforce.bounties.with_streaming_response.list() as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- payout_method = response.parse()
- assert_matches_type(SyncCursorPage[PayoutMethodListResponse], payout_method, path=["response"])
+ bounty = response.parse()
+ assert_matches_type(SyncCursorPage[WorkforceBountyListItem], bounty, path=["response"])
assert cast(Any, response.is_closed) is True
-class TestAsyncPayoutMethods:
+class TestAsyncBounties:
parametrize = pytest.mark.parametrize(
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
)
@@ -115,34 +116,34 @@ class TestAsyncPayoutMethods:
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_method_retrieve(self, async_client: AsyncWhop) -> None:
- payout_method = await async_client.payout_methods.retrieve(
- "potk_xxxxxxxxxxxxx",
+ bounty = await async_client.workforce.bounties.retrieve(
+ "id",
)
- assert_matches_type(PayoutMethodRetrieveResponse, payout_method, path=["response"])
+ assert_matches_type(WorkforceBounty, bounty, 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.payout_methods.with_raw_response.retrieve(
- "potk_xxxxxxxxxxxxx",
+ response = await async_client.workforce.bounties.with_raw_response.retrieve(
+ "id",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- payout_method = await response.parse()
- assert_matches_type(PayoutMethodRetrieveResponse, payout_method, path=["response"])
+ bounty = await response.parse()
+ assert_matches_type(WorkforceBounty, bounty, 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.payout_methods.with_streaming_response.retrieve(
- "potk_xxxxxxxxxxxxx",
+ async with async_client.workforce.bounties.with_streaming_response.retrieve(
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- payout_method = await response.parse()
- assert_matches_type(PayoutMethodRetrieveResponse, payout_method, path=["response"])
+ bounty = await response.parse()
+ assert_matches_type(WorkforceBounty, bounty, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -150,52 +151,53 @@ async def test_streaming_response_retrieve(self, async_client: AsyncWhop) -> Non
@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.payout_methods.with_raw_response.retrieve(
+ await async_client.workforce.bounties.with_raw_response.retrieve(
"",
)
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_method_list(self, async_client: AsyncWhop) -> None:
- payout_method = await async_client.payout_methods.list(
- company_id="biz_xxxxxxxxxxxxxx",
- )
- assert_matches_type(AsyncCursorPage[PayoutMethodListResponse], payout_method, path=["response"])
+ bounty = await async_client.workforce.bounties.list()
+ assert_matches_type(AsyncCursorPage[WorkforceBountyListItem], bounty, 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_method = await async_client.payout_methods.list(
- company_id="biz_xxxxxxxxxxxxxx",
+ bounty = await async_client.workforce.bounties.list(
+ account_id="account_id",
after="after",
before="before",
- first=42,
- last=42,
+ created_after="created_after",
+ created_before="created_before",
+ direction="asc",
+ first=100,
+ last=100,
+ order="created_at",
+ query="query",
+ status="scheduled",
+ user_id="user_id",
)
- assert_matches_type(AsyncCursorPage[PayoutMethodListResponse], payout_method, path=["response"])
+ assert_matches_type(AsyncCursorPage[WorkforceBountyListItem], bounty, 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.payout_methods.with_raw_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
- )
+ response = await async_client.workforce.bounties.with_raw_response.list()
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- payout_method = await response.parse()
- assert_matches_type(AsyncCursorPage[PayoutMethodListResponse], payout_method, path=["response"])
+ bounty = await response.parse()
+ assert_matches_type(AsyncCursorPage[WorkforceBountyListItem], bounty, 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.payout_methods.with_streaming_response.list(
- company_id="biz_xxxxxxxxxxxxxx",
- ) as response:
+ async with async_client.workforce.bounties.with_streaming_response.list() as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- payout_method = await response.parse()
- assert_matches_type(AsyncCursorPage[PayoutMethodListResponse], payout_method, path=["response"])
+ bounty = await response.parse()
+ assert_matches_type(AsyncCursorPage[WorkforceBountyListItem], bounty, path=["response"])
assert cast(Any, response.is_closed) is True