# API onboarding Build your own onboarding flow using Stripe's APIs. With API onboarding, you use the Accounts API to build an onboarding flow, reporting functionality, and communication channels for your users. Stripe can be completely invisible to the account holder. However, your platform is responsible for all interactions with your accounts and for collecting all the information needed to verify them. > #### Additional responsibilities > > With API onboarding, your custom flow must meet all legal and regulatory requirements in the regions where you do business. You must also commit resources to track changes to those requirements and collect updated information on an ongoing basis, at least once every six months. If you want to implement a customised onboarding flow, Stripe strongly recommends that you use [embedded onboarding](https://docs.stripe.com/connect/embedded-onboarding.md). (See full diagram at https://docs.stripe.com/connect/api-onboarding) ## Establish requirements The following factors affect the [onboarding requirements](https://docs.stripe.com/connect/required-verification-information.md) for your connected accounts: - The origin country of the connected accounts - The [service agreement type](https://docs.stripe.com/connect/service-agreement-types.md) applicable to the connected accounts - The [capabilities](https://docs.stripe.com/connect/account-capabilities.md) requested for the connected accounts - The [business_type](https://docs.stripe.com/api/accounts/object.md#account_object-business_type) (for example, individual or company) and [company.structure](https://docs.stripe.com/api/accounts/object.md#account_object-company-structure) (for example, `public_corporation` or `private_partnership`) Use the [Required Verification Information](https://docs.stripe.com/connect/required-verification-information.md) tool to see how changing these factors affects the onboarding requirements for your connected accounts. ## Create forms to collect information [Client-side] As a best practice, organise the required parameters into logical groupings or forms in your onboarding flow. You might wish to encode a mapping between the Stripe parameters and the logical groupings. Suggested logical groupings for parameters are shown in the first column of the example requirements table. After you encode the required parameters into your application, generate UIs for the parameters corresponding to these requirements. For each parameter, design a UI form that includes: - Parameter label, localised for each supported country and language - Parameter description, localised for each supported country and language - Parameter input fields with data validation logic and document uploading where required It’s important to architect your application logic to account for the possibility of additional parameters in the future. For example, Stripe might introduce new parameters, new verifications, or new thresholds that you must incorporate into your onboarding flows over time. Changing any of the factors that determine your connected accounts’ requirements means you must also adjust your collection forms to handle the changed requirements. [Country](https://docs.stripe.com/api/accounts/object.md#account_object-country) and [service agreement type](https://docs.stripe.com/api/accounts/object.md#account_object-tos_acceptance-service_agreement) are immutable, while [capabilities](https://docs.stripe.com/api/accounts/object.md#account_object-capabilities) and [business type](https://docs.stripe.com/api/accounts/object.md#account_object-business_type) are mutable. - To change an immutable field, create a new connected account with the new values to replace the existing account. - To change a mutable field, update the connected account. ### Include the Stripe Terms of Service Agreement Your connected accounts must accept Stripe’s terms of service before they can activate. You can [wrap Stripe’s terms of service in your own terms of service](https://docs.stripe.com/connect/updating-service-agreements.md#adding-stripes-service-agreement-to-your-terms-of-service). ## Create a connected account [Server-side] Create an [Account](https://docs.stripe.com/api/accounts/create.md) where your platform is liable for negative balances, Stripe collects fees from your platform account, and your connected accounts don’t have access to a Stripe-hosted Dashboard. Request any capabilities that your connected accounts need. Pre-fill the business type and any other available information matching your [requirements](https://docs.stripe.com/connect/api-onboarding.md#establish-requirements). Alternatively, you can create a connected account with `type` set to `custom` and desired capabilities. If you don’t specify the country and service type agreement, they’re assigned the following default values: - The `country` defaults to the same country as your platform. - The service type agreement (`tos_acceptance.service_agreement`) defaults to `full`. > To comply with French PSD2 regulations, platforms in France [must use account tokens](https://stripe.com/guides/frequently-asked-questions-about-stripe-connect-and-psd2#regulatory-status-of-connect). An additional benefit of tokens is that the platform doesn’t have to store PII data, which is transferred from the connected account directly to Stripe. For platforms in other countries, we recommend using account tokens, but they aren’t required. #### With controller properties ```curl curl https://api.stripe.com/v1/accounts \ -u "<>:" \ -d "controller[losses][payments]=application" \ -d "controller[fees][payer]=application" \ -d "controller[stripe_dashboard][type]=none" \ -d "controller[requirement_collection]=application" \ -d "capabilities[card_payments][requested]=true" \ -d "capabilities[transfers][requested]=true" \ -d business_type=individual \ -d country=US ``` #### With an account type ```curl curl https://api.stripe.com/v1/accounts \ -u "<>:" \ -d type=custom \ -d "capabilities[card_payments][requested]=true" \ -d "capabilities[transfers][requested]=true" \ -d business_type=individual \ -d country=US ``` ## Determine the information to collect [Server-side] As the platform, you must decide if you want to collect the required information from your connected accounts *up front* (Upfront onboarding is a type of onboarding where you collect all required verification information from your users at sign-up) or *incrementally* (Incremental onboarding is a type of onboarding where you gradually collect required verification information from your users. You collect a minimum amount of information at sign-up, and you collect more information as the connected account earns more revenue). Up-front onboarding collects the `eventually_due` requirements for the account, while incremental onboarding only collects the `currently_due` requirements. | Onboarding type | Advantages | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Up-front** | - Normally requires only one request for all information - Avoids the possibility of payout and processing issues due to missed deadlines - Exposes potential risk early when accounts refuse to provide information | | **Incremental** | - Accounts can onboard quickly because they don’t have to provide as much information | To determine whether to use up-front or incremental onboarding, review the [requirements](https://docs.stripe.com/connect/required-verification-information.md) for your connected accounts’ locations and capabilities. While Stripe tries to minimise any impact to connected accounts, requirements might change over time. For connected accounts where you’re responsible for requirement collection, you can customise the behaviour of [future requirements](https://docs.stripe.com/connect/handle-verification-updates.md) using the `collection_options` parameter. To collect the account’s future requirements, set [`collection_options.future_requirements`](https://docs.stripe.com/api/account_links/create.md#create_account_link-collection_options-future_requirements) to `include`. To implement your onboarding strategy, inspect the requirements hash of the connected account you created. The requirements hash provides a complete list of the information you must collect to activate the connected account. - For incremental onboarding, inspect the `currently_due` hash in the requirements hash and build an onboarding flow that only collects those requirements. - For up-front onboarding, inspect the`currently_due` and `eventually_due` hashes in the requirements hash, and build an onboarding flow that collects those requirements. ```json { ... "requirements": { "alternatives": [], "current_deadline": null, "currently_due": [ "business_profile.product_description", "business_profile.support_phone", "business_profile.url", "external_account", "tos_acceptance.date", "tos_acceptance.ip" ], "disabled_reason": "requirements.past_due", "errors": [],"eventually_due": [ "business_profile.product_description", "business_profile.support_phone", "business_profile.url", "external_account", "tos_acceptance.date", "tos_acceptance.ip" ], "past_due": [], "pending_verification": [] }, ... } ``` ## Handle liveness requirements An account can have one or more [Person](https://docs.stripe.com/api/persons.md) objects with a `proof_of_liveness` requirement. A `proof_of_liveness` requirement might require collection of an electronic ID credential, such as [MyInfo](https://www.singpass.gov.sg/main/individuals/) in Singapore, or by using Stripe Identity to collect a document or selfie. We recommend using Stripe-hosted or embedded onboarding to satisfy all variations of the `proof_of_liveness` requirement. #### Hosted [Stripe-hosted onboarding](https://docs.stripe.com/connect/hosted-onboarding.md) can complete all variations of `proof_of_liveness` requirements. [Create an Account Link](https://docs.stripe.com/connect/hosted-onboarding.md#create-account-link) using the connected account ID, and send the account to the `url` returned. ```curl curl https://api.stripe.com/v1/account_links \ -u "<>:" \ -d "account={{CONNECTEDACCOUNT_ID}}" \ --data-urlencode "refresh_url=https://example.com/refresh" \ --data-urlencode "return_url=https://example.com/return" \ -d type=account_onboarding \ -d "collection_options[fields]=currently_due" ``` The account receives a prompt to complete the `proof_of_liveness` requirement, along with any other currently due requirements. Listen to the `account.updated` event sent to your webhook endpoint to be notified when the account completes requirements and updates their information. After the account completes the requirement, the account is redirected to the `return_url` specified. #### Embedded [Embedded onboarding](https://docs.stripe.com/connect/embedded-onboarding.md) can complete all forms of `proof_of_liveness` requirements. When [creating an Account Session](https://docs.stripe.com/api/account_sessions/create.md), enable account onboarding by specifying `account_onboarding` in the `components` parameter. If you don’t need to collect bank account information, disable `external_account_collection`. This typically applies to Connect platforms that want to use third-party external account collection providers. ```curl curl https://api.stripe.com/v1/account_sessions \ -u "<>:" \ -d "account={{CONNECTEDACCOUNT_ID}}" \ -d "components[account_onboarding][enabled]=true" \ -d "components[account_onboarding][features][external_account_collection]=false" ``` After creating the Account Session and [initialising ConnectJS](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#account-sessions), you can render the Account onboarding component in the front end: #### JavaScript ```js // Include this element in your HTML const accountOnboarding = stripeConnectInstance.create('account-onboarding'); accountOnboarding.setOnExit(() => { console.log('User exited the onboarding flow'); }); container.appendChild(accountOnboarding); // Optional: make sure to follow our policy instructions above // accountOnboarding.setFullTermsOfServiceUrl('{{URL}}') // accountOnboarding.setRecipientTermsOfServiceUrl('{{URL}}') // accountOnboarding.setPrivacyPolicyUrl('{{URL}}') // accountOnboarding.setCollectionOptions({ // fields: 'eventually_due', // futureRequirements: 'include', // requirements: { // exclude: ['business_profile.product_description'] // } // }) // accountOnboarding.setOnStepChange((stepChange) => { // console.log(`User entered: ${stepChange.step}`); // }); ``` The account receives a prompt to complete the `proof_of_liveness` requirement, along with any other currently due requirements. Listen to the `account.updated` event sent to your webhook endpoint to be notified when the account completes requirements and updates their information. After the account completes the requirements, ConnectJS calls your `onExit` JavaScript handler. #### Identity You can use [Stripe Identity](https://docs.stripe.com/identity.md) to fulfill a `proof_of_liveness` requirement on a `Person` object by collecting a document and selfie. [Create a VerificationSession](https://docs.stripe.com/api/identity/verification_sessions/create.md). Specify the `related_person` parameter to associate the verification data collected with the `Person` object that requires the `proof_of_liveness`, as shown in the following example. ```curl curl https://api.stripe.com/v1/identity/verification_sessions \ -u "<>:" \ -d type=document \ -d "options[document][require_matching_selfie]=true" \ -d "related_person[account]={{CONNECTEDACCOUNT_ID}}" \ -d "related_person[person]={{PERSON_ID}}" ``` After you create the `VerificationSession`, use the returned `client_secret` to [show the Identity modal to the user](https://docs.stripe.com/identity/verify-identity-documents.md?platform=web&type=modal#show-modal) or redirect the user to the `url`. Verification completion automatically updates the account. We send an `account.updated` event to your webhook endpoint when the account completes the identity check and updates their information. ## Update the connected account [Server-side] [Update the Account object](https://docs.stripe.com/api/accounts/update.md) with new information as your connected account progresses through each step of the onboarding flow. That allows Stripe to validate the information as soon as it’s added. After Stripe confirms acceptance of our terms of service, any change to the `Account` triggers reverification. For example, if you change the connected account’s name and ID number, Stripe reruns verifications. ```curl curl https://api.stripe.com/v1/accounts/{{CONNECTEDACCOUNT_ID}} \ -u "<>:" \ --data-urlencode "business_profile[url]=https://furever.dev" \ -d "tos_acceptance[date]=1609798905" \ -d "tos_acceptance[ip]=8.8.8.8" ``` When updating a connected account, you must handle any [verification errors](https://docs.stripe.com/connect/api-onboarding.md#handle-verification-errors) or [HTTP error codes](https://docs.stripe.com/error-handling.md). ## Handle verification errors [Server-side] When the connected account’s data is submitted, Stripe verifies it. This process might take minutes or hours, depending on the nature of the verification. During this process, the capabilities you requested have a `status` of `pending`. ### Review status You can retrieve the status of your connected account’s capabilities by: - Inspecting the Account object’s [capabilities](https://docs.stripe.com/api/accounts/object.md#account_object-capabilities) hash for the relevant capability. - Requesting capabilities directly from the [Capabilities API](https://docs.stripe.com/api/capabilities/retrieve.md) and inspecting the status of the relevant capability. - Listening for `account.updated` [events](https://docs.stripe.com/api/events/types.md#event_types-account.updated) in your [webhook](https://docs.stripe.com/connect/webhooks.md) endpoint and inspecting the `capabilities` hash for the relevant capability. After verifications are complete, a capability becomes `active` and available to the connected account. Account verifications run continuously, and if a future verification fails, a capability can transition out of `active`. Listen for `account.updated` events to detect changes to capability states. Confirm that your Connect integration is compliant and operational by checking that the account’s `charges_enabled` and `payouts_enabled` are both true. You can use the API or listen for `account.updated` events. For details on other relevant fields, check the account’s [requirements](https://docs.stripe.com/api/accounts/object.md#account_object-requirements) hash. You can’t confirm the integration based on a single value because statuses can vary depending on the application and related policies. - [charges_enabled](https://docs.stripe.com/api/accounts/object.md#account_object-charges_enabled) confirms that your full charge path including the charge and transfer works correctly and evaluates if either `card_payments` or `transfers` capabilities are active. - [payouts_enabled](https://docs.stripe.com/api/accounts/object.md#account_object-payouts_enabled) evaluates whether your connected account can pay out to an external account. Depending on your risk policies, you can allow your connected account to start transacting without payouts enabled. You [must eventually enable payouts](https://docs.stripe.com/connect/manage-payout-schedule.md) to pay your connected accounts. You can use the following logic as a starting point for defining a summary status to display to your connected account. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' def account_state(account) reqs = account.requirements if reqs.disabled_reason && reqs.disabled_reason.include?("rejected") "rejected" elsif account.payouts_enabled && account.charges_enabled if reqs.pending_verification "pending enablement" elsif !reqs.disabled_reason && !reqs.currently_due if !reqs.eventually_due "complete" else "enabled" end else "restricted" end elsif !account.payouts_enabled && account.charges_enabled "restricted (payouts disabled)" elsif !account.charges_enabled && account.payouts_enabled "restricted (charges disabled)" elsif reqs.past_due "restricted (past due)" elsif reqs.pending_verification "pending (disabled)" else "restricted" end end accounts = Stripe::Account.list(limit: 10) accounts.each do |account| puts "#{account.id} has state: #{account_state(account)}" end ``` > You can’t use the API to respond to Stripe risk reviews. You can enable your connected accounts to respond using embedded components, Stripe-hosted onboarding, or remediation links. You can also use the Dashboard to respond to risk reviews on behalf of your connected accounts. Listen to the [account.updated](https://docs.stripe.com/api/events/types.md#event_types-account.updated) event. If the account contains any `currently_due` fields when the `current_deadline` arrives, the corresponding functionality is disabled and those fields are added to `past_due`. [Create a form](https://docs.stripe.com/connect/api-onboarding.md#create-forms-to-collect-information) with clear instructions that the account can use to correct the information. Notify the account, then [submit the corrected information](https://docs.stripe.com/connect/api-onboarding.md#update-the-connected-account) using the Accounts API. (See full diagram at https://docs.stripe.com/connect/api-onboarding) If you plan to create custom flows to handle all your verification errors: - Review the details regarding all possible [verification errors and how to handle them](https://docs.stripe.com/connect/handling-api-verification.md). - [Test verification states](https://docs.stripe.com/connect/testing-verification.md).