Virtual Accounts

Learn how to use a virtual account.

Virtual accounts are generated account details (account number and bank) that allow Flutterwave merchants to receive payments from customers via bank transfer. Virtual accounts are currently only available in naira.

🚧

Virtual Cards and Virtual Accounts are Unrelated

Virtual accounts allow you to receive payments into your Flutterwave wallet via bank transfer, while virtual cards allow you to make online payments.

Virtual accounts are either dynamic (temporary) or static (permanent). A temporary account number expires after handling the specified number of transactions (the frequency parameter), while a static account number doesn't expire.

Temporary Virtual Accounts are useful for receiving one-off payments via bank transfer. When the customer is checking out, you generate a temporary virtual account with a fixed amount and provide it to them. When they make payment, we'll send you a webhook and you can handle it.

Static Virtual Accounts can be useful if you're building an app with a wallet system. You can issue a virtual account number for each customer to use in funding their wallet:

  1. You generate a virtual account for the customer with our API and provide them with the details.
  2. The customer transfers to their assigned account.
  3. We send you a webhook notifying you that we've received the payment.
  4. You credit the needed funds to the customer's wallet on your platform.

Creating a Virtual Account

You can generate a virtual account with this endpoint, which is supported in our backend SDKs. You will need to specify the email to be associated with the account number (the customer's email). If you're creating a static virtual number, their bvn will be required.

// 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 details = {
    email: "[email protected]"
};
flw.VirtualAcct.create(details)
    .then(console.log)
    .catch(console.log);

// Install with: composer require flutterwavedev/flutterwave-v3

$flw = new \Flutterwave\Rave(getenv('FLW_SECRET_KEY')); // Set `PUBLIC_KEY` as an environment variable
$virtualAccountsService = new \Flutterwave\VirtualAccount();
$details = [
    "email" => "[email protected]",
];
$response = $virtualAccountsService->createVirtualAccount($details);
# Install with: gem install flutterwave_sdk

require 'flutterwave_sdk'

flw = Flutterwave.new(ENV["FLW_PUBLIC_KEY"], ENV["FLW_SECRET_KEY"], ENV["FLW_ENCRYPTION_KEY"])
virtual_account_number = VirtualAccountNumber.new(flw)
details = {
  email: "[email protected]"
}
response = virtual_account_number.create_virtual_account_number details
print response
# Install with: pip install rave_python

import os
from rave_python import Rave

rave = Rave(os.getenv("FLW_PUBLIC_KEY"), os.getenv("FLW_SECRET_KEY"))
res = rave.VirtualAccount.create({
    "email": "[email protected]"
})
print(res)
// Install with: go get github.com/Flutterwave/Rave-go/rave

import (
  "fmt"
  "os"
  "github.com/Flutterwave/Rave-go/rave"
)
var r = rave.Rave{
  false,
  os.Getenv("FLW_PUBLIC_KEY"),
  os.Getenv("FLW_SECRET_KEY"),
}
var virtualAccount = rave.Virtualaccount{
    r,
}
details := rave.CreateAcctData {
  Email: "[email protected]",
}
err, response := virtualAccount.Create(details)
if err != nil {
    panic(err)
}
fmt.Println(response)
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]"
}'

🚧

BVN is Required for Static Virtual Account

When generating a static virtual account, you'll need to provide a BVN. If you've created a static virtual account without a BVN in the past, you'll need to set a BVN. You'll find more details in our announcement.


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

ParametersFunctions
amountThe amount to be collected per transaction.
frequencyThe number of times the account can be used before expiring.
narrationThe name should be shown when the account details are fetched.
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.

If the account is created successfully, you'll get a successful response. The response will have a response_code of 02 and a response_message of "Transaction in progress", indicating that the account number has been successfully created, and we're ready to accept payments for you.

{
    "status": "success",
    "message": "Virtual account created",
    "data": {
        "response_code": "02",
        "response_message": "Transaction in progress",
        "order_ref": "URF_1613406439309_370935",
        "account_number": "7824822527",
        "bank_name": "WEMA BANK",
        "amount": null
    }
}
{
  "status": "error",
  "message": "BVN is required for static account number",
  "data": null
}

Virtual Account Webhooks

Next, pass the details on to your customers, and they can make a transfer into the account. When they do, we'll send you a webhook that looks like this:

{
  "event": "charge.completed",
  "data": {
    "id": 407347576,
    "tx_ref": "Links-221401982810",
    "flw_ref": "000016210415121239000082517439",
    "device_fingerprint": "7852b6c97d67edce50a5f1e540719e39",
    "amount": 30020,
    "currency": "NGN",
    "charged_amount": 10,
    "app_fee": 0.14,
    "merchant_fee": 0,
    "processor_response": "success",
    "auth_model": "AUTH",
    "ip": "72.140.222.142",
    "narration": "payment for sample product",
    "status": "successful",
    "payment_type": "bank_transfer",
    "created_at": "2021-04-15T11:13:10.000Z",
    "account_id": 82913,
    "customer": {
      "id": 254967086,
      "fullname": "Flutterwave Developers",
      "phone_number": null,
      "email": "[email protected]",
      "created_at": "2021-04-14T16:39:17.000Z"
    }
  },
  "event.type": "BANK_TRANSFER_TRANSACTION"
}

If you specify a tx_ref when creating the account, the reference field will be set to that value. If you don't set one, we'll generate a unique value for that.

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