Comprehensive catalog of all error codes returned by LendFoundry APIs with resolution steps
Error Codes
Comprehensive Error ReferenceThis document provides a complete catalog of all error codes returned by LendFoundry APIs. Each error includes HTTP status code, error code, message, and resolution steps.
Understanding error responses is critical for building robust integrations that handle failures gracefully.
Error Response Format
All errors follow this standard JSON format:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": [
{
"field": "field_name",
"issue": "SPECIFIC_ISSUE"
}
],
"trace_id": "a1b2c3d4e5f6",
"timestamp": "2025-12-15T10:30:00Z"
}
}| Field | Type | Description |
|---|---|---|
code | string | Machine-readable error code |
message | string | Human-readable error description |
details | array | Specific field-level errors (optional) |
trace_id | string | Unique identifier for support tickets |
timestamp | string | When the error occurred (ISO 8601) |
HTTP Status Codes 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 LR
subgraph ERRORS[📋 Error Categories]
A[4xx Client] --> B[400 Bad Request]
A --> C[401 Unauthorized]
A --> D[403 Forbidden]
A --> E[404 Not Found]
A --> F[429 Rate Limit]
G[5xx Server] --> H[500 Internal]
G --> I[503 Unavailable]
end
style A fill:#d97706,stroke:#b45309,color:#fff
style G fill:#dc2626,stroke:#b91c1c,color:#fff
style B fill:#d97706,stroke:#b45309,color:#fff
style C fill:#d97706,stroke:#b45309,color:#fff
style D fill:#d97706,stroke:#b45309,color:#fff
style E fill:#d97706,stroke:#b45309,color:#fff
style F fill:#d97706,stroke:#b45309,color:#fff
style H fill:#dc2626,stroke:#b91c1c,color:#fff
style I fill:#dc2626,stroke:#b91c1c,color:#fff
| Status | Meaning | Retryable | Common Causes |
|---|---|---|---|
400 | Bad Request | ❌ No | Invalid request format, missing fields |
401 | Unauthorized | ⚠️ Sometimes | Invalid credentials, expired token |
403 | Forbidden | ❌ No | Insufficient permissions |
404 | Not Found | ❌ No | Resource doesn't exist |
409 | Conflict | ❌ No | Duplicate resource, state conflict |
422 | Unprocessable Entity | ❌ No | Validation errors, business rules |
429 | Too Many Requests | ✅ Yes | Rate limit exceeded |
500 | Internal Server Error | ✅ Yes | Server-side error |
502 | Bad Gateway | ✅ Yes | Gateway error |
503 | Service Unavailable | ✅ Yes | Service temporarily down |
504 | Gateway Timeout | ✅ Yes | Request timeout |
Authentication Errors (401, 403)
UNAUTHORIZED
HTTP Status: 401
System: Both LOS and LMS
Message: "Invalid or missing authentication credentials"
Causes:
- LOS: API key missing, invalid, or revoked
- LMS: JWT token missing, invalid, or expired
Resolution:
# LOS - Check API key format
headers = {"Authorization": api_key} # No Bearer prefix
# LMS - Refresh expired token
token = refresh_jwt_token()
headers = {"Authorization": f"Bearer {token}"}Example Response:
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key",
"trace_id": "a1b2c3d4e5"
}
}TOKEN_EXPIRED
HTTP Status: 401
System: LMS only
Message: "JWT token has expired"
Resolution: Request new token via OAuth endpoint
def refresh_token(client_id, client_secret):
"""Request new JWT token."""
response = requests.post(
"https://api.demo.lms.lendfoundry.com/oauth/token",
data={
"grant_type": "client_credentials",
"client_id": client_id,
"client_secret": client_secret
}
)
return response.json()["access_token"]Example Response:
{
"error": {
"code": "TOKEN_EXPIRED",
"message": "JWT token expired at 2025-12-15T10:30:00Z",
"details": "Request a new token from /oauth/token"
}
}FORBIDDEN
HTTP Status: 403
System: Both
Message: "Insufficient permissions to access this resource"
Resolution: Contact support to verify account permissions
Example Response:
{
"error": {
"code": "FORBIDDEN",
"message": "Insufficient permissions to access this resource",
"details": "Your API key does not have access to this endpoint"
}
}Validation Errors (400, 422)
INVALID_REQUEST
HTTP Status: 400
System: Both
Message: "Request body is malformed or missing required fields"
Common Causes:
- Invalid JSON syntax
- Missing required fields
- Wrong data types
Example Response:
{
"error": {
"code": "INVALID_REQUEST",
"message": "Request body is malformed",
"details": [
{
"field": "loan_amount",
"issue": "REQUIRED_FIELD_MISSING"
},
{
"field": "interest_rate",
"issue": "INVALID_TYPE",
"expected": "number",
"received": "string"
}
]
}
}VALIDATION_ERROR
HTTP Status: 422
System: Both
Message: "Request failed validation"
Common Issues:
| Issue Code | Description |
|---|---|
INVALID_LOAN_AMOUNT | Amount outside valid range |
INVALID_DATE_FORMAT | Date format incorrect |
INVALID_EMAIL | Email format invalid |
INVALID_PHONE | Phone number format invalid |
INVALID_SSN | SSN format invalid |
Example Response:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Loan amount cannot exceed maximum product limit",
"details": [
{
"field": "loan_amount",
"issue": "MAX_LIMIT_EXCEEDED",
"max": 50000,
"provided": 75000
}
]
}
}INVALID_DATE_FORMAT
HTTP Status: 422
System: Both
Message: "Date format is invalid"
Expected Format: ISO 8601 (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ssZ)
Example Response:
{
"error": {
"code": "INVALID_DATE_FORMAT",
"message": "Date must be in ISO 8601 format",
"details": [
{
"field": "application_date",
"issue": "INVALID_FORMAT",
"expected": "YYYY-MM-DD",
"received": "12/15/2025"
}
]
}
}Resource Errors (404, 409)
RESOURCE_NOT_FOUND
HTTP Status: 404
System: Both
Message: "The requested resource does not exist"
Common Resources: Loan, Application, Borrower, Document
Example Response:
{
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "Loan with ID LN-2024-001234 not found",
"details": {
"resource_type": "loan",
"resource_id": "LN-2024-001234"
}
}
}Resolution:
- Verify resource ID is correct
- Check if resource was deleted
- Confirm using correct environment
DUPLICATE_RESOURCE
HTTP Status: 409
System: Both
Message: "Resource already exists"
Example Response:
{
"error": {
"code": "DUPLICATE_RESOURCE",
"message": "Application with this borrower already exists",
"details": {
"resource_type": "application",
"existing_id": "APP-2024-001234"
}
}
}Resolution: Use existing resource or update instead of create
RESOURCE_CONFLICT
HTTP Status: 409
System: Both
Message: "Resource state conflict"
Example: Trying to approve an already-approved application
Resolution: Check current resource state before operation
Business Rule Errors (422)
BUSINESS_RULE_VIOLATION
HTTP Status: 422
System: Both
Message: "Operation violates business rules"
Common Rules:
| Rule Code | Description |
|---|---|
LOAN_AMOUNT_EXCEEDS_LIMIT | Amount exceeds product limit |
INSUFFICIENT_COLLATERAL | Collateral value insufficient |
CREDIT_SCORE_TOO_LOW | Credit score below minimum |
DTI_TOO_HIGH | Debt-to-income ratio exceeds limit |
INVALID_LOAN_PURPOSE | Purpose not allowed for product |
Example Response:
{
"error": {
"code": "BUSINESS_RULE_VIOLATION",
"message": "Loan amount exceeds maximum product limit",
"details": [
{
"rule": "LOAN_AMOUNT_EXCEEDS_LIMIT",
"product_id": "PROD001",
"max_amount": 50000,
"requested_amount": 75000
}
]
}
}WORKFLOW_STATE_INVALID
HTTP Status: 422
System: Both
Message: "Invalid workflow state transition"
Example: Trying to fund an application that's not approved
Resolution: Check current state and use valid transition
{
"error": {
"code": "WORKFLOW_STATE_INVALID",
"message": "Cannot fund application in current state",
"details": {
"current_state": "under_review",
"requested_action": "fund",
"valid_actions": ["approve", "decline"]
}
}
}Rate Limiting Errors (429)
RATE_LIMIT_EXCEEDED
HTTP Status: 429
System: Both
Message: "Rate limit exceeded. Please retry after the specified time."
Example Response:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded",
"details": {
"limit": 100,
"remaining": 0,
"reset_at": "2025-12-15T10:31:00Z",
"retry_after": 60
}
}
}Resolution:
- Wait for
retry_afterseconds - Implement exponential backoff
- Reduce request frequency
- Use request batching
Server Errors (500, 502, 503, 504)
INTERNAL_SERVER_ERROR
HTTP Status: 500
Retryable: ✅ Yes (with backoff)
Resolution:
- Retry with exponential backoff
- If persists, contact support with
trace_id
Example Response:
{
"error": {
"code": "INTERNAL_SERVER_ERROR",
"message": "An unexpected error occurred",
"trace_id": "a1b2c3d4e5f6",
"details": "Please contact support with trace_id if issue persists"
}
}SERVICE_UNAVAILABLE
HTTP Status: 503
Retryable: ✅ Yes
Resolution: Retry after delay (check Retry-After header)
Error Handling Best Practices
Comprehensive Error Handler
import requests
import time
class APIError(Exception):
"""Custom exception for API errors."""
def __init__(self, code, message, details=None, trace_id=None):
self.code = code
self.message = message
self.details = details
self.trace_id = trace_id
super().__init__(f"{code}: {message}")
def handle_response(response):
"""Handle API response and raise appropriate errors."""
if response.status_code >= 400:
error_data = response.json().get('error', {})
raise APIError(
code=error_data.get('code', 'UNKNOWN_ERROR'),
message=error_data.get('message', 'Unknown error'),
details=error_data.get('details'),
trace_id=error_data.get('trace_id')
)
return response.json()
def make_request_with_retry(url, headers, data=None, max_retries=3):
"""Make request with comprehensive error handling."""
for attempt in range(max_retries):
try:
response = requests.post(url, json=data, headers=headers)
return handle_response(response)
except APIError as e:
# Handle specific error codes
if e.code == 'RATE_LIMIT_EXCEEDED':
retry_after = e.details.get('retry_after', 60) if e.details else 60
time.sleep(retry_after)
continue
elif e.code == 'TOKEN_EXPIRED':
# Refresh token and retry
headers['Authorization'] = f"Bearer {refresh_token()}"
continue
elif e.code in ['INTERNAL_SERVER_ERROR', 'SERVICE_UNAVAILABLE']:
# Exponential backoff for server errors
time.sleep(2 ** attempt)
continue
else:
# Non-retryable error
raise
except requests.exceptions.RequestException as e:
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt)
raise Exception("Max retries exceeded")Error Code Quick Reference
| Error Code | HTTP Status | System | Retryable | Description |
|---|---|---|---|---|
UNAUTHORIZED | 401 | Both | ⚠️ | Invalid credentials |
TOKEN_EXPIRED | 401 | LMS | ✅ | JWT expired |
FORBIDDEN | 403 | Both | ❌ | Insufficient permissions |
INVALID_REQUEST | 400 | Both | ❌ | Malformed request |
VALIDATION_ERROR | 422 | Both | ❌ | Validation failed |
RESOURCE_NOT_FOUND | 404 | Both | ❌ | Resource doesn't exist |
DUPLICATE_RESOURCE | 409 | Both | ❌ | Resource already exists |
BUSINESS_RULE_VIOLATION | 422 | Both | ❌ | Business rule violation |
RATE_LIMIT_EXCEEDED | 429 | Both | ✅ | Rate limit exceeded |
INTERNAL_SERVER_ERROR | 500 | Both | ✅ | Server error |
SERVICE_UNAVAILABLE | 503 | Both | ✅ | Service unavailable |
Support
Need help with an error?
- Email: [email protected]
- Include: Error code, trace_id, request details (sanitized)
Understanding Errors?Head to the Versioning guide to understand API versioning and deprecation policies.
