# Accept a payment Securely accept payments online. ## Start here: Install agent skills Stripe recommends using official skills to integrate with the API using best practices. Follow the instructions below to learn how. **Tip: Use curl instead of Fetch tools.** Skills are detailed 10–20 KB markdown files. Fetch tools summarise them. `curl -sL` guarantees the full content. **Using `npx skills`**: Check if `npx` is installed on the system. If `npx` is available, run `npx skills add https://docs.stripe.com --list` to list available skills, then run `npx skills add https://docs.stripe.com --yes --skill <--skill other-skills>` to install individual skills. **If `npx skills` isn’t available**: You can use curl to fetch the index of available skills, what they do, and their files from `https://docs.stripe.com/.well-known/skills/index.json`. To download a skill and its related files, use curl to download them from `https://docs.stripe.com/.well-known/skills/`. For this article, we recommend using these skills: `stripe-best-practices` Instructions for LLMs: Stripe recommends using the Checkout Sessions API with the Payment Element over Payment Intents for most integrations. Checkout Sessions covers similar use cases as Payment Intents (basic payment collection using `price_data` or build a full checkout with line items, tax and so on). Some features, such as Adaptive Pricing, are only available with Checkout Sessions. Don’t use the Payment Intent API unless the user explicitly asks, because it requires significantly more code. Learn more about Elements with the Checkout Sessions API: https://docs.stripe.com/payments/quickstart-checkout-sessions. With Checkout Sessions (`ui_mode: "elements"`) and the Payment Element, the `client_secret` initialises Checkout itself (`stripe.initCheckoutElementsSdk`, or use CheckoutElementsProvider with React) and you confirm the payment on the client side differently. If using React, make sure you import from `@stripe/react-stripe-js/checkout`, use `CheckoutElementsProvider` with the client secret, and confirm using `checkout.confirm`. If using HTML, make sure you use `checkout = stripe.initCheckoutElementsSdk({clientSecret: promise}); checkout.createPaymentElement(); paymentElement = checkout.createPaymentElement(); paymentElement.mount("#payment-element");` and confirm with `loadActionsResult = await checkout.loadActions(); actions = loadActionsResult.actions; error = await actions.confirm();`. Coding agents should install the Stripe CLI (`npm i -g @stripe/cli`) and run the command `stripe sandbox create --help` to provision an anonymous Stripe sandbox with working API keys. No account registration required. Build a payment form or use a prebuilt checkout page to start accepting online payments. # Checkout Sessions API Build a custom payment form using [Stripe Elements](https://docs.stripe.com/payments/elements.md) and the [Checkout Sessions API](https://docs.stripe.com/api/checkout/sessions.md). See how this integration [compares to Stripe’s other integration types](https://docs.stripe.com/payments/online-payments.md#compare-features-and-availability). The Checkout Sessions API provides built-in support for tax calculation, discounts, shipping and currency conversion, reducing the amount of custom code you need to write. This is the recommended approach for most integrations. Learn more about [when to use Checkout Sessions instead of PaymentIntents](https://docs.stripe.com/payments/checkout-sessions-and-payment-intents-comparison.md). The client-side and server-side code builds a checkout form that accepts various payment methods. #### Integration effort Complexity: 3/5 #### Integration type Combine UI components into a custom payment flow #### UI customisation CSS-level customisation with the [Appearance API](https://docs.stripe.com/elements/appearance-api.md) ## Set up the server [Server-side] Before you begin, you need to [register](https://dashboard.stripe.com/register) for a Stripe account. Use the official Stripe libraries to access the API from your application. #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` ## Create a Checkout Session [Server-side] Add an endpoint on your server that creates a [Checkout Session](https://docs.stripe.com/api/checkout/sessions/create.md) and returns its [`client_secret`](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-client_secret) to your front end. A Checkout Session represents your customer’s session as they pay for one-time purchases or subscriptions. Checkout Sessions expire 24 hours after creation. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d ui_mode=elements \ -d "line_items[0][price_data][currency]=usd" \ -d "line_items[0][price_data][product_data][name]=T-shirt" \ -d "line_items[0][price_data][unit_amount]=2000" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ --data-urlencode "return_url=https://example.com/return?session_id={CHECKOUT_SESSION_ID}" ``` ## Set up the front end [Client-side] #### HTML + 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. Make sure you’re using the latest Stripe.js version. Learn more about [Stripe.js versioning](https://docs.stripe.com/sdks/stripejs-versioning.md). ```html Checkout ``` > Stripe provides an npm package that you can use to load Stripe.js as a module. See the [project on GitHub](https://github.com/stripe/stripe-js). Version [7.0.0](https://www.npmjs.com/package/%40stripe/stripe-js/v/7.0.0) or later is required. Initialise stripe.js. ```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( '<>', ); ``` #### React Install [React Stripe.js](https://www.npmjs.com/package/@stripe/react-stripe-js) and the [Stripe.js loader](https://www.npmjs.com/package/@stripe/stripe-js) from the npm public registry. You need at least version 5.0.0 for React Stripe.js and version 8.0.0 for the Stripe.js loader. ```bash npm install --save @stripe/react-stripe-js @stripe/stripe-js ``` Initialise a `stripe` instance on your front end with your publishable key. ```javascript import {loadStripe} from '@stripe/stripe-js'; const stripe = loadStripe("<>"); ``` ## Initialise Checkout [Client-side] #### HTML + JS Call [initCheckoutElementsSdk](https://docs.stripe.com/js/custom_checkout/init), passing in `clientSecret`. `initCheckoutElementsSdk` returns a [Checkout](https://docs.stripe.com/js/custom_checkout) object that contains data from the Checkout Session and methods to update it. Read the `total` and `lineItems` from [actions.getSession()](https://docs.stripe.com/js/custom_checkout/session), and display them in your UI. This lets you turn on new features with minimal code changes. For example, adding [manual currency prices](https://docs.stripe.com/payments/custom/localize-prices/manual-currency-prices.md) requires no UI changes if you display the `total`. ```html
``` ```javascript const clientSecret = fetch('/create-checkout-session', {method: 'POST'}) .then((response) => response.json()) .then((json) => json.client_secret); const checkout = stripe.initCheckoutElementsSdk({clientSecret}); const loadActionsResult = await checkout.loadActions(); if (loadActionsResult.type === 'success') { const session = loadActionsResult.actions.getSession(); const checkoutContainer = document.getElementById('checkout-container'); checkoutContainer.append(JSON.stringify(session.lineItems, null, 2)); checkoutContainer.append(document.createElement('br')); checkoutContainer.append(`Total: ${session.total.total.amount}`); } ``` #### React Wrap your application with the [CheckoutElementsProvider](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider) component, passing in `clientSecret` and the `stripe` instance. ```jsx import React from 'react'; import {CheckoutElementsProvider} from '@stripe/react-stripe-js/checkout'; import CheckoutForm from './CheckoutForm'; const clientSecret = fetch('/create-checkout-session', {method: 'POST'}) .then((response) => response.json()) .then((json) => json.client_secret); const App = () => { return ( ); }; export default App; ``` Access the [Checkout](https://docs.stripe.com/js/custom_checkout) object in your checkout form component by using the `useCheckoutElements()` hook. The `Checkout` object contains data from the Checkout Session and methods to update it. Read the `total` and `lineItems` from the `Checkout` object, and display them in your UI. This lets you enable features with minimal code changes. For example, adding [manual currency prices](https://docs.stripe.com/payments/custom/localize-prices/manual-currency-prices.md) requires no UI changes if you display the `total`. ```jsx import React from 'react'; import {useCheckoutElements} from '@stripe/react-stripe-js/checkout'; const CheckoutForm = () => {const checkoutState = useCheckoutElements(); if (checkoutState.type === 'loading') { return (
Loading...
); } if (checkoutState.type === 'error') { return (
Error: {checkoutState.error.message}
); } return (
{JSON.stringify(checkoutState.checkout.lineItems, null, 2)} {/* A formatted total amount */} Total: {checkoutState.checkout.total.total.amount}
); }; ``` ## Collect customer email address [Client-side] #### HTML + JS You must provide a valid customer email when completing a Checkout Session. Use the [Contact Details Element](https://docs.stripe.com/js/custom_checkout/create_contact_details_element) to collect your customer’s email address. It handles email collection and validation for you, and helps customers sign in to Link. Alternatively, you can: - Pass in [customer_email](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer_email), [customer_account](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer_account) (for customers represented as customer-configured `Account` objects), or [customer](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer) (for customers represented as `Customer` objects) when creating the Checkout Session. Stripe validates emails provided this way. - These prefill the session with an email that customers can’t edit on the checkout page. If you want to prefill with an editable email, use [defaultValues.email](https://docs.stripe.com/js/custom_checkout/init#custom_checkout_init-options-defaultValues-email) when initialising Checkout. - Pass in an email you already validated on [updateEmail](https://docs.stripe.com/js/custom_checkout/update_email) or [checkout.confirm](https://docs.stripe.com/js/custom_checkout/confirm). ```html
``` ```javascript const contactDetailsElement = checkout.createContactDetailsElement(); contactDetailsElement.mount("#contact-details-element"); ``` #### React You must provide a valid customer email when completing a Checkout Session. Use the [ContactDetailsElement](https://docs.stripe.com/js/react_stripe_js/checkout/contact_details_element) to collect your customer’s email address. It handles email collection and validation for you, and helps customers sign in to Link. Alternatively, you can: - Pass in [customer_email](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer_email), [customer_account](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer_account) (for customers represented as customer-configured `Account` objects), or [customer](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer) (for customers represented as `Customer` objects) when creating the Checkout Session. Stripe validates emails provided this way. - These prefill the session with an email that customers can’t edit on the checkout page. If you want to prefill with an editable email, use [defaultValues.email](https://docs.stripe.com/js/custom_checkout/init#custom_checkout_init-options-defaultValues-email) when initialising Checkout. - Pass in an email you already validated on [updateEmail](https://docs.stripe.com/js/react_stripe_js/checkout/update_email) or [confirm](https://docs.stripe.com/js/react_stripe_js/checkout/confirm). ```jsx import {ContactDetailsElement} from '@stripe/react-stripe-js/checkout'; // Inside your CheckoutForm component: ``` ## Collect payment details [Client-side] Collect payment details on the client with the [Payment Element](https://docs.stripe.com/payments/payment-element.md). The Payment Element is a pre-built 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. If you choose to use an iframe and want to accept Apple Pay or Google Pay, the iframe must have the [allow](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-allowpaymentrequest) attribute set to equal `"payment *"`. 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](https://docs.stripe.com/security/guide.md#tls) when you’re ready to accept live payments. #### HTML + JS First, create a container DOM element to mount the [Payment Element](https://docs.stripe.com/payments/payment-element.md). Then create an instance of the `Payment Element` using [checkout.createPaymentElement](https://docs.stripe.com/js/custom_checkout/create_payment_element) and mount it by calling [element.mount](https://docs.stripe.com/js/element/mount), providing either a CSS selector or the container DOM element. ```html
``` ```javascript const paymentElement = checkout.createPaymentElement(); paymentElement.mount('#payment-element'); ``` See the [Stripe.js docs](https://docs.stripe.com/js/custom_checkout/create_payment_element#custom_checkout_create_payment_element-options) to view the supported options. You can [customise the appearance](https://docs.stripe.com/payments/checkout/customization/appearance.md) of all Elements by passing [elementsOptions.appearance](https://docs.stripe.com/js/custom_checkout/init#custom_checkout_init-options-elementsOptions-appearance) when initialising Checkout on the front end. #### React Mount the [Payment Element](https://docs.stripe.com/payments/payment-element.md) component within the [CheckoutElementsProvider](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider). ```jsx import React from 'react';import {PaymentElement, useCheckoutElements} from '@stripe/react-stripe-js/checkout'; const CheckoutForm = () => { const checkoutState = useCheckoutElements(); if (checkoutState.type === 'loading') { return (
Loading...
); } if (checkoutState.type === 'error') { return (
Error: {checkoutState.error.message}
); } return (
{JSON.stringify(checkoutState.checkout.lineItems, null, 2)} {/* A formatted total amount */} Total: {checkoutState.checkout.total.total.amount} ); }; export default CheckoutForm; ``` See the [Stripe.js docs](https://docs.stripe.com/js/custom_checkout/create_payment_element#custom_checkout_create_payment_element-options) to view the supported options. You can [customise the appearance](https://docs.stripe.com/payments/checkout/customization/appearance.md) of all Elements by passing [elementsOptions.appearance](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider#react_checkout_provider-options-elementsOptions-appearance) to the [CheckoutElementsProvider](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider). ## Submit the payment [Client-side] #### HTML + JS Render a **Pay** button that calls [confirm](https://docs.stripe.com/js/custom_checkout/confirm) from the `Checkout` instance to submit the payment. ```html
``` ```js const checkout = stripe.initCheckoutElementsSdk({clientSecret}); checkout.on('change', (session) => { document.getElementById('pay-button').disabled = !session.canConfirm; }); const loadActionsResult = await checkout.loadActions(); if (loadActionsResult.type === 'success') { const {actions} = loadActionsResult; const button = document.getElementById('pay-button'); const errors = document.getElementById('confirm-errors'); button.addEventListener('click', () => { // Clear any validation errors errors.textContent = ''; actions.confirm().then((result) => { if (result.type === 'error') { errors.textContent = result.error.message; } }); }); } ``` #### React Render a **Pay** button that calls [confirm](https://docs.stripe.com/js/custom_checkout/confirm) from [useCheckoutElements](https://docs.stripe.com/js/react_stripe_js/checkout/use_checkout_elements) to submit the payment. ```jsx import React from 'react'; import {useCheckoutElements} from '@stripe/react-stripe-js/checkout'; const PayButton = () => { const checkoutState = useCheckoutElements(); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(null); if (checkoutState.type !== "success") { return null; } const handleClick = () => { setLoading(true);checkoutState.checkout.confirm().then((result) => { if (result.type === 'error') { setError(result.error) } setLoading(false); }) }; return (
{error &&
{error.message}
}
) }; export default PayButton; ``` ## Test your integration 1. Navigate to your checkout page. 2. Fill in the payment details with a payment method from the following table. For card payments: - Enter any future date for card expiry. - Enter any 3-digit number for CVC. - Enter any billing postal code. 3. Submit the payment to Stripe. 4. Go to the Dashboard and look for the payment on the [Transactions page](https://dashboard.stripe.com/test/payments?status%5B0%5D=successful). If your payment succeeded, you’ll see it in that list. 5. Click your payment to see more details, like billing information and the list of purchased items. You can use this information to [fulfil the order](https://docs.stripe.com/checkout/fulfillment.md). #### Cards | Card number | Scenario | How to test | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | 4242424242424242 | The card payment succeeds and doesn’t require authentication. | Fill in the credit card form using the credit card number with any expiry date, CVC, and postal code. | | 4000002500003155 | The card payment requires *authentication* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase). | Fill in the credit card form using the credit card number with any expiry date, CVC, and postal code. | | 4000000000009995 | The card is declined with a decline code like `insufficient_funds`. | Fill in the credit card form using the credit card number with any expiry date, CVC, and postal code. | | 6205500000000000004 | The UnionPay card has a variable length of 13-19 digits. | Fill in the credit card form using the credit card number with any expiry date, CVC, and postal code. | #### Wallets | Payment method | Scenario | How to test | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Alipay | Your customer successfully pays with a redirect-based and [immediate notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment method. | Choose any redirect-based payment method, fill out the required details, and confirm the payment. Then click **Complete test payment** on the redirect page. | #### Bank redirects | Payment method | Scenario | How to test | | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | BECS Direct Debit | Your customer successfully pays with BECS Direct Debit. | Fill out the form using the account number `900123456` and BSB `000000`. The confirmed PaymentIntent initially transitions to `processing`, then transitions to the `succeeded` status 3 minutes later. | | BECS Direct Debit | Your customer’s payment fails with an `account_closed` error code. | Fill out the form using the account number `111111113` and BSB `000000`. | | Bancontact, EPS, iDEAL, and Przelewy24 | Your customer fails to authenticate on the redirect page for a redirect-based and immediate notification payment method. | Choose any redirect-based payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. | | Pay by Bank | Your customer successfully pays with a redirect-based and [delayed notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment method. | Choose the payment method, fill out the required details, and confirm the payment. Then click **Complete test payment** on the redirect page. | | Pay by Bank | Your customer fails to authenticate on the redirect page for a redirect-based and delayed notification payment method. | Choose the payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. | | BLIK | BLIK payments fail in a variety of ways – immediate failures (for example, the code has expired or is invalid), delayed errors (the bank declines) or timeouts (the customer didn’t respond in time). | Use email patterns to [simulate the different failures.](https://docs.stripe.com/payments/blik/accept-a-payment.md#simulate-failures) | #### Bank debits | Payment method | Scenario | How to test | | ----------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | SEPA Direct Debit | Your customer successfully pays with SEPA Direct Debit. | Fill out the form using the account number `AT321904300235473204`. The confirmed PaymentIntent initially transitions to processing, then transitions to the succeeded status three minutes later. | | SEPA Direct Debit | Your customer’s payment intent status transitions from `processing` to `requires_payment_method`. | Fill out the form using the account number `AT861904300235473202`. | #### Vouchers | Payment method | Scenario | How to test | | -------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | Boleto, OXXO | Your customer pays with a Boleto or OXXO voucher. | Select Boleto or OXXO as the payment method and submit the payment. Close the dialog after it appears. | See [Testing](https://docs.stripe.com/testing.md) for additional information to test your integration. ## Optional: Create products and prices Before you create a Checkout Session, you can create *Products* (Products represent what your business sells—whether that's a good or a service) and *Prices* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) upfront. Use products to represent different physical goods or levels of service, and *Prices* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) to represent each product’s pricing. You can [set up your Checkout Session](https://docs.stripe.com/payments/checkout/pay-what-you-want.md) to accept tips and donations, or sell pay-what-you-want products and services. For example, you can create a T-shirt as a product with a price of 20 USD. This allows you to update and add prices without needing to change the details of your underlying products. You can either create products and prices with the Stripe Dashboard or API. Learn more about [how products and prices work](https://docs.stripe.com/products-prices/how-products-and-prices-work.md). #### API The API only requires a `name` to create a [Product](https://docs.stripe.com/api/products.md). Checkout displays the product `name`, `description`, and `images` that you supply. ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ -d name=T-shirt ``` Next, create a [Price](https://docs.stripe.com/api/prices.md) to define how much to charge for your product. This includes how much the product costs and what currency to use. ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d "product={{PRODUCT_ID}}" \ -d unit_amount=2000 \ -d currency=usd ``` #### Dashboard > Copy products created in a sandbox to live mode so that you don’t need to re-create them. In the Product detail view in the Dashboard, click **Copy to live mode** in the upper right corner. You can copy the same sandbox product to live mode more than once. Each copy creates a separate live product, and subsequent updates to the sandbox product aren’t reflected in existing live copies. Make sure you’re in a sandbox by clicking **Sandboxes** within the Dashboard account picker. Next, define the items you want to sell. To create a new product and price: - Navigate to the [Products](https://dashboard.stripe.com/test/products) section in the Dashboard. - Click **Add product**. - Select **One time** when setting the price. Checkout displays the product name, description, and images that you supply. Each price you create has an ID. When you create a Checkout Session, reference the price ID and quantity. If you’re selling in multiple currencies, make your Price *multi-currency* (A single Price object can support multiple currencies. Each purchase uses one of the supported currencies for the Price, depending on how you use the Price in your integration). Checkout automatically [determines the customer’s local currency](https://docs.stripe.com/payments/checkout/localize-prices/manual-currency-prices.md) and presents that currency if the Price supports it. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d ui_mode=elements \ -d mode=payment \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ --data-urlencode "return_url=https://example.com/return?session_id={CHECKOUT_SESSION_ID}" ``` ## Optional: Pre-fill customer data [Server-side] If you’ve already collected your customer’s email address and want to pre-fill it in the Checkout Session for them, pass [customer_email](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer_email) when creating a Checkout Session. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ --data-urlencode "customer_email=customer@example.com" \ -d ui_mode=elements \ -d mode=payment \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ --data-urlencode "return_url=https://example.com/return?session_id={CHECKOUT_SESSION_ID}" ``` ## Optional: Save payment method details Learn how to [accept a payment and save your customer’s payment details](https://docs.stripe.com/payments/save-during-payment.md) for future purchases. ## Optional: Listen for Checkout Session changes ### Listen for Checkout Session changes You can listen for changes to the [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md) by adding an event listener on the `change` event with [checkout.on](https://docs.stripe.com/js/custom_checkout/change_event). #### HTML + JS ```javascript checkout = stripe.initCheckoutElementsSdk({ clientSecret: promise, elementsOptions: { appearance }, }); checkout.on('change', (session) => { // Handle changes to the checkout session }); ``` #### React ```jsx import React from 'react'; import { useCheckoutElements } from '@stripe/react-stripe-js/checkout'; const CheckoutForm = () => { const checkoutState = useCheckoutElements(); if (checkoutState.type === 'success') { checkoutState.checkout.on('change', (session) => { // Handle changes to the checkout session }); } }; ``` ## Optional: Collect billing and shipping addresses ## Collect a billing address By default, a Checkout Session collects the minimal billing details required for payment through the Payment Element. ### Using the Billing Address Element You can collect complete billing addresses using the Billing Address Element. First, pass [billing_address_collection=required](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-billing_address_collection) when you create the Checkout Session. #### HTML + JS Create a container DOM element to mount the Billing Address Element. Then create an instance of the Billing Address Element using [checkout.createBillingAddressElement](https://docs.stripe.com/js/custom_checkout/create_billing_address_element) and mount it by calling [element.mount](https://docs.stripe.com/js/element/mount), providing either a CSS selector or the container DOM element. ```html
``` ```javascript const billingAddressElement = checkout.createBillingAddressElement(); billingAddressElement.mount('#billing-address'); ``` The Billing Address Element supports the following options: - [contacts](https://docs.stripe.com/js/custom_checkout/create_billing_address_element#custom_checkout_create_billing_address_element-options-contacts) - [display](https://docs.stripe.com/js/custom_checkout/create_billing_address_element#custom_checkout_create_billing_address_element-options-display) #### React Mount the `BillingAddressElement` component within the `CheckoutElementsProvider`. ```jsx import React from 'react'; import {BillingAddressElement} from '@stripe/react-stripe-js/checkout'; const CheckoutForm = () => { return (
) }; ``` The Billing Address Element supports the following props: - [contacts](https://docs.stripe.com/js/custom_checkout/create_billing_address_element#custom_checkout_create_billing_address_element-options-contacts) - [display](https://docs.stripe.com/js/custom_checkout/create_billing_address_element#custom_checkout_create_billing_address_element-options-display) ### Using a custom form You can build your own form to collect billing addresses. - If your checkout page has a distinct address collection step before confirmation, call [updateBillingAddress](https://docs.stripe.com/js/react_stripe_js/checkout/update_billing_address) when your customer submits the address. - Otherwise, you can submit the address when your customer clicks the “pay” button by passing [billingAddress](https://docs.stripe.com/js/custom_checkout/confirm#custom_checkout_session_confirm-options-billingAddress) to [confirm](https://docs.stripe.com/js/custom_checkout/confirm). ### Collect partial billing addresses To collect partial billing addresses, such as only the country and postal code, pass [billing_address_collection=auto](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-billing_address_collection). When collecting partial billing addresses, you must [collect addresses manually](https://docs.stripe.com/payments/accept-a-payment.md#collect-billing-addresses-manually). By default, the Payment Element automatically collects the minimal billing details required for payment. To avoid double collection of billing details, pass [fields.billingDetails=never](https://docs.stripe.com/js/custom_checkout/create_payment_element#custom_checkout_create_payment_element-options-fields-billingDetails) when creating the Payment Element. If you only intend to collect a subset of billing details (such as the customer’s name), pass `never` for only the fields you intend to collect yourself. ## Collect a shipping address To collect a customer’s shipping address, pass the [shipping_address_collection](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-shipping_address_collection) parameter when you create the Checkout Session. When you collect a shipping address, you must also specify which countries to allow shipping to. Configure the [allowed_countries](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-shipping_address_collection-allowed_countries) property with an array of [two-letter ISO country codes](https://www.nationsonline.org/oneworld/country_code_list.htm). ### How to use the Shipping Address Element You can collect complete shipping addresses with the Shipping Address Element. #### HTML + JS Create a container DOM element to mount the Shipping Address Element. Then create an instance of the Shipping Address Element using [checkout.createShippingAddressElement](https://docs.stripe.com/js/custom_checkout/create_shipping_address_element) and mount it by calling [element.mount](https://docs.stripe.com/js/element/mount), providing either a CSS selector or the container DOM element. ```html
``` ```javascript const shippingAddressElement = checkout.createShippingAddressElement(); shippingAddressElement.mount('#shipping-address'); ``` The Shipping Address Element supports the following options: - [contacts](https://docs.stripe.com/js/custom_checkout/create_shipping_address_element#custom_checkout_create_shipping_address_element-options-contacts) - [display](https://docs.stripe.com/js/custom_checkout/create_shipping_address_element#custom_checkout_create_shipping_address_element-options-display) #### React Mount the `ShippingAddressElement` component within the `CheckoutElementsProvider`. ```jsx import React from 'react'; import {ShippingAddressElement} from '@stripe/react-stripe-js/checkout'; const CheckoutForm = () => { return (
) }; ``` The Shipping Address Element supports the following props: - [contacts](https://docs.stripe.com/js/custom_checkout/create_shipping_address_element#custom_checkout_create_shipping_address_element-options-contacts) - [display](https://docs.stripe.com/js/custom_checkout/create_shipping_address_element#custom_checkout_create_shipping_address_element-options-display) ### Listen for Checkout Session changes You can listen for changes to the [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md) by adding an event listener to handle address-related changes. #### HTML + JS Use the [Session object](https://docs.stripe.com/js/custom_checkout/session_object) to render the shipping amount in your checkout form. ```html

Totals

``` ```javascript const checkout = stripe.initCheckoutElementsSdk({clientSecret}); const subtotal = document.getElementById('subtotal'); const shipping = document.getElementById('shipping'); const total = document.getElementById('total'); checkout.on('change', (session) => { subtotal.textContent = `Subtotal: ${session.total.subtotal.amount}`; shipping.textContent = `Shipping: ${session.total.shippingRate.amount}`; total.textContent = `Total: ${session.total.total.amount}`; }); ``` #### React Use [useCheckoutElements](https://docs.stripe.com/js/react_stripe_js/checkout/use_checkout_elements) to render the shipping cost in your checkout form. ```jsx import React from 'react'; import {useCheckoutElements, ShippingAddressElement} from '@stripe/react-stripe-js/checkout'; const CheckoutForm = () => { const checkoutState = useCheckoutElements(); if (checkoutState.type === 'error') { return (
Error: {checkoutState.error.message}
); } return (

Checkout Summary

{checkoutState.type === 'success' && ( <>
              {JSON.stringify(checkoutState.checkout.lineItems, null, 2)}
            

Totals

              Subtotal: {checkoutState.checkout.total.subtotal.amount}
              Shipping: {checkoutState.checkout.total.shippingRate.amount}
              Total: {checkoutState.checkout.total.total.amount}
            
)}
) }; ``` ### Sync billing and shipping addresses When you use both a Billing Address Element and Shipping Address Element, you can show a checkbox that lets customers sync their billing and shipping addresses. #### HTML + JS Pass the [syncAddressCheckbox](https://docs.stripe.com/js/custom_checkout/init#custom_checkout_init-options-elementsOptions-syncAddressCheckbox) option in `elementsOptions` when initialising Checkout to configure which Address Element shows the checkbox. ```javascript const checkout = stripe.initCheckoutElementsSdk({ clientSecret, elementsOptions: { syncAddressCheckbox: 'shipping', }, }); ``` #### React Pass the [syncAddressCheckbox](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider#react_checkout_provider-options-elementsOptions-syncAddressCheckbox) option in `elementsOptions` to the `CheckoutElementsProvider` to configure which Address Element shows the checkbox. ```jsx promise, elementsOptions: { syncAddressCheckbox: 'shipping', }, }} > ``` Set the value to `'billing'` or `'shipping'` to choose which Address Element shows the checkbox. Set it to `'none'` to hide the checkbox, or leave it blank to use the default value (`'billing'`). ### Use a custom form You can build your own form to collect shipping addresses. - If your checkout page has a distinct address collection step before confirmation, call [updateShippingAddress](https://docs.stripe.com/js/react_stripe_js/checkout/update_shipping_address) when your customer submits the address. - Otherwise, you can submit the address when your customer clicks the “pay” button by passing [shippingAddress](https://docs.stripe.com/js/custom_checkout/confirm#custom_checkout_session_confirm-options-shippingAddress) to [confirm](https://docs.stripe.com/js/custom_checkout/confirm). ## Optional: Separate authorisation and capture [Server-side] Stripe supports two-step card payments so you can first authorise a card, then capture funds later. When Stripe authorises a payment, the card issuer guarantees the funds and places a hold for the payment amount on the customer’s card. You then have a certain amount of time to capture the funds, [depending on the card](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md#auth-capture-limitations)). If you don’t capture the payment before the authorisation expires, the payment is cancelled and the issuer releases the held funds. Separating authorisation and capture is useful if you need to take additional actions between confirming that a customer is able to pay and collecting their payment. For example, if you’re selling stock-limited items, you might need to confirm that an item purchased by your customer using Checkout is still available before capturing their payment and fulfilling the purchase. Accomplish this using the following workflow: 1. Confirm that Stripe authorised the customer’s payment method. 2. Consult your inventory management system to confirm that the item is still available. 3. Update your inventory management system to indicate that a customer has purchased the item. 4. Capture the customer’s payment. 5. Inform your customer whether their purchase was successful on your confirmation page. To indicate that you want to separate authorisation and capture, you must set the value of [payment_intent_data.capture_method](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-payment_intent_data-capture_method) to `manual` when creating the Checkout Session. This instructs Stripe to only authorise the amount on the customer’s card. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ -d "payment_intent_data[capture_method]=manual" \ -d return_url={{RETURN_URL}} \ -d ui_mode=elements ``` To capture an uncaptured payment, you can use either the [Dashboard](https://dashboard.stripe.com/test/payments?status%5B%5D=uncaptured) or the [capture](https://docs.stripe.com/api/payment_intents/capture.md) endpoint. Programmatically capturing payments requires access to the PaymentIntent created during the Checkout Session, which you can get from the [Session](https://docs.stripe.com/api/payment_intents/capture.md) object. ## Optional: Customer account management [No code] Let your customers [manage](https://docs.stripe.com/customer-management.md) their own accounts by sharing a link to your *customer portal* (The customer portal is a secure, Stripe-hosted page that lets your customers manage their subscriptions and billing details). The customer portal lets customers log in with their email address to manage subscriptions, update payment methods, and so on. ## Optional: Order fulfilment Learn how to [programmatically get a notification](https://docs.stripe.com/checkout/fulfillment.md?payment-ui=embedded-components) when a customer pays. ## See also - [Add discounts for one-time payments](https://docs.stripe.com/payments/advanced/discounts.md) - [Collect taxes](https://docs.stripe.com/tax/checkout/elements.md) - [Enable adjustable line item quantities](https://docs.stripe.com/payments/advanced/adjustable-quantity.md) - [Add one-click buttons](https://docs.stripe.com/elements/express-checkout-element/accept-a-payment.md?payment-ui=embedded-components) - [Sample project on GitHub](https://github.com/stripe-samples/accept-a-payment/tree/main/elements-with-checkout-sessions)