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.

If you’ve previously used Stripe to transfer money to third-parties, you’ve likely created Recipient objects to represent your users. With Connect, we have deprecated recipients and replaced the functionality with Accounts. Existing integrations continue to work, but it is no longer documented or maintained.

To help you transition, we created a migration path for turning your Recipient objects into Account objects. This guide will also help you convert your current integration to a new integration, using the new API.

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 recipient’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 a lot more 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 transfering directly from your balance to a third-party account’s balance, this should be done fairly infrequently. If you are unable to determine the recipient of funds at charge time, Stripe may not be able to support your business model currently.

Changes required

To start using Managed Accounts you must first activate your account as a platform. You must also be on at least version “2014-12-17” of the API. If you’re on an older version, please upgrade before migrating to Managed Accounts.

Additionally, you must have all of your users agree to Stripe’s Services Agreement. For example, you can usually update your terms to include a reference to Stripe’s terms, and properly notify users of the change. However, Stripe cannot provide legal advice on what constitutes agreement to the terms; you should consult an attorney. It is your responsibility to ensure that your users have properly agreed to these terms.

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 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}"

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}"
}

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 login. 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 or a bank account 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

The strongly preferred way to transfer funds to a third-party is to specify the recipient of funds at charge time. You may do this using the destination parameter. For example, to charge $10 USD, keeping $2 USD for yourself and sending $8 USD to another account:

curl https://api.stripe.com/v1/charges \
   -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
   -u {PLATFORM_SECRET_KEY}: \
   -d customer="{STRIPE_CUSTOMER_ID}" \
   -d amount=1000 \
   -d currency=usd \
   -d destination="{CONNECTED_STRIPE_ACCOUNT_ID}" \
   -d application_fee=200

(The Stripe fees will come out of the platform account’s $2.)

This will, by default, 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 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.

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}"

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": 1481608800,
    "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.

Now that you're migrated

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