# Charge SaaS fees to your connected accounts Use Billing to charge SaaS fee subscriptions directly to your connected accounts. This guide explains how to use [Accounts v2](https://docs.stripe.com/connect/accounts-v2.md) to integrate Billing and Connect into your SaaS platform, which lets you charge subscription fees directly to your connected accounts. **You can enable Accounts v2 for your Connect platform from your [Dashboard](https://dashboard.stripe.com/settings/early_access).** > #### Test environment > > To try this integration, you must use a [Sandbox](https://docs.stripe.com/sandboxes.md). You can’t use test mode. ## Onboard your platform to Connect Set up your Stripe account as a Connect platform by following the onboarding process [in your Dashboard](https://dashboard.stripe.com/connect). The [Connect integration guide](https://docs.stripe.com/connect/interactive-platform-guide.md) explains the platform configuration options. If you have an existing platform, this integration doesn’t support your connected accounts that use Accounts v1. If you want to include them, you have to recreate them, following the process explained here, then remove their old accounts. ## Create your connected accounts using the Accounts v2 API > This integration uses only [Accounts](https://docs.stripe.com/api/v2/core/accounts.md), [Account Links](https://docs.stripe.com/api/v2/core/account-links.md), [Events](https://docs.stripe.com/api/v2/core/events.md?api-version=preview), [EventDestinations](https://docs.stripe.com/api/v2/core/event_destinations.md?api-version=preview), and [Persons](https://docs.stripe.com/api/v2/core/persons.md) from API v2. All other objects belong to API v1. For each connected account, use the Accounts v2 API to create an `Account` object with the `customer` and `merchant` configurations. - The `customer` configuration allows the `Account` to pay your platform a subscription fee using a payment method that you attach to the `Account`. - The `merchant` configuration makes the `Account` a connected account that can accept card payments from its own customers. When you assign the `merchant` configuration, you also define other aspects of the connected account, such as: - Request the ability to accept card payments by setting [configuration.merchant.capabilities.card_payments.requested](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-merchant-capabilities-card_payments-requested) to true. - Specify access to a Stripe Dashboard by setting [dashboard](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-dashboard). In the following example, we set `dashboard` to `full`, which means the `Account` has access to the full Stripe Dashboard. - Specify responsibility for collecting fees from the `Account` by setting [defaults.responsibilities.fees_collector](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-defaults-responsibilities-fees_collector) to `stripe` or `application`. - Specify responsibility for negative balances on the `Account` by setting [defaults.responsibilities.losses_collector](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-defaults-responsibilities-losses_collector) to `stripe` or `application`. > #### Use include to populate objects in the response > > When you create, retrieve, or update an `Account` in API v2, certain properties are only populated in the response if you specify them [in the include parameter](https://docs.stripe.com/api-includable-response-values.md). For any of those properties that you don’t specify, the response includes them as null, regardless of their actual value. ```curl curl -X POST https://api.stripe.com/v2/core/accounts \ -H "Authorization: Bearer <>" \ -H "Stripe-Version: 2026-02-25.preview" \ --json '{ "contact_email": "furever_contact@example.com", "display_name": "Furever", "dashboard": "full", "identity": { "business_details": { "registered_name": "Furever" }, "country": "us", "entity_type": "company" }, "configuration": { "customer": { "capabilities": { "automatic_indirect_tax": { "requested": true } } }, "merchant": { "capabilities": { "card_payments": { "requested": true } } } }, "defaults": { "currency": "usd", "responsibilities": { "fees_collector": "stripe", "losses_collector": "stripe" }, "locales": [ "en-US" ] }, "include": [ "configuration.customer", "configuration.merchant", "identity", "requirements" ] }' ``` The response includes the ID, which you use to reference the `Account` throughout your integration. ```json{% { "id": "acct_xxxxxxxxxxxxxxxx", "object": "v2.core.account", "applied_configurations": [ "customer", "merchant" ], "configuration": { "customer": { "automatic_indirect_tax": { "exempt": "none", "ip_address": null, "location": null, "location-source": "identity_address" }, "billing": { ... }, "capabilities": { "automatic_indirect_tax": { "requested": true, "status": "restricted", "status_details": [ { "code": "requirements_past_due", "resolution": "provide_info" } ] } }, "shipping": ..., "test_clock": ... }, "merchant": { "bacs_debit_payments": null, "branding": { ... }, "capabilities": { ... "card_payments": { "requested": true, "status": "restricted", "status_details": [ { "code": "requirements_past_due", "resolution": "provide_info" } ] }, "stripe_balance": { "payouts": { "requested": true, "status": "restricted", "status_details": [ { "code": "requirements_past_due", "resolution": "provide_info" } ] } }, ... }, "card_payments": { "decline_on": { "avs_failure": false, "cvc_failure": false } }, "mcc": null, ... "statement_descriptor": { ... }, "support": { "address": { ... }, ... } }, "recipient": null }, "contact_email": "furever_contact@example.com", "created": "2025-03-04T02:23:20.000Z", "dashboard": "full", "identity": { "attestations": { ... }, "terms_of_service": { "account": null }, "business_details": { ... "registered_name": "Furever", ... }, "country": "US", "entity_type": "company", "individual": null }, "defaults": null, "display_name": "Furever", "metadata": {}, "requirements": { "collector": "stripe", "entries": [ { "awaiting_action_from": "user", "description": "representative.surname", "errors": [], "impact": { "restricts_capabilities": [ { "capability": "card_payments", "configuration": "merchant", "deadline": { "status": "past_due" } }, { "capability": "stripe_balance.payouts", "configuration": "merchant", "deadline": { "status": "past_due" } } ] }, "minimum_deadline": { "status": "past_due" }, "reference": null, "requested_reasons": [ { "code": "routine_onboarding" } ] } ], "summary": { "minimum_deadline": { "status": "past_due", "time": null } } } } ``` ### Account Responsibilities Responsibilities define certain behaviors of connected accounts, such as how they pay Stripe fees and responsibility for negative balances. You set them when you add the `merchant` configuration to your connected accounts. To enable your `Accounts` to collect payments as connected accounts, set the following `responsibilities`: | Property | Description | Values | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [defaults.responsibilities.fees_collector](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-defaults-responsibilities-fees_collector) | Defines how Stripe collects payment fees for direct charges on the connected account. (For destination or separate charges, Stripe always collects fees from your platform.) | - `application`: Your platform collects application fees from the connected account, and Stripe collects payment fees from your platform. - `stripe`: Stripe collects payment fees directly from the connected account. | | [defaults.responsibilities.losses_collector](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-defaults-responsibilities-losses_collector) | Assigns responsibility for negative balances incurred by the connected account. | - `application`: Your platform is responsible for negative balances and [manages risk](https://docs.stripe.com/connect/risk-management.md) for the connected account. - `stripe`: Stripe is liable for the connected account’s negative balances. Your platform is still liable for negative balances on your platform account. | Responsibilities are subject to the following restrictions: - If you set `losses_collector` to `application`, then you must also set `fees_collector` to `application`. - If you use destination charges with an Account, we recommend that you set both `losses_collector` and `fees_collector` to `application`. For more information about supported configurations, see [Integration recommendations](https://docs.stripe.com/connect/integration-recommendations.md). ### Charge types The preview release supports only direct and destination [charges for connected accounts](https://docs.stripe.com/connect/charges.md). You can’t use separate charges and transfers. To use destination charges, you must [set the on_behalf_of parameter](https://docs.stripe.com/connect/destination-charges.md?platform=web&ui=elements#settlement-merchant) to make the connected account the settlement merchant. You must also add the `recipient` configuration to your connected accounts and request the `stripe_transfers` capability for them. ## Add the recipient configuration to connected accounts To allow the transfer of funds from your platform’s Stripe balance to the connected account’s Stripe balance, add the `recipient` configuration and request the `stripe_balance.stripe_transfers` capability. Destination charges require this capability. Requesting `stripe_balance.stripe_transfers` also automatically requests the `recipient` configuration’s `stripe_balance.payouts` capability, which allows the connected account to pay out to their external bank account. The `merchant` configuration automatically requests its own `stripe_balance.payouts` capability, which is identical to the `recipient` configuration’s `stripe_balance.payouts` capability. If the account doesn’t need any other `recipient` capabilities, you don’t need to add the `recipient` configuration. > The preview release doesn’t support [cross-border payouts](https://docs.stripe.com/connect/cross-border-payouts.md). To add the `recipient` configuration and request the `stripe_balance.stripe_transfers` capability, update the `Account` and set the [configuration.recipient.capabilities.stripe_balance.stripe_transfers.requested](https://docs.stripe.com/api/v2/core/accounts/update.md#v2_update_accounts-configuration-recipient-capabilities-stripe_balance-stripe_transfers-requested) parameter to true. ```curl curl -X POST https://api.stripe.com/v2/core/accounts/acct_xxxxxxxxxxxxxxxx \ -H "Authorization: Bearer <>" \ -H "Stripe-Version: 2026-02-25.preview" \ --json '{ "include": [ "identity", "requirements" ], "configuration": { "recipient": { "capabilities": { "stripe_balance": { "stripe_transfers": { "requested": true } } } } } }' ``` ## Onboard your connected accounts Before your connected accounts can accept payments through your platform, you must [onboard them](https://docs.stripe.com/connect/onboarding.md). You can direct your accounts to Stripe-hosted onboarding, offer a branded flow using a Connect embedded component, or code your own custom onboarding flow. Stripe-hosted onboarding is the simplest option. Using an embedded component allows for some customization while handling most of the process automatically. A custom onboarding flow gives your platform full control, but requires the most resources for implementation and ongoing updates. #### Stripe-hosted onboarding To integrate Stripe-hosted onboarding, follow the steps in the [Stripe-hosted onboarding guide](https://docs.stripe.com/connect/hosted-onboarding.md), with the following changes: - In the [Create an account and prefill information](https://docs.stripe.com/connect/hosted-onboarding.md#create-account) step, create your `Accounts` following the Accounts v2 process described in this guide. - In the [Identify and address requirement updates](https://docs.stripe.com/connect/hosted-onboarding.md#requirement-updates) step, create an event destination to [listen for v2.core.account[requirements].updated events](https://docs.stripe.com/connect/integrate-billing-connect.md#listen-for-account-updates). Don’t listen for the `account.updated` v1 event. > The Stripe-hosted onboarding guide uses the Accounts v1 API. You can’t use the Accounts v1 API with API v2, and the structure of an [Account in API v2](https://docs.stripe.com/api/v2/core/accounts.md) differs from the structure of an [Account in API v1](https://docs.stripe.com/api/accounts.md?api-version=preview). Where the hosted onboarding guide refers to properties of Accounts v1, use the corresponding properties in Accounts v2 instead. Remember to [use the include parameter](https://docs.stripe.com/api-includable-response-values.md) to retrieve most `Account` properties in API v2. #### Embedded onboarding These steps describe the basic process for onboarding your connected accounts by including the [Account onboarding Connect embedded component](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md) on your site. For full details about the onboarding process, see the [Embedded onboarding guide](https://docs.stripe.com/connect/embedded-onboarding.md). 1. [Create an Account Session](https://docs.stripe.com/api/account_sessions/create.md?api-version=preview), specifying the ID of the `Account` and `account_onboarding` as the component to enable. ```curl curl https://api.stripe.com/v1/account_sessions \ -u "<>:" \ -d account=acct_xxxxxxxxxxxxxxxx \ -d "components[account_onboarding][enabled]"=true \ -d "components[account_onboarding][features][external_account_collection]"=true ``` 1. After creating the Account Session and [initializing ConnectJS](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#account-sessions), 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}`); // }); ``` #### HTML + JS | Method | Type | Description | Default | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | `setFullTermsOfServiceUrl` | `string` | Absolute URL to your [full terms of service](https://docs.stripe.com/connect/service-agreement-types.md#full) agreement. | [Stripe’s full service agreement](https://stripe.com/connect-account/legal/full) | | `setRecipientTermsOfServiceUrl` | `string` | Absolute URL to your [recipient terms of service](https://docs.stripe.com/connect/service-agreement-types.md#recipient) agreement. | [Stripe’s recipient service agreement](https://stripe.com/connect-account/legal/recipient) | | `setPrivacyPolicyUrl` | `string` | Absolute URL to your privacy policy. | [Stripe’s privacy policy](https://stripe.com/privacy) | | `setSkipTermsOfServiceCollection` | `string` | [DEPRECATED] Use requirement restriction `exclude: ["tos_acceptance.*"]` instead. If true, embedded onboarding skips terms of service collection and you must [collect terms acceptance yourself](https://docs.stripe.com/connect/updating-service-agreements.md#indicating-acceptance). | false | | `setCollectionOptions` | `{fields: 'currently_due' | 'eventually_due', future_requirements: 'omit' | 'include', requirements: { exclude: string[] } | { only: string[] }}` | Customizes collecting `currently_due` or `eventually_due` requirements, controls whether to include [future requirements](https://docs.stripe.com/connect/handle-verification-updates.md), and allows restricting requirements collection. Specifying `eventually_due` collects both `eventually_due` and `currently_due` requirements. | `{fields: 'currently_due', futureRequirements: 'omit'}` | | `setOnExit` | `() => void` | The connected account has exited the onboarding process | | | `setOnStepChange` | `({step}: StepChange) => void` | The connected account has navigated from one step to another within the onboarding process. Use `StepChange` to identify the current step, as described below. | | To use this component to set up new accounts: 1. Create a [connected account](https://docs.stripe.com/api/accounts/create.md). You can prefill information on the `Account` object in this API call. 1. [Initialize Connect embedded components](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#account-sessions) using the ID of the connected account. 1. Include the `account-onboarding` element to show the onboarding flow to the connected account. 1. Listen for the `exit` event emitted from this component. Stripe sends this event when the connected account exits the onboarding process. 1. When `exit` triggers, retrieve the `Account` details to check the status of: - [details_submitted](https://docs.stripe.com/api/accounts/object.md#account_object-details_submitted) - [charges_enabled](https://docs.stripe.com/api/accounts/object.md#account_object-charges_enabled) - [payouts_enabled](https://docs.stripe.com/api/accounts/object.md#account_object-payouts_enabled) - Any other requested capabilities If all required capabilities are enabled, you can take the connected account to the next step of your flow. #### React | React prop | Type | Description | Default | Required or Optional | | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | -------------------- | | `onExit` | `() => void` | The component executes this callback function when the connected account exits the onboarding process | | required | | `fullTermsOfServiceUrl` | `string` | Link to your [full terms of service](https://docs.stripe.com/connect/service-agreement-types.md#full) agreement | [Stripe’s full service agreement](https://stripe.com/connect-account/legal/full) | optional | | `recipientTermsOfServiceUrl` | `string` | Link to your [recipient terms of service](https://docs.stripe.com/connect/service-agreement-types.md#recipient) agreement | [Stripe’s recipient service agreement](https://stripe.com/connect-account/legal/recipient) | optional | | `privacyPolicyUrl` | `string` | Link to your privacy policy | [Stripe’s privacy policy](https://stripe.com/privacy) | optional | | `skipTermsOfServiceCollection` | `boolean` | [DEPRECATED] Use requirement restriction `exclude: ["tos_acceptance.*"]` instead. If true, embedded onboarding skips terms of service collection and you must [collect terms acceptance yourself](https://docs.stripe.com/connect/updating-service-agreements.md#indicating-acceptance). | false | optional | | `collectionOptions` | `{fields: 'currently_due' | 'eventually_due', futureRequirements?: 'omit' | 'include', requirements?: { exclude: string[] } | { only: string[] }}` | Customizes collecting `currently_due` or `eventually_due` requirements, controls whether to include [future requirements](https://docs.stripe.com/connect/handle-verification-updates.md), and allows restricting requirements collection. Specifying `eventually_due` collects both `eventually_due` and `currently_due` requirements. You can’t update this parameter after the component has initially rendered. | `{fields: 'currently_due', futureRequirements: 'omit'}` | optional | | `onStepChange` | `({step}: StepChange) => void` | The component executes this callback function when the connected account has navigated from one step to another within the onboarding process. Use `StepChange` to identify the current step, as described below. | | optional | 1. Create a [connected account](https://docs.stripe.com/api/accounts/create.md). You can prefill information on the `Account` object in this API call. 1. [Initialize Connect embedded components](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#account-sessions) using the ID of the connected account. 1. Include the `account-onboarding` element to show the onboarding flow to the connected account. 1. Pass a callback function `onExit` to run when the connected account exits the onboarding process. 1. When `onExit` triggers, retrieve the `Account` details to check the status of: - [details_submitted](https://docs.stripe.com/api/accounts/object.md#account_object-details_submitted) - [charges_enabled](https://docs.stripe.com/api/accounts/object.md#account_object-charges_enabled) - [payouts_enabled](https://docs.stripe.com/api/accounts/object.md#account_object-payouts_enabled) - Any other requested capabilities If all required capabilities are enabled, you can take the connected account to the next step of your flow. ### The StepChange object The `StepChange` type is defined in `connect.js`. Every time the connected account navigates from one step to another in the onboarding process, the step change handler receives a `StepChange` object with the following property: | Name | Type | Example value | | ------ | ------------------------------------ | --------------- | | `step` | `string` (must be a valid step name) | `business_type` | The unique reference to an onboarding step. | ##### Step restrictions - The `StepChange` object is only for analytics. - Steps can appear in any order and can repeat. - The list of valid `step` names can change at any time, without notice. #### Step names Each page in an onboarding flow has one of the following step names. | Step name | Description | | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `stripe_user_authentication` | [User authentication](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#user-authentication-in-connect-embedded-components) includes a popup to a Stripe-owned window. The connected account must authenticate before they can continue their workflow. | | `risk_intervention` | Guides the connected account to resolve risk-related requirements. | | `legal_entity_sharing` | Connected accounts can optionally [reuse business information](https://docs.stripe.com/connect/networked-onboarding.md) from existing accounts with the same owner. | | `business_type` | Sets the business type of the connected account. In certain cases the connected account can also set their country. | | `business_details` | Collects information related to the connected account’s business. | | `business_verification` | Collects a proof of entity document establishing the business’ entity ID number, such as the company’s articles of incorporation. Or allows users to correct wrongly entered information related to the entity. | | `business_bank_account_ownership_verification` | Collects documents needed to verify that bank account information, such as the legal owner’s name and account number, match the information on the user’s Stripe account. | | `business_documents` | Collects other documents and verification requirements related to the business. | | `representative_details` | Collects information about the account representative. | | `representative_document` | Collects a government-issued ID verifying the existence of the account representative. | | `representative_additional_document` | Collects an additional document to verifying the details of the account representative. | | `legal_guardian_details` | Collects the legal guardians consent for accounts opened by minors. | | `owners` | Collects information about the [beneficial owners](https://support.stripe.com/questions/beneficial-owner-and-director-definitions) of a company. | | `directors` | Collects information about the [directors](https://support.stripe.com/questions/beneficial-owner-and-director-definitions) of a company. | | `executives` | Collects information about the [executives](https://support.stripe.com/questions/beneficial-owner-and-director-definitions) of a company. | | `proof_of_ownership_document` | Collects documentation that verifies a company’s [beneficial owners](https://support.stripe.com/questions/beneficial-owner-and-director-definitions). | | `proof_of_authorization` | Collects documentation to verify that the [account representative holds a position of sufficient authority](https://support.stripe.com/questions/representative-authority-verification) within a company. | | `confirm_owners` | Allows connected accounts to attest that the beneficial owner information provided to Stripe is both current and correct. | | `risa_compliance_survey` | (Applies only to businesses in Japan.) Answers questions concerning the [Revised Installment Sales Act](https://stripe.com/guides/installment-sales-act). | | `treasury_and_card_issuing_terms_of_service` | Collects [Financial Accounts for platforms and Card Issuing](https://docs.stripe.com/financial-accounts/connect.md) terms of service when requesting those capabilities. | | `external_account` | Collects the [external account](https://docs.stripe.com/api/accounts/object.md#account_object-external_accounts) of the connected account. | | `support_details` | Collects information that helps customers recognize the connected accounts business. This support information can be visible in payment statements, invoices, and receipts. | | `climate` | Allows a connected account to opt into [Stripe Climate](https://docs.stripe.com/climate.md). | | `tax` | Allows a connected account to opt into [Stripe Tax](https://docs.stripe.com/tax.md). | | `summary` | Final review step of onboarding. The connected account can update entered information from this step. The terms of service and privacy URL is displayed in this screen. | | `summary_risk` | From the summary step, a connected account can update information related to risk requirements. | | `summary_business_type` | From the summary step, a connected account can update information related to their business type. | | `summary_business` | From the summary step, a connected account can update information related to their business. | | `summary_support` | From the summary step, a connected account can update public-facing information related to their business. | | `summary_persons` | From the summary step, a connected account can update information about each person on their account. | | `summary_external_account` | From the summary step, a connected account can update information related to their [external account](https://docs.stripe.com/api/accounts/object.md#account_object-external_accounts). | | `summary_tax` | From the summary step, a connected account can update information related to their [Stripe Tax](https://docs.stripe.com/tax.md) integration. | | `summary_tax_identification_form` | From the summary step, a connected account can update information related to their W8/W9 certified tax information. This is shown when Stripe must collect W8/W9 information. | | `summary_climate` | From the summary step, a connected account can update information related to their [Stripe Climate](https://docs.stripe.com/climate.md) integration. | | `terms_of_service` | When leveraging requirement restrictions to collect `only` ToS acceptance, we render a special step because the summary step isn’t rendered when leveraging `only` requirement restrictions. | #### Custom onboarding using the API With API onboarding, you use the [Accounts API](https://docs.stripe.com/api/v2/core/accounts.md) to build an onboarding flow, reporting functionality, and communication channels for your connected accounts. Stripe can be completely invisible to them. Your platform is responsible for all interactions with your connected accounts and for collecting all the information needed to verify their identity. You must review and update requirements regularly, because changing laws and regulations can affect them. > The [API onboarding guide](https://docs.stripe.com/connect/api-onboarding.md) provides detailed guidance for implementing a custom onboarding flow. However, its code examples use the Accounts v1 API. You can’t use the Accounts v1 API with API v2, and the structure of an [Account in API v2](https://docs.stripe.com/api/v2/core/accounts.md) differs from the structure of an [Account in API v1](https://docs.stripe.com/api/accounts.md?api-version=preview). Where the onboarding guide refers to properties of Accounts v1, use the corresponding properties in Accounts v2 instead. Remember to [use the include parameter](https://docs.stripe.com/api-includable-response-values.md) to retrieve most `Account` properties in API v2. To identify an `Account`’s requirements based on its requested capabilities and responsibilities, retrieve the `Account` using the `include` parameter to request information about its requirements, configuration, and identity. ```curl curl -G https://api.stripe.com/v2/core/accounts/acct_xxxxxxxxxxxxxxxx \ -H "Authorization: Bearer <>" \ -H "Stripe-Version: 2026-01-28.clover" \ -d "include[0]"=requirements \ -d "include[1]"="configuration.merchant" \ -d "include[2]"=defaults \ -d "include[3]"=identity ``` After identifying what information is required, collect and verify it, then add it to the `Account`. The process for adding identity information depends on whether the `Account` represents an individual or a company: - If the `Account` has an [identity.entity_type](https://docs.stripe.com/api/v2/core/accounts/retrieve.md#v2_retrieve_accounts-response-identity-entity_type) of `individual`, you can update it directly: ```curl curl -X POST https://api.stripe.com/v2/core/accounts/acct_xxxxxxxxxxxxxxxx \ -H "Authorization: Bearer <>" \ -H "Stripe-Version: 2026-01-28.clover" \ --json '{ "include": [ "configuration.merchant", "defaults", "identity", "requirements" ], "configuration": { "merchant": { "mcc": "5734", "statement_descriptor": { "descriptor": "FurEver" }, "support": { "phone": "+14155552863" } } }, "identity": { "entity_type": "individual", "business_details": { "product_description": "Saas pet grooming platform at furever.dev using Connect embedded components", "url": "http://accessible.stripe.com" }, "attestations": { "terms_of_service": { "account": { "ip": "255.255.255.255" } } }, "individual": { "date_of_birth": { "day": 1, "month": 1, "year": 1990 }, "email": "jenny.rosen@example.com", "given_name": "Jenny", "surname": "Rosen" } } }' ``` - If the `Account` has an [identity.entity_type](https://docs.stripe.com/api/v2/core/accounts/retrieve.md#v2_retrieve_accounts-response-identity-entity_type) of `company`, you have to [create a Person object for that Account](https://docs.stripe.com/api/v2/core/persons/create.md) with [relationship.representative](https://docs.stripe.com/api/v2/core/persons/create.md#v2_create_core_person-relationship-representative) set to true. For example: ```curl curl -X POST https://api.stripe.com/v2/core/accounts/acct_xxxxxxxxxxxxxxxx/persons \ -H "Authorization: Bearer <>" \ -H "Stripe-Version: 2026-01-28.clover" \ --json '{ "nationalities": [ "us" ], "phone": "415-555-2863", "given_name": "Jenny", "surname": "Rosen", "email": "jenny.rosen@example.com", "address": { "line1": "27 Fredrick Ave", "city": "Brothers", "postal_code": "97712", "state": "OR", "country": "us" }, "id_numbers": [ { "type": "us_ssn_last_4", "value": "0000" } ], "date_of_birth": { "day": 28, "month": 1, "year": 2000 }, "relationship": { "director": true, "executive": false, "legal_guardian": false, "owner": true, "percent_ownership": "0.8", "representative": true, "title": "CEO" }, "legal_gender": "female", "political_exposure": "none" }' ``` ## Create external accounts for your connected accounts The process for creating an external account depends on your connected accounts’ Dashboard access: - If an `Account`’s `dashboard` is `full` or `express`, the account owner adds its external account using their Dashboard. - If an `Account`’s `dashboard` is `none`, you can create its external account using the [/v1/external_accounts](https://docs.stripe.com/api/external_account_bank_accounts/create.md?api-version=preview) endpoint. > Regardless of your connected accounts’ Dashboard access, you can [retrieve](https://docs.stripe.com/api/external_account_bank_accounts/retrieve.md?api-version=preview), [list](https://docs.stripe.com/api/external_account_bank_accounts/list.md?api-version=preview), [update](https://docs.stripe.com/api/external_account_bank_accounts/update.md?api-version=preview), or [delete](https://docs.stripe.com/api/external_account_bank_accounts/delete.md?api-version=preview) their external accounts using an API v1 call. ```curl curl https://api.stripe.com/v1/external_accounts \ -u "<>:" \ -H "Stripe-Version: 2025-04-30.preview" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d "external_account[account_number]"=000123456789 \ -d "external_account[routing_number]"=110000000 \ -d "external_account[country]"=US \ -d "external_account[currency]"=USD \ -d "external_account[object]"=bank_account ``` ## Set up payments for your connected accounts To set up payments for your connected accounts, follow the instructions in [Direct charges](https://docs.stripe.com/connect/direct-charges.md?platform=web) or [Destination charges](https://docs.stripe.com/connect/destination-charges.md?platform=web). To use destination charges, you must [set the on_behalf_of parameter](https://docs.stripe.com/connect/destination-charges.md?platform=web#settlement-merchant). ## Set up payouts for your connected accounts You can configure your connected accounts’ payout settings, including the schedule, statement descriptor, and delay days, using either your Dashboard or the API. #### API Use the [Balance Settings](https://docs.stripe.com/api/balance-settings.md) API. ```curl curl https://api.stripe.com/v1/balance_settings \ -u "<>:" \ -H "Stripe-Version: 2025-08-27.preview" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d debit_negative_balances=true \ -d "payments[payouts][schedule][interval]"=weekly \ -d "payments[payouts][schedule][weekly_payout_days][]"=monday ``` #### Dashboard 1. In your Dashboard, go to the [Connected accounts](https://dashboard.stripe.com/connect/accounts) page and search for the account you want to update. 1. Click the account to open its details page. 1. In the Activity section, click the overflow menu (⋯) next to Account balances, then click **Edit payout schedule**. ## Listen for requirements changes on your connected accounts Account requirements can change, often due to changes implemented by financial regulators, card networks, and other financial institutions. To set up webhook notifications of requirement changes, create an event destination to listen for Account v2 update events. 1. In your [Stripe Dashboard](https://dashboard.stripe.com), open the Developers menu by clicking **Developers** in the navigation menu footer, then select **Webhooks**. 1. Click **+ Add destination**. 1. In the Events from section, select **Connected accounts**. 1. Select **Show advanced options**. In the Payload style section, select **Thin**. 1. In the Events field, type “v2” to search for v2 event types. Select **v2.core.account[requirements].updated** and the **v2.core.account[configuration.configuration\_type].capability\_status\_updated** type for each configuration type used by your connected accounts. Continue setting up your event destination by following the [interactive webhook endpoint builder](https://docs.stripe.com/webhooks/quickstart.md). Configure your application to respond to update events by collecting any updated requirements. ### Set up a local listener during development You can send events to your local server for development purposes by installing the [Stripe CLI](https://docs.stripe.com/cli/listen) and setting up a local listener. 1. Log in to the [Stripe Dashboard](https://dashboard.stripe.com). 1. In the Stripe CLI, enter the `stripe login` command. It redirects you to your browser to confirm and authenticate your account. 1. Return to the CLI and run the following command. It listens to all available V2 events on your platform and connected accounts, and forwards them to http://localhost:4242. #### curl ```bash stripe listen --thin-events 'v2.core.account[requirements].updated,v2.core.account[configuration.recipient].capability_status_updated,v2.core.account[configuration.merchant].capability_status_updated,v2.core.account[configuration.customer].capability_status_updated' --forward-thin-to http://localhost:4242 ``` ## Integrate Billing to collect recurring fees Collecting recurring fees from your connected accounts with Stripe Billing involves the following steps: 1. Create one or more products to represent the recurring fees. 1. Create subscriptions for your fee products with the accounts as customers. 1. (Optional) To collect subscription fees directly from connected accounts’ Stripe balances, avoiding transaction fees associated with other payment methods such as cards, [configure it as a payment method](https://docs.stripe.com/payments/pay-with-balance.md). > A connected account can pay using its Stripe balance only if it has a sufficient available balance to make the payment. We provide recommendations for avoiding balance payment failures [later in these instructions](https://docs.stripe.com/connect/integrate-billing-connect.md#avoid-balance-payment-failures). ### 1. Create a product with a recurring price Create a product and price representing your subscription fee. You can use the API or the Dashboard. #### API [Create a Product](https://docs.stripe.com/api/products/create.md?api-version=preview) and define the default price as a recurring charge. Return the price information by including `default_price` in the `expand` parameter. ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ -d name="Connected account subscription fee" \ -d "default_price_data[unit_amount]"=1000 \ -d "default_price_data[currency]"=usd \ -d "default_price_data[recurring][interval]"=month \ -d "expand[]"=default_price ``` Record the price ID (`price_xxxxxxxxxxxxxx`) to use later when you create a subscription. > If you accept balance payments in multiple currencies, [create a separate price](https://docs.stripe.com/products-prices/manage-prices.md#create-price) in each currency for each product. For example, if you create a product with a USD price, and want to charge a connected account for it in EUR, add a price for that product in EUR. #### Dashboard In your Dashboard, go to the [Product catalog](https://dashboard.stripe.com/products?active=true) and click **+ Create product**. [Create a product](https://docs.stripe.com/products-prices/manage-prices.md#create-product) and assign it a price. To configure the price as a subscription, select **Recurring** pricing and set the **Billing period**. After you add the product and price, record the price ID to use later when you create a subscription. The price ID looks like `price_xxxxxxxxxxxxxx`. In the Dashboard, you can copy the price ID to the clipboard from the product details page. In the Pricing section, click the overflow menu (⋯) next to the subscription price, and then click **Copy price ID**. ### 2. Create subscriptions to charge your connected accounts You can collect SaaS subscription fees directly from a connected account’s Stripe balance. The connected account must meet the following requirements: - It must have both the `merchant` and `customer` configurations. - Its `merchant` configuration’s `card_payments` capability must be active. - Its available balance must have sufficient funds to make a full payment. #### Use SetupIntents To implement a custom process for your connected account owners to purchase subscriptions, [use a SetupIntent](https://docs.stripe.com/payments/save-and-reuse.md?platform=web&ui=elements) to attach a `PaymentMethod` to their `Account` object. To attach [payment from the account’s Stripe balance](https://docs.stripe.com/payments/pay-with-balance.md) as the payment method when creating a SetupIntent, specify the following values: ```curl curl https://api.stripe.com/v1/setup_intents \ -u "<>:" \ -H "Stripe-Version: 2025-04-30.preview" \ -d "payment_method_types[]"=stripe_balance \ -d confirm=true \ -d customer_account=acct_xxxxxxxxxxxxxx \ -d usage=off_session \ -d "payment_method_data[type]"=stripe_balance ``` Successful creation of the SetupIntent returns data similar to the following: ```json { "id": "seti_123", "object": "setup_intent", "customer": "cus_xxxxxxxxxxxxxx", "customer_account": "acct_xxxxxxxxxxxxxx", "payment_method": "pm_xxxxxxxxxxxxxx", "status": "succeeded" } ``` You can then [create Subscriptions](https://docs.stripe.com/billing/subscriptions/build-subscriptions.md?payment-ui=elements&api-integration=checkout#create-session) using the account’s attached `PaymentMethod` by passing the `Account` ID as the [customer_account](https://docs.stripe.com/api/subscriptions/create.md?api-version=preview#create_subscription-customer). To create a subscription that collects payments from the account’s Stripe balance, set the payment method type explicitly, as in the following example. ```curl curl https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -H "Stripe-Version: 2025-04-30.preview" \ -d customer_account=acct_xxxxxxxxxxxxxx \ -d default_payment_method=pm_xxxxxxxxxxxxxx \ -d "items[0][price]"=price_xxxxxxxxxxxxxx \ -d "items[0][quantity]"=1 \ -d "payment_settings[payment_method_types][0]"=stripe_balance ``` #### Use Embedded Checkout With [Embedded Checkout](https://docs.stripe.com/billing/subscriptions/build-subscriptions.md?payment-ui=checkout&ui=embedded-form), you embed a payment form on your site that your connected account owners can access to purchase subscriptions. > Embedded Checkout doesn’t support [payments directly from Stripe balances](https://docs.stripe.com/payments/pay-with-balance.md). To collect subscription fees from Stripe balances, create a custom confirmation flow using SetupIntents. #### Create a Checkout Session, and pass the following parameters: - Add a hash to the [line_items](https://docs.stripe.com/api/checkout/sessions/create.md?api-version=preview#create_checkout_session-line_items) array. Set the `quantity` to `1` and the `price` to the price ID of the product you created. - Set [mode](https://docs.stripe.com/api/checkout/sessions/create.md?api-version=preview#create_checkout_session-mode) to `subscription`. - Set [ui_mode](https://docs.stripe.com/api/checkout/sessions/create.md?api-version=preview#create_checkout_session-ui_mode) to `embedded`. - Set [return_url](https://docs.stripe.com/api/checkout/sessions/create.md?api-version=preview#create_checkout_session-return_url) to the address of the page to return the connected account owner to after they attempt payment. In the URL, set `session_id` to the `{CHECKOUT_SESSION_ID}` template variable, as shown in the following code example. Checkout replaces the variable with the Checkout Session ID so your return page can access it. - Set [customer_account](https://docs.stripe.com/api/checkout/sessions/create.md?api-version=preview#create_checkout_session-customer_account) to the ID of the `Account` that you want to charge. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -H "Stripe-Version: 2025-04-30.preview" \ -d "line_items[0][price]"=price_xxxxxxxxxxxxxx \ -d "line_items[0][quantity]"=1 \ -d mode=subscription \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}" \ -d customer_account=acct_xxxxxxxxxxxxxxxx ``` > You’re responsible for creating and hosting the page that Stripe returns the connected account owner to after payment. They return to that page regardless of whether the payment succeeds. The returned `Session` object includes a [client_secret](https://docs.stripe.com/api/checkout/sessions/object.md?api-version=preview#checkout_session_object-client_secret) value. Record it to use when you render the checkout form. #### Render the embedded checkout form using the client_secret from the previous step, as shown in the following code examples. #### HTML + JS 1. Load Stripe.js Use *Stripe.js* (Use Stripe.js’ APIs to tokenize customer information, collect sensitive card data, and accept payments with browser payment APIs) to remain *PCI compliant* (Any party involved in processing, transmitting, or storing credit card data must comply with the rules specified in the Payment Card Industry (PCI) Data Security Standards. PCI compliance is a shared responsibility and applies to both Stripe and your business) by ensuring that payment details are sent directly to Stripe without hitting your server. Always load Stripe.js from js.stripe.com to remain compliant. Don’t include the script in a bundle or host it yourself. 1. Define the payment form To securely collect the customer’s information, create an empty placeholder `div`. Stripe inserts an iframe into the `div`. Checkout is available as part of [Stripe.js](https://docs.stripe.com/js.md). Include the Stripe.js script on your page by adding it to the head of your HTML file. Next, create an empty DOM node (container) to use for mounting. ```html Accept a payment
``` 1. Initialize Stripe.js Initialize Stripe.js with your publishable API key. 1. Fetch a Checkout Session client secret Create an asynchronous `fetchClientSecret` function that makes a request to your server to [create a Checkout Session](https://docs.stripe.com/api/checkout/sessions/create.md?api-version=preview) and retrieve the client secret. 1. Initialize Checkout Initialize Checkout with your `fetchClientSecret` function and mount it to the placeholder `
` in your payment form. Checkout renders 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. ```javascript // Initialize Stripe.js const stripe = Stripe('<>'); initialize(); // Fetch Checkout Session and retrieve the client secret async function initialize() { const fetchClientSecret = async () => { const response = await fetch("/create-checkout-session", { method: "POST", }); const { clientSecret } = await response.json(); return clientSecret; }; // Initialize Checkout const checkout = await stripe.initEmbeddedCheckout({ fetchClientSecret, }); // Mount Checkout checkout.mount('#checkout'); } ``` #### React 1. Add Stripe to your React app To stay *PCI compliant* (Any party involved in processing, transmitting, or storing credit card data must comply with the rules specified in the Payment Card Industry (PCI) Data Security Standards. PCI compliance is a shared responsibility and applies to both Stripe and your business) by ensuring that payment details go directly to Stripe and never reach your server, install [React Stripe.js](https://docs.stripe.com/sdks/stripejs-react.md). ```bash npm install --save @stripe/react-stripe-js @stripe/stripe-js ``` 1. Load Stripe.js To configure the Stripe library, call `loadStripe()` with your Stripe publishable API key. Create an `EmbeddedCheckoutProvider`. Pass the returned `Promise` to the provider. 1. Fetch a Checkout Session client secret Create an asynchronous `fetchClientSecret` function that makes a request to your server to [create a Checkout Session](https://docs.stripe.com/api/checkout/sessions/create.md?api-version=preview) and retrieve the client secret. 1. Initialize Checkout To allow the child components to access the Stripe service through the embedded Checkout consumer, pass the resulting promise from `loadStripe` and the `fetchClientSecret` function as an `option` to the embedded Checkout provider. ```jsx 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_123', { }); const App = ({fetchClientSecret}) => { const options = {fetchClientSecret}; return ( ); } ``` #### Show a return page After your customer attempts payment, Stripe redirects them to a return page that you host on your site. When you created the Checkout Session, you specified the URL of the return page in the [return_url](https://docs.stripe.com/api/checkout/sessions/create.md?api-version=preview#create_checkout_session-return_url) parameter. You also configured it to include the Checkout Session ID. > During payment, some payment methods redirect the customer to an intermediate page, such as a bank authorization page. When they complete that page, Stripe redirects them to your return page. Handle the payment result on your return page. When it loads, use the Checkout Session ID from the URL to [retrieve the Checkout Session](https://docs.stripe.com/api/checkout/sessions/retrieve.md?api-version=preview) and examine its [status](https://docs.stripe.com/api/checkout/sessions/object.md?api-version=preview#checkout_session_object-status). The status value corresponds to the payment result as follows: - `complete`: The payment succeeded. Use the information from the Checkout Session to render a success page. - `open`: The payment failed or was canceled. Remount Checkout so that your customer can try again. ```js // Retrieve a Checkout Session // Use the session ID initialize(); async function initialize() { const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); const sessionId = urlParams.get('session_id'); const response = await fetch(`/session-status?session_id=${sessionId}`); const session = await response.json(); // Handle the session according to its status if (session.status == 'open') { // Remount embedded Checkout window.location.replace('http://localhost:4242/checkout.html') } else if (session.status == 'complete') { document.getElementById('success').classList.remove('hidden'); document.getElementById('customer-email').textContent = session.customer_email; // Show success page // Optionally use session.payment_status or session.customer_email // to customize the success page } } ``` ```javascript // Add an endpoint to fetch the Checkout Session status app.get('/session_status', async (req, res) => { const session = await stripe.checkout.sessions.retrieve(req.query.session_id); const customer = await stripe.customers.retrieve(session.customer); res.send({ status: session.status, payment_status: session.payment_status, customer_email: customer.email }); }); ``` ## Configure your integration to manage Stripe balance payment failures When you collect a payment from a connected account’s Stripe balance, the account’s available balance must have sufficient funds to make the full payment. Otherwise, the payment fails. If you plan to collect payments directly from your connected accounts’ Stripe balances, we recommend configuring your integration to manage balance-related payment failures. ### Avoid balance payment failures Because payments from a connected account’s Stripe balance rely on its available funds, you can avoid payment failures by taking steps to maximize your connected accounts’ balances. #### Tailor connected account payout schedules Coordinate your payout schedules with your subscription billing cycles. For example, if you charge subscription fees on the first day of each month, and schedule weekly payouts on Mondays, then months with more Mondays have more payouts. Those months have lower available balances than months with fewer payouts, making payment failures more likely. Another way to avoid payment failures due to payouts is to change to manual payouts before a subscription payment. At a set time before each subscription payment, if a connected account has sufficient available funds, switch it to [manual payouts](https://docs.stripe.com/connect/manage-payout-schedule.md) so the subscription payment gets paid before the automatic payout clears the account. After the subscription payment, resume automatic payouts. #### Set a minimum balance on connected accounts You can prevent automatic payouts from reducing a connected account’s available balance below a certain amount by defining a minimum balance for that account. You can programmatically configure minimum balances per connected account using the [Balance Settings API](https://docs.stripe.com/payouts/minimum-balances-for-automatic-payouts.md#minimum-balances-platforms). Alternatively, you can manually set the minimum balance for each connected account in the Dashboard: 1. Find the account in your Dashboard. 1. From the account’s overflow menu (⋯), select [View Dashboard as…](https://docs.stripe.com/connect/dashboard/managing-individual-accounts.md#view-the-dashboard-as-a-connected-account). 1. Click the gear icon and select **Settings**. 1. Under Account Settings, click **Business**. 1. Select the **External payout accounts and scheduling** tab. 1. Turn on **Keep a minimum amount in your payments balance** and enter an amount. ### Handle balance payment failures Set up [webhooks](https://docs.stripe.com/webhooks.md) and [event destinations](https://docs.stripe.com/billing/subscriptions/webhooks.md#events) to receive notifications about subscription payments. Identify payment failures by listening for the `invoice.payment_failed` event. When a payment fails: - The PaymentIntent status changes to `requires_action`. - The Subscription status remains `incomplete` for the current invoice. - The Subscription continues to generate invoices, which remain in `draft` status. #### Automatic retries [Enable retries](https://dashboard.stripe.com/revenue_recovery/retries) for failed balance payments due to insufficient available funds on recurring subscription invoices. Automatic retries schedules 2 payment attempts following an insufficient funds failure: - The first retry happens at least 24 hours after the failed payment. - If needed, the second retry happens on the next Sunday following the first retry. This retry schedule aims to give your connected account time to accumulate more funds in their Stripe balance and to avoid conflicts with scheduled payouts. You can enable retries for any amount for no additional fee. #### Manually retrying If a payment from a Stripe balance fails due to insufficient available funds, you can manually retry it by following these steps: 1. Set the connected account’s payout schedule interval to `manual`. 1. Listen for the next payment that comes into the connected account, then [check the account’s available balance](https://docs.stripe.com/api/balance/balance_retrieve.md). 1. If the available balance is equal to or greater than the subscription fee, set the unpaid invoice’s payment method to `stripe_balance` and retry it. Otherwise, continue listening for payments until the available balance is enough to pay the invoice. 1. If the payment succeeds, restore the connected account’s normal payout schedule. Instead of retrying a failed payment from a Stripe balance, you can try using a different payment method by [specifying it directly on the invoice](https://docs.stripe.com/billing/collection-method.md#set-collection-method-invoice). You can also implement a flow that allows connected accounts to [update their own subscription payment methods](https://docs.stripe.com/billing/subscriptions/payment-methods-setting.md#update-payment-method). ## Preview considerations Accounts v2 allows you to use a single, configurable account for each business on your platform that collects payments directly. The [preview release](https://docs.stripe.com/release-phases.md) doesn’t support Financial Accounts for platforms, Issuing, or payment methods that are in preview. You can still use Financial Accounts for platforms, Issuing, or payment methods in preview with Accounts v1. Enable Accounts v2 for your Connect platform from your [Dashboard](https://dashboard.stripe.com/settings/early_access).