Accepting payments with USD Virtual Bank Accounts

🚧

Beta Disclaimer

Please note that this service is currently only available to merchants participating in our beta program. If you have any feedback or questions, please contact us.

A USD Virtual Bank Account allows you to receive payments in USD at any time from your customers. Each account is “fixed” - there’s no need to generate a new one for every transaction. Every USD Virtual Bank Account is dedicated to a single customer, ensuring that all payments made to that account are automatically associated with them.

Use Case

Virtual USD bank accounts give businesses a simple way to receive cross-border payments. Businesses can create these accounts for their customers, enabling them to make payments directly on the platform. This provides a seamless, global payment experience for both the business and its customers.


There are four main steps to note when accepting USD payments from your customers with Virtual Bank Accounts:

  1. Create Virtual Bank Account Holders for your customers: To create a virtual bank account holder, make a POST request to the Create Virtual Bank Account Holder endpoint.
  2. Create Virtual Bank Accounts for your customers: To create virtual bank accounts for your customers, make a request to the Create Fixed Virtual Bank Account API. These accounts can be used to accept payments immediately after they are created. To retrieve details of a virtual account, make a request to the Virtual Bank Account Query API. By default, you can only create one fixed virtual bank account per account holder.
  3. Set up Webhooks: Since payments to virtual accounts are initiated outside your application, you can only be notified when the payment is complete. Therefore, set up webhooks so that Kora can notify you when your customers make payments.
  4. Verify Payments: After you receive a webhook notification, verify the payment by making a request to our Transaction Query API.

Creating a USD Virtual Bank Account Holder via API

To create of a virtual bank account holder, make a POST request to the Create Virtual Bank Account Holder endpoint:

{{baseurl}}/api/v1/virtual-bank-account/account-holders

Request Parameters:

ParameterTypeRequiredDescription
first_nameStringTrueThe first name of the customer/account holder.
last_nameStringTrueThe last name of the customer/account holder.
use_caseStringTrueThis is the use case for which the account holder and the related accounts are created
typeStringTrueThe type of account holder to be created for the customer. This can be individual or corporate
emailStringTrueThe email address of the customer
date_of_birthStringFalseThe date of birth of the customer
nationalityStringTrueThe nationality of the customer
occupationStringTrueThe customer's job occupation
phoneStringTrueThe phone number of the customer (should include country code)
source_of_inflowStringTrueThis is the customer's source of income
source_of_inflow_documentStringTrueThis should be in data URI format data:application/pdf;base63,...
selfieStringTrueThis should be in data URI format data:application/pdf;base63,...
identification.typeStringTrueThis is the type of identification document. Currently, only passport is accepted.
identification.document_frontStringTrueThis should be in data URI format data:application/pdf;base63,...
identification.issued_dateStringTrueThis is the issue date of the identification document, in the format YYYY-MM-DD.
identification.expiry_dateStringTrueThis is the expiry date of the identification document, in the format YYYY-MM-DD.
identification.countryStringTrueThis is the country of the identification document.
proof_of_address.typeStringTrueThis is the type of document submitted for the proof of address. It can either be bank_statement or utility_bill.
proof_of_address.documentStringTrueThis should be in data URI format data:application/pdf;base63,...
address.countyStringTrueThis is the country of residence.
address.zipStringTrueThis is the address' ZIP code.
address.addressStringTrueThis is the address line of the residential address.
address.stateStringTrueThis is the state of the residential address.
address.cityStringTrueThis is the city of the residential address.
employment.statusStringTrueThis is the status of employment for the account holder. This can either be employer or employee.
employment.employerStringTrueThis is the employer name.
employment.descriptionStringTrueThis is the description of the employment.
metadataObjectFalseThis is any additional information you may want to share.

The request format would look like this:

{
  "first_name": "Sarah",
  "last_name": "Doe",
  "use_case": "Personal",
  "type": "individual",
  "date_of_birth": "1988-04-04",
  "nationality": "NG",
  "occupation": "Entrepreneur",
  "email": "[email protected]",
  "phone": "+2348133443000",
  "bank_id_number": "12332435200",
  "source_of_inflow": "bank_statement",
  "source_of_inflow_document": "data:application/pdf;base64,…",
  "selfie": "data:image/jpeg;base64,…",
  "identification": {
     "type": "passport",
     "number": "A11111111",
     "document_front": "data:image/jpeg;base64,…",
     "issued_date": "2010-01-01",
     "expiry_date": "2030-01-01",
     "country": "NG"
  },
  "proof_of_address": {
    "type": "bank_statement",
    "document": "data:application/pdf;base64,…"
  },
  "address": {
    "country": "NG",
    "zip": "12345",
    "address": "Freedom Way St",
    "state": "Lagos",
    "city": "Lagos"
  },
  "employment": {
    "status": "employer",
    "employer": "Google",
    "description": "I am an employer"
  },
  "metadata": {
    "key1": "value1"
  }
}

The response to this request would have the following parameters and format:

ParameterTypeRequiredDescription
statusBooleanTrueThis is the request status
messageStringTrueThis is the request message
data.referenceStringTrueThis is the account holder reference
data.emailStringTrueThis is the account holder email
data.statusStringTrueThis is the account holder status. It can either be pending, approval, suspended and deactivated.
data.metadataObjectFalseThis is the metadata object that was passed when creating the account.
{
    "status": true,
    "message": "Virtual account holder creation requested successfully",
    "data": {
        "reference": "KPY-AH-CGAXuc6jZwDA8TJ",
        "email": "[email protected]",
        "status": "pending",
        "metadata": {
            "key1": "value1"
        }
    }
}


The details of an Account Holder can also be viewed on your Merchant dashboard. To view details, navigate to the list of Virtual Accounts and select the Account Holder for the chosen foreign currency. You would also be able view the Account Holder’s account number, along with their transaction history and KYC information.

A webhook notification will be sent to your application once your account holder creation request has been approved or rejected.


Account Holder Approval Process

All created Account Holders go through an approval process, which is typically completed within 24 hours. Once reviewed, a webhook notification will be sent to you indicating whether the Account Holder has been approved or rejected, so you can take the next steps.

If approved: You can immediately create individual Virtual Bank Accounts using the Create Individual FVBA API.

If rejected: You can re-upload the KYC information and re-submit the request using the KYC Update API.


Updating the KYC details of a USD Virtual Bank Account Holder (Individual)

If a USD Virtual Bank Account Holder’s KYC needs to be updated or is rejected, you can update their details by sending a PATCH request to the KYC Update endpoint.

{{baseurl}}/api/v1/virtual-bank-account/account-holders/:reference/update-kyc

These are the request parameters:

ParameterTypeRequiredDescription
first_nameStringFalseThis is the first name of your customer
last_nameStringFalseThis is the last name of your customer
source_of_inflowStringTrueThis should either be payslip or bank_statement.
source_of_inflow_documentStringTrueThis should be in data URI format data:application/pdf;base63,...
selfieStringTrueThis should be in data URI format data:application/pdf;base63,...
identification.typeStringTrueThis is the type of identification document, which can either be nin, voters_card, or passport.
identification.numberStringTrueThis is the identification number.
identification.document_frontStringTrueThis should be in data URI format data:application/pdf;base63,...
identification.issue_dateStringTrueThis is the issue date of the identification document, in the format YYYY-MM-DD.
identification.expiry_dateStringTrueThis is the expiry date of the identification document, in the format YYYY-MM-DD.
identification.countryStringTrueThis is the country on the identification document.
proof_of_address.typeStringTrueThis is the type of document for the proof of address. Either bank_statement or utility_bill is allowed.
proof_of_address.documentStringTrueThis should be in data URI format data:application/pdf;base63,...

Here's a sample request format:

{
  "first_name": "Sarah",
  "last_name": "Doe",
  "source_of_inflow": "bank_statement",
  "source_of_inflow_document": "data:application/pdf;base64,…",
  "selfie": "data:image/jpeg;base64,…",
  "identification": {
     "type": "passport",
     "number": "A11111111",
     "document_front": "data:image/jpeg;base64,…",
     "issued_date": "2010-01-01",
     "expiry_date": "2030-01-01",
     "country": "NG"
  },
  "proof_of_address": {
    "type": "bank_statement",
    "document": "data:application/pdf;base64,…"
  },
}

A response to this request could look like this:

{
    "status": true,
  "message": "Virtual bank account holder update kyc requested successfully",
    "data": {
        "reference": "KPY-AH-WveCyyYAvKh107Y",
        "first_name": "Sarah",
        "last_name": "Doe",
        "status": "pending"
    }
}

Retrieving the details of a Virtual Account Holder

The details of a Virtual Bank Account can be retrieved at any time after creating the account. To retrieve the details of the account holder, initiate a GET request to the Fixed Virtual Bank Account Holder Query endpoint.

{{baseurl}}/api/v1/virtual-bank-account/account-holders/:accountHolderReference/details

Here's an example of a response you'd receive for your request:

{
    "status": true,
    "message": "Virtual account holder retrieved successfully",
    "data": {
        "reference": "KPY-AH-WveCyyYAvKh107Y",
        "account_type": "individual",
        "first_name": "Sarah",
        "last_name": "Doe",
        "email": "[email protected]",
        "phone_number": "+2348100000000",
        "occupation": "Software Engineering",
        "status": "pending",
        "metadata": {
            "key1": "value1"
        },
        "date_created": "2024-03-22T13:27:17.000Z",
        "country": "NG",
        "date_of_birth": "1988-04-04T00:00:00.000Z",
        "address": {
            "zip": "12345",
            "city": "Lagos",
            "state": "Lagos",
            "address": "Freedom Way St",
            "country": "NG"
        },
        "documents": {
            "identification_front": "base64String",
            "identification_back": "base64String",
            "proof_of_address": "base64String",
            "selfie": "base64String",
            "source_of_inflow": "base64String"
        }
    }
}

Creating a USD Virtual Bank Account (for Individual)

After successfully creating the account holder, you can now create a Virtual Bank Account for your customer by making a POST request to the Create Virtual Bank Account API endpoint.

{{baseurl}}/api/v1/virtual-bank-account

The request parameters include:

ParameterTypeRequiredDescription
currencyStringTrueThis is the currency for which you want to create the Virtual Bank Account, e.g, USD.
account_holder_referenceStringTrueThis is the unique reference returned after creating the account holder.
account_referenceStringTrueThis is your unique reference which would be used to identify the virtual account.

Here's how the format of this request could look:

{
    "currency": "USD",
    "account_holder_reference": "KPY-AH-EKf82jtn6z3696V",
    "account_reference": "AcmWYgVOoq3xkm51"
}

And, the response would have the following format and parameters:

{
    "status": true,
    "message": "Virtual bank account created successfully",
    "data": {
        "tier": 1,
        "account_reference": "your-account-reference",
        "unique_id": "kora-unique-reference",
        "account_status": "pending",
        "created_at": "2024-06-04T07:35:06.782Z",
        "currency": "USD",
        "account_holder_reference": "KPY-AH-WveCyyYAvKh107Y"
    }
}
ParameterTypeRequiredDescription
statusStringTrueThis is the request status.
messageStringTrueThis is the request message.
data.tierNumberTrueThis is the virtual account tier.
data.account_referenceStringTrueThis is the virtual account reference that you passed when creating the account.
data.unique_idStringTrueThis is the unique reference for the virtual account.
data.account_statusStringTrueThis is the virtual account's status. It can be pending, active, suspended or deactivated.
data.created_atStringTrueThis is the date on which the virtual account was created.
data.currencyStringTrueThis is the virtual account currency, e.g., USD.
data.account_holder_referenceStringTrueThis is the account holder reference.
🚧

Please note that, by default, you can only create a total of one (1) virtual bank account per account holder for each currency.



These accounts can be used to accept payments immediately they are created. The details of a USD Individual Virtual Bank Account can also be viewed on your Merchant dashboard. To view, simply click on the list of Virtual Accounts and explore by Account Numbers for the to view its details.

In the details page, you would see an account summary showing the status, account number and bank, account name, account reference and date created. You can click on any of the virtual accounts to view more details about that virtual account number, the account deposit details through which the payments will be made into the account, as well as other important information on the account. You would also see a list of all the transactions made through the virtual account in the Transaction section.


Retrieving the details of a USD Individual Virtual Bank Account:

The details of a Virtual Bank Account can be retrieved at any time after creating the account. To do this, you’ll need to initiate a GET request to the Fixed Virtual Bank Account Query endpoint.

{{baseurl}}/api/v1/virtual-bank-account/:accountReference

The format for the response received could look like this:

{
    "status": true,
    "message": "Virtual bank account retrieved successfully",
    "data": {
        "account_name": null,
        "account_number": "579076548910",
        "account_status": "pending",
        "account_reference": "DSU2-hfyycZ2625126c1",
        "unique_id": "KPY-VA-WSCtv7FNlJ9ZBGt",
        "iban": null,
        "tier": 1,
        "payment_schemes": {
            "swift": {
                "account_holder_name": "Sarah Doe",
                "account_number": "579076548910",
                "memo": "UNHZMBE",
                "bank_name": "Bank of the Lakes",
                "account_holder_address": {
                    "city": "Lagos",
                    "postal_code": "12345",
                    "country_code": "NG",
                    "address_line1": "Freedom Way St"
                },
                "bank_address": {
                    "city": "Duluth",
                    "state": "MN",
                    "postal_code": "55812",
                    "country_code": "US",
                    "address_line1": "123 Cherry Street",
                    "address_line2": ""
                },
                "swift_code": "LAKEUS41"
            },
            "ach": {
                "account_holder_name": "Sarah Doe",
                "account_number": "579076548910",
                "routing_code": "021001208",
                "memo": "XR6MYQ5",
                "bank_name": "Bank of the Lakes"
            },
            "fedwire": {
                "account_holder_name": "Sarah Doe",
                "account_number": "579076548910",
                "routing_code": "021001208",
                "memo": "2Z2T3UV",
                "bank_name": "Bank of the Lakes",
                "account_holder_address": {
                    "city": "Lagos",
                    "postal_code": "12345",
                    "country_code": "NG",
                    "address_line1": "Freedom Way St"
                },
                "bank_address": {
                    "city": "Duluth",
                    "state": "MN",
                    "postal_code": "55812",
                    "country_code": "US",
                    "address_line1": "123 Cherry Street",
                    "address_line2": ""
                }
            }
        },
        "account_type": "individual",
        "email": "[email protected]",
        "pending_upgrade_request": false,
        "account_holder": {
            "reference": "KPY-AH-AcmWYgVOoq3xkm5"
        },
        "bank_code": null,
        "currency": "USD",
        "created_at": "2024-04-30T09:47:20.000Z",
        "customer": {
            "name": "Sarah Doe",
            "email": "[email protected]"
        }
    }
}

Getting notified of payments

After a payment has been made into your Virtual Bank Account, we send a webhook notification to your webhook notification URL. The reference in the notification payload will be used to get the details of the payment. You can read more about how to handle webhook notifications here

More details on the payments made to Virtual Bank Account can also be viewed from the Pay-ins page of your dashboard. Simply:

  • Log in to your dashboard. Create an account if you don’t already have one.
  • Navigate to the Pay-ins page.
  • Search for the transaction using the transaction reference.
  • Click on the transaction to view further details.

Fetching transactions on a USD Fixed Virtual Bank Account

You can fetch the details of transactions carried out on a USD Virtual Bank Account. To do this, you’ll need to initiate a GET request to the Get Virtual Bank Account Transactions endpoint.

{{baseurl}}/api/v1/virtual-bank-account/transactions?account_number={{accountNumber}}

This is an example of how the response to this request would look like:

{
    "status": true,
    "message": "Virtual bank account transactions retrieved successfully",
    "data": {
        "total_amount_received": null,
        "account_number": "470492276567",
        "currency": "USD",
        "transactions": [
            {
                "reference": "KPY-PAY-OkFLnGJycmRmmDA",
                "status": "success",
                "amount": "150.00",
                "fee": "2.00",
                "currency": "USD",
                "description": "Payment to Test by Sarah Doe",
                "payer_bank_account": {
                    "account_number": "81191697",
                    "account_name": "simulate test",
                    "bank_name": "Auto Loan Account"
                }
            },
            {
                "reference": "KPY-PAY-OkFLnGJycmRmmDB",
                "status": "flagged",
                "amount": "150.00",
                "fee": "2.00",
                "currency": "USD",
                "description": "Payment to Test by Sarah Doe",
                "payer_bank_account": {
                    "account_number": "81191697",
                    "account_name": "simulate test",
                    "bank_name": "Auto Loan Account"
                }
            }
        ],
        "pagination": {
            "page": 1,
            "total": 2,
            "pageCount": 1,
            "totalPages": 2
        }
    }
}

Account Management on the Kora Dashboard

You can manage your USD Virtual Bank Accounts and Account Holders directly from the merchant dashboard. This includes suspending, reactivating, and deactivating accounts as needed.


Account holder management

  1. Suspending an account holder

    1. Virtual Bank Account Holders can be suspended at any time after they have been created.
    2. When an Account Holder is suspended, all Virtual Bank Accounts linked to that Account Holder will also be suspended automatically.
    3. While suspended, the Account Holder cannot create new Virtual Bank Accounts, and existing accounts cannot receive payments.
    4. Any incoming payment attempts will be flagged and not settled into your balance. For flagged transactions, please contact [email protected].

  2. Reactivating a suspended account holder

    1. To reactivate a suspended Account Holder, navigate to the Manage Account settings on the USD Account Holder details page and click Request Reactivation. This request will be sent to the Kora admin team for approval.
    2. Once reactivated, all associated Virtual Bank Accounts will also be reactivated.
    3. If an individual Virtual Bank Account was suspended independently, you must request its reactivation separately.
    4. Requests to reactivate an Account Holder are reviewed by our team before approval.

    🚧

    Note that your request to reactivate a suspended account holder will be sent to our team to review before approval.

  3. Deactivating an account holder

    1. Account Holders can also be deactivated at any time.
    2. Be cautious, deactivation is final. Once done, the Account Holder and all associated Virtual Bank Accounts cannot be reactivated.
    3. Payments to a deactivated account will be flagged and not settled.

Account number management

  1. Suspending a virtual bank account

    1. Individual USD Virtual Bank Accounts can be suspended at any time.
    2. While suspended, no payments can be made into the account. Any detected payment will be flagged and not settled.

  2. Reactivating a Suspended Virtual Bank Account

    1. To reactivate a suspended account, navigate to the Manage Account settings on the USD Virtual Bank Account details page and click Request Reactivation.
    2. This request will be sent to the Kora support team for approval.

    🚧

    Your request to reactivate a USD account number will be sent to our team to review before approval.

  3. Deactivating a Virtual Bank Account

    1. A Virtual Bank Account can be deactivated at any time.
    2. Take caution because deactivation is final. Once deactivated, the Virtual Bank Account cannot be reactivated.
    3. Payments to a deactivated account will be flagged and not settled.


Crediting a Virtual Bank Account in the Sandbox Environment

Fixed Virtual Accounts on the sandbox environment can be credited with test payments. To do this, you need to make a POST request to the Credit Sandbox VBA endpoint.

{{baseURL}}/api/v1/virtual-bank-account/sandbox/credit

The request parameters are as follows:

ParameterTypeRequiredDescription
account_numberStringTrueThis is the account number of the fixed virtual bank account.
amountNumberTrueThis is the amount that you want to credit to the account.
currencyStringTrueThis is the currency of the account. This field only accepts USD for now.

The response to the request would be:

{
  "status": true,
  "message": "Virtual bank account credited successfully",
  "data": null
}

Definition of supported payment collection schemes:

  1. ACH: Automated Clearing House interbank payment system, or the ACH network, is an interconnected computer system that communicates with each other to help transfer or receive payments. The ACH payment system is native to the US and is used to complete transactions in USD among financial institutions with bank accounts in the US.
  2. FEDWIRE: Fedwire, also known as Federal Reserve Wire Network, is a payment system local to the United States, allowing entities to execute time-sensitive, large-value transactions. Fedwire is a well-known payment network for entities as it processes transactions in real-time (immediate fund transfers) with high transactional security.
  3. SWIFT: SWIFT (Society for Worldwide Interbank Financial Telecommunication) is a global messaging network that facilitates secure communication of financial transactions between institutions worldwide. Transfers can take a few days depending on where it's coming from.