Skip to main content

Process ACH Payouts

Now that you have completed the Collect Bank Accounts guide, let's process an ACH payout with the newly captured bank account.

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 the payouts:instant account setting to be enabled — see Request Account Setting Access below.

Getting Started​

To get started, you will need a Credova Account.

Get your Secret Key​

Next you will need your Secret Key. Go to your Developers section and click Reveal for your Secret Key and copy the value.

Save the Secret Key as it will be used in the next steps of this guide.

Request Account Setting Access​

This section only applies if you plan to use 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.

Process the Payout​

We will need to use the information from the previously collected bank account to create a new payout. A verified bank account is the more reliable choice if you plan to send an instant payout — if you haven't already, complete the Collect Verified Bank Accounts guide first.

For example, given you have a previously collected 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"
}

Create a Payout​

We need to make a call to Create Payout endpoint. Omitting payout_type defaults to standard:

Create a Payout
curl 'https://api.publicsquare.com/payouts' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPONTENCY-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 provided in cents. 1000 is the equivalent of $10.00
The IDEMPONTENCY-KEY header can be passed to protect against duplicate payouts being processed.

Create a Same-Day or Instant Payout​

To use a faster payout type, set payout_type to same_day or instant:

Create an Instant Payout
curl 'https://api.publicsquare.com/payouts' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPONTENCY-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"
}
}'
If the 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 the customer_id when processing the payout:

Create a Payout with Customer
curl 'https://api.publicsquare.com/payouts' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPONTENCY-KEY: '09ec2c87-7fb8-44ca-bb18-5c71a76974da' \
-H 'Content-Type: application/json' \
-d '{
"amount": 1000,
"currency": "USD",
"payment_method": {
"bank_account": "ba_7Ay5mcUXAxwrN6wQEQUVEHBCJ"
},
"customer": {
"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:

Create a Payout with Payment Method
curl 'https://api.publicsquare.com/payouts' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPONTENCY-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:

Create a Payout with Payment Method
curl 'https://api.publicsquare.com/payouts' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPONTENCY-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 above 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. The linked bank account's status may also change as a result of the decline. See Bank Accounts.

Conclusion​

Now that we have seen how to process payouts with a collected bank account, we may need to manage the payout or view information about the payout. Follow these guides to learn more: