Transition of Approved Loan to Active Loan Servicing APIs Guide

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 Point

This 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:

RequirementStatusDescription
Application StatusapprovedMust be in approved state
All Verifications✅ CompleteNo pending verifications
All Documents✅ UploadedRequired documents verified
Credit Report✅ PulledCredit check completed
Underwriting✅ CompleteFinal 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

PropertyValue
MethodPOST
Path/application/submit/business/onboard
Base URLhttps://api.demo.lms.lendfoundry.com/v1/lms-application-processor
Full URLhttps://api.demo.lms.lendfoundry.com/v1/lms-application-processor/application/submit/business/onboard
AuthBearer JWT Token

Request Payload

Required Fields

FieldTypeDescriptionExample
application_uidstringLOS application UID"0x1234567890abcdef"
application_numberstringLOS application number"APP-2025-001234"
loan_amountnumberLoan principal amount50000
interest_ratenumberAnnual interest rate (%)5.5
loan_termintegerLoan term in months60
loan_start_datestringLoan start date (ISO 8601)"2025-12-20"

Optional Fields

FieldTypeDescriptionExample
funding_datestringFunding/disbursement date"2025-12-20"
first_payment_datestringFirst payment due date"2026-01-20"
payment_frequencystringPayment frequency"monthly"
collateral_valuenumberCollateral value75000
loan_purposestringPurpose 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 FieldLMS FieldNotes
application_uidapplication_uidReference preserved
application_numberapplication_numberReference preserved
loan_amountprincipal_amountSame value
interest_rateinterest_rateSame value
loan_termterm_monthsSame value
borrower_nameborrower_nameAuto-transferred
borrower_ssnborrower_ssnAuto-transferred
collateral_descriptioncollateral_descriptionAuto-transferred

Automatically Transferred Data

The following data is automatically transferred during boarding:

CategoryData Elements
Borrower InfoName, SSN/EIN, Email, Phone, Address
Business InfoCompany name, EIN, Business address
Document ReferencesDocument IDs, Types, Verification status
Verification ResultsIncome, 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

💡

Note

The LOS application status is automatically updated to "funded" after successful boarding.


Troubleshooting

IssueCauseSolution
Application Not FoundWrong UID or not approvedVerify UID and check status
Already BoardedPreviously boardedUse existing loan number
Invalid RequestMissing required fieldsCheck all required fields
Auth FailedWrong token or expiredRefresh JWT token

Best Practices

✅ DO❌ DON'T
Verify prerequisites before boardingSkip validation
Handle 409 (already boarded) gracefullyFail on duplicate boarding
Verify loan creation after boardingAssume success
Generate amortization scheduleSkip schedule generation
Log all boarding operationsIgnore audit trail

Support

Questions about loan boarding?


Loan Boarded Successfully?

See Validation Rules for field-level validation requirements.