Create Virtual Account
Create system-generated accounts to receive funds, hold balances, and enable wallet-like experiences.
A Virtual Account is a system-generated account that allows you to:
- Receive funds programmatically
- Hold balances per customer or use-case
- Enable wallet-like experiences
- Support deposits, deductions, and internal transfers
Virtual Accounts are ideal for:
- Customer wallets
- Escrow accounts
- Marketplace balances
- Prepaid and stored-value systems
When to Use Virtual Accounts
Use Virtual Accounts when you need:
- A unique account per customer or merchant
- Separation of funds by purpose
- Programmatic credit and debit operations
- Transaction history and balance tracking
Endpoint
POST /v2/virtual-accounts
Host: api.chapa.coAuthentication
Headers
| Name | Required | Description |
|---|---|---|
Authorization | Yes | Bearer <PRIVATE_API_KEY> |
Content-Type | Yes | application/json |
Idempotency-Key | No | Prevent duplicate account creation |
Request Body
Required Fields
| Field | Type | Description |
|---|---|---|
account_name | string | Name or label for the virtual account |
currency | string | Account currency (ETB, USD, UGX, DJF — availability depends on setup) |
Optional Fields
| Field | Type | Description |
|---|---|---|
merchant_reference | string | Merchant-generated identifier |
meta | object | Custom metadata |
Example Request
Example Request
JSON
{
"account_name": "Abebe Bikila Wallet",
"currency": "ETB",
"merchant_reference": "VA_001",
"meta": {
"customer_id": "CUST_12345"
}
}cURL
curl -X POST https://api.chapa.co/v2/virtual-accounts \
-H "Authorization: Bearer CHAPA_TEST_xxxxxxxxxxxxx"
-H "Content-Type: application/json" \
-d '{
"account_name": "Abebe Bikila Wallet",
"currency": "ETB",
"merchant_reference": "VA_001",
"meta": {
"customer_id": "CUST_12345"
}
}'JavaScript
const response = await fetch("https://api.chapa.co/v2/virtual-accounts", {
method: "POST",
headers: {
"Authorization": "Bearer CHAPA_TEST_xxxxxxxxxxxxx",
"Content-Type": "application/json"
},
body: JSON.stringify({
"account_name": "Abebe Bikila Wallet",
"currency": "ETB",
"merchant_reference": "VA_001",
"meta": {
"customer_id": "CUST_12345"
}
})
});
const data = await response.json();
console.log(data);Example Response
Example Response
Success
{
"status": "success",
"message": "Virtual account created successfully",
"data": {
"virtual_account_id": "VA_ABC123456",
"account_name": "Abebe Bikila Wallet",
"currency": "ETB",
"balance": 0,
"created_at": "2025-11-07T10:00:00Z"
}
}Response Fields
Virtual Account Object
| Field | Description |
|---|---|
virtual_account_id | Unique virtual account identifier |
account_name | Account label |
currency | Account currency |
balance | Initial balance (always 0) |
created_at | Creation timestamp |
Key Notes
- Virtual accounts start with a zero balance
- Funds must be deposited before they can be used
- Currency is fixed and cannot be changed later
- Each virtual account is isolated from others
Best Practices
- Use
merchant_referenceto map accounts internally - Create one virtual account per customer or use-case
- Store
virtual_account_idsecurely - Avoid recreating accounts on retries (use idempotency)
Common Errors
| HTTP | Error Code | Description |
|---|---|---|
| 400 | INVALID_VALUE | Unsupported currency |
| 409 | RESOURCE_CONFLICT | Duplicate virtual account |
| 500 | PROCESSING_FAILED | Failed to create virtual account |
Next Steps
- Get Virtual Account - Retrieve account details
- Deposit to Virtual Account - Add funds
- Deduct from Virtual Account - Withdraw funds