Skip to content

1.0.0

Choose a tag to compare

@whop-elements-release whop-elements-release released this 21 Sep 18:26
· 9 commits to main since this release

Major Changes

  • 4629eac: Initial release of Whop Elements — embeddable Whop UI for any website. Drop the elements.js script tag (or install @whop/elements) and mount ready-made, themeable components that talk to Whop for you; @whop/elements-react ships first-class React bindings on top. This first release includes the full foundation: typed handles with live update(), events and actions; light/dark theming and appearance customization; localized components; prerendered loading skeletons for flash-free first paints; modal and inline flow surfaces; and generated TypeScript types for the entire surface. (#30895)
  • 4629eac: Added the payments branding element — the "Powered by Whop" notice with terms and privacy links. It is required: the other payments elements stay in their loading state until it is mounted, and payments cannot be confirmed without it — a missing branding mount fails createConfirmationToken with the coded BRANDING_NOT_MOUNTED error, and one the embedding page hides or shrinks away fails with BRANDING_HIDDEN. Breaking for existing payments integrations: mount branding alongside your other payments elements when you upgrade. (#30895)
  • 4629eac: Removed the campaign builder's showToasts prop and errored event. Failure toasts now always appear exactly once through the standard toast surface — on your own page when the builder is embedded — so there is nothing left to mirror or turn off. (#30895)
  • 4629eac: Choose which Whop environment your elements run against when you create them: WhopElements({ environment: 'sandbox' }) uses test data with no real money moving, and production is the default. This is the one setting that decides where the elements send what a buyer enters — they only ever talk to Whop. (#30895)

Minor Changes

  • 4629eac: The embedded campaign builder shows the merchant when something fails: a refused launch, a failed upload or a draft that would not save renders as a toast in the builder itself, and comes back on an errored event if your page wants to log it or show it its own way. (#30895)

  • 4629eac: The ads reporting table gained a linkClicks column — clicks on links in the ad that lead to your destination, as reported by the ad platform, next to the broader clicks count. Off by default; turn it on from the column picker or by passing it in columns, and it comes back in columnsChanged like any other column. (#30895)

  • 4629eac: Bank wire payout methods now show the destination-currency country flag on the bottom-right of the card icon, so AED, EUR, and other wires are distinguishable in the method picker. (#30895)

  • 4629eac: The checkout offers one-press express checkout: Apple Pay and Google Pay buttons above the form, shown when the wallet is available on the buyer's device and the page's origin is approved for the account. The wallet sheet collects whatever the checkout still needs — the buyer's email, and the shipping address when the purchase requires one — and the buttons stack best-first for the browser: Apple Pay first on Safari and iOS, Google Pay first elsewhere. (#30895)

  • 4629eac: Added the express checkout element — one-press Apple Pay and Google Pay buttons you can mount on their own under a checkout handle (checkout.create("expressCheckout"), or <ExpressCheckoutElement/> in React). The OS payment sheet collects the buyer's email and shipping address when the session needs them, so one press finishes the purchase. It shares the checkout's entry slot with the checkout element: a handle mounts exactly one of the two. Two options shape it: wallets picks which wallet buttons may render (a filter over what the buyer's device actually offers — the element never shows a wallet the device can't pay with), and layout controls how the buttons stack (auto follows the container, horizontal and vertical force one arrangement). (#30895)

  • 4629eac: Added Bitcoin deposits to the Deposit element, with a reusable BTC address and direct settlement as USDT0 on Plasma. (#30895)

  • 4629eac: Collect Splitit's required billing phone once, show missing-phone feedback, and submit the collected or caller-supplied number with the payment method.

    Use one simple phone input for Splitit and reuse a phone already collected by checkout. Add fields.phone to disable duplicate collection and change.requiresBillingPhone to expose the selected method’s requirement. (#30895)

  • 4629eac: Added an rfi element to the verifications namespace: it lists everything an account still owes compliance, grouped by what each requirement affects, and collects the answers in place. (#30895)

  • 4629eac: Added the verifications namespace and its complete verification element. It collects KYC or KYB intake details, starts or resumes the hosted provider session, answers follow-up information and document requests, polls status, and renders the result using the 2026-08-05 API version. The hosted provider step opens in a secure tab so camera and document access work from embedded integrations. (#30895)

  • 4629eac: Checkout element: buyers are charged in their own currency, not shown a converted price. The server picks the currency from where the checkout was opened and publishes the one alternative as a "Pay in USD instead" switch. A converted total discloses what it converted from and at what locked rate, to five significant digits ("1 USD = 0.92191 EUR"), and when a promo code is applied the original price is struck through in the currency the buyer actually pays. (#30895)

  • 4629eac: How a checkout finishes: when you set a returnUrl, a completed purchase redirects the page the element is embedded in straight to it — fulfill from webhooks, which are the source of truth for a landed payment — and a page whose sandbox blocks that navigation gets a Continue button that makes the same trip. A payment step that leaves the page, like 3D Secure or a bank page, carries the buyer back to a page that tells them exactly where the order stands. Completion is judged by the payment's own status: a payment that settles later, like a bank debit, shows clearing copy while the money is still moving and only sends the buyer on once it has genuinely settled, and a dismissed 3D Secure dialog rests on a "Finish your payment" button. (#30895)

  • 4629eac: The checkout element now takes buyerEmail and lockBuyerEmail on embedded mounts too — pass the email your page already collected (checkout.create("checkout", { buyerEmail }), or <CheckoutElement buyerEmail={…} />) and the email row is seeded with it; add lockBuyerEmail to keep the buyer from editing it. Both were direct-mode props before, so a third-party page migrating from the legacy embedded checkout's prefill.email had no way to prefill the buyer's email. A session that already holds its buyer's email still wins over the prefill, exactly as on whop.com's own checkout page. (#30895)

  • 4629eac: Checkout now accepts an items array so one checkout can sell multiple plans and quantities in a single payment. Multi-item checkouts show every server-priced item directly below the total, while the existing plan and quantity options continue to work as the single-item shorthand. (#30895)

  • 4629eac: Added the tax ID element to the payments namespace: a standalone registration collector with a type select covering every registration the API accepts — labeled the way buyers know them (EU VAT, AR CUIT, US EIN, …) — and a value input whose placeholder follows the selected type. When you pass the buyer's country it preselects the right type. The checkout element's company-purchase section composes it, so a business buyer can enter any accepted tax ID at checkout: the total re-prices with the reverse charge applied where it applies, and the charge is taxed under the same registration. (#30895)

  • 4629eac: The checkout element says what the two special checkouts actually are. Opening a transfer link states in the order summary that you are accepting an existing membership — nothing is charged today, when the inherited access ends, and when the payment method you add first renews. A waitlist join tells the whole truth about money: the total reads "If accepted" rather than "Due today", the terms explain the buyer is only charged if the seller accepts their request, and a completed join says you are on the waitlist — the seller reviews requests, and the saved payment method is only charged if they accept you — both inside the element and on the hosted return page. A completed join is also announced to an embedding iOS/Android app so its checkout sheet closes. (#30895)

  • 4629eac: Added default activity type filters so embedded activity feeds can open scoped to flows such as card spend, reversals, and refunds. (#30895)

  • 4629eac: The balance breakdown can now sit inside a surface that already has its own heading: showTotal hides its currency title and total, and padded drops its page padding. (#30895)

  • 4629eac: The activity list now reports the row under the pointer (activityHovered), and the balance chart takes a markedAt timestamp to mark that moment on the line — so hovering a transaction shows where it sits in the balance history. (#30895)

  • 4629eac: Checkout links can carry where a sale came from. promoCode, attribution (UTM parameters, a tracking link, a funnel, your own source label) and metadata are options on checkout.create(), recorded on the order at the moment it is opened. The hosted checkout page reads them straight off the URL, so a campaign link keeps its attribution all the way to the payment. (#30895)

  • 4629eac: Added the tracking namespace with people and events elements — the account's pixel-resolved visitors and its raw event stream, with the same filters, search and pagination as the dashboard, on the handle's own window. A links config points cross-links at your own pages: the ads reporting table's click and result counts link to where you mounted people/events (via links.people/links.events on the ads handle), and person rows follow the tracking handle's links.person template ({personId}/{identifier} placeholders) or raise personOpened when unset. (#30895)

  • 4629eac: Added the Wallet Convert element for swapping USD with Gold or Coinbase Wrapped Bitcoin through Whop's public API. Fiat-to-fiat conversion remains unavailable to embedded consumers and is limited to gated internal users in first-party direct surfaces. (#30895)

  • 4629eac: Apple Pay now appears in Chrome, Edge and other non-Safari browsers, not just Safari — buyers pay through Apple's secure handoff flow, and no changes are needed on your page. (#30895)

  • 4629eac: The payment element reports the billing address it collects through the addressChange event, so your checkout can quote tax, rate your own shipping, or update anything else that depends on the address while the buyer is still filling it in. It carries the whole address — street, city, region, postal code and country — and it is debounced, so a typed postal code arrives as one update instead of one per keystroke. If the buyer changes payment method, the address you get follows the method they are on: one they started typing and walked away from never reaches you. (#30895)

  • 4629eac: Elements can now show toast notifications — brief status updates such as "Payment failed" appear at the bottom-right of the page the elements are embedded in. Pass toasts: false to WhopElements() (or the <WhopElements> provider) to turn them off. (#30895)

  • 4629eac: Payment methods are offered by the total each method would itself charge, so a fee-free method (like a buy-now-pay-later option) is priced — and minimum-checked — at its own amount. Composing checkouts pass the offerAmounts input; plain amount mounts offer every method at that amount. (#30895)

  • 4629eac: RequiredActionsElement and VerificationElement moved from Wallet to Dashboard, beside the payments table and detail, and now read with the handle's accountId and accessToken instead of taking their own token. The required-action bar no longer opens the wallet's deposit overlay for Add money; it reports depositRequested so the host mounts its own deposit flow, such as the wallet DepositElement. (#30895)

  • 4629eac: Added the dashboard namespace for an account's own records. Mount PaymentsTableElement for the account's payments and PaymentDetailElement for one payment under Dashboard, with one accountId and one scoped accessToken for both. PaymentsElement under Payments moved here as PaymentsTableElement, and the Payments handle no longer takes accessToken. (#30895)

  • 4629eac: The deposit element can now preview a fee under the rail picker. Pass depositRailFees keyed by rail (bank, crypto) and the element shows the rate before an amount is entered and the charged amount after — the percentage in the deposit currency, the fixed part in USD. (#30895)

  • 4629eac: The payment element now offers card installment plans inside the card pane: buyers pick an installment count or pay in full, per-installment amounts are shown fee-adjusted, and eligibility follows the entered card. The card elements' change event now reports the detected funding type. (#30895)

  • 4629eac: Added a compact layout option to the wallet verification banner. (#30895)

  • 4629eac: Added the checkout element — mount a complete checkout from a plan id: live price summary, promo codes, the currency the buyer pays in, every payment method, and the pay flow in one element. (#30895)

  • 4629eac: loadWhop() now loads the SDK from cdn.whop.com, and its failure message includes what the browser measured for the request. If your Content Security Policy lists script or frame sources, replace js.whop.cloud with cdn.whop.com. (#30895)

  • 4629eac: Added buyer sign-in to the payments family: the email element collects the one email for the checkout and recognizes returning buyers, and a verification-code dialog signs them in with a one-time code. A signed-in buyer is carried through the rest of the checkout, so you never ask them who they are twice. (#30895)

  • 4629eac: If your page also runs the Whop pixel, elements now connect their analytics visitor id to the pixel's visitor id — one identity link that makes element activity joinable to your ad-attribution data in Whop's identity graph. The connection is a single call made through the pixel's own SDK, at most once per page view — repeats are deduplicated on Whop's side, elements read and store nothing on your page for it, and the element frames themselves are never involved. Skip it entirely with WhopElements({ skipPixel: true }) (also available on the React <WhopElements> provider). Pages without the pixel are unaffected: no link, no extra requests. (#30895)

  • 4629eac: Cashback can be selected in the Activity type filter under Cards. It remains excluded from the default activity feed. (#30895)

  • 4629eac: Added the send element to the wallet namespace — sends money to a user, another business, or a public claim link, with recipient search built in. (#30895)

  • 4629eac: Added the ads billing-setup element: the primary and backup payment methods ad spend bills against, saved as they are picked. (#30895)

  • 4629eac: Added destroy() to namespace handles — tear down a checkout (or any element group) when you are done with it, freeing its elements, frames, and subscriptions. React groups keep doing this automatically when the provider unmounts. (#30895)

  • 4629eac: The checkout now shows the buyer what makes up their total, not just the number. The order summary itemizes what is being bought, the discount a promo code applied, the service fee, and tax — with anything owed after today listed separately, whether that is a single later charge, a subscription, or a fixed number of installments. Tax is priced for the address the buyer enters and appears as its own line: added on top where a market charges it that way, and disclosed as already included where it does not. A struck-through original sits beside the total whenever a promo lowered it, measured on the same basis so the two figures agree. Every row is labelled in the buyer's language, and the total is always the amount the payment will charge. (#30895)

  • 4629eac: loadWhop() no longer caches a failed load for the rest of the page. The promise it returns now carries retry(), which starts a fresh load after a failure. <WhopElements> gains onLoadError(error, retry): with it set, a failed load is reported instead of thrown, your tree stays mounted, and calling retry() loads again in place. (#30895)

  • 4629eac: The wallet payment sheet is a first-class paymentRequest resource: mint it with whop.payments.paymentRequest.create({ accountId, currency, amount, … }) (React: useWhop().payments.paymentRequest.create(…)). The instance carries the canMakePayment()/show() ceremony and exposes typed onShippingAddressChange/onShippingOptionChange/onConfirmationToken/onCancel subscriptions, each returning its unsubscribe function, with a dedicated docs page covering the options, the user-gesture rule on show(), and the reply-once updateWith contract. The API origin follows your WhopElements({ environment }) setup automatically, and the Apple Pay sheet's merchant country comes from the seller's registered merchant record; set countryCode only to override it. (#30895)

  • 4629eac: Added the ads namespace, starting with report-chart: what an advertising account spent and what it got back over a window you choose, with a picker for which result to plot — spend, impressions, clicks, or any conversion the account records. It is the same chart the Whop dashboard draws, not a lookalike, so it cannot drift from it. The window lives on the handle rather than the element, so set it with period (or customRange), read every move back off periodChanged, and any further surfaces you mount under the same handle report on exactly the same window. Narrow what it reports on the same way: campaignIds, adGroupIds or adIds on the handle scope every surface under it to that selection, narrowest wins — pass a single id for an exact figure, since the reporting API scopes by one source path and the chart reports on the first id given. (#30895)

  • 4629eac: Added an embeddable wallet action row whose Deposit and Send controls open their built-in flows and whose Accept control opens the corresponding Whop setup. (#30895)

  • 4629eac: The wallet activity detail drawer can now be opened straight from a card transaction ID, so a card table row press can hand it the transaction it already has. Its card receipt now names the card it was charged to and its last four digits, adds the cardholder row on a company account — clicking it reports cardholderSelected — and states the cashback rate a purchase earned. (#30895)

  • 4629eac: The checkout element walks buyers through bank verification challenges when joining a paid waitlist, so a card that asks for 3D Secure can finish being saved. (#30895)

  • 4629eac: The payment element offers a buyer's Whop balances as their own payment method instead of mixing them into the saved payment methods. Selecting it opens a scrollable list of the buyer's wallets — each with its account name, logo, and available amount in the checkout currency — that pages in as the buyer scrolls, automatically lands on a wallet that can cover the charge, and keeps the buyer's own pick through sign-ins and session changes. Compact checkouts offer a balance only when one can actually cover the charge. The new tile ships with its own styling hooks (PaymentBalanceList, PaymentBalance, PaymentBalanceRow, PaymentBalanceRowSelected, PaymentBalanceHint, PaymentBalanceMore). (#30895)

  • 4629eac: Added exact payout quotes to the withdraw element. Enabled accounts can show the destination amount, fees, exchange rate, and quote expiry before confirmation, then safely retry a quote or payout when its result is uncertain. (#30895)

  • 4629eac: The wallet action row can now offer Withdraw: turn on showWithdraw to show it, withdrawDisabled to grey it out, and it reports withdrawRequested as the wallet handle opens its withdraw overlay. (#30895)

  • 4629eac: Adds pixel-setup to the websites namespace — the Whop Pixel install wizard as a mountable element.

    It opens on a "why a pixel" splash (showIntro, on by default — turn it off for a flow that already sent the merchant here knowing why), hands over the install snippet with Google Tag Manager instructions and an invite-a-developer path, checks pages for it, and walks them through wiring conversion events, including a "verify live" pass for pages a server-side scan cannot reach. Once the pixel is detected the wizard says so and stays put, so the merchant can read the result before choosing to optimize further.

    Everything is set on the element itself. Point it at a page with destinationUrl, or leave that blank and it asks for one. eventName is optional: name an event and the events step blocks until it fires, leave it unset and every event is offered with none gating anything. Credentials come from accessToken; omit it same-origin and the viewer's session carries the calls.

    Read what it learned off scanned, eventVerified, redirectUrlChanged and finished — it reports what it checked and leaves deciding whether your requirements are met to you. scanned fires for every URL the wizard checks, so gate on its primary flag when you only mean the page being set up. (#30895)

  • 4629eac: When pixel-setup is mounted without a destinationUrl, the empty URL field now suggests up to three pages to check, drawn from the account's ad destination URLs and the hostnames its pixel already fires on. Picking a suggestion runs the check immediately. The suggestion reads use the element's accessToken and need ad_campaign:basic:read and stats:read; without those scopes the field simply stays bare, as before.

    The element also emits four new events a host can subscribe to: urlSubmitted (the account owner named the page, typed or picked from a suggestion), verifyLaunched ("Verify live" was pressed, with whether the browser blocked the funnel window), verifyConnected (the funnel page's pixel pinged back), and verdict (the walk finished, with the gap codes it found).

    A new verifyFirst prop leads with that page check instead of the install instructions: the URL field sits at the top, the install paths fold under a "Pixel not installed yet?" toggle, and the header reads "Verify your pixel". A passing page check then goes straight into the events step, which opens on the live funnel walk rather than the event catalog: a page-view scan alone is the false comfort this mode exists to remove. It is for an account owner who already has a pixel and wants to know why nothing is being attributed; pair it with showIntro: false. (#30895)

  • 4629eac: The withdraw element's payout-details step offers "Link your bank" when the supported method allows Plaid, emitting a plaidLinkRequested event for the host to open Plaid Link; supported methods carry a supportsPlaid flag. (#30895)

  • 4629eac: The checkout element spells out the full billing terms in its order summary: how long a free trial runs and what it renews to, the renewal price and how often it is charged, an installment plan’s total number of payments, a one-time setup fee folded into today’s charge, and how long a one-time purchase keeps access. The pay button says what the click actually does — “Start trial” on a trial, “Subscribe” on a subscription — never “Pay $0.00”. An applied promo code shows its discount against today’s charge with the original price struck through beside it. The terms line under the button names Whop as the merchant of record on every payable checkout — hosted and embedded alike — and links the seller’s own published terms, privacy, return and licence documents; a seller who requires an explicit agreement gets a checkbox that holds the pay button until the buyer ticks it — the checkout only attests to terms the buyer actually accepted. (#30895)

  • 4629eac: Added the accessToken prop to the deposit element so a personal account's funding rails resolve on any page — mint it with payout:account:read, plus payout:account:update to provision the bank rail. (#30895)

  • 4629eac: Added the payments namespace: the payment element (the seller's eligible payment methods rendered live, with inline card fields, billing address collection, and one confirm verb that mints confirmation tokens), the drop-in card element, the exploded card-fields unit for custom layouts, the address element, and the payment completion flow. (#30895)

  • 4629eac: paymentRequest.canMakePayment() now also returns order — the wallets ranked by which sheet is native to the browser (Apple Pay first on Safari, Google Pay first elsewhere), so express buttons can be stacked best-first. (#30895)

  • 4629eac: Signed-in buyers see the payment methods they already saved, listed above the ones they would have to type out, and the payment element opens on the first of them. Only methods this charge can actually take are listed, so a saved card in a currency you don't accept — or a method you've turned off — never appears. Buyers who sign in partway through checkout get their saved methods without losing anything they had already filled in.

    Style the new rows with .whop-PaymentSavedMethods, .whop-PaymentSavedMethod, .whop-PaymentSavedMethodRow, .whop-PaymentSavedMethodRowSelected, .whop-PaymentSavedMethodSeparated, .whop-PaymentSavedMethodHint, .whop-PaymentSavedMore and .whop-PaymentSavedMoreSpinner — or keep using .whop-PaymentMethodRow, which every row still carries, and style both lists at once.

    When a saved method is selected, change carries complete and type but no method block: that block describes a method's collection rules, and a stored method has none. Drive your pay button off complete. (#30895)

  • 4629eac: The send element accepts an optional title prop so a host can replace the default "Choose recipient" header. (#30895)

  • 4629eac: Added the wallet namespace and its deposit element: an embeddable deposit surface that resolves an account's live funding rails (crypto deposit addresses per network, bank wire fields per settlement currency) with no credentials, and hands card / platform-balance rails back to the host as events. (#30895)

  • 4629eac: Added the maxItems prop to the balances list. Set it to show only the largest holdings up to that count; the list gains a "Show all balances" control that expands the rest in place. (#30895)

  • 4629eac: The deposit element always offers bank transfer, and sends the viewer to identity verification when the account does not yet have a virtual bank account. (#30895)

  • 4629eac: Payments can mount in setup mode. Pass mode: "setup" with a currency to save a buyer's payment method without charging them: the method list offers only methods that can be saved and amount limits do not apply. Confirm as usual and create the setup intent from your server. (#30895)

  • 4629eac: Added externalMediaIds to the campaign-creator element: file IDs your app uploads via POST /api/v1/files now surface at the top of the builder's creative library, and the media pickers open on the library while any are set. Update the element with new IDs to stream media into an open builder. (#30895)

  • 4629eac: The payment element's change event now carries supportsBuyerFee: whether a charge on the method the buyer picked carries Whop's service fee. The hosted checkout uses it to re-price the total the moment a fee-free method is chosen, so the figure on the pay button is the figure that gets charged — and any page driving its own summary off the payment element can do the same. (#30895)

  • 4629eac: The wallet cards element tells you what to do when there are no cards. An account with no card program is offered account verification instead of a retry message that could never work — the press starts the hosted verification session and leaves for it, emitting verificationRequested so a host can record the trip. A provisioned account with no cards yet gets an invitation to create its first one, with a placeholder row where it will sit. Genuine transient failures keep the retry message. (#30895)

  • 4629eac: Added a checkoutSession option on the payments provider that records a mid-checkout sign-in on your checkout session. The checkout element walks a seller’s verified-phone requirement end to end: sign in, verify the number, pay. (#30895)

  • 4629eac: The wallet activity list can now render as a short preview: maxItems caps the rows and stops paging, hideFilters removes the filter control, and a See all activity control reports seeAllRequested so you can open your own full activity screen. (#30895)

  • 4629eac: Checkout collects exactly what the seller set it up to ask for — the buyer's email, the seller's own questions (the shirt size, the Discord handle, the gamertag), an agreement to the seller's terms — all on one screen, in the order the seller chose, and will not take the payment until the required ones are answered. Whop decides what a checkout still needs and what happens once it is paid, so a seller who starts asking for something new does not need you to ship anything, and every buyer ends up wherever that seller sends them, whether the payment finished on the page or came back from their bank. (#30895)

  • 4629eac: Embed balance reports and filtered report activity, including CSV exports, with wallet.reports. (#30895)

  • 4629eac: Added the cards element to the wallet namespace — lists an account's issued cards with a limit, and disableRedirect/hideAddButton toggles. (#30895)

  • 4629eac: The campaign creator now lets advertisers choose the conversion event for TikTok campaigns on conversion-optimized goals — the same standard and custom pixel events the Meta picker offers — instead of always optimizing for the event implied by the campaign objective. (#30895)

  • 4629eac: The tracking handle gained a person element: the view a person click on people or events finally leads to. It draws one person's whole record: who they are and every identifier they have been seen under, where they came from touch by touch, what they have spent, their memberships and receipts, and their entire event history in order, the same view Whop's own dashboard shows. Set identifier to any identifier the account has seen the person under (the stable prsn_… person ID, a Whop user ID, or an email); that is exactly what personOpened hands you. Mount it inline on the page your links.person template points at, or present it over your own page with createOverlay("person") when a click comes back as personOpened. (#30895)

  • 4629eac: The checkout tells a returning buyer when a plan's free trial is not theirs to start again. If the account has already used the trial, the summary says so and shows the real amount due today, the pay button drops "Start trial", and the quote carries a trial_skipped flag. A payment submitted against a price that did not account for it is refused and re-priced instead of ever charging more than the buyer saw. (#30895)

  • 4629eac: The embedded checkout offers “Finish on whop.com” when a completed purchase still has an account claim waiting — the buyer finishes claiming their purchase in a new tab on whop.com. (#30895)

  • 4629eac: Added the activity element to the wallet namespace — an account's ledger activity feed with type and date-range filters built in. (#30895)

  • 4629eac: The verifications namespace gains a capabilities element: the account's individual and business verification standing, and the capabilities that standing unlocks. hideStatus and hideCapabilities drop either half, and pressing a verify button reports verificationRequested rather than navigating, so the host mounts its own flow. (#30895)

  • 4629eac: Embed a payments table with status counts, filters, CSV export, and payment selection events using PaymentsElement under Payments. Set showActions={false} to hide its header action menu, Export, and table settings. Set showRowActions={false} to hide row menus and showStatusTabs={false} to hide the status boxes. (#30895)

  • 4629eac: Added a configurable Convert button to ActionsElement. Handle convertRequested to open the host-owned conversion flow, or set showConvert to false to hide it. (#30895)

  • 4629eac: Added the Wallet balances breakdown and settlement Elements. The breakdown matches the dashboard balance layout and shows one fiat currency or token balance as a total, a proportional bar, and non-zero available, pending, reserve, and negative rows. showSourceCurrency switches between the holding's own unit and its USD value. Every row and matching bar segment is interactive, emits breakdownSelected, and opens the new dashboard-style settlement modal with available funds, dated and undated pending settlements, reserve terms, and negative balance details. Money-movement buttons stay outside the Elements so each host can own its Deposit, Send, Convert, and Withdraw flows. The common setup only needs the wallet account ID and access token; currency and display options retain defaults. Set openActivityOnSelect to use Wallet's built-in activity detail modal; it stays off by default so existing activitySelected handlers keep ownership of their own detail UI. The standalone activityDetail Element accepts either an optional prefetched activity row or an optional activity ID, retrieving the selected row from the Financial Activity REST API only when the prefetched row is absent. (#30895)

  • 4629eac: Added the balances unit to the wallet namespace, with two faces. The list shows what an account holds — every currency and token gets its own row with its dollar value, largest first — and emits balanceSelected so the host owns navigation; with includeOwnedAccounts, a user's personal balance is followed by every account they own. The balance chart draws the account's value over time, mountable on its own or carried above the holdings. Reading balances is privileged: pass an accessToken minted with POST /v1/access_tokens and scoped to company:balance:read, or mount same-origin and the viewer's own session carries the read. (#30895)

  • 4629eac: The wallet's card surfaces move into a cards unit and gain two more. cardDetails is a drawer for one card — its art, what it has spent against its limit, and its latest transactions. cardTransactions is the account's full transaction table, filterable by card and searchable over what it has loaded. The existing list, roster, spend chart and revealable card keep their published names — CardsElement, CardsTableElement, CardsChartElement, WhopCardElement — but are now minted from the unit rather than the wallet handle directly, so a page showing several of them wires the account and credential once. (#30895)

  • 4629eac: The wallet balances list can show a holding's USD or cash balance page in the same embed. Pass openHoldingOnSelect on the wallet handle or the balances unit; a row click then replaces the chart and list with that holding's amount, available / pending / reserve split, Deposit / Send / Withdraw, and that holding's activity. (#30895)

  • 4629eac: The wallet playground now has the outstanding-action bar from the balance dashboard. Mount required-actions and it shows the same banners an account sees there — identity verification first in the demo, plus deposits, tax, and the rest when the API returns them. Verify starts hosted KYC; Add money opens the Wallet deposit overlay. An account with nothing outstanding renders nothing, so the bar can sit in a layout permanently. (#30895)

  • 4629eac: Payment requests announce the selected card's billing address. Subscribe with onBillingAddressChange to reprice an open wallet sheet for where the buyer's card lives: the event fires at sheet open and on card switches with the redacted address (city, state, postal code, and country) and a reply-once updateWith — answer updateWith({ amount }) in minor units, or updateWith({}) to keep the current total. Every event is answered exactly once, so a slow, thrown, or superseded handler keeps the current total and never stalls the sheet. (#30895)

  • 4629eac: The wallet sheet's email contract is explicit. A payment request created with requestPayerEmail: false takes the buyer's email at show(type, { email }) — collected by your own form — and refuses to open the sheet without one, since the confirmation token requires an email. The default (requestPayerEmail: true) keeps collecting it in the sheet, as before. (#30895)

  • 4629eac: The wallet has a new verification face: a banner that asks an account holder to verify their identity, and renders nothing at all once they have — so it can sit permanently in a layout. Its headline and body track the account's real state, from an unstarted account through one under review to one that failed, and pressing the button starts a hosted verification session and sends the viewer to it. (#30895)

  • 4629eac: Added three card surfaces to the Wallet controller. WhopCardElement renders a single revealable issued card with native tilt and flip animations, permission-aware secret prefetching, configurable controls, and a host-owned Apple Wallet event. CardsTableElement renders the full sortable card roster with cardholders, spending, limits, and creation dates. CardsChartElement renders the dashboard's interactive card-spend chart with selectable reporting periods. (#30895)

  • 4629eac: Added the websites namespace with the websites element: an account's websites in one table — every site built on whop.app from the moment it exists, merged by hostname with every domain the Whop Pixel reports — with visitors, page views, trend, per-domain pages, and a per-row event breakdown, mountable on any page. Optional pixel checking is reported through verifyRequested, whop.app row settings through settingsRequested, and showEdit adds a primary Edit button on whop.app rows reporting through editRequested — the host page owns the popup and the editing surface. A site that is not live yet renders as a waiting row: a site the mounted pixel-setup wizard proves live gets its row automatically — remembered on your page, so it survives a reload — and pendingWebsites declares the waits the handle cannot see for itself, such as a whop.app site you just created. websitesLoaded fires on every settled load, so use it to drop pending entries once their domain reaches the table. (#30895)

  • 4629eac: The ads handle carries the chart selection as well as its window. metric (with metricEvent for a per-conversion one) sets what is plotted and follows the picker, so mirroring metricChanged into your own URL and handing it back is enough to make the choice survive a reload. sources chooses which traffic is reported on — null, the default, is advertising bought through Whop; [] is every source; an array of source paths (ext:*, referrer:*, direct) narrows to those. Ratios derived from spend stay Whop-attributed whatever you set, because spend only ever bought Whop ads. timezone is a choice between the two zones the chart's picker offers — 'account', the account's own reporting zone, or 'local', the viewer's; to report in some third zone, change the account's. timezoneChanged carries both halves: the choice, which is what to persist and hand back, and resolved, the IANA zone it came out as. (#30895)

  • 4629eac: Added a Wallet withdrawal flow with grouped payout speeds, payout method collection, fee details, and confirmation. (#30895)

  • 4629eac: Added the bankWarning prop to the wallet withdraw element. When a withdrawal is refused because the bank could not confirm the account holder's name, the host sets it and the element shows a fix-or-confirm screen instead of a generic error; confirming re-emits withdrawalRequested with the optional acknowledgeBankWarning field so the host can retry the same payout with the warning acknowledged. (#30895)

  • 4629eac: The wallet withdraw element now lists payout methods and creates the payout itself — pass accessToken the same way as Send, cards, and deposit. A host that already talks to the payouts API can still supply methods and handle withdrawalRequested; confirming after a self-serve create only reports success so that host does not post twice. (#30895)

  • 4629eac: A failed payment never spends the checkout: a decline — at the payment step or after a 3D Secure challenge — reopens the same checkout with the reason shown, and the buyer simply pays again. Mount the element with a plan and it opens and manages its checkout session end to end. (#30895)

  • namespace "payments" added (payments)

  • namespace "verifications" added (verifications)

  • namespace "checkout" added (checkout)

  • namespace "ads" added (ads)

  • namespace "tracking" added (tracking)

  • namespace "wallet" added (wallet)

  • namespace "websites" added (websites)

  • namespace "dashboard" added (dashboard)

Patch Changes

  • 4629eac: Address fields now reject card numbers with a field error and prevent those values from being submitted or sent to address autocomplete. (#30895)

  • 4629eac: The ads billing slots show a balance the account funds ads with even when the viewer has no access to that balance themselves — it renders with the balance's own name and icon instead of reading as an empty slot, and the other slot can be changed without the save being refused. (#30895)

  • 4629eac: The ads reporting chart's funnel view lets the viewer choose its steps — up to ten, in any order, from impressions, clicks, every standard conversion and every custom conversion the account records — and reports what the window cost: the period's total spend beside the conversion rate, and the cost of one action under every step, shown as a dash where the step never fired rather than an infinite price. Every figure is read against the equal-length window immediately before it, so total spend, each step's count and each step's cost per action carry their relative change, with a cheaper action coloured as the improvement it is; a figure whose previous window was zero reads as new rather than an infinite rise, and All time — which has no preceding window — reports no change at all. A step that fires more often than the one before it is drawn and reported as growth above 100% rather than clipped flat at the top of the plot, so a double-firing or mis-scoped pixel is visible. (#30895)

  • 4629eac: Apple Pay reports itself available only where a payment can actually finish. A page whose origin isn't approved for the account reports it unavailable — matching Google Pay, and matching what the payment sheet itself would do at merchant validation; first-party whop.com pages are pre-approved, and a merchant page needs its domain registered as a payment method domain. Mobile non-WebKit browsers report it unavailable too — the cross-browser flow there is the desktop handoff, which a phone can't sensibly complete. Native Apple Pay in iOS browsers is unaffected. (#30895)

  • 4629eac: When automatic withdrawals are on, undated pending funds say "Automatic withdrawal" instead of "Awaiting settlement". (#30895)

  • 4629eac: Bank transfer instruction steps now show the receiving bank's code even when the bank's name is not supplied, so buyers paying by IBAN get the BIC alongside the account number instead of only a reference. (#30895)

  • 4629eac: Bank wire payout methods use a bank icon instead of a card icon in the method picker. (#30895)

  • 4629eac: SendElement now authenticates with the accessToken it is given. Every call it made — the recipient list, recipient search, the account balance on the amount screen, and the transfer itself — went out with no credential, so the element only worked on a page that already carried a Whop session cookie and refused with 401 everywhere else. (#30895)

  • 4629eac: The checkout element collects the shipping address when the product requires one, so physical-goods checkouts complete inside the element. (#30895)

  • 4629eac: The cards table now renders each card's spend limit (for example "$1.5K / month") instead of an unformatted placeholder. (#30895)

  • 4629eac: Checkout and payment elements now hide Bank Wire when the current plan or promo code cannot use it. (#30895)

  • 4629eac: The embedded checkout no longer grows taller on every resize when appearance styles add padding or a border around the element — embedded frames now size to the checkout content, and the full-page checkout layout is unchanged. For the same reason, appearance styles can no longer size an element's growth from the viewport: heights (any fraction — even 50vh), padding, margins, borders, gaps, font sizes, line heights, and flex bases with viewport-unit values (vmin excepted), or reached through var() or calc(), are dropped on those properties, and appearance variables no longer accept viewport-height units at all. max-height caps still work, and the framework's --whop-viewport variable cannot be redefined through appearance. (#30895)

  • 4629eac: The checkout's pay button says the purchase button text set on the product — "Join", "Apply now", "Get access" and the rest — instead of always saying "Pay". Buyers picking a pay-over-time method were reading "Pay" as a demand for the full amount today. A membership transfer, a checkout that only saves a payment method, and a waitlist join keep their own wording, since those name something the product's label was not written for. (#30895)

  • 4629eac: A checkout that cannot open — a plan link that no longer points at anything you can sell, or a network failure at mount — shows a readable message. (#30895)

  • 4629eac: Passing an email to paymentRequest.show() now tells the wallet sheet you already collected one, so the sheet no longer asks the buyer for a second email. Omit it and the sheet collects one, exactly as before. (#30895)

  • 4629eac: Match activity-detail drawer content to the dashboard and improve wallet action and activity loading skeletons. (#30895)

  • 4629eac: Payment completion dialogs automatically show the account name from the payment, so buyers can see who they are paying. (#30895)

  • 4629eac: Clarify crypto deposits with a 0.3% deposit fee, a Bitcoin processing estimate of 10–30 minutes with confirmations on a separate line, and no receive row. Improve spacing and alignment on narrow screens. (#30895)

  • 4629eac: The deposit element no longer offers verification to an account that has already verified. It was treating "no usable bank rails" as "identity outstanding", so a verified account whose bank details are not provisioned was shown a Verify identity button that could not change anything. It now reads the account's outstanding actions and only offers verification when one is genuinely waiting on the viewer: bank transfer reports that it is not available yet when the account is verified or its verification is still in review, and the element re-reads the account on refresh so the button clears as soon as verification completes. (#30895)

  • 4629eac: Aligned wallet bank instructions with Whop's native deposit modal by moving the instruction title into the header and tightening the details layout. (#30895)

  • 4629eac: The deposit amount picker now shows bank transfer and crypto together while deposit details are still loading. Continue stays disabled with a spinner until the rails resolve, instead of revealing crypto only after the request finishes. (#30895)

  • 4629eac: Render declared loading skeletons before fixed-width modal-only elements initialize. (#30895)

  • 4629eac: A promo code that makes a checkout entirely free no longer strands the buyer on an empty payment-method list: fully free checkouts skip payment collection, and $0-today checkouts offer methods judged against the first charge that takes money. A checkout with nothing to pay also stops advertising adaptive pricing — free plans, membership transfers, and checkouts a promo code makes entirely free drop the "pay in another currency" switch and the conversion note, and always price in the seller's own currency. (#30895)

  • 4629eac: Fixed appearance.classes being ignored when keyed by bare class names ("whop-PayButton") — the shape the Styling docs show. Declarations now apply at create() and through update({ appearance }) alike. (#30895)

  • 4629eac: The Send note field now keeps a neutral border while focused. (#30895)

  • 4629eac: Restored release-date and amount tooltips on reserve charts. (#30895)

  • 4629eac: Fixed the withdrawal method picker on mobile so payout options stay accessible in a nested sheet. (#30895)

  • 4629eac: Withdrawal details for an Interac e-Transfer now show the security answer, so the recipient can look it up when the transfer arrives instead of only seeing it once at the moment they withdraw. (#30895)

  • 4629eac: Improved the TikTok campaign creator to match the Meta flow's visual hierarchy and controls. (#30895)

  • 4629eac: Payment submissions now validate card fields at submission time, preventing valid autofilled cards from being incorrectly blocked. (#30895)

  • 4629eac: Identity verification now runs inside the element on Whop's own pages instead of sending people to a separate window — they scan their document and finish where they started. Embeds on other sites keep the pop-out handoff, which is the only way the provider can reach a camera from there. (#30895)

  • 4629eac: Verification forms now show the reason an answer was rejected — for example that a field needs at least 50 characters — instead of a generic failure message. (#30895)

  • 4629eac: Fixed personal cash balances to show matching totals in the original currency and USD, including pending and reserved funds. (#30895)

  • 4629eac: Onboarding rewards now use the gift icon in wallet activity. (#30895)

  • 4629eac: The payment element offers a method whenever the buyer's own country accepts the charge, instead of holding every buyer to the narrowest range across all the countries a method serves. It uses the detected country before an address is available, then re-evaluates methods from the live billing country and keeps that country when the buyer switches methods. A method whose limit is lower in some other market — Klarna in euros, capped far below its Italian ceiling in Greece and Portugal — now shows for the buyers it is actually available to. (#30895)

  • 4629eac: The payment detail Plan row now shows the plan's price. It previously showed the business's private plan notes, which are free text and are no longer displayed. (#30895)

  • 4629eac: Payment instruction steps now render buyer-ready panes: vouchers draw a scannable barcode with a copyable reference, QR methods draw the scannable code and the copyable payment key, and bank transfers list the account details with a copyable transfer reference — with amounts and deadlines formatted in the buyer's locale. (#30895)

  • 4629eac: Show platform fees and fee credits in the default wallet activity feed and activity type filters, including the account that paid or received the fee. (#30895)

  • 4629eac: Wallet balance loading states now honor the same appearance classes as their loaded surfaces. (#30895)

  • 4629eac: The first toast on a page no longer pauses while the toast area boots — it is ready the moment the elements script initializes. (#30895)

  • 4629eac: A completed checkout whose post-purchase destination is reserved for the signed-in buyer says so on the success face — "check your email to claim your purchase", or that the purchase was completed on another device. The purchase always stands; the element just tells the buyer their next move honestly. (#30895)

  • 4629eac: Verification RFIs now show the payouts reviewer's full instructions beside the uploads they describe, instead of cutting them off, and number the uploads when a review asks for more than one document. (#30895)

  • 4629eac: The wallet withdraw confirmation screen again accepts an optional note (up to 255 characters) that only the team can see. Confirming includes it on withdrawalRequested so the host can store it on the payout. (#30895)

  • 4629eac: The wallet elements work for personal accounts, not only businesses: balances, activity (including its currency filter), send, and withdrawals all accept a personal account. (#30895)

  • 4629eac: Keep existing payments integrations working when they do not yet mount the branding element, while still refusing explicitly mounted branding that is hidden. (#30895)

  • 4629eac: Risk-related reserves now explain why funds may be held and use each hold's actual unlock date instead of the account's standing reserve period. (#30895)

  • 4629eac: Popping a toast when none are showing no longer pauses before it appears. (#30895)

  • 4629eac: When a send is blocked because the account still needs identity verification, the send element now opens verification instead of showing a raw whop.com/verify-identity URL under Confirm. (#30895)

  • 4629eac: The send element's recipient picker now uses the same side padding as the amount and confirm screens, so the search field, people list, and "Send to" title line up with the modal edges. (#30895)

  • 4629eac: SEPA Debit checkout fields now load reliably when card is also offered, so buyers can enter their bank account details after switching payment methods. (#30895)

  • 4629eac: Show the originating action on platform fee activity rows and in the Activity Detail Element. (#30895)

  • 4629eac: Fixed Send to choose fiat or crypto from the source account. (#30895)

  • 4629eac: Deposit elements now load bank and crypto fees from the account and show them beneath the selected funding method. (#30895)

  • 4629eac: Added a centered receipt pictogram, high-contrast message, and blue Verify action when Cards needs verification. Unverified bank deposits now label their primary action “Verify identity.” (#30895)

  • 4629eac: font-family declarations in appearance.classes now apply — font name lists like Georgia, 'Times New Roman', serif are accepted, quoted or unquoted. The font shorthand is no longer an accepted property; use the font-family, font-size, font-weight, and font-style longhands. (#30895)

  • 4629eac: Google Pay is offered on merchants' own verified domains, beside Apple Pay. The express checkout and paymentRequest docs now state that both wallets need the page's domain verified as a payment method domain, and link the Google Pay API Terms of Service that offering Google Pay on your site accepts. (#30895)

  • 4629eac: Fixed toasts collapsing into a thin one-character-wide strip on embedding pages. (#30895)

  • 4629eac: The checkout element now sells password-protected plans — the form asks for the password when the plan requires one — and collects the buyer’s phone number when the seller has phone collection turned on. (#30895)

  • 4629eac: Send, Deposit, Withdraw, Capabilities, Payments, and Payment Details show static labels and controls immediately, with one consistent set of placeholders until their initial data is ready. (#30895)

  • 4629eac: Address autocomplete on the street field: the suggestions box opens as you type — with an "Enter address manually" option always available, even when nothing matches — and dismissing it reveals the remaining address fields. (#30895)

  • 4629eac: Send transfers can now include an optional note, which appears as a memo in transfer activity details. (#30895)

  • 4629eac: Cashback activity now uses a green gift icon, matching airdrops. (#30895)

  • 4629eac: Wallet sheets inside the embedded checkout and express-checkout elements now judge the page framing them instead of the element frame: Apple Pay validates the top-level page, and Google Pay can run on a merchant domain verified as a payment method domain through Whop's registration once enabled for the account. (#30895)

  • 4629eac: Secure card fields now follow live theme changes: updating the appearance after mount restyles the hosted card number, expiration, and security code inputs, which previously kept their mount-time colors. (#30895)

  • 4629eac: The events and people tables now resolve the Today and Yesterday periods as full days in the handle's timezone choice, the same way the reporting chart does. Before, the tables bucketed these presets as UTC days, so a table could show a different count than the chart beside it for the same period. The events table's Time column also renders in that timezone now, so the rows visibly agree with the window they were selected by. (#30895)

  • 4629eac: CardsElement now loads a personal wallet's cards — mounting it with a user_ account was refused outright instead of listing the viewer's own cards. (#30895)

  • 4629eac: The verification banner now paints a skeleton while it reads the account, and holds its ready signal until it has something to show. Previously it reported ready on an empty first paint, so a host that swapped its own placeholder on onReady uncovered a blank space a moment before the banner arrived. (#30895)

  • 4629eac: Verify live now follows a funnel across domains. When a form post or redirect carries the walk onto another domain — a WebinarJam registration landing on its thank-you page, a booking tool's confirmation page — the tracking overlay used to vanish there even with the pixel installed, because only link clicks carried the walk across. The wizard now hands the walk to the new page itself, so the overlay and the event list keep going.

    It also explains the overlay's remaining disappearing acts before they happen. On a Shopify store it says the overlay vanishes inside Shopify's checkout — Shopify sandboxes its checkout, so that's expected rather than a broken install — and links the Shopify setup guide, whose custom pixel keeps reporting checkout events. On a funnel that books through iClosed it says the overlay must survive the post-booking redirect, and links the iClosed setup guide when the confirmation page needs the pixel. (#30895)

  • 4629eac: The wallet actions row stays readable on narrow screens: each action stacks its icon above its label instead of letting the labels run into the buttons beside them. (#30895)

  • 4629eac: Fixed crypto balance icons in ActivityDetailElement so swaps render correctly when embedded outside whop.com. (#30895)

  • 4629eac: The wallet balance chart keeps its line and end-dot inside the chart box, so a spike no longer sits on the 1D/1W/1M/1Y/ALL range pills. Those pills are optically centered, and the cards list uses the same 24px corner and padding as the balances list. (#30895)

  • 4629eac: Show the parent account's configured fee before confirming an internal transfer or crypto conversion. (#30895)

  • 4629eac: Wallet settlement details now replace blocked in-transit and undated balances with one actionable identity-verification or information-request row instead of saying the funds are still settling. (#30895)

  • 4629eac: The checkout element shows payment method fields only when the checkout actually collects a payment method. A free plan or a free waitlist renders no payment form at all and completes without one; paid waitlists save the payment method so the seller can charge it if they accept the request; $0-due-today trials with a paid renewal collect one. (#30895)

  • 4629eac: Elements hidden while a group-level fallback is showing stay fully laid out (invisible and inert). Payment fields and other measurement-sensitive content initialize against their real dimensions while hidden, and reveal without a size pop. (#30895)

  • 4629eac: Bank transfer instructions show the receiving bank's code on its own copyable row, under the name its own rail gives it, instead of appending it to the bank name. US bank wires now carry the receiving bank's SWIFT/BIC for buyers sending from abroad. (#30895)

  • 4629eac: Bank wire payment instructions now show the receiving bank's routing number and address alongside its name and account number, so buyers have the full details needed to complete a transfer. (#30895)

  • 4629eac: The withdraw element no longer opens on an instant payout method when instant delivery has no available balance. It now picks the opening method and delivery speed from what the saved methods support and what the live limits allow, so an account whose funds are only withdrawable at standard speed lands on a standard method instead of on "You don't have an available balance to withdraw instantly". (#30895)

  • 4629eac: The deposit and withdraw amount fields no longer stop accepting digits partway through a large amount. Both rejected anything above 9,999,999, which is a rule about US dollars: an account holding a balance of COP 12,430,560 could not type its own balance, and neither could it reach it with MAX. The ceiling is now a limit on how many digits an amount may have rather than on how much it is worth. In withdraw, what a payer may actually move is still bounded by the available balance and the payout method's limits, which say so in words instead of silently swallowing a keystroke; deposit has no such balance to check against, so its amount is bounded server-side when the charge is made.

    The fields also accept a third decimal place for the currencies that have one, such as BHD, and never fewer than two for any currency. Long amounts shrink to stay on screen rather than running past the edge of the sheet. (#30895)

  • 4629eac: The withdraw payout method list shows a separate choice for every currency a method can deliver, so a bank wire that settles in either USD or EUR appears as distinct USD and EUR rows instead of looking EUR-only. Searching by currency returns the matching choices, and selecting one carries that currency into the payout details form. The wallet demo now includes such a multi-currency wire. (#30895)

  • 4629eac: The withdraw element no longer says "You are currently unable to withdraw" when the payout cap is zero. It now uses the payout limit's own reason when the API sends one, explains that pending funds are not withdrawable yet when that is the case, and otherwise says there is no available balance. (#30895)

  • 4629eac: When a withdrawal is held for review because the account has an open information request, the activity detail drawer now shows that request with its button, instead of telling the payer nothing is needed from them. (#30895)