Send Bank Account Payouts
This guide sends a payout to a bank account over the ACH network or real-time payment rails.
You need a saved bank account for this guide. Save one with Save Bank Accounts, from your web app or from your servers. Either way you get a bank account id that starts with ba_.
You can also skip saving the bank account and send its details in the payout request. See Create with Bank Account Details.
Before you start
Secret Key- Authenticates requests from your server. Never send it to the browser.
Payout Types
Payouts made to a bank account travel over the ACH network and support three speeds, set via the payout_type field on Create Payout:
standard(default) — A standard ACH transfer. Settles over the standard multi-day ACH timeline.same_day— A same-day ACH transfer. Settles the same business day.instant— Sent over real-time payment rails instead of ACH batch processing, and typically settles within minutes. Requires thepayouts:instantaccount setting to be enabled — see Request Account Setting Access below.
Process the Payout
We will use a saved bank account to create a new payout. A verified bank account is the more reliable choice if you plan to send an instant payout. See Instant Verification.
For example, given this saved bank account:
{
"id": "ba_7Ay5mcUXAxwrN6wQEQUVEHBCJ",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"customer_id": "cus_7Ay5mcUXAxwrN6wQEQUVEHBCJ",
"account_holder_name": "John Doe",
"account_holder_type": "individual",
"account_type": "checking",
"routing_number": "110000000",
"account_number_last4": "1011",
"billing_details": {
"address_line_1": "111 Colorado Ave.",
"address_line_2": "Apt 403",
"city": "Des Moines",
"state": "IA",
"postal_code": "51111",
"country": "US"
},
"created_at": "2024-06-30T01:02:29.212Z",
"modified_at": "2024-06-30T01:02:29.212Z"
}
Request Account Setting Access
instant payouts. Skip it if you're using the default standard or same_day payout types.To use instant payouts, you will need to request access to the payouts:instant account setting type.
To do this, go to the merchant portal and click on the Request this feature button next to the Instant Payouts setting.
Alternatively, you can request access via the API.
Create a Payout
We need to make a call to Create Payout endpoint. Omitting payout_type defaults to standard:
curl 'https://api.publicsquare.com/payouts' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPOTENCY-KEY: 09ec2c87-7fb8-44ca-bb18-5c71a76974da' \
-H 'Content-Type: application/json' \
-d '{
"amount": 1000,
"currency": "USD",
"payment_method": {
"bank_account": "ba_7Ay5mcUXAxwrN6wQEQUVEHBCJ"
},
"customer": {
"first_name": "John",
"last_name": "Smith",
"email": "john.smith@email.com"
},
"billing_details": {
"address_line_1": "111 Test St.",
"city": "Des Moines",
"state": "IA",
"postal_code": "51111",
"country": "US"
}
}'
The amount is in cents. 1000 is $10.00.
Create with Bank Account Details
If you have not saved the bank account yet, you can send its details with the payout. The API saves the bank account and sends the payout in the same request, so you do not need to call Create Bank Account first.
Before you use bank_account_details:
- Your account must have the
payment-methods:bank-accounts:manual-creationaccount setting. See Request Account Setting Access. - A restricted API key must have the
payment-method:writepermission in addition topayout:write. Secret keys have all permissions.
curl 'https://api.publicsquare.com/payouts' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPOTENCY-KEY: 09ec2c87-7fb8-44ca-bb18-5c71a76974da' \
-H 'Content-Type: application/json' \
-d '{
"amount": 1000,
"currency": "USD",
"payment_method": {
"bank_account_details": {
"account_holder_name": "John Doe",
"account_holder_type": "individual",
"account_type": "checking",
"routing_number": "110000000",
"account_number": "000123456789"
}
},
"customer": {
"first_name": "John",
"last_name": "Smith",
"email": "john.smith@email.com"
},
"billing_details": {
"address_line_1": "111 Test St.",
"city": "Des Moines",
"state": "IA",
"postal_code": "51111",
"country": "US"
}
}'
bank_account_detailsaccepts the same fields as Create Bank Account.- Include
account_holder_nameandaccount_holder_type. Some processors require them. - You cannot combine
bank_account_detailswithbank_accountorcard. - If you omit the top-level
customerorbilling_details, the payout uses thecustomer_idandbilling_detailsinsidebank_account_details. - Every
payout_typeworks withbank_account_details, with the same requirements as a saved bank account. - The response returns the saved bank account in
payment_method.bank_account. Use itsidasbank_accountfor later payouts.
Send an IDEMPOTENCY-KEY with each request. If a request fails and you retry it with the same key, the payout uses the bank account that the first
request saved. A retry with the same key and different bank account details returns a 400. Use a new key when you change the bank account details.
{
"title": "Error",
"status": 400,
"detail": "'bank_account_details' differs from the request first sent with this IDEMPOTENCY-KEY."
}
Create a Same-Day or Instant Payout
To use a faster payout type, set payout_type to same_day or instant:
curl 'https://api.publicsquare.com/payouts' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPOTENCY-KEY: 09ec2c87-7fb8-44ca-bb18-5c71a76974da' \
-H 'Content-Type: application/json' \
-d '{
"amount": 1000,
"currency": "USD",
"payout_type": "instant",
"payment_method": {
"bank_account": "ba_7Ay5mcUXAxwrN6wQEQUVEHBCJ"
},
"customer": {
"first_name": "John",
"last_name": "Smith",
"email": "john.smith@email.com"
},
"billing_details": {
"address_line_1": "111 Test St.",
"city": "Des Moines",
"state": "IA",
"postal_code": "51111",
"country": "US"
}
}'
payouts:instant account setting has not been enabled for your account, an instant payout request will fail. See Request Account Setting Access above. same_day payouts require no additional account setup.Create with Existing Customer
If you created a customer, then you can pass its ID as customer.id when processing the payout:
curl 'https://api.publicsquare.com/payouts' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPOTENCY-KEY: 09ec2c87-7fb8-44ca-bb18-5c71a76974da' \
-H 'Content-Type: application/json' \
-d '{
"amount": 1000,
"currency": "USD",
"payment_method": {
"bank_account": "ba_7Ay5mcUXAxwrN6wQEQUVEHBCJ"
},
"customer": {
"id": "cus_7Ay5mcUXAxwrN6wQEQUVEHBCJ"
},
"billing_details": {
"address_line_1": "111 Test St.",
"city": "Des Moines",
"state": "IA",
"postal_code": "51111",
"country": "US"
}
}'
Create with Customer's Payment Method
If you attached the bank account to a customer, then you can omit the customer section when processing the payout:
curl 'https://api.publicsquare.com/payouts' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPOTENCY-KEY: 09ec2c87-7fb8-44ca-bb18-5c71a76974da' \
-H 'Content-Type: application/json' \
-d '{
"amount": 1000,
"currency": "USD",
"payment_method": {
"bank_account": "ba_7Ay5mcUXAxwrN6wQEQUVEHBCJ"
},
"billing_details": {
"address_line_1": "111 Test St.",
"city": "Des Moines",
"state": "IA",
"postal_code": "51111",
"country": "US"
}
}'
Create with Payment Method's Billing Details
If you supplied the billing_details or updated the bank account, then you can omit the billing_details section when processing the payout:
curl 'https://api.publicsquare.com/payouts' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPOTENCY-KEY: 09ec2c87-7fb8-44ca-bb18-5c71a76974da' \
-H 'Content-Type: application/json' \
-d '{
"amount": 1000,
"currency": "USD",
"payment_method": {
"bank_account": "ba_7Ay5mcUXAxwrN6wQEQUVEHBCJ"
}
}'
Each of these request variants works the same way for same_day and instant payouts — just add the corresponding payout_type to the request body.
Payout Response
Given the bank account payout examples, you should see a payout result similar to:
{
"id": "pyt_24NFPd3jSZFTxiaH9UwjuqNdP",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"status": "pending",
"payout_type": "instant",
"transaction_id": "trx_6QgmXzQzk3S5K5EsR3DfEiMRj",
"amount": 1000,
"currency": "USD",
"payment_method": {
"bank_account": {
"id": "ba_7Ay5mcUXAxwrN6wQEQUVEHBCJ",
"status": "verified",
"account_holder_name": "John Doe",
"account_holder_type": "individual",
"account_type": "individual",
"routing_number": "123456789",
"account_number_last4": "1011"
}
},
"customer": {
"id": "cus_7Ay5mcUXAxwrN6wQEQUVEHBCJ",
"first_name": "John",
"last_name": "Smith",
"email": "john.smith@email.com",
},
"billing_details": {
"address_line_1": "111 Test St.",
"city": "Des Moines",
"state": "IA",
"postal_code": "51111",
"country": "US"
},
"transaction": {
"id": "trx_6QgmXzQzk3S5K5EsR3DfEiMRj",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"status": "pending",
"amount": -1000,
"fee_amount": 0,
"net_amount": -1000,
"currency": "USD",
"type_id": "pyt_24NFPd3jSZFTxiaH9UwjuqNdP",
"type": "payout",
"processor": "nuvei",
"processor_id": "7110000000010554769",
"created_at": "2024-06-30T01:02:29.212Z",
"modified_at": "2024-06-30T01:02:29.212Z"
},
"created_at": "2024-06-30T01:02:29.212Z",
"modified_at": "2024-06-30T01:02:29.212Z"
}
The payout's status is pending immediately after creation, and the response's payout_type reflects the speed you requested. For instant payouts, the terminal succeeded or declined status typically arrives via the payout:update webhook much sooner than standard or same_day payouts.
Handling Declines
If a payout is declined, the response's declined_reason will contain the reason available at the time of the decline. When the receiving bank returns the payout, declined_reason contains the ACH return code and its description, for example R03 - No Account/Unable to Locate Account. The linked bank account's status may also change as a result of the decline. See Bank Accounts.
Conclusion
Now that we have sent a payout to a bank account, we may need to cancel it or view information about it. Follow these guides to learn more: