Pay with Bank (NG)

Debit your Customer's Bank account

Pay with Bank (PWB), also referred to as direct debit, provides a seamless, reliable option for customers to complete transactions directly from their bank accounts using Mono's bank connection page.

🚧

Feature Availability

This payment method is only available for NGN (Nigerian Naira) collections.

Requirements

You should ensure that these requirements are met before you proceed to integrate this feature:

  1. Read the introduction before you continue with this guide.
  2. Retrieve your API keys from your dashboard.
  3. Configure your webhooks to manage payment status updates.

How PWB payments work.

When a customer chooses to pay using the bank account payment method, they are redirected to Mono's secure authorization page. From Mono's page, the customer selects their bank from a list of supported financial institutions and authorizes the transaction using the method supported by their bank, such as internet banking, mobile banking, OTP, a hardware token, or bank USSD code.

Once authorized, the bank debits the customer's account, and the customer is redirected back to your specified redirect_url while Flutterwave sends a successful webhook to your server.


Payment Flow

To collect payments from customers using Pay With Bank Account, follow these steps:

  1. Collect the customer's information to initiate the charge. Providing an email is required, while the name, address, and phone are optional at this stage.
  2. Create the bank account payment method by specifying the type as bank_account.
  3. Create the charge by specifying the customer_id, payment_method_id,amount, reference, currency, and redirect_url .
  4. Redirect the customer to the URL returned in thedata.next_action.redirect_url(Mono's page) object to select their respective banks and authorize the payment.
  5. Verify the payment status, amount, customer_id and transaction_id using webhooks and the retrieve a charge API before providing the value to the customer.

Steps to collecting bank account payments with Flutterwave.

🚧

Integration method

This guide follows the general integration flow. Please refer to the orchestrator flow for the alternative integration method.

Step 1: Create a customer

To create a new customer, send a request to the create customer endpoint including the name, email, phone, address, etc. Only the customer's email is required to create a customer entity; however, we recommend that you collect as much information as you can.

You can also use the retrieve a customer endpoint to query and fetch a customer's information. This is helpful if you wish to initiate charges for returning or existing customers.

curl --request POST \
  --url 'https://developersandbox-api.flutterwave.com/customers' \
  --header 'Authorization: Bearer {{YOUR_ACCESS_TOKEN}}' \
  --header 'Content-Type: application/json' \
  --header 'X-Trace-Id: {{YOUR_UNIQUE_TRACE_ID}}' \
  --header 'X-Idempotency-Key: {{YOUR_UNIQUE_IDEMPOTENCY_KEY}}' \
  --data '{
    "address": {
      "city": "Gotham",
      "country": "US",
      "line1": "221B Baker Street",
      "line2": "321B Hazard Avenue",
      "postal_code": "94105",
      "state": "Colorado"
    },
    "name": {
      "first": "Derek",
      "middle": "Jones",
      "last": "Blue"
    },
    "phone": {
      "country_code": "233",
      "number": "9012345678"
    },
    "email": "[email protected]"
  }'

{
    "status": "success",
    "message": "Customer created",
    "data": {
        "id": "cus_Gh5xysiG40",
        "address": {
            "city": "Gotham",
            "country": "US",
            "line1": "221B Baker Street",
            "line2": "321B Hazard Avenue",
            "postal_code": "94105",
            "state": "Colorado"
        },
        "email": "[email protected]",
        "name": {
            "first": "Derek",
            "middle": "Jones",
            "last": "Blue"
        },
        "phone": {
            "country_code": "233",
            "number": "9012345678"
        },
        "meta": {},
        "created_datetime": "2026-08-07T14:41:52.180Z"
    }
}


Step 2: Create a bank account payment method

Create a Bank Account payment method by sending a request to the create a payment method endpoint. In your request, set the type to bank_account.

curl --request POST \
  --url 'https://developersandbox-api.flutterwave.com/payment-methods' \
  --header 'Authorization: Bearer {{YOUR_ACCESS_TOKEN}}' \
  --header 'Content-Type: application/json' \
  --header 'X-Trace-Id: {{YOUR_UNIQUE_TRACE_ID}}' \
  --header 'X-Idempotency-Key: {{YOUR_UNIQUE_IDEMPOTENCY_KEY}}' \
  --data '{
    "type": "bank_account",
    "bank_account": {}
  }'

{
    "status": "success",
    "message": "Payment method created",
    "data": {
        "type": "bank_account",
        "bank_account": {},
        "id": "pmd_kB7xcrobND",
        "meta": {},
        "created_datetime": "2026-08-07T14:48:08.770Z"
    }
}


Step 3: Create Charge.

Create the Bank Account charge by sending a request to the create a charge endpoint with the following parameters:

  • customer_id: The data.id returned from Step 1(customer creation).
  • payment_method_id: The data.id returned from Step 2(payment method creation).
  • Transaction details including: amount, redirect_url, currency, and a unique reference for the transaction.

curl --request POST \
  --url 'https://developersandbox-api.flutterwave.com/charges' \
  --header 'Authorization: Bearer {{YOUR_ACCESS_TOKEN}}' \
  --header 'Content-Type: application/json' \
  --header 'X-Trace-Id: {{YOUR_UNIQUE_TRACE_ID}}' \
  --header 'X-Idempotency-Key: {{YOUR_UNIQUE_IDEMPOTENCY_KEY}}' \
  --data '{
    "reference": "185878aa-5647-47b6-b4d5-2f34bf596814",
    "currency": "NGN",
    "customer_id": "cus_Gh5xysiG40",
    "payment_method_id": "pmd_kB7xcrobND",
    "redirect_url": "https://flutterwave.com/",
    "amount": 250,
    "meta": {
      "person_name": "Derek Jones",
      "role": "Developer"
    }
  }'

{
    "status": "success",
    "message": "Charge created",
    "data": {
        "id": "chg_SCmmjzx9Vf",
        "amount": 250,
        "fees": [
            {
                "type": "vat",
                "amount": 0
            },
            {
                "type": "app",
                "amount": 0
            },
            {
                "type": "merchant",
                "amount": 0
            },
            {
                "type": "stamp_duty",
                "amount": 0
            }
        ],
        "currency": "NGN",
        "customer_id": "cus_Gh5xysiG40",
        "settled": false,
        "settlement_id": [],
        "meta": {
            "person_name": "Derek Jones",
            "role": "Developer"
        },
        "next_action": {
            "type": "redirect_url",
            "redirect_url": {
                "url": "https://developersandbox.flutterwave.com/redirects?bank_account&token=eyJhbGciOiJIUzI1NiJ9.eyJjbGllbnRJZCI6IjQ0OTllNjBiLThkYzgtNDdlMy05ZDYyLWQwOTUyNjA1ZTYyOSIsImNoYXJnZUlkIjoiY2hnX1NDbW1qeng5VmYiLCJzdWIiOiI0NDk5ZTYwYi04ZGM4LTQ3ZTMtOWQ2Mi1kMDk1MjYwNWU2MjkiLCJpYXQiOjE3ODYxMTM5NDUsImV4cCI6MTc4NjExNDI0NX0.V0gqfYqugfHmRX1Dcb4HA_HErmkyfAz16-xMSZWrKho"
            }
        },
        "payment_method_details": {
            "type": "bank_account",
            "bank_account": {},
            "id": "pmd_G6oIU2NQ9R",
            "meta": {},
            "created_datetime": "2026-08-07T14:44:34.123Z"
        },
        "redirect_url": "https://flutterwave.com/",
        "reference": "TRN-cOEunIgj74os",
        "status": "pending",
        "processor_response": {
            "type": "pending",
            "code": "02"
        },
        "created_datetime": "2026-08-07T14:45:45.827Z"
    }
}

{
    "status": "failed",
    "error": {
        "type": "CURRENCY_NOT_SUPPORTED",
        "code": "1125400",
        "message": "Currency not supported for bank account charge.",
        "validation_errors": []
    }
}

Step 4: Authorise Payment

You may notice that the data.status in the response object after creating the charge is "pending", indicating the charge has not yet been completed.

{
    "status": "success",
    "message": "Charge created",
    "data": {
       ...
        "status": "pending",
       ...
           }
}       

To complete the charge, redirect the customer to the URL provided in the data.next_action.redirect_url object to open Mono's page.

{
    "status": "success",
    "message": "Charge created",
    "data": {
    ...
        "next_action": {
            "type": "redirect_url",
            "redirect_url": {
                "url": "https://developer-sandbox.flutterwave.com/redirects?bank_account&token=eyJhbGciOiJIUzI1NiJ9.eyJjbGllbnRJZCI6IjQ0OTllNjBiLThkYzgtNDdlMy05ZDYyLWQwOTUyNjA1ZTYyOSIsImNoYXJnZUlkIjoiY2hnX29mTGx1SDRnNnYiLCJzdWIiOiI0NDk5ZTYwYi04ZGM4LTQ3ZTMtOWQ2Mi1kMDk1MjYwNWU2MjkiLCJpYXQiOjE3NDgwMDg1MDgsImV4cCI6MTc0ODAwODgwOH0.CfqeQgfrCNeod8GyOpnRp1Gj8eed0WksRLrCkvH1sn8"
            }
        }
   ...
    }
}

On Mono's page, the customer will select their bank from the list of supported banks and authorize the payment.

Once the payment has been authorized and completed, Flutterwave redirects the customer to the redirect_url specified in the create a charge request and sends you a webhook notifying you of the final status of the charge.


Step 5: Verify Payment

Before you provide value to the customer, confirm the transaction's final status and amount. You can verify the transaction information either using webhooks or by retrieving the charge details:

  • Webhooks : It is important to have webhooks enabled on your Flutterwave dashboard. If you do not have webhooks set up, you can learn more by visiting here. If you have webhooks enabled, we'll call your webhook URL with the payment details when the charge is completed or fails. Below is a sample webhook payload:
{
  "webhook_id": "wbk_ckhz9yMjxvSPQZDeGJrt",
  "timestamp": 1786362486906,
  "type": "charge.completed",
  "data": {
    "id": "chg_SCmmjzx9Vf",
    "amount": 250,
    "currency": "NGN",
    "customer": {
      "id": "cus_Gh5xysiG40",
      "address": {
        "city": "Gotham",
        "country": "US",
        "line1": "221B Baker Street",
        "line2": "321B Hazard Avenue",
        "postal_code": "94105",
        "state": "Colorado"
      },
      "email": "[email protected]",
      "name": {
        "first": "Derek",
        "middle": "Jones",
        "last": "Blue"
      },
      "phone": {
        "country_code": "233",
        "number": "9012345678"
      },
      "meta": {},
      "created_datetime": "2026-08-07T14:41:52.180Z"
    },
    "description": null,
    "meta": {
      "person_name": "Derek Jones",
      "role": "Developer"
    },
    "payment_method": {
      "type": "bank_account",
      "bank_account": {},
      "id": "pmd_kB7xcrobND",
      "customer_id": "cus_Gh5xysiG40",
      "meta": {},
      "device_fingerprint": null,
      "client_ip": null,
      "created_datetime": "2026-08-07T14:44:34.123Z"
    },
    "redirect_url": "https://flutterwave.com/",
    "reference": "TRN-cOEunIgj74os",
    "status": "succeeded",
    "processor_response": {
      "type": "approved",
      "code": "00"
    },
    "created_datetime": "2026-08-07T14:45:45.827Z"
  }
}


  • Retrieve the charge: You can manually check the status of the charge by calling the retrieve a charge endpoint using the data.id returned in your create a charge response.
{
    "status": "success",
    "message": "Charge created",
    "data": {
        "id": "chg_SCmmjzx9Vf",
     ...
    }
}

Sample request:

curl --request GET \
  --url 'https://developersandbox-api.flutterwave.com/charges/chg_SCmmjzx9Vf/' \
  --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  --header 'Content-Type: application/json' \
  --header 'X-Trace-Id: <YOUR_UNIQUE_TRACE_ID>' \
  --header 'X-Idempotency-Key: <YOUR_UNIQUE_IDEMPOTENCY_KEY>'

{
    "status": "success",
    "message": "Charge fetched",
    "data": {
        "id": "chg_SCmmjzx9Vf",
        "amount": 250,
        "fees": [
            {
                "type": "vat",
                "amount": 0
            },
            {
                "type": "app",
                "amount": 0
            },
            {
                "type": "merchant",
                "amount": 0
            },
            {
                "type": "stamp_duty",
                "amount": 0
            }
        ],
        "currency": "NGN",
        "customer_id": "cus_Gh5xysiG40",
        "settled": false,
        "settlement_id": [],
        "meta": {
            "person_name": "Derek Jones",
            "role": "Developer"
        },
        "payment_method_details": {
            "type": "bank_account",
            "bank_account": {},
            "id": "pmd_G6oIU2NQ9R",
            "meta": {},
            "created_datetime": "2026-08-07T14:44:34.123Z"
        },
        "redirect_url": "https://flutterwave.com/",
        "reference": "TRN-cOEunIgj74os",
        "status": "succeeded",
        "processor_response": {
            "type": "approved",
            "code": "00"
        },
        "created_datetime": "2026-08-07T14:46:24.031Z"
    }
}



Testing your integration

Testing your integration requires no extra configuration or special data. Create the Bank Account charge and open the URL returned in the next_action object. On the sandbox authorization page, enter a dummy account number and password, then select the desired transaction outcome to simulate a successful, failed, or cancelled payment.

Once the mock payment is completed, you are redirected back to the redirect_url specified during charge creation. Flutterwave also sends a charge.completed webhook event to your server.

Next steps

That’s it! You’ve successfully integrated the bank account payment method. It doesn't end there, there is more:

  • Learn how to set settlement of funds after a successful payment into your Flutterwave balance.
  • For cases where refunds are necessary, see the refunds guide for more information on how to process transaction refunds.

Did this page help you?