Accepting payments with USD Virtual Bank Accounts
Beta DisclaimerPlease 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:
- 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.
- 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.
- 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.
- 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:
Parameter | Type | Required | Description |
---|---|---|---|
first_name | String | True | The first name of the customer/account holder. |
last_name | String | True | The last name of the customer/account holder. |
use_case | String | True | This is the use case for which the account holder and the related accounts are created |
type | String | True | The type of account holder to be created for the customer. This can be individual or corporate |
email | String | True | The email address of the customer |
date_of_birth | String | False | The date of birth of the customer |
nationality | String | True | The nationality of the customer |
occupation | String | True | The customer's job occupation |
phone | String | True | The phone number of the customer (should include country code) |
source_of_inflow | String | True | This is the customer's source of income |
source_of_inflow_document | String | True | This should be in data URI format data:application/pdf;base63,... |
selfie | String | True | This should be in data URI format data:application/pdf;base63,... |
identification.type | String | True | This is the type of identification document. Currently, only passport is accepted. |
identification.document_front | String | True | This should be in data URI format data:application/pdf;base63,... |
identification.issued_date | String | True | This is the issue date of the identification document, in the format YYYY-MM-DD . |
identification.expiry_date | String | True | This is the expiry date of the identification document, in the format YYYY-MM-DD . |
identification.country | String | True | This is the country of the identification document. |
proof_of_address.type | String | True | This is the type of document submitted for the proof of address. It can either be bank_statement or utility_bill . |
proof_of_address.document | String | True | This should be in data URI format data:application/pdf;base63,... |
address.county | String | True | This is the country of residence. |
address.zip | String | True | This is the address' ZIP code. |
address.address | String | True | This is the address line of the residential address. |
address.state | String | True | This is the state of the residential address. |
address.city | String | True | This is the city of the residential address. |
employment.status | String | True | This is the status of employment for the account holder. This can either be employer or employee . |
employment.employer | String | True | This is the employer name. |
employment.description | String | True | This is the description of the employment. |
metadata | Object | False | This 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:
Parameter | Type | Required | Description |
---|---|---|---|
status | Boolean | True | This is the request status |
message | String | True | This is the request message |
data.reference | String | True | This is the account holder reference |
data.email | String | True | This is the account holder email |
data.status | String | True | This is the account holder status. It can either be pending , approval , suspended and deactivated . |
data.metadata | Object | False | This 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:
Parameter | Type | Required | Description |
---|---|---|---|
first_name | String | False | This is the first name of your customer |
last_name | String | False | This is the last name of your customer |
source_of_inflow | String | True | This should either be payslip or bank_statement . |
source_of_inflow_document | String | True | This should be in data URI format data:application/pdf;base63,... |
selfie | String | True | This should be in data URI format data:application/pdf;base63,... |
identification.type | String | True | This is the type of identification document, which can either be nin , voters_card , or passport . |
identification.number | String | True | This is the identification number. |
identification.document_front | String | True | This should be in data URI format data:application/pdf;base63,... |
identification.issue_date | String | True | This is the issue date of the identification document, in the format YYYY-MM-DD . |
identification.expiry_date | String | True | This is the expiry date of the identification document, in the format YYYY-MM-DD . |
identification.country | String | True | This is the country on the identification document. |
proof_of_address.type | String | True | This is the type of document for the proof of address. Either bank_statement or utility_bill is allowed. |
proof_of_address.document | String | True | This 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:
Parameter | Type | Required | Description |
---|---|---|---|
currency | String | True | This is the currency for which you want to create the Virtual Bank Account, e.g, USD . |
account_holder_reference | String | True | This is the unique reference returned after creating the account holder. |
account_reference | String | True | This 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"
}
}
Parameter | Type | Required | Description |
---|---|---|---|
status | String | True | This is the request status. |
message | String | True | This is the request message. |
data.tier | Number | True | This is the virtual account tier. |
data.account_reference | String | True | This is the virtual account reference that you passed when creating the account. |
data.unique_id | String | True | This is the unique reference for the virtual account. |
data.account_status | String | True | This is the virtual account's status. It can be pending , active , suspended or deactivated . |
data.created_at | String | True | This is the date on which the virtual account was created. |
data.currency | String | True | This is the virtual account currency, e.g., USD . |
data.account_holder_reference | String | True | This 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
-
Suspending an account holder
- Virtual Bank Account Holders can be suspended at any time after they have been created.
- When an Account Holder is suspended, all Virtual Bank Accounts linked to that Account Holder will also be suspended automatically.
- While suspended, the Account Holder cannot create new Virtual Bank Accounts, and existing accounts cannot receive payments.
- Any incoming payment attempts will be flagged and not settled into your balance. For flagged transactions, please contact [email protected].
-
Reactivating a suspended account holder
- 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.
- Once reactivated, all associated Virtual Bank Accounts will also be reactivated.
- If an individual Virtual Bank Account was suspended independently, you must request its reactivation separately.
- 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.
-
Deactivating an account holder
- Account Holders can also be deactivated at any time.
- Be cautious, deactivation is final. Once done, the Account Holder and all associated Virtual Bank Accounts cannot be reactivated.
- Payments to a deactivated account will be flagged and not settled.
Account number management
-
Suspending a virtual bank account
- Individual USD Virtual Bank Accounts can be suspended at any time.
- While suspended, no payments can be made into the account. Any detected payment will be flagged and not settled.
-
Reactivating a Suspended Virtual Bank Account
- To reactivate a suspended account, navigate to the Manage Account settings on the USD Virtual Bank Account details page and click Request Reactivation.
- 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.
-
Deactivating a Virtual Bank Account
- A Virtual Bank Account can be deactivated at any time.
- Take caution because deactivation is final. Once deactivated, the Virtual Bank Account cannot be reactivated.
- 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:
Parameter | Type | Required | Description |
---|---|---|---|
account_number | String | True | This is the account number of the fixed virtual bank account. |
amount | Number | True | This is the amount that you want to credit to the account. |
currency | String | True | This 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:
- 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.
- 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.
- 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.
Updated about 13 hours ago