Universal Transaction Management
Overview
BankLingo provides a universal transaction management system that standardizes approval, rejection, cancellation, and reversal workflows across all transaction types. These commands work consistently whether you're managing deposits, withdrawals, cheque transactions, loan disbursements, teller operations, vault movements, or till transfers.
This document describes the four universal commands that enable consistent transaction lifecycle management throughout the core banking system.
Transaction State Model
All transactions in BankLingo follow a standardized state model with four possible states:
Transaction States
State Descriptions
| State | Description | Entry Point | Exit Points | Balance Impact | Hold Impact |
|---|---|---|---|---|---|
| PENDING | Transaction awaits approval | Created with requireApproval=true | SETTLED (approve), CANCELLED (reject/cancel) | None | Increased |
| SETTLED | Transaction completed successfully | Created with requireApproval=false OR approved from PENDING | REVERSED (reverse) | Updated | Released |
| CANCELLED | Transaction rejected before settlement | Rejected/cancelled from PENDING | None (terminal) | None | Released |
| REVERSED | Transaction reversed after settlement | Reversed from SETTLED | None (terminal) | Restored | N/A |
Universal Commands
1. ApproveTransactionCommand
Approves a pending transaction, transitioning it from PENDING to SETTLED and applying balance changes.
Endpoint
POST /api/bpm/cmd/ApproveTransaction
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
transactionId | guid | Yes | Unique identifier of the pending transaction |
approverNotes | string | No | Optional notes from approver (max 500 characters) |
approvalDate | datetime | No | Optional approval date (defaults to current time) |
Example Request
{
"transactionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"approverNotes": "High-value deposit verified. Customer identity confirmed via BVN.",
"approvalDate": "2026-01-01T14:30:00Z"
}
Response (200 OK)
{
"isSuccessful": true,
"message": "Transaction approved successfully",
"data": {
"transactionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"previousState": "PENDING",
"newState": "SETTLED",
"approvedBy": "Jane Smith",
"approvalDate": "2026-01-01T14:30:00Z",
"balanceImpact": {
"accountNumber": "2001234567",
"previousBalance": 100000.00,
"newBalance": 600000.00,
"transactionAmount": 500000.00,
"holdReleased": 500000.00
}
}
}
Approval Effects by Transaction Type
| Transaction Type | Balance Change | Additional Effects |
|---|---|---|
| Deposit | Account balance increased | Hold released, available balance increased |
| Withdrawal | Account balance decreased | Hold released, cash dispensed, available balance decreased |
| Cheque Deposit | Account balance increased | Cheque state → CLEARED (if cheque also approved), hold released |
| Cheque Withdrawal | Account balance decreased | Cheque state → CLEARED, hold released |
| Loan Disbursement | Loan account funded | Loan state → DISBURSED, disbursement amount transferred |
| Teller Transaction | Till/account balance updated | Till balance updated, hold released |
| Vault Transaction | Vault balance updated | Vault inventory updated |
| Till Transfer | Both tills updated | Source till decreased, destination till increased |
2. RejectTransactionCommand
Rejects a pending transaction, transitioning it from PENDING to CANCELLED without applying balance changes.
Endpoint
POST /api/bpm/cmd/RejectTransaction
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
transactionId | guid | Yes | Unique identifier of the pending transaction |
rejectionReason | string | Yes | Reason for rejection (required for audit, max 1000 characters) |
rejectionCategory | string | No | Category: FRAUD, COMPLIANCE, INSUFFICIENT_DOCUMENTATION, POLICY_VIOLATION, OTHER |
Example Request
{
"transactionId": "b2c3d4e5-f6g7-8901-bcde-f12345678901",
"rejectionReason": "Customer unable to provide valid source of funds documentation. Transaction flagged for AML review.",
"rejectionCategory": "COMPLIANCE"
}
Response (200 OK)
{
"isSuccessful": true,
"message": "Transaction rejected successfully",
"data": {
"transactionId": "b2c3d4e5-f6g7-8901-bcde-f12345678901",
"previousState": "PENDING",
"newState": "CANCELLED",
"rejectedBy": "John Doe",
"rejectionDate": "2026-01-01T15:00:00Z",
"rejectionReason": "Customer unable to provide valid source of funds documentation. Transaction flagged for AML review.",
"rejectionCategory": "COMPLIANCE",
"balanceImpact": {
"accountNumber": "2001234567",
"balance": 100000.00,
"holdReleased": 500000.00,
"netChange": 0.00
}
}
}
Rejection Effects
- ✅ Transaction state: PENDING → CANCELLED
- ✅ Hold released (if applicable)
- ✅ Balance unchanged (transaction never settled)
- ✅ Customer notified of rejection (via SMS/Email)
- ✅ Audit trail created with rejection reason
- ✅ Compliance report generated (if fraud/AML category)
3. CancelTransactionCommand
Cancels a pending transaction, transitioning it from PENDING to CANCELLED. Functionally equivalent to RejectTransaction but typically initiated by the transaction creator rather than an approver.
Endpoint
POST /api/bpm/cmd/CancelTransaction
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
transactionId | guid | Yes | Unique identifier of the pending transaction |
cancellationReason | string | Yes | Reason for cancellation (required for audit, max 1000 characters) |
Example Request
{
"transactionId": "c3d4e5f6-g7h8-9012-cdef-123456789012",
"cancellationReason": "Customer requested cancellation before approval. Will re-submit with correct beneficiary account."
}
Response (200 OK)
{
"isSuccessful": true,
"message": "Transaction cancelled successfully",
"data": {
"transactionId": "c3d4e5f6-g7h8-9012-cdef-123456789012",
"previousState": "PENDING",
"newState": "CANCELLED",
"cancelledBy": "Jane Smith",
"cancellationDate": "2026-01-01T16:00:00Z",
"cancellationReason": "Customer requested cancellation before approval. Will re-submit with correct beneficiary account.",
"balanceImpact": {
"accountNumber": "2001234567",
"balance": 100000.00,
"holdReleased": 500000.00,
"netChange": 0.00
}
}
}
Cancel vs Reject
| Aspect | CancelTransaction | RejectTransaction |
|---|---|---|
| Initiator | Transaction creator, customer, or system | Approver or compliance officer |
| Context | Voluntary cancellation (error correction, customer request) | Denial after review (fraud, policy violation, insufficient docs) |
| Reason Required | Yes | Yes |
| Category Field | No | Yes (FRAUD, COMPLIANCE, etc.) |
| Compliance Report | No | Yes (for certain categories) |
| Customer Notification | Optional | Mandatory |
| Effect | PENDING → CANCELLED | PENDING → CANCELLED |
4. ReverseTransactionCommand
Reverses a settled transaction, transitioning it from SETTLED to REVERSED and restoring the original balance state.
Endpoint
POST /api/bpm/cmd/ReverseTransaction
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
transactionId | guid | Yes | Unique identifier of the settled transaction |
reversalReason | string | Yes | Reason for reversal (required for audit, max 1000 characters) |
reversalNarration | string | No | Narration for reversal transaction (max 200 characters) |
reversalCategory | string | No | Category: ERROR_CORRECTION, FRAUD, CUSTOMER_REQUEST, SYSTEM_ERROR, DUPLICATE, OTHER |
Example Request
{
"transactionId": "d4e5f6g7-h8i9-0123-defg-234567890123",
"reversalReason": "Duplicate transaction detected. Original transaction TXN-20260101-123456 already processed on 2025-12-31.",
"reversalNarration": "Reversal: Duplicate Deposit - TXN-20260101-234567",
"reversalCategory": "DUPLICATE"
}
Response (200 OK)
{
"isSuccessful": true,
"message": "Transaction reversed successfully",
"data": {
"transactionId": "d4e5f6g7-h8i9-0123-defg-234567890123",
"previousState": "SETTLED",
"newState": "REVERSED",
"reversedBy": "John Doe",
"reversalDate": "2026-01-02T09:00:00Z",
"reversalReason": "Duplicate transaction detected. Original transaction TXN-20260101-123456 already processed on 2025-12-31.",
"reversalCategory": "DUPLICATE",
"balanceImpact": {
"accountNumber": "2001234567",
"previousBalance": 600000.00,
"newBalance": 100000.00,
"reversalAmount": -500000.00
},
"reversalTransactionId": "e5f6g7h8-i9j0-1234-efgh-345678901234",
"originalTransaction": {
"transactionDate": "2026-01-01T10:00:00Z",
"amount": 500000.00,
"narration": "Cash Deposit"
}
}
}
Reversal Effects by Transaction Type
| Transaction Type | Balance Change | Additional Effects |
|---|---|---|
| Deposit | Account balance decreased | Funds withdrawn from account |
| Withdrawal | Account balance increased | Funds returned to account (cash must be physically returned) |
| Cheque Deposit | Account balance decreased | Cheque state → BOUNCED or REVERSED |
| Cheque Withdrawal | Account balance increased | Cheque state → CANCELLED |
| Loan Disbursement | Loan account defunded | Loan state → APPROVED (reverted), funds returned to disbursement GL |
| Teller Transaction | Till/account balance reversed | Till balance adjusted, audit log updated |
| Vault Transaction | Vault balance reversed | Vault inventory adjusted |
| Till Transfer | Both tills reversed | Source till increased, destination till decreased |
Reversal Restrictions
Most transactions have time limits for reversal:
- Same-Day Reversals: Typically allowed within 24 hours
- Next-Day Reversals: May require supervisor approval
- Aged Reversals (more than 48 hours): Require senior management approval and detailed justification
- Inter-Bank Transfers: May be irreversible after settlement window closes
- Loan Disbursements: Require customer account to have sufficient balance if funds already withdrawn
Workflow Examples
Example 1: High-Value Deposit with Approval
Scenario: Customer deposits ₦5,000,000 cash. Bank policy requires approval for deposits greater than ₦1,000,000.
Step 1: Create Deposit (PENDING)
POST /api/bpm/cmd/InitiateDeposit
{
"accountNumber": "2001234567",
"amount": 5000000.00,
"narration": "Cash Deposit",
"requireApproval": true,
"channel": "BRANCH"
}
Response:
{
"transactionId": "txn-001",
"status": "PENDING",
"holdAmount": 5000000.00,
"balance": 100000.00,
"availableBalance": 100000.00
}
Step 2: Approve Deposit
POST /api/bpm/cmd/ApproveTransaction
{
"transactionId": "txn-001",
"approverNotes": "Cash source verified. Customer provided employment letter and payslip."
}
Response:
{
"newState": "SETTLED",
"balance": 5100000.00,
"availableBalance": 5100000.00,
"holdReleased": 5000000.00
}
Example 2: Suspicious Withdrawal Rejected
Scenario: Customer attempts to withdraw ₦2,000,000. Transaction flagged for suspicious activity (account dormant for 6 months, sudden large withdrawal).
Step 1: Create Withdrawal (PENDING)
POST /api/bpm/cmd/InitiateWithdrawal
{
"accountNumber": "2001234567",
"amount": 2000000.00,
"narration": "Cash Withdrawal",
"requireApproval": true,
"channel": "BRANCH"
}
Response:
{
"transactionId": "txn-002",
"status": "PENDING",
"holdAmount": 2000000.00,
"balance": 5100000.00,
"availableBalance": 3100000.00
}
Step 2: Reject Withdrawal
POST /api/bpm/cmd/RejectTransaction
{
"transactionId": "txn-002",
"rejectionReason": "Account dormant for 6 months. Large withdrawal request requires additional KYC verification and face-to-face interview with branch manager.",
"rejectionCategory": "COMPLIANCE"
}
Response:
{
"newState": "CANCELLED",
"balance": 5100000.00,
"availableBalance": 5100000.00,
"holdReleased": 2000000.00
}
Example 3: Duplicate Deposit Reversal
Scenario: Teller accidentally processes same deposit twice. Second deposit must be reversed.
Step 1: Create Two Deposits (SETTLED - direct)
POST /api/bpm/cmd/InitiateDeposit
{
"accountNumber": "2001234567",
"amount": 50000.00,
"narration": "Cash Deposit",
"requireApproval": false
}
Response 1: balance = 5150000.00
Response 2 (duplicate): balance = 5200000.00
Step 2: Reverse Duplicate
POST /api/bpm/cmd/ReverseTransaction
{
"transactionId": "txn-004",
"reversalReason": "Duplicate transaction. Original transaction txn-003 already processed.",
"reversalNarration": "Reversal: Duplicate Deposit",
"reversalCategory": "DUPLICATE"
}
Response:
{
"newState": "REVERSED",
"previousBalance": 5200000.00,
"newBalance": 5150000.00,
"reversalAmount": -50000.00
}
Example 4: Customer-Requested Cancellation
Scenario: Customer initiates online transfer, realizes wrong beneficiary account, cancels before approval.
Step 1: Create Transfer (PENDING)
POST /api/bpm/cmd/InitiateWithdrawal
{
"accountNumber": "2001234567",
"amount": 100000.00,
"narration": "Transfer to 3001234567",
"requireApproval": true,
"channel": "ONLINE"
}
Response:
{
"transactionId": "txn-005",
"status": "PENDING",
"availableBalance": 5050000.00
}
Step 2: Cancel Transfer
POST /api/bpm/cmd/CancelTransaction
{
"transactionId": "txn-005",
"cancellationReason": "Customer entered wrong beneficiary account. Will re-submit with correct account number."
}
Response:
{
"newState": "CANCELLED",
"balance": 5150000.00,
"availableBalance": 5150000.00,
"holdReleased": 100000.00
}
Balance Impact Formulas
PENDING State (Approval Required)
When a transaction is created with requireApproval = true:
Deposit:
Account Balance: Unchanged
Hold Amount: +Transaction Amount
Available Balance: Unchanged
Withdrawal:
Account Balance: Unchanged
Hold Amount: +Transaction Amount
Available Balance: -Transaction Amount
SETTLED State (Approved or Direct)
When a transaction is approved or created with requireApproval = false:
Deposit:
Account Balance: +Transaction Amount
Hold Amount: -Transaction Amount (released)
Available Balance: +Transaction Amount
Withdrawal:
Account Balance: -Transaction Amount
Hold Amount: -Transaction Amount (released)
Available Balance: Unchanged (hold already deducted)
CANCELLED State (Rejected or Cancelled)
When a transaction is rejected or cancelled:
Deposit:
Account Balance: Unchanged
Hold Amount: -Transaction Amount (released)
Available Balance: Unchanged
Withdrawal:
Account Balance: Unchanged
Hold Amount: -Transaction Amount (released)
Available Balance: +Transaction Amount (restored)
REVERSED State (Reversal)
When a settled transaction is reversed:
Deposit Reversal:
Account Balance: -Transaction Amount
Available Balance: -Transaction Amount
Withdrawal Reversal:
Account Balance: +Transaction Amount
Available Balance: +Transaction Amount
Authorization & Permissions
Universal commands require specific permissions based on transaction amount and type:
Permission Matrix
| Command | Permission | Additional Requirements |
|---|---|---|
| ApproveTransaction | transactions.approve | Amount-based approval limits (see below) |
| RejectTransaction | transactions.approve OR transactions.reject | Rejection reason required |
| CancelTransaction | transactions.create (own txn) OR transactions.cancel (any txn) | Must be transaction creator or have cancel permission |
| ReverseTransaction | transactions.reverse | Reversal reason required, time limits apply |
Approval Limits by Role
| Role | Amount Limit | Transaction Types |
|---|---|---|
| Teller | ≤ ₦500,000 | Deposits, Withdrawals, Teller transactions |
| Senior Teller | ≤ ₦2,000,000 | All retail transactions |
| Approver | ≤ ₦5,000,000 | All transaction types |
| Branch Manager | ≤ ₦50,000,000 | All transaction types including loan disbursements |
| Regional Manager | ≤ ₦200,000,000 | All transaction types, multi-branch |
| Admin | Unlimited | All transaction types |
Configuration
Approval Threshold Configuration
Configure approval thresholds by transaction type and channel:
{
"transactionType": "DEPOSIT",
"channel": "BRANCH",
"thresholds": [
{
"accountTier": "BASIC",
"amountThreshold": 500000.00,
"requireApproval": true,
"approverRole": "Teller"
},
{
"accountTier": "PREMIUM",
"amountThreshold": 2000000.00,
"requireApproval": true,
"approverRole": "Senior Teller"
},
{
"accountTier": "VIP",
"amountThreshold": 10000000.00,
"requireApproval": true,
"approverRole": "Branch Manager"
}
]
}
Reversal Window Configuration
Configure time limits for reversals:
{
"transactionType": "DEPOSIT",
"reversalWindows": [
{
"windowName": "Same-Day",
"maxHours": 24,
"requiresApproval": false
},
{
"windowName": "Next-Day",
"maxHours": 48,
"requiresApproval": true,
"approverRole": "Branch Manager"
},
{
"windowName": "Aged",
"maxHours": 720,
"requiresApproval": true,
"approverRole": "Regional Manager",
"requiresDetailedJustification": true
}
]
}
Error Handling
Common Error Codes
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
TRANSACTION_NOT_FOUND | 404 | Transaction ID does not exist | Verify transaction ID |
INVALID_STATE_TRANSITION | 400 | Cannot transition from current state | Check transaction current state |
TRANSACTION_NOT_PENDING | 400 | Transaction is not in PENDING state | Only PENDING transactions can be approved/rejected/cancelled |
TRANSACTION_NOT_SETTLED | 400 | Transaction is not in SETTLED state | Only SETTLED transactions can be reversed |
INSUFFICIENT_PERMISSIONS | 403 | User lacks required permissions | Assign appropriate role/permissions |
APPROVAL_LIMIT_EXCEEDED | 403 | Transaction amount exceeds user's approval limit | Escalate to higher-level approver |
REVERSAL_WINDOW_EXPIRED | 400 | Transaction too old to reverse | Requires special approval or alternative correction |
DUPLICATE_REQUEST | 409 | Transaction already in target state | Refresh transaction status |
CUSTOMER_ACCOUNT_CLOSED | 400 | Customer account is closed | Cannot process transactions on closed accounts |
INSUFFICIENT_BALANCE | 400 | Insufficient balance for reversal | Reversal of withdrawal requires sufficient balance |
Error Response Example
{
"isSuccessful": false,
"message": "Transaction approval failed",
"errors": [
{
"code": "APPROVAL_LIMIT_EXCEEDED",
"message": "Transaction amount (₦10,000,000) exceeds your approval limit (₦5,000,000). Escalate to Branch Manager.",
"transactionAmount": 10000000.00,
"userApprovalLimit": 5000000.00,
"requiredRole": "Branch Manager"
}
]
}
Audit & Compliance
Audit Log Entries
Every universal command execution creates an audit log entry:
{
"eventType": "TransactionApproved",
"timestamp": "2026-01-01T14:30:00Z",
"userId": "user-123",
"userName": "Jane Smith",
"role": "Branch Manager",
"action": "ApproveTransaction",
"transactionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"transactionType": "DEPOSIT",
"transactionAmount": 5000000.00,
"previousState": "PENDING",
"newState": "SETTLED",
"approverNotes": "Cash source verified. Customer provided employment letter and payslip.",
"balanceImpact": {
"previousBalance": 100000.00,
"newBalance": 5100000.00,
"holdReleased": 5000000.00
},
"ipAddress": "192.168.1.100",
"userAgent": "Mozilla/5.0...",
"branchId": "branch-456",
"branchName": "Lagos Main Branch"
}
Compliance Reporting
High-value transactions and certain categories trigger compliance reports:
Triggers:
- Transactions greater than ₦5,000,000 (AML reporting threshold)
- Rejection category:
FRAUD,COMPLIANCE - Multiple failed approval attempts
- Reversals greater than ₦1,000,000
- Frequent cancellations by same user (velocity check)
Reports Generated:
- Suspicious Activity Report (SAR): Submitted to NFIU (Nigeria Financial Intelligence Unit)
- High-Value Transaction Report: Daily report to Central Bank of Nigeria
- Reversal Report: Weekly report to Risk Management and Audit
Best Practices
When to Require Approval
✅ DO Require Approval When:
- Transaction amount exceeds configured threshold
- Customer account flagged for suspicious activity
- Dormant account (no activity greater than 90 days)
- New account (less than 30 days old)
- High-risk transaction channel (ATM, online, mobile)
- Customer's first international transfer
- Unusual transaction pattern detected
❌ DO NOT Require Approval When:
- Low-value routine transactions (less than ₦50,000)
- Automated recurring transactions (salary, bill payments)
- Pre-authorized standing orders
- Inter-account transfers within same customer
- Teller-to-teller till transfers (branch operations)
When to Reverse vs Cancel
Use CancelTransaction:
- Transaction still in PENDING state
- Customer requests cancellation before approval
- Data entry error detected before settlement
- Duplicate pending transaction identified
- Customer account validation fails
Use ReverseTransaction:
- Transaction already SETTLED
- Duplicate settled transaction detected
- Fraud identified after settlement
- Customer disputes transaction post-settlement
- System error resulted in incorrect settlement
Security Considerations
-
Dual Authorization
- High-value approvals (greater than ₦10M) require two approvers
- Reversal of high-value transactions requires maker-checker workflow
- Inter-bank transfers require additional authorization
-
Time-Based Controls
- Reversals older than 48 hours require additional approval
- Pending transactions auto-expire after 24 hours (configurable)
- Approval SLA monitoring (flag transactions pending greater than 4 hours)
-
Fraud Prevention
- Velocity checks (max 5 approvals per user per hour)
- Amount-based alerts (flag approvals greater than user's typical limit)
- Pattern detection (unusual approval times, locations, devices)
-
Audit Trail
- All actions logged with user identity, timestamp, IP address
- Immutable audit logs stored for 10 years (regulatory requirement)
- Real-time monitoring of high-value approvals/reversals
Transaction Type Support
Universal commands work across all BankLingo transaction types:
| Transaction Category | Transaction Types | Approval Support | Reversal Support |
|---|---|---|---|
| Deposits | Cash Deposit, Cheque Deposit, Transfer-In | ✅ Full | ✅ Full |
| Withdrawals | Cash Withdrawal, Cheque Withdrawal, Transfer-Out | ✅ Full | ✅ Full |
| Cheque Operations | Cheque Deposit, Cheque Withdrawal, Cheque Clearing | ✅ Full (two-level) | ✅ Full |
| Loan Transactions | Loan Disbursement, Loan Repayment | ⏳ Planned (disbursement) | ✅ Full |
| Teller Operations | Deposit to Till, Withdraw from Till | ✅ Full | ✅ Full |
| Till Management | Add Cash, Remove Cash, Transfer Between Tills | ✅ Full | ✅ Full |
| Vault Operations | Fund Vault, Transfer from Vault | ✅ Full | ✅ Full |
Related Documentation
- Initiate Deposit - Deposit with approval workflow
- Initiate Withdrawal - Withdrawal with approval workflow
- Cheque Transactions - Cheque approval workflow
- Disburse Loan - Loan disbursement (future approval support)
- Data Flow Architecture - Approval workflow architecture
Performance Characteristics
| Metric | Value | Notes |
|---|---|---|
| Average Approval Time | 200-300ms | Internal processing |
| Average Rejection Time | 150-200ms | Faster than approval (no balance update) |
| Average Cancellation Time | 150-200ms | Same as rejection |
| Average Reversal Time | 300-500ms | Slower due to accounting entries |
| Concurrent Approvals | Up to 1000/second | Horizontally scalable |
| Approval SLA | 4 hours | Transactions pending greater than 4 hours flagged |
Summary
BankLingo's universal transaction management system provides:
✅ Standardized Workflow: Consistent approval/rejection/cancellation/reversal across all transaction types
✅ Flexible Approval: Configurable thresholds by amount, account tier, channel, and transaction type
✅ Granular Permissions: Role-based approval limits with escalation support
✅ Complete Audit Trail: Immutable logs for every state transition
✅ Balance Safety: Holds prevent double-spending, reversals restore original state
✅ Compliance Ready: Automated reporting for high-value transactions and suspicious activity
✅ Future-Proof: Approval workflow being extended to loan disbursements (planned)
Key Commands:
- ApproveTransaction: PENDING → SETTLED (apply balance changes)
- RejectTransaction: PENDING → CANCELLED (release hold, no balance change)
- CancelTransaction: PENDING → CANCELLED (same as reject, different initiator)
- ReverseTransaction: SETTLED → REVERSED (restore original balance)