ACH
Learn how you can accept payment with ACH.
Getting Started
We recommend checking out the introductory section to understand the basics of direct charge first. This guide assumes you’ve read that.
Charging Bank Accounts
Direct account charge allows you to collect payments directly from your customers' bank accounts.
There are three "flavours" of direct bank account charges, depending on the bank account's currency/country:
- Direct debit (for Nigerian accounts): The customer authorizes the payment with their bank, and the money is debited from their account.
- UK (GBP accounts): The customer logs in to their bank's Internet/mobile banking and makes a transfer to a generated bank account.
- ACH payment (for USD and ZAR accounts).
This guide covers ACH payments. See the guides for NG accounts and UK accounts.
Approval Required
To receive payments from US accounts, your merchant account needs to be approved. Contact us at [email protected] for approval.
The Process
To charge a bank account in the US or South Africa:
- You send the payment details to the charge endpoint.
- The customer then makes the transfer from their bank's Internet banking platform, and we notify you when it's done.
- You can then call our API to verify that the payment was successful before giving value (the verify transaction endpoint).

Initiating the Payment
To initiate the charge, you'll need to specify amount
, currency
, email
, and a unique tx_ref
. You can also specify additional information like customer's phone_number
and custom meta
information.
Selecting Supported Currencies and Banks
This payment method only supports
USD
andZAR
payments.
Next, you'll end these payment details to the charge via ACH endpoint. Here are some examples with our SDKs:
# US Account
curl --request POST \
--url https://api.flutterwave.com/v3/charges?type=ach_payment \
--header 'Authorization: Bearer YOUR_SECRET_KEY' \
--header 'content-type: application/json' \
--data '{
"amount": 250,
"currency": "USD",
"email": "[email protected]",
"tx_ref": "ACH1234567x01"
}'
// Install with: npm i flutterwave-node-v3
const Flutterwave = require('flutterwave-node-v3');
const flw = new Flutterwave(
process.env.FLW_PUBLIC_KEY,
process.env.FLW_SECRET_KEY
);
const payload = {
amount: 250,
currency: 'USD',
email: '[email protected]',
tx_ref: this.generateTransactionReference(),
};
await flw.Charge.ach(payload);
// Install with: composer require flutterwavedev/flutterwave-v3
$flw = new \Flutterwave\Rave(getenv('FLW_SECRET_KEY'));
// Set `PUBLIC_KEY` as an environment variable
$achChargeService = new \Flutterwave\Ach();
$payload = [
"type" => "ach_payment",
"amount" => 250,
"currency" => 'USD',
"email" => '[email protected]',
"tx_ref" => $this->generateTransactionReference(),
];
$response = $achChargeService->achCharge($payload);
# Install with: gem install flutterwave_sdk
require 'flutterwave_sdk'
flw = Flutterwave.new(ENV["FLW_PUBLIC_KEY"], ENV["FLW_SECRET_KEY"], ENV["FLW_ENCRYPTION_KEY"])
account_payment = AccountPayment.new(flw)
payload = {
amount: 250,
currency: 'USD',
email: '[email protected]',
tx_ref: generate_transaction_reference,
}
# Automatically uses the right endpoint based on the currency
response = account_payment.initiate_charge payload
ZAR Payments
ACH payments in South Africa can only be made through the supported banks listed below.
S/N | Bank Name | Bank Code |
---|---|---|
1 | ABSA | ABSA |
2 | African Bank | AfricanBank |
3 | Bidvest Bank | Bidvest |
4 | First National Bank | FNB |
5 | Investec Bank | Investec |
6 | Nedbank Limited | Nedbank |
7 | Standard Bank | Standard |
8 | Tyme Bank | Tyme |
# ZAR Account
curl --request POST \
--url https://api.flutterwave.com/v3/charges?type=ach_payment \
--header 'Authorization: Bearer YOUR_SECRET_KEY' \
--header 'content-type: application/json' \
--data '{
"tx_ref":"YOUR_UNIQUE_REFERENCE",
"amount":"100",
"currency":"ZAR",
"country":"ZA",
"email":"[email protected]",
"phone_number":"08056789051",
"fullname":"John Doe"
}'
You can also specify the bank by including the sa_bank_code
parameter in your payment request. This redirects the customer to their preferred bank’s interface to complete the charge. To retrieve the correct bank code, use the Get Banks endpoint.
# ZAR Account
curl --request POST \
--url https://api.flutterwave.com/v3/charges?type=ach_payment \
--header 'Authorization: Bearer YOUR_SECRET_KEY' \
--header 'content-type: application/json' \
--data '{
"tx_ref":"YOUR_UNIQUE_REFERENCE",
"amount":"100",
"currency":"ZAR",
"country":"ZA",
"email":"[email protected]",
"phone_number":"08056789051",
"fullname":"John Doe",
"sa_bank_code": "ABSA"
}'
Handling the Response
If all goes well, you'll get a response that looks like this:
{
"status": "success",
"message": "Charge initiated",
"data": {
"id": 4962269,
"tx_ref": "ACH1234567x01",
"flw_ref": "FKYJ50811710276768063172919",
"device_fingerprint": "62wd23423rq324323qew1",
"amount": 100,
"charged_amount": 100,
"app_fee": 3.4,
"merchant_fee": 0,
"processor_response": "Request Accepted",
"auth_model": "AUTH",
"currency": "USD",
"ip": "54.75.161.64",
"narration": "Flutterwave Developers",
"status": "pending",
"auth_url": "https://mx-middleware.dev-flutterwave.com/transactions?reference=FKYJ50811710276768063172919",
"payment_type": "account-ach-us",
"fraud_status": "ok",
"charge_type": "normal",
"created_at": "2024-03-12T20:52:47.000Z",
"account_id": 20937,
"customer": {
"id": 2006690,
"phone_number": "0902620185",
"name": "Yolande Aglaé",
"email": "[email protected]",
"created_at": "2023-03-21T14:22:25.000Z"
},
"meta": {
"authorization": {
"mode": "redirect",
"redirect": "https://mx-middleware.dev-flutterwave.com/transactions?reference=FKYJ50811710276768063172919",
"validate_instructions": ""
}
}
}
}
{
"status": "success",
"message": "Charge initiated",
"data": {
"id": 593421312,
"tx_ref": "ref-1585230ew9v5050e8-abcdefg-10",
"flw_ref": "ACH64190164701343961",
"device_fingerprint": "N/A",
"amount": 10,
"charged_amount": 10.25,
"app_fee": 0.25,
"merchant_fee": 0,
"processor_response": "Transaction in progress",
"auth_model": "AUTH",
"currency": "ZAR",
"ip": "52.18.161.235",
"narration": "Globus Technologies",
"status": "pending",
"auth_url": "https://pay.ozow.com/6ab3a781-1b4f-490d-964b-e07bda58a105/Secure",
"payment_type": "account",
"fraud_status": "ok",
"created_at": "2022-03-11T15:43:59.000Z",
"account_id": 82913,
"customer": {
"id": 223898841,
"phone_number": "0902620185",
"name": "Yemi Desola",
"email": "[email protected]",
"created_at": "2020-09-17T13:07:36.000Z"
},
"account": {
"account_number": "0000000000",
"bank_code": "000",
"first_name": "Yemi",
"last_name": "Desola"
},
"meta": {
"authorization": {
"mode": "redirect",
"redirect": "https://pay.ozow.com/6ab3a781-1b4f-490d-964b-e07bda58a105/Secure",
"validate_instructions": ""
}
}
}
}
Completing the Payment
To complete the payment, the customer makes the transfer, typically from their bank's Internet banking platform.
When the payment is completed, we'll send you a webhook notification. Here's what that looks like:
{
"event": "charge.completed",
"data": {
"id": 593416278,
"tx_ref": "ref-1585230ew9v5050e8-abcdefg-10",
"flw_ref": "ACH97785164701281024",
"device_fingerprint": "N/A",
"amount": 100,
"currency": "ZAR",
"charged_amount": 102.5,
"app_fee": 2.5,
"merchant_fee": 0,
"processor_response": "Transaction cancelled by user",
"auth_model": "AUTH",
"ip": "54.154.184.168",
"narration": "Globus Technologies",
"status": "failed",
"payment_type": "account",
"created_at": "2022-03-11T15:33:30.000Z",
"account_id": 82913,
"customer": {
"id": 223898841,
"name": "Yemi Desola",
"phone_number": "0902620185",
"email": "[email protected]",
"created_at": "2020-09-17T13:07:36.000Z"
},
"account": {
"account_name": "Yemi Desola",
"account_number": "0000000000",
"bank_code": "000"
}
},
"meta_data": {},
"event.type": "ACCOUNT_TRANSACTION"
}
In your webhook handler, you can then verify the payment and credit your customers with whatever they paid for. See our guide to transaction verification for details.
Updated 11 days ago