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 tools

Build two-step confirmationLegacy

Add an optional review page or run validations after a user enters their payment details.

Warning

You’re currently viewing an unsupported implementation. If you’re using an older integration with createPaymentMethod, we recommend you use our latest docs to Build two-step confirmation and Migrate to Confirmation Tokens.

While we recommend the standard integration for most scenarios, this integration allows you to add an extra step in your checkout. This provides the buyer an opportunity to review their order details or for you to run additional validations before confirming the order.

Set up Stripe

First, you need a Stripe account. Register now.

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

Command Line
Ruby
# Available as a gem sudo gem install stripe
Gemfile
Ruby
# 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/v3/"></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', paymentMethodCreation: 'manual', // 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

OptionalCustomize the appearance
Client-side

OptionalSave and retrieve customer payment methods

OptionalAdditional Elements options
Client-side

Create a PaymentMethod
Client-side

When the customer submits your payment form, you can create a PaymentMethod to send to your server for additional validation or business logic prior to confirmation.

Caution

You must immediately use a created PaymentMethod to confirm a PaymentIntent or SetupIntent and attach it to a Customer if you intend to use it in the future.

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 PaymentMethod using the details collected by the Payment Element const {error, paymentMethod} = await stripe.createPaymentMethod({ elements, params: { billing_details: { name: 'Jenny Rosen', } } }); if (error) { // This point is only reached if there's an immediate error when // creating the PaymentMethod. Show the error to your customer (for example, payment details incomplete) handleError(error); return; } // Now that you have a PaymentMethod, you can use it in the following steps to render a confirmation page or run additional validations on the server });

Show the payment method details on the confirmation page

At this point, you have all of the information you need to render the confirmation page. Call the server to obtain the necessary information and render the confirmation page accordingly.

server.js
Node
// Using Express const express = require('express'); const app = express(); app.use(express.json()); app.post('/summarize-payment', async (req, res) => { try { let details; if (request.body.payment_method_id) { const intent = await stripe.paymentIntents.create({ payment_method: request.body.payment_method_id, amount: 1099, currency: 'usd', // 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}, { expand: ['payment_method'] } }); details = summarizePaymentMethod(intent.payment_method); } // Send the response to the client response.send(generateResponse(details)); } catch (e) { // Display error on client return response.send({ error: e.message }); } }); function summarizePaymentMethod(paymentMethod) { // Use paymentMethod.type to derive the applicable summary fields for your UI }
confirmation.js
JavaScript
const fetchAndRenderSummary = async () => { const res = await fetch('/summarize-payment', { method: "POST", body: JSON.stringify({ payment_method_id: '{PAYMENT_METHOD_ID}' }); }); const summary = await res.json(); // Render the summary object returned by your server };

Submit the payment to Stripe

When your user confirms their order, use stripe.confirmPayment to complete the payment with the details they entered into the Payment Element. Provide a return_url to this function to indicate where Stripe needs to redirect the user after they complete the payment. Your user might be redirected to an intermediate site first (such as 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, set redirect to if_required. This only redirects customers that check out with redirect-based payment methods.

checkout-confirmation.js
JavaScript
const form = document.getElementById('payment-form'); form.addEventListener('submit', async (event) => { event.preventDefault(); const {error} = await stripe.confirmPayment({ clientSecret: '{PAYMENT_INTENT_CLIENT_SECRET}', confirmParams: { return_url: 'https://example.com/order/123/complete', }, }); if (error) { // This point will only be reached if there is an immediate error when // confirming the payment. Show error to your customer. const messageContainer = document.querySelector('#error-message'); messageContainer.textContent = error.message; } else { // Your customer will be redirected to your `return_url`. For some payment // methods like iDEAL, your customer will be redirected to an intermediate // site first to authorize the payment, then redirected to the `return_url`. } });

Disclose Stripe to your customers

Stripe collects information on customer interactions with Elements to provide services to you, prevent fraud, and improve its services. This includes using cookies and IP addresses to identify which Elements a customer saw during a single checkout session. You’re responsible for disclosing and obtaining all rights and consents necessary for Stripe to use data in these ways. For more information, visit our privacy center.

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