Deduct from Virtual Account
Debit money from a virtual account to pay for orders, services, or fees.
A Deduction debits money from a Virtual Account, reducing its available balance.
Use deductions to:
- Pay for orders or services from a wallet balance
- Move funds into escrow or settlement flows (depending on your product design)
- Charge fees or subscriptions from stored value
- Reverse previously credited amounts (if supported by your business logic)
After a successful deduction:
- The virtual account balance decreases
- A debit record appears in the account's debit history
Endpoint
POST /v2/virtual-accounts/{virtual_account_id}/deduct
Host: api.chapa.coAuthentication
Headers
| Name | Required | Description |
|---|---|---|
Authorization | Yes | Bearer <PRIVATE_API_KEY> |
Content-Type | Yes | application/json |
Idempotency-Key | No | Prevent duplicate deductions on retries |
Path Parameter
| Parameter | Required | Description |
|---|---|---|
virtual_account_id | Yes | Unique virtual account identifier |
Request Body
Required Fields
| Field | Type | Description |
|---|---|---|
amount | number | Amount to deduct |
currency | string | Currency (must match the virtual account currency) |
Optional Fields
| Field | Type | Description |
|---|---|---|
merchant_reference | string | Merchant-generated reference for the deduction |
reason | string | Description of why the deduction happened |
meta | object | Custom metadata (e.g. order_id, customer_id) |
Example Request
Example Request
JSON
{
"amount": 3000,
"currency": "ETB",
"merchant_reference": "DEB_001",
"reason": "Payment for order ORD_99887",
"meta": {
"customer_id": "CUST_12345",
"order_id": "ORD_99887"
}
}cURL
curl -X POST https://api.chapa.co/v2/virtual-accounts/VA_ABC123456/deduct \
-H "Authorization: Bearer CHAPA_TEST_xxxxxxxxxxxxx"
-H "Content-Type: application/json" \
-d '{
"amount": 3000,
"currency": "ETB",
"merchant_reference": "DEB_001",
"reason": "Payment for order ORD_99887",
"meta": {
"customer_id": "CUST_12345",
"order_id": "ORD_99887"
}
}'JavaScript
const response = await fetch("https://api.chapa.co/v2/virtual-accounts/VA_ABC123456/deduct", {
method: "POST",
headers: {
"Authorization": "Bearer CHAPA_TEST_xxxxxxxxxxxxx",
"Content-Type": "application/json"
},
body: JSON.stringify({
"amount": 3000,
"currency": "ETB",
"merchant_reference": "DEB_001",
"reason": "Payment for order ORD_99887",
"meta": {
"customer_id": "CUST_12345",
"order_id": "ORD_99887"
}
})
});
const data = await response.json();
console.log(data);Example Response
{
"status": "success",
"message": "Deduction completed successfully",
"data": {
"virtual_account_id": "VA_ABC123456",
"debit_reference": "DEB_TRX_123456",
"amount": 3000,
"currency": "ETB",
"balance_before": 12500,
"balance_after": 9500,
"created_at": "2025-11-07T13:20:00Z"
}
}Response Fields
| Field | Description |
|---|---|
virtual_account_id | Virtual account debited |
debit_reference | Unique debit transaction reference |
amount | Amount deducted |
currency | Currency deducted |
balance_before | Balance before deduction |
balance_after | Balance after deduction |
created_at | Deduction timestamp |
Validation Rules
currencymust match the virtual account currencyamountmust be a positive number- Account must have sufficient funds
merchant_referenceshould be unique (recommended)
Insufficient Balance Handling
If the account does not have enough balance:
- Return a clear user-facing message (e.g. "Insufficient wallet balance")
- Avoid retry loops
- Optionally suggest topping up (deposit)
Best Practices
- Use idempotency keys on retries
- Store debit references for reconciliation
- Log
balance_before/balance_afterfor auditing - Use
merchant_referenceto prevent duplicate charges - Optionally validate balance before calling deduct (still handle race conditions)
Common Errors
| HTTP | Error Code | Meaning |
|---|---|---|
| 400 | INVALID_VALUE | Amount invalid or currency mismatch |
| 400 | INSUFFICIENT_BALANCE | Not enough funds in account |
| 404 | NOT_FOUND | Virtual account not found |
| 409 | INVALID_STATE | Duplicate reference or idempotency conflict |
| 500 | PROCESSING_FAILED | Deduction failed due to system error |
Next Steps
- Create Virtual Account - Create a new account
- Deposit to Virtual Account - Add funds
- Get Debit History - View debit transactions