Detailed technical guide for boarding approved loans from LOS to LMS for servicing" category: "API Reference
Transition of Approved Loan to Active Loan Service API
Critical Handoff PointThis guide provides detailed technical documentation for the handoff between Application Submission APIs (LOS) and Active Loan Servicing APIs (LMS). This is the critical transition when an approved loan moves from origination to servicing.
The loan boarding process transfers all necessary data from the origination system to the servicing system, ensuring seamless loan management.
Handoff Overview
%%{init: {'theme': 'base', 'themeVariables': {'background': '#ffffff', 'mainBkg': '#ffffff', 'clusterBkg': '#f9fafb', 'clusterBorder': '#2563eb', 'primaryColor': '#2563eb', 'primaryTextColor': '#ffffff', 'titleColor': '#000000', 'lineColor': '#374151'}, 'flowchart': {'padding': 25, 'nodeSpacing': 45, 'rankSpacing': 50}}}%%
flowchart TB
subgraph LOS[📋 Application Submission APIs]
A[✅ Approved App]
end
subgraph HAND[🔄 Handoff Process]
B[🔍 Verify Ready] --> C[📤 Submit Board]
C --> D[✅ Confirm Success]
end
subgraph LMS[💰 Active Loan Servicing APIs]
E[🏦 Boarded Loan]
end
A --> B
D --> E
style A fill:#059669,stroke:#047857,color:#fff
style B fill:#2563eb,stroke:#1e40af,color:#fff
style C fill:#2563eb,stroke:#1e40af,color:#fff
style D fill:#059669,stroke:#047857,color:#fff
style E fill:#059669,stroke:#047857,color:#fff
Prerequisites
Before Boarding
Verify the application meets all boarding requirements:
| Requirement | Status | Description |
|---|---|---|
| Application Status | ✅ approved | Must be in approved state |
| All Verifications | ✅ Complete | No pending verifications |
| All Documents | ✅ Uploaded | Required documents verified |
| Credit Report | ✅ Pulled | Credit check completed |
| Underwriting | ✅ Complete | Final decision made |
Verify Prerequisites Programmatically
import requests
def verify_ready_for_boarding(application_uid, los_api_key):
"""Verify application is ready for boarding to LMS."""
url = "https://loc.demo.kendra.lendfoundry.com/v1/darbaan/back-office/rest/api/get-borrower-application-by-uid"
headers = {
"Authorization": los_api_key,
"Content-Type": "application/json"
}
response = requests.post(url, json={"uid": application_uid}, headers=headers)
response.raise_for_status()
app_data = response.json()
# Check status
if app_data["status"] != "approved":
raise ValueError(f"Application not approved. Status: {app_data['status']}")
# Check for pending verifications
verifications = app_data.get("verifications", [])
pending = [v for v in verifications if v.get("status") != "completed"]
if pending:
raise ValueError(f"Pending verifications: {len(pending)}")
# Check for pending documents
documents = app_data.get("documents", [])
missing = [d for d in documents if d.get("status") == "pending"]
if missing:
raise ValueError(f"Missing documents: {len(missing)}")
print("✅ Application ready for boarding")
return True
# Usage
verify_ready_for_boarding(application_uid, los_api_key)Boarding Endpoint
Endpoint Details
| Property | Value |
|---|---|
| Method | POST |
| Path | /application/submit/business/onboard |
| Base URL | https://api.demo.lms.lendfoundry.com/v1/lms-application-processor |
| Full URL | https://api.demo.lms.lendfoundry.com/v1/lms-application-processor/application/submit/business/onboard |
| Auth | Bearer JWT Token |
Request Payload
Required Fields
| Field | Type | Description | Example |
|---|---|---|---|
application_uid | string | LOS application UID | "0x1234567890abcdef" |
application_number | string | LOS application number | "APP-2025-001234" |
loan_amount | number | Loan principal amount | 50000 |
interest_rate | number | Annual interest rate (%) | 5.5 |
loan_term | integer | Loan term in months | 60 |
loan_start_date | string | Loan start date (ISO 8601) | "2025-12-20" |
Optional Fields
| Field | Type | Description | Example |
|---|---|---|---|
funding_date | string | Funding/disbursement date | "2025-12-20" |
first_payment_date | string | First payment due date | "2026-01-20" |
payment_frequency | string | Payment frequency | "monthly" |
collateral_value | number | Collateral value | 75000 |
loan_purpose | string | Purpose of loan | "Business Expansion" |
Complete Request Example
{
"application_uid": "0x1234567890abcdef",
"application_number": "APP-2025-001234",
"loan_amount": 50000,
"interest_rate": 5.5,
"loan_term": 60,
"loan_start_date": "2025-12-20",
"funding_date": "2025-12-20",
"first_payment_date": "2026-01-20",
"payment_frequency": "monthly",
"collateral_value": 75000,
"loan_purpose": "Business Expansion"
}Code Examples
curl -X POST "https://api.demo.lms.lendfoundry.com/v1/lms-application-processor/application/submit/business/onboard" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"application_uid": "0x1234567890abcdef",
"application_number": "APP-2025-001234",
"loan_amount": 50000,
"interest_rate": 5.5,
"loan_term": 60,
"loan_start_date": "2025-12-20"
}'const boardLoanToLMS = async (boardingData, jwtToken) => {
const response = await fetch(
'https://api.demo.lms.lendfoundry.com/v1/lms-application-processor/application/submit/business/onboard',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${jwtToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(boardingData)
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Boarding failed: ${error.error?.message}`);
}
return await response.json();
};
// Usage
const result = await boardLoanToLMS({
application_uid: '0x1234567890abcdef',
application_number: 'APP-2025-001234',
loan_amount: 50000,
interest_rate: 5.5,
loan_term: 60,
loan_start_date: '2025-12-20'
}, jwtToken);
console.log(`Loan boarded: ${result.loan_number}`);import requests
from datetime import datetime
def board_loan_to_lms(boarding_data, jwt_token):
"""Board approved loan from LOS to LMS."""
url = "https://api.demo.lms.lendfoundry.com/v1/lms-application-processor/application/submit/business/onboard"
headers = {
"Authorization": f"Bearer {jwt_token}",
"Content-Type": "application/json"
}
response = requests.post(url, json=boarding_data, headers=headers)
# Handle specific error cases
if response.status_code == 409:
error_data = response.json()
existing_loan = error_data.get('error', {}).get('details', {}).get('loan_number')
return {"loan_number": existing_loan, "status": "already_boarded"}
response.raise_for_status()
return response.json()
# Usage
result = board_loan_to_lms({
"application_uid": "0x1234567890abcdef",
"application_number": "APP-2025-001234",
"loan_amount": 50000,
"interest_rate": 5.5,
"loan_term": 60,
"loan_start_date": "2025-12-20"
}, jwt_token)
print(f"Loan boarded: {result['loan_number']}")public class LoanBoardingService {
private final String jwtToken;
private final HttpClient client;
public LoanBoardingService(String jwtToken) {
this.jwtToken = jwtToken;
this.client = HttpClient.newHttpClient();
}
public String boardLoan(String boardingJson) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.demo.lms.lendfoundry.com/v1/lms-application-processor/application/submit/business/onboard"))
.header("Authorization", "Bearer " + jwtToken)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(boardingJson))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
throw new RuntimeException("Boarding failed: " + response.body());
}
return response.body();
}
}Data Mapping
LOS to LMS Field Mapping
| LOS Field | LMS Field | Notes |
|---|---|---|
application_uid | application_uid | Reference preserved |
application_number | application_number | Reference preserved |
loan_amount | principal_amount | Same value |
interest_rate | interest_rate | Same value |
loan_term | term_months | Same value |
borrower_name | borrower_name | Auto-transferred |
borrower_ssn | borrower_ssn | Auto-transferred |
collateral_description | collateral_description | Auto-transferred |
Automatically Transferred Data
The following data is automatically transferred during boarding:
| Category | Data Elements |
|---|---|
| Borrower Info | Name, SSN/EIN, Email, Phone, Address |
| Business Info | Company name, EIN, Business address |
| Document References | Document IDs, Types, Verification status |
| Verification Results | Income, Identity, Employment verification status |
Response Format
Success Response (200 OK)
{
"loan_number": "LN-2025-001234",
"status": "boarded",
"message": "Loan successfully boarded to LMS",
"loan_id": "12345",
"boarded_at": "2025-12-15T10:30:00Z",
"application_uid": "0x1234567890abcdef",
"application_number": "APP-2025-001234"
}Error Responses
400 Bad Request — Invalid Payload
{
"error": {
"code": "INVALID_REQUEST",
"message": "Missing required field: loan_amount",
"details": [
{
"field": "loan_amount",
"issue": "REQUIRED_FIELD_MISSING"
}
]
}
}404 Not Found — Application Not Found
{
"error": {
"code": "APPLICATION_NOT_FOUND",
"message": "Application with UID 0x1234567890abcdef not found or not approved",
"details": {
"application_uid": "0x1234567890abcdef",
"current_status": "under_review"
}
}
}409 Conflict — Already Boarded
{
"error": {
"code": "LOAN_ALREADY_BOARDED",
"message": "Application already boarded. Loan number: LN-2025-001234",
"details": {
"loan_number": "LN-2025-001234",
"boarded_at": "2025-12-15T09:00:00Z"
}
}
}Complete Integration Class
import requests
from datetime import datetime
import os
class LOSToLMSIntegration:
"""Complete integration for boarding loans from LOS to LMS."""
def __init__(self, los_api_key, lms_jwt_token):
self.los_api_key = los_api_key
self.lms_jwt_token = lms_jwt_token
self.los_base = "https://loc.demo.kendra.lendfoundry.com/v1/darbaan/back-office/rest/api"
self.lms_base = "https://api.demo.lms.lendfoundry.com/v1"
def get_application(self, application_uid):
"""Retrieve application data from LOS."""
response = requests.post(
f"{self.los_base}/get-borrower-application-by-uid",
json={"uid": application_uid},
headers={"Authorization": self.los_api_key, "Content-Type": "application/json"}
)
response.raise_for_status()
return response.json()
def verify_ready(self, application_uid):
"""Verify application is ready for boarding."""
app = self.get_application(application_uid)
if app["status"] != "approved":
raise ValueError(f"Not approved. Status: {app['status']}")
return app
def board_loan(self, application_uid, loan_details):
"""Execute loan boarding to LMS."""
# Verify prerequisites
app = self.verify_ready(application_uid)
# Prepare boarding request
boarding_data = {
"application_uid": application_uid,
"application_number": app["application_number"],
"loan_amount": loan_details.get("loan_amount", app.get("loan_amount")),
"interest_rate": loan_details.get("interest_rate"),
"loan_term": loan_details.get("loan_term"),
"loan_start_date": loan_details.get("loan_start_date", datetime.now().strftime("%Y-%m-%d")),
"loan_purpose": app.get("loan_purpose", "")
}
# Submit boarding request
response = requests.post(
f"{self.lms_base}/lms-application-processor/application/submit/business/onboard",
json=boarding_data,
headers={
"Authorization": f"Bearer {self.lms_jwt_token}",
"Content-Type": "application/json"
}
)
# Handle already boarded
if response.status_code == 409:
error = response.json()
return {
"loan_number": error["error"]["details"]["loan_number"],
"status": "already_boarded"
}
response.raise_for_status()
return response.json()
def verify_loan_created(self, loan_number):
"""Verify loan was successfully created in LMS."""
response = requests.get(
f"{self.lms_base}/loan-management/search/{loan_number}/details",
headers={"Authorization": f"Bearer {self.lms_jwt_token}"}
)
response.raise_for_status()
return response.json()
# Usage
integration = LOSToLMSIntegration(
los_api_key=os.getenv('LOS_API_KEY'),
lms_jwt_token=os.getenv('LMS_JWT_TOKEN')
)
# Board loan
result = integration.board_loan(
application_uid="0x1234567890abcdef",
loan_details={
"loan_amount": 50000,
"interest_rate": 5.5,
"loan_term": 60,
"loan_start_date": "2025-12-20"
}
)
print(f"Loan: {result['loan_number']}, Status: {result['status']}")
# Verify in LMS
loan = integration.verify_loan_created(result['loan_number'])
print(f"Verified in LMS: {loan['status']}")Post-Boarding Steps
1. Verify Loan Created
def verify_loan_in_lms(loan_number, jwt_token):
"""Verify loan exists in LMS after boarding."""
response = requests.get(
f"https://api.demo.lms.lendfoundry.com/v1/loan-management/search/{loan_number}/details",
headers={"Authorization": f"Bearer {jwt_token}"}
)
response.raise_for_status()
return response.json()2. Generate Amortization Schedule
def generate_amortization(loan_number, jwt_token):
"""Generate payment schedule for boarded loan."""
response = requests.post(
f"https://api.demo.lms.lendfoundry.com/v1/loan-management/{loan_number}/amortize",
headers={"Authorization": f"Bearer {jwt_token}"}
)
response.raise_for_status()
return response.json()3. Update LOS Application Status
NoteThe LOS application status is automatically updated to "funded" after successful boarding.
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| Application Not Found | Wrong UID or not approved | Verify UID and check status |
| Already Boarded | Previously boarded | Use existing loan number |
| Invalid Request | Missing required fields | Check all required fields |
| Auth Failed | Wrong token or expired | Refresh JWT token |
Best Practices
| ✅ DO | ❌ DON'T |
|---|---|
| Verify prerequisites before boarding | Skip validation |
| Handle 409 (already boarded) gracefully | Fail on duplicate boarding |
| Verify loan creation after boarding | Assume success |
| Generate amortization schedule | Skip schedule generation |
| Log all boarding operations | Ignore audit trail |
Support
Questions about loan boarding?
- Email: [email protected]
- Related: API Integration Flow
Loan Boarded Successfully?See Validation Rules for field-level validation requirements.
