Skip to main content
Mounts inside Payments. Pass props and callbacks through the create options or React props. Keep the created handle, or React ref, to call select().
Exclusive. PaymentElement is an alternative to CardElement or CardFields in this Payments handle. Mount one at a time. Destroy it before mounting another.
Mounts inside a WhopPayments scope. Renders the method tiles the charge offers, then whatever the selected method collects: the card fields, the fields it declares, or the Apple Pay button.
Mount inside <Payments>, which owns the charge and the confirmation token. <Payments> itself mounts inside <WhopElements>. It renders the method tiles for the charge and collects whatever the selected method declares, so a card, a wallet sheet and a bank redirect are the same one line.

Example data. Open the Playground.

Props

string[]
Controls display order in either layout. Listed types appear first in order. Unlisted types retain their relative order. Does not affect availability. Defaults to [].
{ billingDetails?: "full" | "minimal" | "never" | undefined; }
Controls billing-details collection. billingDetails: 'minimal' (default) follows each method’s matrix. Methods collect name and the complete country format by default. An override may collect only the declared minimum or nothing. For cards, the minimum is name on card, country, and postal code. 'full' requires name and the complete country format for every fresh method. 'never' hides the block. Pass the address to createConfirmationToken instead. The country selector includes only countries supported by the method and payment currency. With an installment plan selected, it narrows to the countries the plan serves — the billing country is the transaction country the charge processes under. It locks when only one is available. Defaults to {"billingDetails":"minimal"}.
"accordion" | "horizontal"
Picker layout. accordion (default) stacks methods and expands details inline. horizontal shows equal-width, non-scrolling tiles with selected details below. After four methods, a More tile opens a native selector. The method picked there occupies the final tile until the next selection. Selection and confirmation behave identically. Defaults to "accordion".
boolean
accordion only. Adds spacing and separate card styling between methods. Ignored when layout is horizontal. Defaults to false.
boolean
Whether to select the first offered method after resolution. The default true respects order and emits selected and change like a buyer interaction. It runs once before buyer interaction and does nothing when no method is offered. Set false to mount unselected. Independently, if an update removes the selected method, selection falls back to the first offered method. An already unselected element stays unselected. Defaults to true.

Events

Pass callbacks in the create options or React props.

onChange

Fires when selection changes. complete: true means the buyer selected a method and completed its card fields or required inputs. Use it to enable confirmation. method provides category, per-currency countries, and amount bounds for dependent UI such as country fields. supportsBuyerFee indicates whether to include Whop’s buyer service fee in the displayed total.Signature: ((payload: { complete: boolean; type?: string | undefined; supportsBuyerFee?: boolean | undefined; method?: { type: string; category: string; template: string; display_name: string; countries: ({ country: string; min_amount: number | null; max_amount: number | null; })[]; min_amount: number | null; max_amount: number | null; } | undefined; }) => void)

onAddressChange

Fires about 300 ms after the internal billing address changes. Use it for tax, shipping, or other address-dependent updates. country is an ISO 3166-1 alpha-2 code. The payload omits other address keys when empty or unused for that country. complete: true means the billing block is valid and complete. This event fires only while the payment element owns address collection. With fields.billingDetails: 'never', use your address source. With a mounted AddressElement, use its change event.Signature: ((payload: { complete: boolean; address: { line1?: string | undefined; line2?: string | undefined; city?: string | undefined; state?: string | undefined; postal_code?: string | undefined; country: string; }; }) => void)

onLoaderStart

Runs after the loading skeleton first paints and before onReady.Signature: (() => void)

onReady

Runs after the element’s first complete paint.Signature: (() => void)

onError

Runs when the element fails to load or crashes. The fallback remains visible. Use code for programmatic handling. sourceKey identifies a failed host-state source.Signature: ((e: { message: string; code?: string | undefined; sourceKey?: string | undefined; }) => void)

Methods

Call these on the handle returned by create, or through a React ref.

select

Select a method through the same path as a buyer interaction. For example, select('cashapp') expands the tile and emits selected and change. Cards remain complete: false until their fields are complete. Unknown, unavailable, or amount-gated methods reject with code METHOD_NOT_OFFERED. select(null) clears selection and emits change with complete: false. Use with autoSelect={false} for full external control.Signature: (input: string | null) => Promise<void>

mount

Mounts the element in target and starts loading. React components mount themselves.Signature: (target: string | HTMLElement) => void

destroy

Removes the element and releases its frame and subscriptions. You can call it more than once. React removes the element automatically.Signature: () => void

update

Merges new props into the mounted element. In React, change the component props instead.Signature: (options: Partial<PaymentElementProps>) => void

Styling

Style these parts through appearance.classes. Use camel case or kebab case for property names and include units. Page stylesheets can’t reach the element’s frame. The framework validates each declaration before injecting it.
In React, pass appearance to <Payments>. Set it globally with WhopElements({ appearance }).

Parameters

[WhopPaymentMethodType]
Tile order for this mount, overriding the controller’s methodOrder. Listed types take their list position; the rest keep their incoming order behind them.
Binding<WhopPaymentSelection>?
Reads the current selection and its completeness back out. The controller tracks both either way.

WhopPaymentSelection

What a selection hands back:
  • isComplete: Bool: the selected method has everything it needs
  • type: WhopPaymentMethodType?: the selected method
  • displayName: String?: its label, as the matrix spells it
  • category: String?: card, wallet, bank_debit, …

States

Shows skeleton tiles while the method matrix loads, and the failure message when the read fails. A method whose category this build cannot run is skipped rather than rendered as a broken tile. Selecting a wallet swaps the confirm surface for Apple Pay.

Good to know

  • Apple Pay needs nothing from your app: no merchant identifier, no In-App Payments capability. The merchant is the one registered on the Whop account, and the tile renders whenever the device can pay.
  • A method that declares a secure field renders it as a hosted input. Those values never enter your process.
  • A signed-in buyer’s stored methods appear above the fresh ones. Mount WhopEmailElement to offer the sign-in that produces the credential; picking a stored row collects nothing and mints a reference.
  • A card charge that publishes installment tiers shows a plan picker inside the card pane. A plan the buyer’s card cannot take collapses rather than dimming, and a plan whose region does not pair with the billing country is refused before any tokenizer runs.
  • A market that requires an identity document (an ars charge, today) renders the type picker and number field inside the pane. That number passes through your app on its way to the tokenizer, unlike the card, and still never reaches Whop.
  • Card and secure-field values are tokenized before the mint, so the confirmation token is the only thing that crosses your app.
  • Mount WhopAddressElement beside it when a method needs a billing country: the tile list narrows to the methods that country allows.

Install

Mount it inside a WhopPayments(accountID:charge:) scope, which creates the controller and hands it to its content. payments.buyer is the signed-in buyer once an email sign-in has proven one. WhopBrandingElement has to be on screen too, because Whop is merchant of record on these sales and createConfirmationToken refuses without it. Style with .whopElementsAppearance(_:). The module is Elements, not the wallet SDK’s WhopElements. See Getting started and Appearance.

Props

string[]
Method display order, with Stripe’s paymentMethodOrder semantics. Unlisted types keep their incoming relative order behind the listed ones. Also settable once on <Payments>.
(payload: PaymentChangePayload) => void
Fires on every selection and completeness change. Gate your submit button on complete.
StyleProp<ViewStyle>
Applied to the element’s outer View. For theming, prefer appearance.parts on the provider, which covers every element on this surface. Note the React Native part names are their own set today, not the web’s whop-* class names, so a web appearance object does not port across unchanged.
ReactNode
Rendered instead of the built-in skeleton while the element loads.
() => void
Fires once the element is interactive. <Payments> groups these, so its own onLoadingChange is usually the one you want.
(error: { message: string; code?: string }) => void
A load or configuration failure for this element. The element renders its own error face either way.

PaymentChangePayload

What onChange hands back:
  • complete: boolean: the selected method has everything it needs
  • type?: string: the selected method type, e.g. card
  • method?: { type, category, template, display_name }: the selected method’s matrix entry

States

Three skeleton rows until the method matrix lands, then the tiles. Selecting a tile expands its detail region beneath it. onChange reports complete when the selected method has everything it needs, which is what gates your submit button. A charge with no eligible method renders an explanatory empty state rather than nothing.

Good to know

  • Card numbers never pass through your code. The fields are PCI-isolated native inputs, and the SDK hands Whop a token, so your app stays out of PCI scope.
  • Apple Pay and Google Pay both present the platform’s own sheet. Neither needs anything from you: Apple Pay uses the merchant registered on the Whop account, so there is no merchant identifier to pass and no capability to add in Xcode, and googlePayMerchantName only sets the name shown in the sheet, which defaults to Whop.
  • Redirect methods and 3D Secure open ASWebAuthenticationSession on iOS and Custom Tabs on Android. The system browser, never a WebView, so the issuer’s page stays outside your app’s trust boundary.
  • Set returnUrl on <Payments> to an https URL you host. The API refuses anything but https or loopback (PaymentsApi::ValidateReturnUrl), so a custom app scheme is not available here. You do not register a deep link: after the issuer redirects, handleNextAction polls the payment to rest and closes the browser itself.
Wrap your app in <WhopElements getToken={…}> once, then mount <Payments> around the elements. See Getting started and Appearance.