ACH Payment
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.For South African ACH payments, you can specify the bank by passing
sa_bank_code
in your payment request. Please retrieve the correct bank code from the get banks endpoint.
Next, you'll end these payment details to the charge via ACH endpoint. Here are some examples with our SDKs:
// 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
# 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"
}'
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 about 1 month ago