Initiate Withdrawal
Overview
The Initiate Withdrawal API allows financial institutions to process withdrawal transactions from customer deposit accounts. This operation debits the account balance, validates withdrawal limits, enforces overdraft rules, and handles all necessary accounting entries through configurable channels (such as teller transactions, ATMs, or online banking).
Command Details
Command Name: InitiateWithdrawalCommand
Operation Type: Command (Write Operation)
Transaction Type: Withdrawal
Use Cases
- Cash Withdrawals: Process over-the-counter cash withdrawals at bank branches
- ATM Withdrawals: Handle automated teller machine withdrawal transactions
- Online/Mobile Banking Withdrawals: Process customer-initiated withdrawals through digital channels
- Teller Withdrawals: Support assisted withdrawals at teller counters
- Check Withdrawals: Process check issuance and payment transactions
- Emergency Withdrawals: Handle urgent withdrawal requests with proper authorization
API Endpoint
POST /api/bpm/cmd
Content-Type: application/json
Authorization: Bearer {access_token}
Request Structure
Request Body
{
"commandName": "InitiateWithdrawalCommand",
"data": {
"accountEncodedKey": "string",
"channelCode": "string",
"amount": 0.00,
"transactionType": 2,
"notes": "string",
"serviceId": "string",
"serviceDescription": "string",
"isBackDated": false,
"backDateValueDate": "2025-12-17T10:30:00Z",
"isBookingDate": false,
"bookingDate": "2025-12-17T10:30:00Z",
"entryDate": "2025-12-17T10:30:00Z"
}
}
Request Fields
| Field Name | Type | Mandatory | Description | Additional Information |
|---|---|---|---|---|
accountEncodedKey | String | Yes | Unique identifier or account number of the deposit account | Can be either encodedKey or account number |
channelCode | String | Yes | Code identifying the transaction channel | Must be a valid channel code (e.g., TELLER, ATM, MOBILE, ONLINE) |
amount | Decimal | Yes | Withdrawal amount | Must be positive number with up to 2 decimal places |
transactionType | Integer | Yes | Type of core transaction | Default: 2 (Withdrawal). Enum: CoreTransactionType |
notes | String | No | Transaction notes or remarks | Free text field for additional information |
serviceId | String | No | Service identifier for the transaction | Used for tracking specific services |
serviceDescription | String | No | Description of the service | Human-readable service description |
isBackDated | Boolean | No | Whether transaction is backdated | Default: false. Requires backDateValueDate if true |
backDateValueDate | DateTime | Conditional | Value date for backdated transaction | Required if isBackDated is true. ISO 8601 format |
isBookingDate | Boolean | No | Whether to use specific booking date | Default: false. Requires bookingDate if true |
bookingDate | DateTime | Conditional | Specific booking date for transaction | Required if isBookingDate is true. ISO 8601 format |
entryDate | DateTime | No | Transaction entry date | ISO 8601 format. Defaults to current date/time |
Sample Requests
1. Standard ATM Cash Withdrawal
{
"commandName": "InitiateWithdrawalCommand",
"data": {
"accountEncodedKey": "8a8e87e87d1234567890abcd",
"channelCode": "ATM",
"amount": 5000.00,
"transactionType": 2,
"notes": "ATM withdrawal - Branch A ATM"
}
}
2. Teller-Assisted Withdrawal
{
"commandName": "InitiateWithdrawalCommand",
"data": {
"accountEncodedKey": "1234567890",
"channelCode": "TELLER",
"amount": 25000.00,
"transactionType": 2,
"notes": "Counter withdrawal - verified with ID",
"serviceId": "TELLER-WD-2025-001",
"serviceDescription": "Teller Withdrawal Service"
}
}
3. Backdated Withdrawal (Administrative Correction)
{
"commandName": "InitiateWithdrawalCommand",
"data": {
"accountEncodedKey": "8a8e87e87d1234567890abcd",
"channelCode": "BRANCH",
"amount": 10000.00,
"transactionType": 2,
"notes": "Correcting missed withdrawal from previous day",
"isBackDated": true,
"backDateValueDate": "2025-12-16T14:00:00Z"
}
}
4. Online Banking Withdrawal
{
"commandName": "InitiateWithdrawalCommand",
"data": {
"accountEncodedKey": "1234567890",
"channelCode": "ONLINE",
"amount": 15000.00,
"transactionType": 2,
"notes": "Online transfer to external account"
}
}
Response Structure
Success Response
{
"isSuccessful": true,
"statusCode": "00",
"message": "Deposit account has been added successfully.",
"data": {
"transactionKey": "2000345",
"accountNumber": "1234567890",
"accountOfficerEncodedKey": "8a8e87e87d0987654321",
"branchEncodedKey": "8a8e87e87d1111222233",
"clientEncodedKey": "8a8e87e87d4444555566",
"depositEncodedKey": "8a8e87e87d1234567890abcd"
}
}
Response Fields
| Field Name | Type | Description |
|---|---|---|
transactionKey | String | Unique transaction reference number |
accountNumber | String | Account number from which withdrawal was made |
accountOfficerEncodedKey | String | Encoded key of the account officer |
branchEncodedKey | String | Encoded key of the branch |
clientEncodedKey | String | Encoded key of the client/customer |
depositEncodedKey | String | Encoded key of the deposit account |
Error Responses
1. Invalid Account
{
"isSuccessful": false,
"statusCode": "CBS_404",
"message": "Invalid deposit account encoded key"
}
2. Insufficient Balance
{
"isSuccessful": false,
"statusCode": "CBS_400",
"message": "Insufficient balance"
}
3. Account Frozen
{
"isSuccessful": false,
"statusCode": "CBS_400",
"message": "You cannot perform any transaction on this account. It is presently frozen."
}
4. Withdrawal Limit Exceeded
{
"isSuccessful": false,
"statusCode": "CBS_425",
"message": "The maximum transaction withdrawal limit on the account tier is 50000.00 NGN."
}
5. Daily Limit Exceeded
{
"isSuccessful": false,
"statusCode": "CBS_425",
"message": "Exceeded the transaction limit for the day. The maximum amount allowed for withdrawal for the day is 100000.00 NGN."
}
6. Account Locked
{
"isSuccessful": false,
"statusCode": "CBS_400",
"message": "You cannot perform any transaction on this account. It is presently locked."
}
Business Logic
Transaction Processing Flow
-
Account Validation
- Verify account exists and is accessible
- Check account status (not frozen, locked, or dormant)
- Validate account type allows withdrawals
-
Channel Validation
- Validate channel code exists and is active
- Verify channel is configured for withdrawal operations
- Check channel has associated GL account
-
Balance Validation
- Check account has sufficient balance for withdrawal
- Consider minimum balance requirements
- Factor in available overdraft facilities if configured
- Account for holds and locks on the account
-
Limit Validation
- Check against account tier single withdrawal transaction limit
- Verify daily withdrawal limit not exceeded
- Check monthly withdrawal limit not exceeded
- Validate daily transaction count limit
- Verify monthly transaction count limit
- Check product-level maximum withdrawal amount
-
Overdraft Handling
- If account has overdraft facility, calculate allowable overdraft
- Check overdraft expiry date
- Adjust available balance with overdraft limit
- Ensure minimum opening balance maintained
-
Date Processing
- Apply backdating if specified (requires backDateValueDate)
- Set booking date if specified
- Default to current date/time if no special dates
-
Fee Calculation
- Calculate applicable withdrawal fees based on product configuration
- Apply fee trigger rules (OnWithdrawal)
- Generate fee transactions if applicable
-
Narration Generation
- Execute customer narration template with transaction context
- Execute channel narration template
- Generate transaction ID from template
-
Transaction Creation
- Create CBS transaction record
- Generate unique transaction key
- Set transaction state (PENDING or SETTLED based on approval requirements)
-
Account Updates
- If pending approval: Decrease hold amount (lock debit), create amount lock transaction
- If immediate settlement: Debit account balance, create deposit transaction
- Update account state to Active if currently inactive
- Create settlement transaction for channel
-
PND (Post No Debit) Handling
- If withdrawal limit exceeded and PND not already active, activate PND on account
- Prevents further debits until PND is released
-
Persistence
- Save all transaction records
- Update account balances
- Commit changes to database
Special Handling
Overdraft Accounts:
- Checks for active overdraft adjustment with valid expiry date
- Calculates allowable overdraft based on overdraft limit
- Ensures minimum opening balance is maintained even with overdraft
Pending Transactions:
- Amount is locked (decreases holdAmount for debit lock)
- Amount lock transaction created with DEBIT_LOCKED state
- Account balance not updated until approval
Settled Transactions:
- Account balance immediately debited
- Deposit transaction created with new balance
- Account state set to Active
PND Activation:
- If withdrawal exceeds limit, PND (Post No Debit) is automatically activated
- Prevents further debit transactions until manually released
- Requires administrator intervention to release
Account Balance Impact
Immediate Settlement (No Approval Required)
Before Transaction:
- Account Balance: 50,000.00
- Available Balance: 50,000.00
- Hold Amount: 0.00
Withdrawal: 15,000.00
After Transaction:
- Account Balance: 35,000.00
- Available Balance: 35,000.00
- Hold Amount: 0.00
With Overdraft Facility
Before Transaction:
- Account Balance: 5,000.00
- Available Balance: 5,000.00
- Overdraft Limit: 10,000.00
- Minimum Opening Balance: 1,000.00
Withdrawal: 12,000.00
After Transaction:
- Account Balance: -7,000.00
- Available Balance: -7,000.00
- Overdraft Used: 7,000.00 (within 10,000 limit)
- Actual Balance after min. requirement: Still acceptable (5,000 - 12,000 + 10,000 overdraft - 1,000 min = valid)
Pending Approval
Before Transaction:
- Account Balance: 50,000.00
- Available Balance: 50,000.00
- Hold Amount: 0.00
Withdrawal (Pending): 40,000.00
After Transaction:
- Account Balance: 50,000.00 (unchanged)
- Available Balance: 50,000.00
- Hold Amount: -40,000.00 (locked for debit until approved)
Related Operations
- InitiateDeposit - Process deposit transactions
- InitiateTransfer - Transfer funds between accounts
- ReleasePNDFromDepositAccount - Release Post No Debit restriction
- RetrieveDepositTransactionList - Query transaction history
Architecture Diagram
Security Considerations
- Authentication: Requires valid bearer token
- Authorization: User must have permission to process withdrawals on the account
- Audit Trail: All withdrawals are logged with user information, timestamps, and IP addresses
- Channel Security: Channel must be properly configured and validated
- Amount Validation: Prevents negative amounts and enforces limits
- Fraud Detection: Large withdrawals may trigger fraud alerts
- PND Protection: Automatic PND activation prevents unauthorized debits after limit violations
Performance Considerations
- Transaction Speed: Typically completes in 200-500ms
- Database Impact: Creates 2-4 transaction records per withdrawal
- Caching: Channel configuration is cached for improved performance
- Concurrent Transactions: Uses database locking to prevent race conditions
- Indexing: Account number and transaction key are indexed for fast lookups
- Balance Calculations: Efficient queries for transaction breakdowns and limits
Troubleshooting
Issue: Insufficient Balance Error
Symptom: CBS_400 error with message "Insufficient balance"
Possible Causes:
- Account balance lower than withdrawal amount
- Minimum balance requirement not considered
- Hold amount reducing available balance
- Overdraft facility expired or not configured
Solution:
- Check actual account balance vs. withdrawal amount
- Verify minimum opening balance requirement from product configuration
- Check for pending transactions or holds reducing available balance
- If overdraft exists, verify it hasn't expired
- Consider splitting withdrawal into smaller amounts
Issue: Daily Limit Exceeded
Symptom: Error stating daily withdrawal limit exceeded
Possible Causes:
- Customer has reached daily withdrawal amount limit
- Daily transaction count limit reached
- Multiple withdrawals throughout the day accumulated
- Account tier has restrictive limits
Solution:
- Check transaction breakdown for today's withdrawal total
- Verify account tier daily withdrawal limit
- Inform customer of limit and current usage
- Process withdrawal the next business day
- Request tier upgrade if customer qualifies
Issue: PND Activated on Account
Symptom: Withdrawal succeeded but subsequent transactions fail with PND error
Possible Causes:
- Withdrawal exceeded configured limit, triggering automatic PND
- System automatically activated PND for protection
- No administrator approval for PND release
Solution:
- Verify withdrawal amount vs. configured limits
- Check account for active PND flag
- Use
ReleasePNDFromDepositAccountCommandto remove PND - Investigate why limit was exceeded
- Consider tier upgrade or limit adjustment
Issue: Overdraft Not Applied
Symptom: Withdrawal denied despite account having overdraft facility
Possible Causes:
- Overdraft adjustment has expired
- Withdrawal amount exceeds balance + overdraft limit
- Minimum balance still cannot be maintained even with overdraft
- Overdraft not properly configured
Solution:
- Check overdraft expiry date in DepositAccoundOverdraftAdjustment table
- Verify overdraft limit is sufficient for requested withdrawal
- Calculate: balance - withdrawal + overdraft - minimum balance
- Renew overdraft facility if expired
- Increase overdraft limit if customer qualifies
Issue: Channel Unavailable
Symptom: CBS_404 error for channel code
Possible Causes:
- Channel code doesn't exist in system
- Channel is inactive or disabled
- Channel not configured for withdrawal operations
- Channel GL account not set up
Solution:
- Verify channel code with
LookUpTransactionChannelsQuery - Check channel is active and withdrawal operation is enabled
- Ensure channel has associated GL account
- Contact system administrator for channel configuration
- Use alternative channel if available
Issue: Transaction Count Limit Reached
Symptom: Error stating maximum number of transactions reached
Possible Causes:
- Customer has made maximum allowed withdrawals for the day
- Monthly transaction count limit reached
- Account tier has very restrictive transaction limits
- Test transactions counted toward limit
Solution:
- Check transaction breakdown for count today/this month
- Verify account tier transaction count limits
- Explain limits to customer
- Process urgent withdrawals with supervisor override if authorized
- Recommend tier upgrade for customers with high transaction needs
Monitoring and Alerts
Key Metrics to Track
- Total withdrawal volume (amount)
- Withdrawal transaction count
- Success rate percentage
- Average transaction processing time
- Failed withdrawal rate
- Withdrawals by channel
- Insufficient balance rejection rate
- PND activation frequency
Recommended Alerts
- Failed withdrawals exceeding 5% threshold
- Unusually large withdrawal amounts (potential fraud)
- Multiple withdrawal attempts on single account
- High number of insufficient balance errors
- Withdrawal processing time exceeding 1 second
- Channel unavailability
- Frequent PND activations (may indicate limit configuration issues)
Audit and Compliance
Audit Log Entries
Every withdrawal transaction creates audit records including:
- Transaction key and timestamp
- User who initiated transaction
- Account number and customer details
- Amount and currency
- Channel used
- Before and after account balances
- Notes and remarks
- IP address and device information
- Approval workflow (if applicable)
- PND activation (if triggered)
Compliance Requirements
- Anti-Money Laundering (AML): Large withdrawals may trigger AML checks
- Transaction Limits: Must comply with regulatory withdrawal limits
- Customer Verification: Identity verification required for large withdrawals
- Reporting: Withdrawals may need to be reported to financial authorities
- Record Retention: Transaction records retained per regulatory requirements (typically 7+ years)
- Fraud Prevention: Multiple withdrawal attempts monitored for suspicious patterns
Code Examples
C# Example
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public class WithdrawalService
{
private readonly HttpClient _httpClient;
private readonly string _baseUrl;
private readonly string _bearerToken;
public WithdrawalService(HttpClient httpClient, string baseUrl, string bearerToken)
{
_httpClient = httpClient;
_baseUrl = baseUrl;
_bearerToken = bearerToken;
}
public async Task<WithdrawalResponse> InitiateWithdrawalAsync(string accountEncodedKey,
string channelCode, decimal amount, string notes = null)
{
var request = new
{
commandName = "InitiateWithdrawalCommand",
data = new
{
accountEncodedKey,
channelCode,
amount,
transactionType = 2,
notes
}
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _bearerToken);
var response = await _httpClient.PostAsync($"{_baseUrl}/api/bpm/cmd", content);
var responseJson = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<WithdrawalResponse>(responseJson);
}
}
public class WithdrawalResponse
{
public bool IsSuccessful { get; set; }
public string StatusCode { get; set; }
public string Message { get; set; }
public WithdrawalData Data { get; set; }
}
public class WithdrawalData
{
public string TransactionKey { get; set; }
public string AccountNumber { get; set; }
public string AccountOfficerEncodedKey { get; set; }
public string BranchEncodedKey { get; set; }
public string ClientEncodedKey { get; set; }
public string DepositEncodedKey { get; set; }
}
// Usage
var withdrawalService = new WithdrawalService(httpClient, "https://api.banklingo.com", "your-token-here");
var result = await withdrawalService.InitiateWithdrawalAsync(
"8a8e87e87d1234567890abcd",
"ATM",
5000.00m,
"ATM withdrawal - Branch A"
);
if (result.IsSuccessful)
{
Console.WriteLine($"Withdrawal successful. Transaction Key: {result.Data.TransactionKey}");
}
else
{
Console.WriteLine($"Withdrawal failed: {result.Message}");
}
JavaScript/TypeScript Example
interface InitiateWithdrawalRequest {
commandName: string;
data: {
accountEncodedKey: string;
channelCode: string;
amount: number;
transactionType: number;
notes?: string;
serviceId?: string;
serviceDescription?: string;
isBackDated?: boolean;
backDateValueDate?: string;
};
}
interface WithdrawalResponse {
isSuccessful: boolean;
statusCode: string;
message: string;
data?: {
transactionKey: string;
accountNumber: string;
accountOfficerEncodedKey: string;
branchEncodedKey: string;
clientEncodedKey: string;
depositEncodedKey: string;
};
}
async function initiateWithdrawal(
accountEncodedKey: string,
channelCode: string,
amount: number,
notes?: string
): Promise<WithdrawalResponse> {
const request: InitiateWithdrawalRequest = {
commandName: 'InitiateWithdrawalCommand',
data: {
accountEncodedKey,
channelCode,
amount,
transactionType: 2,
notes,
},
};
const response = await fetch('https://api.banklingo.com/api/bpm/cmd', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${YOUR_ACCESS_TOKEN}`,
},
body: JSON.stringify(request),
});
const result: WithdrawalResponse = await response.json();
return result;
}
// Usage
const result = await initiateWithdrawal(
'8a8e87e87d1234567890abcd',
'TELLER',
25000.00,
'Counter withdrawal - verified with ID'
);
if (result.isSuccessful) {
console.log(`Withdrawal successful! Transaction: ${result.data?.transactionKey}`);
} else {
console.error(`Withdrawal failed: ${result.message}`);
}
Python Example
import requests
import json
from typing import Optional, Dict, Any
from datetime import datetime
class WithdrawalService:
def __init__(self, base_url: str, access_token: str):
self.base_url = base_url
self.access_token = access_token
self.headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {access_token}'
}
def initiate_withdrawal(
self,
account_encoded_key: str,
channel_code: str,
amount: float,
notes: Optional[str] = None,
service_id: Optional[str] = None,
is_backdated: bool = False,
backdate_value_date: Optional[datetime] = None
) -> Dict[str, Any]:
"""
Initiate a withdrawal transaction from a deposit account.
Args:
account_encoded_key: Account identifier (encoded key or account number)
channel_code: Transaction channel code (e.g., 'ATM', 'TELLER')
amount: Withdrawal amount (must be positive)
notes: Optional transaction notes
service_id: Optional service identifier
is_backdated: Whether transaction is backdated
backdate_value_date: Value date for backdated transaction
Returns:
Dictionary containing response with transaction details
"""
payload = {
'commandName': 'InitiateWithdrawalCommand',
'data': {
'accountEncodedKey': account_encoded_key,
'channelCode': channel_code,
'amount': amount,
'transactionType': 2,
}
}
# Add optional fields
if notes:
payload['data']['notes'] = notes
if service_id:
payload['data']['serviceId'] = service_id
if is_backdated:
payload['data']['isBackDated'] = True
if backdate_value_date:
payload['data']['backDateValueDate'] = backdate_value_date.isoformat()
response = requests.post(
f'{self.base_url}/api/bpm/cmd',
json=payload,
headers=self.headers
)
return response.json()
# Usage
withdrawal_service = WithdrawalService(
base_url='https://api.banklingo.com',
access_token='your-access-token-here'
)
result = withdrawal_service.initiate_withdrawal(
account_encoded_key='8a8e87e87d1234567890abcd',
channel_code='ATM',
amount=5000.00,
notes='ATM withdrawal - Branch A ATM'
)
if result['isSuccessful']:
print(f"Withdrawal successful!")
print(f"Transaction Key: {result['data']['transactionKey']}")
print(f"Account Number: {result['data']['accountNumber']}")
else:
print(f"Withdrawal failed: {result['message']}")
print(f"Status Code: {result['statusCode']}")
Response Codes
| Code | Description | Resolution |
|---|---|---|
00 | Success | Withdrawal processed successfully |
CBS_400 | Bad Request / Account Locked or Frozen | Check account status, ensure account is not frozen, locked, or dormant |
CBS_404 | Account or Channel Not Found | Verify account encoded key and channel code |
CBS_425 | Withdrawal Limit Exceeded | Check account tier limits, wait for next period, or request tier upgrade |
CBS_426 | Insufficient Balance | Verify account balance, check for holds, review overdraft facility |
CBS_427 | Invalid Amount | Ensure amount is positive and properly formatted |
CBS_428 | Daily/Monthly Limit Exceeded | Check transaction breakdown, inform customer of limits, process next period |
Business Rules
Validation Rules
- Account Encoded Key - Must correspond to an existing, active deposit account; can be either the encoded key or account number
- Channel Code - Must be a valid, active transaction channel configured for withdrawal operations with associated GL account
- Amount - Must be a positive decimal value with up to 2 decimal places; zero or negative amounts are rejected
- Transaction Type - Must be valid CoreTransactionType enum value; defaults to 2 (Withdrawal)
- Backdated Transactions - If
isBackDatedis true,backDateValueDatemust be provided and must be in the past - Booking Date - If
isBookingDateis true,bookingDatemust be provided - Account Status - Account must not be frozen (
IsOnFreeze= false), locked, or dormant - Balance Sufficiency - Account balance (plus any active overdraft) must be sufficient for withdrawal amount plus minimum opening balance requirement
Operational Rules
- Withdrawals debit account balance immediately for settled transactions, or create hold amount (debit lock) for pending transactions requiring approval
- Transaction limits are enforced based on account tier configuration (single transaction limit, daily amount limit, monthly amount limit, daily count limit, monthly count limit)
- Minimum opening balance must be maintained after withdrawal, even when overdraft facility is used
- Overdraft facilities are validated for active status (expiry date must be in the future) before being applied to available balance calculations
- If withdrawal exceeds configured limits and PND (Post No Debit) is not already active, system automatically activates PND to prevent further unauthorized debits
- Fees are calculated automatically based on product configuration and applied according to fee trigger rules (OnWithdrawal)
- Narrations are generated from configurable templates using transaction context (account, channel, amount, etc.)
- All withdrawal transactions create corresponding accounting entries: debit to customer account, credit to channel/GL account
- Pending transactions (requiring approval) create amount lock transactions with DEBIT_LOCKED state until approved or rejected
- Transaction keys are generated using configurable templates and sequence numbers to ensure uniqueness
- Date handling supports backdating (for corrections) and custom booking dates with proper validation
- All withdrawals are recorded in audit trail with complete transaction context including user, timestamp, IP address, and device information
Changelog
Version 1.0.0 - December 17, 2025
- Initial documentation
- Comprehensive field documentation with business rules
- Multiple code examples (C#, JavaScript, Python)
- Detailed business logic and transaction flow
- Troubleshooting guide with common scenarios
- Complete API specification with sample requests/responses
- Overdraft handling documentation
- PND activation rules
Last Updated: December 17, 2025
API Version: 1.0
Document Version: 1.0.0