clientSecret to the
page; the SDK does the rest. You keep full control of the surrounding checkout
UI, including the email, name, and billing-address fields. Requires React 18
or 19.
Overview
- Your server calls
POST /payments/payment-intentand returns theclientSecretto the browser. The secret is scoped to that one intent and is only issued on the create response; the SDK uses it both to load the intent and to confirm the payment on the buyer’s behalf. - Wrap your checkout in
<PaymentProvider clientSecret={...}>, render<PaymentElement />where the payment-method form should appear, and render the required<BrandingElement />. - Collect email, name, and billing address in your own fields, then call
confirm()fromusePaymentElements(). - Treat the result as “the buyer is done”, not “the payment settled”. Fulfill
from your server when the intent’s
statusbecomessucceeded, via thepayments.payment_intent.updatedwebhook.
Components
<PaymentProvider>
Loads the payment intent for the given clientSecret and provides state to
everything inside it. Render one provider per payment intent.
The provider is safe to render on the server: it emits non-interactive
placeholders until it runs in the browser.
<PaymentElement>
The payment-method form. Renders the card input and any wallets enabled for
your account. Billing details are not collected here; you own those fields
and pass them to confirm(). The element reports its completeness to the
provider, which drives canConfirm.
<BrandingElement>
Renders the required payment-processing attribution.
React hooks
usePaymentElements()
Returns the current PaymentInitializationState. Must be called inside a
<PaymentProvider>. The state is a discriminated union on state:
In the
'ready' state:
canConfirm: boolean—trueonce the buyer has filled in a complete payment method. Bind your pay button’sdisabledto!canConfirm.confirm(input): Promise<PaymentResult>— see Static methods.fetchUpdates(): Promise<void>— see Static methods.
Static methods
Available on the'ready' state returned by usePaymentElements().
confirm()
Tokenizes the payment method, confirms the intent, and runs any buyer step
(such as 3-D Secure) inline. Resolves to a PaymentResult
once the buyer is done or the attempt failed.
Takes a single object with the buyer details you collected. Missing or
malformed fields are rejected before any network call with a
validation_error listing each offending field.
string
required
Buyer’s email.
string
required
Buyer’s name as it appears on the card.
object
required
Billing address for the payment method.
string
https:// URL the buyer is sent back to if a payment method requires a
full-page redirect. Provide it if you enable wallets or redirect-based
methods.fetchUpdates()
Reloads the intent’s current amount, currency, and allowed payment methods.
Call it after your server changes the intent (for example after applying a
discount) so the form reflects the new amount, and after a
payment_intent_updated error before asking the buyer to confirm again.
Overlapping calls share one request.
Results and errors
PaymentResult
confirm() never throws for payment outcomes; it resolves to exactly one of:
Repeated
confirm() calls for the same intent while one is in flight share the
same pending promise.
PaymentError
Initialization errors
WhenusePaymentElements() returns state: 'error', error is a
PaymentInitializationError:
Full example
Gotchas
processingis not success. Confirmation resolving means the buyer’s part is over. Settlement happens asynchronously; the only signal to fulfill on is the intent’sstatusreachingsucceeded, read from your server. Never grant goods or services based on a browser-side result alone.- Declines are retryable in place. A
payment_method_declinedresult returns the intent topending, so the buyer can enter another card andconfirm()again without a new intent. - After an
api_error, check before retrying. The attempt may still hold the intent’s processing lock. Read the intent from your server; if it ispending, the buyer can retry. - Redirect-based methods. If the payment method sends the buyer to another
page,
confirm()resolvesprocessingat the moment of handoff and the buyer returns toreturnUrl. Treat that landing page like any other post-checkout page: wait for the webhook. - One intent per provider. To switch intents, render a new
<PaymentProvider>with the newclientSecret; state does not carry over.