We are back with yet another exciting guide of Stripe integration with React applications. Over the course of this series we have explored Stripe integration with React applications and it’s various modes. Let’s a quick recap on what we have looked into so far.

  1. Standard stripe connect integration to React application.

The Stripe connect integration further had three types viz. Standard, Express, and Custom. Having explored standard Stripe connect integration, we are not back with Stripe connect express integration with React applications.

What is Stripe Connect Express?

Stripe Connect Express is one of the three account types offered by Stripe Connect for managing and paying out to users on your platform. It's designed for platforms that need a more streamlined onboarding experience while giving some control to the platform itself. The platform can collect essential details, and Stripe handles the rest of the onboarding process, reducing friction.

The major difference between Express Account and Standard accounts is the access to the dashboard. The standard gives full access to the dashboard to connected accounts whereas express accounts restrict some functionality like refunds and disputes. Other features like available balance, see upcoming payouts, and track their earnings in real time are yet to be available for express accounts as well.

Use the Express Dashboard when:

Your users are marketplace sellers that need limited access to workflows. You primarily send payouts to these users. Users won’t manage refunds or disputes directly. You want to fully brand the dashboard look and feel. You are comfortable taking responsibility for negative balance liability and managing risk of loss on connected accounts.

How to integrate stripe connect Express account

1. Install libraries and setup server

Create a server using express, then install and setup the stripe npm using the following command

npm install --save stripe@13.4.0 Setup your Stripe secret key that you get from the dashboard const stripe = require("stripe")( // This is your test secret API key. 'sk_test_XXXX', { apiVersion: "2023-10-16" } );

2. Stripe connect for client i.e react

Import the @stripe/react-connect-js module. React Connect.js is a thin wrapper around Connect embedded components that allows you to add embedded components to any React app.

npm install --save @stripe/react-connect-js

3. Create a connected account

Add an endpoint for creating a connected account.

Set up an endpoint on your server for your client to call to handle creating a connected account. The below api creates an endpoint for creating account.

server.js

app.post("/account", async (req, res) => { try { const account = await stripe.accounts.create({ controller: { stripe_dashboard: { type: "express", }, fees: { payer: "application" }, losses: { payments: "application" }, }, }); res.json({ account: account.id, }); } catch (error) { console.error("An error occurred when calling the Stripe API to create an account", error ); res.status(500) res.send({ error: error.message }); } });

4. Call the endpoint to create a connected account

Client.js

<button onClick={async () => { setAccountCreatePending(true); setError(false); fetch("/account", { method: "POST", }) .then((response) => response.json()) .then((json) => { setAccountCreatePending(false); const { account, error } = json; if (account) { setConnectedAccountId(account); } if (error) { setError(true); } }); }}

Sign up

5. Onboard the connected account

Add an endpoint for creating an account session. Add a server endpoint for your client to call to create an AccountSession. An AccountSession allows you to use Connect.js embedded components.

server.js

app.post("/account_session", async (req, res) => { try { const { account } = req.body; const accountSession = await stripe.accountSessions.create({ account: account, components: { account_onboarding: { enabled: true }, }, }); res.json({ client_secret: accountSession.client_secret }); } catch (error) { console.error("An error occurred when calling the Stripe API to create an account session", error ); res.status(500).send({ error: error.message }); } });

Here in account param Specify the ID of the connected account you’re acting on behalf of, also
Enable the account_onboarding component for the AccountSession.
Return the client secret from the AccountSession.

Initialise Connect.js

client.js

loadConnectAndInitialize returns a StripeConnect object, which creates a StripeConnectInstance.
Pass in your publishable key and a function that creates an AccountSession and returns its client_secret.

setStripeConnectInstance( loadConnectAndInitialize({ publishableKey: process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY, fetchClientSecret, appearance: { overlays: "dialog", variables: { colorPrimary: "#081e1d", }, }, }) );

Include the Connect onboarding embedded component

Looking of ReactJS app developers?

Connect with us today!! Contact us

6. Add the Connect onboarding embedded component.

After initialisation, the StripeConnectInstance manages the context and handles making requests to Stripe using the client secret and publishable key.

client.js

<ConnectAccountOnboarding onExit={() => setOnboardingExited(true)} />

Use the onExit callback to progress your user.

The component calls onExit when the user completes embedded onboarding.

7. Accept pay

Now that you have onboarded a connected account, continue to accept payments

Create destination charges

Create destination charges when customers transact with your platform for products or services provided by your connected accounts and you immediately transfer funds to your connected accounts. With this charge type:

Destination charges are only supported if both your platform and the connected account are in the same country. For cross-region support, you must specify the settlement merchant to the connected account using the on_behalf_of parameter on the Payment Intent or other valid cross-border transfers scenarios.

We recommend using destination charges for connected accounts that have access to the Express Dashboard or no dashboard access.

8. Create a Checkout Session

Create a Checkout Session in a server-side endpoint (for example, /create-checkout-session). The response includes a client_secret which you’ll use in the next step to mount Checkout.

There are two ways to accept payments

i.e Destination account and on_behalf_of,

Destination account

server.js

const stripe = require('stripe')( 'sk_test_XXXX' 'sk_test_XXXX'); const session = await stripe.checkout.sessions.create({ line_items: [{ price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 1000, }, quantity: 1, }], payment_intent_data: { application_fee_amount: 123, transfer_data: { destination: '{{CONNECTED_ACCOUNT_ID}}', }, }, mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/checkout/return?session\_id={CHECKOUT\_SESSION\_ID}', });

Here

Payment_intent_data[transfer_data][destination]: This parameter indicates that this is a destination charge. A destination charge means the charge is processed on the platform and then the funds are immediately and automatically transferred to the connected account’s pending balance.

return_url: Stripe redirects the customer to the return URL after they complete a payment attempt and replaces the {CHECKOUT_SESSION_ID} string with the Checkout Session ID. Use this to retrieve the Checkout Session and inspect the status to decide what to show your customer. Make sure the return URL corresponds to a page on your website that provides the status of the payment.

Payment_intent_data[application_fee_amount]: This parameter specifies the amount your platform plans to take from the transaction. The full charge amount is immediately transferred from the platform to the connected account that’s specified by transfer_data[destination] after the charge is captured. The application_fee_amount is then transferred back to the platform, and the Stripe fee is deducted from the platform’s amount.

9. Mount Checkout

To use the Embedded Checkout component, create an EmbeddedCheckoutProvider. Call loadStripe with your publishable API key and pass the returned Promise to the provider.

Use the options prop accepted by the provider to pass the client_secret from the previous step.

Client.js

import * as React from 'react'; import { loadStripe } from '@stripe/stripe-js'; import { EmbeddedCheckoutProvider, EmbeddedCheckout } from '@stripe/react-stripe-js'; // Make sure to call 'loadStripe' outside of a component’s render to avoid // recreating the 'Stripe' object on every render. const stripePromise = loadStripe('pk_test_XXXX'); const App = ({ clientSecret }) => { const options = { clientSecret }; return ( <EmbeddedCheckoutProvider stripe={stripePromise} options={options}

); };

Checkout is rendered in an iframe that securely sends payment information to Stripe over an HTTPS connection. Avoid placing Checkout within another iframe because some payment methods require redirecting to another page for payment confirmation.

10. Handle Post-Payment events

To handle the post-payment events we can use the webhooks provided by stripe.

Stripe sends a checkout.session.completed event when the payment completes.

Stripe recommends handling all the following events when collecting payments with Checkout:

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 - The customer’s payment succeeded. Fulfil the purchased goods or services.

Checkout.session.async_payment_failed - The payment was declined, or failed for some other reason. Contact the customer through email and ask them to place a new order.

11. Test the integration

For testing the integration we have the test-cards provided by stripe and can be accessed from here.

Integrate stripe connect express today in your apps.

Contact Nimblechapps! Contact us

12. Collect fees

You can collect fees with either an application-fee-amount or transfer-data[amount].

Application-fee-amount

When creating charges with an application_fee_amount, the full charge amount is immediately transferred from the platform to the transfer_data[destination] account after the charge is captured. The application_fee_amount (capped at the full amount of the charge) is then transferred back to the platform.

const stripe = require('stripe')('sk_test_XXXX'); const session = await stripe.checkout.sessions.create({ line_items: [{ price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 1000, }, quantity: 1, }], payment_intent_data: { application_fee_amount: 123, transfer_data: { destination: '{{CONNECTED_ACCOUNT_ID}}', }, }, mode: 'payment', ui_mode: 'embedded', success_url: 'https://example.com/success', });

Flow of funds for application_fee:

With the above code, the full charge amount (10.00 USD) is added to the connected account’s pending balance. The application_fee_amount (1.23 USD) is subtracted from the charge amount and is transferred to your platform. Stripe fees (0.59 USD) are subtracted from your platform account’s balance. The application fee amount minus the Stripe fees (1.23 USD - 0.59 USD = 0.64 USD) remains in your platform account’s balance.

Transfer-data[amount]

The transfer_data[amount] is a positive integer reflecting the amount of the charge to be transferred to the transfer_data[destination]. You subtract your platform’s fees from the charge amount, then pass the result of this calculation as the transfer_data[amount].

const stripe = require('stripe')('sk_test_XXXX'); const session = await stripe.checkout.sessions.create({ line_items: [{ price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 1000, }, quantity: 1, }], payment_intent_data: { transfer_data: { amount: 877, destination: '{{CONNECTED_ACCOUNT_ID}}', }, }, mode: 'payment', ui_mode: 'embedded', success_url: 'https://example.com/success', });

Flow of funds for transfer-data[amount]

With the above code, charge amount (10.00 USD) is added to the platform account’s balance. The transfer_data[amount] (8.77 USD) is subtracted from the platform account’s balance and added to the connected account’s pending balance. The charge amount (10.00 USD) less the transfer_data[amount] (8.77 USD) less the Stripe fees (on charge amount), for a net amount of 0.64 USD, remains in the platform account’s pending balance.

13. Issue Refunds

Charges created on the platform account can be refunded using the platform account’s secret key. When refunding a charge that has a transfer_data[destination], by default the destination account keeps the funds that were transferred to it, leaving the platform account to cover the negative balance from the refund. To pull back the funds from the connected account to cover the refund, set the reverse_transfer parameter to true when creating the refund:

const stripe = require('stripe')('sk_test_XXXX'); const refund = await stripe.refunds.create({ charge: '{CHARGE_ID}', reverse_transfer: true, });

By default, the entire charge is refunded, but you can create a partial refund by setting an amount value as a positive integer.

If the refund results in the entire charge being refunded, the entire transfer is reversed. Otherwise, a proportional amount of the transfer is reversed.

14. Refund application fees

When refunding a charge with an application fee, by default the platform account keeps the funds from the application fee. To push the application fee funds back to the connected account, set the refund_application_fee parameter to true when creating the refund:

const stripe = require('stripe')('sk_test_XXXX'); const refund = await stripe.refunds.create({ charge: '{CHARGE_ID}', reverse_transfer: true, });

If you refund the application fee for a destination charge, you must also reverse the transfer. If the refund results in the entire charge being refunded, the entire application fee is refunded as well. Otherwise, a proportional amount of the application fee is refunded.

Failed refunds

If a refund fails, or you cancel it, the amount of the failed refund returns to your platform account’s Stripe balance. Create a Transfer to move the funds to the connected account, as needed.

Conclusion

We have always felt that being a top web development company, it’s our responsibility to give back to the ReactJS community and educated our fellow developers with the know-how, issues, and the solutions we have faced during our decade long development experience. Stripe integration was one of the aspect which was miserly touched by the developers. Often our team found the information scattered across the internet. We wanted to bring all the types of Stripe integration under one series and hence we came up with this idea. We are hopeful that our readers like this series. Please stay tuned for the next and final type of Stripe integration i.e. Stripe connect Custom integration in React applications.