GHS Virtual Accounts

Learn how to create and manage a Ghanaian Virtual Account.

🚧

Feature Availability

This feature is currently available to Ghanaian merchants only. If you're a merchant based outside Ghana, you'll need to request activation for your account. To do so, please email us at [email protected].

Virtual accounts are generated bank account details (account number and bank name) that allow Flutterwave merchants to receive GHS payments from customers via direct bank transfers. There are two types of virtual accounts you can create:

  • Dynamic Virtual Accounts
  • Static Virtual Accounts

We recommend starting with the introduction to Virtual Accounts to understand the fundamentals before proceeding.

Creating a Dynamic Virtual Account

To create a virtual account, send a request to the create virtual account endpoint, specifying an amount greater than zero and the customer's email.

curl --request POST 'https://api.flutterwave.com/v3/virtual-account-numbers' \
  --header 'Authorization: Bearer YOUR_SECRET_KEY' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "currency": "GHS",
    "firstname":"John",
    "lastname":"Doe",
    "narration":"Kids Foundation",
    "email":"[email protected]",
    "amount": 2000,
    "tx_ref":"apex_tx-002202"
}'

You'll get a response similar to this:

{
  "status": "success",
  "message": "Virtual account created",
  "data": {
    "response_code": "02",
    "response_message": "Transaction in progress",
    "flw_ref": "MockFLWRef-1742528799499",
    "order_ref": "URF_1742528799246_7392335",
    "account_number": "7003000100286",
    "account_status": "active",
    "frequency": 1,
    "bank_name": "Affinity",
    "created_at": "2025-03-21 3:46:39 AM",
    "expiry_date": "2025-03-21 4:46:39 AM",
    "note": "Mock note",
    "amount": "2000.00"
  }
}

The response will include a response_code of 02 and a response_message of "Transaction in progress", indicating that the virtual account has been successfully created and is ready to receive payments. The response body will also contain the bank name and account number. You can display these details to your customer to facilitate payment via bank transfer.

Customers are expected to complete the payment before the expiry_date of the virtual account. Once the customer completes a payment, we will send a webhook to notify you of the transaction status.

Creating a Static Virtual Account

You can generate a virtual account using the same create virtual account endpoint. You'll need to specify the customer's email to be associated with the account number.

curl --request POST 'https://api.flutterwave.com/v3/virtual-account-numbers' \
  --header 'Authorization: Bearer YOUR_SECRET_KEY' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "currency": "GHS",
    "firstname":"Jane",
    "lastname":"Doe",
    "narration":"Kids Foundation",
    "email":"[email protected]",
    "tx_ref":"apex_tx-0022025",
    "phonenumber":"23324XX0000",
    "is_permanent": true
}'

There are more options available when generating static virtual accounts. You can also set the following:

ParametersDefinition
currencyMust be set to GHS. If omitted, it defaults to NGN.
amountThe amount to be collected per transaction.
narrationThe name should be shown when the account details are fetched. this should be 35 characters long.
tx_refThe transaction reference that should be returned whenever a transfer is made into the account.

Additionally, you can create virtual accounts in bulk and retrieve their details at any time. For more details, see the API reference.

On a successful request, you'll get a response similar to this:

{
    "status": "success",
    "message": "Virtual account created",
    "data": {
        "response_code": "02",
        "response_message": "Transaction in progress",
        "flw_ref": "FLW-211b4eea7b3d465d8797fa354c127f79",
        "order_ref": "URF_1726608838391_595235",
        "account_number": "8548497837",
        "frequency": "N/A",
        "bank_name": "WEMA BANK",
        "created_at": "2024-09-17 21:33:58",
        "expiry_date": "N/A",
        "note": "Please make a bank transfer to Hefa Cust No.20 FLW",
        "amount": "0.00"
    }
}

🚧

Handling Underpayments and Overpayments

For cases where a customer sends less than the expected amount (an underpayment) or more than the expected amount (an overpayment) into a GHS virtual account, the transaction results in a failed transaction. The customer must send the exact amount for the transaction to go through successfully.

Virtual Account Webhooks

Whenever a transfer is made to the virtual account, we'll send you a webhook that looks like this:

{
  "event": "charge.completed",
  "data": {
    "id": 1549596704,
    "tx_ref": "apex_tx_ref-002201",
    "flw_ref": "000030240917214228820592962026",
    "device_fingerprint": "N/A",
    "amount": 100,
    "currency": "GHS",
    "charged_amount": 101.4,
    "app_fee": 1.4,
    "merchant_fee": 0,
    "processor_response": "success",
    "auth_model": "AUTH",
    "ip": "::ffff:172.16.85.133",
    "narration": "Kids Foundation",
    "status": "successful",
    "payment_type": "bank_transfer",
    "created_at": "2024-09-17T20:47:20.000Z",
    "account_id": 47337,
    "customer": {
      "id": 980070204,
      "name": "Jane Doe",
      "phone_number": "23324XX0000",
      "email": "[email protected]",
      "created_at": "2024-09-17T20:38:43.000Z"
    }
  },
  "event.type": "BANK_TRANSFER_TRANSACTION"
}

Now, your webhook handler can handle the event and credit the customer's wallet. For help setting up webhooks, see our guide on webhooks.

Creating Bulk Virtual Accounts.

You can generate bulk static virtual accounts for your customers with just a single request. This is important if you’re managing a large customer base or need to streamline payment collections.

To create bulk virtual accounts, make a POST request to the bulk virtual account endpoint with the following parameters:

  • currency: Must be set to GHS. If omitted, it defaults to NGN.
  • batch_ref: A unique reference to identify the current batch.
  • narration (optional): Provides context or the reason for the request.
  • bulk_data: A list containing virtual account details for each customer. Each entry should include:
  • firstname: Customer’s first name.
  • lastname: Customer’s last name.
  • email: Customer’s email address.
  • is_permanent: Set to true for a static virtual account.
curl -X POST 'https://api.flutterwave.com/v3/bulk-virtual-account-numbers' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer FLWSECK_TEST-XXXXXXXXXXXXXXXXXXXXXXXXXX-X' \
--data-raw '{
    "batch_ref": "Bulk-VA-RWIESDP1",
    "narration": "Subscription Accounts 2025-01-05",
    "bulk_data": [
        {
            "firstname": "Jane",
            "lastname": "Doe",
            "email": "[email protected]",
            "is_permanent": true
        },
        {
            "email": "[email protected]",
            "firstname": "John",
            "lastname": "Doe",
            "is_permanent": true
        }
    ]
}
'

On a successful request, your response should include the following:

  • batch_id: A unique identifier for the batch. You can use this to retrieve the generated virtual accounts.
  • response_code: Indicates whether the request has been acknowledged. This should return the value "02".
  • response_message: Confirms that the request will be processed.
{
    "status": "success",
    "message": "Bulk virtual accounts creation queued",
    "data": {
        "batch_id": "-RND_4651739890196713",
        "response_code": "02",
        "response_message": "Request added to Queue"
    }
}

To retrieve the newly created virtual accounts, pass the batch_id returned from the bulk request as a path parameter to the get bulk account endpoint.

curl -X GET 'https://api.flutterwave.com/v3/bulk-virtual-account-numbers/-RND_4651739890196713' \
--header 'Authorization: ••••••'

{
    "status": "success",
    "message": "Bulk virtual accounts fetched",
    "data": {
        "virtual_accounts": [
            {
                "response_code": "02",
                "response_message": "Transaction in progress",
                "flw_ref": "NFKW801617398049775989437",
                "order_ref": "URF_1739804838924_8401035",
                "account_number": "8520074870",
                "account_status": "ACTIVE",
                "frequency": "N/A",
                "bank_name": "Sterling BANK",
                "created_at": "2025-02-17 16:09:37",
                "expiry_date": "N/A",
                "note": "Please make a bank transfer to Jane Doe FLW",
                "amount": "0.00"
            },
            {
                "response_code": "02",
                "response_message": "Transaction in progress",
                "flw_ref": "MSAX8174173980497760559657",
                "order_ref": "URF_1739804838924_398835",
                "account_number": "8520155462",
                "account_status": "ACTIVE",
                "frequency": "N/A",
                "bank_name": "Sterling BANK",
                "created_at": "2025-02-17 16:09:37",
                "expiry_date": "N/A",
                "note": "Please make a bank transfer to John Doe FLW",
                "amount": "0.00"
            }
       ]
    }
}