Recipient to Account Migrations

    Learn how to migrate your existing recipients to Connect. If you need help after reading this, check out our answers to common questions or chat live with other developers in #stripe on freenode.

    Recipients were deprecated in March 2015 and will be removed from the Stripe API during the first half of 2017. The replacement is Connect, a powerful set of tools for verifying and paying individuals & businesses through Stripe. If your business currently relies on Recipients, you need to migrate to using Connect as soon as possible. You may have already received communications from Stripe with a timeline and next steps for the transition.

    After the Recipients API has been removed, anyone receiving funds through Stripe must have a Stripe account. With Connect, you’ll be able to convert your existing Recipients to Managed Accounts and, with careful testing, be able to seamlessly transition your existing recipients.

    To help you transition, we created a migration path for turning your Recipient objects into Account objects. This guide is designed to address common questions about moving to Connect from Transfer Recipients, help you work through your integration changes, and ease your business’s transition to the new API.

    Terminology

    In Connect terms, anyone getting paid is a “provider”, who:

    • Has their own Stripe account.
    • Provides the good or performs the service being sold.

    Your business is the “platform” through which providers conduct their business. For example, if you have an on-demand taxi service, the “platform” runs the application which allows customers to book a ride, and the “provider” is the driver who picks up the customer and provides the service. When the ride is complete, the platform pays the provider from funds collected from the customer’s credit card.

    Your platform creates a Managed Account for each provider who is paid through your application or service. A managed account is a Stripe account but, unlike a standalone account, does not have access to the Stripe dashboard. All access to Stripe is managed by and mediated through your platform and Stripe integration. Similar to a Recipient, a Managed Account is used to moved funds from Stripe to a bank account or debit card.

    Each platform can charge an Application Fee as part of payments made to the provider. Continuing the taxi example, the platform might collect 10% of each ride as an “application fee”. This fee should be charged at the time the good or service is paid for.

    Stripe Connect

    At a high level, Connect (with Managed Accounts) offers many advantages over the Recipients API:

    • Accounting is built into Connect. It is straightforward to track available account balances and transactions across all of your connected Stripe accounts. You’re no longer mixing your operating funds with funds designated for your sellers. You can send a transfer to a managed account by making a single API call.

    • More powerful features: Every new feature we add to Stripe is immediately available to your providers. You’re able to take advantage of features like custom statement descriptors for each account, automatic transfers, and Instant Payouts

    • New accounts follow a straightforward verification process, and you are able to collect information from the account as needed rather than ask for it all up front.

    • With Connect, you can pay providers in a growing number of countries—anywhere Stripe is available. This allows you to expand your business into new markets without significant engineering effort.

    • As a Connect platform, you have full control over the payment flow. For a given refund, you can choose to have your provider pay the refund, or pay the refund from your platform directly. You also choose whether or not you refund your platform’s fee on the transaction. Previously, with recipients, tracking these type of refunds could only be reconciled with manual programming and accounting.

    • Connect provides a full account history for each connected account, which simplifies the design of any reporting tools, reducing the amount of complexity in your application.

    Example Migration Project Plan

    User-Facing Communications

    1. Update your existing Terms of Service to include or link to the Stripe Connected Account Agreement.
    2. Audit existing recipients, find inactive users, determine how many should be migrated to Connect.
    3. Notify existing users of your Terms of Service update.

    Engineering Changes

    1. Register your Connect platform on your Dashboard.
    2. Verify that your account meets the necessary API and Bindings Versions to use all features of Managed Accounts.
    3. Update your application to use the Connect APIs. Before replacing your existing Recipient code, you should use Managed Accounts for all new providers on your platform, allowing you to test and debug your Connect implementation without breaking your existing payment flow.
    4. Establish a Connect Webhook for your Platform.
    5. Build and test Managed Account verification flow.
    6. Begin to use Managed Accounts for all new providers on your platform.
    7. Audit existing recipients, find inactive users, determine how many will be migrated.
    8. Migrate a small batch of recipients.
      • Migrating over a few recipients at a time and dealing with errors as they happen will allow you to fix problems with your Connect integration gradually rather than dealing with a variety of different errors all at once.
    9. Correct any problems with verification flow.
    10. Continue to migrate over small batches.
    11. Once all recipients are migrated, remove inactive Recipients code from your codebase.

    Required API & Bindings Versions

    Connect with Managed Accounts may require that you upgrade the Stripe API version on your account. If possible, try to upgrade to the newest available version (2016-07-06 or later). The minimum API version for Managed Accounts is 2014-12-17.

    Caution: upgrading the API version on your Stripe account may cause your existing implementation to break. Please read through API Upgrades for a summary of API changes and proceed with caution.

    Verify your API version from your Dashboard. If you have more than one account—for example, an extra account for testing—be sure that you check the API settings on your platform’s account.

    Rather than set the new version from your Dashboard, we recommend setting your code to use a specific version. This allows you test the version upgrade without changing the version for your entire account. Later, when you’re satisfied that your implementation works with the latest API version, go ahead and upgrade your API version through the Dashboard.

    You may also need to update the version of the Stripe bindings you’re using in order to use all of the features of Connect. While it’s best to use the latest versions of the Stripe libraries, here are the minimum supported versions for using Connect with Managed Accounts:

    Binding Recommended Minimum  
    stripe-ruby 1.57.1 or later 1.19.0
    stripe-python 1.43.0 or later 1.19.0
    stripe-php 4.3.0 or later 3.10.0
    stripe-java 3.5.0 or later 1.27.0
    stripe-node 4.14.0 or later 3.7.0
    stripe-go 19.0.1 or later 6.0.0 Always sets the required API version.

    API differences

    There are several differences between the Managed Accounts you’ll be switching to and the recipients you currently use:

    • Accounts have balances. Whereas with recipients you would transfer funds directly from your balance to a recipient’s bank account, accounts hold their own balances. This introduces an extra conceptual step: funds are transferred to the managed account’s Stripe balance (normally as part of the charge request), and then the funds are paid out from that balance to their bank account. This enables Stripe to automatically handle many payout models automatically. For example, you can use Stripe to payout recipients on a weekly basis with no additional work: simply set the account to weekly payouts, and Stripe will accumulate balances for the account as payments come in, paying them to the bank account on the schedule you specify.
    • When transfering to an account, you should usually specify the destination at charge time (though you may keep a portion of this as an application_fee). While Stripe supports transfers directly from your balance to a third-party account’s balance, this should be done fairly infrequently. If you are unable to determine which managed account receives the funds at charge time, Stripe may not be able to support your business model.

    Payment Flow Changes

    One major change with Connect is that—except in special circumstances—each payment made to a Managed Account must be linked to an original charge by a customer. By linking each transfer to a customer purchase, you can clearly track the movement of money through your platform, which simplifies both your accounting and compliance flow.

    Unlike Recipients, Connect is designed to have the transfer to the managed account happen at the time of purchase. Previously, your application may have tracked the amount due to each provider, keeping payments in your Stripe account balance until you were ready to pay each recipient. With Connect, your platform is paid through Application Fees, and the transfer to the connected account happens automatically during the charge.

    For each charge, your application specifies an “application fee” that is immediately transferred to your platform’s Stripe balance. For example, if your taxi service collects $2.50 for each ride booked through your app, that $2.50 is your “application fee”. Stripe’s processing fees are deducted from the application fees you collect.

    While the transfer to your provider’s Stripe balance happens immediately, transfers to your provider’s bank accounts can happen either automatically, or on a manual schedule defined by your software. In general, any funds paid to a managed account must be transferred out to their bank account within 30 days. See Transfers for more details.

    This guide focuses on the use of Destination Charges, which allow you create the necessary charge, transfer, and application fee at the time of purchase with a single API call.

    API Differences

    With Recipients, your payment flow looked something like this (in Ruby):

    # First: create the charge
    Charge::create(source => "tok_xxx", amount => 1000)
    
    # Later: transfer funds to the recipient, less $2.00 fee to platform
    Transfer::create(amount => 800, destination => "rp_198249abl281izck")
    

    With Connect, this is now handled with a single Create Charge API call with the destination parameter:

    curl https://api.stripe.com/v1/charges \
       -u {PLATFORM_SECRET_KEY}: \
       -d amount=1000 \
       -d currency=usd \
       -d source="{TOKEN}" \
       -d destination="{CONNECTED_STRIPE_ACCOUNT_ID}"
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    Stripe::Charge.create({
      :amount => 1000,
      :currency => "usd",
      :source => {TOKEN},
      :destination => {CONNECTED_STRIPE_ACCOUNT_ID}
    })
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    stripe.Charge.create(
      amount=1000,
      currency="usd",
      source={TOKEN},
      destination={CONNECTED_STRIPE_ACCOUNT_ID}
    )
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    \Stripe\Charge::create(array(
      'amount' => 1000,
      'currency' => 'usd',
      'source' => {TOKEN},
      'destination' => {CONNECTED_STRIPE_ACCOUNT_ID}
    ));
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";
    
    Map<String, Object> chargeParams = new HashMap<String, Object>();
    chargeParams.put("amount", 1000);
    chargeParams.put("currency", "usd");
    chargeParams.put("source", {TOKEN});
    chargeParams.put("destination", {CONNECTED_STRIPE_ACCOUNT_ID});
    
    Charge.create(chargeParams);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    stripe.charges.create({
      amount: 1000,
      currency: 'usd',
      source: {TOKEN},
      destination: {CONNECTED_STRIPE_ACCOUNT_ID}
    });
    

    When you use the destination parameter, the following objects are created immediately in the Stripe API:

    • The entire amount of the charge will be immediately transferred to the destination account. The ID of the resulting transfer will be returned in the transfer field of the response.
    • The Stripe fee comes out of the charge object on the platform’s account (i.e., you pay the fee).
    • The amount specified by the application_fee parameter (if provided) will be deducted from the total amount and credited to the platform’s account.

    The destination account receives a charge object. The platform account will have the charge object and a transfer (the transfer is tied to the destination account’s charge). The platform account will have an application fee object, too, if an application fee was set. Note, as well, that the Stripe fee is paid by the platform account in this case.

    This may seem complicated, but such complexity is necessary to handle many edge cases of currency conversion and possible refunds. This structure allows each part of the flow to be refunded independently of others. For example, you can choose to refund the charge to a customer’s credit card with or without reversing the transfer to the connected account, and with or without reversing the application fee you took.

    The following are also true when creating charges with the destination parameter: - The charge will be attributed to the destination account for tax reporting. - When using a token as the payment source, the token must be created using the platform’s publishable key. If charging a Customer object, the Customer must exist within the platform’s account. - The charge will be settled in the default currency of the destination account. The platform will also take its application_fee in this currency, accumulating balances in the currency of the destination account. If the platform does not have a bank account in this currency, the platform may manually convert these balances to another currency.

    Issuing refunds on charges

    Destination charges created on the platform account can be refunded using the platform account's secret key:

    curl https://api.stripe.com/v1/charges/{CHARGE_ID}/refunds \
       -u {PLATFORM_SECRET_KEY}: \
       -d amount=1000
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    ch = Stripe::Charge.retrieve(CHARGE_ID)
    ch.refunds.create(:amount => 1000)
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    ch = stripe.Charge.retrieve(CHARGE_ID)
    ch.refunds.create(amount=1000)
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    $ch = \Stripe\Charge::retrieve(CHARGE_ID);
    $ch->refunds->create(array('amount' => 1000));
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";
    
    Charge ch = Charge.retrieve(CHARGE_ID);
    
    Map<String, Object> refundParams = new HashMap<String, Object>();
    refundParams.put("amount", 1000);
    
    ch.refund(refundParams);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    stripe.charges.createRefund(
      CHARGE_ID,
      {amount: 1000},
      function(err, refund) {}
    );
    

    When refunding a charge that has a destination value, by default the destination account will keep 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:

    curl https://api.stripe.com/v1/charges/{CHARGE_ID}/refunds \
       -u {PLATFORM_SECRET_KEY}: \
       -d amount=1000 \
       -d reverse_transfer=true
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    ch = Stripe::Charge.retrieve(CHARGE_ID)
    ch.refunds.create(:amount => 1000, :reverse_transfer => true)
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    ch = stripe.Charge.retrieve(CHARGE_ID)
    ch.refunds.create(amount=1000, reverse_transfer=true)
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    $ch = \Stripe\Charge::retrieve(CHARGE_ID);
    $ch->refunds->create(array('amount' => 1000, 'reverse_transfer' => true));
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";
    
    Charge ch = Charge.retrieve(CHARGE_ID);
    
    Map<String, Object> refundParams = new HashMap<String, Object>();
    refundParams.put("amount", 1000);
    refundParams.put("reverse_transfer", true);
    
    ch.refund(refundParams);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    stripe.charges.createRefund(
      CHARGE_ID,
      {amount: 1000, reverse_transfer: true},
      function(err, refund) {}
    );
    

    When you use the reverse_transfer parameter, a proportional amount of the transfer will be reversed to cover the refund. If the refund_application_fee parameter is also set to true:

    • If the refund results in the entire charge being refunded, your application fees will also be refunded
    • Otherwise, a proportional amount of the application fee will be refunded to the Connected account

    If you want to charge a variable fee that is unknown at the time of the charge, collect the largest amount upfront and then refund the difference using application fee refunds. You can access the application fee ID and object via the application_fee parameter returned as part of the charge object.

    Stripe Fees & Refunds

    As with Recipients, Stripe fees are charged against your platform account. Be sure to set your application fee with this in mind. To have your managed accounts pay the Stripe processing fees, you can calculate Stripe’s fee and add it to your application fee when creating a charge.

    For a given refund, Stripe will refund the processing fee in proportion to the amount refunded. For example, if you make a $10 charge, and then refund $5, Stripe will refund half of the processing fee. Likewise, if you make a $10 charge and refund it completely, Stripe will refund all processing fees. With destination charges it’s important to note that the fee refund is credited to the platform account.

    Migrating existing recipients

    Stripe provides a new endpoint for turning any recipient into an account. Stripe will copy over the identity details, verification state, and bank account or debit card information, although we will not migrate historical transfer data. This migration will also put the recipient in read-only mode. Any Recipient object that has been migrated to an Account object can no longer be used for updates or transfers: you must use the new account instead.

    To migrate a recipient to an account, make a POST request to /v1/accounts, passing the existing recipient ID:

    curl https://api.stripe.com/v1/accounts \
       -u {PLATFORM_SECRET_KEY}: \
       -d from_recipient="{RECIPIENT_ID}"
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    # Caution! This makes the Recipient object read-only and disables
    # transfers to the recipient.
    account = Stripe::Account.create({
      from_recipient: 'rp_198249abl281izck'
    })
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    # Caution! This makes the Recipient object read-only and disables
    # transfers to the recipient.
    account = stripe.Account.create(
      from_recipient='rp_198249abl281izck'
    )
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    // Caution! This makes the Recipient object read-only and disables
    // transfers to the recipient.
    $account = \Stripe\Account::create(array(
      "from_recipient" => "rp_198249abl281izck"
    ));
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";
    
    // Caution! This makes the Recipient object read-only and disables
    // transfers to the recipient.
    Map<String, Object> accountParams = new HashMap<String, Object>();
    accountParams.put("from_recipient", "rp_198249abl281izck");
    
    Account account = Account.create(accountParams);
    
        // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    // Caution! This makes the Recipient object read-only and disables
    // transfers to the recipient.
    stripe.accounts.create({
      from_recipient: "rp_198249abl281izck"
    }, function(err, account) {
      // asynchronously called
    });
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.Key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    // Caution! This makes the Recipient object read-only and disables
    // transfers to the recipient.
    acc, err := account.New(&stripe.AccountParams{
      FromRecipient: "rp_198249abl281izck",
    })
    

    The request returns an Account object as described here. The Recipient object will now be read-only, and will contain a reference to the newly created account:

    curl https://api.stripe.com/v1/recipients/{RECIPIENT_ID} \
       -u {PLATFORM_SECRET_KEY}:
    
    {
      "id": "{RECIPIENT_ID}",
      ...
      "migrated_to": "{STRIPE_ACCOUNT_ID}"
    }

    Verification for Migrated Recipients

    Before migrating any Recipients, be sure you’ve read and understood Managed Account Verification. We designed the migration process to allow you to create a Managed Account from a Verified Recipient without needing to collect information. However, in some cases you will need to collect information at the time of migration — these are detailed below.

    Stripe will let you know what information is required in the fields_needed property of the managed account. When this information is required, Stripe will send an account.updated event with details on what information you need to collect, and when the information is due by. It may take Stripe a few minutes to verify the identity information you submit via the update account endpoint, so it is best to rely on your Connect webhook to know about changes to your managed account’s verification status.

    Verified Recipient, Individual

    When you migrate a Verified Recipient for an individual (not a business) (that is, a Recipient whose verified property is true, and type is individual) to a Managed Account, the account will be immediately active for charges and transfers to the associated bank account. At some point, when you have paid this account approximately $4–7k in volume, Stripe will require you to collect the following information:

    • Home Address

    In a minority of cases, Stripe may also ask for the managed account owner’s tax ID (SSN or EIN in the United States) and date of birth.

    Verified Recipient, Business

    When you migrate a Verified Recipient for a business to a Managed Account, the account will be immediately active for charges and transfers to the associated bank account. At some point, when this account has been paid $4–7k in volume, Stripe will require you to collect the following information:

    • The name, date of birth, and address of a representative of the business.

    Unverified Recipient (Individual)

    When you migrate an Unverified Recipient (individual) to a Managed Account, the account will be active for charges and transfers to the associated bank account. At some point, when you have paid this account approximately $4–7k in volume, Stripe will require you to collect the following information about the individual:

    • Home address
    • Date of birth
    • Last 4 digits of their Social Security Number (SSN)

    If Stripe is unable to verify the individual based on that information, we may ask that you provide the individual’s full SSN or a copy of a government-issued photo ID.

    Unverified Recipient (Business)

    When you migrate an Unverified Recipient (individual) to a Managed Account, the account will be active for charges, however, transfers will be disabled to the associated bank account. To enable transfers, you will need to provide the name of a of the business representative.

    At some point, when you have paid this account approximately $4–7k in volume, Stripe will require you to collect the following information about the individual:

    • The date of birth, and address of a representative of the business.
    • The business’s Employer Identification Number (EIN)

    Creating a new account

    To create a new account (as opposed to creating a recipient), use the same /v1/accounts endpoint, but provide more information than you would when creating a recipient:

    curl https://api.stripe.com/v1/accounts \
       -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
       -u {PLATFORM_SECRET_KEY}: \
       -d country=US \
       -d managed=true \
       -d legal_entity[type]=individual \
       -d legal_entity[first_name]=Bob \
       -d legal_entity[last_name]=Smith \
       -d legal_entity[dob][day]=20 \
       -d legal_entity[dob][month]=7 \
       -d legal_entity[dob][year]=1969 \
       -d external_account=EXTERNAL_ACCOUNT_TOKEN
    

    Note the managed=true parameter, which is necessary to indicate that the account will not be able to log in to the Stripe Dashboard. Bear in mind that country is a required parameter and cannot be changed after account creation. All parameters after this are optional and may be provided at later dates. The external_account parameter can be either a hash of bank account details, a bank account token obtained from Stripe.js, or a debit card token obtained from Stripe.js.

    To enable transfers, you must provide at least the name and date of birth. (Learn more about Managed Accounts.)

    Transferring Funds

    With Connect, you must specify who will receive the funds at charge time, as discussed above under Payment Flow Changes.

    By default, Stripe will pay out available funds to the third-party’s bank account on a rolling basis as funds become available, usually 2 days for Managed Accounts in the U.S. (Learn more about processing charges.)

    If you need to pay out additional funds, for example as a bonus for reaching certain goals, you may do so via the Transfers API. For example:

    curl https://api.stripe.com/v1/transfers \
       -u {PLATFORM_SECRET_KEY}: \
       -d amount=1000 \
       -d currency=usd \
       -d destination="{CONNECTED_STRIPE_ACCOUNT_ID}"
    

    However, you should mainly rely on application fees and “destination” charges as a means of moving money between your platform and your managed accounts.

    Again, with this new design, it should be fairly uncommon to need to transfer funds directly from your Stripe account to another. (Learn more about sending transfers.)

    Updating an account

    In order to keep an account in good standing, Stripe may ask for additional information. It is your obligation to collect this information from the user, and provide it to Stripe. To do this, you should listen for the account.updated event via Connect webhooks. When you receive an account.updated event, you’ll want to check the received data for three relevant fields:

    {
      "verification": {
        "fields_needed": [
          "legal_entity.address.line1",
          "legal_entity.address.city",
          "legal_entity.address.state",
          "legal_entity.address.postal_code",
          "legal_entity.ssn_last_4"
        ],
        "due_by": 1488229200,
        "contacted": false
      }
    }

    In this example, Stripe is requesting the address and last four digits (last 4) of the Social Security number, and informing you that you have three days to provide it—with the usual consequence that Stripe will pause transfers for the account if the information is not received in time. See the managed account guide for more details on these fields.

    In the United States, the name, date of birth, address, and last four digits of the Social Security number is usually, but not always, sufficient to fully verify an identity.

    When implementing this flow, it may be helpful to refer to the Handling Identity Verification Notifications for Managed Accounts recipe. This recipe demonstrates emailing your providers in response to Stripe account.updated notifications.

    Accounting & Reporting

    Following the recommended flow in Payment Flow Changes eliminates the need to manage a “pool” or “float” of balances in your platform account. Instead, for each charge, Stripe automatically transfers funds to your provider’s Stripe account balance. Rather than managing a pool of balances in your own software, you can track your Managed Account balances through the Stripe API. Just like your platform account, accounting entries are exposed to your application through Balance Transaction objects and the Balance History API.

    A common task here is to create a view for managed accounts in your app which replicates what Stripe shows in the “Transfers” section of the Dashboard, showing charges, refunds, fees, and other transactions associated with a transfer. This is possible by passing the transfer property to the list balance history API endpoint.

    For more on this, see: How can I find the charges and other transactions associated with each transfer?

    Now that you're migrated

    Read more about what you can do with your connected accounts.