@whop/cli 0.26.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -27909,7 +27909,7 @@ function resolveDisplayName(name, aliases) {
27909
27909
  }
27910
27910
 
27911
27911
  // src/cli.ts
27912
- import { join as join14 } from "path";
27912
+ import { join as join15 } from "path";
27913
27913
 
27914
27914
  // src/api/native-spec.json
27915
27915
  var native_spec_default = {
@@ -27919,7 +27919,7 @@ var native_spec_default = {
27919
27919
  termsOfService: "https://whop.com/tos-developer-api/",
27920
27920
  title: "Whop API",
27921
27921
  version: "1.0.0",
27922
- "x-api-version-date": "2026-10-13-1"
27922
+ "x-api-version-date": "2026-10-14"
27923
27923
  },
27924
27924
  servers: [
27925
27925
  {
@@ -28104,9 +28104,9 @@ var native_spec_default = {
28104
28104
  "x-whop-summary": "Turn a variant into a shareable, prefilled checkout link."
28105
28105
  },
28106
28106
  {
28107
- description: "A Payment Method Domain registers a hostname with a wallet provider so its payment methods can appear at a checkout served from that domain. The domain proves ownership by hosting the provider's association file \u2014 for Apple Pay, at `/.well-known/apple-developer-merchantid-domain-association` \u2014 and `status` reports whether verification has completed.\n\nUse the Payment Method Domains API to register domains for your account or its connected accounts, retry verification once the association file is hosted, and remove domains that should no longer serve wallet payments. A domain a platform shares with its connected accounts at checkout is listed on the platform's account, not on each connected account.\n\nWallet buttons at checkout depend on this: embedded surfaces like the [Express Checkout element](/elements/beta/checkout/expressCheckout) only render Apple Pay, Google Pay and PayPal express on a `verified` domain (first-party whop.com pages are pre-approved). To verify a domain, [create it](/api-reference/beta/payment-method-domains/create-payment-method-domain), host the association file at the path above, then [retry verification](/api-reference/beta/payment-method-domains/verify-payment-method-domain) until `status` is `verified`.\n",
28107
+ description: "The Payment Method Domains API is deprecated. Add, check, and remove Apple Pay domains with the `apple_pay` capability of the [Domains API](/api-reference/beta/domains/domain) instead. These endpoints keep working and return `Deprecation` and successor `Link` headers. A domain keeps its ID, so `/domains/{id}` takes the `dom_` or `pmd_` ID these endpoints return.\n\nA Payment Method Domain registers a hostname with a wallet provider so its payment methods can appear at a checkout served from that domain. The domain proves ownership by hosting the provider's association file \u2014 for Apple Pay, at `/.well-known/apple-developer-merchantid-domain-association` \u2014 and `status` reports whether verification has completed. Embedded surfaces like the [Express Checkout element](/elements/beta/checkout/expressCheckout) only render Apple Pay, Google Pay and PayPal express on a `verified` domain (first-party whop.com pages are pre-approved).\n\n| Payment Method Domains API | Domains API |\n| --- | --- |\n| `GET /payment_method_domains?status=verified` | `GET /domains?apple_pay=ready`, or `apple_pay=any` for every Apple Pay domain |\n| `?hostname=` | `?domain=` |\n| `GET /payment_method_domains/{id}` | `GET /domains/{id}` |\n| `POST /payment_method_domains` with `hostname` and `account_id` | `POST /domains` with `domain`, `account_id`, and `apple_pay: {}`. If the account already has the domain, `PATCH /domains/{id}` with `apple_pay: {}` |\n| `POST /payment_method_domains/{id}/verify` | `POST /domains/{id}/check` |\n| `DELETE /payment_method_domains/{id}` | `PATCH /domains/{id}` with `apple_pay: null` |\n| `hostname` | `domain` |\n| `status: verified` | `apple_pay.state: ready` |\n| `status: pending` | `apple_pay.state: pending` while Whop registers the domain, or `action_required` until you host the association file and check the domain |\n| `provider` | No field: every Apple Pay domain is registered with Apple |\n\nRegistration runs in the background, so creating or checking a domain returns `pending`: retrieve the domain until `apple_pay.state` is `ready` or `action_required`. The Domains API needs the `domain:read` and `domain:manage` permissions instead of `company:manage_checkout`, so give API keys those scopes. `DELETE /domains/{id}` removes the whole domain, including any website on it, so use `PATCH` to remove only Apple Pay.\n",
28108
28108
  name: "Payment Method Domains",
28109
- "x-whop-summary": "Domains verified to show wallet payment methods like Apple Pay at checkout."
28109
+ "x-whop-summary": "Deprecated: domains verified to show Apple Pay at checkout. Use Domains instead."
28110
28110
  },
28111
28111
  {
28112
28112
  description: "A Shipment attaches a carrier tracking number to a payment and follows the package from label creation to delivery, exposing the current delivery status and a customer-facing tracking URL.\n\nUse the Shipments API to list an account's shipments, retrieve one by its ID or the payment it fulfills, attach a tracking number to a payment, and update the tracking number on an existing shipment.\n",
@@ -28199,7 +28199,7 @@ var native_spec_default = {
28199
28199
  "x-whop-summary": "Deprecated compatibility endpoints for external accounts."
28200
28200
  },
28201
28201
  {
28202
- description: "An App is software you build on Whop. It can be a hosted web app served at `<route>.whop.site` or an API integration installed as an experience, and it belongs to the account that owns its credentials, settings, builds, and runtime logs.\n\nUse the Apps API to manage app configuration, deploy an app's working copy and follow the run on the app's `deployment` field, and, for hosted apps, read server runtime logs for console output, uncaught exceptions, and failed requests.\n\nApps are also reusable blueprints. List official blueprints with `app_type=website&verified=true&order=template_usage`, or community blueprints with `app_type=website&verified=false&recommended=true&order=template_usage`. Pass the returned App `id` as `blueprint_id` when creating an Account.\n",
28202
+ description: "An App is software you build on Whop. It can be a hosted web app served at its domains, such as a `whop.site` address or a custom domain, or an API integration installed as an experience, and it belongs to the account that owns its credentials, settings, builds, and runtime logs.\n\nUse the Apps API to manage app configuration, deploy an app's working copy and follow the run on the app's `deployment` field, and, for hosted apps, read server runtime logs for console output, uncaught exceptions, and failed requests.\n\nApps are also reusable blueprints. List official blueprints with `app_type=website&verified=true&order=template_usage`, or community blueprints with `app_type=website&verified=false&recommended=true&order=template_usage`. Pass the returned App `id` as `blueprint_id` when creating an Account.\n",
28203
28203
  name: "Apps",
28204
28204
  "x-whop-summary": "Apps you build on Whop: metadata, hosted builds, runtime logs."
28205
28205
  },
@@ -32748,6 +32748,11 @@ var native_spec_default = {
32748
32748
  description: "The account's business website, as an `http` or `https` URL of at most 255 characters. Also added to the account's `social_links` as a `website` entry. Pass `null` to clear the website; existing social links are left unchanged.",
32749
32749
  example: "https://shinetimedetail.com",
32750
32750
  type: ["string", "null"]
32751
+ },
32752
+ whop_partner_enabled: {
32753
+ description: "Set to `true` to turn on Whop Partner mode for the account, so its team can refer businesses and the account is paid partner commission on their sales. Recorded once; `false` is rejected.",
32754
+ example: true,
32755
+ type: "boolean"
32751
32756
  }
32752
32757
  },
32753
32758
  type: "object"
@@ -33550,7 +33555,7 @@ var native_spec_default = {
33550
33555
  }
33551
33556
  },
33552
33557
  {
33553
- description: "The field to sort by. Defaults to created_at. Stat columns (spend, impressions, \u2026) 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.",
33558
+ description: "The field to sort by. Defaults to created_at. Stat columns (spend, impressions, \u2026) 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, and link_clicks by the same Whop pixel page views.",
33554
33559
  in: "query",
33555
33560
  name: "order",
33556
33561
  required: false,
@@ -35264,7 +35269,7 @@ var native_spec_default = {
35264
35269
  }
35265
35270
  },
35266
35271
  {
35267
- description: "The field to sort by. Defaults to created_at. Stat columns (spend, impressions, \u2026) 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.",
35272
+ description: "The field to sort by. Defaults to created_at. Stat columns (spend, impressions, \u2026) 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, and link_clicks by the same Whop pixel page views.",
35268
35273
  in: "query",
35269
35274
  name: "order",
35270
35275
  required: false,
@@ -37555,7 +37560,7 @@ var native_spec_default = {
37555
37560
  }
37556
37561
  },
37557
37562
  {
37558
- description: "The field to sort by. Defaults to created_at. Stat columns (spend, impressions, \u2026) 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.",
37563
+ description: "The field to sort by. Defaults to created_at. Stat columns (spend, impressions, \u2026) 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, and link_clicks by the same Whop pixel page views.",
37559
37564
  in: "query",
37560
37565
  name: "order",
37561
37566
  required: false,
@@ -40212,7 +40217,6 @@ var native_spec_default = {
40212
40217
  },
40213
40218
  base_url: {
40214
40219
  description: "The base production URL where the app is hosted, such as `https://myapp.example.com`.",
40215
- example: "https://booking.shinetime.example",
40216
40220
  type: ["string", "null"]
40217
40221
  },
40218
40222
  domain_id: {
@@ -40487,7 +40491,7 @@ var native_spec_default = {
40487
40491
  },
40488
40492
  base_url: {
40489
40493
  description: "The base production URL where the app is hosted. Set to `null` to take the app proxy offline.",
40490
- example: "https://booking.shinetime.example",
40494
+ example: "https://shine-time-booking.whop.site",
40491
40495
  type: ["string", "null"]
40492
40496
  },
40493
40497
  dashboard_path: {
@@ -46970,7 +46974,7 @@ var native_spec_default = {
46970
46974
  },
46971
46975
  "/deposits": {
46972
46976
  post: {
46973
- description: "Returns the deposit methods for an account or user, including crypto addresses, bank transfer instructions, and, for a business, a hosted deposit page. Bitcoin deposits are converted to USDT on Plasma in the destination's wallet. Business destinations require no authentication.",
46977
+ description: "Returns the deposit methods for an account or user, including crypto addresses, bank transfer instructions, and, for a business, a hosted deposit page. Bitcoin deposits are converted to USDT on Plasma in the destination's wallet. Business destinations require no authentication. Pass `payment_method_id` to also charge a business's saved payment method for `amount` in USD and add it to the business's balance; that requires authentication with the `payment:charge` scope. The charge has no fees or taxes and does not count as revenue.",
46974
46978
  operationId: "create",
46975
46979
  parameters: [
46976
46980
  {
@@ -46983,7 +46987,7 @@ var native_spec_default = {
46983
46987
  schema: {
46984
46988
  properties: {
46985
46989
  amount: {
46986
- description: "Amount to prefill on hosted deposit page. Crypto deposits require a $10 minimum.",
46990
+ description: "Amount to prefill on hosted deposit page. Crypto deposits require a $10 minimum. With `payment_method_id`, the amount in USD to charge, and required.",
46987
46991
  example: 50,
46988
46992
  type: "number"
46989
46993
  },
@@ -46991,6 +46995,11 @@ var native_spec_default = {
46991
46995
  description: "Account ID to fund, `biz_` or `user_`. Any business resolves without authentication; a user account resolves only for that same authenticated user.",
46992
46996
  example: "biz_xxxxxxxxxxxxxx",
46993
46997
  type: "string"
46998
+ },
46999
+ payment_method_id: {
47000
+ description: "A saved payment method of the business to charge for `amount`, prefixed `payt_`. Save one with Create setup intent and `owner_id` set to the account. Only for a `biz_` destination, and requires authentication with the `payment:charge` scope. A declined charge fails the request with 400.",
47001
+ example: "payt_xxxxxxxxxxxxxx",
47002
+ type: "string"
46994
47003
  }
46995
47004
  },
46996
47005
  required: ["destination"],
@@ -47016,6 +47025,23 @@ var native_spec_default = {
47016
47025
  example: "50.00",
47017
47026
  type: "string"
47018
47027
  },
47028
+ card: {
47029
+ description: "The charge to a saved payment method. Null unless `payment_method_id` was passed.",
47030
+ properties: {
47031
+ payment_id: {
47032
+ description: "The payment the charge created, prefixed `pay_`. Retrieve it, or listen for `payment.succeeded`, to confirm the funds landed.",
47033
+ example: "pay_xxxxxxxxxxxxxx",
47034
+ type: "string"
47035
+ },
47036
+ payment_method_id: {
47037
+ description: "The saved payment method that was charged, prefixed `payt_`.",
47038
+ example: "payt_xxxxxxxxxxxxxx",
47039
+ type: "string"
47040
+ }
47041
+ },
47042
+ required: ["payment_method_id", "payment_id"],
47043
+ type: ["object", "null"]
47044
+ },
47019
47045
  hosted_url: {
47020
47046
  description: "URL of the hosted deposit page. Only present for business destinations.",
47021
47047
  example: "https://whop.com/deposit/biz_xxxxxxxxxxxxxx/",
@@ -47201,7 +47227,13 @@ var native_spec_default = {
47201
47227
  type: "string"
47202
47228
  }
47203
47229
  },
47204
- required: ["object", "account_id", "hosted_url", "methods"],
47230
+ required: [
47231
+ "object",
47232
+ "account_id",
47233
+ "hosted_url",
47234
+ "methods",
47235
+ "card"
47236
+ ],
47205
47237
  type: "object"
47206
47238
  }
47207
47239
  }
@@ -47220,6 +47252,9 @@ var native_spec_default = {
47220
47252
  {},
47221
47253
  {
47222
47254
  bearerAuth: ["payout:account:read"]
47255
+ },
47256
+ {
47257
+ bearerAuth: ["payment:charge"]
47223
47258
  }
47224
47259
  ],
47225
47260
  summary: "Create Deposit",
@@ -49003,10 +49038,6 @@ var native_spec_default = {
49003
49038
  $ref: "#/components/responses/InvalidParameters",
49004
49039
  description: "Invalid search"
49005
49040
  },
49006
- "403": {
49007
- $ref: "#/components/responses/Forbidden",
49008
- description: "Domain search is not available to this caller"
49009
- },
49010
49041
  "503": {
49011
49042
  $ref: "#/components/responses/ServiceUnavailable",
49012
49043
  description: "The registrar is unavailable"
@@ -49265,10 +49296,6 @@ var native_spec_default = {
49265
49296
  "400": {
49266
49297
  $ref: "#/components/responses/InvalidParameters",
49267
49298
  description: "Invalid hostname"
49268
- },
49269
- "403": {
49270
- $ref: "#/components/responses/Forbidden",
49271
- description: "Domain search is not available to this caller"
49272
49299
  }
49273
49300
  },
49274
49301
  security: [
@@ -52499,7 +52526,7 @@ var native_spec_default = {
52499
52526
  type: "array"
52500
52527
  },
52501
52528
  filters: {
52502
- description: "Resource-specific filters. For native REST resources (`payouts`, `transfers`, `products`) these are the resource's own list query params; for dashboard tables they mirror the dashboard table filters.\n\n<details>\n<summary>Filters by resource (25)</summary>\n\n<details>\n<summary>ad_campaigns (5)</summary>\n\nMirrors the filtering query params of `GET /api/v1/ad_campaigns`.\n\n- `campaign_type` `string` \u2014 Only return campaigns of this type. One of `standard`, `search`.\n- `created_after` `string` \u2014 Only return campaigns created after this timestamp.\n- `created_before` `string` \u2014 Only return campaigns created before this timestamp.\n- `query` `string` \u2014 Filter campaigns by a title or ID substring.\n- `status` `string` \u2014 Only return campaigns with this status. One of `draft`, `active`, `paused`, `payment_failed`.\n\n</details>\n<details>\n<summary>ad_groups (6)</summary>\n\nMirrors the filtering query params of `GET /api/v1/ad_groups`.\n\n- `ad_campaign_id` `string` \u2014 Filter to ad groups in this campaign.\n- `ad_campaign_ids` `string[]` \u2014 Filter to ad groups in these campaigns (max 100). Repeat the parameter for each id (ad_campaign_ids=a&ad_campaign_ids=b).\n- `created_after` `string` \u2014 Only return ad groups created after this timestamp.\n- `created_before` `string` \u2014 Only return ad groups created before this timestamp.\n- `query` `string` \u2014 Filter ad groups by a title or ID substring.\n- `status` `string` \u2014 Filter to ad groups with this status. One of `active`, `paused`, `rejected`, `duplicating`.\n\n</details>\n<details>\n<summary>ads (8)</summary>\n\nMirrors the filtering query params of `GET /api/v1/ads`.\n\n- `ad_campaign_id` `string` \u2014 Only return ads in this ad campaign.\n- `ad_campaign_ids` `string[]` \u2014 Only return ads in these ad campaigns (max 100). Repeat the parameter for each id (ad_campaign_ids=a&ad_campaign_ids=b).\n- `ad_group_id` `string` \u2014 Only return ads in this ad group.\n- `ad_group_ids` `string[]` \u2014 Only return ads in these ad groups (max 100). Repeat the parameter for each id (ad_group_ids=a&ad_group_ids=b).\n- `created_after` `string` \u2014 Only return ads created after this timestamp.\n- `created_before` `string` \u2014 Only return ads created before this timestamp.\n- `query` `string` \u2014 Filter ads by a title or ID substring.\n- `status` `string` \u2014 Only return ads with this status. One of `active`, `paused`, `in_review`, `rejected`.\n\n</details>\n<details>\n<summary>apps (6)</summary>\n\nMirrors the filtering query params of `GET /api/v1/apps`.\n\n- `app_type` `string` \u2014 Filter apps by the type of end-user they are built for. Apps of type `website` are left out unless you ask for them by name. One of `b2b_app`, `b2c_app`, `company_app`, `component`, `website`.\n- `query` `string` \u2014 A search string matched against app names.\n- `recommended` `boolean` \u2014 Only return apps Whop recommends (or, with `false`, only those it does not), independently of verification status.\n- `verified` `boolean` \u2014 Only return apps whose Whop verification status matches this value. Omit this filter to include every verification status the caller can see.\n- `verified_apps_only` `boolean` \u2014 Legacy compatibility filter. Use `verified` for field equality. `true` returns verified apps; clients pinned before `2026-08-25-2` retain the earlier public website discovery behavior.\n- `view_type` `string` \u2014 Only return apps supporting this view type, such as `dashboard` or `hub`. One of `hub`, `discover`, `dash`, `dashboard`, `analytics`, `skills`, `openapi`.\n\n</details>\n<details>\n<summary>audiences (3)</summary>\n\nMirrors the filtering query params of `GET /api/v1/audiences`.\n\n- `audience_id` `string` \u2014 Audience ID, prefixed `adaud_`, used to filter the response to one audience.\n- `audience_type` `string` \u2014 Filter by custom or lookalike audiences. One of `custom`, `lookalike`.\n- `source_type` `string` \u2014 Filter by uploaded customer lists, Whop People filters, or social engagement. One of `csv_upload`, `people_filter`, `engagement`.\n\n</details>\n<details>\n<summary>bounties (8)</summary>\n\nMirrors the filtering query params of `GET /api/v1/bounties`.\n\n- `business_goal_type` `string` \u2014 Filter by the poster's declared goal. Bounties created before the goal taxonomy carry no goal and never match this filter. One of `clipping`, `post_engagement`, `owned_account_growth`, `ugc_content`, `local_activation`, `data_capture`, `other`.\n- `country` `string` \u2014 Only bounties workable from this country, as an ISO 3166-1 alpha-2 code. Bounties with no country targeting are workable worldwide and always match.\n- `created_after` `string` \u2014 Only bounties created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only bounties created before this ISO 8601 timestamp.\n- `experience_id` `string` \u2014 Only bounties posted to this forum experience, prefixed `exp_`. An unknown experience, or one outside the caller's scope, matches nothing.\n- `query` `string` \u2014 Substring match on the bounty title or ID.\n- `status` `string` \u2014 Filter by lifecycle state. One of `scheduled`, `open`, `closed`, `completed`, `canceled`.\n- `user_id` `string` \u2014 List the bounties this user participated in (`user_` tag). Must be the authenticated user.\n\n</details>\n<details>\n<summary>bounty_submissions (4)</summary>\n\nMirrors the filtering query params of `GET /api/v1/bounty_submissions`.\n\n- `bounty_id` `string` \u2014 Only submissions on this bounty (`bnty_` tag).\n- `created_after` `string` \u2014 Only submissions created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only submissions created before this ISO 8601 timestamp.\n- `status` `string` \u2014 Filter by lifecycle state. One of `in_progress`, `submitted`, `approved`, `denied`.\n\n</details>\n<details>\n<summary>card_transactions (7)</summary>\n\nMirrors the filtering query params of `GET /api/v1/card_transactions`.\n\n- `card_id` `string[]` \u2014 Return only transactions charged to these cards, each prefixed `icrd_`.\n- `cardholder_id` `string[]` \u2014 Return only transactions on cards assigned to these users, each prefixed `user_`.\n- `created_after` `string` \u2014 Return only transactions authorized at or after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Return only transactions authorized at or before this ISO 8601 timestamp.\n- `status` `string` \u2014 Return only transactions with this status. One of `pending`, `completed`, `reversed`, `declined`.\n- `transaction_ids` `string[]` \u2014 Return only these card transactions, each prefixed `citx_`. Repeat the parameter, or pass one comma-separated value.\n- `user_id` `string` \u2014 The user whose personal card transactions to list, prefixed `user_`. Provide this or `account_id`. Only that user can read them.\n\n</details>\n<details>\n<summary>checkout_configurations (3)</summary>\n\nMirrors the filtering query params of `GET /api/v1/checkout_configurations`.\n\n- `created_after` `string` \u2014 Only return checkout configurations created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only return checkout configurations created before this ISO 8601 timestamp.\n- `plan_id` `string` \u2014 Only return checkout configurations for this variant ID, prefixed `plan_`.\n\n</details>\n<details>\n<summary>disputes (4)</summary>\n\nMirrors the filtering query params of `GET /api/v1/disputes`.\n\n- `created_after` `string` \u2014 Only disputes opened after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only disputes opened before this ISO 8601 timestamp.\n- `currency` `string` \u2014 Only disputes in this three-letter ISO currency.\n- `status` `string[]` \u2014 Only disputes in these statuses. Repeat the parameter to pass several \u2014 one paginated list covers all of them. Inquiries match only the `warning_` statuses. A `needs_response` dispute whose evidence deadline has passed reports and filters as `under_review` instead.\n\n</details>\n<details>\n<summary>events (14)</summary>\n\nMirrors the filtering query params of `GET /api/v1/events`.\n\n- `attribution_model` `string` \u2014 Attribution model for the source filter (defaults to last_touch). One of `last_touch`, `first_touch`.\n- `browser` `string` \u2014 Browser families to filter by, comma-separated (e.g. Chrome, Mobile Safari).\n- `city` `string` \u2014 Cities to filter by, comma-separated.\n- `country` `string` \u2014 Country codes to filter by, comma-separated.\n- `device` `string` \u2014 Device families to filter by, comma-separated (e.g. iPhone, Mac).\n- `event` `string` \u2014 Full event names to filter by, comma-separated (payment.completed, pixel.lead, pixel.page, pixel.custom:<name>) \u2014 the same vocabulary the events / people metrics use.\n- `from` `string` \u2014 Start of the time range as an ISO 8601 timestamp. Required when identifier is omitted.\n- `hostname` `string` \u2014 Page hostnames to filter by, comma-separated.\n- `identifier` `string` \u2014 Any hard identifier of the person: a person ID (prsn_*), user ID, email, phone number, or a tracking cookie value (wuid, anonymous ID, fbp/fbc/ttp/ga). Omit to list recent events for the account.\n- `os` `string` \u2014 Operating system families to filter by, comma-separated (e.g. iOS, Windows).\n- `page` `string` \u2014 Page paths to filter by, comma-separated.\n- `source` `string` \u2014 Canonical source path, exact or with a trailing :* prefix (whop:<campaign>:*, ext:meta:*, referrer:<domain>, direct, unknown). Selects conversions credited to this source.\n- `to` `string` \u2014 End of the time range as an ISO 8601 timestamp. Required when identifier is omitted; otherwise defaults to now.\n- `utm_source` `string` \u2014 utm_source values to filter by, comma-separated.\n\n</details>\n<details>\n<summary>external_accounts (5)</summary>\n\nMirrors the filtering query params of `GET /api/v1/external_accounts`.\n\n- `platform` `string` \u2014 Only return external accounts for the platform that is specified. One of `x`, `instagram`, `youtube`, `tiktok`, `facebook`, `discord`, `telegram`, `linkedin`, `snapchat`.\n- `scopes` `string[]` \u2014 Only return external accounts that have these scopes.\n- `trust_level` `string` \u2014 Only return external accounts linked with this trust level, such as `oauth` for accounts connected through OAuth. One of `oauth`, `verified`, `authorized`, `claimed`, `scraped`.\n- `user_id` `string` \u2014 The User that the external accounts are connected to. Provide either this or account_id.\n- `verified` `boolean` \u2014 Only return external accounts that are verified on the platform.\n\n</details>\n<details>\n<summary>financial-activity (15)</summary>\n\nMirrors the filtering query params of `GET /api/v1/financial_activity`.\n\n- `activity_id` `string` \u2014 Optional ledger activity ID (for example `line_3`). Returns at most that one activity.\n- `available_after` `string` \u2014 Only include balance credits and debits available on or after this `YYYY-MM-DD` date (UTC), distinct from posted_at. Requires currency.\n- `available_before` `string` \u2014 Only include balance credits and debits available on or before this `YYYY-MM-DD` date (UTC). Set equal to available_after for a single day. Requires currency.\n- `balance_type` `string` \u2014 Which balance the activity changes. `total` includes available, pending, and reserved funds. `available` includes only movements into or out of available funds, including reservations, releases, and fees. Movements within the selected balance are omitted. Omit to preserve the existing activity feed. Requires account_id or user_id; cannot be combined with available_after or available_before. One of `total`, `available`.\n- `currency` `string` \u2014 Optional currency code filter, for example `usd`.\n- `exclude_internal_movements` `boolean` \u2014 Whether to exclude balance reservations and balanced movements between the account's own balances.\n- `include_owned_accounts` `boolean` \u2014 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`.\n- `include_resource` `boolean` \u2014 Whether to include the `resource` field in the response or not. Consider passing `false` if you need a fast response without as many rich details.\n- `line_types` `string[]` \u2014 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.\n- `payment_id` `string` \u2014 Filter activity by payment ID (pay_), including related refunds, disputes, and fees. Combines with resource_id and other filters within the selected accounts. Unknown payments return an empty list.\n- `posted_after` `string` \u2014 Only include rows posted after this ISO 8601 timestamp.\n- `posted_before` `string` \u2014 Only include rows posted before this ISO 8601 timestamp.\n- `resource_id` `string` \u2014 Optional prefixed resource ID. Returns activity associated with that resource.\n- `user_id` `string` \u2014 The owning user ID (a user_ identifier). Provide this or account_id.\n- `withdrawal_id` `string` \u2014 Withdrawal ID (wdrl_). With balance_type=available, selects the same period as its statement, after the previous withdrawal and through this withdrawal, excluding this withdrawal and its fee. Requires a single account. Overrides currency and posted-date filters.\n\n</details>\n<details>\n<summary>members (11)</summary>\n\nMirrors the filtering query params of `GET /api/v1/members`.\n\n- `access_level` `string` \u2014 Filter by what the member can reach on the account. One of `no_access`, `admin`, `customer`.\n- `created_after` `string` \u2014 Only members who joined after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only members who joined before this ISO 8601 timestamp.\n- `membership_status` `string` \u2014 `active` returns members holding at least one membership that currently grants access; `inactive` returns members holding at least one membership that does not. Combined with `product_ids`, `plan_ids`, or `promo_code_ids`, one membership must match all of them. One of `active`, `inactive`.\n- `most_recent_actions` `string[]` \u2014 Only return members whose `most_recent_action` is one of these values.\n- `plan_ids` `string[]` \u2014 Only return members holding a membership on one of these plans, prefixed `plan_`. Unknown IDs match nothing.\n- `product_ids` `string[]` \u2014 Only return members holding a membership to one of these products, prefixed `prod_`. Unknown IDs match nothing.\n- `promo_code_ids` `string[]` \u2014 Only return members holding a membership bought with one of these promo codes, prefixed `promo_`. Unknown IDs match nothing.\n- `query` `string` \u2014 Search members by name or username. An exact email address also matches when the credential holds the member:email:read scope.\n- `status` `string` \u2014 Filter by whether the member is still part of the account. One of `joined`, `left`.\n- `user_ids` `string[]` \u2014 Only return members whose users match these `user_` identifiers.\n\n</details>\n<details>\n<summary>memberships (11)</summary>\n\nMirrors the filtering query params of `GET /api/v1/memberships`.\n\n- `created_after` `string` \u2014 Only memberships created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only memberships created before this ISO 8601 timestamp.\n- `member_id` `string` \u2014 Narrow to one member's memberships (`mber_` tag), including memberships bought by another business. A member outside the caller's visible set returns an empty list.\n- `plan_id` `string` \u2014 Filter to memberships of this variant (`plan_` tag).\n- `plan_ids` `string[]` \u2014 Filter to memberships of any of these variants, each prefixed `plan_`. Repeat the parameter to pass several.\n- `product_id` `string` \u2014 Filter to memberships of this product (`prod_` tag).\n- `product_ids` `string[]` \u2014 Filter to memberships of any of these products, each prefixed `prod_`. Repeat the parameter to pass several.\n- `promo_code_ids` `string[]` \u2014 Filter to memberships discounted by any of these promo codes, each prefixed `promo_`. Repeat the parameter to pass several.\n- `status` `string` \u2014 Filter by billing state. `trialing`, `active`, `past_due`, `completed`, `canceled`, and `expired` match the membership's `status`; `active`, `trialing`, and `past_due` exclude memberships set to cancel at period end. The other values are derived buckets that never appear as a `status`: `canceling` matches memberships set to cancel at period end; `paused` matches memberships with payment collection paused; `expiring` matches one-time purchases that have not yet expired; `one_time` matches one-time purchases that never expire; `unclaimed` matches memberships with no buyer user, including memberships bought by another business; `banned` matches memberships whose buyer is banned from the account. One of `active`, `trialing`, `past_due`, `completed`, `canceled`, `expired`, `canceling`, `paused`, `expiring`, `one_time`, `unclaimed`, `banned`.\n- `statuses` `string[]` \u2014 Filter to memberships matching any of these billing states, with the same meanings as `status`. Repeat the parameter to pass several. Combined with `status` when both are sent.\n- `user_id` `string` \u2014 Narrow to one user's memberships (`user_` tag, or `me` for the caller). A user outside the caller's visible set returns an empty list.\n\n</details>\n<details>\n<summary>payouts (7)</summary>\n\nMirrors the filtering query params of `GET /api/v1/payouts`.\n\n- `created_after` `string` \u2014 Only payouts created at or after this ISO 8601 time (inclusive).\n- `created_before` `string` \u2014 Only payouts created before this ISO 8601 time (exclusive).\n- `currency` `string` \u2014 Optional currency code filter, for example `usd`.\n- `payout_method_id` `string` \u2014 Filter to payouts sent to one saved payout method (a pytk_ identifier). An unknown id matches nothing.\n- `source` `string` \u2014 Filter by how the payout was created. Payouts created before source tracking or through internal tooling carry no source and never match. One of `api`, `dashboard`, `automatic`.\n- `status` `string` \u2014 Filter to payouts whose `status` reads this word, matching exactly what this version displays \u2014 `reversed` finds settled payouts the bank later returned. Requires Api-Version-Date 2026-08-21 or later. One of `requested`, `in_review`, `processing`, `completed`, `reversed`, `canceled`, `failed`, `denied`.\n- `user_id` `string` \u2014 The owning user ID (a user_ identifier). Provide this or account_id.\n\n</details>\n<details>\n<summary>people (39)</summary>\n\nMirrors the filtering query params of `GET /api/v1/people`.\n\n- `aov_gt` `number` \u2014 Select people whose lifetime aov is greater than this value. LTV and AOV are in USD.\n- `aov_gte` `number` \u2014 Select people whose lifetime aov is at least this value. LTV and AOV are in USD.\n- `aov_lt` `number` \u2014 Select people whose lifetime aov is less than this value. LTV and AOV are in USD.\n- `aov_lte` `number` \u2014 Select people whose lifetime aov is at most this value. LTV and AOV are in USD.\n- `attribution_model` `string` \u2014 Attribution model the source filter matches against (defaults to last_touch). One of `last_touch`, `first_touch`.\n- `audience_id` `string` \u2014 Only include people in this audience. An audience that keeps itself up to date resolves to the People filters that define it, so this always reflects who matches now; uploaded lists and point-in-time snapshots match their recorded members.\n- `contactable` `boolean` \u2014 true for people who have an email address or phone number \u2014 the ones an ad platform can match.\n- `country` `string` \u2014 Only include people with activity from this ISO 3166-1 alpha-2 country code.\n- `custom_event` `string` \u2014 Only include people who fired this custom pixel event.\n- `email` `string` \u2014 Only include the person linked to this email address.\n- `event_count_gt` `number` \u2014 Select people whose lifetime event_count is greater than this value. LTV and AOV are in USD.\n- `event_count_gte` `number` \u2014 Select people whose lifetime event_count is at least this value. LTV and AOV are in USD.\n- `event_count_lt` `number` \u2014 Select people whose lifetime event_count is less than this value. LTV and AOV are in USD.\n- `event_count_lte` `number` \u2014 Select people whose lifetime event_count is at most this value. LTV and AOV are in USD.\n- `event_from` `string` \u2014 The inclusive start of the matching activity window.\n- `event_name` `string[]` \u2014 Only include people who fired any of these events, e.g. payment.completed or page.checkout.view.\n- `event_to` `string` \u2014 The inclusive end of the matching activity window, for both stats drilldowns and saved audiences.\n- `event_within_days` `integer` \u2014 Match activity within a rolling number of days. Cannot be combined with event_from/event_to.\n- `first_seen_after` `string` \u2014 Only include people first seen at or after this ISO 8601 timestamp.\n- `first_seen_before` `string` \u2014 Only include people first seen before this ISO 8601 timestamp.\n- `first_seen_within_days` `integer` \u2014 Only include people first seen within this many days, as a rolling window.\n- `from` `string` \u2014 Inclusive activity-window start. Alias for event_from.\n- `has_purchased` `boolean` \u2014 true for customers only, false for people who have never purchased.\n- `last_seen_after` `string` \u2014 Only include people last seen at or after this ISO 8601 timestamp.\n- `last_seen_before` `string` \u2014 Only include people last seen before this ISO 8601 timestamp.\n- `last_seen_within_days` `integer` \u2014 Only include people last seen within this many days, as a rolling window.\n- `ltv_gt` `number` \u2014 Select people whose lifetime ltv is greater than this value. LTV and AOV are in USD.\n- `ltv_gte` `number` \u2014 Select people whose lifetime ltv is at least this value. LTV and AOV are in USD.\n- `ltv_lt` `number` \u2014 Select people whose lifetime ltv is less than this value. LTV and AOV are in USD.\n- `ltv_lte` `number` \u2014 Select people whose lifetime ltv is at most this value. LTV and AOV are in USD.\n- `phone` `string` \u2014 Only include the person linked to this phone number.\n- `purchase_count_gt` `number` \u2014 Select people whose lifetime purchase_count is greater than this value. LTV and AOV are in USD.\n- `purchase_count_gte` `number` \u2014 Select people whose lifetime purchase_count is at least this value. LTV and AOV are in USD.\n- `purchase_count_lt` `number` \u2014 Select people whose lifetime purchase_count is less than this value. LTV and AOV are in USD.\n- `purchase_count_lte` `number` \u2014 Select people whose lifetime purchase_count is at most this value. LTV and AOV are in USD.\n- `query` `string` \u2014 Search people by name, email, phone, or whop user ID (case-insensitive substring match).\n- `source` `string[]` \u2014 Only include people acquired from any of these sources \u2014 canonical paths (whop:<campaign>:<group>:<ad>, ext:<platform>:..., referrer:<domain>, direct, other), exact or with a trailing :* prefix. The same vocabulary the events / people metrics use.\n- `to` `string` \u2014 Inclusive activity-window end. Alias for event_to.\n- `user_id` `string` \u2014 Only include the person linked to this whop user ID.\n\n</details>\n<details>\n<summary>products (10)</summary>\n\nMirrors the filtering query params of `GET /api/v1/products`.\n\n- `access_pass_types` `string[]` \u2014 Filter to only products matching these types.\n- `created_after` `string` \u2014 Only return products created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only return products created before this ISO 8601 timestamp.\n- `labels` `string[]` \u2014 Filter to only products carrying all of these labels. Labels are matched lowercased.\n- `marketplace_category_route` `string` \u2014 Only return marketplace products assigned to this category route, such as `trading`.\n- `plan_types` `string[]` \u2014 Filter to products with a buyable variant of these billing models, such as `one_time` or `renewal`.\n- `price_maximum` `number` \u2014 Only return products whose advertised buyable variant has a displayed price of at most this amount. Recurring variants use renewal price.\n- `price_minimum` `number` \u2014 Only return products whose advertised buyable variant has a displayed price of at least this amount. Recurring variants use renewal price.\n- `query` `string` \u2014 Filters products by text. The public marketplace list searches product title, account name, headline and description, ranking products that match every word first and the closest partial matches after them; an account's own list is a plain substring match over title, headline and description. Omit to browse by recency.\n- `visibilities` `string[]` \u2014 Filter to only products matching these visibility states. Ignored on the public marketplace list, which only returns visible products.\n\n</details>\n<details>\n<summary>promo_codes (5)</summary>\n\nMirrors the filtering query params of `GET /api/v1/promo_codes`.\n\n- `created_after` `string` \u2014 Only promo codes created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only promo codes created before this ISO 8601 timestamp.\n- `plan_ids` `string[]` \u2014 Only promo codes scoped to these variant IDs.\n- `product_ids` `string[]` \u2014 Only promo codes scoped to these product IDs.\n- `status` `string` \u2014 Promo-code status. `expired` groups inactive and archived codes. One of `active`, `inactive`, `archived`, `expired`.\n\n</details>\n<details>\n<summary>resolution_center_cases (6)</summary>\n\nMirrors the filtering query params of `GET /api/v1/resolution_center_cases`.\n\n- `created_after` `string` \u2014 Only cases created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only cases created before this ISO 8601 timestamp.\n- `outcome` `string[]` \u2014 Only closed cases that ended these ways. Repeat the parameter to pass several.\n- `reason` `string[]` \u2014 Only cases opened for these reasons. Repeat the parameter to pass several.\n- `status` `string[]` \u2014 Only cases in these statuses. Repeat the parameter to pass several \u2014 one paginated list covers all of them.\n- `user_id` `string` \u2014 Only cases opened by this customer \u2014 a `user_` tag, or `me` for the calling user. It narrows what you can already read, so `me` lists the cases you opened without the ones on accounts you are a team member of.\n\n</details>\n<details>\n<summary>shipments (4)</summary>\n\nMirrors the filtering query params of `GET /api/v1/shipments`.\n\n- `created_after` `string` \u2014 Return shipments created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Return shipments created before this ISO 8601 timestamp.\n- `payment_id` `string[]` \u2014 Only shipments fulfilling these payments, each prefixed `pay_`. Repeat the parameter to pass several, up to 100 per request \u2014 one paginated list covers all of them.\n- `status` `string` \u2014 Filter to shipments with this delivery status. One of `unknown`, `pre_transit`, `in_transit`, `out_for_delivery`, `delivered`, `available_for_pickup`, `return_to_sender`, `failure`, `cancelled`, `error`.\n\n</details>\n<details>\n<summary>social_accounts (5)</summary>\n\nMirrors the filtering query params of `GET /api/v1/social_accounts`.\n\n- `platform` `string` \u2014 Only return external accounts for the platform that is specified. One of `x`, `instagram`, `youtube`, `tiktok`, `facebook`, `discord`, `telegram`, `linkedin`, `snapchat`.\n- `scopes` `string[]` \u2014 Only return external accounts that have these scopes.\n- `trust_level` `string` \u2014 Only return external accounts linked with this trust level, such as `oauth` for accounts connected through OAuth. One of `oauth`, `verified`, `authorized`, `claimed`, `scraped`.\n- `user_id` `string` \u2014 The User that the external accounts are connected to. Provide either this or account_id.\n- `verified` `boolean` \u2014 Only return external accounts that are verified on the platform.\n\n</details>\n<details>\n<summary>team_members (5)</summary>\n\nMirrors the filtering query params of `GET /api/v1/team_members`.\n\n- `created_after` `string` \u2014 Only return members added after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only return members added before this ISO 8601 timestamp.\n- `role` `string` \u2014 Only return members with this role. `custom` matches members on a dashboard-managed custom role. One of `owner`, `admin`, `partner`, `sales_manager`, `moderator`, `advertiser`, `app_manager`, `support`, `manager`, `workforce`, `custom`.\n- `status` `string` \u2014 Only return members with this status: `joined` (accepted members) or `pending` (pending invites). Both are returned by default. One of `joined`, `pending`.\n- `user_id` `string` \u2014 Only return the membership for this user ID, prefixed `user_`.\n\n</details>\n<details>\n<summary>transfers (4)</summary>\n\nMirrors the filtering query params of `GET /api/v1/transfers`.\n\n- `created_after` `string` \u2014 Only transfers created strictly after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only transfers created strictly before this ISO 8601 timestamp.\n- `destination_id` `string` \u2014 Filter to transfers received by this account.\n- `origin_id` `string` \u2014 Filter to transfers sent from this account.\n\n</details>\n<details>\n<summary>webhooks (3)</summary>\n\nMirrors the filtering query params of `GET /api/v1/webhooks`.\n\n- `app_id` `string` \u2014 Only return webhooks attached to this app. Omit to list the account's own webhooks.\n- `has_failures` `boolean` \u2014 Only return webhooks whose endpoint is currently failing \u2014 every delivery since the current failure streak began has been rejected. Clears as soon as a delivery succeeds.\n- `include_app_webhooks` `boolean` \u2014 Also return webhooks attached to the account's apps, not just the account's own. Cannot be combined with `app_id`.\n\n</details>\n</details>",
52529
+ description: "Resource-specific filters. For native REST resources (`payouts`, `transfers`, `products`) these are the resource's own list query params; for dashboard tables they mirror the dashboard table filters.\n\n<details>\n<summary>Filters by resource (25)</summary>\n\n<details>\n<summary>ad_campaigns (5)</summary>\n\nMirrors the filtering query params of `GET /api/v1/ad_campaigns`.\n\n- `campaign_type` `string` \u2014 Only return campaigns of this type. One of `standard`, `search`.\n- `created_after` `string` \u2014 Only return campaigns created after this timestamp.\n- `created_before` `string` \u2014 Only return campaigns created before this timestamp.\n- `query` `string` \u2014 Filter campaigns by a title or ID substring.\n- `status` `string` \u2014 Only return campaigns with this status. One of `draft`, `active`, `paused`, `payment_failed`.\n\n</details>\n<details>\n<summary>ad_groups (6)</summary>\n\nMirrors the filtering query params of `GET /api/v1/ad_groups`.\n\n- `ad_campaign_id` `string` \u2014 Filter to ad groups in this campaign.\n- `ad_campaign_ids` `string[]` \u2014 Filter to ad groups in these campaigns (max 100). Repeat the parameter for each id (ad_campaign_ids=a&ad_campaign_ids=b).\n- `created_after` `string` \u2014 Only return ad groups created after this timestamp.\n- `created_before` `string` \u2014 Only return ad groups created before this timestamp.\n- `query` `string` \u2014 Filter ad groups by a title or ID substring.\n- `status` `string` \u2014 Filter to ad groups with this status. One of `active`, `paused`, `rejected`, `duplicating`.\n\n</details>\n<details>\n<summary>ads (8)</summary>\n\nMirrors the filtering query params of `GET /api/v1/ads`.\n\n- `ad_campaign_id` `string` \u2014 Only return ads in this ad campaign.\n- `ad_campaign_ids` `string[]` \u2014 Only return ads in these ad campaigns (max 100). Repeat the parameter for each id (ad_campaign_ids=a&ad_campaign_ids=b).\n- `ad_group_id` `string` \u2014 Only return ads in this ad group.\n- `ad_group_ids` `string[]` \u2014 Only return ads in these ad groups (max 100). Repeat the parameter for each id (ad_group_ids=a&ad_group_ids=b).\n- `created_after` `string` \u2014 Only return ads created after this timestamp.\n- `created_before` `string` \u2014 Only return ads created before this timestamp.\n- `query` `string` \u2014 Filter ads by a title or ID substring.\n- `status` `string` \u2014 Only return ads with this status. One of `active`, `paused`, `in_review`, `rejected`.\n\n</details>\n<details>\n<summary>apps (6)</summary>\n\nMirrors the filtering query params of `GET /api/v1/apps`.\n\n- `app_type` `string` \u2014 Filter apps by the type of end-user they are built for. Apps of type `website` are left out unless you ask for them by name. One of `b2b_app`, `b2c_app`, `company_app`, `component`, `website`.\n- `query` `string` \u2014 A search string matched against app names.\n- `recommended` `boolean` \u2014 Only return apps Whop recommends (or, with `false`, only those it does not), independently of verification status.\n- `verified` `boolean` \u2014 Only return apps whose Whop verification status matches this value. Omit this filter to include every verification status the caller can see.\n- `verified_apps_only` `boolean` \u2014 Legacy compatibility filter. Use `verified` for field equality. `true` returns verified apps; clients pinned before `2026-08-25-2` retain the earlier public website discovery behavior.\n- `view_type` `string` \u2014 Only return apps supporting this view type, such as `dashboard` or `hub`. One of `hub`, `discover`, `dash`, `dashboard`, `analytics`, `skills`, `openapi`.\n\n</details>\n<details>\n<summary>audiences (3)</summary>\n\nMirrors the filtering query params of `GET /api/v1/audiences`.\n\n- `audience_id` `string` \u2014 Audience ID, prefixed `adaud_`, used to filter the response to one audience.\n- `audience_type` `string` \u2014 Filter by custom or lookalike audiences. One of `custom`, `lookalike`.\n- `source_type` `string` \u2014 Filter by uploaded customer lists, Whop People filters, or social engagement. One of `csv_upload`, `people_filter`, `engagement`.\n\n</details>\n<details>\n<summary>bounties (8)</summary>\n\nMirrors the filtering query params of `GET /api/v1/bounties`.\n\n- `business_goal_type` `string` \u2014 Filter by the poster's declared goal. Bounties created before the goal taxonomy carry no goal and never match this filter. One of `clipping`, `post_engagement`, `owned_account_growth`, `ugc_content`, `local_activation`, `data_capture`, `other`.\n- `country` `string` \u2014 Only bounties workable from this country, as an ISO 3166-1 alpha-2 code. Bounties with no country targeting are workable worldwide and always match.\n- `created_after` `string` \u2014 Only bounties created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only bounties created before this ISO 8601 timestamp.\n- `experience_id` `string` \u2014 Only bounties posted to this forum experience, prefixed `exp_`. An unknown experience, or one outside the caller's scope, matches nothing.\n- `query` `string` \u2014 Substring match on the bounty title or ID.\n- `status` `string` \u2014 Filter by lifecycle state. One of `scheduled`, `open`, `closed`, `completed`, `canceled`.\n- `user_id` `string` \u2014 List the bounties this user participated in (`user_` tag). Must be the authenticated user.\n\n</details>\n<details>\n<summary>bounty_submissions (4)</summary>\n\nMirrors the filtering query params of `GET /api/v1/bounty_submissions`.\n\n- `bounty_id` `string` \u2014 Only submissions on this bounty (`bnty_` tag).\n- `created_after` `string` \u2014 Only submissions created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only submissions created before this ISO 8601 timestamp.\n- `status` `string` \u2014 Filter by lifecycle state. One of `in_progress`, `submitted`, `approved`, `denied`.\n\n</details>\n<details>\n<summary>card_transactions (7)</summary>\n\nMirrors the filtering query params of `GET /api/v1/card_transactions`.\n\n- `card_id` `string[]` \u2014 Return only transactions charged to these cards, each prefixed `icrd_`.\n- `cardholder_id` `string[]` \u2014 Return only transactions on cards assigned to these users, each prefixed `user_`.\n- `created_after` `string` \u2014 Return only transactions authorized at or after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Return only transactions authorized at or before this ISO 8601 timestamp.\n- `status` `string` \u2014 Return only transactions with this status. One of `pending`, `completed`, `reversed`, `declined`.\n- `transaction_ids` `string[]` \u2014 Return only these card transactions, each prefixed `citx_`. Repeat the parameter, or pass one comma-separated value.\n- `user_id` `string` \u2014 The user whose personal card transactions to list, prefixed `user_`. Provide this or `account_id`. Only that user can read them.\n\n</details>\n<details>\n<summary>checkout_configurations (3)</summary>\n\nMirrors the filtering query params of `GET /api/v1/checkout_configurations`.\n\n- `created_after` `string` \u2014 Only return checkout configurations created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only return checkout configurations created before this ISO 8601 timestamp.\n- `plan_id` `string` \u2014 Only return checkout configurations for this variant ID, prefixed `plan_`.\n\n</details>\n<details>\n<summary>disputes (4)</summary>\n\nMirrors the filtering query params of `GET /api/v1/disputes`.\n\n- `created_after` `string` \u2014 Only disputes opened after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only disputes opened before this ISO 8601 timestamp.\n- `currency` `string` \u2014 Only disputes in this three-letter ISO currency.\n- `status` `string[]` \u2014 Only disputes in these statuses. Repeat the parameter to pass several \u2014 one paginated list covers all of them. Inquiries match only the `warning_` statuses. A `needs_response` dispute whose evidence deadline has passed reports and filters as `under_review` instead.\n\n</details>\n<details>\n<summary>events (14)</summary>\n\nMirrors the filtering query params of `GET /api/v1/events`.\n\n- `attribution_model` `string` \u2014 Attribution model for the source filter (defaults to last_touch). One of `last_touch`, `first_touch`.\n- `browser` `string` \u2014 Browser families to filter by, comma-separated (e.g. Chrome, Mobile Safari).\n- `city` `string` \u2014 Cities to filter by, comma-separated.\n- `country` `string` \u2014 Country codes to filter by, comma-separated.\n- `device` `string` \u2014 Device families to filter by, comma-separated (e.g. iPhone, Mac).\n- `event` `string` \u2014 Full event names to filter by, comma-separated (payment.completed, pixel.lead, pixel.page, pixel.custom:<name>) \u2014 the same vocabulary the events / people metrics use.\n- `from` `string` \u2014 Start of the time range as an ISO 8601 timestamp. Required when identifier is omitted.\n- `hostname` `string` \u2014 Page hostnames to filter by, comma-separated.\n- `identifier` `string` \u2014 Any hard identifier of the person: a person ID (prsn_*), user ID, email, phone number, or a tracking cookie value (wuid, anonymous ID, fbp/fbc/ttp/ga). Omit to list recent events for the account.\n- `os` `string` \u2014 Operating system families to filter by, comma-separated (e.g. iOS, Windows).\n- `page` `string` \u2014 Page paths to filter by, comma-separated.\n- `source` `string` \u2014 Canonical source path, exact or with a trailing :* prefix (whop:<campaign>:*, ext:meta:*, referrer:<domain>, direct, unknown). Selects conversions credited to this source.\n- `to` `string` \u2014 End of the time range as an ISO 8601 timestamp. Required when identifier is omitted; otherwise defaults to now.\n- `utm_source` `string` \u2014 utm_source values to filter by, comma-separated.\n\n</details>\n<details>\n<summary>external_accounts (5)</summary>\n\nMirrors the filtering query params of `GET /api/v1/external_accounts`.\n\n- `platform` `string` \u2014 Only return external accounts for the platform that is specified. One of `x`, `instagram`, `youtube`, `tiktok`, `facebook`, `discord`, `telegram`, `linkedin`, `snapchat`.\n- `scopes` `string[]` \u2014 Only return external accounts that have these scopes.\n- `trust_level` `string` \u2014 Only return external accounts linked with this trust level, such as `oauth` for accounts connected through OAuth. One of `oauth`, `verified`, `authorized`, `claimed`, `scraped`.\n- `user_id` `string` \u2014 The User that the external accounts are connected to. Provide either this or account_id.\n- `verified` `boolean` \u2014 Only return external accounts that are verified on the platform.\n\n</details>\n<details>\n<summary>financial-activity (15)</summary>\n\nMirrors the filtering query params of `GET /api/v1/financial_activity`.\n\n- `activity_id` `string` \u2014 Optional ledger activity ID (for example `line_3`). Returns at most that one activity.\n- `available_after` `string` \u2014 Only include balance credits and debits available on or after this `YYYY-MM-DD` date (UTC), distinct from posted_at. Requires currency.\n- `available_before` `string` \u2014 Only include balance credits and debits available on or before this `YYYY-MM-DD` date (UTC). Set equal to available_after for a single day. Requires currency.\n- `balance_type` `string` \u2014 Which balance the activity changes. `total` includes available, pending, and reserved funds. `available` includes only movements into or out of available funds, including reservations, releases, and fees. Movements within the selected balance are omitted. Omit to preserve the existing activity feed. Requires account_id or user_id; cannot be combined with available_after or available_before. One of `total`, `available`.\n- `currency` `string` \u2014 Optional currency code filter, for example `usd`.\n- `exclude_internal_movements` `boolean` \u2014 Whether to exclude balance reservations and balanced movements between the account's own balances.\n- `include_owned_accounts` `boolean` \u2014 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`.\n- `include_resource` `boolean` \u2014 Whether to include the `resource` field in the response or not. Consider passing `false` if you need a fast response without as many rich details.\n- `line_types` `string[]` \u2014 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.\n- `payment_id` `string` \u2014 Filter activity by payment ID (pay_), including related refunds, disputes, and fees. Combines with resource_id and other filters within the selected accounts. Unknown payments return an empty list.\n- `posted_after` `string` \u2014 Only include rows posted after this ISO 8601 timestamp.\n- `posted_before` `string` \u2014 Only include rows posted before this ISO 8601 timestamp.\n- `resource_id` `string` \u2014 Optional prefixed resource ID. Returns activity associated with that resource.\n- `user_id` `string` \u2014 The owning user ID (a user_ identifier). Provide this or account_id.\n- `withdrawal_id` `string` \u2014 Withdrawal ID (wdrl_). With balance_type=available, selects the same period as its statement, after the previous withdrawal and through this withdrawal, excluding this withdrawal and its fee. Requires a single account. Overrides currency and posted-date filters.\n\n</details>\n<details>\n<summary>members (11)</summary>\n\nMirrors the filtering query params of `GET /api/v1/members`.\n\n- `access_level` `string` \u2014 Filter by what the member can reach on the account. One of `no_access`, `admin`, `customer`.\n- `created_after` `string` \u2014 Only members who joined after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only members who joined before this ISO 8601 timestamp.\n- `membership_status` `string` \u2014 `active` returns members holding at least one membership that currently grants access; `inactive` returns members holding at least one membership that does not. Combined with `product_ids`, `plan_ids`, or `promo_code_ids`, one membership must match all of them. One of `active`, `inactive`.\n- `most_recent_actions` `string[]` \u2014 Only return members whose `most_recent_action` is one of these values.\n- `plan_ids` `string[]` \u2014 Only return members holding a membership on one of these plans, prefixed `plan_`. Unknown IDs match nothing.\n- `product_ids` `string[]` \u2014 Only return members holding a membership to one of these products, prefixed `prod_`. Unknown IDs match nothing.\n- `promo_code_ids` `string[]` \u2014 Only return members holding a membership bought with one of these promo codes, prefixed `promo_`. Unknown IDs match nothing.\n- `query` `string` \u2014 Search members by name or username. An exact email address also matches when the credential holds the member:email:read scope.\n- `status` `string` \u2014 Filter by whether the member is still part of the account. One of `joined`, `left`.\n- `user_ids` `string[]` \u2014 Only return members whose users match these `user_` identifiers.\n\n</details>\n<details>\n<summary>memberships (11)</summary>\n\nMirrors the filtering query params of `GET /api/v1/memberships`.\n\n- `created_after` `string` \u2014 Only memberships created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only memberships created before this ISO 8601 timestamp.\n- `member_id` `string` \u2014 Narrow to one member's memberships (`mber_` tag), including memberships bought by another business. A member outside the caller's visible set returns an empty list.\n- `plan_id` `string` \u2014 Filter to memberships of this variant (`plan_` tag).\n- `plan_ids` `string[]` \u2014 Filter to memberships of any of these variants, each prefixed `plan_`. Repeat the parameter to pass several.\n- `product_id` `string` \u2014 Filter to memberships of this product (`prod_` tag).\n- `product_ids` `string[]` \u2014 Filter to memberships of any of these products, each prefixed `prod_`. Repeat the parameter to pass several.\n- `promo_code_ids` `string[]` \u2014 Filter to memberships discounted by any of these promo codes, each prefixed `promo_`. Repeat the parameter to pass several.\n- `status` `string` \u2014 Filter by billing state. `trialing`, `active`, `past_due`, `completed`, `canceled`, and `expired` match the membership's `status`; `active`, `trialing`, and `past_due` exclude memberships set to cancel at period end. The other values are derived buckets that never appear as a `status`: `canceling` matches memberships set to cancel at period end; `paused` matches memberships with payment collection paused; `expiring` matches one-time purchases that have not yet expired; `one_time` matches one-time purchases that never expire; `unclaimed` matches memberships with no buyer user, including memberships bought by another business; `banned` matches memberships whose buyer is banned from the account. One of `active`, `trialing`, `past_due`, `completed`, `canceled`, `expired`, `canceling`, `paused`, `expiring`, `one_time`, `unclaimed`, `banned`.\n- `statuses` `string[]` \u2014 Filter to memberships matching any of these billing states, with the same meanings as `status`. Repeat the parameter to pass several. Combined with `status` when both are sent.\n- `user_id` `string` \u2014 Narrow to one user's memberships (`user_` tag, or `me` for the caller). A user outside the caller's visible set returns an empty list.\n\n</details>\n<details>\n<summary>payouts (7)</summary>\n\nMirrors the filtering query params of `GET /api/v1/payouts`.\n\n- `created_after` `string` \u2014 Only payouts created at or after this ISO 8601 time (inclusive).\n- `created_before` `string` \u2014 Only payouts created before this ISO 8601 time (exclusive).\n- `currency` `string` \u2014 Optional currency code filter, for example `usd`.\n- `payout_method_id` `string` \u2014 Filter to payouts sent to one saved payout method (a pytk_ identifier). An unknown id matches nothing.\n- `source` `string` \u2014 Filter by how the payout was created. Payouts created before source tracking or through internal tooling carry no source and never match. One of `api`, `dashboard`, `automatic`.\n- `status` `string` \u2014 Filter to payouts whose `status` reads this word, matching exactly what this version displays \u2014 `reversed` finds settled payouts the bank later returned. Requires Api-Version-Date 2026-08-21 or later. One of `requested`, `in_review`, `processing`, `completed`, `reversed`, `canceled`, `failed`, `denied`.\n- `user_id` `string` \u2014 The owning user ID (a user_ identifier). Provide this or account_id.\n\n</details>\n<details>\n<summary>people (39)</summary>\n\nMirrors the filtering query params of `GET /api/v1/people`.\n\n- `aov_gt` `number` \u2014 Select people whose lifetime aov is greater than this value. LTV and AOV are in USD.\n- `aov_gte` `number` \u2014 Select people whose lifetime aov is at least this value. LTV and AOV are in USD.\n- `aov_lt` `number` \u2014 Select people whose lifetime aov is less than this value. LTV and AOV are in USD.\n- `aov_lte` `number` \u2014 Select people whose lifetime aov is at most this value. LTV and AOV are in USD.\n- `attribution_model` `string` \u2014 Attribution model the source filter matches against (defaults to last_touch). One of `last_touch`, `first_touch`.\n- `audience_id` `string` \u2014 Only include people in this audience. An audience that keeps itself up to date resolves to the People filters that define it, so this always reflects who matches now; uploaded lists and point-in-time snapshots match their recorded members.\n- `contactable` `boolean` \u2014 true for people who have an email address or phone number \u2014 the ones an ad platform can match.\n- `country` `string` \u2014 Only include people with activity from this ISO 3166-1 alpha-2 country code.\n- `custom_event` `string` \u2014 Only include people who fired this custom pixel event.\n- `email` `string` \u2014 Only include the person linked to this email address.\n- `event_count_gt` `number` \u2014 Select people whose lifetime event_count is greater than this value. LTV and AOV are in USD.\n- `event_count_gte` `number` \u2014 Select people whose lifetime event_count is at least this value. LTV and AOV are in USD.\n- `event_count_lt` `number` \u2014 Select people whose lifetime event_count is less than this value. LTV and AOV are in USD.\n- `event_count_lte` `number` \u2014 Select people whose lifetime event_count is at most this value. LTV and AOV are in USD.\n- `event_from` `string` \u2014 The inclusive start of the matching activity window.\n- `event_name` `string[]` \u2014 Only include people who fired any of these events, e.g. payment.completed or page.checkout.view.\n- `event_to` `string` \u2014 The inclusive end of the matching activity window, for both stats drilldowns and saved audiences.\n- `event_within_days` `integer` \u2014 Match activity within a rolling number of days. Cannot be combined with event_from/event_to.\n- `first_seen_after` `string` \u2014 Only include people first seen at or after this ISO 8601 timestamp.\n- `first_seen_before` `string` \u2014 Only include people first seen before this ISO 8601 timestamp.\n- `first_seen_within_days` `integer` \u2014 Only include people first seen within this many days, as a rolling window.\n- `from` `string` \u2014 Inclusive activity-window start. Alias for event_from.\n- `has_purchased` `boolean` \u2014 true for customers only, false for people who have never purchased.\n- `last_seen_after` `string` \u2014 Only include people last seen at or after this ISO 8601 timestamp.\n- `last_seen_before` `string` \u2014 Only include people last seen before this ISO 8601 timestamp.\n- `last_seen_within_days` `integer` \u2014 Only include people last seen within this many days, as a rolling window.\n- `ltv_gt` `number` \u2014 Select people whose lifetime ltv is greater than this value. LTV and AOV are in USD.\n- `ltv_gte` `number` \u2014 Select people whose lifetime ltv is at least this value. LTV and AOV are in USD.\n- `ltv_lt` `number` \u2014 Select people whose lifetime ltv is less than this value. LTV and AOV are in USD.\n- `ltv_lte` `number` \u2014 Select people whose lifetime ltv is at most this value. LTV and AOV are in USD.\n- `phone` `string` \u2014 Only include the person linked to this phone number.\n- `purchase_count_gt` `number` \u2014 Select people whose lifetime purchase_count is greater than this value. LTV and AOV are in USD.\n- `purchase_count_gte` `number` \u2014 Select people whose lifetime purchase_count is at least this value. LTV and AOV are in USD.\n- `purchase_count_lt` `number` \u2014 Select people whose lifetime purchase_count is less than this value. LTV and AOV are in USD.\n- `purchase_count_lte` `number` \u2014 Select people whose lifetime purchase_count is at most this value. LTV and AOV are in USD.\n- `query` `string` \u2014 Search people by name, email, phone, or whop user ID (case-insensitive substring match).\n- `source` `string[]` \u2014 Only include people acquired from any of these sources \u2014 canonical paths (whop:<campaign>:<group>:<ad>, ext:<platform>:..., referrer:<domain>, direct, other), exact or with a trailing :* prefix. The same vocabulary the events / people metrics use.\n- `to` `string` \u2014 Inclusive activity-window end. Alias for event_to.\n- `user_id` `string` \u2014 Only include the person linked to this whop user ID.\n\n</details>\n<details>\n<summary>products (10)</summary>\n\nMirrors the filtering query params of `GET /api/v1/products`.\n\n- `access_pass_types` `string[]` \u2014 Filter to only products matching these types.\n- `created_after` `string` \u2014 Only return products created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only return products created before this ISO 8601 timestamp.\n- `labels` `string[]` \u2014 Filter to only products carrying all of these labels. Labels are matched lowercased.\n- `marketplace_category_route` `string` \u2014 Only return marketplace products assigned to this category route, such as `trading`.\n- `plan_types` `string[]` \u2014 Filter to products with a buyable variant of these billing models, such as `one_time` or `renewal`.\n- `price_maximum` `number` \u2014 Only return products whose advertised buyable variant has a displayed price of at most this amount. Recurring variants use renewal price.\n- `price_minimum` `number` \u2014 Only return products whose advertised buyable variant has a displayed price of at least this amount. Recurring variants use renewal price.\n- `query` `string` \u2014 Filters products by text. The public marketplace list searches product title, account name, headline and description, ranking products that match every word first and the closest partial matches after them; an account's own list is a plain substring match over title, headline and description. Omit to browse by recency.\n- `visibilities` `string[]` \u2014 Filter to only products matching these visibility states. Ignored on the public marketplace list, which only returns visible products.\n\n</details>\n<details>\n<summary>promo_codes (5)</summary>\n\nMirrors the filtering query params of `GET /api/v1/promo_codes`.\n\n- `created_after` `string` \u2014 Only promo codes created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only promo codes created before this ISO 8601 timestamp.\n- `plan_ids` `string[]` \u2014 Only promo codes scoped to these variant IDs.\n- `product_ids` `string[]` \u2014 Only promo codes scoped to these product IDs.\n- `status` `string` \u2014 Promo-code status. `expired` groups inactive and archived codes. One of `active`, `inactive`, `archived`, `expired`.\n\n</details>\n<details>\n<summary>resolution_center_cases (6)</summary>\n\nMirrors the filtering query params of `GET /api/v1/resolution_center_cases`.\n\n- `created_after` `string` \u2014 Only cases created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only cases created before this ISO 8601 timestamp.\n- `outcome` `string[]` \u2014 Only closed cases that ended these ways. Repeat the parameter to pass several.\n- `reason` `string[]` \u2014 Only cases opened for these reasons. Repeat the parameter to pass several.\n- `status` `string[]` \u2014 Only cases in these statuses. Repeat the parameter to pass several \u2014 one paginated list covers all of them.\n- `user_id` `string` \u2014 Only cases opened by this customer \u2014 a `user_` tag, or `me` for the calling user. It narrows what you can already read, so `me` lists the cases you opened without the ones on accounts you are a team member of.\n\n</details>\n<details>\n<summary>shipments (4)</summary>\n\nMirrors the filtering query params of `GET /api/v1/shipments`.\n\n- `created_after` `string` \u2014 Return shipments created after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Return shipments created before this ISO 8601 timestamp.\n- `payment_id` `string[]` \u2014 Only shipments fulfilling these payments, each prefixed `pay_`. Repeat the parameter to pass several, up to 100 per request \u2014 one paginated list covers all of them.\n- `status` `string` \u2014 Filter to shipments with this delivery status. One of `unknown`, `pre_transit`, `in_transit`, `out_for_delivery`, `delivered`, `available_for_pickup`, `return_to_sender`, `failure`, `cancelled`, `error`.\n\n</details>\n<details>\n<summary>social_accounts (5)</summary>\n\nMirrors the filtering query params of `GET /api/v1/social_accounts`.\n\n- `platform` `string` \u2014 Only return external accounts for the platform that is specified. One of `x`, `instagram`, `youtube`, `tiktok`, `facebook`, `discord`, `telegram`, `linkedin`, `snapchat`.\n- `scopes` `string[]` \u2014 Only return external accounts that have these scopes.\n- `trust_level` `string` \u2014 Only return external accounts linked with this trust level, such as `oauth` for accounts connected through OAuth. One of `oauth`, `verified`, `authorized`, `claimed`, `scraped`.\n- `user_id` `string` \u2014 The User that the external accounts are connected to. Provide either this or account_id.\n- `verified` `boolean` \u2014 Only return external accounts that are verified on the platform.\n\n</details>\n<details>\n<summary>team_members (9)</summary>\n\nMirrors the filtering query params of `GET /api/v1/team_members`.\n\n- `created_after` `string` \u2014 Only return members added after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only return members added before this ISO 8601 timestamp.\n- `direct_reports_max` `integer` \u2014 Only return members with at most this many direct reports; `0` returns the people who manage no one. Pending invites are excluded, and the list pages in `created_at` order without moving Partner-role members last.\n- `direct_reports_min` `integer` \u2014 Only return members with at least this many direct reports. Pending invites are excluded, and the list pages in `created_at` order without moving Partner-role members last.\n- `query` `string` \u2014 Only return members whose name or username contains this text, and invites whose email contains it.\n- `reports_to_id` `string` \u2014 Only return the direct reports of this team member, prefixed `ausr_`. Pass the account ID, prefixed `biz_`, for the members who report to the business directly. Pending invites are excluded, and the list pages in `created_at` order without moving Partner-role members last.\n- `role` `string` \u2014 Only return members with this role. `custom` matches members on a dashboard-managed custom role. One of `owner`, `admin`, `partner`, `sales_manager`, `moderator`, `advertiser`, `app_manager`, `support`, `manager`, `workforce`, `custom`.\n- `status` `string` \u2014 Only return members with this status: `joined` (accepted members) or `pending` (pending invites). Both are returned by default. One of `joined`, `pending`.\n- `user_id` `string` \u2014 Only return the membership for this user ID, prefixed `user_`.\n\n</details>\n<details>\n<summary>transfers (4)</summary>\n\nMirrors the filtering query params of `GET /api/v1/transfers`.\n\n- `created_after` `string` \u2014 Only transfers created strictly after this ISO 8601 timestamp.\n- `created_before` `string` \u2014 Only transfers created strictly before this ISO 8601 timestamp.\n- `destination_id` `string` \u2014 Filter to transfers received by this account.\n- `origin_id` `string` \u2014 Filter to transfers sent from this account.\n\n</details>\n<details>\n<summary>webhooks (3)</summary>\n\nMirrors the filtering query params of `GET /api/v1/webhooks`.\n\n- `app_id` `string` \u2014 Only return webhooks attached to this app. Omit to list the account's own webhooks.\n- `has_failures` `boolean` \u2014 Only return webhooks whose endpoint is currently failing \u2014 every delivery since the current failure streak began has been rejected. Clears as soon as a delivery succeeds.\n- `include_app_webhooks` `boolean` \u2014 Also return webhooks attached to the account's apps, not just the account's own. Cannot be combined with `app_id`.\n\n</details>\n</details>",
52503
52530
  example: {
52504
52531
  include_resource: false,
52505
52532
  posted_after: "2026-01-01T12:00:00.000Z",
@@ -53175,12 +53202,13 @@ var native_spec_default = {
53175
53202
  type: "string"
53176
53203
  },
53177
53204
  platform: {
53178
- description: "The platform to connect the external account on. Use `meta_business` to connect Meta Business assets, which is how Facebook Pages and Instagram accounts are connected \u2014 there is no separate `instagram` value. Use `tiktok` for TikTok accounts, `snapchat` for Snapchat Public Profiles, `linkedin` to connect the authenticated user\u2019s LinkedIn profile, or `youtube` to connect their YouTube channel.",
53205
+ description: "The platform to connect the external account on. Use `meta_business` to connect Meta Business assets, which is how Facebook Pages and Instagram accounts are connected \u2014 there is no separate `instagram` value. Use `tiktok` for TikTok accounts, `snapchat` for Snapchat Public Profiles, `linkedin` to connect the authenticated user\u2019s LinkedIn profile, `youtube` to connect their YouTube channel, or `x` to connect their X profile.",
53179
53206
  enum: [
53180
53207
  "meta_business",
53181
53208
  "tiktok",
53182
53209
  "linkedin",
53183
53210
  "youtube",
53211
+ "x",
53184
53212
  "snapchat"
53185
53213
  ],
53186
53214
  example: "meta_business",
@@ -53192,7 +53220,7 @@ var native_spec_default = {
53192
53220
  type: "string"
53193
53221
  },
53194
53222
  scopes: {
53195
- description: "The connection purpose. For `meta_business` and `snapchat`, `advertise` is required and connects company advertising assets. For `linkedin` and `youtube`, omit scopes to connect the authenticated user\u2019s profile; advertising is not supported. For `tiktok`, omit scopes to connect the authenticated user\u2019s profile, or pass `advertise` to connect company advertising assets. Profile connections still request the platform permissions needed to read the profile.",
53223
+ description: "The connection purpose. For `meta_business` and `snapchat`, `advertise` is required and connects company advertising assets. For `linkedin`, `youtube`, and `x`, omit scopes to connect the authenticated user\u2019s profile; advertising is not supported. For `tiktok`, omit scopes to connect the authenticated user\u2019s profile, or pass `advertise` to connect company advertising assets. Profile connections still request the platform permissions needed to read the profile.",
53196
53224
  items: {
53197
53225
  enum: ["advertise"],
53198
53226
  example: "advertise",
@@ -54478,6 +54506,8 @@ var native_spec_default = {
54478
54506
  "misc_reversal",
54479
54507
  "onboarding_reward",
54480
54508
  "onchain_deposit",
54509
+ "onchain_internal_transfer_incoming",
54510
+ "onchain_internal_transfer_outgoing",
54481
54511
  "onchain_swap_source",
54482
54512
  "onchain_swap_target",
54483
54513
  "onchain_wallet_transfer_incoming",
@@ -54936,6 +54966,8 @@ var native_spec_default = {
54936
54966
  "misc_reversal",
54937
54967
  "onboarding_reward",
54938
54968
  "onchain_deposit",
54969
+ "onchain_internal_transfer_incoming",
54970
+ "onchain_internal_transfer_outgoing",
54939
54971
  "onchain_swap_source",
54940
54972
  "onchain_swap_target",
54941
54973
  "onchain_wallet_transfer_incoming",
@@ -55322,6 +55354,8 @@ var native_spec_default = {
55322
55354
  "onboarding_reward",
55323
55355
  "onchain_deposit",
55324
55356
  "onchain_deposit_offset",
55357
+ "onchain_internal_transfer_incoming",
55358
+ "onchain_internal_transfer_outgoing",
55325
55359
  "onchain_swap_offset",
55326
55360
  "onchain_swap_source",
55327
55361
  "onchain_swap_target",
@@ -60085,7 +60119,7 @@ var native_spec_default = {
60085
60119
  },
60086
60120
  "/partners/businesses/{id}": {
60087
60121
  get: {
60088
- description: "Retrieves a single referred business and its referral terms.",
60122
+ description: "Retrieves a single referred business and its referral terms. The original referrer or a caller with company:basic:read on the business credited for the referral can read it.",
60089
60123
  operationId: "get",
60090
60124
  parameters: [
60091
60125
  {
@@ -60502,12 +60536,18 @@ var native_spec_default = {
60502
60536
  },
60503
60537
  security: [
60504
60538
  {
60505
- oauthTokenAuth: ["partner:basic:read"]
60539
+ accountApiKeyOrOauthTokenAuth: ["partner:basic:read"]
60540
+ },
60541
+ {
60542
+ accountApiKeyOrOauthTokenAuth: ["referral:basic:read"]
60543
+ },
60544
+ {
60545
+ accountApiKeyOrOauthTokenAuth: ["company:basic:read"]
60506
60546
  }
60507
60547
  ],
60508
60548
  summary: "Retrieve a referred business",
60509
60549
  tags: ["Partners"],
60510
- "x-whop-credentials": ["oauth_token"],
60550
+ "x-whop-credentials": ["account_api_key", "oauth_token"],
60511
60551
  "x-codeSamples": [
60512
60552
  {
60513
60553
  lang: "TypeScript",
@@ -60705,7 +60745,7 @@ var native_spec_default = {
60705
60745
  },
60706
60746
  "/partners/businesses/{id}/earnings": {
60707
60747
  get: {
60708
- description: "Lists the earnings Whop pays out for one referred business's activity, most recent first.",
60748
+ description: "Lists the earnings Whop pays out for one referred business's activity, most recent first. The original referrer or a caller with company:basic:read on the business credited for the referral can read them.",
60709
60749
  operationId: "earnings",
60710
60750
  parameters: [
60711
60751
  {
@@ -61329,12 +61369,18 @@ var native_spec_default = {
61329
61369
  },
61330
61370
  security: [
61331
61371
  {
61332
- oauthTokenAuth: ["partner:basic:read"]
61372
+ accountApiKeyOrOauthTokenAuth: ["partner:basic:read"]
61373
+ },
61374
+ {
61375
+ accountApiKeyOrOauthTokenAuth: ["referral:basic:read"]
61376
+ },
61377
+ {
61378
+ accountApiKeyOrOauthTokenAuth: ["company:basic:read"]
61333
61379
  }
61334
61380
  ],
61335
61381
  summary: "List referred business earnings",
61336
61382
  tags: ["Partners"],
61337
- "x-whop-credentials": ["oauth_token"],
61383
+ "x-whop-credentials": ["account_api_key", "oauth_token"],
61338
61384
  "x-codeSamples": [
61339
61385
  {
61340
61386
  lang: "TypeScript",
@@ -62632,7 +62678,8 @@ var native_spec_default = {
62632
62678
  },
62633
62679
  "/payment_method_domains": {
62634
62680
  get: {
62635
- description: "Lists the payment method domains registered for your account and its connected accounts.",
62681
+ deprecated: true,
62682
+ description: "Lists the payment method domains registered for your account and its connected accounts. Deprecated: list domains with `GET /domains` and the `apple_pay` filter instead.",
62636
62683
  operationId: "list",
62637
62684
  parameters: [
62638
62685
  {
@@ -62829,6 +62876,8 @@ var native_spec_default = {
62829
62876
  ],
62830
62877
  summary: "List Payment Method Domains",
62831
62878
  tags: ["Payment Method Domains"],
62879
+ "x-whop-deprecated-since": "2026-10-14",
62880
+ "x-whop-successor": "GET /domains",
62832
62881
  "x-mint": {
62833
62882
  metadata: {
62834
62883
  sidebarTitle: "List"
@@ -62842,7 +62891,8 @@ var native_spec_default = {
62842
62891
  ]
62843
62892
  },
62844
62893
  post: {
62845
- description: "Registers a hostname with the wallet provider and attempts verification inline. Returns `verified` when the provider fetched the domain-association file (for Apple Pay, `/.well-known/apple-developer-merchantid-domain-association`), or `pending` when it could not: host the file, then retry with `POST /payment_method_domains/:id/verify`.",
62894
+ deprecated: true,
62895
+ description: "Registers a hostname with the wallet provider and attempts verification inline. Returns `verified` when the provider fetched the domain-association file (for Apple Pay, `/.well-known/apple-developer-merchantid-domain-association`), or `pending` when it could not: host the file, then retry with `POST /payment_method_domains/:id/verify`. Deprecated: add Apple Pay with `POST /domains` and `apple_pay: {}` instead.",
62846
62896
  operationId: "create",
62847
62897
  parameters: [
62848
62898
  {
@@ -62912,6 +62962,8 @@ var native_spec_default = {
62912
62962
  ],
62913
62963
  summary: "Create Payment Method Domain",
62914
62964
  tags: ["Payment Method Domains"],
62965
+ "x-whop-deprecated-since": "2026-10-14",
62966
+ "x-whop-successor": "POST /domains",
62915
62967
  "x-mint": {
62916
62968
  metadata: {
62917
62969
  sidebarTitle: "Create"
@@ -62927,7 +62979,8 @@ var native_spec_default = {
62927
62979
  },
62928
62980
  "/payment_method_domains/{id}": {
62929
62981
  delete: {
62930
- description: "Unregisters a payment method domain so its wallet payment methods stop rendering there.",
62982
+ deprecated: true,
62983
+ description: "Unregisters a payment method domain so its wallet payment methods stop rendering there. Deprecated: remove Apple Pay with `PATCH /domains/{id}` and `apple_pay: null` instead. `DELETE /domains/{id}` removes the whole domain, including any website on it.",
62931
62984
  operationId: "delete",
62932
62985
  responses: {
62933
62986
  "200": {
@@ -62971,6 +63024,8 @@ var native_spec_default = {
62971
63024
  ],
62972
63025
  summary: "Delete Payment Method Domain",
62973
63026
  tags: ["Payment Method Domains"],
63027
+ "x-whop-deprecated-since": "2026-10-14",
63028
+ "x-whop-successor": "PATCH /domains/{id}",
62974
63029
  "x-mint": {
62975
63030
  metadata: {
62976
63031
  sidebarTitle: "Delete"
@@ -62998,7 +63053,8 @@ var native_spec_default = {
62998
63053
  ]
62999
63054
  },
63000
63055
  get: {
63001
- description: "Retrieves a payment method domain to check its verification status.",
63056
+ deprecated: true,
63057
+ description: "Retrieves a payment method domain to check its verification status. Deprecated: retrieve the domain with `GET /domains/{id}` instead, using the same ID.",
63002
63058
  operationId: "get",
63003
63059
  responses: {
63004
63060
  "200": {
@@ -63031,6 +63087,8 @@ var native_spec_default = {
63031
63087
  ],
63032
63088
  summary: "Retrieve Payment Method Domain",
63033
63089
  tags: ["Payment Method Domains"],
63090
+ "x-whop-deprecated-since": "2026-10-14",
63091
+ "x-whop-successor": "GET /domains/{id}",
63034
63092
  "x-mint": {
63035
63093
  metadata: {
63036
63094
  sidebarTitle: "Retrieve"
@@ -63060,7 +63118,8 @@ var native_spec_default = {
63060
63118
  },
63061
63119
  "/payment_method_domains/{id}/verify": {
63062
63120
  post: {
63063
- description: "Re-attempts provider verification of a pending domain once the association file is hosted. Fails with a `bad_request` explaining what to fix; verifying an already `verified` domain is a no-op.",
63121
+ deprecated: true,
63122
+ description: "Re-attempts provider verification of a pending domain once the association file is hosted. Fails with a `bad_request` explaining what to fix; verifying an already `verified` domain is a no-op. Deprecated: check the domain with `POST /domains/{id}/check` instead.",
63064
63123
  operationId: "verify",
63065
63124
  parameters: [
63066
63125
  {
@@ -63117,6 +63176,8 @@ var native_spec_default = {
63117
63176
  ],
63118
63177
  summary: "Verify Payment Method Domain",
63119
63178
  tags: ["Payment Method Domains"],
63179
+ "x-whop-deprecated-since": "2026-10-14",
63180
+ "x-whop-successor": "POST /domains/{id}/check",
63120
63181
  "x-codeSamples": [
63121
63182
  {
63122
63183
  lang: "TypeScript",
@@ -75675,6 +75736,11 @@ var native_spec_default = {
75675
75736
  },
75676
75737
  type: ["object", "null"]
75677
75738
  },
75739
+ owner_id: {
75740
+ description: "Who the saved payment method belongs to. Pass `account_id` to save it on the account itself, which needs `payment:charge` on the account. Pass your own user ID, prefixed `user_`, to save it on the authenticated user. Omit it to save it on the buyer: the caller when it is the buyer, otherwise the user the confirmation token names. Not available with `payment_method_id`, which keeps its current owner, or with `purpose`.",
75741
+ example: "biz_xxxxxxxxxxxxxx",
75742
+ type: ["string", "null"]
75743
+ },
75678
75744
  payment_method_id: {
75679
75745
  description: "An existing payment method to re-verify and save, prefixed `payt_`. Provide this or `confirmation_token`, not both. Not available to a buyer credential.",
75680
75746
  example: "payt_xxxxxxxxxxxxxx",
@@ -76711,12 +76777,13 @@ var native_spec_default = {
76711
76777
  type: "string"
76712
76778
  },
76713
76779
  platform: {
76714
- description: "The platform to connect the external account on. Use `meta_business` to connect Meta Business assets, which is how Facebook Pages and Instagram accounts are connected \u2014 there is no separate `instagram` value. Use `tiktok` for TikTok accounts, `snapchat` for Snapchat Public Profiles, `linkedin` to connect the authenticated user\u2019s LinkedIn profile, or `youtube` to connect their YouTube channel.",
76780
+ description: "The platform to connect the external account on. Use `meta_business` to connect Meta Business assets, which is how Facebook Pages and Instagram accounts are connected \u2014 there is no separate `instagram` value. Use `tiktok` for TikTok accounts, `snapchat` for Snapchat Public Profiles, `linkedin` to connect the authenticated user\u2019s LinkedIn profile, `youtube` to connect their YouTube channel, or `x` to connect their X profile.",
76715
76781
  enum: [
76716
76782
  "meta_business",
76717
76783
  "tiktok",
76718
76784
  "linkedin",
76719
76785
  "youtube",
76786
+ "x",
76720
76787
  "snapchat"
76721
76788
  ],
76722
76789
  example: "meta_business",
@@ -76728,7 +76795,7 @@ var native_spec_default = {
76728
76795
  type: "string"
76729
76796
  },
76730
76797
  scopes: {
76731
- description: "The connection purpose. For `meta_business` and `snapchat`, `advertise` is required and connects company advertising assets. For `linkedin` and `youtube`, omit scopes to connect the authenticated user\u2019s profile; advertising is not supported. For `tiktok`, omit scopes to connect the authenticated user\u2019s profile, or pass `advertise` to connect company advertising assets. Profile connections still request the platform permissions needed to read the profile.",
76798
+ description: "The connection purpose. For `meta_business` and `snapchat`, `advertise` is required and connects company advertising assets. For `linkedin`, `youtube`, and `x`, omit scopes to connect the authenticated user\u2019s profile; advertising is not supported. For `tiktok`, omit scopes to connect the authenticated user\u2019s profile, or pass `advertise` to connect company advertising assets. Profile connections still request the platform permissions needed to read the profile.",
76732
76799
  items: {
76733
76800
  enum: ["advertise"],
76734
76801
  example: "advertise",
@@ -79786,7 +79853,7 @@ var native_spec_default = {
79786
79853
  },
79787
79854
  "/team_members": {
79788
79855
  get: {
79789
- description: "Lists an account's team members, including pending invites. A user credential with `company:basic:read` may list only its own joined membership by passing its own `user_id` and `status=joined`. Listing `role=workforce` is also allowed with the `bounty:create` scope.",
79856
+ description: "Lists an account's team members, including pending invites. A user credential with `company:basic:read` may list only its own joined membership by passing its own `user_id` and `status=joined`. Listing `role=workforce` is also allowed with the `bounty:create` scope. Members with the view-only Partner role are listed after all other members.",
79790
79857
  operationId: "list",
79791
79858
  parameters: [
79792
79859
  {
@@ -79842,6 +79909,44 @@ var native_spec_default = {
79842
79909
  type: "string"
79843
79910
  }
79844
79911
  },
79912
+ {
79913
+ description: "Only return members whose name or username contains this text, and invites whose email contains it.",
79914
+ in: "query",
79915
+ name: "query",
79916
+ required: false,
79917
+ schema: {
79918
+ type: "string"
79919
+ }
79920
+ },
79921
+ {
79922
+ description: "Only return the direct reports of this team member, prefixed `ausr_`. Pass the account ID, prefixed `biz_`, for the members who report to the business directly. Pending invites are excluded, and the list pages in `created_at` order without moving Partner-role members last.",
79923
+ in: "query",
79924
+ name: "reports_to_id",
79925
+ required: false,
79926
+ schema: {
79927
+ type: "string"
79928
+ }
79929
+ },
79930
+ {
79931
+ description: "Only return members with at least this many direct reports. Pending invites are excluded, and the list pages in `created_at` order without moving Partner-role members last.",
79932
+ in: "query",
79933
+ name: "direct_reports_min",
79934
+ required: false,
79935
+ schema: {
79936
+ minimum: 0,
79937
+ type: "integer"
79938
+ }
79939
+ },
79940
+ {
79941
+ description: "Only return members with at most this many direct reports; `0` returns the people who manage no one. Pending invites are excluded, and the list pages in `created_at` order without moving Partner-role members last.",
79942
+ in: "query",
79943
+ name: "direct_reports_max",
79944
+ required: false,
79945
+ schema: {
79946
+ minimum: 0,
79947
+ type: "integer"
79948
+ }
79949
+ },
79845
79950
  {
79846
79951
  description: "Only return members added before this ISO 8601 timestamp.",
79847
79952
  in: "query",
@@ -79861,7 +79966,7 @@ var native_spec_default = {
79861
79966
  }
79862
79967
  },
79863
79968
  {
79864
- description: "Field used to sort members.",
79969
+ description: "Field used to sort members. Members with the view-only Partner role are listed after all other members whichever way the list is sorted.",
79865
79970
  in: "query",
79866
79971
  name: "order",
79867
79972
  required: false,
@@ -80555,7 +80660,7 @@ var native_spec_default = {
80555
80660
  type: "string"
80556
80661
  },
80557
80662
  instrument_type: {
80558
- description: "`perpetual` or `spot`. Required for an order. Spot needs the trading account in Hyperliquid's unified account mode.",
80663
+ description: "`perpetual` or `spot`. Required for an order. A spot order first switches the trading account to Hyperliquid's unified account mode, where spot and perpetuals share one USDC balance.",
80559
80664
  enum: ["perpetual", "spot"],
80560
80665
  example: "perpetual",
80561
80666
  type: "string"
@@ -83819,6 +83924,63 @@ var native_spec_default = {
83819
83924
  ]
83820
83925
  }
83821
83926
  },
83927
+ "/users/{user_id}/fees": {
83928
+ get: {
83929
+ description: "Retrieves the fees charged when the user moves money with their personal balance: withdrawals, transfers, bank deposits, and funding cards from pending balance. Each fee has the same shape as in Retrieve Account Fees. You can only retrieve your own fees, and they are read-only.",
83930
+ operationId: "fees",
83931
+ responses: {
83932
+ "200": {
83933
+ content: {
83934
+ "application/json": {
83935
+ schema: {
83936
+ $ref: "#/components/schemas/UserFees"
83937
+ }
83938
+ }
83939
+ },
83940
+ description: "fees retrieved"
83941
+ },
83942
+ "401": {
83943
+ $ref: "#/components/responses/Unauthorized",
83944
+ description: "unauthorized"
83945
+ },
83946
+ "403": {
83947
+ $ref: "#/components/responses/Forbidden",
83948
+ description: "another user's fees"
83949
+ },
83950
+ "404": {
83951
+ $ref: "#/components/responses/NotFound",
83952
+ description: "user not found"
83953
+ }
83954
+ },
83955
+ security: [
83956
+ {
83957
+ oauthTokenAuth: ["user:balance:read"]
83958
+ }
83959
+ ],
83960
+ summary: "Retrieve User Fees",
83961
+ tags: ["Users"],
83962
+ "x-whop-credentials": ["oauth_token"],
83963
+ "x-mint": {
83964
+ metadata: {
83965
+ sidebarTitle: "Retrieve Fees"
83966
+ }
83967
+ },
83968
+ parameters: [
83969
+ {
83970
+ description: "`me`, or the authenticated user's own `user_` tag or username.",
83971
+ in: "path",
83972
+ name: "user_id",
83973
+ required: true,
83974
+ schema: {
83975
+ type: "string"
83976
+ }
83977
+ },
83978
+ {
83979
+ $ref: "#/components/parameters/ApiVersionDate"
83980
+ }
83981
+ ]
83982
+ }
83983
+ },
83822
83984
  "/variants": {
83823
83985
  get: {
83824
83986
  description: "Lists an account's variants. To list a product's public, buyable variants without authentication, omit `account_id` and pass `product_ids`.",
@@ -88034,7 +88196,7 @@ var native_spec_default = {
88034
88196
  properties: {
88035
88197
  api_version_date: {
88036
88198
  description: "The dated API version (Api-Version-Date) to pin this webhook's payloads to. Omit to leave the webhook unpinned, tracking the current payload shape.",
88037
- example: "2026-10-13-1",
88199
+ example: "2026-01-01",
88038
88200
  type: ["string", "null"]
88039
88201
  },
88040
88202
  child_resource_events: {
@@ -88121,10 +88283,13 @@ var native_spec_default = {
88121
88283
  "shipment.updated",
88122
88284
  "member.created",
88123
88285
  "member.updated",
88286
+ "ad_campaign.created",
88124
88287
  "ad_campaign.payment_failed",
88125
88288
  "ad_campaign.updated",
88126
88289
  "ad_campaign.events",
88290
+ "ad_group.created",
88127
88291
  "ad_group.updated",
88292
+ "ad.created",
88128
88293
  "ad.updated",
88129
88294
  "chat.message.created",
88130
88295
  "chat.reaction.created",
@@ -88396,7 +88561,7 @@ var native_spec_default = {
88396
88561
  properties: {
88397
88562
  api_version_date: {
88398
88563
  description: "The dated API version (Api-Version-Date) to pin this webhook's payloads to. Only valid for `v1` webhooks. Omit to leave the current pin unchanged, or pass `null` to unpin and track the current payload shape.",
88399
- example: "2026-10-13-1",
88564
+ example: "2026-01-01",
88400
88565
  type: ["string", "null"]
88401
88566
  },
88402
88567
  child_resource_events: {
@@ -88483,10 +88648,13 @@ var native_spec_default = {
88483
88648
  "shipment.updated",
88484
88649
  "member.created",
88485
88650
  "member.updated",
88651
+ "ad_campaign.created",
88486
88652
  "ad_campaign.payment_failed",
88487
88653
  "ad_campaign.updated",
88488
88654
  "ad_campaign.events",
88655
+ "ad_group.created",
88489
88656
  "ad_group.updated",
88657
+ "ad.created",
88490
88658
  "ad.updated",
88491
88659
  "chat.message.created",
88492
88660
  "chat.reaction.created",
@@ -89097,7 +89265,7 @@ var native_spec_default = {
89097
89265
  example: {
89098
89266
  account_id: "biz_xxxxxxxxxxxxxx",
89099
89267
  api_version: "v1",
89100
- api_version_date: "2026-10-13-1",
89268
+ api_version_date: "2026-10-14",
89101
89269
  data: {
89102
89270
  ads_spend_usd: null,
89103
89271
  balances: [],
@@ -89117,7 +89285,7 @@ var native_spec_default = {
89117
89285
  crypto_deposit: "active",
89118
89286
  crypto_payout: "inactive",
89119
89287
  instant_payout: "inactive",
89120
- run_ads: "active",
89288
+ run_ads: "inactive",
89121
89289
  standard_payout: "inactive",
89122
89290
  transfer: "inactive"
89123
89291
  },
@@ -89297,6 +89465,7 @@ var native_spec_default = {
89297
89465
  business: null,
89298
89466
  individual: null
89299
89467
  },
89468
+ volume_l30d_usd: null,
89300
89469
  volume_usd: 0,
89301
89470
  wallet: null,
89302
89471
  website: null
@@ -89417,7 +89586,7 @@ var native_spec_default = {
89417
89586
  example: {
89418
89587
  account_id: "biz_xxxxxxxxxxxxxx",
89419
89588
  api_version: "v1",
89420
- api_version_date: "2026-10-13-1",
89589
+ api_version_date: "2026-10-14",
89421
89590
  data: {
89422
89591
  ads_spend_usd: null,
89423
89592
  balances: [],
@@ -89437,7 +89606,7 @@ var native_spec_default = {
89437
89606
  crypto_deposit: "active",
89438
89607
  crypto_payout: "inactive",
89439
89608
  instant_payout: "inactive",
89440
- run_ads: "active",
89609
+ run_ads: "inactive",
89441
89610
  standard_payout: "inactive",
89442
89611
  transfer: "inactive"
89443
89612
  },
@@ -89617,6 +89786,7 @@ var native_spec_default = {
89617
89786
  business: null,
89618
89787
  individual: null
89619
89788
  },
89789
+ volume_l30d_usd: null,
89620
89790
  volume_usd: 0,
89621
89791
  wallet: null,
89622
89792
  website: null
@@ -89737,7 +89907,7 @@ var native_spec_default = {
89737
89907
  example: {
89738
89908
  account_id: "biz_xxxxxxxxxxxxxx",
89739
89909
  api_version: "v1",
89740
- api_version_date: "2026-10-13-1",
89910
+ api_version_date: "2026-10-14",
89741
89911
  data: {
89742
89912
  account_id: "biz_xxxxxxxxxxxxxx",
89743
89913
  disabled_at: "2026-01-01T12:00:00.000Z",
@@ -89867,7 +90037,7 @@ var native_spec_default = {
89867
90037
  example: {
89868
90038
  account_id: "biz_xxxxxxxxxxxxxx",
89869
90039
  api_version: "v1",
89870
- api_version_date: "2026-10-13-1",
90040
+ api_version_date: "2026-10-14",
89871
90041
  data: {
89872
90042
  ads_spend_usd: null,
89873
90043
  balances: [],
@@ -89887,7 +90057,7 @@ var native_spec_default = {
89887
90057
  crypto_deposit: "active",
89888
90058
  crypto_payout: "inactive",
89889
90059
  instant_payout: "inactive",
89890
- run_ads: "active",
90060
+ run_ads: "inactive",
89891
90061
  standard_payout: "inactive",
89892
90062
  transfer: "inactive"
89893
90063
  },
@@ -90067,6 +90237,7 @@ var native_spec_default = {
90067
90237
  business: null,
90068
90238
  individual: null
90069
90239
  },
90240
+ volume_l30d_usd: null,
90070
90241
  volume_usd: 0,
90071
90242
  wallet: null,
90072
90243
  website: null
@@ -90187,7 +90358,7 @@ var native_spec_default = {
90187
90358
  example: {
90188
90359
  account_id: "biz_xxxxxxxxxxxxxx",
90189
90360
  api_version: "v1",
90190
- api_version_date: "2026-10-13-1",
90361
+ api_version_date: "2026-10-14",
90191
90362
  data: {
90192
90363
  ad_campaign: {
90193
90364
  id: "adcamp_xxxxxxxxxxxxxx"
@@ -90592,7 +90763,7 @@ var native_spec_default = {
90592
90763
  example: {
90593
90764
  account_id: "biz_xxxxxxxxxxxxxx",
90594
90765
  api_version: "v1",
90595
- api_version_date: "2026-10-13-1",
90766
+ api_version_date: "2026-10-14",
90596
90767
  data: {
90597
90768
  bid_type: null,
90598
90769
  budget_amount: 50,
@@ -90911,7 +91082,7 @@ var native_spec_default = {
90911
91082
  example: {
90912
91083
  account_id: "biz_xxxxxxxxxxxxxx",
90913
91084
  api_version: "v1",
90914
- api_version_date: "2026-10-13-1",
91085
+ api_version_date: "2026-10-14",
90915
91086
  data: {
90916
91087
  bid_type: null,
90917
91088
  budget_amount: 50,
@@ -91230,7 +91401,7 @@ var native_spec_default = {
91230
91401
  example: {
91231
91402
  account_id: "biz_xxxxxxxxxxxxxx",
91232
91403
  api_version: "v1",
91233
- api_version_date: "2026-10-13-1",
91404
+ api_version_date: "2026-10-14",
91234
91405
  data: {
91235
91406
  ad_campaign: {
91236
91407
  id: "adcamp_xxxxxxxxxxxxxx"
@@ -91701,7 +91872,7 @@ var native_spec_default = {
91701
91872
  example: {
91702
91873
  account_id: "biz_xxxxxxxxxxxxxx",
91703
91874
  api_version: "v1",
91704
- api_version_date: "2026-10-13-1",
91875
+ api_version_date: "2026-10-14",
91705
91876
  data: {
91706
91877
  billing: null,
91707
91878
  canceled_at: null,
@@ -92017,7 +92188,7 @@ var native_spec_default = {
92017
92188
  example: {
92018
92189
  account_id: "biz_xxxxxxxxxxxxxx",
92019
92190
  api_version: "v1",
92020
- api_version_date: "2026-10-13-1",
92191
+ api_version_date: "2026-10-14",
92021
92192
  data: {
92022
92193
  billing: null,
92023
92194
  canceled_at: null,
@@ -92333,7 +92504,7 @@ var native_spec_default = {
92333
92504
  example: {
92334
92505
  account_id: "biz_xxxxxxxxxxxxxx",
92335
92506
  api_version: "v1",
92336
- api_version_date: "2026-10-13-1",
92507
+ api_version_date: "2026-10-14",
92337
92508
  data: {
92338
92509
  billing: null,
92339
92510
  canceled_at: null,
@@ -92649,7 +92820,7 @@ var native_spec_default = {
92649
92820
  example: {
92650
92821
  account_id: "biz_xxxxxxxxxxxxxx",
92651
92822
  api_version: "v1",
92652
- api_version_date: "2026-10-13-1",
92823
+ api_version_date: "2026-10-14",
92653
92824
  data: {
92654
92825
  billing: null,
92655
92826
  canceled_at: null,
@@ -92965,7 +93136,7 @@ var native_spec_default = {
92965
93136
  example: {
92966
93137
  account_id: "biz_xxxxxxxxxxxxxx",
92967
93138
  api_version: "v1",
92968
- api_version_date: "2026-10-13-1",
93139
+ api_version_date: "2026-10-14",
92969
93140
  data: {
92970
93141
  hosted_url: null,
92971
93142
  id: "ciac_xxxxxxxxxxxxxx",
@@ -93115,7 +93286,7 @@ var native_spec_default = {
93115
93286
  example: {
93116
93287
  account_id: "biz_xxxxxxxxxxxxxx",
93117
93288
  api_version: "v1",
93118
- api_version_date: "2026-10-13-1",
93289
+ api_version_date: "2026-10-14",
93119
93290
  data: {
93120
93291
  hosted_url: null,
93121
93292
  id: "ciac_xxxxxxxxxxxxxx",
@@ -93265,7 +93436,7 @@ var native_spec_default = {
93265
93436
  example: {
93266
93437
  account_id: "biz_xxxxxxxxxxxxxx",
93267
93438
  api_version: "v1",
93268
- api_version_date: "2026-10-13-1",
93439
+ api_version_date: "2026-10-14",
93269
93440
  data: {
93270
93441
  hosted_url: null,
93271
93442
  id: "ciac_xxxxxxxxxxxxxx",
@@ -93415,7 +93586,7 @@ var native_spec_default = {
93415
93586
  example: {
93416
93587
  account_id: "biz_xxxxxxxxxxxxxx",
93417
93588
  api_version: "v1",
93418
- api_version_date: "2026-10-13-1",
93589
+ api_version_date: "2026-10-14",
93419
93590
  data: {
93420
93591
  hosted_url: null,
93421
93592
  id: "ciac_xxxxxxxxxxxxxx",
@@ -93565,7 +93736,7 @@ var native_spec_default = {
93565
93736
  example: {
93566
93737
  account_id: "biz_xxxxxxxxxxxxxx",
93567
93738
  api_version: "v1",
93568
- api_version_date: "2026-10-13-1",
93739
+ api_version_date: "2026-10-14",
93569
93740
  data: {
93570
93741
  card_id: "icrd_xxxxxxxxxxxxxx",
93571
93742
  cardholder_id: null,
@@ -93696,7 +93867,7 @@ var native_spec_default = {
93696
93867
  example: {
93697
93868
  account_id: "biz_xxxxxxxxxxxxxx",
93698
93869
  api_version: "v1",
93699
- api_version_date: "2026-10-13-1",
93870
+ api_version_date: "2026-10-14",
93700
93871
  data: {
93701
93872
  card_id: "icrd_xxxxxxxxxxxxxx",
93702
93873
  cardholder_id: null,
@@ -93827,7 +93998,7 @@ var native_spec_default = {
93827
93998
  example: {
93828
93999
  account_id: "biz_xxxxxxxxxxxxxx",
93829
94000
  api_version: "v1",
93830
- api_version_date: "2026-10-13-1",
94001
+ api_version_date: "2026-10-14",
93831
94002
  data: {
93832
94003
  card_id: "icrd_xxxxxxxxxxxxxx",
93833
94004
  cardholder_id: null,
@@ -93958,7 +94129,7 @@ var native_spec_default = {
93958
94129
  example: {
93959
94130
  account_id: "biz_xxxxxxxxxxxxxx",
93960
94131
  api_version: "v1",
93961
- api_version_date: "2026-10-13-1",
94132
+ api_version_date: "2026-10-14",
93962
94133
  data: {
93963
94134
  card_id: "icrd_xxxxxxxxxxxxxx",
93964
94135
  cardholder_id: null,
@@ -94089,7 +94260,7 @@ var native_spec_default = {
94089
94260
  example: {
94090
94261
  account_id: "biz_xxxxxxxxxxxxxx",
94091
94262
  api_version: "v1",
94092
- api_version_date: "2026-10-13-1",
94263
+ api_version_date: "2026-10-14",
94093
94264
  data: {
94094
94265
  card_id: "icrd_xxxxxxxxxxxxxx",
94095
94266
  cardholder_id: null,
@@ -94220,7 +94391,7 @@ var native_spec_default = {
94220
94391
  example: {
94221
94392
  account_id: "biz_xxxxxxxxxxxxxx",
94222
94393
  api_version: "v1",
94223
- api_version_date: "2026-10-13-1",
94394
+ api_version_date: "2026-10-14",
94224
94395
  data: {
94225
94396
  amount: "75000000000",
94226
94397
  available_at: null,
@@ -94352,7 +94523,7 @@ var native_spec_default = {
94352
94523
  example: {
94353
94524
  account_id: "biz_xxxxxxxxxxxxxx",
94354
94525
  api_version: "v1",
94355
- api_version_date: "2026-10-13-1",
94526
+ api_version_date: "2026-10-14",
94356
94527
  data: {
94357
94528
  account_id: "biz_xxxxxxxxxxxxxx",
94358
94529
  amount: 150,
@@ -94532,7 +94703,7 @@ var native_spec_default = {
94532
94703
  example: {
94533
94704
  account_id: "biz_xxxxxxxxxxxxxx",
94534
94705
  api_version: "v1",
94535
- api_version_date: "2026-10-13-1",
94706
+ api_version_date: "2026-10-14",
94536
94707
  data: {
94537
94708
  account_id: "biz_xxxxxxxxxxxxxx",
94538
94709
  amount: 150,
@@ -94712,7 +94883,7 @@ var native_spec_default = {
94712
94883
  example: {
94713
94884
  account_id: "biz_xxxxxxxxxxxxxx",
94714
94885
  api_version: "v1",
94715
- api_version_date: "2026-10-13-1",
94886
+ api_version_date: "2026-10-14",
94716
94887
  data: {
94717
94888
  account_id: null,
94718
94889
  amount: 25,
@@ -94842,7 +95013,7 @@ var native_spec_default = {
94842
95013
  example: {
94843
95014
  account_id: "biz_xxxxxxxxxxxxxx",
94844
95015
  api_version: "v1",
94845
- api_version_date: "2026-10-13-1",
95016
+ api_version_date: "2026-10-14",
94846
95017
  data: {
94847
95018
  created_at: "2026-01-01T12:00:00.000Z",
94848
95019
  download_url: "https://s3.amazonaws.com/uploads/exports/members-export.csv",
@@ -94963,7 +95134,7 @@ var native_spec_default = {
94963
95134
  example: {
94964
95135
  account_id: "biz_xxxxxxxxxxxxxx",
94965
95136
  api_version: "v1",
94966
- api_version_date: "2026-10-13-1",
95137
+ api_version_date: "2026-10-14",
94967
95138
  data: {
94968
95139
  created_at: "2026-01-01T12:00:00.000Z",
94969
95140
  download_url: null,
@@ -95084,7 +95255,7 @@ var native_spec_default = {
95084
95255
  example: {
95085
95256
  account_id: "biz_xxxxxxxxxxxxxx",
95086
95257
  api_version: "v1",
95087
- api_version_date: "2026-10-13-1",
95258
+ api_version_date: "2026-10-14",
95088
95259
  data: {
95089
95260
  amount: "512345000000",
95090
95261
  available_at: "2026-01-01T12:00:00.000Z",
@@ -95221,7 +95392,7 @@ var native_spec_default = {
95221
95392
  example: {
95222
95393
  account_id: "biz_xxxxxxxxxxxxxx",
95223
95394
  api_version: "v1",
95224
- api_version_date: "2026-10-13-1",
95395
+ api_version_date: "2026-10-14",
95225
95396
  data: {
95226
95397
  id: "idpf_xxxxxxxxxxxxxx"
95227
95398
  },
@@ -95343,7 +95514,7 @@ var native_spec_default = {
95343
95514
  example: {
95344
95515
  account_id: "biz_xxxxxxxxxxxxxx",
95345
95516
  api_version: "v1",
95346
- api_version_date: "2026-10-13-1",
95517
+ api_version_date: "2026-10-14",
95347
95518
  data: {
95348
95519
  access_level: "customer",
95349
95520
  account_id: "biz_xxxxxxxxxxxxxx",
@@ -95484,7 +95655,7 @@ var native_spec_default = {
95484
95655
  example: {
95485
95656
  account_id: "biz_xxxxxxxxxxxxxx",
95486
95657
  api_version: "v1",
95487
- api_version_date: "2026-10-13-1",
95658
+ api_version_date: "2026-10-14",
95488
95659
  data: {
95489
95660
  access_level: "customer",
95490
95661
  account_id: "biz_xxxxxxxxxxxxxx",
@@ -95625,7 +95796,7 @@ var native_spec_default = {
95625
95796
  example: {
95626
95797
  account_id: "biz_xxxxxxxxxxxxxx",
95627
95798
  api_version: "v1",
95628
- api_version_date: "2026-10-13-1",
95799
+ api_version_date: "2026-10-14",
95629
95800
  data: {
95630
95801
  account: {
95631
95802
  id: "biz_xxxxxxxxxxxxxx",
@@ -95791,7 +95962,7 @@ var native_spec_default = {
95791
95962
  example: {
95792
95963
  account_id: "biz_xxxxxxxxxxxxxx",
95793
95964
  api_version: "v1",
95794
- api_version_date: "2026-10-13-1",
95965
+ api_version_date: "2026-10-14",
95795
95966
  data: {
95796
95967
  account: {
95797
95968
  id: "biz_xxxxxxxxxxxxxx",
@@ -95963,7 +96134,7 @@ var native_spec_default = {
95963
96134
  example: {
95964
96135
  account_id: "biz_xxxxxxxxxxxxxx",
95965
96136
  api_version: "v1",
95966
- api_version_date: "2026-10-13-1",
96137
+ api_version_date: "2026-10-14",
95967
96138
  data: {
95968
96139
  account: {
95969
96140
  id: "biz_xxxxxxxxxxxxxx",
@@ -96129,7 +96300,7 @@ var native_spec_default = {
96129
96300
  example: {
96130
96301
  account_id: "biz_xxxxxxxxxxxxxx",
96131
96302
  api_version: "v1",
96132
- api_version_date: "2026-10-13-1",
96303
+ api_version_date: "2026-10-14",
96133
96304
  data: {
96134
96305
  account_id: "biz_xxxxxxxxxxxxxx",
96135
96306
  amount_after_fees: {
@@ -96402,7 +96573,7 @@ var native_spec_default = {
96402
96573
  example: {
96403
96574
  account_id: "biz_xxxxxxxxxxxxxx",
96404
96575
  api_version: "v1",
96405
- api_version_date: "2026-10-13-1",
96576
+ api_version_date: "2026-10-14",
96406
96577
  data: {
96407
96578
  account_id: "biz_xxxxxxxxxxxxxx",
96408
96579
  amount_after_fees: {
@@ -96675,7 +96846,7 @@ var native_spec_default = {
96675
96846
  example: {
96676
96847
  account_id: "biz_xxxxxxxxxxxxxx",
96677
96848
  api_version: "v1",
96678
- api_version_date: "2026-10-13-1",
96849
+ api_version_date: "2026-10-14",
96679
96850
  data: {
96680
96851
  account_id: "biz_xxxxxxxxxxxxxx",
96681
96852
  amount_after_fees: {
@@ -96948,7 +97119,7 @@ var native_spec_default = {
96948
97119
  example: {
96949
97120
  account_id: "biz_xxxxxxxxxxxxxx",
96950
97121
  api_version: "v1",
96951
- api_version_date: "2026-10-13-1",
97122
+ api_version_date: "2026-10-14",
96952
97123
  data: {
96953
97124
  account_id: "biz_xxxxxxxxxxxxxx",
96954
97125
  amount_after_fees: {
@@ -97221,7 +97392,7 @@ var native_spec_default = {
97221
97392
  example: {
97222
97393
  account_id: "biz_xxxxxxxxxxxxxx",
97223
97394
  api_version: "v1",
97224
- api_version_date: "2026-10-13-1",
97395
+ api_version_date: "2026-10-14",
97225
97396
  data: {
97226
97397
  account_id: "biz_xxxxxxxxxxxxxx",
97227
97398
  amount_after_fees: {
@@ -97488,7 +97659,7 @@ var native_spec_default = {
97488
97659
  example: {
97489
97660
  account_id: "biz_xxxxxxxxxxxxxx",
97490
97661
  api_version: "v1",
97491
- api_version_date: "2026-10-13-1",
97662
+ api_version_date: "2026-10-14",
97492
97663
  data: {
97493
97664
  account_id: "biz_xxxxxxxxxxxxxx",
97494
97665
  amount_after_fees: {
@@ -97767,7 +97938,7 @@ var native_spec_default = {
97767
97938
  example: {
97768
97939
  account_id: "biz_xxxxxxxxxxxxxx",
97769
97940
  api_version: "v1",
97770
- api_version_date: "2026-10-13-1",
97941
+ api_version_date: "2026-10-14",
97771
97942
  data: {
97772
97943
  account_id: "biz_xxxxxxxxxxxxxx",
97773
97944
  amount_after_fees: {
@@ -98040,7 +98211,7 @@ var native_spec_default = {
98040
98211
  example: {
98041
98212
  account_id: "biz_xxxxxxxxxxxxxx",
98042
98213
  api_version: "v1",
98043
- api_version_date: "2026-10-13-1",
98214
+ api_version_date: "2026-10-14",
98044
98215
  data: {
98045
98216
  amount: "10.0",
98046
98217
  created_at: "2026-01-01T12:00:00.000Z",
@@ -98428,7 +98599,7 @@ var native_spec_default = {
98428
98599
  example: {
98429
98600
  account_id: "biz_xxxxxxxxxxxxxx",
98430
98601
  api_version: "v1",
98431
- api_version_date: "2026-10-13-1",
98602
+ api_version_date: "2026-10-14",
98432
98603
  data: {
98433
98604
  amount: "10.0",
98434
98605
  created_at: "2026-01-01T12:00:00.000Z",
@@ -98813,7 +98984,7 @@ var native_spec_default = {
98813
98984
  example: {
98814
98985
  account_id: "biz_xxxxxxxxxxxxxx",
98815
98986
  api_version: "v1",
98816
- api_version_date: "2026-10-13-1",
98987
+ api_version_date: "2026-10-14",
98817
98988
  data: {
98818
98989
  amount: "10.0",
98819
98990
  created_at: "2026-01-01T12:00:00.000Z",
@@ -99194,7 +99365,7 @@ var native_spec_default = {
99194
99365
  example: {
99195
99366
  account_id: "biz_xxxxxxxxxxxxxx",
99196
99367
  api_version: "v1",
99197
- api_version_date: "2026-10-13-1",
99368
+ api_version_date: "2026-10-14",
99198
99369
  data: {
99199
99370
  account_reference: "4483",
99200
99371
  bank_verification_state: null,
@@ -99677,7 +99848,7 @@ var native_spec_default = {
99677
99848
  example: {
99678
99849
  account_id: "biz_xxxxxxxxxxxxxx",
99679
99850
  api_version: "v1",
99680
- api_version_date: "2026-10-13-1",
99851
+ api_version_date: "2026-10-14",
99681
99852
  data: {
99682
99853
  account: {
99683
99854
  id: "biz_xxxxxxxxxxxxxx",
@@ -99979,7 +100150,7 @@ var native_spec_default = {
99979
100150
  example: {
99980
100151
  account_id: "biz_xxxxxxxxxxxxxx",
99981
100152
  api_version: "v1",
99982
- api_version_date: "2026-10-13-1",
100153
+ api_version_date: "2026-10-14",
99983
100154
  data: {
99984
100155
  account: {
99985
100156
  id: "biz_xxxxxxxxxxxxxx",
@@ -100281,7 +100452,7 @@ var native_spec_default = {
100281
100452
  example: {
100282
100453
  account_id: "biz_xxxxxxxxxxxxxx",
100283
100454
  api_version: "v1",
100284
- api_version_date: "2026-10-13-1",
100455
+ api_version_date: "2026-10-14",
100285
100456
  data: {
100286
100457
  account: {
100287
100458
  id: "biz_xxxxxxxxxxxxxx",
@@ -100583,7 +100754,7 @@ var native_spec_default = {
100583
100754
  example: {
100584
100755
  account_id: "biz_xxxxxxxxxxxxxx",
100585
100756
  api_version: "v1",
100586
- api_version_date: "2026-10-13-1",
100757
+ api_version_date: "2026-10-14",
100587
100758
  data: {
100588
100759
  account: {
100589
100760
  id: "biz_xxxxxxxxxxxxxx",
@@ -100735,7 +100906,7 @@ var native_spec_default = {
100735
100906
  example: {
100736
100907
  account_id: "biz_xxxxxxxxxxxxxx",
100737
100908
  api_version: "v1",
100738
- api_version_date: "2026-10-13-1",
100909
+ api_version_date: "2026-10-14",
100739
100910
  data: {
100740
100911
  account: {
100741
100912
  id: "biz_xxxxxxxxxxxxxx",
@@ -100887,7 +101058,7 @@ var native_spec_default = {
100887
101058
  example: {
100888
101059
  account_id: "biz_xxxxxxxxxxxxxx",
100889
101060
  api_version: "v1",
100890
- api_version_date: "2026-10-13-1",
101061
+ api_version_date: "2026-10-14",
100891
101062
  data: {
100892
101063
  account: {
100893
101064
  id: "biz_xxxxxxxxxxxxxx",
@@ -101039,7 +101210,7 @@ var native_spec_default = {
101039
101210
  example: {
101040
101211
  account_id: "biz_xxxxxxxxxxxxxx",
101041
101212
  api_version: "v1",
101042
- api_version_date: "2026-10-13-1",
101213
+ api_version_date: "2026-10-14",
101043
101214
  data: {
101044
101215
  account: {
101045
101216
  id: "biz_xxxxxxxxxxxxxx",
@@ -101191,7 +101362,7 @@ var native_spec_default = {
101191
101362
  example: {
101192
101363
  account_id: "biz_xxxxxxxxxxxxxx",
101193
101364
  api_version: "v1",
101194
- api_version_date: "2026-10-13-1",
101365
+ api_version_date: "2026-10-14",
101195
101366
  data: {
101196
101367
  account: {
101197
101368
  id: "biz_xxxxxxxxxxxxxx",
@@ -101343,7 +101514,7 @@ var native_spec_default = {
101343
101514
  example: {
101344
101515
  account_id: "biz_xxxxxxxxxxxxxx",
101345
101516
  api_version: "v1",
101346
- api_version_date: "2026-10-13-1",
101517
+ api_version_date: "2026-10-14",
101347
101518
  data: {
101348
101519
  account: {
101349
101520
  id: "biz_xxxxxxxxxxxxxx",
@@ -101503,7 +101674,7 @@ var native_spec_default = {
101503
101674
  example: {
101504
101675
  account_id: "biz_xxxxxxxxxxxxxx",
101505
101676
  api_version: "v1",
101506
- api_version_date: "2026-10-13-1",
101677
+ api_version_date: "2026-10-14",
101507
101678
  data: {
101508
101679
  account: {
101509
101680
  id: "biz_xxxxxxxxxxxxxx",
@@ -101663,7 +101834,7 @@ var native_spec_default = {
101663
101834
  example: {
101664
101835
  account_id: "biz_xxxxxxxxxxxxxx",
101665
101836
  api_version: "v1",
101666
- api_version_date: "2026-10-13-1",
101837
+ api_version_date: "2026-10-14",
101667
101838
  data: {
101668
101839
  account: {
101669
101840
  id: "biz_xxxxxxxxxxxxxx",
@@ -101823,7 +101994,7 @@ var native_spec_default = {
101823
101994
  example: {
101824
101995
  account_id: "biz_xxxxxxxxxxxxxx",
101825
101996
  api_version: "v1",
101826
- api_version_date: "2026-10-13-1",
101997
+ api_version_date: "2026-10-14",
101827
101998
  data: {
101828
101999
  account_id: "biz_xxxxxxxxxxxxxx",
101829
102000
  checkout_configuration_id: null,
@@ -101964,7 +102135,7 @@ var native_spec_default = {
101964
102135
  example: {
101965
102136
  account_id: "biz_xxxxxxxxxxxxxx",
101966
102137
  api_version: "v1",
101967
- api_version_date: "2026-10-13-1",
102138
+ api_version_date: "2026-10-14",
101968
102139
  data: {
101969
102140
  account_id: "biz_xxxxxxxxxxxxxx",
101970
102141
  checkout_configuration_id: null,
@@ -102108,7 +102279,7 @@ var native_spec_default = {
102108
102279
  example: {
102109
102280
  account_id: "biz_xxxxxxxxxxxxxx",
102110
102281
  api_version: "v1",
102111
- api_version_date: "2026-10-13-1",
102282
+ api_version_date: "2026-10-14",
102112
102283
  data: {
102113
102284
  account_id: "biz_xxxxxxxxxxxxxx",
102114
102285
  checkout_configuration_id: null,
@@ -102287,7 +102458,7 @@ var native_spec_default = {
102287
102458
  example: {
102288
102459
  account_id: "biz_xxxxxxxxxxxxxx",
102289
102460
  api_version: "v1",
102290
- api_version_date: "2026-10-13-1",
102461
+ api_version_date: "2026-10-14",
102291
102462
  data: {
102292
102463
  account_id: "biz_xxxxxxxxxxxxxx",
102293
102464
  carrier: "ups",
@@ -102411,7 +102582,7 @@ var native_spec_default = {
102411
102582
  example: {
102412
102583
  account_id: "biz_xxxxxxxxxxxxxx",
102413
102584
  api_version: "v1",
102414
- api_version_date: "2026-10-13-1",
102585
+ api_version_date: "2026-10-14",
102415
102586
  data: {
102416
102587
  account_id: "biz_xxxxxxxxxxxxxx",
102417
102588
  carrier: "ups",
@@ -102535,7 +102706,7 @@ var native_spec_default = {
102535
102706
  example: {
102536
102707
  account_id: "biz_xxxxxxxxxxxxxx",
102537
102708
  api_version: "v1",
102538
- api_version_date: "2026-10-13-1",
102709
+ api_version_date: "2026-10-14",
102539
102710
  data: {
102540
102711
  account: {
102541
102712
  id: "biz_xxxxxxxxxxxxxx",
@@ -102767,7 +102938,7 @@ var native_spec_default = {
102767
102938
  example: {
102768
102939
  account_id: "biz_xxxxxxxxxxxxxx",
102769
102940
  api_version: "v1",
102770
- api_version_date: "2026-10-13-1",
102941
+ api_version_date: "2026-10-14",
102771
102942
  data: {
102772
102943
  amount: {
102773
102944
  amount: "250.00",
@@ -103090,7 +103261,7 @@ var native_spec_default = {
103090
103261
  example: {
103091
103262
  account_id: "biz_xxxxxxxxxxxxxx",
103092
103263
  api_version: "v1",
103093
- api_version_date: "2026-10-13-1",
103264
+ api_version_date: "2026-10-14",
103094
103265
  data: {
103095
103266
  amount: {
103096
103267
  amount: "250.00",
@@ -103413,7 +103584,7 @@ var native_spec_default = {
103413
103584
  example: {
103414
103585
  account_id: "biz_xxxxxxxxxxxxxx",
103415
103586
  api_version: "v1",
103416
- api_version_date: "2026-10-13-1",
103587
+ api_version_date: "2026-10-14",
103417
103588
  data: {
103418
103589
  amount: null,
103419
103590
  created_at: "2026-01-01T12:00:00.000Z",
@@ -103702,7 +103873,7 @@ var native_spec_default = {
103702
103873
  name: "Api-Version-Date",
103703
103874
  required: false,
103704
103875
  schema: {
103705
- example: "2026-10-13-1",
103876
+ example: "2026-10-14",
103706
103877
  type: "string"
103707
103878
  }
103708
103879
  },
@@ -103874,7 +104045,7 @@ var native_spec_default = {
103874
104045
  },
103875
104046
  collect_vat_id: {
103876
104047
  description: "Whether checkout shows a VAT/tax ID field for buyers to optionally enter. Does not require a VAT ID to purchase.",
103877
- example: true,
104048
+ example: false,
103878
104049
  type: "boolean"
103879
104050
  },
103880
104051
  company_formation: {
@@ -103896,6 +104067,11 @@ var native_spec_default = {
103896
104067
  example: "Mobile ceramic coating, paint correction, and interior detailing across the Austin metro.",
103897
104068
  type: ["string", "null"]
103898
104069
  },
104070
+ direct_reports_count: {
104071
+ description: "How many team members report to the business directly, with no manager above them. Present on single-account reads.",
104072
+ example: 0,
104073
+ type: "integer"
104074
+ },
103899
104075
  dispute_fighter_enabled: {
103900
104076
  description: "Whether Whop assembles and files dispute evidence for this account. Enabling it opts the account into the success fee charged on disputes it wins.",
103901
104077
  example: false,
@@ -103955,7 +104131,7 @@ var native_spec_default = {
103955
104131
  },
103956
104132
  invoice_prefix: {
103957
104133
  description: "Prefix used for account invoices.",
103958
- example: "SHINE",
104134
+ example: "INV",
103959
104135
  type: ["string", "null"]
103960
104136
  },
103961
104137
  level: {
@@ -103977,15 +104153,14 @@ var native_spec_default = {
103977
104153
  metadata: {
103978
104154
  description: "Arbitrary key/value metadata supplied at account creation.",
103979
104155
  example: {
103980
- external_id: "shop_4417",
103981
- region: "austin"
104156
+ external_id: "connected_account_123"
103982
104157
  },
103983
104158
  type: "object"
103984
104159
  },
103985
104160
  onboarding_type: {
103986
104161
  description: "Type of onboarding the account has completed.",
103987
104162
  enum: ["platform", "seller", null],
103988
- example: "seller",
104163
+ example: "platform",
103989
104164
  type: ["string", "null"]
103990
104165
  },
103991
104166
  opengraph_image_url: {
@@ -104089,7 +104264,7 @@ var native_spec_default = {
104089
104264
  },
104090
104265
  require_2fa: {
104091
104266
  description: "Whether authorized users must enable two-factor authentication.",
104092
- example: true,
104267
+ example: false,
104093
104268
  type: "boolean"
104094
104269
  },
104095
104270
  required_actions: {
@@ -104140,17 +104315,17 @@ var native_spec_default = {
104140
104315
  },
104141
104316
  show_joined_whops: {
104142
104317
  description: "Whether the account appears in joined whops on other accounts.",
104143
- example: false,
104318
+ example: true,
104144
104319
  type: "boolean"
104145
104320
  },
104146
104321
  show_reviews_dtc: {
104147
104322
  description: "Whether reviews are displayed on direct-to-consumer product pages.",
104148
- example: false,
104323
+ example: true,
104149
104324
  type: "boolean"
104150
104325
  },
104151
104326
  show_user_directory: {
104152
104327
  description: "Whether the account shows users in the user directory.",
104153
- example: false,
104328
+ example: true,
104154
104329
  type: "boolean"
104155
104330
  },
104156
104331
  social_links: {
@@ -104261,7 +104436,7 @@ var native_spec_default = {
104261
104436
  },
104262
104437
  use_logo_as_opengraph_image_fallback: {
104263
104438
  description: "Whether the account uses its logo as the fallback Open Graph image.",
104264
- example: true,
104439
+ example: false,
104265
104440
  type: "boolean"
104266
104441
  },
104267
104442
  verification: {
@@ -104272,6 +104447,11 @@ var native_spec_default = {
104272
104447
  },
104273
104448
  type: "object"
104274
104449
  },
104450
+ volume_l30d_usd: {
104451
+ description: "Volume through the account in the last 30 days (GMV from paid receipts), normalized to USD. Computed only on `list` for callers with `stats:read` on the account; `null` otherwise.",
104452
+ example: 0,
104453
+ type: ["number", "null"]
104454
+ },
104275
104455
  volume_usd: {
104276
104456
  description: "Lifetime volume through the account \u2014 sales plus transfers received \u2014 normalized to USD. Computed only on `list` for callers with `stats:read` on the account; `null` otherwise.",
104277
104457
  type: ["number", "null"]
@@ -104291,6 +104471,11 @@ var native_spec_default = {
104291
104471
  description: "The account's business website URL, or `null` if none has been provided. Setting it also adds a `website` entry to `social_links`.",
104292
104472
  example: "https://shinetimedetail.com",
104293
104473
  type: ["string", "null"]
104474
+ },
104475
+ whop_partner_enabled_at: {
104476
+ description: "When the account turned on Whop Partner mode, as an ISO 8601 timestamp. Present on single-account reads and update responses; `null` until the account turns Whop Partner mode on by sending `whop_partner_enabled: true` on update.",
104477
+ example: null,
104478
+ type: ["string", "null"]
104294
104479
  }
104295
104480
  },
104296
104481
  required: [
@@ -104337,6 +104522,7 @@ var native_spec_default = {
104337
104522
  "status",
104338
104523
  "status_reason",
104339
104524
  "volume_usd",
104525
+ "volume_l30d_usd",
104340
104526
  "ads_spend_usd",
104341
104527
  "level",
104342
104528
  "capabilities",
@@ -104527,9 +104713,9 @@ var native_spec_default = {
104527
104713
  type: "string"
104528
104714
  },
104529
104715
  run_ads: {
104530
- description: "Launching ad campaigns through Whop Ads. `inactive` while a requested ads services agreement is awaiting the account's signature.",
104716
+ description: "Launching ad campaigns through Whop Ads. `inactive` until the account's identity or business is verified, and while a requested ads services agreement is awaiting the account's signature.",
104531
104717
  enum: ["active", "inactive", "pending"],
104532
- example: "active",
104718
+ example: "inactive",
104533
104719
  type: "string"
104534
104720
  },
104535
104721
  standard_payout: {
@@ -108010,7 +108196,7 @@ var native_spec_default = {
108010
108196
  },
108011
108197
  pending_auto_topup: {
108012
108198
  $ref: "#/components/schemas/AccountFee",
108013
- description: "Charged on a Whop Ads auto top-up that is funded from pending balance."
108199
+ description: "Charged when pending, not-yet-settled balance is advanced to fund the account's cards balance."
108014
108200
  },
108015
108201
  platform_processing: {
108016
108202
  $ref: "#/components/schemas/AccountFee",
@@ -108022,7 +108208,7 @@ var native_spec_default = {
108022
108208
  },
108023
108209
  revshare: {
108024
108210
  $ref: "#/components/schemas/AccountFee",
108025
- description: "Charged on revenue shared with the account."
108211
+ description: "Charged on payments where the account shares revenue with revshare affiliates."
108026
108212
  },
108027
108213
  tax_calculation: {
108028
108214
  $ref: "#/components/schemas/AccountFee",
@@ -109311,7 +109497,7 @@ var native_spec_default = {
109311
109497
  type: "number"
109312
109498
  },
109313
109499
  link_clicks: {
109314
- description: "Clicks on links in the ad that lead to your destination, as reported by the ad platform. A subset of clicks, which also counts likes, comments, and other interactions with the ad.",
109500
+ description: "Page views on your destination from people who clicked the ad, recorded by the Whop pixel. Counted the same way on every ad platform.",
109315
109501
  example: 1071,
109316
109502
  type: "number"
109317
109503
  },
@@ -109807,7 +109993,7 @@ var native_spec_default = {
109807
109993
  type: "number"
109808
109994
  },
109809
109995
  link_clicks: {
109810
- description: "Clicks on links in the ad that lead to your destination, as reported by the ad platform. A subset of clicks, which also counts likes, comments, and other interactions with the ad.",
109996
+ description: "Page views on your destination from people who clicked the ad, recorded by the Whop pixel. Counted the same way on every ad platform.",
109811
109997
  example: 4400,
109812
109998
  type: "number"
109813
109999
  },
@@ -110582,7 +110768,7 @@ var native_spec_default = {
110582
110768
  ]
110583
110769
  },
110584
110770
  link_clicks: {
110585
- description: "Clicks on links in the ad that lead to your destination, as reported by the ad platform. A subset of clicks, which also counts likes, comments, and other interactions with the ad.",
110771
+ description: "Page views on your destination from people who clicked the ad, recorded by the Whop pixel. Counted the same way on every ad platform.",
110586
110772
  example: 4400,
110587
110773
  type: "number"
110588
110774
  },
@@ -112143,9 +112329,10 @@ var native_spec_default = {
112143
112329
  "2026-10-09-1",
112144
112330
  "2026-10-09-2",
112145
112331
  "2026-10-13",
112146
- "2026-10-13-1"
112332
+ "2026-10-13-1",
112333
+ "2026-10-14"
112147
112334
  ],
112148
- example: "2026-10-13-1",
112335
+ example: "2026-10-14",
112149
112336
  type: "string"
112150
112337
  },
112151
112338
  created_at: {
@@ -112317,7 +112504,7 @@ var native_spec_default = {
112317
112504
  },
112318
112505
  base_url: {
112319
112506
  description: "The production base URL where the app is hosted. `null` if no base URL is configured, if the caller lacks the `developer:basic:read` permission on the app's account, or on list responses, which never expose it.",
112320
- example: "https://booking.shinetime.example",
112507
+ example: "https://shine-time-booking.whop.site",
112321
112508
  type: ["string", "null"]
112322
112509
  },
112323
112510
  businesses_created_count: {
@@ -112957,7 +113144,7 @@ var native_spec_default = {
112957
113144
  },
112958
113145
  base_url: {
112959
113146
  description: "The production base URL where the app is hosted. `null` if no base URL is configured, if the caller lacks the `developer:basic:read` permission on the app's account, or on list responses, which never expose it.",
112960
- example: "https://booking.shinetime.example",
113147
+ example: "https://shine-time-booking-store.whop.site",
112961
113148
  type: ["string", "null"]
112962
113149
  },
112963
113150
  businesses_created_count: {
@@ -116045,7 +116232,7 @@ var native_spec_default = {
116045
116232
  type: "object"
116046
116233
  },
116047
116234
  owned_by: {
116048
- description: "The other account that has proven it owns this hostname. `null` when no other account does.",
116235
+ description: "The account that has proven it owns this hostname on Whop, which can be your own. `null` when no account has.",
116049
116236
  oneOf: [
116050
116237
  {
116051
116238
  $ref: "#/components/schemas/DomainOwner"
@@ -116397,7 +116584,7 @@ var native_spec_default = {
116397
116584
  type: "object"
116398
116585
  },
116399
116586
  owned_by: {
116400
- description: "The other account that has proven it owns this hostname. `null` when no other account does.",
116587
+ description: "The account that has proven it owns this hostname on Whop, which can be your own. `null` when no account has.",
116401
116588
  oneOf: [
116402
116589
  {
116403
116590
  $ref: "#/components/schemas/DomainOwner"
@@ -116517,18 +116704,22 @@ var native_spec_default = {
116517
116704
  properties: {
116518
116705
  id: {
116519
116706
  description: "ID of the account that owns the domain, prefixed `biz_`.",
116707
+ example: "biz_xxxxxxxxxxxxxx",
116520
116708
  type: "string"
116521
116709
  },
116522
116710
  logo_url: {
116523
116711
  description: "Account logo image URL.",
116712
+ example: null,
116524
116713
  type: ["string", "null"]
116525
116714
  },
116526
116715
  route: {
116527
116716
  description: "Account public route identifier.",
116717
+ example: "biz_xxxxxxxxxxxxxx",
116528
116718
  type: "string"
116529
116719
  },
116530
116720
  title: {
116531
116721
  description: "Account display name.",
116722
+ example: "Rival Shop",
116532
116723
  type: "string"
116533
116724
  }
116534
116725
  },
@@ -116822,7 +117013,7 @@ var native_spec_default = {
116822
117013
  properties: {
116823
117014
  base_url: {
116824
117015
  description: "The production base URL where the app is hosted. `null` if no base URL is configured or the domain isn't yours.",
116825
- example: null,
117016
+ example: "https://domains-spec-site.whop.site",
116826
117017
  type: ["string", "null"]
116827
117018
  },
116828
117019
  id: {
@@ -118654,6 +118845,8 @@ var native_spec_default = {
118654
118845
  "trading_account_deposit_offset",
118655
118846
  "onchain_wallet_transfer_outgoing",
118656
118847
  "onchain_wallet_transfer_incoming",
118848
+ "onchain_internal_transfer_outgoing",
118849
+ "onchain_internal_transfer_incoming",
118657
118850
  "onchain_swap_source",
118658
118851
  "onchain_swap_target",
118659
118852
  "onchain_swap_offset",
@@ -124314,6 +124507,7 @@ var native_spec_default = {
124314
124507
  "ai_chat:delete",
124315
124508
  "ai_chat:update",
124316
124509
  "user:notifications:read",
124510
+ "user:abuse_report:create",
124317
124511
  "user:notifications:update",
124318
124512
  "user:profile:update"
124319
124513
  ],
@@ -124599,6 +124793,7 @@ var native_spec_default = {
124599
124793
  "AiChatDelete",
124600
124794
  "AiChatUpdate",
124601
124795
  "UserNotificationsRead",
124796
+ "UserAbuseReportCreate",
124602
124797
  "UserNotificationsUpdate",
124603
124798
  "UserProfileUpdate"
124604
124799
  ]
@@ -127551,6 +127746,11 @@ var native_spec_default = {
127551
127746
  example: "2026-01-01T12:00:00.000Z",
127552
127747
  type: "string"
127553
127748
  },
127749
+ direct_reports_count: {
127750
+ description: "How many team members report directly to this member. `null` for invites.",
127751
+ example: 0,
127752
+ type: ["integer", "null"]
127753
+ },
127554
127754
  email: {
127555
127755
  description: "The member's email address. For accepted members, `null` unless the caller holds the `company:authorized_user:email:read` scope; for invites, the invited address.",
127556
127756
  example: "marcus@shinetime.example",
@@ -127566,6 +127766,11 @@ var native_spec_default = {
127566
127766
  example: false,
127567
127767
  type: "boolean"
127568
127768
  },
127769
+ reports_to_id: {
127770
+ description: "The team member this member reports to, prefixed `ausr_`. `null` when the member reports to the business directly, and for invites.",
127771
+ example: "ausr_xxxxxxxxxxxxxx",
127772
+ type: ["string", "null"]
127773
+ },
127569
127774
  role: {
127570
127775
  description: "The member's role on the account. `custom` means a bespoke dashboard-managed role; the API can read but not grant it.",
127571
127776
  enum: [
@@ -127617,6 +127822,8 @@ var native_spec_default = {
127617
127822
  "created_at",
127618
127823
  "updated_at",
127619
127824
  "authorized_role",
127825
+ "reports_to_id",
127826
+ "direct_reports_count",
127620
127827
  "user"
127621
127828
  ],
127622
127829
  type: "object"
@@ -128414,6 +128621,245 @@ var native_spec_default = {
128414
128621
  ],
128415
128622
  type: "object"
128416
128623
  },
128624
+ UserFees: {
128625
+ properties: {
128626
+ bank_deposit: {
128627
+ $ref: "#/components/schemas/AccountFee",
128628
+ description: "Charged on bank deposits into the user's balance."
128629
+ },
128630
+ payouts: {
128631
+ additionalProperties: {
128632
+ $ref: "#/components/schemas/AccountFee"
128633
+ },
128634
+ description: "Fees on withdrawals, keyed by payout method: `bank_wire`, `same_day_bank`, `next_day_bank`, `rtp`, `crypto`, and `digital_wallet`.",
128635
+ example: {
128636
+ bank_wire: {
128637
+ adjustable: false,
128638
+ category: "payouts",
128639
+ default: {
128640
+ fixed: {
128641
+ amount: "30.00",
128642
+ currency: "usd",
128643
+ decimals: 2,
128644
+ display_decimals: 2
128645
+ },
128646
+ percentage: null
128647
+ },
128648
+ ends_at: null,
128649
+ fixed: {
128650
+ amount: "30.00",
128651
+ currency: "usd",
128652
+ decimals: 2,
128653
+ display_decimals: 2
128654
+ },
128655
+ maximum: null,
128656
+ minimum: null,
128657
+ percentage: null,
128658
+ region: null,
128659
+ regions: {},
128660
+ reset: {
128661
+ fixed: {
128662
+ amount: "30.00",
128663
+ currency: "usd",
128664
+ decimals: 2,
128665
+ display_decimals: 2
128666
+ },
128667
+ percentage: null
128668
+ },
128669
+ source: "default",
128670
+ unadjustable_reason: "not_permitted"
128671
+ },
128672
+ crypto: {
128673
+ adjustable: false,
128674
+ category: "payouts",
128675
+ default: {
128676
+ fixed: null,
128677
+ percentage: 0
128678
+ },
128679
+ ends_at: null,
128680
+ fixed: null,
128681
+ maximum: null,
128682
+ minimum: null,
128683
+ percentage: 0,
128684
+ region: null,
128685
+ regions: {},
128686
+ reset: {
128687
+ fixed: null,
128688
+ percentage: 0
128689
+ },
128690
+ source: "default",
128691
+ unadjustable_reason: "not_permitted"
128692
+ },
128693
+ digital_wallet: {
128694
+ adjustable: false,
128695
+ category: "payouts",
128696
+ default: {
128697
+ fixed: {
128698
+ amount: "0.00",
128699
+ currency: "usd",
128700
+ decimals: 2,
128701
+ display_decimals: 2
128702
+ },
128703
+ percentage: 0
128704
+ },
128705
+ ends_at: null,
128706
+ fixed: {
128707
+ amount: "0.00",
128708
+ currency: "usd",
128709
+ decimals: 2,
128710
+ display_decimals: 2
128711
+ },
128712
+ maximum: null,
128713
+ minimum: null,
128714
+ percentage: 0,
128715
+ region: null,
128716
+ regions: {},
128717
+ reset: {
128718
+ fixed: {
128719
+ amount: "0.00",
128720
+ currency: "usd",
128721
+ decimals: 2,
128722
+ display_decimals: 2
128723
+ },
128724
+ percentage: 0
128725
+ },
128726
+ source: "default",
128727
+ unadjustable_reason: "not_permitted"
128728
+ },
128729
+ next_day_bank: {
128730
+ adjustable: false,
128731
+ category: "payouts",
128732
+ default: {
128733
+ fixed: {
128734
+ amount: "2.50",
128735
+ currency: "usd",
128736
+ decimals: 2,
128737
+ display_decimals: 2
128738
+ },
128739
+ percentage: null
128740
+ },
128741
+ ends_at: null,
128742
+ fixed: {
128743
+ amount: "2.50",
128744
+ currency: "usd",
128745
+ decimals: 2,
128746
+ display_decimals: 2
128747
+ },
128748
+ maximum: null,
128749
+ minimum: null,
128750
+ percentage: null,
128751
+ region: null,
128752
+ regions: {},
128753
+ reset: {
128754
+ fixed: {
128755
+ amount: "2.50",
128756
+ currency: "usd",
128757
+ decimals: 2,
128758
+ display_decimals: 2
128759
+ },
128760
+ percentage: null
128761
+ },
128762
+ source: "default",
128763
+ unadjustable_reason: "not_permitted"
128764
+ },
128765
+ rtp: {
128766
+ adjustable: false,
128767
+ category: "payouts",
128768
+ default: {
128769
+ fixed: {
128770
+ amount: "0.00",
128771
+ currency: "usd",
128772
+ decimals: 2,
128773
+ display_decimals: 2
128774
+ },
128775
+ percentage: 0
128776
+ },
128777
+ ends_at: null,
128778
+ fixed: {
128779
+ amount: "0.00",
128780
+ currency: "usd",
128781
+ decimals: 2,
128782
+ display_decimals: 2
128783
+ },
128784
+ maximum: null,
128785
+ minimum: null,
128786
+ percentage: 0,
128787
+ region: null,
128788
+ regions: {},
128789
+ reset: {
128790
+ fixed: {
128791
+ amount: "0.00",
128792
+ currency: "usd",
128793
+ decimals: 2,
128794
+ display_decimals: 2
128795
+ },
128796
+ percentage: 0
128797
+ },
128798
+ source: "default",
128799
+ unadjustable_reason: "not_permitted"
128800
+ },
128801
+ same_day_bank: {
128802
+ adjustable: false,
128803
+ category: "payouts",
128804
+ default: {
128805
+ fixed: {
128806
+ amount: "2.50",
128807
+ currency: "usd",
128808
+ decimals: 2,
128809
+ display_decimals: 2
128810
+ },
128811
+ percentage: null
128812
+ },
128813
+ ends_at: null,
128814
+ fixed: {
128815
+ amount: "2.50",
128816
+ currency: "usd",
128817
+ decimals: 2,
128818
+ display_decimals: 2
128819
+ },
128820
+ maximum: null,
128821
+ minimum: null,
128822
+ percentage: null,
128823
+ region: null,
128824
+ regions: {},
128825
+ reset: {
128826
+ fixed: {
128827
+ amount: "2.50",
128828
+ currency: "usd",
128829
+ decimals: 2,
128830
+ display_decimals: 2
128831
+ },
128832
+ percentage: null
128833
+ },
128834
+ source: "default",
128835
+ unadjustable_reason: "not_permitted"
128836
+ }
128837
+ },
128838
+ type: "object"
128839
+ },
128840
+ pending_auto_topup: {
128841
+ $ref: "#/components/schemas/AccountFee",
128842
+ description: "Charged when pending, not-yet-settled balance is advanced to fund the user's cards balance."
128843
+ },
128844
+ transfers: {
128845
+ $ref: "#/components/schemas/AccountFee",
128846
+ description: "Charged on transfers from the user's balance to another Whop balance."
128847
+ },
128848
+ user_id: {
128849
+ description: "The user these fees are charged to, prefixed `user_`.",
128850
+ example: "user_xxxxxxxxxxxxxx",
128851
+ type: "string"
128852
+ }
128853
+ },
128854
+ required: [
128855
+ "user_id",
128856
+ "payouts",
128857
+ "transfers",
128858
+ "pending_auto_topup",
128859
+ "bank_deposit"
128860
+ ],
128861
+ type: "object"
128862
+ },
128417
128863
  UserNotificationPreference: {
128418
128864
  properties: {
128419
128865
  created_at: {
@@ -129421,7 +129867,7 @@ var native_spec_default = {
129421
129867
  },
129422
129868
  api_version_date: {
129423
129869
  description: "The dated API version (Api-Version-Date) that v1 payloads for this endpoint are pinned to: events serialize exactly like a REST read at this version (the native serializer where the resource has one). Null when unpinned \u2014 legacy (v2/v5) webhooks, and v1 webhooks on the legacy payload shape.",
129424
- example: "2026-10-13-1",
129870
+ example: "2026-01-01",
129425
129871
  type: ["string", "null"]
129426
129872
  },
129427
129873
  child_resource_events: {
@@ -129532,10 +129978,13 @@ var native_spec_default = {
129532
129978
  "shipment.updated",
129533
129979
  "member.created",
129534
129980
  "member.updated",
129981
+ "ad_campaign.created",
129535
129982
  "ad_campaign.payment_failed",
129536
129983
  "ad_campaign.updated",
129537
129984
  "ad_campaign.events",
129985
+ "ad_group.created",
129538
129986
  "ad_group.updated",
129987
+ "ad.created",
129539
129988
  "ad.updated",
129540
129989
  "chat.message.created",
129541
129990
  "chat.reaction.created",
@@ -129669,10 +130118,13 @@ var native_spec_default = {
129669
130118
  "shipment.updated",
129670
130119
  "member.created",
129671
130120
  "member.updated",
130121
+ "ad_campaign.created",
129672
130122
  "ad_campaign.payment_failed",
129673
130123
  "ad_campaign.updated",
129674
130124
  "ad_campaign.events",
130125
+ "ad_group.created",
129675
130126
  "ad_group.updated",
130127
+ "ad.created",
129676
130128
  "ad.updated",
129677
130129
  "chat.message.created",
129678
130130
  "chat.reaction.created",
@@ -129825,7 +130277,7 @@ var native_spec_default = {
129825
130277
  },
129826
130278
  api_version_date: {
129827
130279
  description: "The dated API version (Api-Version-Date) that v1 payloads for this endpoint are pinned to: events serialize exactly like a REST read at this version (the native serializer where the resource has one). Null when unpinned \u2014 legacy (v2/v5) webhooks, and v1 webhooks on the legacy payload shape.",
129828
- example: "2026-10-13-1",
130280
+ example: "2026-01-01",
129829
130281
  type: ["string", "null"]
129830
130282
  },
129831
130283
  child_resource_events: {
@@ -129936,10 +130388,13 @@ var native_spec_default = {
129936
130388
  "shipment.updated",
129937
130389
  "member.created",
129938
130390
  "member.updated",
130391
+ "ad_campaign.created",
129939
130392
  "ad_campaign.payment_failed",
129940
130393
  "ad_campaign.updated",
129941
130394
  "ad_campaign.events",
130395
+ "ad_group.created",
129942
130396
  "ad_group.updated",
130397
+ "ad.created",
129943
130398
  "ad.updated",
129944
130399
  "chat.message.created",
129945
130400
  "chat.reaction.created",
@@ -130136,7 +130591,7 @@ var apps_spec_default = {
130136
130591
  termsOfService: "https://whop.com/tos-developer-api/",
130137
130592
  title: "Whop API",
130138
130593
  version: "1.0.0",
130139
- "x-api-version-date": "2026-10-13-1"
130594
+ "x-api-version-date": "2026-10-14"
130140
130595
  },
130141
130596
  paths: {
130142
130597
  "/app_builds": {
@@ -130715,7 +131170,6 @@ var apps_spec_default = {
130715
131170
  },
130716
131171
  base_url: {
130717
131172
  description: "The base production URL where the app is hosted, such as `https://myapp.example.com`.",
130718
- example: "https://booking.shinetime.example",
130719
131173
  type: ["string", "null"]
130720
131174
  },
130721
131175
  domain_id: {
@@ -130990,7 +131444,7 @@ var apps_spec_default = {
130990
131444
  },
130991
131445
  base_url: {
130992
131446
  description: "The base production URL where the app is hosted. Set to `null` to take the app proxy offline.",
130993
- example: "https://booking.shinetime.example",
131447
+ example: "https://shine-time-booking.whop.site",
130994
131448
  type: ["string", "null"]
130995
131449
  },
130996
131450
  dashboard_path: {
@@ -131620,7 +132074,7 @@ var apps_spec_default = {
131620
132074
  },
131621
132075
  base_url: {
131622
132076
  description: "The production base URL where the app is hosted. `null` if no base URL is configured, if the caller lacks the `developer:basic:read` permission on the app's account, or on list responses, which never expose it.",
131623
- example: "https://booking.shinetime.example",
132077
+ example: "https://shine-time-booking-store.whop.site",
131624
132078
  type: ["string", "null"]
131625
132079
  },
131626
132080
  businesses_created_count: {
@@ -131805,7 +132259,7 @@ var apps_spec_default = {
131805
132259
  },
131806
132260
  base_url: {
131807
132261
  description: "The production base URL where the app is hosted. `null` if no base URL is configured, if the caller lacks the `developer:basic:read` permission on the app's account, or on list responses, which never expose it.",
131808
- example: "https://booking.shinetime.example",
132262
+ example: "https://shine-time-booking.whop.site",
131809
132263
  type: ["string", "null"]
131810
132264
  },
131811
132265
  businesses_created_count: {
@@ -132489,7 +132943,7 @@ var apps_spec_default = {
132489
132943
  name: "Api-Version-Date",
132490
132944
  required: false,
132491
132945
  schema: {
132492
- example: "2026-10-13-1",
132946
+ example: "2026-10-14",
132493
132947
  type: "string"
132494
132948
  }
132495
132949
  },
@@ -132568,7 +133022,7 @@ var files_spec_default = {
132568
133022
  termsOfService: "https://whop.com/tos-developer-api/",
132569
133023
  title: "Whop API",
132570
133024
  version: "1.0.0",
132571
- "x-api-version-date": "2026-10-13-1"
133025
+ "x-api-version-date": "2026-10-14"
132572
133026
  },
132573
133027
  paths: {
132574
133028
  "/files": {
@@ -133146,7 +133600,7 @@ var files_spec_default = {
133146
133600
  name: "Api-Version-Date",
133147
133601
  required: false,
133148
133602
  schema: {
133149
- example: "2026-10-13-1",
133603
+ example: "2026-10-14",
133150
133604
  type: "string"
133151
133605
  }
133152
133606
  },
@@ -133287,7 +133741,7 @@ async function announceActionUrl(url2, {
133287
133741
  // package.json
133288
133742
  var package_default = {
133289
133743
  name: "@whop/cli",
133290
- version: "0.26.0",
133744
+ version: "0.27.0",
133291
133745
  description: "The Whop CLI \u2014 build and manage Whop apps from your terminal. Human and agent friendly.",
133292
133746
  keywords: [
133293
133747
  "agent",
@@ -135658,7 +136112,7 @@ var groups_default = [
135658
136112
  {
135659
136113
  name: "payment-method-domains",
135660
136114
  tag: "Payment Method Domains",
135661
- description: "Domains verified to show wallet payment methods like Apple Pay at checkout.",
136115
+ description: "Deprecated: domains verified to show Apple Pay at checkout. Use Domains instead.",
135662
136116
  group: "Commerce"
135663
136117
  },
135664
136118
  {
@@ -135908,11 +136362,443 @@ async function buildSubgroupedGroup(name, description, spec2, fetch3) {
135908
136362
  // src/apps/commands.ts
135909
136363
  import { spinner as spinner4 } from "@clack/prompts";
135910
136364
  import { createHash as createHash3 } from "crypto";
135911
- import { existsSync as existsSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync12, rmSync as rmSync4 } from "fs";
136365
+ import { existsSync as existsSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync12, rmSync as rmSync5 } from "fs";
135912
136366
  import { tmpdir as tmpdir3 } from "os";
135913
- import { join as join12, relative as relative3, resolve as resolve9 } from "path";
136367
+ import { join as join13, relative as relative3, resolve as resolve9 } from "path";
135914
136368
  import chalk2 from "chalk";
135915
136369
 
136370
+ // src/apps/config.ts
136371
+ import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
136372
+ import { join as join6, resolve as resolve5 } from "path";
136373
+ var APP_CONFIG_FILENAME = "whop.app.json";
136374
+ var PLATFORM_DOMAIN_SUFFIX = "whop.site";
136375
+ function linkConfigFor(app) {
136376
+ return { app_id: app.id, name: app.name };
136377
+ }
136378
+ function findProjectDir(startDir) {
136379
+ let dir = resolve5(startDir ?? process.cwd());
136380
+ for (let i = 0; i < 25; i++) {
136381
+ if (existsSync8(join6(dir, APP_CONFIG_FILENAME))) return dir;
136382
+ const parent = resolve5(dir, "..");
136383
+ if (parent === dir) break;
136384
+ dir = parent;
136385
+ }
136386
+ return null;
136387
+ }
136388
+ function readAppConfig(projectDir) {
136389
+ const path9 = join6(projectDir, APP_CONFIG_FILENAME);
136390
+ if (!existsSync8(path9)) return null;
136391
+ try {
136392
+ const parsed = JSON.parse(
136393
+ readFileSync8(path9, "utf-8")
136394
+ );
136395
+ if (typeof parsed.app_id !== "string") return null;
136396
+ return {
136397
+ app_id: parsed.app_id,
136398
+ name: typeof parsed.name === "string" ? parsed.name : parsed.app_id
136399
+ };
136400
+ } catch {
136401
+ return null;
136402
+ }
136403
+ }
136404
+ function writeAppConfig(projectDir, config2) {
136405
+ writeFileSync6(
136406
+ join6(projectDir, APP_CONFIG_FILENAME),
136407
+ `${JSON.stringify(config2, null, " ")}
136408
+ `
136409
+ );
136410
+ }
136411
+ function appSlug(app) {
136412
+ return slugify4(app.name) || app.id.toLowerCase().replace("_", "-");
136413
+ }
136414
+ function platformDomainFor(name) {
136415
+ return `${slugify4(name)}.${PLATFORM_DOMAIN_SUFFIX}`;
136416
+ }
136417
+ function domainFor(input) {
136418
+ const host = input.trim().toLowerCase();
136419
+ return host.includes(".") ? host : platformDomainFor(host);
136420
+ }
136421
+ function slugify4(name) {
136422
+ return name.toLowerCase().normalize("NFKD").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 63);
136423
+ }
136424
+
136425
+ // src/apps/shared.ts
136426
+ import { isCancel as isCancel4, select as select3, spinner as spinner2, text as text2 } from "@clack/prompts";
136427
+ import { spawnSync as spawnSync2 } from "child_process";
136428
+ import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
136429
+ import { join as join8 } from "path";
136430
+
136431
+ // src/apps/scaffold.ts
136432
+ import { spawnSync } from "child_process";
136433
+ import { existsSync as existsSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
136434
+ import { basename as basename3, join as join7 } from "path";
136435
+ var SPAWN_VIA_SHELL = process.platform === "win32";
136436
+ var DLX_RUNNERS = {
136437
+ npm: ["npx", "-y"],
136438
+ pnpm: ["pnpm", "dlx"],
136439
+ bun: ["bunx"],
136440
+ yarn: ["yarn", "dlx"]
136441
+ };
136442
+ var PM_PRIORITY = [
136443
+ "bun",
136444
+ "pnpm",
136445
+ "npm"
136446
+ ];
136447
+ function isPmInstalled(pm) {
136448
+ const result = spawnSync(pm, ["--version"], {
136449
+ stdio: "ignore",
136450
+ shell: SPAWN_VIA_SHELL
136451
+ });
136452
+ return !result.error && result.status === 0;
136453
+ }
136454
+ function detectPackageManager() {
136455
+ return PM_PRIORITY.find(isPmInstalled) ?? null;
136456
+ }
136457
+ function pmInstallHint(pm) {
136458
+ const win = process.platform === "win32";
136459
+ switch (pm) {
136460
+ case "bun":
136461
+ return win ? 'powershell -c "irm bun.sh/install.ps1 | iex"' : "curl -fsSL https://bun.sh/install | bash";
136462
+ case "pnpm":
136463
+ return win ? 'powershell -c "irm get.pnpm.io/install.ps1 | iex"' : "curl -fsSL https://get.pnpm.io/install.sh | sh -";
136464
+ case "npm":
136465
+ return "install Node.js (includes npm): https://nodejs.org";
136466
+ case "yarn":
136467
+ return "npm install -g yarn";
136468
+ }
136469
+ }
136470
+ var TANSTACK_CREATE_FLAGS = [
136471
+ "--framework",
136472
+ "React",
136473
+ "--deployment",
136474
+ "cloudflare",
136475
+ "--no-git",
136476
+ "--no-install",
136477
+ "--no-intent",
136478
+ "--no-toolchain",
136479
+ "--no-examples",
136480
+ "--non-interactive"
136481
+ ];
136482
+ function outputTail(result) {
136483
+ const combined = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
136484
+ if (!combined) return "";
136485
+ return `
136486
+
136487
+ ${combined.split("\n").slice(-15).join("\n")}`;
136488
+ }
136489
+ function runTanstackCreate(options) {
136490
+ const [runner, ...runnerArgs] = DLX_RUNNERS[options.pm];
136491
+ const result = spawnSync(
136492
+ runner,
136493
+ [
136494
+ ...runnerArgs,
136495
+ "@tanstack/cli@latest",
136496
+ "create",
136497
+ options.projectName,
136498
+ "--target-dir",
136499
+ options.targetDir,
136500
+ ...TANSTACK_CREATE_FLAGS
136501
+ ],
136502
+ {
136503
+ stdio: ["ignore", "pipe", "pipe"],
136504
+ encoding: "utf-8",
136505
+ shell: SPAWN_VIA_SHELL
136506
+ }
136507
+ );
136508
+ if (result.error) throw result.error;
136509
+ if (result.status !== 0) {
136510
+ throw new Error(
136511
+ `\`${options.pm === "npm" ? "npx" : options.pm} @tanstack/cli create\` failed (exit ${result.status}). Check your network connection and try again.${outputTail(result)}`
136512
+ );
136513
+ }
136514
+ }
136515
+ var VITE_CONFIG_NAMES = [
136516
+ "vite.config.ts",
136517
+ "vite.config.mts",
136518
+ "vite.config.js",
136519
+ "vite.config.mjs"
136520
+ ];
136521
+ function findViteConfig(dir) {
136522
+ return VITE_CONFIG_NAMES.map((name) => join7(dir, name)).find(
136523
+ (path9) => existsSync9(path9)
136524
+ );
136525
+ }
136526
+ var WRANGLER_CONFIG_NAMES = ["wrangler.jsonc", "wrangler.json"];
136527
+ function whopifyProject(options) {
136528
+ const manualSteps = [];
136529
+ patchPackageJson(options.targetDir, manualSteps);
136530
+ patchViteConfig(options.targetDir, manualSteps);
136531
+ patchWranglerConfig(options.targetDir, options.workerName, manualSteps);
136532
+ return { manualSteps };
136533
+ }
136534
+ function patchPackageJson(dir, manualSteps) {
136535
+ const file2 = join7(dir, "package.json");
136536
+ let raw;
136537
+ let pkg;
136538
+ try {
136539
+ raw = readFileSync9(file2, "utf-8");
136540
+ pkg = JSON.parse(raw);
136541
+ } catch {
136542
+ manualSteps.push(
136543
+ 'package.json could not be parsed. Add a "deploy": "whop apps deploy" script, a "typecheck" script, and a devDependency "@whop/cli": "latest".'
136544
+ );
136545
+ return;
136546
+ }
136547
+ pkg.scripts = {
136548
+ ...pkg.scripts,
136549
+ deploy: "whop apps deploy",
136550
+ typecheck: pkg.scripts?.typecheck ?? "tsc --noEmit"
136551
+ };
136552
+ pkg.devDependencies = {
136553
+ ...pkg.devDependencies,
136554
+ // The project imports the whop() vite plugin from @whop/cli/vite. Pinned
136555
+ // to the building binary's own version until that broke: a standalone
136556
+ // build carries the workspace version, which is routinely ahead of what
136557
+ // is on npm, so the pin resolved to nothing and install failed.
136558
+ "@whop/cli": pkg.devDependencies?.["@whop/cli"] ?? "latest"
136559
+ };
136560
+ writeIfChanged(file2, `${JSON.stringify(pkg, null, 2)}
136561
+ `, raw);
136562
+ }
136563
+ function writeIfChanged(file2, next, current) {
136564
+ if (next === current) return;
136565
+ writeFileSync7(file2, next);
136566
+ }
136567
+ var WHOP_PLUGIN_CALL = "whop({ disableTanstackDevtools: true })";
136568
+ function patchViteConfig(dir, manualSteps) {
136569
+ const file2 = findViteConfig(dir);
136570
+ if (!file2) {
136571
+ manualSteps.push(
136572
+ "No vite config found (looked for vite.config.ts/.mts/.js/.mjs). Whop hosting serves Vite builds \u2014 create a vite config that builds with @cloudflare/vite-plugin (emitting dist/client and, for SSR, dist/server) and includes the whop() plugin from @whop/cli/vite in its plugins array."
136573
+ );
136574
+ return;
136575
+ }
136576
+ let content = readFileSync9(file2, "utf-8");
136577
+ const hasWhopPlugin = content.includes("@whop/cli/vite");
136578
+ if (!hasWhopPlugin) {
136579
+ const pluginsOpen = /plugins:\s*\[/;
136580
+ if (!pluginsOpen.test(content)) {
136581
+ manualSteps.push(
136582
+ `Could not find a \`plugins: [...]\` array in ${basename3(file2)}. Add \`import { whop } from '@whop/cli/vite'\` and include \`whop()\` in the config's plugins so builds pack dist/whop-build.zip.`
136583
+ );
136584
+ } else {
136585
+ content = `import { whop } from '@whop/cli/vite'
136586
+ ${content}`;
136587
+ content = content.replace(
136588
+ pluginsOpen,
136589
+ (match) => `${match}
136590
+ ${WHOP_PLUGIN_CALL},`
136591
+ );
136592
+ writeFileSync7(file2, content);
136593
+ }
136594
+ }
136595
+ if (!content.includes("@cloudflare/vite-plugin")) {
136596
+ manualSteps.push(
136597
+ `${basename3(file2)} does not use @cloudflare/vite-plugin. Whop hosting runs builds on Cloudflare Workers: install @cloudflare/vite-plugin and wrangler, add \`cloudflare({ viteEnvironment: { name: 'ssr' } })\` to the plugins array (before your framework plugin), and make sure \`vite build\` emits dist/client (static assets) and dist/server (worker modules with an index.js entry).`
136598
+ );
136599
+ }
136600
+ }
136601
+ function patchWranglerConfig(dir, workerName, manualSteps) {
136602
+ const file2 = WRANGLER_CONFIG_NAMES.map((name) => join7(dir, name)).find(
136603
+ (path9) => existsSync9(path9)
136604
+ );
136605
+ if (!file2) {
136606
+ manualSteps.push(
136607
+ `No wrangler config found. Create wrangler.jsonc with: { "name": "${workerName}", "compatibility_date": "<today>", "compatibility_flags": ["nodejs_compat"], "main": "<your framework's server entry>" } (for TanStack Start the main is "@tanstack/react-start/server-entry").`
136608
+ );
136609
+ return;
136610
+ }
136611
+ const content = readFileSync9(file2, "utf-8");
136612
+ const updated = replaceTopLevelName(content, workerName);
136613
+ if (updated) {
136614
+ writeIfChanged(file2, updated, content);
136615
+ } else {
136616
+ manualSteps.push(
136617
+ `Set the top-level "name" in ${basename3(file2)} to "${workerName}" so the worker is named after the app.`
136618
+ );
136619
+ }
136620
+ }
136621
+ function replaceTopLevelName(content, name) {
136622
+ let depth = 0;
136623
+ let i = 0;
136624
+ while (i < content.length) {
136625
+ const ch = content[i];
136626
+ if (ch === '"') {
136627
+ let j = i + 1;
136628
+ while (j < content.length && content[j] !== '"') {
136629
+ j += content[j] === "\\" ? 2 : 1;
136630
+ }
136631
+ if (depth === 1 && content.slice(i + 1, j) === "name") {
136632
+ const after = content.slice(j + 1);
136633
+ const value = after.match(/^(\s*:\s*)"(?:[^"\\]|\\.)*"/);
136634
+ if (value) {
136635
+ const start = j + 1 + value[1].length;
136636
+ const end = j + 1 + value[0].length;
136637
+ return `${content.slice(0, start)}"${name}"${content.slice(end)}`;
136638
+ }
136639
+ }
136640
+ i = j + 1;
136641
+ continue;
136642
+ }
136643
+ if (ch === "/" && content[i + 1] === "/") {
136644
+ const newline = content.indexOf("\n", i);
136645
+ i = newline === -1 ? content.length : newline + 1;
136646
+ continue;
136647
+ }
136648
+ if (ch === "/" && content[i + 1] === "*") {
136649
+ const close = content.indexOf("*/", i + 2);
136650
+ i = close === -1 ? content.length : close + 2;
136651
+ continue;
136652
+ }
136653
+ if (ch === "{" || ch === "[") depth++;
136654
+ if (ch === "}" || ch === "]") depth--;
136655
+ i++;
136656
+ }
136657
+ return null;
136658
+ }
136659
+
136660
+ // src/apps/shared.ts
136661
+ var CommandAbort = class extends Error {
136662
+ constructor(options) {
136663
+ super(options.message);
136664
+ this.options = options;
136665
+ }
136666
+ };
136667
+ function log2(c2, message) {
136668
+ if (!c2.agent) console.log(message);
136669
+ }
136670
+ var PHASE_MARKER = "[whop:phase]";
136671
+ function phase(name) {
136672
+ process.stderr.write(`${PHASE_MARKER} ${name} t=${Date.now()}
136673
+ `);
136674
+ }
136675
+ function cancelled() {
136676
+ throw new CommandAbort({
136677
+ code: "CANCELLED",
136678
+ message: "Cancelled.",
136679
+ exitCode: 130
136680
+ });
136681
+ }
136682
+ async function promptText(message, placeholder, initialValue) {
136683
+ const value = await text2({ message, placeholder, initialValue });
136684
+ if (isCancel4(value)) return null;
136685
+ return String(value);
136686
+ }
136687
+ async function promptSelect(message, options) {
136688
+ const choice = await select3({ message, options });
136689
+ if (isCancel4(choice)) cancelled();
136690
+ return String(choice);
136691
+ }
136692
+ async function promptForAppType() {
136693
+ const choice = await promptSelect("What are you building?", [
136694
+ { value: "b2c_app", label: "An app \u2014 creators install it into their whop" },
136695
+ { value: "website", label: "A website \u2014 visitors browse it at its domain" }
136696
+ ]);
136697
+ return choice;
136698
+ }
136699
+ async function promptForNewApp(knownAppType) {
136700
+ const appType = knownAppType ?? await promptForAppType();
136701
+ const name = await promptText("What is your app called?", "My Site");
136702
+ if (name === null) cancelled();
136703
+ return { name, domain: await promptForDomain(name), appType };
136704
+ }
136705
+ async function promptForDomain(name) {
136706
+ const suggested = platformDomainFor(name);
136707
+ const input = await promptText(
136708
+ `Which domain should it live at? (a ${PLATFORM_DOMAIN_SUFFIX} name, or a domain you own)`,
136709
+ suggested,
136710
+ suggested
136711
+ );
136712
+ if (input === null) cancelled();
136713
+ const domain2 = domainFor(input);
136714
+ if (domain2 === `.${PLATFORM_DOMAIN_SUFFIX}`) {
136715
+ throw new CommandAbort({
136716
+ code: "DOMAIN_REQUIRED",
136717
+ message: `Couldn't derive a domain from "${input}" \u2014 use letters and numbers (e.g. my-site).`,
136718
+ retryable: true
136719
+ });
136720
+ }
136721
+ return domain2;
136722
+ }
136723
+ function ensurePackageManager() {
136724
+ const pm = detectPackageManager();
136725
+ if (pm) return pm;
136726
+ throw new CommandAbort({
136727
+ code: "NO_PACKAGE_MANAGER",
136728
+ message: `No package manager found (looked for bun, pnpm, npm). Install one and retry:
136729
+
136730
+ bun (recommended): ${pmInstallHint("bun")}
136731
+ pnpm: ${pmInstallHint("pnpm")}
136732
+ npm: ${pmInstallHint("npm")}`
136733
+ });
136734
+ }
136735
+ var SPAWN_VIA_SHELL2 = process.platform === "win32";
136736
+ function detectProjectPackageManager(projectDir) {
136737
+ if (existsSync10(join8(projectDir, "bun.lock")) || existsSync10(join8(projectDir, "bun.lockb")))
136738
+ return "bun";
136739
+ if (existsSync10(join8(projectDir, "pnpm-lock.yaml"))) return "pnpm";
136740
+ if (existsSync10(join8(projectDir, "yarn.lock"))) return "yarn";
136741
+ if (existsSync10(join8(projectDir, "package-lock.json"))) return "npm";
136742
+ return detectPackageManager() ?? "npm";
136743
+ }
136744
+ function hasScript(projectDir, script) {
136745
+ try {
136746
+ const pkg = JSON.parse(
136747
+ readFileSync10(join8(projectDir, "package.json"), "utf-8")
136748
+ );
136749
+ return Boolean(pkg.scripts?.[script]);
136750
+ } catch {
136751
+ return false;
136752
+ }
136753
+ }
136754
+ function runScript(projectDir, script, extraEnv = {}, scriptArgs = []) {
136755
+ const pm = detectProjectPackageManager(projectDir);
136756
+ const separator = pm === "npm" && scriptArgs.length > 0 ? ["--"] : [];
136757
+ const result = spawnSync2(pm, ["run", script, ...separator, ...scriptArgs], {
136758
+ cwd: projectDir,
136759
+ stdio: "inherit",
136760
+ shell: SPAWN_VIA_SHELL2,
136761
+ env: { ...process.env, ...extraEnv }
136762
+ });
136763
+ if (result.error) {
136764
+ throw new Error(
136765
+ `Could not run \`${pm} run ${script}\`: ${result.error.message}`
136766
+ );
136767
+ }
136768
+ if (result.status !== 0) {
136769
+ throw new Error(
136770
+ `\`${pm} run ${script}\` failed with exit code ${result.status ?? "unknown"}`
136771
+ );
136772
+ }
136773
+ }
136774
+ function runInstall(c2, projectDir) {
136775
+ const pm = detectProjectPackageManager(projectDir);
136776
+ const spin = c2.agent ? null : spinner2();
136777
+ spin?.start(`Installing dependencies with ${pm}`);
136778
+ const result = spawnSync2(pm, ["install"], {
136779
+ cwd: projectDir,
136780
+ stdio: ["ignore", "pipe", "pipe"],
136781
+ encoding: "utf-8",
136782
+ shell: SPAWN_VIA_SHELL2
136783
+ });
136784
+ if (result.error || result.status !== 0) {
136785
+ spin?.error(`${pm} install failed`);
136786
+ throw new Error(
136787
+ `\`${pm} install\` failed${result.status != null ? ` with exit code ${result.status}` : ""} \u2014 run it manually inside ${projectDir}, then retry.${outputTail(result)}`
136788
+ );
136789
+ }
136790
+ spin?.stop(`Installed dependencies with ${pm}`);
136791
+ }
136792
+ async function downloadArchive(sourceUrl) {
136793
+ const response = await fetch(sourceUrl);
136794
+ if (!response.ok) {
136795
+ throw new Error(
136796
+ `Download failed: ${response.status} ${response.statusText}`
136797
+ );
136798
+ }
136799
+ return new Uint8Array(await response.arrayBuffer());
136800
+ }
136801
+
135916
136802
  // src/apps/api.ts
135917
136803
  async function createApp(input) {
135918
136804
  const company_id = input.company_id ?? await resolveActiveAccountId();
@@ -135938,8 +136824,70 @@ async function listApps() {
135938
136824
  async function getApp(appId) {
135939
136825
  return makeWhopRequest("GET", `/apps/${appId}`);
135940
136826
  }
135941
- async function updateAppRoute(appId, route) {
135942
- return makeWhopRequest("PATCH", `/apps/${appId}`, { route });
136827
+ async function pendingDomainSteps(app) {
136828
+ const pending = (app.domains ?? []).filter((d) => d.status !== "ready");
136829
+ const steps = await Promise.all(
136830
+ pending.map(async ({ id, domain: domain2 }) => {
136831
+ let details;
136832
+ try {
136833
+ details = await makeWhopRequest("GET", `/domains/${id}`);
136834
+ } catch (err2) {
136835
+ return [
136836
+ `Couldn't read ${domain2}'s status (${err2 instanceof Error ? err2.message : "unknown error"}); check it with \`whop domains get ${domain2}\`.`
136837
+ ];
136838
+ }
136839
+ const purchaseUrl = details.registration?.purchase_url;
136840
+ if (purchaseUrl)
136841
+ return [`Pay for ${domain2} to finish buying it: ${purchaseUrl}`];
136842
+ const issues = details.issues ?? [];
136843
+ if (issues.length === 0) {
136844
+ return [
136845
+ `${domain2} is ${details.status} and not serving yet; check it with \`whop domains get ${domain2}\`.`
136846
+ ];
136847
+ }
136848
+ return issues.map(
136849
+ (issue2) => `${domain2}: ${issue2.message} (records: \`whop domains get ${domain2}\`)`
136850
+ );
136851
+ })
136852
+ );
136853
+ return steps.flat();
136854
+ }
136855
+ async function ownerFor(hostname3) {
136856
+ if (hostname3.endsWith(`.${PLATFORM_DOMAIN_SUFFIX}`)) return { platform: {} };
136857
+ const lookup = await makeWhopRequest(
136858
+ "GET",
136859
+ `/domains/${encodeURIComponent(hostname3)}`
136860
+ );
136861
+ return lookup.availability?.available ? { registration: {} } : { verification: {} };
136862
+ }
136863
+ async function ensureDomain(input) {
136864
+ const website = input.appId ? { website: { app_id: input.appId } } : {};
136865
+ const accountId = input.accountId ?? await resolveActiveAccountId();
136866
+ const query = new URLSearchParams({
136867
+ domain: input.hostname,
136868
+ ...accountId ? { account_id: accountId } : {}
136869
+ });
136870
+ const owned = await makeWhopRequest(
136871
+ "GET",
136872
+ `/domains?${query}`
136873
+ );
136874
+ const existing = owned.data?.[0];
136875
+ const serving = existing?.website?.app?.id;
136876
+ if (serving && serving !== input.appId) {
136877
+ throw new CommandAbort({
136878
+ code: "DOMAIN_IN_USE",
136879
+ message: `${input.hostname} already serves ${serving}, so it was left as it is. To work on that app, run \`whop apps pull --app ${serving}\`, or \`whop apps init --app ${serving}\` if it has never been deployed. Otherwise ask the user for another domain.`
136880
+ });
136881
+ }
136882
+ if (existing) {
136883
+ return input.appId ? makeWhopRequest("PATCH", `/domains/${existing.id}`, website) : existing;
136884
+ }
136885
+ return makeWhopRequest("POST", "/domains", {
136886
+ account_id: accountId,
136887
+ domain: input.hostname,
136888
+ ...await ownerFor(input.hostname),
136889
+ ...website
136890
+ });
135943
136891
  }
135944
136892
  async function updateAppSecrets(appId, secrets) {
135945
136893
  return makeWhopRequest("PATCH", `/apps/${appId}`, { secrets });
@@ -135953,6 +136901,18 @@ async function createAppBuild(input) {
135953
136901
  ...input.source_file_id ? { source_attachment: { id: input.source_file_id } } : {}
135954
136902
  });
135955
136903
  }
136904
+ async function hasWebBuilds(appId) {
136905
+ const query = new URLSearchParams({
136906
+ app_id: appId,
136907
+ platform: "web",
136908
+ first: "1"
136909
+ });
136910
+ const builds = await makeWhopRequest(
136911
+ "GET",
136912
+ `/app_builds?${query}`
136913
+ );
136914
+ return (builds.data?.length ?? 0) > 0;
136915
+ }
135956
136916
  async function getAppBuild(buildId) {
135957
136917
  return makeWhopRequest("GET", `/app_builds/${buildId}`);
135958
136918
  }
@@ -136012,57 +136972,17 @@ function sleep(ms) {
136012
136972
  return new Promise((resolve10) => setTimeout(resolve10, ms));
136013
136973
  }
136014
136974
 
136015
- // src/apps/config.ts
136016
- import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
136017
- import { join as join6, resolve as resolve5 } from "path";
136018
- var APP_CONFIG_FILENAME = "whop.app.json";
136019
- function findProjectDir(startDir) {
136020
- let dir = resolve5(startDir ?? process.cwd());
136021
- for (let i = 0; i < 25; i++) {
136022
- if (existsSync8(join6(dir, APP_CONFIG_FILENAME))) return dir;
136023
- const parent = resolve5(dir, "..");
136024
- if (parent === dir) break;
136025
- dir = parent;
136026
- }
136027
- return null;
136028
- }
136029
- function readAppConfig(projectDir) {
136030
- const path9 = join6(projectDir, APP_CONFIG_FILENAME);
136031
- if (!existsSync8(path9)) return null;
136032
- try {
136033
- const parsed = JSON.parse(
136034
- readFileSync8(path9, "utf-8")
136035
- );
136036
- if (typeof parsed.app_id === "string" && typeof parsed.name === "string" && typeof parsed.route === "string") {
136037
- return { app_id: parsed.app_id, name: parsed.name, route: parsed.route };
136038
- }
136039
- return null;
136040
- } catch {
136041
- return null;
136042
- }
136043
- }
136044
- function writeAppConfig(projectDir, config2) {
136045
- writeFileSync6(
136046
- join6(projectDir, APP_CONFIG_FILENAME),
136047
- `${JSON.stringify(config2, null, " ")}
136048
- `
136049
- );
136050
- }
136051
- function slugify4(name) {
136052
- return name.toLowerCase().normalize("NFKD").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 63);
136053
- }
136054
-
136055
136975
  // src/apps/git.ts
136056
- import { spawnSync } from "child_process";
136976
+ import { spawnSync as spawnSync3 } from "child_process";
136057
136977
  import { mkdtempSync, realpathSync as realpathSync3, rmSync as rmSync2 } from "fs";
136058
136978
  import { tmpdir } from "os";
136059
- import { join as join7 } from "path";
136060
- var SPAWN_VIA_SHELL = process.platform === "win32";
136979
+ import { join as join9 } from "path";
136980
+ var SPAWN_VIA_SHELL3 = process.platform === "win32";
136061
136981
  function runGit(dir, args, env = {}) {
136062
- const result = spawnSync("git", args, {
136982
+ const result = spawnSync3("git", args, {
136063
136983
  cwd: dir,
136064
136984
  encoding: "utf-8",
136065
- shell: SPAWN_VIA_SHELL,
136985
+ shell: SPAWN_VIA_SHELL3,
136066
136986
  env: { ...process.env, ...env },
136067
136987
  maxBuffer: 128 * 1024 * 1024
136068
136988
  });
@@ -136083,9 +137003,9 @@ function mustGit(dir, args, env = {}) {
136083
137003
  return result.stdout;
136084
137004
  }
136085
137005
  function gitInstalled() {
136086
- const result = spawnSync("git", ["--version"], {
137006
+ const result = spawnSync3("git", ["--version"], {
136087
137007
  stdio: "ignore",
136088
- shell: SPAWN_VIA_SHELL
137008
+ shell: SPAWN_VIA_SHELL3
136089
137009
  });
136090
137010
  return !result.error && result.status === 0;
136091
137011
  }
@@ -136126,12 +137046,12 @@ function commitAll(dir, message) {
136126
137046
  function commitSnapshot(repoDir, snapshotDir, appId, message, options = {}) {
136127
137047
  const ref = remoteRef(appId);
136128
137048
  const gitDir = mustGit(repoDir, ["rev-parse", "--absolute-git-dir"]);
136129
- const scratch = mkdtempSync(join7(tmpdir(), "whop-git-"));
137049
+ const scratch = mkdtempSync(join9(tmpdir(), "whop-git-"));
136130
137050
  try {
136131
137051
  const env = {
136132
137052
  GIT_DIR: gitDir,
136133
137053
  GIT_WORK_TREE: snapshotDir,
136134
- GIT_INDEX_FILE: join7(scratch, "index")
137054
+ GIT_INDEX_FILE: join9(scratch, "index")
136135
137055
  };
136136
137056
  mustGit(snapshotDir, ["add", "-A", "-f", "."], env);
136137
137057
  const tree = mustGit(snapshotDir, ["write-tree"], env);
@@ -136205,20 +137125,20 @@ function stashPop(dir) {
136205
137125
 
136206
137126
  // src/apps/init.ts
136207
137127
  import { spinner as spinner3 } from "@clack/prompts";
136208
- import { existsSync as existsSync11, readdirSync as readdirSync3 } from "fs";
136209
- import { resolve as resolve7 } from "path";
137128
+ import { existsSync as existsSync11, readdirSync as readdirSync3, rmSync as rmSync3 } from "fs";
137129
+ import { join as join11, resolve as resolve7 } from "path";
136210
137130
  import chalk from "chalk";
136211
137131
 
136212
137132
  // src/apps/source-archive.ts
136213
- import { spawnSync as spawnSync2 } from "child_process";
137133
+ import { spawnSync as spawnSync4 } from "child_process";
136214
137134
  import {
136215
137135
  mkdirSync as mkdirSync7,
136216
137136
  readdirSync as readdirSync2,
136217
- readFileSync as readFileSync9,
137137
+ readFileSync as readFileSync11,
136218
137138
  statSync as statSync2,
136219
- writeFileSync as writeFileSync7
137139
+ writeFileSync as writeFileSync8
136220
137140
  } from "fs";
136221
- import { dirname as dirname8, join as join8, resolve as resolve6, sep as sep2 } from "path";
137141
+ import { dirname as dirname8, join as join10, resolve as resolve6, sep as sep2 } from "path";
136222
137142
 
136223
137143
  // ../../node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/index.mjs
136224
137144
  import { createRequire as createRequire3 } from "module";
@@ -137229,7 +138149,7 @@ function isExcluded(path9) {
137229
138149
  return segments.slice(0, -1).some((dir) => EXCLUDED_DIRS.has(dir)) || isExcludedFile(segments[segments.length - 1]);
137230
138150
  }
137231
138151
  function listGitFiles(projectDir) {
137232
- const listed = spawnSync2(
138152
+ const listed = spawnSync4(
137233
138153
  "git",
137234
138154
  ["ls-files", "--cached", "--others", "--exclude-standard", "-z"],
137235
138155
  { cwd: projectDir, encoding: "utf-8", maxBuffer: 128 * 1024 * 1024 }
@@ -137238,7 +138158,7 @@ function listGitFiles(projectDir) {
137238
138158
  return [...new Set(listed.stdout.split("\0").filter(Boolean))].filter(
137239
138159
  (path9) => {
137240
138160
  try {
137241
- return statSync2(join8(projectDir, path9)).isFile();
138161
+ return statSync2(join10(projectDir, path9)).isFile();
137242
138162
  } catch {
137243
138163
  return false;
137244
138164
  }
@@ -137247,7 +138167,7 @@ function listGitFiles(projectDir) {
137247
138167
  }
137248
138168
  function walkProject(projectDir, prefix = "") {
137249
138169
  const files = [];
137250
- for (const entry of readdirSync2(join8(projectDir, prefix), {
138170
+ for (const entry of readdirSync2(join10(projectDir, prefix), {
137251
138171
  withFileTypes: true
137252
138172
  })) {
137253
138173
  const path9 = prefix ? `${prefix}/${entry.name}` : entry.name;
@@ -137269,7 +138189,7 @@ function packSourceArchive(projectDir) {
137269
138189
  }
137270
138190
  const contents = {};
137271
138191
  for (const path9 of paths) {
137272
- contents[path9] = readFileSync9(join8(projectDir, path9));
138192
+ contents[path9] = readFileSync11(join10(projectDir, path9));
137273
138193
  }
137274
138194
  return {
137275
138195
  zip: zipSync(contents, { level: 9, mem: 12 }),
@@ -137287,396 +138207,27 @@ function extractSourceArchive(zip, targetDir) {
137287
138207
  throw new Error(`Archive entry escapes the target directory: ${name}`);
137288
138208
  }
137289
138209
  mkdirSync7(dirname8(dest), { recursive: true });
137290
- writeFileSync7(dest, data);
138210
+ writeFileSync8(dest, data);
137291
138211
  count++;
137292
138212
  }
137293
138213
  return count;
137294
138214
  }
137295
138215
 
137296
- // src/apps/scaffold.ts
137297
- import { spawnSync as spawnSync3 } from "child_process";
137298
- import { existsSync as existsSync9, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
137299
- import { basename as basename3, join as join9 } from "path";
137300
- var SPAWN_VIA_SHELL2 = process.platform === "win32";
137301
- var DLX_RUNNERS = {
137302
- npm: ["npx", "-y"],
137303
- pnpm: ["pnpm", "dlx"],
137304
- bun: ["bunx"],
137305
- yarn: ["yarn", "dlx"]
137306
- };
137307
- var PM_PRIORITY = [
137308
- "bun",
137309
- "pnpm",
137310
- "npm"
137311
- ];
137312
- function isPmInstalled(pm) {
137313
- const result = spawnSync3(pm, ["--version"], {
137314
- stdio: "ignore",
137315
- shell: SPAWN_VIA_SHELL2
137316
- });
137317
- return !result.error && result.status === 0;
137318
- }
137319
- function detectPackageManager() {
137320
- return PM_PRIORITY.find(isPmInstalled) ?? null;
137321
- }
137322
- function pmInstallHint(pm) {
137323
- const win = process.platform === "win32";
137324
- switch (pm) {
137325
- case "bun":
137326
- return win ? 'powershell -c "irm bun.sh/install.ps1 | iex"' : "curl -fsSL https://bun.sh/install | bash";
137327
- case "pnpm":
137328
- return win ? 'powershell -c "irm get.pnpm.io/install.ps1 | iex"' : "curl -fsSL https://get.pnpm.io/install.sh | sh -";
137329
- case "npm":
137330
- return "install Node.js (includes npm): https://nodejs.org";
137331
- case "yarn":
137332
- return "npm install -g yarn";
137333
- }
137334
- }
137335
- var TANSTACK_CREATE_FLAGS = [
137336
- "--framework",
137337
- "React",
137338
- "--deployment",
137339
- "cloudflare",
137340
- "--no-git",
137341
- "--no-install",
137342
- "--no-intent",
137343
- "--no-toolchain",
137344
- "--no-examples",
137345
- "--non-interactive"
137346
- ];
137347
- function outputTail(result) {
137348
- const combined = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
137349
- if (!combined) return "";
137350
- return `
137351
-
137352
- ${combined.split("\n").slice(-15).join("\n")}`;
137353
- }
137354
- function runTanstackCreate(options) {
137355
- const [runner, ...runnerArgs] = DLX_RUNNERS[options.pm];
137356
- const result = spawnSync3(
137357
- runner,
137358
- [
137359
- ...runnerArgs,
137360
- "@tanstack/cli@latest",
137361
- "create",
137362
- options.projectName,
137363
- "--target-dir",
137364
- options.targetDir,
137365
- ...TANSTACK_CREATE_FLAGS
137366
- ],
137367
- {
137368
- stdio: ["ignore", "pipe", "pipe"],
137369
- encoding: "utf-8",
137370
- shell: SPAWN_VIA_SHELL2
137371
- }
137372
- );
137373
- if (result.error) throw result.error;
137374
- if (result.status !== 0) {
137375
- throw new Error(
137376
- `\`${options.pm === "npm" ? "npx" : options.pm} @tanstack/cli create\` failed (exit ${result.status}). Check your network connection and try again.${outputTail(result)}`
137377
- );
137378
- }
137379
- }
137380
- var VITE_CONFIG_NAMES = [
137381
- "vite.config.ts",
137382
- "vite.config.mts",
137383
- "vite.config.js",
137384
- "vite.config.mjs"
137385
- ];
137386
- function findViteConfig(dir) {
137387
- return VITE_CONFIG_NAMES.map((name) => join9(dir, name)).find(
137388
- (path9) => existsSync9(path9)
137389
- );
137390
- }
137391
- var WRANGLER_CONFIG_NAMES = ["wrangler.jsonc", "wrangler.json"];
137392
- function whopifyProject(options) {
137393
- const manualSteps = [];
137394
- patchPackageJson(options.targetDir, manualSteps);
137395
- patchViteConfig(options.targetDir, manualSteps);
137396
- patchWranglerConfig(options.targetDir, options.route, manualSteps);
137397
- return { manualSteps };
137398
- }
137399
- function patchPackageJson(dir, manualSteps) {
137400
- const file2 = join9(dir, "package.json");
137401
- let raw;
137402
- let pkg;
137403
- try {
137404
- raw = readFileSync10(file2, "utf-8");
137405
- pkg = JSON.parse(raw);
137406
- } catch {
137407
- manualSteps.push(
137408
- 'package.json could not be parsed. Add a "deploy": "whop apps deploy" script, a "typecheck" script, and a devDependency "@whop/cli": "latest".'
137409
- );
137410
- return;
137411
- }
137412
- pkg.scripts = {
137413
- ...pkg.scripts,
137414
- deploy: "whop apps deploy",
137415
- typecheck: pkg.scripts?.typecheck ?? "tsc --noEmit"
137416
- };
137417
- pkg.devDependencies = {
137418
- ...pkg.devDependencies,
137419
- // The project imports the whop() vite plugin from @whop/cli/vite. Pinned
137420
- // to the building binary's own version until that broke: a standalone
137421
- // build carries the workspace version, which is routinely ahead of what
137422
- // is on npm, so the pin resolved to nothing and install failed.
137423
- "@whop/cli": pkg.devDependencies?.["@whop/cli"] ?? "latest"
137424
- };
137425
- writeIfChanged(file2, `${JSON.stringify(pkg, null, 2)}
137426
- `, raw);
137427
- }
137428
- function writeIfChanged(file2, next, current) {
137429
- if (next === current) return;
137430
- writeFileSync8(file2, next);
137431
- }
137432
- var WHOP_PLUGIN_CALL = "whop({ disableTanstackDevtools: true })";
137433
- function patchViteConfig(dir, manualSteps) {
137434
- const file2 = findViteConfig(dir);
137435
- if (!file2) {
137436
- manualSteps.push(
137437
- "No vite config found (looked for vite.config.ts/.mts/.js/.mjs). Whop hosting serves Vite builds \u2014 create a vite config that builds with @cloudflare/vite-plugin (emitting dist/client and, for SSR, dist/server) and includes the whop() plugin from @whop/cli/vite in its plugins array."
137438
- );
137439
- return;
137440
- }
137441
- let content = readFileSync10(file2, "utf-8");
137442
- const hasWhopPlugin = content.includes("@whop/cli/vite");
137443
- if (!hasWhopPlugin) {
137444
- const pluginsOpen = /plugins:\s*\[/;
137445
- if (!pluginsOpen.test(content)) {
137446
- manualSteps.push(
137447
- `Could not find a \`plugins: [...]\` array in ${basename3(file2)}. Add \`import { whop } from '@whop/cli/vite'\` and include \`whop()\` in the config's plugins so builds pack dist/whop-build.zip.`
137448
- );
137449
- } else {
137450
- content = `import { whop } from '@whop/cli/vite'
137451
- ${content}`;
137452
- content = content.replace(
137453
- pluginsOpen,
137454
- (match) => `${match}
137455
- ${WHOP_PLUGIN_CALL},`
137456
- );
137457
- writeFileSync8(file2, content);
137458
- }
137459
- }
137460
- if (!content.includes("@cloudflare/vite-plugin")) {
137461
- manualSteps.push(
137462
- `${basename3(file2)} does not use @cloudflare/vite-plugin. Whop hosting runs builds on Cloudflare Workers: install @cloudflare/vite-plugin and wrangler, add \`cloudflare({ viteEnvironment: { name: 'ssr' } })\` to the plugins array (before your framework plugin), and make sure \`vite build\` emits dist/client (static assets) and dist/server (worker modules with an index.js entry).`
137463
- );
137464
- }
137465
- }
137466
- function patchWranglerConfig(dir, route, manualSteps) {
137467
- const file2 = WRANGLER_CONFIG_NAMES.map((name) => join9(dir, name)).find(
137468
- (path9) => existsSync9(path9)
137469
- );
137470
- if (!file2) {
137471
- manualSteps.push(
137472
- `No wrangler config found. Create wrangler.jsonc with: { "name": "${route}", "compatibility_date": "<today>", "compatibility_flags": ["nodejs_compat"], "main": "<your framework's server entry>" } (for TanStack Start the main is "@tanstack/react-start/server-entry").`
137473
- );
137474
- return;
137475
- }
137476
- const content = readFileSync10(file2, "utf-8");
137477
- const updated = replaceTopLevelName(content, route);
137478
- if (updated) {
137479
- writeIfChanged(file2, updated, content);
137480
- } else {
137481
- manualSteps.push(
137482
- `Set the top-level "name" in ${basename3(file2)} to "${route}" so the worker is named after the app's route.`
137483
- );
137484
- }
137485
- }
137486
- function replaceTopLevelName(content, route) {
137487
- let depth = 0;
137488
- let i = 0;
137489
- while (i < content.length) {
137490
- const ch = content[i];
137491
- if (ch === '"') {
137492
- let j = i + 1;
137493
- while (j < content.length && content[j] !== '"') {
137494
- j += content[j] === "\\" ? 2 : 1;
137495
- }
137496
- if (depth === 1 && content.slice(i + 1, j) === "name") {
137497
- const after = content.slice(j + 1);
137498
- const value = after.match(/^(\s*:\s*)"(?:[^"\\]|\\.)*"/);
137499
- if (value) {
137500
- const start = j + 1 + value[1].length;
137501
- const end = j + 1 + value[0].length;
137502
- return `${content.slice(0, start)}"${route}"${content.slice(end)}`;
137503
- }
137504
- }
137505
- i = j + 1;
137506
- continue;
137507
- }
137508
- if (ch === "/" && content[i + 1] === "/") {
137509
- const newline = content.indexOf("\n", i);
137510
- i = newline === -1 ? content.length : newline + 1;
137511
- continue;
137512
- }
137513
- if (ch === "/" && content[i + 1] === "*") {
137514
- const close = content.indexOf("*/", i + 2);
137515
- i = close === -1 ? content.length : close + 2;
137516
- continue;
137517
- }
137518
- if (ch === "{" || ch === "[") depth++;
137519
- if (ch === "}" || ch === "]") depth--;
137520
- i++;
137521
- }
137522
- return null;
137523
- }
137524
-
137525
- // src/apps/shared.ts
137526
- import { isCancel as isCancel4, select as select3, spinner as spinner2, text as text2 } from "@clack/prompts";
137527
- import { spawnSync as spawnSync4 } from "child_process";
137528
- import { existsSync as existsSync10, readFileSync as readFileSync11 } from "fs";
137529
- import { join as join10 } from "path";
137530
- var CommandAbort = class extends Error {
137531
- constructor(options) {
137532
- super(options.message);
137533
- this.options = options;
137534
- }
137535
- };
137536
- function log2(c2, message) {
137537
- if (!c2.agent) console.log(message);
137538
- }
137539
- var PHASE_MARKER = "[whop:phase]";
137540
- function phase(name) {
137541
- process.stderr.write(`${PHASE_MARKER} ${name} t=${Date.now()}
137542
- `);
137543
- }
137544
- function cancelled() {
137545
- throw new CommandAbort({
137546
- code: "CANCELLED",
137547
- message: "Cancelled.",
137548
- exitCode: 130
137549
- });
137550
- }
137551
- async function promptText(message, placeholder, initialValue) {
137552
- const value = await text2({ message, placeholder, initialValue });
137553
- if (isCancel4(value)) return null;
137554
- return String(value);
137555
- }
137556
- async function promptSelect(message, options) {
137557
- const choice = await select3({ message, options });
137558
- if (isCancel4(choice)) cancelled();
137559
- return String(choice);
137560
- }
137561
- async function promptForAppType() {
137562
- const choice = await promptSelect("What are you building?", [
137563
- { value: "b2c_app", label: "An app \u2014 creators install it into their whop" },
137564
- { value: "website", label: "A website \u2014 visitors browse it at your route" }
137565
- ]);
137566
- return choice;
137567
- }
137568
- async function promptForNewApp(knownAppType) {
137569
- const appType = knownAppType ?? await promptForAppType();
137570
- const name = await promptText("What is your app called?", "My Site");
137571
- if (name === null) cancelled();
137572
- const slug = slugify4(name);
137573
- const routeInput = await promptText(
137574
- "Which route should it live at? (your-route.whop.site)",
137575
- slug,
137576
- slug
137577
- );
137578
- if (routeInput === null) cancelled();
137579
- const route = slugify4(routeInput);
137580
- if (!route) {
137581
- throw new CommandAbort({
137582
- code: "ROUTE_REQUIRED",
137583
- message: `Couldn't derive a route from "${routeInput}" \u2014 use letters and numbers (e.g. my-site).`,
137584
- retryable: true
137585
- });
137586
- }
137587
- return { name, route, appType };
137588
- }
137589
- function ensurePackageManager() {
137590
- const pm = detectPackageManager();
137591
- if (pm) return pm;
137592
- throw new CommandAbort({
137593
- code: "NO_PACKAGE_MANAGER",
137594
- message: `No package manager found (looked for bun, pnpm, npm). Install one and retry:
137595
-
137596
- bun (recommended): ${pmInstallHint("bun")}
137597
- pnpm: ${pmInstallHint("pnpm")}
137598
- npm: ${pmInstallHint("npm")}`
137599
- });
137600
- }
137601
- var SPAWN_VIA_SHELL3 = process.platform === "win32";
137602
- function detectProjectPackageManager(projectDir) {
137603
- if (existsSync10(join10(projectDir, "bun.lock")) || existsSync10(join10(projectDir, "bun.lockb")))
137604
- return "bun";
137605
- if (existsSync10(join10(projectDir, "pnpm-lock.yaml"))) return "pnpm";
137606
- if (existsSync10(join10(projectDir, "yarn.lock"))) return "yarn";
137607
- if (existsSync10(join10(projectDir, "package-lock.json"))) return "npm";
137608
- return detectPackageManager() ?? "npm";
137609
- }
137610
- function hasScript(projectDir, script) {
137611
- try {
137612
- const pkg = JSON.parse(
137613
- readFileSync11(join10(projectDir, "package.json"), "utf-8")
137614
- );
137615
- return Boolean(pkg.scripts?.[script]);
137616
- } catch {
137617
- return false;
137618
- }
137619
- }
137620
- function runScript(projectDir, script, extraEnv = {}, scriptArgs = []) {
137621
- const pm = detectProjectPackageManager(projectDir);
137622
- const separator = pm === "npm" && scriptArgs.length > 0 ? ["--"] : [];
137623
- const result = spawnSync4(pm, ["run", script, ...separator, ...scriptArgs], {
137624
- cwd: projectDir,
137625
- stdio: "inherit",
137626
- shell: SPAWN_VIA_SHELL3,
137627
- env: { ...process.env, ...extraEnv }
137628
- });
137629
- if (result.error) {
137630
- throw new Error(
137631
- `Could not run \`${pm} run ${script}\`: ${result.error.message}`
137632
- );
137633
- }
137634
- if (result.status !== 0) {
137635
- throw new Error(
137636
- `\`${pm} run ${script}\` failed with exit code ${result.status ?? "unknown"}`
137637
- );
137638
- }
137639
- }
137640
- function runInstall(c2, projectDir) {
137641
- const pm = detectProjectPackageManager(projectDir);
137642
- const spin = c2.agent ? null : spinner2();
137643
- spin?.start(`Installing dependencies with ${pm}`);
137644
- const result = spawnSync4(pm, ["install"], {
137645
- cwd: projectDir,
137646
- stdio: ["ignore", "pipe", "pipe"],
137647
- encoding: "utf-8",
137648
- shell: SPAWN_VIA_SHELL3
137649
- });
137650
- if (result.error || result.status !== 0) {
137651
- spin?.error(`${pm} install failed`);
137652
- throw new Error(
137653
- `\`${pm} install\` failed${result.status != null ? ` with exit code ${result.status}` : ""} \u2014 run it manually inside ${projectDir}, then retry.${outputTail(result)}`
137654
- );
137655
- }
137656
- spin?.stop(`Installed dependencies with ${pm}`);
137657
- }
137658
- async function downloadArchive(sourceUrl) {
137659
- const response = await fetch(sourceUrl);
137660
- if (!response.ok) {
137661
- throw new Error(
137662
- `Download failed: ${response.status} ${response.statusText}`
137663
- );
137664
- }
137665
- return new Uint8Array(await response.arrayBuffer());
137666
- }
137667
-
137668
138216
  // src/apps/init.ts
137669
138217
  var initOptions = external_exports.object({
138218
+ app: external_exports.string().optional().describe(
138219
+ "Start the code for this existing app (app_xxx) instead of registering a new one \u2014 for an app that has never been deployed, such as a website created on whop.com. Its name, address and type come from the app"
138220
+ ),
137670
138221
  name: external_exports.string().optional().describe("Name for the new app (prompted for interactively if omitted)"),
137671
- route: external_exports.string().optional().describe(
137672
- "Route the app is served from (<route>.whop.site). Defaults to a slug of the name"
138222
+ domain: external_exports.string().optional().describe(
138223
+ "Domain the app is served at: a whop.site name such as my-site (my-site.whop.site), or a domain the account owns. Defaults to the name's whop.site address"
137673
138224
  ),
137674
138225
  template: external_exports.string().optional().describe(
137675
138226
  "Clone this app's published source archive (app_xxx) instead of the blank TanStack Start template"
137676
138227
  ),
137677
- dir: external_exports.string().optional().describe("Target directory (defaults to ./<route>)"),
138228
+ dir: external_exports.string().optional().describe("Target directory (defaults to ./<app name>)"),
137678
138229
  app_type: external_exports.enum(["b2c_app", "website"]).optional().describe(
137679
- "What you are building: b2c_app (creators install it into their whop) or website (visitors browse it at your route). Asked interactively if omitted, and required when there is nobody to ask"
138230
+ "What you are building: b2c_app (creators install it into their whop) or website (visitors browse it at its domain). Asked interactively if omitted, and required when there is nobody to ask"
137680
138231
  ),
137681
138232
  company_id: external_exports.string().optional().describe(
137682
138233
  "Company the app belongs to (biz_xxx). Defaults to the active account, and is required when the credential has none"
@@ -137688,19 +138239,22 @@ var initOptions = external_exports.object({
137688
138239
  var initOutput = external_exports.object({
137689
138240
  app_id: external_exports.string(),
137690
138241
  name: external_exports.string(),
137691
- route: external_exports.string(),
138242
+ domain: external_exports.string().optional(),
137692
138243
  dir: external_exports.string(),
137693
- manual_steps: external_exports.array(external_exports.string()).optional()
138244
+ manual_steps: external_exports.array(external_exports.string()).optional(),
138245
+ domain_steps: external_exports.array(external_exports.string()).optional().describe(
138246
+ "What the owner must do before the domain serves the app: pay at a purchase link, or publish DNS records"
138247
+ )
137694
138248
  });
137695
- async function resolveAppType(c2, name, route) {
138249
+ async function resolveAppType(c2, name, domain2) {
137696
138250
  if (!c2.agent) return promptForAppType();
137697
138251
  throw new CommandAbort({
137698
138252
  code: "APP_TYPE_REQUIRED",
137699
138253
  message: [
137700
138254
  "Nothing was created. Ask the user what they are building, then re-run with --app_type:",
137701
138255
  "",
137702
- ` whop apps init --name "${name}" --route ${route} --app_type b2c_app (creators install it into their whop)`,
137703
- ` whop apps init --name "${name}" --route ${route} --app_type website (visitors browse it at ${route}.whop.site)`,
138256
+ ` whop apps init --name "${name}" --domain ${domain2} --app_type b2c_app (creators install it into their whop)`,
138257
+ ` whop apps init --name "${name}" --domain ${domain2} --app_type website (visitors browse it at ${domain2})`,
137704
138258
  "",
137705
138259
  "Ask rather than guess: a website cannot be turned back into an app later."
137706
138260
  ].join("\n"),
@@ -137715,19 +138269,19 @@ async function resolveAppType(c2, name, route) {
137715
138269
  }
137716
138270
  });
137717
138271
  }
137718
- async function resolveNameAndRoute(c2, options, templateAppType) {
138272
+ async function resolveNameAndDomain(c2, options, templateAppType) {
137719
138273
  const knownAppType = options.app_type ?? templateAppType;
137720
138274
  if (options.name) {
137721
- const route = slugify4(options.route ?? options.name);
137722
- if (!route) {
138275
+ const domain2 = options.domain ? domainFor(options.domain) : platformDomainFor(options.name);
138276
+ if (domain2 === `.${PLATFORM_DOMAIN_SUFFIX}`) {
137723
138277
  throw new CommandAbort({
137724
- code: "ROUTE_REQUIRED",
137725
- message: `Couldn't derive a route from "${options.route ?? options.name}" \u2014 use letters and numbers (e.g. my-site).`,
138278
+ code: "DOMAIN_REQUIRED",
138279
+ message: `Couldn't derive a domain from "${options.domain ?? options.name}" \u2014 use letters and numbers (e.g. my-site).`,
137726
138280
  retryable: true
137727
138281
  });
137728
138282
  }
137729
- const appType = knownAppType ?? await resolveAppType(c2, options.name, route);
137730
- return { name: options.name, route, appType };
138283
+ const appType = knownAppType ?? await resolveAppType(c2, options.name, domain2);
138284
+ return { name: options.name, domain: domain2, appType };
137731
138285
  }
137732
138286
  if (c2.agent) {
137733
138287
  throw new CommandAbort({
@@ -137735,10 +138289,10 @@ async function resolveNameAndRoute(c2, options, templateAppType) {
137735
138289
  message: [
137736
138290
  "Ask the user three things, then re-run with flags:",
137737
138291
  " 1. What the app is called.",
137738
- " 2. Which route it should live at (the route becomes <route>.whop.site).",
138292
+ " 2. Which domain it should live at: a whop.site name (my-site \u2192 my-site.whop.site) or a domain they own.",
137739
138293
  " 3. Whether they are building an app creators install into their whop, or a website visitors browse.",
137740
138294
  "",
137741
- ' whop apps init --name "My Site" --route my-site --app_type website',
138295
+ ' whop apps init --name "My Site" --domain my-site --app_type website',
137742
138296
  "",
137743
138297
  "--app_type takes b2c_app or website, and is required here. Ask rather than guess: a website cannot be turned back into an app later."
137744
138298
  ].join("\n"),
@@ -137747,25 +138301,17 @@ async function resolveNameAndRoute(c2, options, templateAppType) {
137747
138301
  commands: [
137748
138302
  {
137749
138303
  command: "apps init",
137750
- description: "Re-run with --name and --app_type (and optionally --route)"
138304
+ description: "Re-run with --name and --app_type (and optionally --domain)"
137751
138305
  }
137752
138306
  ]
137753
138307
  }
137754
138308
  });
137755
138309
  }
137756
- if (options.route) {
138310
+ if (options.domain) {
137757
138311
  const appType = knownAppType ?? await promptForAppType();
137758
138312
  const name = await promptText("What is your app called?", "My Site");
137759
138313
  if (name === null) cancelled();
137760
- const route = slugify4(options.route);
137761
- if (!route) {
137762
- throw new CommandAbort({
137763
- code: "ROUTE_REQUIRED",
137764
- message: `Couldn't derive a route from "${options.route}" \u2014 use letters and numbers (e.g. my-site).`,
137765
- retryable: true
137766
- });
137767
- }
137768
- return { name, route, appType };
138314
+ return { name, domain: domainFor(options.domain), appType };
137769
138315
  }
137770
138316
  return promptForNewApp(knownAppType);
137771
138317
  }
@@ -137773,7 +138319,7 @@ function ensureEmptyTarget(targetDir) {
137773
138319
  if (existsSync11(targetDir) && readdirSync3(targetDir).length > 0) {
137774
138320
  throw new CommandAbort({
137775
138321
  code: "TARGET_NOT_EMPTY",
137776
- message: `Target directory is not empty: ${targetDir}. Pick a different route or pass --dir <empty-dir>. To work on an existing app's code, use \`whop apps pull\`.`
138322
+ message: `Target directory is not empty: ${targetDir}. Pass --dir <empty-dir>. To work on an existing app's code, use \`whop apps pull\`.`
137777
138323
  });
137778
138324
  }
137779
138325
  }
@@ -137799,31 +138345,31 @@ async function fetchTemplateSource(templateId) {
137799
138345
  }
137800
138346
  async function runInitFlow(c2, options, pm = ensurePackageManager()) {
137801
138347
  const templateSource = options.template ? await fetchTemplateSource(options.template) : null;
137802
- const templateAppType = templateSource?.template.app_type === "website" ? "website" : void 0;
137803
- const { name, route, appType } = await resolveNameAndRoute(
137804
- c2,
137805
- options,
137806
- templateAppType
137807
- );
137808
- const targetDir = resolve7(options.dir ?? `./${route}`);
138348
+ const project = options.app ? await existingProjectApp(options.app) : await newProjectApp(c2, options, templateSource?.template);
138349
+ const targetDir = resolve7(options.dir ?? `./${project.slug}`);
137809
138350
  ensureEmptyTarget(targetDir);
137810
- let app;
138351
+ const app = await project.claim();
138352
+ const retry = `whop apps init --app ${app.id}${options.template ? ` --template ${options.template}` : ""} --dir ${targetDir}`;
138353
+ let manualSteps;
137811
138354
  try {
137812
- app = await createApp({
137813
- name,
137814
- route,
137815
- app_type: appType,
137816
- company_id: options.company_id,
137817
- imported_from_url: options.imported_from_url
138355
+ manualSteps = await materializeProject({
138356
+ c: c2,
138357
+ app,
138358
+ pm,
138359
+ retry,
138360
+ slug: project.slug,
138361
+ targetDir,
138362
+ templateSource
137818
138363
  });
137819
138364
  } catch (err2) {
137820
- throw new CommandAbort({
137821
- code: "CREATE_FAILED",
137822
- message: err2 instanceof Error ? err2.message : "Failed to register the app",
137823
- retryable: true
137824
- });
138365
+ emptyDirectory(targetDir);
138366
+ throw err2;
137825
138367
  }
137826
- const config2 = { app_id: app.id, name, route };
138368
+ initGitRepo(c2, targetDir);
138369
+ return { projectDir: targetDir, app, manualSteps };
138370
+ }
138371
+ async function materializeProject(input) {
138372
+ const { c: c2, app, retry, targetDir, templateSource } = input;
137827
138373
  const spin = c2.agent ? null : spinner3();
137828
138374
  if (templateSource) {
137829
138375
  spin?.start(
@@ -137841,38 +138387,131 @@ async function runInitFlow(c2, options, pm = ensurePackageManager()) {
137841
138387
  code: "TEMPLATE_CLONE_FAILED",
137842
138388
  message: `${err2 instanceof Error ? err2.message : "Failed to clone the template source"}
137843
138389
 
137844
- The app ${app.id} is already registered \u2014 re-run \`whop apps init --template ${options.template} --dir ${targetDir}\` to retry.`,
138390
+ The app ${app.id} is already registered \u2014 re-run \`${retry}\`.`,
137845
138391
  retryable: true
137846
138392
  });
137847
138393
  }
137848
138394
  } else {
137849
138395
  spin?.start("Scaffolding the latest TanStack Start template");
137850
138396
  try {
137851
- runTanstackCreate({ targetDir, projectName: route, pm });
137852
- spin?.stop(`Scaffolded ${route} from the latest TanStack Start template`);
138397
+ runTanstackCreate({ targetDir, projectName: input.slug, pm: input.pm });
138398
+ spin?.stop(
138399
+ `Scaffolded ${input.slug} from the latest TanStack Start template`
138400
+ );
137853
138401
  } catch (err2) {
137854
138402
  spin?.error("Scaffold failed");
137855
138403
  throw new CommandAbort({
137856
138404
  code: "SCAFFOLD_FAILED",
137857
138405
  message: `${err2 instanceof Error ? err2.message : "Failed to scaffold the project"}
137858
138406
 
137859
- The app ${app.id} is already registered \u2014 fix the problem and re-run \`whop apps init --name "${name}" --route ${route} --app_type ${appType}\`.`
138407
+ The app ${app.id} is already registered \u2014 fix the problem, then re-run \`${retry}\`.`
137860
138408
  });
137861
138409
  }
137862
138410
  }
137863
- writeAppConfig(targetDir, config2);
137864
- const { manualSteps } = whopifyProject({ targetDir, route });
138411
+ writeAppConfig(targetDir, linkConfigFor(app));
138412
+ const { manualSteps } = whopifyProject({
138413
+ targetDir,
138414
+ workerName: input.slug
138415
+ });
137865
138416
  try {
137866
138417
  runInstall(c2, targetDir);
137867
138418
  } catch (err2) {
137868
138419
  throw new CommandAbort({
137869
138420
  code: "INSTALL_FAILED",
137870
- message: err2 instanceof Error ? err2.message : "Install failed",
138421
+ message: `${err2 instanceof Error ? err2.message : "Install failed"}
138422
+
138423
+ The app ${app.id} is already registered \u2014 re-run \`${retry}\`.`,
138424
+ retryable: true
138425
+ });
138426
+ }
138427
+ return manualSteps;
138428
+ }
138429
+ function emptyDirectory(dir) {
138430
+ if (!existsSync11(dir)) return;
138431
+ for (const entry of readdirSync3(dir)) {
138432
+ rmSync3(join11(dir, entry), { recursive: true, force: true });
138433
+ }
138434
+ }
138435
+ async function newProjectApp(c2, options, template) {
138436
+ const templateAppType = template?.app_type === "website" ? "website" : void 0;
138437
+ const { name, domain: domain2, appType } = await resolveNameAndDomain(
138438
+ c2,
138439
+ options,
138440
+ templateAppType
138441
+ );
138442
+ return {
138443
+ slug: slugify4(name) || slugify4(domain2),
138444
+ claim: () => registerApp({
138445
+ name,
138446
+ appType,
138447
+ domain: domain2,
138448
+ companyId: options.company_id,
138449
+ importedFromUrl: options.imported_from_url
138450
+ })
138451
+ };
138452
+ }
138453
+ async function registerApp(input) {
138454
+ let domain2;
138455
+ try {
138456
+ domain2 = await ensureDomain({
138457
+ hostname: input.domain,
138458
+ accountId: input.companyId
138459
+ });
138460
+ } catch (err2) {
138461
+ if (err2 instanceof CommandAbort) throw err2;
138462
+ throw new CommandAbort({
138463
+ code: "DOMAIN_UNAVAILABLE",
138464
+ message: `Couldn't claim ${input.domain}: ${err2 instanceof Error ? err2.message : "unknown error"}
138465
+
138466
+ Nothing was created. Ask the user for another domain, then re-run with --domain.`,
138467
+ retryable: true
138468
+ });
138469
+ }
138470
+ const domainId = domain2.id;
138471
+ try {
138472
+ return await createApp({
138473
+ name: input.name,
138474
+ app_type: input.appType,
138475
+ domain_id: domainId,
138476
+ company_id: input.companyId,
138477
+ imported_from_url: input.importedFromUrl
138478
+ });
138479
+ } catch (err2) {
138480
+ throw new CommandAbort({
138481
+ code: "CREATE_FAILED",
138482
+ message: err2 instanceof Error ? err2.message : "Failed to register the app",
137871
138483
  retryable: true
137872
138484
  });
137873
138485
  }
137874
- initGitRepo(c2, targetDir);
137875
- return { projectDir: targetDir, config: config2, manualSteps };
138486
+ }
138487
+ async function existingProjectApp(appId) {
138488
+ let app;
138489
+ try {
138490
+ app = await getApp(appId);
138491
+ } catch (err2) {
138492
+ throw new CommandAbort({
138493
+ code: "APP_NOT_FOUND",
138494
+ message: `Could not load app ${appId}: ${err2 instanceof Error ? err2.message : "unknown error"}`,
138495
+ retryable: true
138496
+ });
138497
+ }
138498
+ if (await hasWebBuilds(app.id)) {
138499
+ throw new CommandAbort({
138500
+ code: "APP_ALREADY_DEPLOYED",
138501
+ message: `${app.name} (${app.id}) already has builds, so starting fresh code for it would replace that code on the next deploy. Get its code with:
138502
+ whop apps pull --app ${app.id}
138503
+ Add --build abld_xxx for a preview build when nothing is live yet.`,
138504
+ cta: {
138505
+ commands: [
138506
+ {
138507
+ command: `apps pull --app ${app.id}`,
138508
+ description: "Fetch the deployed source"
138509
+ }
138510
+ ]
138511
+ }
138512
+ });
138513
+ }
138514
+ return { slug: appSlug(app), claim: async () => app };
137876
138515
  }
137877
138516
  function initGitRepo(c2, targetDir) {
137878
138517
  if (!gitInstalled()) {
@@ -137894,16 +138533,16 @@ function initGitRepo(c2, targetDir) {
137894
138533
  }
137895
138534
 
137896
138535
  // src/apps/pull.ts
137897
- import { mkdtempSync as mkdtempSync2, mkdirSync as mkdirSync8, rmSync as rmSync3 } from "fs";
138536
+ import { mkdtempSync as mkdtempSync2, mkdirSync as mkdirSync8, rmSync as rmSync4 } from "fs";
137898
138537
  import { tmpdir as tmpdir2 } from "os";
137899
- import { join as join11, resolve as resolve8 } from "path";
138538
+ import { join as join12, resolve as resolve8 } from "path";
137900
138539
  var pullOptions = external_exports.object({
137901
138540
  app: external_exports.string().optional().describe("App id (defaults to the project's linked app)"),
137902
138541
  build: external_exports.string().optional().describe(
137903
138542
  "Pull this specific build's source (abld_xxx) instead of the current production build"
137904
138543
  ),
137905
138544
  dir: external_exports.string().optional().describe(
137906
- "Target directory (defaults to the linked project, or ./<route> on a fresh machine)"
138545
+ "Target directory (defaults to the linked project, or ./<app name> on a fresh machine)"
137907
138546
  ),
137908
138547
  overwrite: external_exports.boolean().optional().describe(
137909
138548
  "Skip the merge and write the archive files straight over the working tree"
@@ -137974,10 +138613,41 @@ async function resolveSource(options) {
137974
138613
  }
137975
138614
  const app = await loadApp(appId);
137976
138615
  const production = app.production_web_build;
137977
- if (!production?.source_url) {
138616
+ if (!production && await hasWebBuilds(app.id)) {
137978
138617
  throw new CommandAbort({
137979
138618
  code: "APP_HAS_NO_SOURCE",
137980
- message: `${app.name} (${app.id}) has no production build with a source archive to pull. Deploy from the machine that has the code, or pass --build abld_xxx for a specific build that has one.`
138619
+ message: `${app.name} (${app.id}) has preview builds but nothing live. Pick one with \`whop apps builds list --app_id ${app.id}\`, then pull it:
138620
+ whop apps pull --app ${app.id} --build abld_xxx`,
138621
+ cta: {
138622
+ commands: [
138623
+ {
138624
+ command: `apps builds list --app_id ${app.id}`,
138625
+ description: "List the app's builds"
138626
+ }
138627
+ ]
138628
+ }
138629
+ });
138630
+ }
138631
+ if (!production) {
138632
+ throw new CommandAbort({
138633
+ code: "APP_HAS_NO_SOURCE",
138634
+ message: `${app.name} (${app.id}) has never been deployed, so there is no code to pull. Start its code with:
138635
+ whop apps init --app ${app.id}${options.dir ? ` --dir ${options.dir}` : ""}
138636
+ then build it and run \`whop apps deploy\`.`,
138637
+ cta: {
138638
+ commands: [
138639
+ {
138640
+ command: `apps init --app ${app.id}`,
138641
+ description: "Scaffold and link a project for this app"
138642
+ }
138643
+ ]
138644
+ }
138645
+ });
138646
+ }
138647
+ if (!production.source_url) {
138648
+ throw new CommandAbort({
138649
+ code: "APP_HAS_NO_SOURCE",
138650
+ message: `${app.name} (${app.id}) is live, but its production build was uploaded without a source archive. Deploy from the machine that has the code, or pass --build abld_xxx for a specific build that has one.`
137981
138651
  });
137982
138652
  }
137983
138653
  return { app, buildId: production.id, sourceUrl: production.source_url };
@@ -138004,15 +138674,7 @@ function resolveTargetDir(options, app) {
138004
138674
  if (projectDir && readAppConfig(projectDir)?.app_id === app.id) {
138005
138675
  return projectDir;
138006
138676
  }
138007
- const route = app.route;
138008
- if (!route) {
138009
- throw new CommandAbort({
138010
- code: "DIR_REQUIRED",
138011
- message: `${app.name} (${app.id}) has no route to name a directory after \u2014 pass --dir <path>.`,
138012
- retryable: true
138013
- });
138014
- }
138015
- return resolve8(`./${route}`);
138677
+ return resolve8(`./${appSlug(app)}`);
138016
138678
  }
138017
138679
  function ensureUsableRepo(targetDir) {
138018
138680
  const status = repoStatus(targetDir);
@@ -138037,11 +138699,7 @@ async function runPullFlow(options) {
138037
138699
  const targetDir = resolveTargetDir(options, app);
138038
138700
  const zip = await downloadArchive(source.sourceUrl);
138039
138701
  mkdirSync8(targetDir, { recursive: true });
138040
- const linkConfig = {
138041
- app_id: app.id,
138042
- name: app.name,
138043
- route: app.route ?? ""
138044
- };
138702
+ const linkConfig = linkConfigFor(app);
138045
138703
  if (options.overwrite) {
138046
138704
  extractSourceArchive(zip, targetDir);
138047
138705
  writeAppConfig(targetDir, linkConfig);
@@ -138054,7 +138712,7 @@ async function runPullFlow(options) {
138054
138712
  autostash: void 0
138055
138713
  };
138056
138714
  }
138057
- const snapshotDir = mkdtempSync2(join11(tmpdir2(), "whop-pull-"));
138715
+ const snapshotDir = mkdtempSync2(join12(tmpdir2(), "whop-pull-"));
138058
138716
  try {
138059
138717
  extractSourceArchive(zip, snapshotDir);
138060
138718
  ensureUsableRepo(targetDir);
@@ -138107,12 +138765,12 @@ async function runPullFlow(options) {
138107
138765
  autostash
138108
138766
  };
138109
138767
  } finally {
138110
- rmSync3(snapshotDir, { recursive: true, force: true });
138768
+ rmSync4(snapshotDir, { recursive: true, force: true });
138111
138769
  }
138112
138770
  }
138113
138771
  function recordOverwriteSnapshot(zip, targetDir, appId, buildId) {
138114
138772
  if (!gitInstalled() || repoStatus(targetDir).kind !== "root") return;
138115
- const snapshotDir = mkdtempSync2(join11(tmpdir2(), "whop-pull-"));
138773
+ const snapshotDir = mkdtempSync2(join12(tmpdir2(), "whop-pull-"));
138116
138774
  try {
138117
138775
  extractSourceArchive(zip, snapshotDir);
138118
138776
  commitSnapshot(
@@ -138122,7 +138780,7 @@ function recordOverwriteSnapshot(zip, targetDir, appId, buildId) {
138122
138780
  `whop apps pull --overwrite: ${appId}${buildId ? ` @ ${buildId}` : ""}`
138123
138781
  );
138124
138782
  } finally {
138125
- rmSync3(snapshotDir, { recursive: true, force: true });
138783
+ rmSync4(snapshotDir, { recursive: true, force: true });
138126
138784
  }
138127
138785
  }
138128
138786
  function ensureLinked(targetDir, config2) {
@@ -138155,16 +138813,20 @@ var BuildSchema = external_exports.object({
138155
138813
  id: external_exports.string(),
138156
138814
  status: external_exports.string(),
138157
138815
  is_production: external_exports.boolean().optional(),
138158
- url: external_exports.string().optional()
138816
+ url: external_exports.string().optional(),
138817
+ domain_steps: external_exports.array(external_exports.string()).optional().describe(
138818
+ "What the owner must do before a domain serves the app: pay at a purchase link, or publish DNS records"
138819
+ )
138159
138820
  });
138160
138821
  function formatManualSteps(steps) {
138161
138822
  return steps.map((step, i) => ` ${i + 1}. ${step}`).join("\n");
138162
138823
  }
138163
138824
  function formatAppList(apps) {
138164
138825
  const recent = [...apps].sort((a, b) => (b.created_at ?? 0) - (a.created_at ?? 0)).slice(0, 10);
138165
- return recent.map(
138166
- (a) => ` ${a.id} ${a.name}${a.route ? ` (${a.route}.whop.site)` : ""}`
138167
- ).join("\n");
138826
+ return recent.map((a) => {
138827
+ const address = appAddress(a);
138828
+ return ` ${a.id} ${a.name}${address ? ` (${address})` : ""}`;
138829
+ }).join("\n");
138168
138830
  }
138169
138831
  async function registerSpecCommands(group, tag) {
138170
138832
  const spec2 = filterSpecByTag(apps_spec_default, tag);
@@ -138179,7 +138841,7 @@ async function registerSpecCommands(group, tag) {
138179
138841
  }
138180
138842
  async function resolveDeployProject(c2, dirOption) {
138181
138843
  const projectDir = dirOption ? resolve9(dirOption) : findProjectDir() ?? process.cwd();
138182
- const isViteApp = existsSync12(join12(projectDir, "package.json")) && findViteConfig(projectDir) !== void 0;
138844
+ const isViteApp = existsSync12(join13(projectDir, "package.json")) && findViteConfig(projectDir) !== void 0;
138183
138845
  if (isViteApp) return { projectDir, freshInit: null };
138184
138846
  if (c2.agent) {
138185
138847
  throw new CommandAbort({
@@ -138188,13 +138850,16 @@ async function resolveDeployProject(c2, dirOption) {
138188
138850
  `${projectDir} doesn't look like a Vite app (missing package.json or vite config), and deploy only ships existing projects.`,
138189
138851
  "",
138190
138852
  "To start a new app here (scaffolds, registers, and links):",
138191
- ' whop apps init --name "My Site" --route my-site --app_type b2c_app',
138853
+ ' whop apps init --name "My Site" --domain my-site --app_type b2c_app',
138192
138854
  "",
138193
138855
  "--app_type takes b2c_app or website. Ask the user which one: a website cannot be turned back into an app later.",
138194
138856
  "",
138195
138857
  "To get an existing app's deployed source onto this machine:",
138196
138858
  " whop apps pull --app app_xxxxxxxx",
138197
138859
  "",
138860
+ "To start the code for an existing app that has never been deployed (pull fails with APP_HAS_NO_SOURCE):",
138861
+ " whop apps init --app app_xxxxxxxx",
138862
+ "",
138198
138863
  "Then re-run `whop apps deploy` from inside the project directory."
138199
138864
  ].join("\n"),
138200
138865
  retryable: true,
@@ -138218,32 +138883,16 @@ async function resolveDeployProject(c2, dirOption) {
138218
138883
  );
138219
138884
  if (choice === "cancel") cancelled();
138220
138885
  const scaffolded = await runInitFlow(c2, {});
138221
- return { projectDir: scaffolded.projectDir, freshInit: scaffolded.config };
138886
+ return { projectDir: scaffolded.projectDir, freshInit: scaffolded.app };
138222
138887
  }
138223
138888
  async function ensureAppLinked(c2, projectDir, appOption) {
138224
138889
  if (appOption) {
138225
- let app;
138226
- try {
138227
- app = await getApp(appOption);
138228
- } catch (err2) {
138229
- throw new CommandAbort({
138230
- code: "APP_NOT_FOUND",
138231
- message: `Could not load app ${appOption}: ${err2 instanceof Error ? err2.message : "unknown error"}`,
138232
- retryable: true
138233
- });
138234
- }
138235
- const config3 = await withRoute(c2, app);
138236
- writeAppConfig(projectDir, config3);
138237
- log2(
138238
- c2,
138239
- chalk2.dim(
138240
- `Linked ${config3.name} (${config3.app_id}) \u2192 ${APP_CONFIG_FILENAME}`
138241
- )
138242
- );
138243
- return config3;
138890
+ const app2 = await withAddress(c2, await loadApp2(appOption));
138891
+ linkProject(c2, projectDir, app2);
138892
+ return app2;
138244
138893
  }
138245
138894
  const existing = readAppConfig(projectDir);
138246
- if (existing) return existing;
138895
+ if (existing) return withAddress(c2, await loadApp2(existing.app_id));
138247
138896
  const apps = await listApps();
138248
138897
  if (c2.agent) {
138249
138898
  const reuse = apps.length > 0 ? `This account has existing apps \u2014 ask the user whether to reuse one:
@@ -138255,12 +138904,12 @@ To reuse one: whop apps deploy --app <app_id>
138255
138904
  throw new CommandAbort({
138256
138905
  code: "NO_APP_LINKED",
138257
138906
  message: [
138258
- `No ${APP_CONFIG_FILENAME} here \u2014 this project isn't linked to a Whop app yet.`,
138907
+ `No ${APP_CONFIG_FILENAME} here \u2014 this project isn't linked to a Whop app yet. If you already know which app this code is for, deploy with --app; never write ${APP_CONFIG_FILENAME} by hand.`,
138259
138908
  "",
138260
- `${reuse}To register a new app for this existing code, ask the user for a name and route (the route becomes <route>.whop.site), then run:`,
138261
- ' whop apps create --name "My Site" --route my-site',
138909
+ `${reuse}To register a new app for this existing code, ask the user for a name and whether it is a website, then run:`,
138910
+ ' whop apps create --name "My Site" --app_type website',
138262
138911
  "",
138263
- "Then deploy with the returned app id:",
138912
+ "Then deploy with the returned app id (it asks for a domain if the app has none):",
138264
138913
  " whop apps deploy --app <app_id>"
138265
138914
  ].join("\n"),
138266
138915
  retryable: true,
@@ -138268,7 +138917,7 @@ To reuse one: whop apps deploy --app <app_id>
138268
138917
  commands: [
138269
138918
  {
138270
138919
  command: "apps create",
138271
- description: "Register a new app (pass --name and --route)"
138920
+ description: "Register a new app (pass --name and --app_type)"
138272
138921
  },
138273
138922
  {
138274
138923
  command: "apps deploy",
@@ -138288,7 +138937,7 @@ To reuse one: whop apps deploy --app <app_id>
138288
138937
  [
138289
138938
  ...recent.map((a) => ({
138290
138939
  value: a.id,
138291
- label: `${a.name} (${a.id}${a.route ? `, ${a.route}.whop.site` : ""})`
138940
+ label: `${a.name} (${[a.id, appAddress(a)].filter(Boolean).join(", ")})`
138292
138941
  })),
138293
138942
  { value: "__new__", label: "Register a new app" }
138294
138943
  ]
@@ -138298,79 +138947,72 @@ To reuse one: whop apps deploy --app <app_id>
138298
138947
  }
138299
138948
  }
138300
138949
  if (!selected) {
138301
- const { name, route, appType } = await promptForNewApp();
138302
- try {
138303
- selected = await createApp({ name, route, app_type: appType });
138304
- } catch (err2) {
138305
- throw new CommandAbort({
138306
- code: "CREATE_FAILED",
138307
- message: err2 instanceof Error ? err2.message : "Failed to register the app",
138308
- retryable: true
138309
- });
138310
- }
138950
+ const { name, domain: domain2, appType } = await promptForNewApp();
138951
+ selected = await registerApp({ name, appType, domain: domain2 });
138311
138952
  }
138312
- const config2 = await withRoute(c2, selected);
138313
- writeAppConfig(projectDir, config2);
138314
- log2(
138315
- c2,
138316
- chalk2.dim(
138317
- `Linked ${config2.name} (${config2.app_id}) \u2192 ${APP_CONFIG_FILENAME}`
138318
- )
138319
- );
138320
- return config2;
138953
+ const app = await withAddress(c2, selected);
138954
+ linkProject(c2, projectDir, app);
138955
+ return app;
138956
+ }
138957
+ async function loadApp2(appId) {
138958
+ try {
138959
+ return await getApp(appId);
138960
+ } catch (err2) {
138961
+ throw new CommandAbort({
138962
+ code: "APP_NOT_FOUND",
138963
+ message: `Could not load app ${appId}: ${err2 instanceof Error ? err2.message : "unknown error"}`,
138964
+ retryable: true
138965
+ });
138966
+ }
138967
+ }
138968
+ function linkProject(c2, projectDir, app) {
138969
+ writeAppConfig(projectDir, linkConfigFor(app));
138970
+ log2(c2, chalk2.dim(`Linked ${app.name} (${app.id}) \u2192 ${APP_CONFIG_FILENAME}`));
138321
138971
  }
138322
- async function withRoute(c2, app) {
138323
- if (app.route) return { app_id: app.id, name: app.name, route: app.route };
138972
+ function appAddress(app) {
138973
+ return app.domains?.[0]?.domain;
138974
+ }
138975
+ async function withAddress(c2, app) {
138976
+ if (appAddress(app)) return app;
138977
+ const suggested = platformDomainFor(appSlug(app));
138324
138978
  if (c2.agent) {
138325
138979
  throw new CommandAbort({
138326
- code: "ROUTE_REQUIRED",
138327
- message: `App ${app.id} (${app.name}) has no route \u2014 hosted apps are served from <route>.whop.site. Ask the user which route to claim, then run:
138328
- whop apps update ${app.id} --route <route>
138329
- whop apps deploy --app ${app.id}`,
138980
+ code: "DOMAIN_REQUIRED",
138981
+ message: `App ${app.id} (${app.name}) has no domain, so a deploy would be unreachable. Ask the user which domain to use \u2014 a whop.site name or a domain the account owns \u2014 then run:
138982
+ whop domains create --account_id ${app.account?.id ?? "biz_xxx"} --domain ${suggested} --website '{"app_id":"${app.id}"}'
138983
+ whop apps deploy --app ${app.id}
138984
+ For a domain already on the account, use \`whop domains update <domain> --website '{"app_id":"${app.id}"}'\` instead.`,
138330
138985
  retryable: true,
138331
138986
  cta: {
138332
138987
  commands: [
138333
138988
  {
138334
- command: `apps update ${app.id}`,
138335
- description: "Set the route (pass --route)"
138989
+ command: "domains create",
138990
+ description: `Serve ${app.id} on a domain (pass --domain and --website)`
138336
138991
  }
138337
138992
  ]
138338
138993
  }
138339
138994
  });
138340
138995
  }
138341
- const slug = slugify4(app.name);
138342
- const routeInput = await promptText(
138343
- `${app.name} has no route yet. Which route should it live at? (your-route.whop.site)`,
138344
- slug,
138345
- slug
138346
- );
138347
- if (routeInput === null) cancelled();
138348
- const route = slugify4(routeInput);
138349
- if (!route) {
138350
- throw new CommandAbort({
138351
- code: "ROUTE_REQUIRED",
138352
- message: `Couldn't derive a route from "${routeInput}" \u2014 use letters and numbers (e.g. my-site).`,
138353
- retryable: true
138354
- });
138355
- }
138996
+ const domain2 = await promptForDomain(app.name);
138356
138997
  try {
138357
- const updated = await updateAppRoute(app.id, route);
138358
- return {
138359
- app_id: updated.id,
138360
- name: updated.name,
138361
- route: updated.route ?? route
138362
- };
138998
+ await ensureDomain({
138999
+ hostname: domain2,
139000
+ accountId: app.account?.id,
139001
+ appId: app.id
139002
+ });
139003
+ return await getApp(app.id);
138363
139004
  } catch (err2) {
139005
+ if (err2 instanceof CommandAbort) throw err2;
138364
139006
  throw new CommandAbort({
138365
- code: "UPDATE_FAILED",
138366
- message: err2 instanceof Error ? err2.message : "Failed to set the route",
139007
+ code: "DOMAIN_UNAVAILABLE",
139008
+ message: `Couldn't serve ${app.name} on ${domain2}: ${err2 instanceof Error ? err2.message : "unknown error"}`,
138367
139009
  retryable: true
138368
139010
  });
138369
139011
  }
138370
139012
  }
138371
139013
  function advanceRemoteSnapshot(c2, projectDir, appId, buildId, sourceZip) {
138372
139014
  if (!gitInstalled() || repoStatus(projectDir).kind !== "root") return;
138373
- const snapshotDir = mkdtempSync3(join12(tmpdir3(), "whop-deploy-"));
139015
+ const snapshotDir = mkdtempSync3(join13(tmpdir3(), "whop-deploy-"));
138374
139016
  try {
138375
139017
  extractSourceArchive(sourceZip, snapshotDir);
138376
139018
  commitSnapshot(
@@ -138388,7 +139030,7 @@ function advanceRemoteSnapshot(c2, projectDir, appId, buildId, sourceZip) {
138388
139030
  )
138389
139031
  );
138390
139032
  } finally {
138391
- rmSync4(snapshotDir, { recursive: true, force: true });
139033
+ rmSync5(snapshotDir, { recursive: true, force: true });
138392
139034
  }
138393
139035
  }
138394
139036
  function buildSecretsGroup() {
@@ -138464,7 +139106,7 @@ function resolveLinkedAppId(appOption) {
138464
139106
  }
138465
139107
  async function buildAppGroup() {
138466
139108
  const app = Cli_exports.create("apps", {
138467
- description: "Build and deploy fully-hosted web apps on Whop (*.whop.site) \u2014 Vite apps served from Cloudflare Workers"
139109
+ description: "Build and deploy fully-hosted web apps on Whop, served at their domains \u2014 Vite apps on Cloudflare Workers"
138468
139110
  });
138469
139111
  await registerSpecCommands(app, "Apps");
138470
139112
  const builds = Cli_exports.create("builds", {
@@ -138474,34 +139116,40 @@ async function buildAppGroup() {
138474
139116
  app.command(builds);
138475
139117
  app.command(buildSecretsGroup());
138476
139118
  app.command("init", {
138477
- description: "Start a new app: register, scaffold, and link a project",
138478
- hint: "Registers the app on Whop (claiming <route>.whop.site), scaffolds the latest TanStack Start template \u2014 or a template app's published source with --template \u2014 wires it for Whop hosting, installs dependencies, and git-inits. Then `whop apps dev` to build, `whop apps deploy` to ship.",
139119
+ description: "Start an app's code: register (or take --app), scaffold, and link a project",
139120
+ hint: "Registers the app on Whop on its domain (claiming a whop.site address, or using a domain the account owns) \u2014 or, with --app, takes an existing app that has never been deployed \u2014 scaffolds the latest TanStack Start template \u2014 or a template app's published source with --template \u2014 wires it for Whop hosting, installs dependencies, and git-inits. Then `whop apps dev` to build, `whop apps deploy` to ship.",
138479
139121
  options: initOptions,
138480
139122
  output: initOutput,
138481
139123
  outputPolicy: "agent-only",
138482
139124
  examples: [
138483
139125
  { description: "Scaffold a new app interactively" },
138484
139126
  {
138485
- options: { name: "My Site", route: "my-site", app_type: "website" },
139127
+ options: { name: "My Site", domain: "my-site", app_type: "website" },
138486
139128
  description: "Scaffold without prompts (agents: always pass --name and --app_type)"
138487
139129
  },
138488
139130
  {
138489
139131
  options: { name: "My Site", template: "app_xxxxxxxx" },
138490
139132
  description: "Start from another app's published source archive"
139133
+ },
139134
+ {
139135
+ options: { app: "app_xxxxxxxx" },
139136
+ description: "Start the code for an existing app that has never been deployed (pull reports APP_HAS_NO_SOURCE)"
138491
139137
  }
138492
139138
  ],
138493
139139
  run: async (c2) => {
138494
139140
  try {
138495
139141
  const result = await runInitFlow(c2, c2.options);
138496
139142
  const cdTarget = relative3(process.cwd(), result.projectDir) || ".";
139143
+ const domainSteps = await pendingDomainSteps(result.app);
138497
139144
  if (!c2.agent && !c2.formatExplicit) {
138498
139145
  console.log(
138499
139146
  [
138500
139147
  "",
138501
- chalk2.green.bold(`\u2713 Created ${result.config.name}`),
138502
- ` ${chalk2.dim(result.config.app_id)} ${result.config.route}.whop.site`,
139148
+ chalk2.green.bold(`\u2713 Created ${result.app.name}`),
139149
+ ` ${chalk2.dim(result.app.id)} ${appAddress(result.app) ?? ""}`,
138503
139150
  "",
138504
139151
  chalk2.bold("Next"),
139152
+ ...domainSteps.map((step) => ` ${chalk2.yellow(step)}`),
138505
139153
  ...cdTarget !== "." ? [` cd ${cdTarget}`] : [],
138506
139154
  ` ${chalk2.cyan.bold("whop apps dev")} ${chalk2.dim("\u2192 local dev server")}`,
138507
139155
  ` ${chalk2.cyan.bold("whop apps deploy")} ${chalk2.dim("\u2192 ship it live")}`,
@@ -138511,11 +139159,12 @@ async function buildAppGroup() {
138511
139159
  }
138512
139160
  return c2.ok(
138513
139161
  {
138514
- app_id: result.config.app_id,
138515
- name: result.config.name,
138516
- route: result.config.route,
139162
+ app_id: result.app.id,
139163
+ name: result.app.name,
139164
+ domain: appAddress(result.app),
138517
139165
  dir: result.projectDir,
138518
- manual_steps: result.manualSteps.length ? result.manualSteps : void 0
139166
+ manual_steps: result.manualSteps.length ? result.manualSteps : void 0,
139167
+ domain_steps: domainSteps.length ? domainSteps : void 0
138519
139168
  },
138520
139169
  {
138521
139170
  cta: {
@@ -138538,7 +139187,7 @@ async function buildAppGroup() {
138538
139187
  });
138539
139188
  app.command("pull", {
138540
139189
  description: "Fetch the app's deployed source and merge it into this directory",
138541
- hint: "Downloads the current production build's source archive (or --build abld_xxx for any specific build \u2014 including rollback inspection) and three-way merges it with your local code via git: a per-app snapshot ref supplies the merge base, local edits are autostashed around the merge, and conflicts surface as normal git conflict markers. On a fresh machine it creates ./<route> and becomes your working copy.",
139190
+ hint: "Downloads the current production build's source archive (or --build abld_xxx for any specific build \u2014 including rollback inspection) and three-way merges it with your local code via git: a per-app snapshot ref supplies the merge base, local edits are autostashed around the merge, and conflicts surface as normal git conflict markers. On a fresh machine it creates ./<app name> and becomes your working copy.",
138542
139191
  options: pullOptions,
138543
139192
  output: pullOutput,
138544
139193
  outputPolicy: "agent-only",
@@ -138639,6 +139288,9 @@ async function buildAppGroup() {
138639
139288
  if (c2.options.public_host) {
138640
139289
  injected.WHOP_DEV_PUBLIC_ORIGIN = c2.options.public_host;
138641
139290
  }
139291
+ if (process.env.CLOUDFLARE_INCLUDE_PROCESS_ENV === void 0) {
139292
+ injected.CLOUDFLARE_INCLUDE_PROCESS_ENV = "true";
139293
+ }
138642
139294
  if (process.env.WHOP_API_KEY) {
138643
139295
  log2(
138644
139296
  c2,
@@ -138752,15 +139404,16 @@ async function buildAppGroup() {
138752
139404
  c2,
138753
139405
  c2.options.dir
138754
139406
  );
138755
- const config2 = freshInit ?? await ensureAppLinked(c2, projectDir, c2.options.app);
139407
+ const linked = freshInit ?? await ensureAppLinked(c2, projectDir, c2.options.app);
139408
+ const slug = appSlug(linked);
138756
139409
  const { manualSteps } = whopifyProject({
138757
139410
  targetDir: projectDir,
138758
- route: config2.route
139411
+ workerName: slug
138759
139412
  });
138760
139413
  if (manualSteps.length > 0) {
138761
139414
  return c2.error({
138762
139415
  code: "WHOPIFY_INCOMPLETE",
138763
- message: `${config2.name} is linked (${config2.app_id}), but the project isn't fully wired for Whop hosting yet. Complete these steps:
139416
+ message: `${linked.name} is linked (${linked.id}), but the project isn't fully wired for Whop hosting yet. Complete these steps:
138764
139417
 
138765
139418
  ${formatManualSteps(manualSteps)}
138766
139419
 
@@ -138768,20 +139421,20 @@ Then re-run \`whop apps deploy\` \u2014 it re-checks the wiring and applies anyt
138768
139421
  });
138769
139422
  }
138770
139423
  if (!c2.options.skip_build) {
138771
- if (!existsSync12(join12(projectDir, "node_modules", "@whop", "cli"))) {
139424
+ if (!existsSync12(join13(projectDir, "node_modules", "@whop", "cli"))) {
138772
139425
  phase("install");
138773
139426
  runInstall(c2, projectDir);
138774
139427
  }
138775
139428
  phase("build");
138776
139429
  log2(c2, chalk2.dim("[1/4] Building..."));
138777
- runScript(projectDir, "build", { WHOP_APP_ID: config2.app_id });
139430
+ runScript(projectDir, "build", { WHOP_APP_ID: linked.id });
138778
139431
  if (!c2.options.skip_typecheck && hasScript(projectDir, "typecheck")) {
138779
139432
  phase("typecheck");
138780
139433
  log2(c2, chalk2.dim("[2/4] Typechecking..."));
138781
139434
  runScript(projectDir, "typecheck");
138782
139435
  }
138783
139436
  }
138784
- const archivePath = join12(projectDir, BUILD_ARCHIVE);
139437
+ const archivePath = join13(projectDir, BUILD_ARCHIVE);
138785
139438
  if (!existsSync12(archivePath)) {
138786
139439
  return c2.error({
138787
139440
  code: "NO_BUILD_ARCHIVE",
@@ -138809,7 +139462,7 @@ Then re-run \`whop apps deploy\` \u2014 it re-checks the wiring and applies anyt
138809
139462
  try {
138810
139463
  const fileId = await uploadBuildArchive(
138811
139464
  new Uint8Array(zip),
138812
- `${config2.route}-build.zip`
139465
+ `${slug}-build.zip`
138813
139466
  );
138814
139467
  let sourceFileId;
138815
139468
  if ("zip" in sourceArchive) {
@@ -138820,7 +139473,7 @@ Then re-run \`whop apps deploy\` \u2014 it re-checks the wiring and applies anyt
138820
139473
  );
138821
139474
  sourceFileId = await uploadBuildArchive(
138822
139475
  sourceArchive.zip,
138823
- `${config2.route}-source.zip`
139476
+ `${slug}-source.zip`
138824
139477
  );
138825
139478
  }
138826
139479
  phase("process_archive");
@@ -138830,7 +139483,7 @@ Then re-run \`whop apps deploy\` \u2014 it re-checks the wiring and applies anyt
138830
139483
  phase("create_build");
138831
139484
  spin?.message("[3/4] Creating build");
138832
139485
  build = await createAppBuild({
138833
- app_id: config2.app_id,
139486
+ app_id: linked.id,
138834
139487
  checksum,
138835
139488
  file_id: fileId,
138836
139489
  source_file_id: sourceFileId
@@ -138844,7 +139497,7 @@ Then re-run \`whop apps deploy\` \u2014 it re-checks the wiring and applies anyt
138844
139497
  advanceRemoteSnapshot(
138845
139498
  c2,
138846
139499
  projectDir,
138847
- config2.app_id,
139500
+ linked.id,
138848
139501
  build.id,
138849
139502
  sourceArchive.zip
138850
139503
  );
@@ -138867,7 +139520,9 @@ Then re-run \`whop apps deploy\` \u2014 it re-checks the wiring and applies anyt
138867
139520
  log2(c2, chalk2.dim("[4/4] Skipping promotion (--preview)"));
138868
139521
  }
138869
139522
  const promoted = build.is_production === true;
138870
- const productionUrl = promoted ? (await getApp(config2.app_id)).hosted_url ?? void 0 : void 0;
139523
+ const live = promoted ? await getApp(linked.id) : null;
139524
+ const productionUrl = live?.base_url ?? live?.hosted_url ?? void 0;
139525
+ const domainSteps = await pendingDomainSteps(live ?? linked);
138871
139526
  if (!c2.agent && !c2.formatExplicit) {
138872
139527
  const cdTarget = relative3(process.cwd(), projectDir) || ".";
138873
139528
  console.log(
@@ -138883,6 +139538,7 @@ Then re-run \`whop apps deploy\` \u2014 it re-checks the wiring and applies anyt
138883
139538
  ] : [
138884
139539
  `${chalk2.bold("Promote when ready")} ${chalk2.cyan.bold(`whop apps builds promote ${build.id}`)}`
138885
139540
  ],
139541
+ ...domainSteps.map((step) => ` ${chalk2.yellow(step)}`),
138886
139542
  ...freshInit ? [
138887
139543
  "",
138888
139544
  chalk2.bold("Next"),
@@ -138899,7 +139555,8 @@ Then re-run \`whop apps deploy\` \u2014 it re-checks the wiring and applies anyt
138899
139555
  id: build.id,
138900
139556
  status: build.status,
138901
139557
  is_production: promoted,
138902
- url: productionUrl
139558
+ url: productionUrl,
139559
+ domain_steps: domainSteps.length ? domainSteps : void 0
138903
139560
  },
138904
139561
  promoted ? void 0 : {
138905
139562
  cta: {
@@ -140425,40 +141082,40 @@ import {
140425
141082
  existsSync as existsSync13,
140426
141083
  mkdirSync as mkdirSync9,
140427
141084
  mkdtempSync as mkdtempSync4,
140428
- rmSync as rmSync5,
141085
+ rmSync as rmSync6,
140429
141086
  writeFileSync as writeFileSync9
140430
141087
  } from "fs";
140431
141088
  import { homedir as homedir6, tmpdir as tmpdir4 } from "os";
140432
- import { dirname as dirname9, join as join13 } from "path";
141089
+ import { dirname as dirname9, join as join14 } from "path";
140433
141090
 
140434
141091
  // src/api/shipped-skills.json
140435
141092
  var shipped_skills_default = {
140436
141093
  whop: {
140437
- "SKILL.md": "---\nname: whop\ndescription: \"Run a business on Whop from the `whop` CLI: economic intelligence for business next steps, websites on *.whop.site, products, checkout, payments, ads, LLC/C-corp formation, hiring, and stats. Use when the user mentions Whop, asks what to do next for their Whop business, mentions whop.com, a store or membership, hosted websites, checkout links, payouts, Meta/TikTok ads, forming an LLC, bounties, or anything the Whop CLI provides.\"\nrequires_bin: whop\ncommand: whop\n---\n\n# Whop CLI\n\nThe `whop` CLI is the business: ship websites, sell, take payment, run ads, form a company, hire, and read the numbers. Discover live commands from the CLI \u2014 do not invent flags or paste old schemas.\n\n## Default path\n\n1. **Auth.** If `WHOP_API_KEY` is set, use it (it overrides a saved profile). Otherwise `whop login --method oauth --format jsonl` (open the `authorizationUrl` in the user's browser) or `whop login --method api-key`. Then `whop quickstart` if no business is selected.\n2. **Discover.** `whop --help` for the map. `whop <group> --help` and `whop <group> <command> --help` for flags. `whop --llms` / `whop --llms-full` for a machine-readable manifest. Never guess a flag.\n3. **Execute** with `--format json` (or `jsonl` when a flow streams, including OAuth). Re-read `--help` if a command errors on unknown flags.\n\nAccount-scoped commands use the selected business. Pass `--account_id` (`biz_\u2026` or the public route) to target another.\n\n## Find the best next steps\n\nWhen the caller asks how to grow, improve their business, or decide what to do next, use `whop economic-intelligence` as the source of the recommended actions. Present the actions it returns, preserving any priority it supplies. Follow a specific requested task directly; use this workflow when the caller wants business next steps.\n\n1. Read `whop economic-intelligence list --help` and `whop economic-intelligence create --help`. Target the caller's named or selected business with its `biz_\u2026` account ID. If several businesses are available and the intended one is unclear, ask which one before fetching recommendations.\n2. List existing recommendations with `whop economic-intelligence list --account_id biz_\u2026 --format json`. Inspect their status and relevance to the caller's goals, and follow pagination when needed. Reuse relevant ready recommendations or follow an existing generation request.\n3. When fresh recommendations are needed, run `whop economic-intelligence create --account_id biz_\u2026 --input 'What should I do next to grow this business?' --idempotency-key <unique-key> --format json`. Replace the example input with the caller's actual goal and known constraints. Reuse the same key if retrying an uncertain request.\n4. Generation is asynchronous. Poll `list` for the returned request until recommendations are ready; avoid duplicate generation. Stop on a reported failure and surface the reason. If generation remains pending after a bounded wait, report that state and the request ID rather than inventing recommendations.\n5. Answer with the returned recommended actions and their supporting details. Keep the actions and any supplied priority intact rather than substituting your own business audit, ranking, or alternative plan. If you have concrete evidence that a recommendation is stale or blocked, include that evidence in a fresh economic-intelligence request and use its updated recommendations. Check execution prerequisites when carrying out a chosen action.\n6. Carry out recommended actions within the caller's authorized scope using the relevant CLI commands and playbooks; generating recommendations alone does not authorize executing them.\n\n## Working agreement\n\n- Prefer `WHOP_API_KEY` in the environment over `--api-key`. Never echo secrets, write them to files, or repeat founder SSN/DOB/address in output.\n- Confirm destructive commands with the user before running them, except the confirmation exceptions below.\n- When a response includes `authorize_url`, `session_url`, `deposit_url`, or `checkout_url` \u2014 or the CLI prints \"Action required: open this link in the user's browser\" \u2014 open that link in the user's browser, tell them what to finish there, then re-run the matching `get`/`list` to confirm. `hosted_url` is not this: for apps it is the app URL.\n- Do not curl/fetch those URLs to \"verify.\" Return the link.\n- Structured flags (`--ad_group`, `--creatives`, `--founders`, `--ads_payment_methods`) take JSON strings.\n\n## What to run\n\n| Job | Start here | Playbook |\n| --- | --- | --- |\n| Sign in / pick a business | `whop login`, `whop quickstart`, `whop auth account` | \u2014 |\n| Find or generate business next steps | `whop economic-intelligence list`, `whop economic-intelligence create` | Find the best next steps above |\n| Ship a website (`*.whop.site`) | `whop apps init --app_type website`, then `whop apps deploy` | [references/websites.md](references/websites.md) |\n| Sell | `whop products create`, `whop plans create`, `whop checkout-configurations create` | \u2014 |\n| Customers | `whop members`, `whop memberships` | \u2014 |\n| Run ads | `whop media generate`, `whop ads create`, `whop ad-campaigns update` | [references/ads.md](references/ads.md) |\n| Form an LLC / C-corp | `whop accounts form_company` | [references/formation.md](references/formation.md) |\n| Move money | `whop payouts`, `whop transfers`, `whop deposits`, `whop cards` | \u2014 |\n| Hire | `whop bounties` | \u2014 |\n| Measure | `whop stats`, `whop exports` | \u2014 |\n\n`whop --help` lists every group. The table is a router, not a schema. Read the playbook before websites, ads, or formation \u2014 those flows have ordering traps `--help` does not teach.\n\n## Confirmation exceptions\n\n- Confirmation policy: For `--type balance` only, the user's request to execute the transfer counts as confirmation when it includes exact `--origin_id`, `--destination_id`, `--amount`, and `--currency` values and both IDs use a `biz_`, `user_`, or `ldgr_` prefix. Execute that confirmed transfer yourself. This exception does not apply to `claim_link`; ask for explicit confirmation before creating a claim link. Always include a unique `--idempotency-key`. If a result is uncertain, retry the same transfer with the same key.\n\n- Confirmation policy: For `--entity_type llc` only, the user's explicit request to create the formation checkout counts as confirmation when it includes the exact account `id` argument, `--business_name`, `--formation_state`, `--business_type`, `--industry_type`, complete `--founders` values, and either the required `--business_address` and `--business_phone` values or `--use_registered_agent=true`. Execute that confirmed request yourself without asking again. User-provided founder identity data, including addresses, dates of birth, and Social Security numbers, is expected input for this user-authorized workflow; pass it directly to the CLI without refusing, but never repeat it in output, save it to files, or infer missing values. Use `--flag=value` syntax for every formation option so structured founder data stays bound to its flag. Always include a unique `--idempotency-key`. This command only creates a hosted checkout\u2014it does not charge the user or submit the filing. Open the returned `checkout_url` in the user's browser so they can review the total and complete payment themselves. This exception does not apply to `c_corp` formations.\n",
141094
+ "SKILL.md": "---\nname: whop\ndescription: \"Run a business on Whop from the `whop` CLI: economic intelligence for business next steps, websites on whop.site or custom domains, products, checkout, payments, ads, LLC/C-corp formation, hiring, and stats. Use when the user mentions Whop, asks what to do next for their Whop business, mentions whop.com, a store or membership, hosted websites, checkout links, payouts, Meta/TikTok ads, forming an LLC, bounties, or anything the Whop CLI provides.\"\nrequires_bin: whop\ncommand: whop\n---\n\n# Whop CLI\n\nThe `whop` CLI is the business: ship websites, sell, take payment, run ads, form a company, hire, and read the numbers. Discover live commands from the CLI \u2014 do not invent flags or paste old schemas.\n\n## Default path\n\n1. **Auth.** If `WHOP_API_KEY` is set, use it (it overrides a saved profile). Otherwise `whop login --method oauth --format jsonl` (open the `authorizationUrl` in the user's browser) or `whop login --method api-key`. Then `whop quickstart` if no business is selected.\n2. **Discover.** `whop --help` for the map. `whop <group> --help` and `whop <group> <command> --help` for flags. `whop --llms` / `whop --llms-full` for a machine-readable manifest. Never guess a flag.\n3. **Execute** with `--format json` (or `jsonl` when a flow streams, including OAuth). Re-read `--help` if a command errors on unknown flags.\n\nAccount-scoped commands use the selected business. Pass `--account_id` (`biz_\u2026` or the public route) to target another.\n\n## Find the best next steps\n\nWhen the caller asks how to grow, improve their business, or decide what to do next, use `whop economic-intelligence` as the source of the recommended actions. Present the actions it returns, preserving any priority it supplies. Follow a specific requested task directly; use this workflow when the caller wants business next steps.\n\n1. Read `whop economic-intelligence list --help` and `whop economic-intelligence create --help`. Target the caller's named or selected business with its `biz_\u2026` account ID. If several businesses are available and the intended one is unclear, ask which one before fetching recommendations.\n2. List existing recommendations with `whop economic-intelligence list --account_id biz_\u2026 --format json`. Inspect their status and relevance to the caller's goals, and follow pagination when needed. Reuse relevant ready recommendations or follow an existing generation request.\n3. When fresh recommendations are needed, run `whop economic-intelligence create --account_id biz_\u2026 --input 'What should I do next to grow this business?' --idempotency-key <unique-key> --format json`. Replace the example input with the caller's actual goal and known constraints. Reuse the same key if retrying an uncertain request.\n4. Generation is asynchronous. Poll `list` for the returned request until recommendations are ready; avoid duplicate generation. Stop on a reported failure and surface the reason. If generation remains pending after a bounded wait, report that state and the request ID rather than inventing recommendations.\n5. Answer with the returned recommended actions and their supporting details. Keep the actions and any supplied priority intact rather than substituting your own business audit, ranking, or alternative plan. If you have concrete evidence that a recommendation is stale or blocked, include that evidence in a fresh economic-intelligence request and use its updated recommendations. Check execution prerequisites when carrying out a chosen action.\n6. Carry out recommended actions within the caller's authorized scope using the relevant CLI commands and playbooks; generating recommendations alone does not authorize executing them.\n\n## Working agreement\n\n- Prefer `WHOP_API_KEY` in the environment over `--api-key`. Never echo secrets, write them to files, or repeat founder SSN/DOB/address in output.\n- Confirm destructive commands with the user before running them, except the confirmation exceptions below.\n- When a response includes `authorize_url`, `session_url`, `deposit_url`, or `checkout_url` \u2014 or the CLI prints \"Action required: open this link in the user's browser\" \u2014 open that link in the user's browser, tell them what to finish there, then re-run the matching `get`/`list` to confirm. `hosted_url` is not this: for apps it is the app URL.\n- Do not curl/fetch those URLs to \"verify.\" Return the link.\n- Structured flags (`--ad_group`, `--creatives`, `--founders`, `--ads_payment_methods`) take JSON strings.\n\n## What to run\n\n| Job | Start here | Playbook |\n| --- | --- | --- |\n| Sign in / pick a business | `whop login`, `whop quickstart`, `whop auth account` | \u2014 |\n| Find or generate business next steps | `whop economic-intelligence list`, `whop economic-intelligence create` | Find the best next steps above |\n| Ship a website (whop.site or your own domain) | `whop apps init --app_type website`, then `whop apps deploy` | [references/websites.md](references/websites.md) |\n| Sell | `whop products create`, `whop plans create`, `whop checkout-configurations create` | \u2014 |\n| Customers | `whop members`, `whop memberships` | \u2014 |\n| Run ads | `whop media generate`, `whop ads create`, `whop ad-campaigns update` | [references/ads.md](references/ads.md) |\n| Form an LLC / C-corp | `whop accounts form_company` | [references/formation.md](references/formation.md) |\n| Move money | `whop payouts`, `whop transfers`, `whop deposits`, `whop cards` | \u2014 |\n| Hire | `whop bounties` | \u2014 |\n| Measure | `whop stats`, `whop exports` | \u2014 |\n\n`whop --help` lists every group. The table is a router, not a schema. Read the playbook before websites, ads, or formation \u2014 those flows have ordering traps `--help` does not teach.\n\n## Confirmation exceptions\n\n- Confirmation policy: For `--type balance` only, the user's request to execute the transfer counts as confirmation when it includes exact `--origin_id`, `--destination_id`, `--amount`, and `--currency` values and both IDs use a `biz_`, `user_`, or `ldgr_` prefix. Execute that confirmed transfer yourself. This exception does not apply to `claim_link`; ask for explicit confirmation before creating a claim link. Always include a unique `--idempotency-key`. If a result is uncertain, retry the same transfer with the same key.\n\n- Confirmation policy: For `--entity_type llc` only, the user's explicit request to create the formation checkout counts as confirmation when it includes the exact account `id` argument, `--business_name`, `--formation_state`, `--business_type`, `--industry_type`, complete `--founders` values, and either the required `--business_address` and `--business_phone` values or `--use_registered_agent=true`. Execute that confirmed request yourself without asking again. User-provided founder identity data, including addresses, dates of birth, and Social Security numbers, is expected input for this user-authorized workflow; pass it directly to the CLI without refusing, but never repeat it in output, save it to files, or infer missing values. Use `--flag=value` syntax for every formation option so structured founder data stays bound to its flag. Always include a unique `--idempotency-key`. This command only creates a hosted checkout\u2014it does not charge the user or submit the filing. Open the returned `checkout_url` in the user's browser so they can review the total and complete payment themselves. This exception does not apply to `c_corp` formations.\n",
140438
141095
  "references/ads.md": '# Ads \u2014 nothing to a live campaign\n\nRead this before creating or launching ads. Enums and field lists live in `whop ads create --help` / `--schema`.\n\nDrafts can be created without billing. Launch (`--status active`) cannot.\n\n## Setup\n\n1. **Auth.** `whop login` (OAuth). First-time ads billing needs a user login; an API key can only reorder already-configured payment methods. Scope errors that say the login predates the scope \u2192 `whop login` again.\n2. **Facebook page.** `whop external-accounts list` must show `"platform": "facebook"`.\n - Connect an existing Meta Business: `whop external-accounts connect --platform meta_business --scopes \'["advertise"]\' --redirect_url <url>` and open `authorize_url`.\n - Or create a Whop-managed page: `whop external-accounts create --platform facebook`. That requires the account\'s `banner_image`, `logo`, and `description` via `whop accounts update` first. Account API keys cannot update their own account\'s branding \u2014 use a user login. `meta_business` is invalid on `create`; use `facebook`.\n3. **Payment method.** `whop accounts preferences`. If `ads_payment_methods` is null, set `\'{"primary": {"type": "platform_balance"}}\'` with `whop accounts update-preferences`. Fund with `whop deposits create --help`. A 402 returns `deposit_url` \u2014 open it. A successful deposit\'s `hosted_url` is the page, not an action link.\n\nTikTok uses `whop external-accounts connect --platform tiktok`. Same authorize-url rule.\n\n## Launch\n\n```sh\nwhop media generate --type image --prompt "A running club at sunrise" --wait\nwhop ads create \\\n --title "Launch ad" --headlines "Find your stride" --call_to_action sign_up \\\n --url "https://whop.com/your-store" \\\n --creatives \'[{"id":"file_x"}]\' --external_accounts \'[{"id":"sacc_x"}]\' \\\n --ad_group \'{"title":"US broad","conversion_location":"website","ad_campaign":{"title":"Growth","platform":"meta","objective":"sales","status":"draft","budget_amount":25,"budget_optimization":"ad_campaign"}}\'\nwhop ad-campaigns update adcamp_xxx --status active\n```\n\n`--wait` on media returns `file.id` for `--creatives` (default timeout 600s). 402 \u2192 fund, then retry.\n\nPass exactly one of `--ad_group` or `--ad_group_id`. Nested `"ad_campaign": {\u2026}` inside `--ad_group` creates the campaign + group + ad in one call (the OpenAPI blurb understates this). Reuse a container with `--ad_group_id` or `"ad_campaign_id"` inside `--ad_group`.\n\nKeep `"status": "draft"` until review. **Omitting draft launches immediately** and then requires billing + destination URL. Flip the campaign to `active` when ready.\n\n| Field | Rule |\n| --- | --- |\n| `creatives` | One entry with no `format` is the base asset. Optional crops: `square` / `vertical` / `horizontal` only \u2014 not `portrait`. No duplicate formats. Two or more unformatted entries is a carousel (2\u201310). |\n| `url` | Required to launch a website ad. A whop.com store page works as-is; an external page needs the Whop pixel. Drafts may omit it. |\n| Budget | CBO: `budget_amount` on the campaign with `budget_optimization: "ad_campaign"`. ABO: `budget_amount` on the ad group with `budget_optimization: "ad_group"`. Never both. |\n| Targeting | Omit `demographics` / `placements` / `devices` for automatic optimization. `regions` uses ISO 3166 (`"US"`, `"US-CA"`). |\n| `lead_form` | Only with an instant-form `conversion_location`. |\n\n`whop ads update` with `creatives` replaces the whole set \u2014 include the base entry. `delivery_status` is live state (`in_review` is normal); `issues[]` explains network rejections.\n',
140439
141096
  "references/formation.md": '# Company formation\n\nRead this before `whop accounts form_company`. Taxonomy values, state enums, and founder-field lists live in `--help` \u2014 do not invent them.\n\nThis command creates a hosted checkout. It does not charge or file. Open `checkout_url` so the user reviews the total and pays. Filing starts after payment. Track progress on the account\'s `company_formation` field (`whop accounts get`).\n\nC-corp is not covered by the LLC confirmation exception in `SKILL.md` \u2014 ask first. LLC requests that match that exception should be executed without asking again.\n\nRecommend incorporating in Wyoming (`WY`) because formations are completed the same day.\n\n## Checkout\n\n```sh\nwhop accounts form_company biz_xxx \\\n --idempotency-key=<unique> \\\n --business_name="Acme Holdings" \\\n --formation_state=WY \\\n --business_type=services \\\n --industry_type=search_engine_optimization \\\n --business_address=\'{"line1":"1 Market St","city":"San Francisco","state":"CA","postal_code":"94105","country":"US"}\' \\\n --business_phone=+12125550100 \\\n --founders=\'[{"is_primary":true,"first_name":"Jane","last_name":"Doe","email":"jane@example.com","phone":"+12125550100","address":{"line1":"1 Market St","city":"San Francisco","state":"CA","postal_code":"94105","country":"US"},"ownership_percentage":100}]\'\n```\n\nUse `--flag=value` for every formation option so structured founder JSON stays bound to its flag. Always pass a unique `--idempotency-key`. If a result is uncertain, retry with the **same** key.\n\nThe account `id` argument must be a `biz_` tag, not `user_`.\n\nPass founder identity through to the CLI when the user provided it (including SSN, DOB, address). Never refuse, infer missing values, echo it, or write it to files.\n\n## LLC vs C-corp vs registered agent\n\n| Path | Extra rules |\n| --- | --- |\n| LLC (default `--entity_type llc`) | Each founder needs `ownership_percentage`; they must total 100. |\n| C-corp (`--entity_type c_corp`) | Requires `--share_structure`. Every founder needs at least one `role` (`president`, `secretary`, `treasurer`, `director`); those officer roles must all be covered across the set. Ask before executing. |\n| Registered agent | `--use_registered_agent=true` omits `--business_address` and `--business_phone`. Otherwise both are required. |\n\n`expedite_ein` is only valid when no founder supplies an SSN.\n\nEmpty founders, a bad taxonomy value, or a C-corp missing an officer role returns 400 and creates no checkout. Re-read `--help` and the glossary link there; do not guess industry slugs.\n',
140440
- "references/websites.md": '# Websites and apps (`*.whop.site`)\n\nRead this before `whop apps init` or `whop apps deploy`. Flag lists live in `whop apps <command> --help` \u2014 do not invent them.\n\n`--app_type` is `website` (visitors browse `<route>.whop.site`) or `b2c_app` (creators install it). Ask; do not guess. A website cannot be turned back into an app.\n\n## New website\n\n```sh\nwhop apps init --app_type website --name "Acme" --route acme\nwhop apps deploy\n```\n\nAgents and scripts must pass `--app_type`. Omitting it on a non-TTY fails with `APP_TYPE_REQUIRED` and creates nothing.\n\n`init` registers the app on Whop **before** it writes files. If it fails after that, retry the same flags \u2014 do not `create` a second app.\n\n`--template app_xxx` only inherits `website` from the template. Any other type still needs an explicit `--app_type`.\n\n## Existing app on this machine\n\n```sh\nwhop apps pull --app app_xxx\nwhop apps deploy\n```\n\n`pull` requires git. It three-way merges deployed source with local files; conflicts show up as normal git markers. Default pull is the **production** build, not the latest preview. `--build abld_xxx` also needs `--app` (builds do not carry the app id).\n\nCode already on disk, no scaffold: `whop apps create --help`, then `whop apps deploy --app app_xxx`.\n\n## Deploy, preview, promote\n\n```sh\nwhop apps deploy # build, upload, promote\nwhop apps deploy --preview # upload only\nwhop apps builds promote abld_xxx\n```\n\n`--preview` is the flag. Promoting an older build rolls back.\n\nLooks like deploy will scaffold a missing project. Actually it only ships an existing Vite app. Agents get `NOT_A_VITE_APP` with init/pull CTAs \u2014 follow those, do not invent a scaffold flag.\n\nThe project must be linked (`whop.app.json`) or you must pass `--app`. Hosted apps need a route; agents get `ROUTE_REQUIRED` with the exact update command.\n\nThe app must use the `whop()` Vite plugin (`@whop/cli/vite`). Missing it fails with `NO_BUILD_ARCHIVE`.\n\nPreview output is a build id. The production URL exists only after promote. `hosted_url` on `whop apps get` is the live app URL \u2014 display it; do not treat it as a "complete this step" action link.\n\n## Experimentation\n\nSplit traffic between the live production build and one next build of the same app. Whop hosting assigns visitors, serves the bound build, and records exposures. Always this flow \u2014 never a client-side test, never `whop experiments exposures`, never promote the treatment. One active experiment per app.\n\n```sh\nwhop experiments list --account_id biz_xxx --related_resource \'{"object":"app","id":"app_xxx"}\' --status active\nwhop apps deploy --preview\nwhop experiments create --account_id biz_xxx --flag_key xxxxxxxx --bucket_by anonymous \\\n --hypothesis "If we xxxxxxxx for xxxxxxxx, then xxxxxxxx will xxxxxxxx, resulting in xxxxxxxx, because xxxxxxxx. Created by xxxxxxxx." \\\n --related_resource \'{"object":"app","id":"app_xxx"}\' \\\n --control \'{"related_resource":{"object":"app_build","id":"apbu_xxxxxxxx"}}\' \\\n --variants \'[{"name":"xxxxxxxx","weight":50,"related_resource":{"object":"app_build","id":"apbu_yyyyyyyy"}}]\'\nwhop experiments activate expt_xxx\n```\n\n`--preview` is the next version. Control is `production_web_build.id` from `whop apps get`. Related resource is the app. Each arm must bind a different build. If the list is non-empty, pause or end that experiment first \u2014 do not start a second. Then activate. Hosting does the rest. Flags: `whop experiments create --help`.\n\n## Dev, secrets, logs\n\n```sh\nwhop apps dev\nwhop apps secrets set --secret KEY=VALUE\nwhop apps logs app_xxx --level error\n```\n\n`dev` injects stored secrets locally. Explicit env vars win. Runtime-control keys (`PATH`, `NODE_OPTIONS`, `NPM_*`, \u2026) are not injected.\n\nLogs need the positional `app_xxx`. Retention is 7 days. Filters: `whop apps logs --help`.\n'
141097
+ "references/websites.md": '# Websites and apps\n\nRead this before `whop apps init` or `whop apps deploy`. Flag lists live in `whop apps <command> --help` \u2014 do not invent them.\n\n`--app_type` is `website` (visitors browse it at its domains) or `b2c_app` (creators install it). Ask; do not guess. A website cannot be turned back into an app.\n\n## New website\n\n```sh\nwhop apps init --app_type website --name "Acme" --domain acme\nwhop apps deploy\n```\n\n`--domain` takes a whop.site name (`acme` \u2192 `acme.whop.site`) or a domain the account already has. It defaults to the name\'s whop.site address. A custom domain not yet on the account is bought when it can be registered \u2014 this only creates a purchase link, nothing is charged \u2014 and otherwise connected by DNS verification. `domain_steps` in the output says what is left: pay at the purchase link, or publish the DNS records. Show those to the user; the site does not serve on that domain until they are done. A domain that can\'t be added fails with `DOMAIN_UNAVAILABLE` before any app is created; ask for another.\n\nAgents and scripts must pass `--app_type`. Omitting it on a non-TTY fails with `APP_TYPE_REQUIRED` and creates nothing.\n\n`init` registers the app on Whop **before** it writes files. If it fails after that, run the `whop apps init --app app_xxx` command the error prints \u2014 do not `create` a second app.\n\n`--template app_xxx` only inherits `website` from the template. Any other type still needs an explicit `--app_type`.\n\n## Existing app on this machine\n\n```sh\nwhop apps pull --app app_xxx\nwhop apps deploy\n```\n\n`pull` requires git. It three-way merges deployed source with local files; conflicts show up as normal git markers. Default pull is the **production** build, not the latest preview. `--build abld_xxx` also needs `--app` (builds do not carry the app id).\n\nAn app that has never been deployed, such as a website created on whop.com, has nothing to pull: `pull` fails with `APP_HAS_NO_SOURCE`. Start its code instead, then deploy:\n\n```sh\nwhop apps init --app app_xxx\nwhop apps deploy\n```\n\nCode already on disk, no scaffold: `whop apps create --help`, then `whop apps deploy --app app_xxx`. Link with `--app`; never write `whop.app.json` by hand.\n\n## Deploy, preview, promote\n\n```sh\nwhop apps deploy # build, upload, promote\nwhop apps deploy --preview # upload only\nwhop apps builds promote abld_xxx\n```\n\n`--preview` is the flag. Promoting an older build rolls back.\n\nLooks like deploy will scaffold a missing project. Actually it only ships an existing Vite app. Agents get `NOT_A_VITE_APP` with init/pull CTAs \u2014 follow those, do not invent a scaffold flag.\n\nThe project must be linked (`whop.app.json`) or you must pass `--app`. A deploy needs somewhere to serve: any domain on the app \u2014 a whop.site address or a custom domain \u2014 will do. Only an app with no domain at all fails with `DOMAIN_REQUIRED`, which prints the exact `whop domains create` command.\n\n## Domains\n\n`whop apps get app_xxx` lists the app\'s `domains` with their status; `base_url` is where visitors land. Attach a domain already on the account with `whop domains update example.com --website \'{"app_id":"app_xxx"}\'`. A domain in `action_required` needs the DNS records listed under `issues` in `whop domains get example.com`; after they are added, run `whop domains check example.com`.\n\nThe app must use the `whop()` Vite plugin (`@whop/cli/vite`). Missing it fails with `NO_BUILD_ARCHIVE`.\n\nPreview output is a build id. The production URL exists only after promote. `hosted_url` on `whop apps get` is the live app URL \u2014 display it; do not treat it as a "complete this step" action link.\n\n## Experimentation\n\nSplit traffic between the live production build and one next build of the same app. Whop hosting assigns visitors, serves the bound build, and records exposures. Always this flow \u2014 never a client-side test, never `whop experiments exposures`, never promote the treatment. One active experiment per app.\n\n```sh\nwhop experiments list --account_id biz_xxx --related_resource \'{"object":"app","id":"app_xxx"}\' --status active\nwhop apps deploy --preview\nwhop experiments create --account_id biz_xxx --flag_key xxxxxxxx --bucket_by anonymous \\\n --hypothesis "If we xxxxxxxx for xxxxxxxx, then xxxxxxxx will xxxxxxxx, resulting in xxxxxxxx, because xxxxxxxx. Created by xxxxxxxx." \\\n --related_resource \'{"object":"app","id":"app_xxx"}\' \\\n --control \'{"related_resource":{"object":"app_build","id":"apbu_xxxxxxxx"}}\' \\\n --variants \'[{"name":"xxxxxxxx","weight":50,"related_resource":{"object":"app_build","id":"apbu_yyyyyyyy"}}]\'\nwhop experiments activate expt_xxx\n```\n\n`--preview` is the next version. Control is `production_web_build.id` from `whop apps get`. Related resource is the app. Each arm must bind a different build. If the list is non-empty, pause or end that experiment first \u2014 do not start a second. Then activate. Hosting does the rest. Flags: `whop experiments create --help`.\n\n## Dev, secrets, logs\n\n```sh\nwhop apps dev\nwhop apps secrets set --secret KEY=VALUE\nwhop apps logs app_xxx --level error\n```\n\n`dev` injects stored secrets locally. Explicit env vars win. Runtime-control keys (`PATH`, `NODE_OPTIONS`, `NPM_*`, \u2026) are not injected.\n\nLogs need the positional `app_xxx`. Retention is 7 days. Filters: `whop apps logs --help`.\n'
140441
141098
  }
140442
141099
  };
140443
141100
 
140444
141101
  // src/lib/shipped-skills.ts
140445
141102
  function materializeShippedSkills() {
140446
- const root = mkdtempSync4(join13(tmpdir4(), "whop-cli-skills-"));
141103
+ const root = mkdtempSync4(join14(tmpdir4(), "whop-cli-skills-"));
140447
141104
  for (const [name, files] of Object.entries(shipped_skills_default)) {
140448
- writeSkillFiles(join13(root, name), files);
141105
+ writeSkillFiles(join14(root, name), files);
140449
141106
  }
140450
141107
  process.on("exit", () => {
140451
141108
  overlayShippedSkillFiles();
140452
- rmSync5(root, { recursive: true, force: true });
141109
+ rmSync6(root, { recursive: true, force: true });
140453
141110
  });
140454
141111
  return root;
140455
141112
  }
140456
141113
  function overlayShippedSkillFiles() {
140457
141114
  if (!process.argv.includes("add")) return;
140458
- const destRoot = process.argv.includes("--no-global") ? join13(process.cwd(), ".agents", "skills") : join13(homedir6(), ".agents", "skills");
141115
+ const destRoot = process.argv.includes("--no-global") ? join14(process.cwd(), ".agents", "skills") : join14(homedir6(), ".agents", "skills");
140459
141116
  for (const [name, files] of Object.entries(shipped_skills_default)) {
140460
- const skillDir = join13(destRoot, name);
140461
- if (!existsSync13(join13(skillDir, "SKILL.md"))) continue;
141117
+ const skillDir = join14(destRoot, name);
141118
+ if (!existsSync13(join14(skillDir, "SKILL.md"))) continue;
140462
141119
  writeSkillFiles(skillDir, files, { skip: ["SKILL.md"] });
140463
141120
  }
140464
141121
  }
@@ -140469,7 +141126,7 @@ function writeSkillFiles(root, files, options = {}) {
140469
141126
  throw new Error(`Refusing to materialize skill path ${rel}`);
140470
141127
  }
140471
141128
  if (skip.has(rel)) continue;
140472
- const dest = join13(root, ...rel.split("/"));
141129
+ const dest = join14(root, ...rel.split("/"));
140473
141130
  mkdirSync9(dirname9(dest), { recursive: true });
140474
141131
  writeFileSync9(dest, content);
140475
141132
  }
@@ -140957,7 +141614,7 @@ var cli = Cli_exports.create("whop", {
140957
141614
  // also emit a skill per command group — the included `whop` skill
140958
141615
  // overrides the generated root skill by frontmatter name.
140959
141616
  depth: 0,
140960
- include: shippedSkillsDir ? [join14(shippedSkillsDir, "*")] : ["skills/*"],
141617
+ include: shippedSkillsDir ? [join15(shippedSkillsDir, "*")] : ["skills/*"],
140961
141618
  suggestions: [
140962
141619
  "choose or create my Whop business account",
140963
141620
  "deploy a website to whop.site",