Finalize payments on the server
The Payment Element allows you to accept multiple payment methods using a single integration. In this integration, you’ll build a custom payment flow where you render the Payment Element, create the PaymentIntent, and confirm the payment from your server.
Set up StripeServer-side
First, register for a Stripe account and then use the Dashboard to create an account name. You can always edit your account name later.
Use our official libraries to access the Stripe API from your application:
Enable payment methods
Stripe doesn’t currently support BLIK for this integration path, and US bank account support is in limited beta. For access to US bank account payments, contact us
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 integration options for product and payment method support, and our pricing page for fees.
Collect payment detailsClient-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 the payment information to Stripe over an HTTPS connection. The checkout page address must also start with https://
rather than http://
for your integration to work.
You can test your integration without using HTTPS. Enable it when you’re ready to accept live payments.
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.
By default, the Payment Element only collects the necessary billing address details. If you need to collect a customer’s full billing address (for example, for calculating the tax for digital goods and services) use the Address Element in billing mode.
Create the PaymentMethodClient-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.
A created PaymentMethod must be immediately used to confirm a PaymentIntent and attached to a Customer if intended for future use.
const form = document.getElementById('payment-form'); const handleError = (error) => { const messageContainer = document.querySelector('#error-message'); messageContainer.textContent = error.message; } form.addEventListener('submit', async (event) => { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); // 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; } // Create the PaymentIntent const res = await fetch("/create-confirm-intent", { method: "POST", headers: {"Content-Type": "application/json"}, body: paymentMethod.id, }); const data = await res.json(); // Handle any next actions or errors. See the Handle any next actions step for implementation. handleServerResponse(data); });
Handle any next actionsClient-side
When the PaymentIntent requires additional action from the customer, such as authenticating with 3D Secure or redirecting to a different site, you need to trigger those actions.
Use stripe.handleNextAction
to trigger the UI for handling customer action and completing the payment.
Create and submit the payment to StripeServer-side
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
, currency
, and automatic_payment_methods
enabled. Always decide how much to charge on the server-side, a trusted environment, as opposed to the client-side. This prevents malicious customers from choosing their own prices.
You can use the PaymentMethod sent by your client to create and confirm the PaymentIntent in a single request.
When confirming a PaymentIntent from the server, pass mandate_data
to acknowledge that you’ve shown the customer the proper terms for collecting their payment details. To make sure you display the proper terms, all Elements options should match your Intent options (for example,setup_future_usage
, amount
, and currency
).
When using Afterpay, mandate_data
must be omitted.
const stripe = require("stripe")(
); const express = require('express'); const app = express(); app.set('trust proxy', true); app.use(express.static(".")); app.post('/create-confirm-intent', async (req, res) => { try { const intent = await stripe.paymentIntents.create({ confirm: true, amount: 1099, currency: 'usd', automatic_payment_methods: {enabled: true}, payment_method: req.body, // the PaymentMethod ID sent by your client return_url: 'https://example.com/order/123/complete', mandate_data: { customer_acceptance: { type: "online", online: { ip_address: req.ip, user_agent: req.get("user-agent"), }, }, }, }); res.json({ client_secret: intent.client_secret, status: intent.status }); } catch (err) { res.json({ error: err }) } }); app.listen(3000, () => { console.log('Running on port 3000'); });"sk_test_4eC39HqLyjWDarjtT1zdp7dc"