Legacy
Moving money using OutboundPayment objects Legacy
Learn how to create outbound payments to move money out of financial accounts to third parties.
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.
OutboundPayment objects represent push-based transfers from your financial account to a third-party external account using ACH or wire transfer, or another financial account associated with the same platform instantly using the stripe network. For example, if you want to send money from your financial account to your vendor’s external US bank account, you create an OutboundPayment to move the funds. The receiving accounts for an OutboundPayment are either an external bank account or another financial account.
The typical transfer time for outbound payments can range from minutes (when using the Stripe network), same day, to 1-2 business days (when using the ACH network). For more information, see the Money movement timelines guide.
Create an OutboundPayment
Use POST /the relevant part of the product to create an OutboundPayment. Among the request’s possible parameters, the following are required:
- amount : Amount in cents to pay.
- currency : Three-letter ISO currency code (only usd supported).
- financial _ account : The source financial account funds are sent from.
- destination _ payment _ method or destination _ payment _ method _ data : Information about the destination of funds for the payment.
- With destination _ payment _ method , you must first set up the PaymentMethod for outbound flows using a SetupIntent . You must also specify the customer ID that matches the Customer object the PaymentMethod is attached to. Alternatively, you can use an existing legacy [BankAccount](/the relevant part of the product) attached to the Customer in place of a PaymentMethod .
- With destination _ payment _ method _ data , you can specify payment method details inline. You can use this parameter to specify bank account details or when you’re sending funds to another financial account over the Stripe network.
Create an OutboundPayment to an external bank account
Use POST /the relevant part of the product to create an OutboundPayment from the financial account identified by the ID in the financial_account parameter value of the body. The following request adds statement_descriptor and destination_payment_method_data information.
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 OutboundPayment.
Select a language
JSON (commented)
JSON
No results
{
"id": "{{OUTBOUND_PAYMENT_ID}}",
"object": "outbound_payment",
// The source FinancialAccount. Funds are pulled from this account.
"financial_account": "{{FINANCIAL_ACCOUNT_ID}}",
// The amount to send. 10.00 USD in this case.
"amount": 1000,
"cancelable": true | false,
"currency": "usd",
// The destination payment method. Either this or `destination_payment_method_data`
Same-day ACH
Same-day ACH enables faster settlement for outbound payments, 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 OutboundPayment 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.
the related setting payroll compliance
the related setting requires originators to explicitly identify ACH payments intended for payroll. When sending an OutboundPayment, set the purpose parameter to payroll to ensure compliance with this requirement.
Create an OutboundPayment to a financial account
To move money between financial accounts, call POST /the relevant part of the product on the origin account and specify the destination account in the destination_payment_method_data parameter. Both financial accounts must be associated with the same platform, but can’t be associated with the same connected account. To transfer money between financial accounts associated with the same connected account, use an OutboundTransfer.
Command Line
Select a language
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
The body of your request must be x-www-form-urlencoded, but the following JSON defines the data you can send.
Select a language
JSON (commented)
JSON
No results
{
// The source FinancialAccount. Funds are pulled from this account.
"financial_account": "{{SOURCE_FINANCIAL_ACCOUNT_ID}}",
// The amount to send.
"amount": 1000,
"currency": "usd",
// The destination payment method. This parameter is the only way to
// send an OutboundPayment through the `stripe` network.
"destination_payment_method_data": {
"type": "financial_account",
Retrieve an OutboundPayment
Use GET /the relevant part of the product/{{the related setting}} to retrieve details for the OutboundPayment with the associated ID.
Command Line
Select a language
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
If successful, the response returns the OutboundPayment 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_PAYMENT_ID}}",
"object": "outbound_payment",
"livemode": true | false,
"created": "{{Timestamp}}",
"financial_account": "{{FINANCIAL_ACCOUNT_ID}}", // Expandable
"amount": 1000,
"currency": "usd",
// Will only be set if `destination_payment_method` was used during the creation of
// the OutboundPayment
Cancel an OutboundPayment
Use POST /the relevant part of the product/{{the related setting}}/cancel to cancel the OutboundPayment with the associated ID. The OutboundPayment object includes a cancelable parameter with a Boolean value to indicate whether you can cancel the transfer. After an OutboundPayment 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 OutboundPayment object with the status value set to canceled.
{
"id": "{{OUTBOUND_PAYMENT_ID}}",
"object": "outbound_payment",
"livemode": false,
"created": 123456,
"financial_account": "{{FINANCIAL_ACCOUNT_ID}}",
"amount": 1000,
"currency": "usd",
...
"status": "canceled",
List OutboundPayments
Use GET /the relevant part of the product to list the OutboundPayments from the financial account with the associated ID. You can filter the list with the standard list parameters or by status or by customer.
{
// Standard list parameters
"limit", "starting_after", "ending_before",
// Filter by status
"status": "processing" | "canceled" | "failed" | "posted" | "returned",
// Filter by FinancialAccount (Required)
"financial_account": "{{FINANCIAL_ACCOUNT_ID}}",
// Filter by Customer
"customer": "{{CUSTOMER_ID}}",
}
The following request retrieves the last five OutboundPayment objects for the financial account attached to the platform and paid to the identified Customer.
Command Line
Select a language
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
OutboundPayment states
The following table describes each status and what the possible transition states are.
| the related setting | the related setting | CAN the related setting TO the related setting |
|---|---|---|
processing | The OutboundPayment starting state. Funds are allotted to a pending transaction (but are still part of the current balance). The user can cancel the OutboundPayment while the value of the cancelable parameter is true. | posted, canceled, failed |
failed (terminal) | OutboundPayment failed to confirm. Stripe voids the pending transaction and returns the funds to the user. | N/A |
canceled (terminal) | A user canceled the OutboundPayment before posting. Stripe voids the pending transaction and returns the funds to the user. | N/A |
posted | The OutboundPayment posted and funds have left the account. The underlying transaction posts. | returned |
returned (terminal) | OutboundPayment failed to successfully arrive at the destination. Funds return to the user with a transaction ( returned_details[transaction]). | N/A |
Test OutboundPayments
To test your integration end-to-end, we recommend using test SetupIntent requests to create a PaymentMethod, then passing that PaymentMethod into an OutboundPayment creation request using the destination_payment_method parameter.
Stripe also allows test PaymentMethod tokens and numbers to trigger specific functionality:
- By passing in a test PaymentMethod token to destination _ payment _ method (for ach and us _ domestic _ wire networks)
- If you’re passing in a test PaymentMethod token directly into destination _ payment _ method , you must still pass in a customer ID to the customer parameter. For convenience, Stripe allows you to pass in any existing test customer. This differs from live mode, which requires the existing PaymentMethod to be attached to a Customer and that same customer ID passed into the customer parameter.
- By passing in test routing and account numbers to destination _ payment _ method _ data[us _ bank _ account] (for ach and us _ domestic _ wire networks).
- By passing in the ID of an existing test financial account owned by an intra-platform account to destination _ payment _ method _ data[financial _ account] (for Stripe network).
In all cases, the OutboundPayment response returns the processing status. Stripe triggers webhooks for the relevant state transitions, and fetching the OutboundPayment after creation returns the expected state.
| the related setting | the related setting (WITH ANY the related setting the related setting the related setting) | the related setting[the related setting] |
|---|---|---|
OutboundPayment in initial processing state | pm_usBankAccount_processing | routing_number: 110000000 account_number: 000000000009 |
OutboundPayment that transitions to posted (from processing) | pm_usBankAccount | routing_number: 110000000 account_number: 000123456789 |
OutboundPayment that transitions to posted (from processing), additionally adding one day to the original expected_arrival_date | pm_usBankAccount_expectedArrivalDateUpdated | routing_number: 110000000 account_number: 000123457890 |
OutboundPayment that transitions to canceled (from processing) | pm_usBankAccount_canceledByUser | routing_number: 110000000 account_number: 000000000123 |
OutboundPayment that transitions to failed (from processing) | pm_usBankAccount_internalFailure | routing_number: 110000000 account_number: 000000000234 |
OutboundPayment that transitions to returned due to account closure (from processing after posted) | pm_usBankAccount_accountClosed | routing_number: 110000000 account_number: 000111111113 |
OutboundPayment that transitions to returned due to no account (from processing after posted) | pm_usBankAccount_noAccount | routing_number: 110000000 account_number: 000111111116 |
OutboundPayment that transitions to returned due to invalid account number (from processing after posted) | pm_usBankAccount_invalidAccountNumber | routing_number: 110000000 account_number: 000111111119 |
OutboundPayment test helper endpoints
Stripe provides endpoints to help you test OutboundPayments in different states. Use the test endpoints to move an OutboundPayment you create directly to a new state of posted, failed, or returned.
- Use the test post endpoint to move the identified
OutboundPaymentfromprocessingtoposted.POST /the relevant part of the product/{{the related setting}}/post - Use the test fail endpoint to move the identified
OutboundPaymentfromprocessingtofailed.POST /the relevant part of the product/{{the related setting}}/fail - Use the test return endpoint to move the identified
OutboundPaymentfromprocessingtoreturned.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 Payment. 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 OutboundPayment after transition returns the expected state.
OutboundPayment webhooks
Stripe emits the following OutboundPayment events to your webhook endpoint:
- treasury. outbound _ payment. created on OutboundPayment creation.
- treasury. outbound _ payment. {{new _ status}} when an OutboundPayment changes status. Available status value options include:
- treasury. outbound _ payment. posted
- treasury. outbound _ payment. failed
- treasury. outbound _ payment. canceled
- treasury. outbound _ payment. returned
- treasury. outbound _ payment. expected _ arrival _ date _ updated when the expected _ arrival _ date of an OutboundPayment changes.
- treasury. outbound _ payment. tracking _ details _ updated when the tracking details for an OutboundPayment are updated.
