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
POST /v2/virtual-accounts/{virtual_account_id}/deduct
Host: api.chapa.co
| Name | Required | Description |
|---|
Authorization | Yes | Bearer <PRIVATE_API_KEY> |
Content-Type | Yes | application/json |
Idempotency-Key | No | Prevent duplicate deductions on retries |
| Parameter | Required | Description |
|---|
virtual_account_id | Yes | Unique virtual account identifier |
| Field | Type | Description |
|---|
amount | number | Amount to deduct |
currency | string | Currency (must match the virtual account currency) |
| 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) |
POST https://api.chapa.co/v2/virtual-accounts/VA_ABC123456/deduct
Authorization: Bearer CHAPA_TEST_xxxxxxxxxxxxx
Content-Type: application/json
{
"amount": 3000,
"currency": "ETB",
"merchant_reference": "DEB_001",
"reason": "Payment for order ORD_99887",
"meta": {
"customer_id": "CUST_12345",
"order_id": "ORD_99887"
}
}
{
"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"
}
}
| 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 |
currency must match the virtual account currency
amount must be a positive number
- Account must have sufficient funds
merchant_reference should be unique (recommended)
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)
- Use idempotency keys on retries
- Store debit references for reconciliation
- Log
balance_before / balance_after for auditing
- Use
merchant_reference to prevent duplicate charges
- Optionally validate balance before calling deduct (still handle race conditions)
| 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 |