Sending Transfers

Transfer funds received from credit cards to third-party bank accounts or debit cards. If you need help after reading this, check out our answers to common questions or chat live with other developers in #stripe on freenode.

Once you’ve received payments through Stripe, you can create transfers through the API to send funds to arbitrary third-party bank accounts or debit cards.

This feature is currently only available for US Stripe accounts. When sending to a bank account, the recipient's bank account must be in the US. When sending to a debit card, transfers must be less than $3000, and the recipient's card must be a US Visa or Mastercard debit card that is not prepaid.

Stripe sends automatic transfers to your bank account on a two-day rolling basis. Once you switch to manual transfers, though, you’ll no longer receive automatic Stripe transfers. Payments you receive will instead accumulate in your Stripe balance. The funds from a payment will become available for you to pay out to third parties (or yourself) after two days.

Collecting recipient details

You can send transfers to one of two destinations: a bank account or a debit card. With either, you’ll also need to collect a legal name. The recipient name is required for the compliance checks that Stripe performs, such as matching against the OFAC list. If the recipient is an individual, you’ll need to collect their full legal name; if they’re a business, the legal corporation name.

In either case, the easiest way to collect this information is to use Stripe.js to tokenize the details. For a bank account, grab the account token on your server in the POST parameters (submitted by your form) and use that token to create a recipient:

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

# Get the bank account details submitted by the form
token_id = params[:stripeToken]

# Create a Recipient
recipient = Stripe::Recipient.create(
  :name => "John Doe",
  :type => "individual",
  :email => "payee@example.com",
  :bank_account => token_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"

# Get the bank account details submitted by the form
token_id = request.POST['stripeToken']

# Create a Recipient
recipient = stripe.Recipient.create(
  name="John Doe",
  type="individual",
  email="payee@example.com",
  bank_account=token_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");

// Get the bank account details submitted by the form
$token_id = $_POST['stripeToken'];

// Create a Recipient
$recipient = \Stripe\Recipient::create(array(
  "name" => "John Doe",
  "type" => "individual",
  "bank_account" => $token_id,
  "email" => "payee@example.com")
);
// 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";

// Get the bank account details submitted by the form
String tokenID = request.getParameter("stripeToken");

// Create a Recipient
Map<String, Object> recipientParams = new HashMap<String, Object>();
recipientParams.put("name", "John Doe");
recipientParams.put("type", "individual");
recipientParams.put("bank_account", tokenID);
recipientParams.put("email", "payee@example.com");

Recipient recipient = Recipient.create(recipientParams);
// 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");

// Get the bank account details submitted by the form
var token_id = request.body.stripeToken; // Using Express

// Create a Recipient
stripe.recipients.create({
  name: "John Doe",
  type: "individual",
  bank_account: token_id,
  email: "payee@example.com"
}, function(err, recipient) {
  // recipient;
});

The process is similar for debit cards using Stripe.js. Grab the debit card information from your POST parameters to create a recipient:

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

# Get the card details submitted by the form
token_id = params[:stripeToken]

# Create a Recipient
recipient = Stripe::Recipient.create(
  :name => "John Doe",
  :type => "individual",
  :email => "payee@example.com",
  :card => token_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"

# Get the card details submitted by the form
token_id = request.POST['stripeToken']

# Create a Recipient
recipient = stripe.Recipient.create(
  name="John Doe",
  type="individual",
  email="payee@example.com",
  card=token_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");

// Get the card details submitted by the form
$token_id = $_POST['stripeToken'];

// Create a Recipient
$recipient = \Stripe\Recipient::create(array(
  "name" => "John Doe",
  "type" => "individual",
  "card" => $token_id,
  "email" => "payee@example.com")
);
// 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";

// Get the card details submitted by the form
String tokenID = request.getParameter("stripeToken");

// Create a Recipient
Map<String, Object> recipientParams = new HashMap<String, Object>();
recipientParams.put("name", "John Doe");
recipientParams.put("type", "individual");
recipientParams.put("card", tokenID);
recipientParams.put("email", "payee@example.com");

Recipient recipient = Recipient.create(recipientParams);
// 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");

// Get the card details submitted by the form
var token = request.body.stripeToken; // Using Express

// Create a Recipient
stripe.recipients.create({
  name: "John Doe",
  type: "individual",
  card: token,
  email: "payee@example.com"
}, function(err, recipient) {
  // recipient;
});

Verifying recipients

It’s important that you verify the identity of anyone receiving transfers, and that the name you’re sending to Stripe is the full legal name of the recipient. If a recipient receives a large volume of transfers, or if there are any anomalies, we may require further information. We’ll contact you if that’s the case.

The broader context here is that there are many laws around money transmission in order to guard against money laundering, terrorist financing, etc. Stripe does its best to make it easy for you to build great products, using simple abstractions, while handling as much of the compliance burden as possible.

Creating transfers

Once you’ve created a recipient, you can initiate a transfer with a single API call. While doing so, you can also specify the description that appears on the recipient’s account statement.

The returned transfer object describes the status of the transfer and specifies when the transfer should be available in the destination bank account or debit card account.

To transfer money to a bank account:

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

# Create a transfer to the specified recipient
transfer = Stripe::Transfer.create(
  :amount => 1000, # amount in cents
  :currency => "usd",
  :recipient => recipient_id,
  :bank_account => bank_account_id,
  :statement_descriptor => "JULY SALES"
)
# 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"

# Create a transfer to the specified recipient
transfer = stripe.Transfer.create(
    amount=1000, # Amount in cents
    currency="usd",
    recipient=recipient_id,
    bank_account=bank_account_id,
    statement_descriptor="JUNE SALES"
)
// 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");

// Create a transfer to the specified recipient
$transfer = \Stripe\Transfer::create(array(
  "amount" => 1000, // amount in cents
  "currency" => "usd",
  "recipient" => $recipient_id,
  "bank_account" => $bank_account_id,
  "statement_descriptor" => "JULY SALES")
);
// 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");

// Create a transfer to the specified recipient
Map<String, Object> transferParams = new HashMap<String, Object>();
transferParams.put("amount", 1000); // amount in cents
transferParams.put("currency", "usd");
transferParams.put("recipient", recipientId);
transferParams.put("bank_account", bankAccountId);
transferParams.put("statement_descriptor", "JULY SALES");

Transfer transfer = Transfer.create(transferParams);
// 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");

// Create a transfer to the specified recipient
stripe.transfers.create({
  amount: 1000, // amount in cents
  currency: "usd",
  recipient: recipientId,
  bank_account: bank_account_id,
  statement_descriptor: "JULY SALES"
}, function(err, transfer) {
  // transfer;
});

The API call is similar for transferring to a debit card:

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

# Create a transfer to the specified recipient
transfer = Stripe::Transfer.create(
  :amount => 1000, # amount in cents
  :currency => "usd",
  :recipient => recipient_id,
  :card => card_id,
  :statement_descriptor => "JULY SALES"
)
# 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"

# Create a transfer to the specified recipient
transfer = stripe.Transfer.create(
    amount=1000, # Amount in cents
    currency="usd",
    recipient=recipient_id,
    card=card_id,
    statement_descriptor="JUNE SALES"
)
// 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");

// Create a transfer to the specified recipient
$transfer = \Stripe\Transfer::create(array(
  "amount" => 1000, // amount in cents
  "currency" => "usd",
  "recipient" => $recipient_id,
  "card" => $card_id,
  "statement_descriptor" => "JULY SALES")
);
// 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";

// Create a transfer to the specified recipient
Map<String, Object> transferParams = new HashMap<String, Object>();
transferParams.put("amount", 1000); // amount in cents
transferParams.put("currency", "usd");
transferParams.put("recipient", recipientId);
transferParams.put("card", cardId);
transferParams.put("statement_descriptor", "JULY SALES");

Transfer transfer = Transfer.create(transferParams);
// 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");

// Create a transfer to the specified recipient
stripe.transfers.create({
  amount: 1000, // amount in cents
  currency: "usd",
  recipient: recipientId,
  card: cardId,
  statement_descriptor: "JULY SALES"
}, function(err, transfer) {
  // transfer;
});

Note that if the recipient only has one card, you may omit the card parameter. However, if your recipient has both a card and a bank account associated, you will need to either pass in the card or bank_account parameter.

Transfer timeline

Unlike charging a credit card, sending a transfer is not synchronous. For bank accounts, transfers will be available in the bank account the next business day if created before 21:00 UTC. If the transfer fails (due to a typo in the bank details, for example), it can take up to five business days for Stripe to be notified.

Transfers to debit cards can take 1 to 2 days to complete. However, unlike with bank accounts, we'll know instantaneously if the debit card is not valid when it is added to the recipient.

Here’s what the flow looks like:

  • A transfer is created via the API. At this point, the transfer’s status is pending.
  • You receive a transfer.paid webhook when the transfer is expected to be available in the recipient’s bank account or debit card. However, this webhook does not guarantee that the transfer was actually successful.
  • If the transfer fails, you’ll receive a transfer.failed webhook within five business days (that’s unfortunately how long some banks take to return transfers) and the transfer will be marked as failed.
  • You can safely assume the transfer was successful if you don’t receive a transfer.failed webhook within five business days.

Handling transfer failures

If a transfer fails, it will most likely be because of incorrect bank account or debit card details. You should update the recipient object with the correct details and retry the transfer.

Sending transfers to yourself

Once you enable manual transfers, Stripe will no longer send automatic transfers to your bank account (if we did, there’d be no funds left for you to pay others out with!). You need to explicitly create a transfer if you’d like to transfer funds from your Stripe balance to your bank account.

If you set the recipient of the transfer as self, the transfer will be sent to the bank account associated with your Stripe account. There are no fees for these transfers.

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

# Create a transfer to the bank account associated with your Stripe account
transfer = Stripe::Transfer.create(
  :amount => 1000, # amount in cents
  :currency => "usd",
  :recipient => "self",
  :statement_descriptor => "JULY SALES"
)
# 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"

# Create a transfer to the bank account associated with your Stripe account
transfer = stripe.Transfer.create(
    amount=1000, # Amount in cents
    currency="usd",
    recipient="self",
    statement_descriptor="JUNE SALES"
)
// 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");

// Create a transfer to the bank account associated with your Stripe account
$transfer = \Stripe\Transfer::create(array(
  "amount" => 1000, // amount in cents
  "currency" => "usd",
  "recipient" => "self",
  "statement_descriptor" => "JULY SALES")
);
// 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");

// Create a transfer to the bank account associated with your Stripe account
Map<String, Object> transferParams = new HashMap<String, Object>();
transferParams.put("amount", 1000); // amount in cents
transferParams.put("currency", "usd");
transferParams.put("recipient", "self");
transferParams.put("statement_descriptor", "JULY SALES");

Transfer transfer = Transfer.create(transferParams);
// 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");

// Create a transfer to the bank account associated with your Stripe account
stripe.transfers.create({
  amount: 1000, // amount in cents
  currency: "usd",
  recipient: "self",
  statement_descriptor: "JULY SALES"
}, function(err, transfer) {
  // transfer;
});

Testing

You can use our test bank account numbers, debit card numbers, and tax IDs to test sending transfers.

Errors

Invalid bank account

You’ll get an error when creating a recipient if the routing number does not correspond to a valid US bank account. For account numbers, we won’t know if the account exists until a successful transfer is made.

{
  "error": {
    "message": "Not a valid US routing number",
    "type": "invalid_request_error"
  }
}

Insufficient funds

If the funds in your Stripe account aren’t enough to cover a transfer, the transfer will not be created:

{
  "error": {
    "message": "Insufficient funds in Stripe account",
    "type": "invalid_request_error"
  }
}

Invalid debit card

You’ll get an error when creating a recipient if the debit card number isn't a US Mastercard or Visa debit card. The card cannot be prepaid.

{
  "error": {
    "message": "This card doesn't appear to be a non-prepaid Visa or Mastercard debit card.",
    "type": "invalid_request_error"
  }
}