Skip to content
Create account
or
Sign in
The Stripe Docs logo
/
Ask AI
Create account
Sign in
Get started
Payments
Revenue
Platforms and marketplaces
Money management
Developer resources
Overview
About Stripe payments
Upgrade your integration
Payments analytics
Online payments
OverviewFind your use caseManaged Payments
Use Payment Links
Build a checkout page
Build an advanced integration
Build an in-app integration
Payment methods
Add payment methods
Manage payment methods
Faster checkout with Link
Payment interfaces
Payment Links
Checkout
Web Elements
In-app Elements
Payment scenarios
Handle multiple currencies
Custom payment flows
    Overview
    Payments for existing customers
    Authorize and capture a payment separately
    Build a two-step checkout flow
    Collect payment details before creating an Intent
    Finalize payments on the server
    Take mail orders and telephone orders (MOTO)
    US and Canadian cards
    Forward card details to third-party API endpoints
    Payments line items
Flexible acquiring
Orchestration
In-person payments
Terminal
Beyond payments
Incorporate your company
Crypto
Financial Connections
Climate
Understand fraud
Radar fraud protection
Manage disputes
Verify identities
HomePaymentsCustom payment flows

Collect payment details before creating an Intent

Build an integration where you can render the Payment Element prior to creating a PaymentIntent or SetupIntent.

The Payment Element allows you to accept multiple payment methods using a single integration. In this integration, learn how to build a custom payment flow where you render the Payment Element, create the PaymentIntent, and confirm the payment from the buyer’s browser. If you prefer to confirm the payment from the server instead, see Finalize payments on the server.

Set up Stripe
Server-side

First, create a Stripe account or sign in.

Use our official libraries to access the Stripe API from your application:

Command Line
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
# Available as a gem sudo gem install stripe
Gemfile
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
# If you use bundler, you can add this line to your Gemfile gem 'stripe'

Enable payment methods

Caution

This integration path doesn’t support BLIK or pre-authorized debits that use the Automated Clearing Settlement System (ACSS).

View your payment methods settings and enable the payment methods you want to support. You need at least one payment method enabled to create a PaymentIntent.

By default, Stripe enables cards and other prevalent payment methods that can help you reach more customers, but we recommend turning on additional payment methods that are relevant for your business and customers. See Payment method support for product and payment method support, and our pricing page for fees.

Collect payment details
Client-side

You’re ready to collect payment details on the client with the Payment Element. The Payment Element is a prebuilt UI component that simplifies collecting payment details for a variety of payment methods.

The Payment Element contains an iframe that securely sends payment information to Stripe over an HTTPS connection. Avoid placing the Payment Element within another iframe because some payment methods require redirecting to another page for payment confirmation.

The checkout page address must start with https:// rather than http:// for your integration to work. You can test your integration without using HTTPS, but remember to enable it when you’re ready to accept live payments.

Set up Stripe.js

The Payment Element is automatically available as a feature of Stripe.js. Include the Stripe.js script on your checkout page by adding it to the head of your HTML file. Always load Stripe.js directly from js.stripe.com to remain PCI compliant. Don’t include the script in a bundle or host a copy of it yourself.

checkout.html
<head> <title>Checkout</title> <script src="https://js.stripe.com/basil/stripe.js"></script> </head>

Create an instance of Stripe with the following JavaScript on your checkout page:

checkout.js
// Set your publishable key: remember to change this to your live publishable key in production // See your keys here: https://dashboard.stripe.com/apikeys const stripe = Stripe(
'pk_test_TYooMQauvdEDq54NiTphI7jx'
);

Add the Payment Element to your checkout page

The Payment Element needs a place to live on your checkout page. Create an empty DOM node (container) with a unique ID in your payment form:

checkout.html
<form id="payment-form"> <div id="payment-element"> <!-- Elements will create form elements here --> </div> <button id="submit">Submit</button> <div id="error-message"> <!-- Display error message to your customers here --> </div> </form>

When the form above has loaded, create an Elements instance with the mode, amount, and currency. These values determine which payment methods are shown to your customer.

Then, create an instance of the Payment Element and mount it to the container DOM node.

checkout.js
const options = { mode: 'payment', amount: 1099, currency: 'usd', // Fully customizable with appearance API. appearance: {/*...*/}, }; // Set up Stripe.js and Elements to use in checkout form const elements = stripe.elements(options); // Create and mount the Payment Element const paymentElementOptions = { layout: 'accordion'}; const paymentElement = elements.create('payment', paymentElementOptions); paymentElement.mount('#payment-element');

The Payment Element renders a dynamic form that allows your customer to pick a payment method. The form automatically collects all necessary payments details for the payment method selected by the customer.

You can customize the Payment Element to match the design of your site by passing the appearance object into options when creating the Elements provider.

Collect addresses

By default, the Payment Element only collects the necessary billing address details. To collect a customer’s full billing address (to calculate the tax for digital goods and services, for example) or shipping address, use the Address Element.

OptionalCustomize the layout
Client-side

You can customize the Payment Element’s layout (accordion or tabs) to fit your checkout interface. For more information about each of the properties, see elements.create.

You can start using the layout features by passing a layout type and other optional properties when creating the Payment Element:

const paymentElement = elements.create('payment', { layout: { type: 'accordion', defaultCollapsed: false, radios: true, spacedAccordionItems: false } });

The following image is the same Payment Element rendered using different layout configurations:

Three checkout form experiences

Payment Element layouts

OptionalCustomize the appearance
Client-side

Now that you’ve added the Payment Element to your page, you can customize its appearance to make it fit your design. To learn more about customizing the Payment Element, see Elements Appearance API.

Customize the Payment Element

Customize the Payment Element

OptionalSave and retrieve customer payment methods

You can configure the Payment Element to save your customer’s payment methods for future use. This section shows you how to integrate the saved payment methods feature, which enables the Payment Element to:

  • Prompt buyers for consent to save a payment method
  • Save payment methods when buyers provide consent
  • Display saved payment methods to buyers for future purchases
  • Automatically update lost or expired cards when buyers replace them
The Payment Element and a saved payment method checkbox

Save payment methods.

The Payment Element with a Saved payment method selected

Reuse a previously saved payment method.

Enable saving the payment method in the Payment Element

Create a CustomerSession on your server by providing the Customer ID and enabling the payment_element component for your session. Configure which saved payment method features you want to enable. For instance, enabling payment_method_save displays a checkbox that allows customers to save their payment details for future use.

You can specify setup_future_usage on a PaymentIntent or Checkout Session to override the default behavior for saving payment methods. This ensures that you automatically save the payment method for future use, even if the customer doesn’t explicitly choose to save it.

Caution

Allowing buyers to remove their saved payment methods by enabling payment_method_remove impacts subscriptions that depend on that payment method. Removing the payment method detaches the PaymentMethod from that Customer.

server.rb
Ruby
Python
PHP
Node.js
Java
Go
.NET
No results
# Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key =
'sk_test_BQokikJOvBiI2HlWgH4olfQ2'
post '/create-customer-session' do customer_session = Stripe::CustomerSession.create({ customer:
{{CUSTOMER_ID}}
, components: { payment_element: { enabled: true, features: { payment_method_redisplay: 'enabled', payment_method_save: 'enabled', payment_method_save_usage: 'off_session', payment_method_remove: 'enabled', }, }, }, }) { customer_session_client_secret: customer_session.client_secret }.to_json end

Your Elements instance uses the CustomerSession’s client secret to access that customer’s saved payment methods. Handle errors properly when you create the CustomerSession. If an error occurs, you don’t need to provide the CustomerSession client secret to the Elements instance, as it’s optional.

Create the Elements instance using the CustomerSession client secret. Then, use the Elements instance to create a Payment Element.

checkout.js
// Create the CustomerSession and obtain its clientSecret const res = await fetch("/create-customer-session", { method: "POST" }); const { customer_session_client_secret: customerSessionClientSecret } = await res.json(); const elementsOptions = { mode: 'payment', amount: 1099, currency: 'usd', customerSessionClientSecret, // Fully customizable with appearance API. appearance: {/*...*/}, }; // Set up Stripe.js and Elements to use in checkout form, passing the client secret // and CustomerSession's client secret obtained in a previous step const elements = stripe.elements(elementsOptions); // Create and mount the Payment Element const paymentElementOptions = { layout: 'accordion'}; const paymentElement = elements.create('payment', paymentElementOptions); paymentElement.mount('#payment-element');

When confirming the PaymentIntent, Stripe.js automatically controls setting setup_future_usage on the PaymentIntent and allow_redisplay on the PaymentMethod, depending on whether the customer checked the box to save their payment details.

Enforce CVC recollection

Optionally, specify require_cvc_recollection both when creating the PaymentIntent and when creating Elements to enforce CVC recollection when a customer is paying with a card.

Detect the selection of a saved payment method

To control dynamic content when a saved payment method is selected, listen to the Payment Element change event, which is populated with the selected payment method.

checkout.js
paymentElement.on('change', function(event) { if (event.value.payment_method) { // Control dynamic content if a saved payment method is selected } })

OptionalDynamically update payment details
Client-side

As the customer performs actions that change the payment details (for example, applying a discount code), update the Elements instance to reflect the new values. Some payment methods, like Apple Pay and Google Pay, show the amount in the UI, so make sure it’s always accurate and up to date.

checkout.js
async function handleDiscountCode(code) { // On the server, validate that the discount code is valid and return the new amount const {newAmount} = await fetch("/apply-discount", { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({code}), }); elements.update({amount: newAmount}); }

OptionalAdditional Elements options
Client-side

The Elements object accepts additional options that influence payment collection. Based on the options provided, the Payment Element displays available payment methods from those you’ve enabled. Learn more about payment method support.

PropertyTypeDescriptionRequired
mode
  • payment
  • setup
  • subscription
Indicates whether the Payment Element is used with a PaymentIntent, SetupIntent, or Subscription.Yes
currencystringThe currency of the amount to charge the customer.Yes
amountnumberThe amount to charge the customer, shown in Apple Pay, Google Pay, or BNPL UIs.For payment and subscription mode
setupFutureUsage
  • off_session
  • on_session
Indicates that you intend to make future payments with the payment details collected by the Payment Element. No
captureMethod
  • automatic
  • automatic_async
  • manual
Controls when to capture the funds from the customer’s account.No
onBehalfOfstringConnect only. The Stripe account ID, which is the business of record. See use cases to determine if this option is relevant for your integration.No
paymentMethodTypesstring[]A list of payment method types to render. You can omit this attribute to manage your payment methods in the Stripe Dashboard.No
paymentMethodConfigurationstringThe payment method configuration to use when managing your payment methods in the Stripe Dashboard. If not specified, your default configuration is used.No
paymentMethodCreationmanualAllows PaymentMethods to be created from the Elements instance using stripe.createPaymentMethod.No
paymentMethodOptions{us_bank_account: {verification_method: string}}Verification options for the us_bank_account payment method. Accepts the same verification methods as Payment Intents.No
paymentMethodOptions{card: {installments: {enabled: boolean}}}Allows manually enabling the card installment plan selection UI if applicable when you aren’t managing your payment methods in the Stripe Dashboard. You must set mode='payment' and explicitly specify paymentMethodTypes. Otherwise an error is raised. Incompatible with paymentMethodCreation='manual'.No

OptionalCreate a ConfirmationToken

If you want to build a multi-page checkout or collect payment method details before running additional validations, see Build a two-step checkout flow. With this flow, you create a ConfirmationToken on the client to collect payment details and then use it to create a PaymentIntent on the server.

Create a PaymentIntent
Server-side

Run custom business logic immediately before payment confirmation

Navigate to step 5 in the finalize payments guide to run your custom business logic immediately before payment confirmation. Otherwise, follow the steps below for a simpler integration, which uses stripe.confirmPayment on the client to both confirm the payment and handle any next actions.

When the customer submits your payment form, use a PaymentIntent to facilitate the confirmation and payment process. Create a PaymentIntent on your server with an amount and currency enabled. In the latest version of the API, specifying the automatic_payment_methods parameter is optional because Stripe enables its functionality by default. You can manage payment methods from the Dashboard. Stripe handles the return of eligible payment methods based on factors such as the transaction’s amount, currency, and payment flow. To prevent malicious customers from choosing their own prices, always decide how much to charge on the server-side (a trusted environment) and not the client.

Included on a PaymentIntent is a client secret. Return this value to your client for Stripe.js to use to securely complete the payment process.

main.rb
Ruby
Python
PHP
Node.js
Java
Go
.NET
No results
require 'stripe' Stripe.api_key =
'sk_test_BQokikJOvBiI2HlWgH4olfQ2'
post '/create-intent' do intent = Stripe::PaymentIntent.create({ # To allow saving and retrieving payment methods, provide the Customer ID. customer: customer.id, # In the latest version of the API, specifying the `automatic_payment_methods` parameter is optional because Stripe enables its functionality by default. automatic_payment_methods: {enabled: true}, amount: 1099, currency: 'usd', }) {client_secret: intent.client_secret}.to_json end

Submit the payment to Stripe
Client-side

Use stripe.confirmPayment to complete the payment using details from the Payment Element.

Provide a return_url to this function to indicate where Stripe should redirect the user after they complete the payment. Your user might be initially redirected to an intermediate site, like a bank authorization page, before being redirected to the return_url. Card payments immediately redirect to the return_url when a payment is successful.

If you don’t want to redirect for card payments after payment completion, you can set redirect to if_required. This only redirects customers that check out with redirect-based payment methods.

checkout.js
const form = document.getElementById('payment-form'); const submitBtn = document.getElementById('submit'); const handleError = (error) => { const messageContainer = document.querySelector('#error-message'); messageContainer.textContent = error.message; submitBtn.disabled = false; } form.addEventListener('submit', async (event) => { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); // Prevent multiple form submissions if (submitBtn.disabled) { return; } // Disable form submission while loading submitBtn.disabled = true; // Trigger form validation and wallet collection const {error: submitError} = await elements.submit(); if (submitError) { handleError(submitError); return; } // Create the PaymentIntent and obtain clientSecret const res = await fetch("/create-intent", { method: "POST", }); const {client_secret: clientSecret} = await res.json(); // Confirm the PaymentIntent using the details collected by the Payment Element const {error} = await stripe.confirmPayment({ elements, clientSecret, confirmParams: { return_url: 'https://example.com/order/123/complete', }, }); if (error) { // This point is only reached if there's an immediate error when // confirming the payment. Show the error to your customer (for example, payment details incomplete) handleError(error); } else { // Your customer is redirected to your `return_url`. For some payment // methods like iDEAL, your customer is redirected to an intermediate // site first to authorize the payment, then redirected to the `return_url`. } });

OptionalHandle post-payment events

Stripe sends a payment_intent.succeeded event when the payment completes. Use the Dashboard, a custom webhook, or a partner solution to receive these events and run actions, like sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow.

Listen for these events rather than waiting on a callback from the client. On the client, the customer could close the browser window or quit the app before the callback executes, and malicious clients could manipulate the response. Setting up your integration to listen for asynchronous events also helps you accept more payment methods in the future. Learn about the differences between all supported payment methods.

  • Handle events manually in the Dashboard

    Use the Dashboard to View your test payments in the Dashboard, send email receipts, handle payouts, or retry failed payments.

  • Build a custom webhook

    Build a custom webhook handler to listen for events and build custom asynchronous payment flows. Test and debug your webhook integration locally with the Stripe CLI.

  • Integrate a prebuilt app

    Handle common business events, such as automation or marketing and sales, by integrating a partner application.

See also

  • Design an integration
Was this page helpful?
YesNo
  • Need help? Contact Support.
  • Join our early access program.
  • Check out our changelog.
  • Questions? Contact Sales.
  • LLM? Read llms.txt.
  • Powered by Markdoc