Record Loan Repayment
Process loan repayment transactions with automated payment allocation across fees, penalties, interest, and principal following the payment hierarchy.
Overview​
The Loan Repayment Commands enable secure processing of loan payments through multiple channels. These operations automatically allocate payments according to the configured payment hierarchy (typically: Fees → Penalties → Interest → Principal), update loan schedules, manage account balances, and maintain compliance with loan product rules.
Available Commands​
- InitiateLoanRepaymentCommand - Process loan repayment from external sources (cash, bank transfer, etc.)
- InitiateLoanRepaymentWithDepositCommand - Process loan repayment by debiting a deposit account
Key Capabilities​
- Automatic Payment Allocation: Distributes payments across fees, penalties, interest, and principal
- Schedule-Based Processing: Updates loan repayment schedules in chronological order
- Multi-Channel Support: Accepts payments from various transaction channels
- Partial Payment Handling: Processes payments less than total amount due
- External Channel Integration: Tracks payments from external institutions
- Deposit Account Integration: Directly debits customer deposit accounts
- Backdating Support: Allows backdated repayment transactions
- Transaction Tracking: Generates unique transaction keys for audit trails
- State Management: Updates loan and schedule states based on payment application
- Accounting Integration: Creates appropriate GL entries based on loan product rules
Command 1: InitiateLoanRepaymentCommand​
Process loan repayment from external payment channels (cash, bank transfer, mobile money, etc.).
API Endpoint​
POST /api/bpm/cmd
Headers​
Content-Type: application/json
Authorization: Bearer {access_token}
X-Tenant-ID: {tenant_id}
Request Structure​
{
"commandName": "InitiateLoanRepaymentCommand",
"data": {
"accountEncodedKey": "string",
"channelEncodedKey": "string",
"amount": "decimal",
"notes": "string",
"serviceId": "string",
"serviceDescription": "string",
"isBackDated": "boolean",
"backDateValueDate": "string (ISO 8601)",
"isBookingDate": "boolean",
"bookingDate": "string (ISO 8601)",
"repaymentChannelDetails": {
"institutionCode": "string",
"institutionAccount": "string",
"narration": "string",
"reference": "string",
"providerCode": "string",
"note": "string"
}
}
}
Request Fields​
| Field | Type | Required | Description | Validation |
|---|---|---|---|---|
accountEncodedKey | string | Yes | Loan account number or encoded key | Must exist, must be Active or In_Arrears |
channelEncodedKey | string | Yes | Transaction channel identifier | Must exist in system |
amount | decimal | Yes | Repayment amount | Must be > 0 |
notes | string | No | Payment description/remarks | Free-text notes |
serviceId | string | No | Service identifier | Defaults to "LOAN_REPAYMENT" |
serviceDescription | string | No | Service description | Defaults to "LOAN REPAYMENT" |
isBackDated | boolean | No | Whether transaction is backdated | Defaults to false |
backDateValueDate | string | Conditional | Transaction value date | Required if isBackDated=true (ISO 8601 format) |
isBookingDate | boolean | No | Whether to specify booking date | Defaults to false |
bookingDate | string | Conditional | Transaction booking date | Required if isBookingDate=true (ISO 8601 format) |
repaymentChannelDetails | object | No | External channel payment details | Optional for tracking external payments |
Repayment Channel Details Object​
| Field | Type | Required | Description |
|---|---|---|---|
institutionCode | string | No | External institution code |
institutionAccount | string | No | External institution account |
narration | string | No | Payment narration |
reference | string | No | External payment reference |
providerCode | string | No | Payment provider code |
note | string | No | Additional notes |
Response Structure​
Success Response​
{
"isSuccessful": true,
"message": "Loan repayment has been processed successfully.",
"statusCode": "00",
"data": {
"transactionKey": "8A3F2D1E9B5C4F7A6E8D2C1B3A9F5E7D",
"principalPaid": 50000.00,
"interestPaid": 5000.00,
"feesPaid": 500.00,
"penaltiesPaid": 1000.00,
"totalPaid": 56500.00
}
}
Error Response​
{
"isSuccessful": false,
"message": "The loan account has been locked presently and no transaction can be posted until it is unlocked",
"statusCode": "REQUEST_NOT_VALID"
}
Response Fields​
| Field | Type | Description |
|---|---|---|
isSuccessful | boolean | Indicates if repayment was successful |
message | string | Descriptive result message |
statusCode | string | Response code (00 = success) |
transactionKey | string | Unique transaction identifier |
principalPaid | decimal | Amount applied to principal |
interestPaid | decimal | Amount applied to interest |
feesPaid | decimal | Amount applied to fees |
penaltiesPaid | decimal | Amount applied to penalties |
totalPaid | decimal | Total amount processed |
Command 2: InitiateLoanRepaymentWithDepositCommand​
Process loan repayment by debiting funds from a customer's deposit account.
API Endpoint​
POST /api/bpm/cmd
Headers​
Content-Type: application/json
Authorization: Bearer {access_token}
X-Tenant-ID: {tenant_id}
Request Structure​
{
"commandName": "InitiateLoanRepaymentWithDepositCommand",
"data": {
"accountEncodedKey": "string",
"depositAccountEncodedKey": "string",
"amount": "decimal",
"notes": "string",
"serviceId": "string",
"serviceDescription": "string",
"allowPartial": "boolean",
"isBackDated": "boolean",
"backDateValueDate": "string (ISO 8601)",
"isBookingDate": "boolean",
"bookingDate": "string (ISO 8601)"
}
}
Request Fields​
| Field | Type | Required | Description | Validation |
|---|---|---|---|---|
accountEncodedKey | string | Yes | Loan account number or encoded key | Must exist, must be Active or In_Arrears |
depositAccountEncodedKey | string | Yes | Deposit account number or encoded key | Must exist, must have sufficient balance |
amount | decimal | Yes | Repayment amount | Must be > 0 |
notes | string | No | Payment description/remarks | Free-text notes |
serviceId | string | No | Service identifier | Optional service tracking |
serviceDescription | string | No | Service description | Human-readable service info |
allowPartial | boolean | No | Allow partial payment if insufficient balance | Defaults to false |
isBackDated | boolean | No | Whether transaction is backdated | Defaults to false |
backDateValueDate | string | Conditional | Transaction value date | Required if isBackDated=true (ISO 8601 format) |
isBookingDate | boolean | No | Whether to specify booking date | Defaults to false |
bookingDate | string | Conditional | Transaction booking date | Required if isBookingDate=true (ISO 8601 format) |
Response Structure​
Same as InitiateLoanRepaymentCommand above.
Sample Requests​
1. Basic Cash Loan Repayment​
{
"commandName": "InitiateLoanRepaymentCommand",
"data": {
"accountEncodedKey": "LOAN123456789",
"channelEncodedKey": "CHANNEL_CASH",
"amount": 25000.00,
"notes": "Monthly installment payment - December 2024"
}
}
Use Case: Customer makes regular monthly payment at branch with cash.
2. External Bank Transfer Repayment​
{
"commandName": "InitiateLoanRepaymentCommand",
"data": {
"accountEncodedKey": "8A3F2D1E9B5C4F7A6E8D2C1B3A9F5E7D",
"channelEncodedKey": "CHANNEL_BANK_TRANSFER",
"amount": 50000.00,
"notes": "Partial loan repayment from external bank",
"serviceId": "BANK_TRANSFER_REPAY",
"serviceDescription": "Bank Transfer Loan Repayment",
"repaymentChannelDetails": {
"institutionCode": "058",
"institutionAccount": "0123456789",
"narration": "Loan repayment for account LOAN123456789",
"reference": "TRF/2024/12/001234",
"providerCode": "GTB",
"note": "Transfer from GTBank"
}
}
}
Use Case: Customer transfers funds from external bank account to repay loan.
3. Mobile Money Repayment​
{
"commandName": "InitiateLoanRepaymentCommand",
"data": {
"accountEncodedKey": "LOAN987654321",
"channelEncodedKey": "CHANNEL_MOBILE_MONEY",
"amount": 15000.00,
"notes": "Mobile money payment via MTN",
"serviceId": "MOBILE_MONEY_REPAY",
"serviceDescription": "Mobile Money Loan Repayment",
"repaymentChannelDetails": {
"institutionCode": "MTN",
"institutionAccount": "233240123456",
"reference": "MM2024120112345",
"providerCode": "MTN_GHANA",
"note": "MTN Mobile Money payment"
}
}
}
Use Case: Customer uses mobile money service to repay loan.
4. Loan Repayment from Deposit Account​
{
"commandName": "InitiateLoanRepaymentWithDepositCommand",
"data": {
"accountEncodedKey": "LOAN123456789",
"depositAccountEncodedKey": "SAV987654321",
"amount": 30000.00,
"notes": "Automatic monthly repayment from savings",
"serviceId": "AUTO_DEBIT_REPAY",
"serviceDescription": "Automatic Loan Repayment"
}
}
Use Case: Automated monthly deduction from customer's savings account.
5. Backdated Repayment Correction​
{
"commandName": "InitiateLoanRepaymentCommand",
"data": {
"accountEncodedKey": "LOAN555666777",
"channelEncodedKey": "CHANNEL_BRANCH",
"amount": 20000.00,
"notes": "Backdated payment correction - received on Dec 15",
"isBackDated": true,
"backDateValueDate": "2024-12-15T00:00:00Z",
"isBookingDate": true,
"bookingDate": "2024-12-18T00:00:00Z"
}
}
Use Case: Recording a payment that was received earlier but not immediately posted.
6. Partial Repayment from Deposit (Allow Partial)​
{
"commandName": "InitiateLoanRepaymentWithDepositCommand",
"data": {
"accountEncodedKey": "LOAN888999000",
"depositAccountEncodedKey": "CHK111222333",
"amount": 40000.00,
"notes": "Partial payment from checking account",
"allowPartial": true,
"serviceId": "PARTIAL_REPAY",
"serviceDescription": "Partial Loan Repayment"
}
}
Use Case: Process whatever amount is available in deposit account, even if less than requested amount.
Business Logic​
Payment Allocation Hierarchy​
Loan repayments are automatically allocated in this order:
Processing Workflow​
-
Validation Phase
- Verify loan account exists and is active (Active or In_Arrears state)
- Check loan is not locked
- Validate transaction channel exists
- Verify amount is greater than zero
- For deposit-based: Check deposit account balance
-
Transaction Creation
- Generate unique transaction key
- Create CBS transaction record
- Set transaction type as "Repayment"
- Apply value date and booking date logic
-
Schedule Processing (in chronological order)
- Retrieve all schedules with outstanding balances
- Order schedules by due date (earliest first)
- For each schedule:
- Calculate outstanding amounts (fees, penalties, interest, principal)
- Allocate payment according to hierarchy
- Update schedule paid amounts
- Mark schedule as "Paid" if fully cleared
- Update schedule state (Due, Late, etc.) if partially paid
-
Account Updates
- Recalculate loan balances
- Update loan state if fully paid
- Create GL entries based on loan product accounting rules
- Record external channel details (if provided)
-
Response Generation
- Return transaction key
- Provide breakdown of payment allocation
- Confirm total amount processed
State Transitions​
Loan States:
- Active → Remains Active (if balance outstanding)
- Active → Closed (if fully paid)
- In_Arrears → Active (if brought current)
- In_Arrears → Closed (if fully paid)
- Locked → Cannot process payment (error returned)
Schedule States:
- Pending → Paid (if schedule fully cleared)
- Due → Paid (if schedule fully cleared)
- Late → Paid (if schedule fully cleared)
- Late → Remains Late (if partially paid, still past due)
- Upfront → Not affected by repayments
Validation Rules​
Common Validations (Both Commands)​
| Validation | Error Message | Status Code |
|---|---|---|
| Loan account not found | "The supplied loan account or encoded key is not valid." | CODE_DOES_NOT_EXIST |
| Loan not active | "The loan - [accountNumber] is no longer active. The present state is [state]." | REQUEST_NOT_VALID |
| Loan is locked | "The loan account has been locked presently and no transaction can be posted until it is unlocked" | REQUEST_NOT_VALID |
| Amount less than or equal to 0 | "The repayment amount must be greater than 0." | REQUEST_NOT_VALID |
| Channel not found | "The selected transaction channel cannot be found." | - |
| Backdate without date | "The backdate is required" | DO_NOT_HONOR |
| Booking date without date | "The book date is required" | DO_NOT_HONOR |
| Duplicate transaction | "A transaction already exists with the same transaction reference." | DUPLICATE_RECORD |
InitiateLoanRepaymentWithDepositCommand Specific​
| Validation | Error Message |
|---|---|
| Deposit account not found | "The supplied deposit account or encoded key is not valid." |
| Deposit account insufficient balance | "The source account does not have sufficient balance." |
| Deposit account locked/frozen | "The deposit account is currently locked/frozen and cannot be debited." |
| Deposit account closed | "Cannot debit from a closed account." |
| Currency mismatch | "Loan and deposit accounts must have the same currency." |
Error Codes​
| Status Code | Description | Resolution |
|---|---|---|
00 | Success | Payment processed successfully |
CODE_DOES_NOT_EXIST | Account not found | Verify account number/encoded key |
REQUEST_NOT_VALID | Invalid request | Check loan state and amount |
DO_NOT_HONOR | Cannot process | Review backdating/booking date requirements |
DUPLICATE_RECORD | Duplicate transaction | Use different transaction reference |
INSUFFICIENT_BALANCE | Insufficient funds | Ensure deposit account has adequate balance |
Integration Examples​
Example 1: Automated Loan Repayment from Salary Account​
{
"commandName": "InitiateLoanRepaymentWithDepositCommand",
"data": {
"accountEncodedKey": "LOAN456789123",
"depositAccountEncodedKey": "SAL123456789",
"amount": 35000.00,
"notes": "Monthly salary deduction for loan repayment",
"serviceId": "SALARY_DEDUCTION",
"serviceDescription": "Salary-Based Loan Repayment"
}
}
Scenario: On salary payment day, automatically deduct loan installment from employee's salary account.
Example 2: USSD Mobile Banking Repayment​
{
"commandName": "InitiateLoanRepaymentCommand",
"data": {
"accountEncodedKey": "LOAN777888999",
"channelEncodedKey": "CHANNEL_USSD",
"amount": 12500.00,
"notes": "USSD payment via *737# code",
"serviceId": "USSD_REPAY",
"serviceDescription": "USSD Loan Repayment"
}
}
Scenario: Customer dials USSD code to make loan payment from any mobile phone.
Example 3: Agent Banking Repayment​
{
"commandName": "InitiateLoanRepaymentCommand",
"data": {
"accountEncodedKey": "LOAN321654987",
"channelEncodedKey": "CHANNEL_AGENT",
"amount": 18000.00,
"notes": "Payment collected by agent AG-1234",
"serviceId": "AGENT_REPAY",
"serviceDescription": "Agent Banking Repayment",
"repaymentChannelDetails": {
"institutionCode": "AGENT",
"institutionAccount": "AG-1234",
"reference": "AGT/2024/12/5678",
"note": "Collected by agent John Doe"
}
}
}
Scenario: Agent collects cash payment on behalf of the bank and remits to customer's loan.
Best Practices​
For Operations Teams​
- Payment Verification: Always verify customer details before processing repayment
- Receipt Generation: Issue payment receipts immediately after successful transaction
- Balance Confirmation: Confirm remaining loan balance with customer
- Documentation: Keep records of external payment references for reconciliation
- Exception Handling: Use backdating only for genuine corrections with proper authorization
For IT Integration​
- Idempotency: Check for duplicate transaction keys before retrying failed payments
- Balance Checks: For deposit-based repayments, verify balance before initiating transaction
- Error Handling: Implement proper retry logic with exponential backoff
- Channel Tracking: Always provide channel information for payment source tracking
- Webhook Notifications: Set up webhooks to receive payment status updates
- Reconciliation: Store transaction keys for end-of-day reconciliation
For Customers​
- Payment Confirmation: Always request and save payment confirmation receipt
- Account Monitoring: Check loan balance after payment to confirm posting
- Early Payments: Know your loan product's policy on early/advance payments
- Multiple Channels: Use the most convenient payment channel available
- Schedule Awareness: Understand your repayment schedule and due dates
Related APIs​
| API | Relationship | Description |
|---|---|---|
| Create Loan | Related | Create the loan account |
| Get Loan Details | Related | Retrieve loan balance and schedule |
| Loan Pay Off | Alternative | Full early repayment |
| Initiate Transfer | Related | Transfer funds between accounts |
| Teller Deposit | Alternative | Process repayment through teller |
Next Steps​
- Learn about Loan Pay Off →
- Explore Loan Account Management →
- Understand Loan Schedules →
- Configure Payment Channels → (Coming Soon)
Product Documentation​
For business process and technical flow details, see: