Payment Processing
Comprehensive guide to processing payments in LMS including payment methods, hierarchies, auto-pay management, and failed payment handling.
Payment Processing
Complete Payment ManagementThe Loan Management System provides comprehensive payment processing capabilities including multiple payment methods, flexible payment hierarchies, auto-pay functionality, and robust failed payment handling.
Payment processing is a core function of LMS, enabling you to accept payments through various methods, allocate funds according to different hierarchies, and manage recurring payments automatically.
Payment Processing Overview
LMS supports multiple payment methods and allocation strategies to meet diverse business needs:
Payment Methods
| Method | Description | Auto-Initiate | Use Case |
|---|---|---|---|
| Cash | In-person cash payment | No | Branch payments, walk-in customers |
| Check | Paper check payment | No | Mailed payments, manual processing |
| ACH | Automated Clearing House bank transfer | Yes | Auto-pay, recurring payments |
| Debit Card | Debit card payment | Yes | Online payments, customer portal |
Payment Flow
%%{init: {'theme': 'base', 'themeVariables': {'background': '#ffffff', 'mainBkg': '#ffffff', 'clusterBkg': '#ffffff', 'clusterBorder': '#2563eb', 'titleColor': '#000000', 'primaryColor': '#2563eb', 'primaryTextColor': '#ffffff', 'lineColor': '#374151'}, 'flowchart': {'padding': 20, 'nodeSpacing': 25, 'rankSpacing': 35}}}%%
flowchart LR
subgraph MainContainer[💳 Payment Processing Flow]
direction LR
A[💳 Payment] --> B[✅ Validate] --> C[💰 Allocate] --> D[📊 Record]
style A fill:#2563eb,stroke:#1e40af,color:#fff
style B fill:#6b7280,stroke:#4b5563,color:#fff
style C fill:#059669,stroke:#047857,color:#fff
style D fill:#2563eb,stroke:#1e40af,color:#fff
end
Flow Steps:
- Payment - Payment received via any method
- Validate - Validate payment date and amount
- Allocate - Apply payment according to hierarchy
- Record - Record transaction and update balances
Payment Hierarchies
Payment hierarchies determine how funds are allocated across principal, interest, and fees:
| Hierarchy | Description | Allocation Order |
|---|---|---|
| System | Default allocation | Fees → Interest → Principal |
| Schedule | Apply to scheduled payment | Per schedule allocation |
| Principal Only | All to principal | 100% Principal |
| Payoff | Clear all balances | All outstanding amounts |
| Custom | User-defined allocation | Custom percentages |
Allocation Flow
%%{init: {'theme': 'base', 'themeVariables': {'background': '#ffffff', 'mainBkg': '#ffffff', 'clusterBkg': '#ffffff', 'clusterBorder': '#2563eb', 'titleColor': '#000000', 'primaryColor': '#2563eb', 'primaryTextColor': '#ffffff', 'lineColor': '#374151'}, 'flowchart': {'padding': 20, 'nodeSpacing': 25, 'rankSpacing': 35}}}%%
flowchart LR
subgraph MainContainer[💰 Payment Allocation]
direction LR
A[💰 Payment] --> B{⚖️ Hierarchy} --> C[📊 Allocate]
B -->|System| D[Fees → Interest → Principal]
B -->|Schedule| E[Per Schedule]
B -->|Principal| F[100% Principal]
B -->|Payoff| G[All Outstanding]
D --> C
E --> C
F --> C
G --> C
style A fill:#2563eb,stroke:#1e40af,color:#fff
style B fill:#6b7280,stroke:#4b5563,color:#fff
style C fill:#059669,stroke:#047857,color:#fff
style D fill:#2563eb,stroke:#1e40af,color:#fff
style E fill:#2563eb,stroke:#1e40af,color:#fff
style F fill:#2563eb,stroke:#1e40af,color:#fff
style G fill:#2563eb,stroke:#1e40af,color:#fff
end
Make Payment API
The Make Payment API allows you to process payments for any loan using various payment methods and hierarchies.
Endpoint
POST /v1/payment-processor/loans/{loanNumber}/payments
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
paymentInstrument | string | Yes | Cash, Check, ACH, DebitCard |
paymentType | string | Yes | System, Schedule, PrincipalOnly, Payoff, Custom |
paymentDate | date | Yes | Date payment is received |
effectiveDate | date | Yes | Date payment is applied |
paymentAmount | number | Yes | Payment amount |
bankAccountId | string | Conditional | Required for ACH payments |
checkNumber | string | Conditional | Required for Check payments |
userRemarks | string | No | Payment notes or comments |
recastingOption | string | No | ReducePayment or KeepPaymentSame |
Payment Validation Rules
| Rule | Description |
|---|---|
| Payment Date | Must be ≥ Funded Date |
| Effective Date | Must be ≥ Funded Date AND ≤ Payment Date |
| Debit Card | Effective Date ≥ max(Funded Date, Today + Processing Days) |
Recasting Options
When a payment exceeds the scheduled amount, you can choose how to handle the excess:
| Option | Description | Impact |
|---|---|---|
| ReducePayment | Lower monthly payment, same term | Payment amount reduced, term unchanged |
| KeepPaymentSame | Same payment, shorter term | Payment amount unchanged, term reduced |
Make Manual Payment (Cash)
curl -X POST 'https://api.demo.lms.lendfoundry.com/v1/payment-processor/loans/LN-2024-001234/payments' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"paymentInstrument": "Cash",
"paymentType": "Schedule",
"paymentDate": "2024-02-01",
"effectiveDate": "2024-02-01",
"paymentAmount": 500.00,
"userRemarks": "Monthly payment - cash",
"recastingOption": "KeepPaymentSame"
}'const makeCashPayment = async (loanNumber, amount, paymentDate) => {
const url = `https://api.demo.lms.lendfoundry.com/v1/payment-processor/loans/${loanNumber}/payments`;
const payload = {
paymentInstrument: 'Cash',
paymentType: 'Schedule',
paymentDate: paymentDate,
effectiveDate: paymentDate,
paymentAmount: amount,
userRemarks: 'Monthly payment - cash',
recastingOption: 'KeepPaymentSame'
};
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
};
const result = await makeCashPayment('LN-2024-001234', 500.00, '2024-02-01');
console.log(`Payment ID: ${result.paymentId}`);import requests
def make_cash_payment(loan_number, amount, payment_date):
url = f"https://api.demo.lms.lendfoundry.com/v1/payment-processor/loans/{loan_number}/payments"
headers = {
"Authorization": "Bearer YOUR_TOKEN",
"Content-Type": "application/json"
}
payload = {
"paymentInstrument": "Cash",
"paymentType": "Schedule",
"paymentDate": payment_date,
"effectiveDate": payment_date,
"paymentAmount": amount,
"userRemarks": "Monthly payment - cash",
"recastingOption": "KeepPaymentSame"
}
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
return response.json()
result = make_cash_payment("LN-2024-001234", 500.00, "2024-02-01")
print(f"Payment ID: {result['paymentId']}")public static String makeCashPayment(String loanNumber, double amount, String paymentDate) throws Exception {
String url = BASE_URL + "/payment-processor/loans/" + loanNumber + "/payments";
Map<String, Object> payload = new HashMap<>();
payload.put("paymentInstrument", "Cash");
payload.put("paymentType", "Schedule");
payload.put("paymentDate", paymentDate);
payload.put("effectiveDate", paymentDate);
payload.put("paymentAmount", amount);
payload.put("userRemarks", "Monthly payment - cash");
payload.put("recastingOption", "KeepPaymentSame");
String requestBody = mapper.writeValueAsString(payload);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer YOUR_TOKEN")
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
return response.body();
}Make ACH Payment
curl -X POST 'https://api.demo.lms.lendfoundry.com/v1/payment-processor/loans/LN-2024-001234/payments' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"paymentInstrument": "ACH",
"paymentType": "System",
"paymentDate": "2024-02-01",
"effectiveDate": "2024-02-01",
"paymentAmount": 750.00,
"bankAccountId": "BA-12345",
"userRemarks": "ACH payment"
}'const makeACHPayment = async (loanNumber, amount, bankAccountId, paymentDate) => {
const url = `https://api.demo.lms.lendfoundry.com/v1/payment-processor/loans/${loanNumber}/payments`;
const payload = {
paymentInstrument: 'ACH',
paymentType: 'System',
paymentDate: paymentDate,
effectiveDate: paymentDate,
paymentAmount: amount,
bankAccountId: bankAccountId,
userRemarks: 'ACH payment'
};
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
};
const result = await makeACHPayment('LN-2024-001234', 750.00, 'BA-12345', '2024-02-01');
console.log(`Payment ID: ${result.paymentId}`);import requests
def make_ach_payment(loan_number, amount, bank_account_id, payment_date):
url = f"https://api.demo.lms.lendfoundry.com/v1/payment-processor/loans/{loan_number}/payments"
headers = {
"Authorization": "Bearer YOUR_TOKEN",
"Content-Type": "application/json"
}
payload = {
"paymentInstrument": "ACH",
"paymentType": "System",
"paymentDate": payment_date,
"effectiveDate": payment_date,
"paymentAmount": amount,
"bankAccountId": bank_account_id,
"userRemarks": "ACH payment"
}
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
return response.json()
result = make_ach_payment("LN-2024-001234", 750.00, "BA-12345", "2024-02-01")
print(f"Payment ID: {result['paymentId']}")public static String makeACHPayment(String loanNumber, double amount, String bankAccountId, String paymentDate) throws Exception {
String url = BASE_URL + "/payment-processor/loans/" + loanNumber + "/payments";
Map<String, Object> payload = new HashMap<>();
payload.put("paymentInstrument", "ACH");
payload.put("paymentType", "System");
payload.put("paymentDate", paymentDate);
payload.put("effectiveDate", paymentDate);
payload.put("paymentAmount", amount);
payload.put("bankAccountId", bankAccountId);
payload.put("userRemarks", "ACH payment");
String requestBody = mapper.writeValueAsString(payload);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer YOUR_TOKEN")
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
return response.body();
}Make Payoff Payment
curl -X POST 'https://api.demo.lms.lendfoundry.com/v1/payment-processor/loans/LN-2024-001234/payments' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"paymentInstrument": "Check",
"paymentType": "Payoff",
"paymentDate": "2024-02-15",
"effectiveDate": "2024-02-15",
"paymentAmount": 46400.00,
"checkNumber": "1234",
"userRemarks": "Payoff payment"
}'const makePayoffPayment = async (loanNumber, amount, checkNumber, paymentDate) => {
const url = `https://api.demo.lms.lendfoundry.com/v1/payment-processor/loans/${loanNumber}/payments`;
const payload = {
paymentInstrument: 'Check',
paymentType: 'Payoff',
paymentDate: paymentDate,
effectiveDate: paymentDate,
paymentAmount: amount,
checkNumber: checkNumber,
userRemarks: 'Payoff payment'
};
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
};
const result = await makePayoffPayment('LN-2024-001234', 46400.00, '1234', '2024-02-15');
console.log(`Payment ID: ${result.paymentId}`);import requests
def make_payoff_payment(loan_number, amount, check_number, payment_date):
url = f"https://api.demo.lms.lendfoundry.com/v1/payment-processor/loans/{loan_number}/payments"
headers = {
"Authorization": "Bearer YOUR_TOKEN",
"Content-Type": "application/json"
}
payload = {
"paymentInstrument": "Check",
"paymentType": "Payoff",
"paymentDate": payment_date,
"effectiveDate": payment_date,
"paymentAmount": amount,
"checkNumber": check_number,
"userRemarks": "Payoff payment"
}
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
return response.json()
result = make_payoff_payment("LN-2024-001234", 46400.00, "1234", "2024-02-15")
print(f"Payment ID: {result['paymentId']}")public static String makePayoffPayment(String loanNumber, double amount, String checkNumber, String paymentDate) throws Exception {
String url = BASE_URL + "/payment-processor/loans/" + loanNumber + "/payments";
Map<String, Object> payload = new HashMap<>();
payload.put("paymentInstrument", "Check");
payload.put("paymentType", "Payoff");
payload.put("paymentDate", paymentDate);
payload.put("effectiveDate", paymentDate);
payload.put("paymentAmount", amount);
payload.put("checkNumber", checkNumber);
payload.put("userRemarks", "Payoff payment");
String requestBody = mapper.writeValueAsString(payload);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer YOUR_TOKEN")
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
return response.body();
}Payment Response Example
{
"paymentId": "PAY-2024-005678",
"loanId": "LN-2024-001234",
"status": "Success",
"paymentDate": "2024-02-01",
"effectiveDate": "2024-02-01",
"paymentAmount": 500.00,
"paymentInstrument": "Cash",
"allocationDetails": {
"principal": 350.00,
"interest": 125.00,
"fees": 25.00
},
"newBalance": {
"principalOutstanding": 44650.00,
"interestOutstanding": 0.00,
"feesOutstanding": 0.00,
"totalOutstanding": 44650.00
},
"message": "Payment recorded successfully"
}Auto-Pay Management
Auto-pay enables automatic payment processing on scheduled dates using ACH or Debit Card.
Auto-Pay Flow
%%{init: {'theme': 'base', 'themeVariables': {'background': '#ffffff', 'mainBkg': '#ffffff', 'clusterBkg': '#ffffff', 'clusterBorder': '#2563eb', 'titleColor': '#000000', 'primaryColor': '#2563eb', 'primaryTextColor': '#ffffff', 'lineColor': '#374151'}, 'flowchart': {'padding': 20, 'nodeSpacing': 25, 'rankSpacing': 35}}}%%
flowchart LR
subgraph MainContainer[⚙️ Auto-Pay Management]
direction LR
A[⚙️ Setup] --> B[📅 Schedule] --> C[💳 Process] --> D{✅ Success?}
D -->|Yes| E[✅ Complete]
D -->|No| F[🔄 Retry]
F --> C
style A fill:#2563eb,stroke:#1e40af,color:#fff
style B fill:#2563eb,stroke:#1e40af,color:#fff
style C fill:#059669,stroke:#047857,color:#fff
style D fill:#6b7280,stroke:#4b5563,color:#fff
style E fill:#059669,stroke:#047857,color:#fff
style F fill:#d97706,stroke:#b45309,color:#fff
end
Pause Auto-Pay
curl -X PUT 'https://api.demo.lms.lendfoundry.com/v1/loan-management/loans/LN-2024-001234/autopay/pause' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"effectiveDate": "2024-02-01",
"reason": "Customer request - temporary hardship"
}'const pauseAutoPay = async (loanNumber, effectiveDate, reason) => {
const url = `https://api.demo.lms.lendfoundry.com/v1/loan-management/loans/${loanNumber}/autopay/pause`;
const payload = {
effectiveDate: effectiveDate,
reason: reason
};
const response = await fetch(url, {
method: 'PUT',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
};
await pauseAutoPay('LN-2024-001234', '2024-02-01', 'Customer request - temporary hardship');import requests
def pause_autopay(loan_number, effective_date, reason):
url = f"https://api.demo.lms.lendfoundry.com/v1/loan-management/loans/{loan_number}/autopay/pause"
headers = {
"Authorization": "Bearer YOUR_TOKEN",
"Content-Type": "application/json"
}
payload = {
"effectiveDate": effective_date,
"reason": reason
}
response = requests.put(url, json=payload, headers=headers)
response.raise_for_status()
return response.json()
pause_autopay("LN-2024-001234", "2024-02-01", "Customer request - temporary hardship")public static String pauseAutoPay(String loanNumber, String effectiveDate, String reason) throws Exception {
String url = BASE_URL + "/loan-management/loans/" + loanNumber + "/autopay/pause";
Map<String, Object> payload = new HashMap<>();
payload.put("effectiveDate", effectiveDate);
payload.put("reason", reason);
String requestBody = mapper.writeValueAsString(payload);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer YOUR_TOKEN")
.header("Content-Type", "application/json")
.PUT(BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
return response.body();
}Resume Auto-Pay
curl -X PUT 'https://api.demo.lms.lendfoundry.com/v1/loan-management/loans/LN-2024-001234/autopay/resume' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"effectiveDate": "2024-03-01"
}'const resumeAutoPay = async (loanNumber, effectiveDate) => {
const url = `https://api.demo.lms.lendfoundry.com/v1/loan-management/loans/${loanNumber}/autopay/resume`;
const payload = {
effectiveDate: effectiveDate
};
const response = await fetch(url, {
method: 'PUT',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
};
await resumeAutoPay('LN-2024-001234', '2024-03-01');import requests
def resume_autopay(loan_number, effective_date):
url = f"https://api.demo.lms.lendfoundry.com/v1/loan-management/loans/{loan_number}/autopay/resume"
headers = {
"Authorization": "Bearer YOUR_TOKEN",
"Content-Type": "application/json"
}
payload = {
"effectiveDate": effective_date
}
response = requests.put(url, json=payload, headers=headers)
response.raise_for_status()
return response.json()
resume_autopay("LN-2024-001234", "2024-03-01")public static String resumeAutoPay(String loanNumber, String effectiveDate) throws Exception {
String url = BASE_URL + "/loan-management/loans/" + loanNumber + "/autopay/resume";
Map<String, Object> payload = new HashMap<>();
payload.put("effectiveDate", effectiveDate);
String requestBody = mapper.writeValueAsString(payload);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer YOUR_TOKEN")
.header("Content-Type", "application/json")
.PUT(BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
return response.body();
}Failed Payment Handling
When auto-pay payments fail, the system handles retries and recovery:
Failure Reasons
| Reason | Description | Action |
|---|---|---|
| NSF | Non-sufficient funds | Retry after grace period |
| Invalid Account | Account closed or invalid | Contact customer |
| Stop Payment | Customer stopped payment | Manual review |
| Processing Error | System processing error | Retry immediately |
Failed Payment Flow
%%{init: {'theme': 'base', 'themeVariables': {'background': '#ffffff', 'mainBkg': '#ffffff', 'clusterBkg': '#ffffff', 'clusterBorder': '#2563eb', 'titleColor': '#000000', 'primaryColor': '#2563eb', 'primaryTextColor': '#ffffff', 'lineColor': '#374151'}, 'flowchart': {'padding': 20, 'nodeSpacing': 25, 'rankSpacing': 35}}}%%
flowchart LR
subgraph MainContainer[❌ Failed Payment Handling]
direction LR
A[💳 Payment] --> B{❌ Failed?}
B -->|Yes| C[📋 Reason] --> D{🔄 Retry?}
D -->|Yes| E[⏱️ Wait] --> F[🔄 Retry]
D -->|No| G[📞 Manual]
F --> B
B -->|No| H[✅ Success]
style A fill:#2563eb,stroke:#1e40af,color:#fff
style B fill:#6b7280,stroke:#4b5563,color:#fff
style C fill:#dc2626,stroke:#b91c1c,color:#fff
style D fill:#6b7280,stroke:#4b5563,color:#fff
style E fill:#d97706,stroke:#b45309,color:#fff
style F fill:#d97706,stroke:#b45309,color:#fff
style G fill:#dc2626,stroke:#b91c1c,color:#fff
style H fill:#059669,stroke:#047857,color:#fff
end
Screenshots
Screenshot: Payment Processing FormThis screenshot shows the payment processing interface in LMS with payment method selection, amount entry, and allocation options.
Screenshot: Payment History ViewThis screenshot shows the payment history interface displaying all processed payments, their status, allocation, and transaction details.
Next Steps
| Resource | Description |
|---|---|
| Loan Onboarding | Learn how to onboard loans from LOS |
| Line of Credit Operations | Understand LOC operations and draw management |
| API Reference | Full API documentation |
Ready for LOC Operations?Head to the Line of Credit Guide to learn about LOC draw management and operations.
Updated 3 months ago
