Create charges on your platform account and transfer funds to multiple connected accounts.
Create separate charges and transfers to transfer funds from one payment to multiple connected accounts, or when a specific user isn’t known at the time of the payment. The charge on your platform account is decoupled from the transfer(s) to your connected accounts. With this charge type:
You create a charge on your platform’s account and also transfer funds to your connected accounts. The payment appears as a charge on your account and there are also transfers to connected accounts (amount determined by you), which are withdrawn from your account balance.
You can transfer funds to multiple connected accounts.
Your account balance is debited for the cost of the Stripe fees, refunds, and chargebacks.
This charge type is most optimal for marketplaces that need to split payments between multiple parties, such as DoorDash, a restaurant delivery platform.
Stripe supports separate charges and transfers in the following regions:
Australia
Austria
Belgium
Brazil
Bulgaria
Canada
Croatia
Cyprus
Czech Republic
Denmark
Estonia
Finland
France
Germany
Greece
Hungary
Ireland
Italy
Japan
Latvia
Liechtenstein
Lithuania
Luxembourg
Malaysia
Malta
Mexico
Netherlands
New Zealand
Norway
Poland
Portugal
Romania
Singapore
Slovakia
Slovenia
Spain
Sweden
Switzerland
United Kingdom
United States
In most scenarios, your platform and any connected account must be in the same region. Attempting to transfer funds across a disallowed border returns an error. For information about cross-region support, see cross-border transfers. You must only use transfers in combination with the permitted use cases for charges, tops-ups and fees.
Build a custom payments integration by embedding UI components on your site, using Stripe Elements. The client-side and server-side code builds a checkout form that accepts various payment methods. See how this integration compares to Stripe’s other integration types.
Customer location
Size
Theme
Layout
This demo only displays Google Pay or Apple Pay if you have an active card with either wallet. To see how Link works, type in any email address into the email input.
Stripe uses a PaymentIntent object to represent your intent to collect payment from a customer, tracking charge attempts and payment state changes throughout the process.
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, don’t list payment methods manually. Stripe evaluates the currency, payment method restrictions, and other parameters to determine the list of supported payment methods. Stripe prioritizes payment methods that help increase conversion and are most relevant to the currency and the customer’s location. Stripe hides lower priority payment methods in an overflow menu.
Create a PaymentIntent on your server with an amount, currency, and a transfer_group value to associate with the transfer of funds later. In the latest version of the API, specifying the automatic_payment_methods parameter is optional because Stripe enables its functionality by default. You can manage payment methods from the Dashboard. Stripe handles the return of eligible payment methods based on factors such as the transaction’s amount, currency, and payment flow.
The PaymentIntent includes a client secret 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.
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 frontend framework like React. Create the server endpoint that serves the client secret:
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:
(async()=>{const response =awaitfetch('/secret');const{client_secret: clientSecret}=await response.json();// Render the form using the clientSecret})();
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.
If you do choose to use an iframe and want to accept Apple Pay or Google Pay, the iframe must have the allow 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 when you’re ready to accept live payments.
Set up Stripe.js
The Payment Element is automatically available as a feature of Stripe.js. Include the Stripe.js script on your checkout page by adding it to the head of your HTML file. Always load Stripe.js directly from js.stripe.com to remain PCI compliant. Don’t include the script in a bundle or host a copy of it yourself.
Create an instance of Stripe with the following JavaScript on your checkout page:
checkout.js
// Set your publishable key: remember to change this to your live publishable key in production// See your keys here: https://dashboard.stripe.com/apikeysconst stripe =Stripe(
'pk_test_TYooMQauvdEDq54NiTphI7jx'
);
Add 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:
checkout.html
<formid="payment-form"><divid="payment-element"><!-- Elements will create form elements here --></div><buttonid="submit">Submit</button><divid="error-message"><!-- Display error message to your customers here --></div></form>
When the previous form loads, create an instance of the Payment Element and mount it to the container DOM node. Pass the client secret from the previous step into options when you create the Elements instance:
Handle the client secret carefully because it can complete the charge. Don’t log it, embed it in URLs, or expose it to anyone but the customer.
checkout.js
const options ={
clientSecret:'{{CLIENT_SECRET}}',// Fully customizable with appearance API.
appearance:{/*...*/},};// Set up Stripe.js and Elements to use in checkout form, passing the client secret obtained in a previous stepconst elements = stripe.elements(options);// Create and mount the Payment Elementconst paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');
The Payment Element renders a dynamic form that allows your customer to pick a payment method. For each payment method, the form automatically asks the customer to fill in all necessary payment details.
Customize appearance
Customize the Payment Element to match the design of your site by passing the appearance object into options when creating the Elements provider.
Collect addresses
By default, the Payment Element only collects the necessary billing address details. To collect a customer’s full billing address (to calculate the tax for digital goods and services, for example) or shipping address, use the Address Element.
Use stripe.confirmPayment to complete the payment using details from the Payment Element. Provide a return_url to this function to indicate where Stripe should redirect the user after they complete the payment. Your user may be first redirected to an intermediate site, like a bank authorization page, before being redirected to the return_url. Card payments immediately redirect to the return_url when a payment is successful.
If you don’t want to redirect for card payments after payment completion, you can set redirect to if_required. This only redirects customers that check out with redirect-based payment methods.
checkout.js
const form = document.getElementById('payment-form');
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`.}});
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:
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 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.
status.js
// Initialize Stripe.js using your publishable keyconst stripe =Stripe(
'pk_test_TYooMQauvdEDq54NiTphI7jx'
);// Retrieve the "payment_intent_client_secret" query parameter appended to// your return_url by Stripe.jsconst clientSecret =newURLSearchParams(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-notificationswitch(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 againbreak;default:
message.innerText='Something went wrong.';break;}});
Stripe sends a payment_intent.succeeded event when the payment completes. Use the Dashboard webhook tool or follow the webhook guide 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 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:
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.
Transfer and charge amounts don’t have to match. You can split a single charge between multiple transfers or include multiple charges in a single transfer. The following example creates an additional transfer associated with the same transfer_group.
The settlement merchant is dependent on the capabilities set on an account and how a charge is created. The settlement merchant determines whose information is used to make the charge. This includes the statement descriptor (either the platform’s or the connected account’s) that’s displayed on the customer’s credit card or bank statement for that charge.
Specifying the settlement merchant allows you to be more explicit about who to create charges for. For example, some platforms prefer to be the settlement merchant because the end customer interacts directly with their platform (such as on-demand platforms). However, some platforms have connected accounts that interact directly with end customers instead (such as a storefront on an e-commerce platform). In these scenarios, it might make more sense for the connected account to be the settlement merchant.
You can set the on_behalf_of parameter to the ID of a connected account to make that account the settlement merchant for the payment. When using on_behalf_of:
Charges settle in the connected account’s country and settlement currency.
The fee structure for the connected account’s country is used.
The connected account’s statement descriptor is displayed on the customer’s credit card statement.
If the connected account is in a different country than the platform, the connected account’s address and phone number are displayed on the customer’s credit card statement.
The number of days that a pending balance is held before being paid out depends on the delay_days setting on the connected account.
If on_behalf_of is omitted, the platform is the business of record for the payment.
Caution
The on_behalf_of parameter is supported only for connected accounts with a payments capability such as card_payments. Accounts under the recipient service agreement can’t request card_payments or other payments capabilities.
When using separate charges and transfers, the platform can collect fees on a charge by reducing the amount it transfers to the destination accounts. For example, consider a restaurant delivery service transaction that involves payments to the restaurant and to the driver:
The customer pays a 100 USD charge.
Stripe collects a 3.20 USD fee and adds the remaining 96.80 USD to the platform account’s pending balance.
The platform transfers 70 USD to the restaurant’s connected account and 20 USD to the driver’s connected account.
A platform fee of 6.80 USD remains in the platform account.
The default behavior is to transfer funds from the platform account’s available balance. Attempting a transfer that exceeds the available balance fails with an error. To avoid this problem, when creating a transfer, tie it to an existing charge by specifying the charge ID as the source_transaction parameter. With a source_transaction, the transfer request returns success regardless of your available balance. However, the funds don’t become available in the destination account until the funds from the associated charge are available to transfer from the platform account.
If the source charge has a transfer_group value, Stripe assigns the same value to the transfer’s transfer_group. If it doesn’t, then Stripe generates a string in the format group_ plus the associated PaymentIntent ID, for example: group_pi_2NHDDD589O8KAxCG0179Du2s. It assigns that string as the transfer_group for both the charge and the transfer.
Note
You must specify the source_transaction when you create a transfer. You can’t update that attribute later.
Get the PaymentIntent’s latest_charge attribute. This attribute is the ID of the most recent charge associated with the PaymentIntent.
Request a list of charges, specifying the payment_intent in the request. This method returns full data for all charges associated with the PaymentIntent.
When using this parameter:
The amount of the transfer must not exceed the amount of the source charge
You can create multiple transfers with the same source_transaction, as long as the sum of the transfers doesn’t exceed the source charge
The transfer takes on the pending status of the associated charge: if the funds from the charge become available in N days, the payment that the destination Stripe account receives from the transfer also becomes available in N days
Stripe automatically creates a transfer_group for you
The currency of the balance transaction associated with the charge must match the currency of the transfer
Asynchronous payment methods, like ACH, can fail after a subsequent transfer request is made. For these payments, avoid using source_transaction. Instead, wait until a charge.succeeded event is triggered before transferring the funds. If you have to use source_transaction with these payments, you must implement functionality to manage payment failures.
When a payment used as a source_transaction fails, funds from your platform’s account balance are transferred to the connected account to cover the payment. To recover these funds, reverse the transfer associated with the failed source_transaction.
Transfer options
You can assign any value to the transfer_group string, but it must represent a single business action. You can also make a transfer with neither an associated charge nor a transfer_group—for example, when you must pay a provider but there’s no associated customer payment.
Note
The transfer_group only identifies associated objects. It doesn’t affect any standard functionality. To prevent a transfer from executing before the funds from the associated charge are available, use the transfer’s source_transaction attribute.
Transfer and charge amounts don’t have to match. You can split a single charge between multiple transfers or include multiple charges in a single transfer. You can perform transfers and charges in any order.
By default, a transfer request fails when the amount exceeds the platform’s available account balance. You can instead validate the transfer amount against its associated charge by specifying that charge as the transfer’s source_transaction. In that case, the transfer request automatically succeeds but isn’t executed until the funds from that charge are available in the platform account.
Note
If you use separate charges and transfers, take that into account when planning your payout schedule. Automatic payouts can interfere with transfers that don’t have a defined source_transaction.
Issue refunds
You can refund charges created on your platform using its secret key. However, refunding a charge has no impact on any associated transfers. It’s up to your platform to reconcile any amount owed back to it by reducing subsequent transfer amounts or by reversing transfers.
Connect supports the ability to reverse transfers made to connected accounts, either entirely or partially (by setting an amount value). Use transfer reversals only for refunds or disputes related to the charge, or to correct errors in the transfer.
Transfer reversals add the specified (or entire) amount back to the platform’s available balance, reducing the connected account’s available balance accordingly. It is only possible to reverse a transfer if the connected account’s available balance is greater than the reversal amount or has connected reserves enabled.
If the transfer reversal requires a currency conversion, and the reversal amount would result in a zero balance after the conversion, it returns an error.
Welcome to the Stripe Shell!
Stripe Shell is a browser-based shell with the Stripe CLI pre-installed. Log in to your
Stripe account and press Control + Backtick (`) on your keyboard to start managing your Stripe
resources in test mode.
- View supported Stripe commands:
- Find webhook events:
- Listen for webhook events:
- Call Stripe APIs: stripe [api resource] [operation] (e.g., )