Legacy
Moving money using OutboundTransfer objects Legacy
Learn how to transfer money out of financial accounts to external accounts.
Legacy integration
The v1 version of Treasury for platforms is a legacy integration that doesn’t support many of the features introduced in Treasury for platforms v2. Don’t build a new v1 integration.
An OutboundTransfer object facilitates money movement out of a financial account. Use OutboundTransfer to send funds over ACH rails or through a domestic wire transfer to an external bank account that a connected account owns.
Outbound transfers typically arrive at the receiving bank between the same day and 2 business days, depending on whether you use a wire or ACH.
Note
Multi FA beta If enrolled in the Multi FA beta, you can use OutboundTransfer to send funds over stripe network rails to another financial account associated with the same connected account. Funds arrive in the destination financial account within minutes.
For more information, see the Money movement timelines guide.
OutboundTransfers support the us_bank_account type of payment method. Alternatively, you can use an existing BankAccount that belongs to the business as an ExternalAccount.
Create an OutboundTransfer
Use POST /the relevant part of the product to create an OutboundTransfer for the financial account with the associated ID. Among the request’s possible parameters, four are required:
- amount : Amount of transfer in cents.
- currency : Three-letter ISO currency code.
- financial _ account : Source financial account ID to pull funds from.
- destination _ payment _ method : Destination PaymentMethod ID or BankAccount ID to receive funds.
- destination _ payment _ method _ data : Financial account to receive funds.
{
// The source financial account to pull funds from.
"financial_account": "{{FINANCIAL_ACCOUNT_ID}}",
// The amount to send. 10.00 USD in this case.
"amount": 1000,
"currency": "usd",
// The destination PaymentMethod or BankAccount.
// This should be nil if destination_payment_method is set.
"destination_payment_method_data": {
"type": "financial_account", // us_bank_account is not supported
"financial_account": "{{FINANCIAL_ACCOUNT_ID}}"
},
// This should be nil if destination_payment_method_data is set.
"destination_payment_method": "{{PAYMENT_METHOD_ID}}" | "{{BANK_ACCOUNT_ID}}",
// Optionally, to explicitly specify a network, override the `network` value
// This should be nil if destination_payment_method_data is set.
"destination_payment_method_options": {
"us_bank_account": {
"network": "ach" | "us_domestic_wire"
}
},
// A description visible on the external bank statement.
"statement_descriptor": "Bank xfer",
// An optional internal description to identify this OutboundTransfer
"description": "Transfer to my external account",
// Stripe doesn't support updating originated transfers after creation.
// You can only set metadata at creation.
"metadata": nil | Hash,
}
The following request creates an OutboundTransfer on an account-attached PaymentMethod with the source of funds coming from the identified financial account.
Command Line
Select a language
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
If successful, the response returns the newly created OutboundTransfer object.
{
"id": "{{OUTBOUND_TRANSFER_ID}}",
"object": "outbound_transfer",
"amount": 1000,
"cancelable": true,
"created": 1648479987,
"currency": "usd",
"description": null,
"destination_payment_method": "{{PAYMENT_METHOD_ID}}" | null,
"destination_payment_method_details": {
Same-day ACH
Same-day ACH enables faster settlement for outbound transfers, with funds arriving the same business day.
Private preview
Same-day ACH is in preview with limited availability. To request access, email . API calls that include same-day ACH parameters return an error until access is granted.
Using same-day ACH enables sending funds that arrive the same business day if the OutboundTransfer call successfully completes before the cutoff time. To use same-day ACH, set the destination_payment_method_options.us_bank_account.network parameter to ach and the destination_payment_method_options.us_bank_account.ach.submission parameter to same_day.
Wire transfer: routing numbers
Some banks might use a separate wire transfer routing number that differs from ACH. Consequently, you might receive an error during wire creation if the routing number on the payment method doesn’t support wire transfers. If you receive this error, you need to add a new payment method with your bank’s wire routing number.
Wire transfer: recipient address
Wire transfers require ACH metadata plus recipient name and billing address. The address is the address of the account holder receiving the wire, not the address of their bank.
When entering the billing_details.address for a payment method, all address fields must be complete. Attempting to send a wire with incomplete fields on the billing_details.address results in an error.
Note
When sending a wire using an OutboundTransfer, if you don’t fill out any address fields, Stripe defaults to the legal entity of the primary Stripe account holder.
Retrieve an OutboundTransfer
Use GET /the relevant part of the product/{{the related setting}} to retrieve details for the OutboundTransfer with the associated ID.
The following request retrieves the OutboundTransfer with the associated ID, expanding the details of the Transaction.
Command Line
Select a language
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
If successful, the response returns the OutboundTransfer object with the associated ID. Some of the parameters in the response have additional details that are only returned when you add them as values to the expand[] parameter. The fields that you can expand have an “Expandable” comment in the following response example. See Expanding Responses to learn more about expanding object responses.
Select a language
JSON (commented)
JSON
No results
{
"id": "{{OUTBOUND_TRANSFER_ID}}",
"object": "outbound_transfer",
"livemode": Boolean,
"created": Timestamp,
"financial_account": "{{FINANCIAL_ACCOUNT_ID}}", // Expandable
"amount": 1000,
"currency": "usd",
"destination_payment_method": "{{PAYMENT_METHOD_ID}}",
"description": "Transfer to my external account",
Cancel an OutboundTransfer
Use POST /the relevant part of the product/{{the related setting}}/cancel to cancel the OutboundTransfer with the associated ID. The OutboundTransfer object includes a cancelable parameter with a Boolean value to indicate whether you can cancel the transfer. After an OutboundTransfer submits to the network, the cancelable value becomes false and you receive an error from this endpoint for that transfer.
Command Line
Select a language
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
If successful, the response returns the OutboundTransfer object with a status of canceled.
{
"id": "{{OUTBOUND_TRANSFER_ID}} ",
"object": "outbound_transfer",
"amount": 1000,
"cancelable": false,
"created": 1648487177,
"currency": "usd",
...
"status": "canceled",
"status_transitions": {
"canceled_at": 1648487198,
"failed_at": null,
"posted_at": null,
"returned_at": null
},
"transaction": "{{TRANSACTION_ID}}"
}
List OutboundTransfers
Use GET /the relevant part of the product to list the OutboundTransfers sent from the financial account with the ID of the financial_account parameter. You can filter the list with the standard list parameters or by status.
{
// Standard list parameters
"limit", "starting_after", "ending_before",
// Filter by status
"status": "processing" | "posted" | "failed" | "returned" | "canceled",
// Filter by FinancialAccount (Required)
"financial_account": "{{FINANCIAL_ACCOUNT_ID}}",
}
The following request retrieves OutboundTransfers from the financial account identified. The included parameters limit the response to the first three transfers after the OutboundTransfer with the provided ID.
Command Line
Select a language
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
If successful, the response returns a list of OutboundTransfer objects that satisfy any filtering conditions.
OutboundTransfer states
The following table describes each status for OutboundTransfers and what the possible transition states are.
| the related setting | the related setting | the related setting TO the related setting |
|---|---|---|
processing | The OutboundTransfer starting state. Funds are allotted to a pending transaction (but are still part of the current balance). The user can cancel the OutboundTransfer while the value of the cancelable parameter is true. | posted, canceled, failed |
canceled (terminal) | A user canceled the OutboundTransfer before posting. Stripe voids the pending transaction and returns the funds to the user. | N/A |
posted | Stripe has adjusted the Financial Account balance and determined the OutboundTransfer is unlikely to be returned. | returned |
returned (terminal) | The OutboundTransfer failed to successfully arrive at the destination (for example, due to incorrect account details). Stripe returns the funds to the user with returned_details[transaction]. | N/A |
failed (terminal) | The OutboundTransfer failed to be sent to the network. Stripe voids the pending transaction and returns the funds to the user. Stripe might use this state to indicate internal errors. | N/A |
Test OutboundTransfers
In testing environments, you can specify the destination_payment_method as a test payment method. You can create your own test PaymentMethods or use our test IDs when testing your integration.
| the related setting | the related setting | the related setting the related setting |
|---|---|---|
us_bank_account | Default, transitions to posted. | pm_usBankAccount |
us_bank_account | Transitions to posted, adds one day to the original expected_arrival_date. | pm_usBankAccount_expectedArrivalDateUpdated |
us_bank_account | Remains in processing. | pm_usBankAccount_processing |
us_bank_account | Transitions to canceled. | pm_usBankAccount_canceledByUser |
us_bank_account | Transitions to failed. | pm_usBankAccount_internalFailure |
us_bank_account | Transitions to returned with returned_details.code="no_account". | pm_usBankAccount_noAccount |
us_bank_account | Transitions to returned with returned_details.code="account_closed". | pm_usBankAccount_accountClosed |
us_bank_account | Transitions to returned with returned_details.code="invalid_account_number". | pm_usBankAccount_invalidAccountNumber |
In all cases, the OutboundTransfer response is in the processing state. Stripe triggers webhooks for the relevant state transitions, and fetching the OutboundTransfer after creation returns the expected state.
OutboundTransfer test helper endpoints
Stripe provides endpoints to help you test OutboundTransfers in different states. After creating an OutboundTransfer, use these endpoints to move the OutboundTransfer directly to a new state of posted, failed, canceled, or returned.
- Use the test post endpoint to move the identified
OutboundTransferfromprocessingtoposted.POST /the relevant part of the product/{{the related setting}}/post - Use the test fail endpoint to move the identified
OutboundTransferfromprocessingtofailed.POST /the relevant part of the product/{{the related setting}}/fail - Use the test return endpoint to move the identified
OutboundTransferfrompostedtoreturned.POST /the relevant part of the product/{{the related setting}}/return
These endpoints are particularly useful when testing error scenarios, such as returns, which would otherwise require outside action.
For the return endpoint, include the optional returned_details.code parameter in the body to indicate why the transfer was returned. If not provided, the transfer defaults to the declined return code.
{
"returned_details": {
"code": "account_closed" |
"account_frozen" |
"bank_account_restricted" |
"bank_ownership_changed" |
"could_not_process" |
"invalid_account_number" |
"incorrect_account_holder_name" |
"invalid_currency" |
"no_account" |
"declined"
}
}
We also provide a test update endpoint to simulate the posting of tracking details on a test Outbound Transfer. The tracking_details field can only be set for test objects.
In all cases, Stripe triggers webhooks for each relevant state transition, and fetching the OutboundTransfer after transition returns the expected state.
OutboundTransfer webhooks
Stripe emits the following OutboundTransfer events to your webhook endpoint:
- treasury. outbound _ transfer. created on OutboundTransfer creation.
- treasury. outbound _ transfer. {{new _ status}} when an OutboundTransfer changes status. Available status value options include:
- treasury. outbound _ transfer. posted
- treasury. outbound _ transfer. failed
- treasury. outbound _ transfer. returned
- treasury. outbound _ transfer. canceled
- treasury. outbound _ transfer. expected _ arrival _ date _ updated when the expected _ arrival _ date of an OutboundTransfer changes.
- treasury. outbound _ transfer. tracking _ details _ updated when the tracking details for an OutboundTransfer are updated.
