/api/v1/withdraw/executeWithdrawal
Initiates a fund transfer from a merchant's Beqelal account to a customer's Financial Institution account.
When to Use
Use this endpoint when a merchant wants to perform an actual withdraw — transferring funds directly from Beqelal into a customer's Financial Institution account via API integration (no checkout page involved).
Authentication
Requires the following headers:
app-id: Your application identifier (from Merchant Portal → Integration → APP ID)api-key: Your secret API key (from Account Management → Generate API Key → API Keys)Request Parameters
Mandatory Fields
bankstringRequiredInstitution ID of the recipient Financial Institution (inst_id)
accountstringRequiredCustomer's Financial Institution account number
amountnumberRequiredAmount to be transferred (in ETB)
trace_numbernumberRequiredMerchant's own transaction reference (must be unique)
Optional Fields
callback_urlstring (url)OptionalIf provided, overrides the portal-configured webhook URL for this transaction. If not provided, the portal-configured webhook URL will be used.
reasonstring (url)OptionalReason for the withdrawal
Processing Flow
1. Input Validation
- Checks if the merchant's account is active and has sufficient balance
- Validates the destination Financial Institution and account_no
- Ensures the transaction complies with minimum balance and transaction limits
2. Fee Calculation
- The system calculates applicable service charges and taxes
- Total debited amount =
amount + fee + VAT (15% of fee) + disaster risk (5% of fee)
3. Fund Transfer Execution
- Funds are deducted from the merchant's Beqelal account
- The customer's Financial Institution account is credited
Response
Returns JSON containing:
- Unique Beqelal transaction reference (
reference_id) - Recipient name from the Financial Institution
- Financial Institution name and acronym
- Transaction amount, fees, and remaining balance (
balance) - Status:
PROCESSEDif transfer is successful
Notes
- This endpoint triggers an actual withdraw, not just validation
- Funds are debited from Beqelal and credited to the Financial Institution account
- All amounts are in ETB
- Enforces minimum/maximum limits and balance thresholds
Error Handling
Returns 400 Bad Request for:
- Inactive or invalid customer account
- Insufficient balance or transaction rule violation
- Missing or invalid request fields
- Real-time query failure to the Financial Institution
Code Examples
curl -X POST "{base_url}/api/v1/withdraw/execute" \
-H "Content-Type: application/json" \
-H "app-id: YOUR_APP_ID" \
-H "api-key: YOUR_API_KEY" \
-d '{
"bank": "404050",
"account": "251911000000",
"callback_url": "https://example.et/",
"amount": 100,
"trace_number": "70RNVPO548",
"reason": "withdrawal to customer"
}'Success Responses
This API can return two types of successful responses, both with status_code = 200, but with different meanings.
Success (200)
200 - Payout completed successfullyWhen the response status is PROCESSED, it means:
- The payout was successfully completed
- Funds have been credited to the destination bank account
- The operation was handled synchronously
- No further callback/webhook will be sent
{
"id": "4G2710H78P",
"bank": "404050",
"account": "251911000000",
"amount": 100,
"fee": 0,
"trace_number": "70RNV744444PO548",
"bbf": 8578.23,
"balance": 940,
"process": "Withdraw",
"description": "Withdraw to bank",
"updated_at": "2025-07-02T23:39:34.821806",
"status": "PROCESSED",
"status_code": 200,
"message": "SUCCESS",
"detail": "Operation Completed Successfully",
"reason": ""
}PENDING — Asynchronous Success (Submitted)
200 - Request submitted, processingWhen the response status is PENDING, it means:
- The payout request was successfully submitted
- The payout is still being processed
- The final payout status will be sent later via callback/webhook
- The funds are not yet confirmed as credited to the bank
{
"id": "4G2710H78P",
"bank": "404050",
"account": "251911000000",
"amount": 100,
"fee": 0,
"trace_number": "70RNV744444PO548",
"bbf": 8578.23,
"balance": 940,
"process": "Withdraw",
"description": "Withdraw to bank",
"updated_at": "2025-07-02T23:39:34.821806",
"status": "PENDING",
"status_code": 200,
"message": "SUCCESS",
"detail": "Operation Completed Successfully",
"reason": ""
}Webhooks
If a webhook URL is configured (portal setting or callback_url from original request), Beqelal sends the result back as a POST request with the following format:
HTTP Headers
Content-Type: application/json
User-Agent: Beqelal-Webhook/1.0
X-Webhook-Signature: <HMAC_SHA256_SIGNATURE> (if webhook secret configured)
X-Webhook-Timestamp: <UNIX_TIMESTAMP> (if webhook secret configured)Request Body
{
"reference": "BEQELAL_REF_123",
"trace_number": "MERCHANT_REF_456",
"status": "PROCESSED",
"amount": 100.0,
"timestamp": 1695123456
}Fields
reference: Beqelal's reference numbertrace_number: Merchant's own transaction referencestatus: Can be 'PROCESSED' (success) or 'FAILED' (failure)amount: Transaction amounttimestamp: Unix timestamp when the webhook was sentSignature Verification
If you have configured a webhook secret, verify the X-Webhook-Signature header using HMAC SHA256. See the webhook test endpoint documentation for details.
Retry Logic
Beqelal will automatically retry failed webhook deliveries up to 3 times with a 1-second delay between attempts.
Quick Comparison
| Status | Meaning | Final? | Callback/Webhook |
|---|---|---|---|
PROCESSED | Payout completed successfully | ✅Yes | ❌No |
PENDING | Request accepted, processing | ❌No | ✅Yes |
Duplicate Trace Number (400)
400 - Duplicate trace number{
"error": {
"status": "FAILED",
"status_code": "439",
"message": "TRACE_NUMBER",
"detail": "trace number must be unique"
}
}Unauthorized IP Access (479)
479 - Unauthorized IP{
"error": {
"status": "FAILED",
"status_code": "479",
"message": "UNAUTHORIZED_IP_ACCESS",
"detail": "Unauthorized IP address access."
}
}