Upcoming — generated from the latest merged element source; documents unreleased development. Use the channel picker at the top of the sidebar for the docs of a published release.
Playground
Assemble the elements with sample data — drive the controls, add and arrange elements, and watch events fire live:Usage
Options
Pass these towhop.payments.create({ … }) — or as props on <Payments> in React.
string
OPTIONLESS — the statics rail (
WhopElements.payments.handleNextAction) boots the namespace handle with no options; no collection face can be created on such a handle (they refuse loudly — pass a plan or currency+amount to collect).string
An existing plan id (
plan_…) — resolved client-side into the inline shape (currency, amount, method configuration); a plan is a preset for the same one config. Pass a plan OR the inline currency/amount, never both.string
Where the buyer lands after an off-site step (bank page, 3DS). Defaults to the mounting page.
"off_session" | "on_session"
Attest the element should display save-consent and mint vault-capable tokens:
off_session or on_session.string
Advanced: override the API origin (sandbox / staging testing).
string
ISO currency the checkout charges in — filters the method matrix.
number
Charge amount in minor units — methods whose bounds exclude it are not offered.
{ enabled?: string[] | undefined; disabled?: string[] | undefined; include_platform_defaults?: boolean | undefined; }
Seller method filtering in the API’s own shape (
enabled, disabled, include_platform_defaults): disabled types are removed, enabled re-adds against the account’s offered set, and with include_platform_defaults: false only enabled types remain. A plan carries its own.Appearance
Visual customization for this group’s elements — overrides the global
WhopElements({ appearance }); change it live with update({ appearance }).WhopElementsLocale
Locale for this group’s element UI text — one of the app’s built locales, overriding the global config; any other value falls back to the default locale.
The options are a union — provide exactly one of these shapes (plus the shared event callbacks below):
{ accountId: string; plan: string; returnUrl?: string; setupFutureUsage?: "off_session" | "on_session"; apiBaseUrl?: string }{ accountId: string; currency: string; amount: number; paymentMethodConfiguration?: { enabled?: string[] | undefined; disabled?: string[] | undefined; include_platform_defaults?: boolean | undefined; }; returnUrl?: string; setupFutureUsage?: "off_session" | "on_session"; apiBaseUrl?: string }{ accountId?: undefined; plan?: undefined; currency?: undefined; amount?: undefined; paymentMethodConfiguration?: undefined; returnUrl?: string; setupFutureUsage?: "off_session" | "on_session"; apiBaseUrl?: string }
Events
Pass a callback in the create options / React props.onConfirmationToken
A confirmation token was minted (also returned by createConfirmationToken()). Confirm it server-side with your secret key.
Signature: ((payload: { id: string; type: string; }) => void)
onLoadingChange
Fired when the grouped loading state changes — true while any mounted element is still loading.
Signature: ((loading: boolean) => void)
Methods
Call these on the Payments handle — the return ofwhop.payments.create({ … }) (vanilla) or usePayments() (React).
createConfirmationToken
Mint a confirmation token from whatever the buyer selected — the ONE confirm verb, for every face, called from YOUR pay button on the payments handle. A card selection tokenizes inside the mounted face (pass the billing details your checkout collected — email required; card also requires name and address with line1 + country). Returns { confirmationToken, type }; confirm it server-side with your secret key, then call WhopElements.payments.handleNextAction(...). Runs on your page (host-side), not in the controller iframe.
Signature: (input: { billingDetails?: { email?: string | undefined; name?: string | undefined; address?: { country?: string | undefined; line1?: string | undefined; line2?: string | undefined; city?: string | undefined; state?: string | undefined; postal_code?: string | undefined; } | undefined; } | undefined; }) => Promise<{ confirmationToken: string; type: string; }>
update
Update the handle live: any of its options (appearance and locale included), propagated to every mounted element. React consumers never call it — updating the namespace component’s props does the same.
Signature: (options: Partial<PaymentsOptions>) => void
Static methods
Available before anything mounts — call them on the namespace accessor:whop.payments.<method>(…) (vanilla, where whop = WhopElements(…)) or useWhop().payments.<method>(…) (React). Useful when no element is on the page, e.g. handling a post-redirect next action.
handleNextAction
Drive a confirmed payment’s pending step to a resting state with NO element mounted — the universal completion surface. The clientSecret alone identifies the payment — its tag is embedded in the secret, so there is no separate payment id to pass (or mismatch). A frameable step (next_action.render includes inline — 3DS challenges, most wallet/redirect rails) runs in a dismissible dialog on YOUR page and the promise resolves in place with the payment’s fresh status (redirected: false; a dismissed dialog resolves with the still-pending status — re-offer at will). A full-page-only step redirects THIS tab (redirected: true) and the hosted return landing brings the buyer back to your return_url — or parks them on a hosted receipt when you never set one. Pass returnUrl to set or override that destination right here: it’s PATCHed onto the payment under the client_secret before the step runs (the innermost layer of the layered return_url; only a full-page step navigates to it — the dialog resolves in place, and a failed PATCH rejects before any step runs). No pending step resolves immediately. Called as WhopElements.payments.handleNextAction(...).
Signature: (input: { clientSecret: string; apiBaseUrl?: string | undefined; returnUrl?: string | undefined; pollIntervalMs?: number | undefined; }) => Promise<{ status: string; redirected: boolean; lastPaymentError: { code?: string | undefined; decline_code?: string | null | undefined; message?: string | undefined; } | null; }>
Elements
The elements this group mounts — each has its own page:AddressElement
Collects a billing or shipping address with per-country formats — the field set, order, required flags, and postal-code validation adapt to the selected country — plus address autocomplete on the street field. Drive your own forms off
onChange, or call validate() / getValues() on the handle.PaymentElement
The drop-in payment method picker: shows the payment methods this seller accepts for the charge — filtered live by currency, amount, and seller configuration — and collects what the chosen method needs: card fields, billing address, method-specific inputs, and any required disclosures. Drive your pay button off the
change event, call payments.createConfirmationToken() on click, confirm the token server-side with your secret key, then pass any pending step to payments.handleNextAction(...). Two arrangements via layout: a stacked list (default) or a horizontal tile row.CardElement
The drop-in card block: number, expiration, and security code pre-arranged as one field group. Reached through
payments.create("card"); drive your pay button off onChange, then confirm with payments.createConfirmationToken(). Card numbers never touch your page or ours. Two arrangements via layout: ‘stacked’ (default) or ‘compact’ (one row).CardFields
The exploded card unit: three individually mountable, PCI-isolated fields (number, expiration, security code) under one completeness surface — for layouts the drop-in card element can’t express. Reached through
payments.create("cardFields"): place each field yourself, drive your pay button off onChange, confirm with payments.createConfirmationToken(). Card numbers never touch your page or ours. (sub-controller — 3 elements)Flow surfaces
These internal elements open automatically during flows (for example a confirmation or verification step). They are not part of the consumer API — you never mount, configure, or subscribe to them directly.- AddressSuggestionsElement (
addressSuggestions) — The address autocomplete overlay — suggestion rows plus “Enter address manually”, anchored beside the street field. - BillingAddressSuggestionsElement (
billingAddressSuggestions) — The billing address autocomplete overlay — suggestion rows plus “Enter address manually”, anchored beside the billing street field. - CompletePaymentElement (
completePayment) — The hosted completion surfacepayments.handleNextActionpresents as a detached modal: it drives a pending payment step — a framed PSP flow, bank-transfer instructions, a confirmation wait — to a resting state, polling the payment status under its scoped client_secret, and closes itself when the payment rests. Never mounted directly.

