Withdrawals
Withdrawals move funds from a user's available_balanceto their verified bank account via the payment provider's disbursement rail. Your app should check the wallet balance, ensure a bank account exists, then request a withdrawal on behalf of the user.
Live keys only. Test-mode balances are simulated and can never be paid out — a withdrawal request on a test key returns 400("withdrawals are not available in test mode").
Withdrawal statuses
pending → processing → successful
↘ failed (funds returned to available balance)
↘ cancelledWithdrawals are auto-approved and move to processing immediately. If Kashia ever disables auto-approval, a request rests at pending until an operator approves it — treat pending as a valid resting state.
Automatic settlement payouts
Marketplace sellers normally never need to withdraw manually: when an escrow settles, Kashia automatically pays the seller's seller_amount — in full, with no withdrawal fee — to their default verified bank account, and emits payout.successful or payout.failed webhooks (reference prefix PYT); payout.initiatedfires additionally when the provider processes the transfer asynchronously, so don't depend on receiving it. If the payout fails or no verified account is on file, the funds stay in the seller's Kashia wallet and Kashia support can retry once an account is added. The manual withdrawal flow below still applies to merchant wallet balances (marketplace commissions, single-vendor proceeds) and to any funds sitting in a wallet.
Limits & fees
- Minimum withdrawal: ₦1,000 (100,000 kobo)
- Maximum withdrawal: ₦5,000,000 (500,000,000 kobo)
- Withdrawal fee: flat ₦50 (5,000 kobo) by default, deducted from the amount
- All four values are live configuration — read them any time from
GET /api/v1/withdrawals/config(no auth required):{ fee_type, fee_value, min_amount, max_amount } - Settlement payouts bypass all of this: full amount, zero fee, no min/max
Complete flow
GET /external/users/:userId/wallet— confirm available balanceGET /external/users/:userId/bank-accounts— pick a verified account (or add one first)POST /external/users/:userId/withdrawals— initiate payout- Listen for
withdrawal.initiated,withdrawal.successful, orwithdrawal.failedwebhooks
Endpoints
/api/v1/external/users/:userId/withdrawalsRequest a withdrawal (returns 201). Debits available balance and initiates the disbursement with the active payment provider.
Request example
curl -X POST https://vault-api.kashiahq.com/api/v1/external/users/USER_UUID/withdrawals \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"amount": 9500000,
"bank_account_id": "BANK_ACCOUNT_UUID",
"currency": "NGN"
}'Response
{
"success": true,
"data": {
"id": "uuid",
"reference": "WTH-a1b2c3d4",
"amount": 9500000,
"fee": 5000,
"net_amount": 9495000,
"currency": "NGN",
"status": "processing",
"source": "manual",
"retry_count": 0,
"bank_account": {
"bank_name": "Guaranty Trust Bank",
"account_number": "0123456789",
"account_name": "JOHN DOE"
},
"created_at": "2025-01-15T10:30:00Z"
}
}/api/v1/external/users/:userId/withdrawalsList withdrawals for a user. Supports status filter and pagination.
| Parameter | Type | Required | Description |
|---|---|---|---|
status | string | No | pending, processing, successful, failed, cancelled |
page | integer | No (default: 1) | Page number |
per_page | integer | No (default: 20) | Items per page |
/api/v1/external/users/:userId/withdrawals/:withdrawalIdGet withdrawal status and bank account summary.