KES Virtual Accounts

Learn how to create and manage Kenyan Virtual Accounts.

🚧

Feature Availability

This feature is only available upon request. Please email us at [email protected] to request access.

Virtual accounts are generated bank account details (account number and bank name) that allow Flutterwave merchants to receive KES payments from customers via direct bank transfers. In KES, only the Dynamic Virtual Account is currently available.

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

Creating a Dynamic Virtual Account

To create a dynamic virtual account, send a request to the create virtual account endpoint with the following parameters:

  • amount: The transaction amount.
  • currency: The currency set to KES.
  • customer_account_number: This is the customer’s account number, which is required for payment confirmation.
  • firstname: The first name associated with the customer’s account
  • lastname: The last name associated with the customer’s account
  • email: The customer’s email address.

Check out the Virtual Account API reference for the full list of supported parameters.

curl --request POST 'https://api.flutterwave.com/v3/virtual-account-numbers' \
--header 'Authorization: Bearer YOUR_SECRET_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
  "email":"[email protected]",  
  "tx_ref":"your_tx_ref",
  "amount":"1",
  "currency":"KES",
  "firstname":"James",
  "lastname":"Bond",
  "customer_account_number":"1234567891"
}'

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-1751989246388",
        "order_ref": "URF_1751989245489_1131435",
        "account_number": "29019229920",
        "account_status": "active",
        "frequency": 1,
        "bank_name": "NBK",
        "created_at": "2025-07-08 15:40:46",
        "expiry_date": "2025-07-08 16:40:46",
        "note": "Mock note",
        "amount": "1.00",
        "customer_ref": "ECR5995062023"
    }
}


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, account number, and customer reference. You can display these details to your customer to facilitate payment via bank transfer.

📘

Payment Reference Requirement

The customer_ref must be included by the customer in the narration when making a bank transfer from their banking application. This is required to ensure accurate and timely payment confirmation.

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.

🚧

Handling Underpayments and Overpayments

When a customer sends less than the expected amount (an underpayment), the transaction fails. In contrast, if the customer sends more than the required amount (an overpayment), the transaction will succeed. To avoid any issues with transaction status, customers should ensure that they send the exact amount required.

Virtual Account Webhooks

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

{
  "event": "charge.completed",
  "data": {
    "id": 674787042,
    "tx_ref": "mcdfdrSddf",
    "flw_ref": "1324604850731752247030482",
    "device_fingerprint": "N/A",
    "amount": 10,
    "currency": "KES",
    "charged_amount": 10.3,
    "app_fee": 0,
    "merchant_fee": 0,
    "processor_response": "success",
    "auth_model": "AUTH",
    "ip": "102.89.68.167",
    "narration": "Wave KES Pool Account",
    "status": "successful",
    "payment_type": "bank_transfer",
    "created_at": "2025-07-11T15:17:17.000Z",
    "account_id": 1091430,
    "customer": {
      "id": 585248775,
      "name": "John Doe",
      "phone_number": "08012345678",
      "email": "[email protected]",
      "created_at": "2025-07-11T15:16:57.000Z"
    }
  }
}

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