# Fully embedded Connect platform integration Provide Connect features to your connected accounts through your own website. Connect embedded components let you add Stripe-managed functionality to a custom interface that you provide to your connected accounts, such as those in SaaS platforms and marketplaces. They can perform payment-related activities there instead of through the Stripe Dashboard. In a fully embedded integration: - Connected accounts access Stripe-related data, forms, and notifications through embedded components in your platform’s application. They don’t have access to a Stripe Dashboard. - Stripe manages credit and fraud risk on your connected accounts. For any risk or compliance actions, we communicate directly with connected accounts and they respond by interacting with embedded components. - Stripe email notifications direct your connected accounts to embedded components on your website to review information or take required action. You must provide Stripe with the URLs for those components. ## View the demo site We’ve built a complete [demo site for our fictitious business, Furever](http://furever.dev). Furever is a platform providing software for pet-groomers that allows their users to collect payments. In this demo, you can interact with many embedded components, including account onboarding and account management. ## Before you begin Before you can build an embedded integration, complete the following prerequisites: 1. [Register your platform](https://dashboard.stripe.com/connect). 1. Add business details to [activate your account](https://dashboard.stripe.com/account/onboarding). 1. [Complete your platform profile](https://dashboard.stripe.com/connect/settings/profile). 1. [Customise your brand settings](https://dashboard.stripe.com/settings/connect/stripe-dashboard/branding). Add a business name, icon, and brand colour. You must also decide whether your platform will own pricing, in which case Stripe collects payment fees from your platform and you bill your connected accounts. Otherwise, Stripe owns pricing and collects payment fees directly from your connected accounts. ## Create a connected account The following example creates a connected account where Stripe [manages risk](https://docs.stripe.com/connect/risk-management.md), controls pricing, and assumes responsibility for account onboarding requirements. Your platform uses embedded components and isn’t responsible for connected account negative balances. Your connected accounts don’t have access to Stripe-hosted Dashboards. > Because Stripe controls pricing in this example, you must integrate the [Documents embedded component](https://docs.stripe.com/connect/supported-embedded-components/documents.md). In addition, Stripe notifies connected accounts by email when their tax invoices or 1099s are ready for download. If you create accounts where your platform controls pricing, the Documents component isn’t required, and Stripe doesn’t send notifications to connected accounts about tax invoices or 1099s. You can request additional capabilities, such as specific payment methods, after the account onboards. Call [/v1/accounts](https://docs.stripe.com/api/accounts/create.md) with the following parameters: - `country` of the account - `controller.stripe_dashboard.type` = `none` - request `card_payments` and `transfers` capabilities ```curl curl https://api.stripe.com/v1/accounts \ -u "<>:" \ -d country=US \ -d "controller[stripe_dashboard][type]=none" \ -d "capabilities[card_payments][requested]=true" \ -d "capabilities[transfers][requested]=true" ``` ```json { "id": ""{{CONNECTED_ACCOUNT_ID}}"", "object": "account", "controller": { "type": "application", "is_controller": true, "losses": {"payments": "stripe"}, "fees": {"payer": "account"}, "requirement_collection": "stripe", "stripe_dashboard": { "type": "none" } }, "type": "none", ... } ``` ## Set up embedded components Connected accounts access their accounts, as well as core payment functionality, directly in your platform and don’t have access to a Stripe-hosted Dashboard. You must provide access to certain features through your website. Your integration must include the following embedded components: - [Account onboarding](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md) - [Account management](https://docs.stripe.com/connect/supported-embedded-components/account-management.md) - [Notification banner](https://docs.stripe.com/connect/supported-embedded-components/notification-banner.md) - [Documents](https://docs.stripe.com/connect/supported-embedded-components/documents.md) (when Stripe collects Stripe fees directly from connected accounts) Your integration must also provide a way to respond to disputes with evidence on individual payments. You can implement this [using our API](https://docs.stripe.com/disputes/api.md) or an embedded component ([Payments](https://docs.stripe.com/connect/supported-embedded-components/payments.md), [Payment details](https://docs.stripe.com/connect/supported-embedded-components/payment-details.md), or [Disputes for a payment](https://docs.stripe.com/connect/supported-embedded-components/disputes-for-a-payment.md)). We recommend that you provide a way to allow connected accounts to add money if needed to avoid a negative balance and prevent business disruptions. You can implement this using an embedded component ([Balances](https://docs.stripe.com/connect/supported-embedded-components/balances.md) or [Payouts](https://docs.stripe.com/connect/supported-embedded-components/payouts.md)). You can also add [additional embedded components](https://docs.stripe.com/connect/supported-embedded-components.md) or build your own UIs using our APIs. Make sure you [set up embedded components](https://docs.stripe.com/connect/get-started-connect-embedded-components.md) before onboarding connected accounts. ## Best practices To maximise the effectiveness of your integration, consider the following strategies: 1. **User focus**: Make sure that the onboarding process is intuitive by using the [account onboarding](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md) component to guide users through account creation and management by breaking the process into simple steps and providing straightforward instructions. 1. **Prompt for compliance**: Use the [notification banner](https://docs.stripe.com/connect/supported-embedded-components/notification-banner.md) component to keep users updated on their compliance status and any outstanding requirements. Place the banner prominently in your application, such as on the homepage of your dashboard, to make sure that it’s visible and prompts timely action on necessary documentation or updates. 1. **Responsive design**: Make sure that the components you integrate are responsive across devices. Because connected accounts might access your platform from various devices, including mobile phones, make sure the onboarding and management interfaces function well on different screen sizes. 1. **User authentication and security**: Implement strong [authentication measures](https://docs.stripe.com/connect/get-started-connect-embedded-components.md?platform=web#user-authentication-in-connect-embedded-components) during the onboarding and account management processes. Although Stripe authentication protects sensitive account information and the ability to change payout details, other sensitive information relies solely on your product’s authentication and security. You can enhance overall security by using methods such as one-time text message codes or two-factor authentication. 1. **Feedback mechanisms**: Integrate feedback options within your onboarding flow and management components. Enable users to report issues or suggest improvements, allowing you to continuously enhance the platform based on their input. 1. **Proactive engagement**: Encourage users to keep their accounts active by sending reminders or alerts about compliance obligations through email or platform notifications. This proactive approach can help prevent account suspensions and reduce frustration on the part of users. ## Onboard connected accounts Stripe uses an [AccountSession](https://docs.stripe.com/api/account_sessions.md) to express your intent to provide embedded component access to the connected account. Using an `AccountSession`, the embedded account onboarding component collects all required information based on your requested capabilities. ### Pre-fill the account You can streamline the onboarding flow for your connected accounts by prefilling `Account` properties with known information before you create an `AccountSession`. The onboarding component doesn’t request information that already exists on the `Account`. Prefill as much information as possible, including company, individual, and external account information, following these steps: 1. Use the [required verification information](https://docs.stripe.com/connect/required-verification-information.md) tool to learn about the requirements for your connected accounts, based on their location, business type, and requested capabilities. 1. Collect pre-fillable information matching the requirements. 1. Provide the collected information when you create the `Account` or add it prior to onboarding by updating the `Account`. After you create an `Account` and request its capabilities, you can check its specific requirements by looking at its [requirements](https://docs.stripe.com/api/accounts/object.md#account_object-requirements) property. Because your platform isn’t responsible for negative balances, your access to certain connected account information, such as payout accounts and legal entity information, is limited. After a connected account completes onboarding through the Account Onboarding embedded component, your platform can no longer update those properties. The connected account must make any updates to them. ### Onboard users through the embedded onboarding component Check out the [Furever demo site](https://furever.dev) for an example placement of the onboarding component. Connected accounts must go through onboarding and provide required information to enable charges and payouts. To onboard a connected account, host the [onboarding embedded component](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md) on your site and direct new accounts there. ### Create an Account Session When [creating an Account Session](https://docs.stripe.com/api/account_sessions/create.md), enable account onboarding by specifying `account_onboarding` in the `components` parameter. ```curl curl https://api.stripe.com/v1/account_sessions \ -u "<>:" \ -d "account={{CONNECTEDACCOUNT_ID}}" \ -d "components[account_onboarding][enabled]=true" ``` ### Render the Account onboarding component After creating the Account Session and [initialising ConnectJS](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#account-sessions), you can render the Account onboarding component in the front end: #### JavaScript ```js // Include this element in your HTML const accountOnboarding = stripeConnectInstance.create('account-onboarding'); accountOnboarding.setOnExit(() => { console.log('User exited the onboarding flow'); }); container.appendChild(accountOnboarding); // Optional: make sure to follow our policy instructions above // accountOnboarding.setFullTermsOfServiceUrl('{{URL}}') // accountOnboarding.setRecipientTermsOfServiceUrl('{{URL}}') // accountOnboarding.setPrivacyPolicyUrl('{{URL}}') // accountOnboarding.setCollectionOptions({ // fields: 'eventually_due', // futureRequirements: 'include', // requirements: { // exclude: ['business_profile.product_description'] // } // }) // accountOnboarding.setOnStepChange((stepChange) => { // console.log(`User entered: ${stepChange.step}`); // }); ``` Present the onboarding flow to the account’s primary owner. The primary owner sets up authentication with Stripe, and is the user who can edit the account details and respond to risk interventions. The connected account has only a single set of authentication credentials with Stripe. The user with authentication credentials can authenticate using one-time SMS codes to perform more sensitive actions such as updating bank accounts for payout destinations or providing updated legal entity information. ### Listen for onboarding events As the connected account proceeds through onboarding, [account.updated](https://docs.stripe.com/api/events/types.md#event_types-account.updated) events are also sent to your configured [Connect webhooks](https://docs.stripe.com/connect/webhooks.md). When the account finishes submitting their details, the `details_submitted` property on the `Account` changes to true. Check the status by looking for `details_submitted: true` in the `account.updated` event body in your webhook handler or by [retrieving the Account](https://docs.stripe.com/api/account/retrieve.md). If `details_submitted` is false, show the embedded onboarding component again. The component skips any information that’s already submitted and collects only the unsubmitted requirements. When a connected account submits their details and completes the onboarding flow, the embedded onboarding component calls the `onExit` handler that you [set when you render the component](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md). Use the callback to direct the account to their next action. If you don’t set an exit handler, or take action inside of the handler, the account sees a completion message without a clear next step. ### Request additional capabilities (optional) Your platform can continue to [request additional capabilities](https://docs.stripe.com/connect/account-capabilities.md#creating) after onboarding a connected account. For example, you must request the capabilities for any payment methods you want to enable for an account. If any requested capabilities require additional information, the connected account receives a notification through the [embedded notification banner](https://docs.stripe.com/connect/build-full-embedded-integration.md#embed-the-notification-banner). ## Handle ongoing compliance and risk updates Because Stripe manages credit and fraud risk for your connected accounts, your accounts must be able to see and respond to alerts from Stripe. To facilitate that, your platform must integrate the notification banner and account management embedded components. For more information about how Stripe supports your connected accounts through these components, see [Embedded Connect support](https://docs.stripe.com/connect/embedded-support.md). ## Embed the notification banner Stripe uses the [notification banner embedded component](https://docs.stripe.com/connect/supported-embedded-components/notification-banner.md) to notify connected accounts of outstanding compliance requirements and other [risk-related requests](https://docs.stripe.com/connect/embedded-risk.md). Responding to these notifications allows an account to remain compliant so it can process payments and receive payouts. If there are no outstanding notifications, the embedded notification banner doesn’t render. Integrate the notification banner in a highly visible and easily accessible location on your website. For example, you can integrate it at the top of your payments page. ### Create an Account Session When [creating an Account Session](https://docs.stripe.com/api/account_sessions/create.md), enable notification banner by specifying `notification_banner` in the `components` parameter. ```curl curl https://api.stripe.com/v1/account_sessions \ -u "<>:" \ -d "account={{CONNECTEDACCOUNT_ID}}" \ -d "components[notification_banner][enabled]=true" \ -d "components[notification_banner][features][external_account_collection]=true" ``` ### Render the notification banner component #### JavaScript ```js // Include this element in your HTML const notificationBanner = stripeConnectInstance.create('notification-banner'); container.appendChild(notificationBanner); // Optional: // notificationBanner.setCollectionOptions({ // fields: 'eventually_due', // futureRequirements: 'include', // }) ``` To respond to a banner notification, the account can click a button in the notification. You don’t need to redirect them to the account management embedded component. ## Embed account management Stripe requires the [account management embedded component](https://docs.stripe.com/connect/supported-embedded-components/account-management.md) when managing risk. Integrate the component in your website where an account updates their settings or profile. ### Create an Account Session When [creating an Account Session](https://docs.stripe.com/api/account_sessions/create.md), enable account management by specifying `account_management` in the `components` parameter. ```curl curl https://api.stripe.com/v1/account_sessions \ -u "<>:" \ -d "account={{CONNECTEDACCOUNT_ID}}" \ -d "components[account_management][enabled]=true" \ -d "components[account_management][features][external_account_collection]=true" ``` ### Render the account management component #### JavaScript ```js // Include this element in your HTML const accountManagement = stripeConnectInstance.create('account-management'); container.appendChild(accountManagement); // Optional: // accountManagement.setCollectionOptions({ // fields: 'eventually_due', // futureRequirements: 'include', // }) ``` This component allows an account to update their account details, respond to compliance requirements that are due, and update their authentication credentials. ## Integrate payments Set up the payments integration after integrating required embedded components. You can add the payment and payout embedded components to your platform or build your own workflows. Configure [Connect webhooks](https://docs.stripe.com/connect/webhooks.md) and listen for the `account.updated` event. A connected account is ready to receive payments when its `charges_enabled` property is true. ## Integrate embedded payments and payouts Add the [payments](https://docs.stripe.com/connect/supported-embedded-components/payments.md) and [payouts](https://docs.stripe.com/connect/supported-embedded-components/payouts.md) embedded components to your platform *before* building your payments integration. That way, a connected account can easily access and manage their core payment workflows. The payments component shows a list of the connected account’s payments, and includes filtering and individual payment detail views. An account can issue refunds and respond to disputes with evidence on individual payments through this component. If you choose to build and maintain a completely API-driven custom payment list instead, you can still enable refunds and disputes using either the [Payment details](https://docs.stripe.com/connect/supported-embedded-components/payment-details.md) component, the [Disputes for a payment](https://docs.stripe.com/connect/supported-embedded-components/disputes-for-a-payment.md) component, or our [APIs](https://docs.stripe.com/disputes/api.md). ## Create an Account Session When you [create an Account Session](https://docs.stripe.com/api/account_sessions/create.md), enable the payments embedded component by specifying `payments` in the `components` parameter. You can turn on or off an individual feature of the payments component by specifying the `features` parameter under `payments`: ```curl curl https://api.stripe.com/v1/account_sessions \ -u "<>:" \ -d "account={{CONNECTEDACCOUNT_ID}}" \ -d "components[payments][enabled]=true" \ -d "components[payments][features][refund_management]=true" \ -d "components[payments][features][dispute_management]=true" \ -d "components[payments][features][capture_payments]=true" \ -d "components[payments][features][destination_on_behalf_of_charge_management]=false" ``` Your connected accounts can view the complete set of information about direct charges. They can also manage refunds, manage disputes and capture payments if you enable the corresponding features when creating an account session. ## Render the payments component After you create the account session and [initialise ConnectJS](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#account-sessions), you can render the payments component in the front end: #### JavaScript ```js // Include this element in your HTML const payments = stripeConnectInstance.create('payments'); container.appendChild(payments); // Optional: specify filters to apply on load // payments.setDefaultFilters({ // amount: {greaterThan: 100}, // date: {before: new Date(2024, 0, 1)}, // status: ['partially_refunded', 'refund_pending', 'refunded'], // paymentMethod: 'card',}); ``` The payouts component shows the connected account’s recent payouts, current balance, and when funds will become available. When [creating an Account Session](https://docs.stripe.com/api/account_sessions/create.md), enable the payouts embedded component by specifying `payouts` in the `components` parameter. You can enable or disable individual features of the payouts component by specifying the `features` parameter under `payouts`: ```curl curl https://api.stripe.com/v1/account_sessions \ -u "<>:" \ -d "account={{CONNECTEDACCOUNT_ID}}" \ -d "components[payouts][enabled]=true" \ -d "components[payouts][features][instant_payouts]=true" \ -d "components[payouts][features][standard_payouts]=true" \ -d "components[payouts][features][edit_payout_schedule]=true" \ -d "components[payouts][features][external_account_collection]=true" ``` After creating the account session and [initialising ConnectJS](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#account-sessions), you can render the payouts component in the front end: #### JavaScript ```js // Include this element in your HTML const payouts = stripeConnectInstance.create('payouts'); container.appendChild(payouts); ``` For an immersive guide to implementing embedded components, follow the [Connect embedded components integration quickstart](https://docs.stripe.com/connect/connect-embedded-components/quickstart.md). ## Accept a payment If your connected accounts transact directly with customers, use [direct charges](https://docs.stripe.com/connect/direct-charges.md). Stripe assesses payment transaction fees to your platform when `controller.fees.payer` isn’t set to `account` for the [Account](https://docs.stripe.com/api/accounts/object.md). In turn, you’re responsible for charging payment processing fees on your connected accounts. You can specify a value for the [application fee](https://docs.stripe.com/connect/direct-charges.md#collect-fees) on each payment or use [platform pricing tools](https://docs.stripe.com/connect/platform-pricing-tools.md) to automatically take fees from connected accounts without having to build it into your integration. (See full diagram at https://docs.stripe.com/connect/build-full-embedded-integration) We recommend using [Stripe Checkout](https://docs.stripe.com/payments/checkout.md), a pre-built Stripe-hosted page, to accept payments. Checkout supports multiple payment methods and automatically shows the most relevant ones to your customer. You can also use the [Payment Element](https://docs.stripe.com/payments/payment-element.md), a pre-built UI component you can embed to accept additional payment methods with a single integration. #### Checkout ### Create a Checkout Session (Client-side) (Server-side) A Checkout Session controls what a customer sees in the Stripe-hosted payment page such as line items, the order amount and currency, and acceptable payment methods. When performing direct charges, Checkout uses the connected account’s branding settings. For more information, see [Customise branding](https://docs.stripe.com/connect/direct-charges.md?platform=web&ui=stripe-hosted#branding). Unlike destination charges or separate charges and transfers, connected accounts are responsible for handling disputes on direct charges – it’s not the responsibility of the platform. To create a Checkout Session, add a checkout button to your website that calls a server-side endpoint. ```html Checkout
``` On your server, make the following call to the Stripe API. After creating a Checkout Session, redirect your customer to the [URL](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-url) returned in the response. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d mode=payment \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d "payment_intent_data[application_fee_amount]=123" \ --data-urlencode "success_url=https://example.com/success" ``` - `line_items` – This parameter represents items that your customer is purchasing and that show up in the hosted user interface. - `success_url` – This argument redirects a customer after they complete a payment. - `Stripe-Account` – This header indicates a [direct charge](https://docs.stripe.com/connect/direct-charges.md) for your connected account. With direct charges, the connected account is responsible for Stripe fees, refunds, and chargebacks. Checkout uses the connected account’s branding, which allows their customers to feel like they’re interacting directly with the connected account instead of your platform. - (Optional) `payment_intent_data[application_fee_amount]` – This argument specifies the amount your platform plans to take from the transaction. After the payment is processed on the connected account, the `application_fee_amount` is transferred to the platform and the Stripe fee is deducted from the connected account’s balance. ### Handle post-payment events (Server-side) Stripe sends a [checkout.session.completed](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.completed) event when the payment completes. [Use a webhook to receive these events](https://docs.stripe.com/webhooks/quickstart.md) and run actions, such as 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. Some payment methods also take 2-14 days for payment confirmation. Setting up your integration to listen for asynchronous events enables you to accept multiple [payment methods](https://stripe.com/payments/payment-methods-guide) with a single integration. In addition to handling the `checkout.session.completed` event, we recommend handling two other events when collecting payments with Checkout: | Event | Description | Next steps | | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | | [checkout.session.completed](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.completed) | The customer has successfully authorised the payment by submitting the Checkout form. | Wait for the payment to succeed or fail. | | [checkout.session.async_payment_succeeded](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.async_payment_succeeded) | The customer’s payment succeeded. | Fulfill the purchased goods or services. | | [checkout.session.async_payment_failed](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.async_payment_failed) | The payment was declined, or it failed for some other reason. | Contact the customer through email and request that they place a new order. | These events all include the [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md) object. After the payment succeeds, the underlying *PaymentIntent* (The Payment Intents API tracks the lifecycle of a customer checkout flow and triggers additional authentication steps when required by regulatory mandates, custom Radar fraud rules, or redirect-based payment methods) status changes from `processing` to `succeeded`. #### Payment Element ### Create a PaymentIntent (Server-side) Stripe uses a [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) object to represent your intent to collect payment from a customer, tracking charge attempts and payment state changes throughout the process. ![An overview diagram of the entire payment flow](https://b.stripecdn.com/docs-statics-srv/assets/accept-a-payment-payment-element.5cf6795a02f864923f9953611493d735.svg) The payment methods shown to customers during the checkout process are also included on the PaymentIntent. You can let Stripe automatically pull payment methods from your Dashboard settings or you can list them manually. Unless your integration requires a code-based option for offering payment methods, Stripe recommends the automated option. That’s because Stripe evaluates the currency, payment method restrictions, and other parameters to determine the list of supported payment methods. Payment methods that increase conversion and that are most relevant to the currency and customer’s location are prioritised. Lower priority payment methods are hidden in an overflow menu (⋯). #### Manage payment methods from the Dashboard Create a PaymentIntent on your server that specifies the amount and currency. 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](https://dashboard.stripe.com/settings/payment_methods). Stripe handles the return of eligible payment methods based on factors such as the transaction’s amount, currency, and payment flow. This makes sure that your PaymentIntent supports the payment methods that you configure in the Dashboard, as applicable. Always decide how much to charge on the server side (a trusted environment) as opposed to the client. This prevents malicious customers from being able to choose their own prices. ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d amount=1099 \ -d currency=eur \ -d "automatic_payment_methods[enabled]=true" \ -d application_fee_amount=123 ``` #### List payment methods manually ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d amount=1099 \ -d currency=eur \ -d "payment_method_types[]=bancontact" \ -d "payment_method_types[]=card" \ -d "payment_method_types[]=eps" \ -d "payment_method_types[]=ideal" \ -d "payment_method_types[]=p24" \ -d "payment_method_types[]=sepa_debit" \ -d "payment_method_types[]=sofort" \ -d application_fee_amount=123 ``` When creating a PaymentIntent, you need to specify certain parameters: - `amount` - Create a PaymentIntent on your server with a specified amount. Always determine how much to charge on the server side, as this is a trusted environment. This approach prevents malicious customers from choosing their own prices. - `currency` - The currency you include in the PaymentIntent filters the payment methods shown to the customer, so choose it based on the payment methods you want to offer. For example, if you pass `eur` and have OXXO enabled in the Dashboard, OXXO won’t appear to the customer because it doesn’t support `eur` payments. Some payment methods support multiple currencies and countries. This guide uses Bancontact, credit cards, EPS, iDEAL, Przelewy24, SEPA Direct Debit, and Sofort in the example code. - `"payment_method_types[]"` - Manually list all the payment methods you want to support. - (Optional) `payment_intent_data[application_fee_amount]` – This argument specifies the amount your platform plans to take from the transaction. If you’re using Stripe’s [Platform Pricing Tool](https://docs.stripe.com/connect/platform-pricing-tools.md) to manage application fee pricing from the [Dashboard](https://dashboard.stripe.com/test/settings/connect/platform_pricing/payments), don’t include this argument as it’ll override any pricing logic set by the tool. After processing the payment on the connected account, the `application_fee_amount` transfers to the platform, and the Stripe fee is deducted from the connected account’s balance. > Each payment method needs to support the currency passed in the PaymentIntent and your business needs to be based in one of the countries each payment method supports. See [Payment method integration options](https://docs.stripe.com/payments/payment-methods/integration-options.md) for more details about what’s supported. ### Retrieve the client secret The PaymentIntent includes a *client secret* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer)) that the client side uses to securely complete the payment process. You can use different approaches to pass the client secret to the client side. #### Single-page application Retrieve the client secret from an endpoint on your server, using the browser’s `fetch` function. This approach is best if your client side is a single-page application, particularly one built with a modern front-end framework such as React. Create the server endpoint that serves the client secret: #### Ruby ```ruby get '/secret' do intent = # ... Create or retrieve the PaymentIntent {client_secret: intent.client_secret}.to_json end ``` And then fetch the client secret with JavaScript on the client side: ```javascript (async () => { const response = await fetch('/secret'); const {client_secret: clientSecret} = await response.json(); // Render the form using the clientSecret })(); ``` #### Server-side rendering Pass the client secret to the client from your server. This approach works best if your application generates static content on the server before sending it to the browser. Add the [client_secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) in your checkout form. In your server-side code, retrieve the client secret from the PaymentIntent: #### Ruby ```erb
``` ```ruby get '/checkout' do @intent = # ... Fetch or create the PaymentIntent erb :checkout end ``` ### Collect payment details (Client-side) 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](https://docs.stripe.com/security/guide.md#tls) when you’re ready to accept live payments. #### Set up Stripe.js #### HTML + 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. ```html Checkout ``` Create an instance of `Stripe` with the following JavaScript on your checkout page: ```javascript // Initialize Stripe.js with the same connected account ID used when creating // the PaymentIntent. const stripe = Stripe('<>', { stripeAccount: '{{CONNECTED_ACCOUNT_ID}}' }); ``` ### Add Stripe Elements and the Payment Element to your payment page The Payment Element needs a place to live on your payment page. Create an empty DOM node (container) with a unique ID in your payment form. ```html
``` When the form has loaded, create an instance of the Payment Element and mount it to the container DOM node along with the [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) from the previous step. Pass this value as an option when creating the [Elements](https://docs.stripe.com/js/elements_object/create) instance. The client secret must be handled carefully because it can complete the charge. Don’t log it, embed it in URLs, or expose it to anyone but the customer. ```javascript const options = { clientSecret: '{{CLIENT_SECRET}}', // Fully customizable with the Appearance API appearance: {/*...*/}, }; // Set up Stripe.js and Elements to use in checkout form using the client secret const elements = stripe.elements(options); // Create and mount the Payment Element const paymentElement = elements.create("payment"); 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 [customise the appearance of the Payment Element](https://docs.stripe.com/elements/appearance-api.md) to match the design of your site when you set up the `Elements` object. #### React Install Connect.js and the React Connect.js libraries from the [npm public registry](https://www.npmjs.com/package/@stripe/react-connect-js). ```bash npm install --save @stripe/connect-js @stripe/react-connect-js ``` ### Add and configure the Elements provider to your payment page To use the Payment Element component, wrap your checkout page component in an [Elements provider](https://docs.stripe.com/sdks/stripejs-react.md#elements-provider). Call `loadStripe` with your publishable key, and pass the returned `Promise` along with the [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) from the previous step as `options` in the `Elements` provider. ```jsx import React from 'react'; import ReactDOM from 'react-dom'; import {Elements} from '@stripe/react-stripe-js'; import {loadStripe} from '@stripe/stripe-js'; import CheckoutForm from './CheckoutForm'; // Make sure to call `loadStripe` outside of a component’s render to avoid // recreating the `Stripe` object on every render. const stripePromise = loadStripe("<>", { stripeAccount: '{{CONNECTED_ACCOUNT_ID}}' }); function App() { const options = { // pass the client secret from the previous step clientSecret: '{{CLIENT_SECRET}}', // Fully customizable with the Appearance API appearance: {/*...*/}, }; return ( ); }; ReactDOM.render(, document.getElementById('root')); ``` #### Add the PaymentElement component Use the `PaymentElement` component to build your form. ```jsx import React from 'react'; import {PaymentElement} from '@stripe/react-stripe-js'; const CheckoutForm = () => { return (
); }; export default CheckoutForm; ``` The Payment Element renders a dynamic form that allows your customer to pick a payment method type. The form automatically collects all necessary payments details for the payment method selected by the customer. You can [customise the appearance of the Payment Element](https://docs.stripe.com/elements/appearance-api.md) to match the design of your site when you configure the `Elements` provider. ### Submit the payment to Stripe (Client-side) Use [stripe.confirmPayment](https://docs.stripe.com/js/payment_intents/confirm_payment) to complete the payment using details from the Payment Element. Provide a [return_url](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-return_url) to this function to indicate where Stripe should redirect the user after they complete the payment. Your user may be first redirected to an intermediate site, such as a bank authorisation 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](https://docs.stripe.com/js/payment_intents/confirm_payment#confirm_payment_intent-options-redirect) to `if_required`. This only redirects customers who check out with redirect-based payment methods. #### HTML + JS ```javascript const form = document.getElementById('payment-form'); form.addEventListener('submit', async (event) => { event.preventDefault(); const {error} = await stripe.confirmPayment({ //`Elements` instance that was used to create the Payment Element elements, 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 (for example, payment // details incomplete) 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`. } }); ``` #### React To call [stripe.confirmPayment](https://docs.stripe.com/js/payment_intents/confirm_payment) from your payment form component, use the [useStripe](https://docs.stripe.com/sdks/stripejs-react.md#usestripe-hook) and [useElements](https://docs.stripe.com/sdks/stripejs-react.md#useelements-hook) hooks. If you prefer traditional class components over hooks, you can instead use an [ElementsConsumer](https://docs.stripe.com/sdks/stripejs-react.md#elements-consumer). ```jsx import React, {useState} from 'react'; import {useStripe, useElements, PaymentElement} from '@stripe/react-stripe-js'; const CheckoutForm = () => { const stripe = useStripe(); const elements = useElements(); const [errorMessage, setErrorMessage] = useState(null); const handleSubmit = async (event) => { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); if (!stripe || !elements) { // Stripe.js hasn't yet loaded. // Make sure to disable form submission until Stripe.js has loaded. return; } const {error} = await stripe.confirmPayment({ //`Elements` instance that was used to create the Payment Element elements, 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 (for example, payment // details incomplete) setErrorMessage(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`. } }; return (
{/* Show error message to your customers */} {errorMessage &&
{errorMessage}
} ); }; export default CheckoutForm; ``` Make sure the `return_url` corresponds to a page on your website that provides the status of the payment. When Stripe redirects the customer to the `return_url`, we provide the following URL query parameters: | Parameter | Description | | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | | `payment_intent` | The unique identifier for the `PaymentIntent`. | | `payment_intent_client_secret` | The [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) of the `PaymentIntent` object. | > If you have tooling that tracks the customer’s browser session, you might need to add the `stripe.com` domain to the referrer exclude list. Redirects cause some tools to create new sessions, which prevents you from tracking the complete session. Use one of the query parameters to retrieve the PaymentIntent. Inspect the [status of the PaymentIntent](https://docs.stripe.com/payments/paymentintents/lifecycle.md) to decide what to show your customers. You can also append your own query parameters when providing the `return_url`, which persist through the redirect process. #### HTML + JS ```javascript // Initialize Stripe.js using your publishable key const stripe = Stripe('<>'); // Retrieve the "payment_intent_client_secret" query parameter appended to // your return_url by Stripe.js const clientSecret = new URLSearchParams(window.location.search).get( 'payment_intent_client_secret' ); // Retrieve the PaymentIntent stripe.retrievePaymentIntent(clientSecret).then(({paymentIntent}) => { const message = document.querySelector('#message') // Inspect the PaymentIntent `status` to indicate the status of the payment // to your customer. // // Some payment methods will [immediately succeed or fail][0] upon // confirmation, while others will first enter a `processing` state. // // [0]: https://stripe.com/docs/payments/payment-methods#payment-notification switch (paymentIntent.status) { case 'succeeded': message.innerText = 'Success! Payment received.'; break; case 'processing': message.innerText = "Payment processing. We'll update you when payment is received."; break; case 'requires_payment_method': message.innerText = 'Payment failed. Please try another payment method.'; // Redirect your user back to your payment page to attempt collecting // payment again break; default: message.innerText = 'Something went wrong.'; break; } }); ``` #### React ```jsx import React, {useState, useEffect} from 'react'; import {useStripe} from '@stripe/react-stripe-js'; const PaymentStatus = () => { const stripe = useStripe(); const [message, setMessage] = useState(null); useEffect(() => { if (!stripe) { return; } // Retrieve the "payment_intent_client_secret" query parameter appended to // your return_url by Stripe.js const clientSecret = new URLSearchParams(window.location.search).get( 'payment_intent_client_secret' ); // Retrieve the PaymentIntent stripe .retrievePaymentIntent(clientSecret) .then(({paymentIntent}) => { // Inspect the PaymentIntent `status` to indicate the status of the payment // to your customer. // // Some payment methods will [immediately succeed or fail][0] upon // confirmation, while others will first enter a `processing` state. // // [0]: https://stripe.com/docs/payments/payment-methods#payment-notification switch (paymentIntent.status) { case 'succeeded': setMessage('Success! Payment received.'); break; case 'processing': setMessage("Payment processing. We'll update you when payment is received."); break; case 'requires_payment_method': // Redirect your user back to your payment page to attempt collecting // payment again setMessage('Payment failed. Please try another payment method.'); break; default: setMessage('Something went wrong.'); break; } }); }, [stripe]); return message; }; export default PaymentStatus; ``` ### Handle post-payment events (Server-side) Stripe sends a [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.succeeded) event when the payment completes. Use the [Dashboard webhook tool](https://dashboard.stripe.com/webhooks) or follow the [webhook guide](https://docs.stripe.com/webhooks/quickstart.md) to receive these events and run actions, such as 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 is what enables you to accept [different types of payment methods](https://stripe.com/payments/payment-methods-guide) with a single integration. In addition to handling the `payment_intent.succeeded` event, we recommend handling these other events when collecting payments with the Payment Element: | Event | Description | Action | | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.succeeded) | Sent when a customer successfully completes a payment. | Send the customer an order confirmation and *fulfill* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected) their order. | | [payment_intent.processing](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.processing) | Sent when a customer successfully initiates a payment, but the payment has yet to complete. This event is most commonly sent when the customer initiates a bank debit. It’s followed by either a `payment_intent.succeeded` or `payment_intent.payment_failed` event in the future. | Send the customer an order confirmation that indicates their payment is pending. For digital goods, you might want to fulfill the order before waiting for payment to complete. | | [payment_intent.payment_failed](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.payment_failed) | Sent when a customer attempts a payment, but the payment fails. | If a payment transitions from `processing` to `payment_failed`, offer the customer another attempt to pay. | ## Set up email communications to connected accounts Stripe communicates with your connected accounts on your behalf to manage risk and ensure ongoing compliance. You can customise and brand these email communications with your own email domain and platform branding. We send the following emails to your connected accounts: - **Account emails** verify an account’s information, such as additions or changes to an email address, phone number, or bank account. - **Compliance emails** notify accounts to provide required information. Stripe often needs to collect further information to maintain compliance with our financial partners. - **Risk emails** notify accounts when they’re under a risk review. These emails often provide instructions on how to submit information to resolve a risk action; for example, to remove a pause on payouts. - **Tax emails** (only when Stripe collects Stripe fees directly from connected accounts) notify users when their tax invoices or 1099s are ready to download. If you want to send any other payments-related emails to your connected accounts, you must send them yourself. For example, to send emails for new disputes, [listen for](https://docs.stripe.com/webhooks.md) the `charge.dispute.created` event on a connected account. When that event occurs, use [the Disputes API](https://docs.stripe.com/api/disputes.md) to get the details and email them to the account. You must [update your Connect settings with the URLs](https://dashboard.stripe.com/settings/connect/site-links) of your payments and connected account workflows so Stripe’s email communications can direct your connected accounts to them. You must set these links before creating an `AccountSession` or an `AccountLink` in live mode. ## Handle redirects from email links Emails sent by Stripe that contain a call to action need to include a link to that action. For example, if we send an email directing action on a connected account, it must include a link to your Account management component. Before you can create a live mode Account Session, you must provide the URLs where you have integrated the embedded components into your website. Configure the sending email domain and embedded component URLs in the **Site links** section of [your platform’s Connect settings](https://dashboard.stripe.com/settings/connect/site-links). > Testing environments use the same URLs as live mode. For embedded components integrated in your site, select **Yes** and enter the URL of the page that hosts the component. For any actions not handled by an embedded component, select **No** and enter the URL of the page on your site where the account can perform the action. After entering the URLs, test them to verify that they open the right pages. You must set URLs for the following: - Notification banner - Account management - Payments - Payouts - Balances - Documents (when Stripe collects Stripe fees directly from connected accounts) When sending an email, Stripe automatically appends the connected account ID to the redirect URL as the `stripe_account_id` parameter. Use that parameter to identify the account and verify that they’re authenticated. Set up the route on your server to read the parameters and display the correct embedded component. For more information about configuring Stripe emails to your connected accounts, see [Email communications in embedded Connect integrations](https://docs.stripe.com/connect/embedded-comms.md) ## Configure email branding and settings Stripe can send emails reflecting your platform’s brand settings from your own email domain to your connected accounts. To configure Stripe emails to your connected accounts, visit [Emails](https://dashboard.stripe.com/settings/connect/emails) in your platform Dashboard. ## Go live At this point, you’ve configured your platform integration by doing the following: - Created connected accounts in the correct configuration - Integrated embedded components to allow connected accounts to onboard, manage their account, and respond to risk actions through your website - Set up payments using Direct charges with an application fee - Set up branded email communications to enable Stripe to communicate with your users for compliance, risk actions, and necessary documents ## Test your integration Test your account creation flow by using the embedded account onboarding integrated in your platform. Test the settings of your payment methods for your connected accounts by logging into one of your test accounts and navigating to the [Payment methods settings](https://dashboard.stripe.com/settings/payment_methods). Test your checkout flow with your test keys and a test account. You can use our [test cards](https://docs.stripe.com/testing.md) to test your payments flow and simulate various payment outcomes.