ACH payment

Hey👋. We recommend checking out the overview 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 charge, depending on the bank account's currency/country:

  1. Direct debit (for Nigerian accounts): The customer authorizes the payment with their bank, and the money is debited from their account.
  2. UK (GBP) accounts: The customer logs in to their bank's Internet/mobile banking and makes a transfer to a generated bank account.
  3. 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 hi@flutterwavego.com for approval.

Process

To charge a bank account in the US or South Africa:

  1. You send the payment details to the charge endpoint.
  2. The customer then makes the transfer from their bank's Internet banking platform, and we notify you when it's done.
  3. 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 more details, such as the customer's phone_number and custom meta information.

The currency you specify must match the account's currency ( USD or ZAR ).

Next, you'll send 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: 'user@example.com',
    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" => 'user@example.com',
    "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: 'user@example.com',
    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": "user@example.com",
     "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": "user@example.com",
      "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": "user@flw.com",
      "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": "user@flw.com",
      "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 customer with whatever they paid for. See our guide to transaction verification for details.

Loading...