LendEasy/Docs
Get API keys
GuidesLoansLoan lifecycle

Loan lifecycle

Follow a consumer loan from application through approval, settled funding, active servicing, and an evidence-backed terminal state.

A loan advances only through explicit, permissioned lifecycle commands. Workflow approval authorizes a transition; money movement completes it only after the rail and ledger agree.

Charge-off, write-off, and contract termination are distinct terminal or accounting outcomes. They are never aliases for normal payoff.

SUBMITTED: proposed, not committed

Creating an application resolves the selected product, validates the proposed terms, and computes the schedule. It does not move funds or create an active receivable. The clientId is the numeric value of the LendEasy customerId, and every date-bearing body declares its own dateFormat and locale.

curl -X POST "$BASE/v1/loans" \
  -H "Authorization: Bearer $TOKEN" \
  -H "LendEasy-Tenant: demo-lender" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: originate-harbor-2026-001" \
  -d '{
    "clientId": 412,
    "productId": 3,
    "loanType": "individual",
    "principal": 8400.0,
    "loanTermFrequency": 18,
    "loanTermFrequencyType": 2,
    "numberOfRepayments": 18,
    "repaymentEvery": 1,
    "repaymentFrequencyType": 2,
    "interestRatePerPeriod": 13.25,
    "interestType": 0,
    "interestCalculationPeriodType": 1,
    "amortizationType": 1,
    "transactionProcessingStrategyCode": "advanced-payment-allocation-strategy",
    "expectedDisbursementDate": "2026-08-12",
    "submittedOnDate": "2026-08-11",
    "externalId": "origination-HBR-2026-001",
    "dateFormat": "yyyy-MM-dd",
    "locale": "en",
    "charges": [{ "chargeId": 12, "amount": 252.0 }]
  }'
{ "officeId": 1, "clientId": 412, "loanId": 7204, "resourceId": 7204 }

To preview terms before committing anything, send the same body to POST /v1/loans?command=calculateLoanSchedule. It returns the computed amortization schedule—periods and totals—without persisting a loan.

While submitted, PUT /v1/loans/{loanId} modifies the application with the same field catalog as creation. Approval always evaluates the loan as it stands at decision time.

APPROVED: authorized, not funded

Lifecycle decisions are commands on the loan resource:

POST /v1/loans/7204?command=approve
POST /v1/loans/7204?command=reject
POST /v1/loans/7204?command=withdrawnByApplicant

Approve carries { "approvedOnDate": "2026-08-11", "approvedLoanAmount": 8400.0, "expectedDisbursementDate": "2026-08-12", "dateFormat": "yyyy-MM-dd", "locale": "en" }; reject and withdraw carry their own decision dates. Approval also computes and finalizes the APR disclosure automatically—if the disclosure cannot be produced, the approval fails.

An approved loan has no disbursed principal. There is no public disburse command: money moves through the funding API, and a payout in SUBMITTED or PROCESSING does not activate the loan or begin accrual. If funding fails, the loan remains approved.

ACTIVE: funding and ledger agree

The loan becomes active when released funds are posted as a disbursement. The activation date is the posted value date, not the date a user clicked “fund.” From activation:

  • the repayment schedule is live;
  • interest accrues under the contract’s calculation settings;
  • payments and autopay can operate;
  • due-date statements are scheduled; and
  • servicing actions evaluate against current loan facts.

For Juniper, the checkout down payment is a separate posted transaction. Reversing that transaction does not erase the loan; it triggers the product’s down-payment recovery or cancellation workflow.

Reading the loan

GET /v1/loans lists loans in the native envelope—totalFilteredRecords plus pageItems—with externalId, accountNo, clientId, and status filters. The full model, including the authoritative repayment schedule, lives on the loan itself:

GET /v1/loans/7204?associations=repaymentSchedule,transactions

Response dates serialize as [year, month, day] arrays, so Harbor’s first installment appears as "dueDate": [2026, 9, 12] with "principalDue": 424.39 and "interestDue": 92.75. For servicing views—balances, overdue components, payoff projection, APR disclosure, autopay state, restrictions—read the one-call summary at GET /v1/loans/7204/summary instead of stitching raw associations together.

Active does not mean current

Delinquency, hardship, bankruptcy, fraud review, and a servicing restriction are facts or overlays on an active obligation—not replacement lifecycle states. Keeping them separate prevents a restriction from losing the underlying loan state.

Overlay Example What it changes
Delinquency 22 days past due Collections, fees, reporting, and eligibility facts.
Restriction Bankruptcy stay Which actions and contacts are permitted.
Servicing plan Active promise-to-pay Outreach suppression and follow-up.
Schedule modification Re-age or re-amortize Future schedule and related evidence.
Accounting classification Charged off Receivable accounting and permitted recovery actions.

Normal closure

When all principal, interest, fees, and other due components reach zero—and there is no unresolved credit balance—the loan transitions to CLOSED_OBLIGATIONS_MET. In-flight payments do not close it early. A covering payment first settles and posts; closure follows the posted balance.

If the account has a credit balance, LendEasy keeps it open for refund or an approved disposition. If a payment later returns after normal closure, the original posting is reversed and the loan can reopen under the product’s state rules, with a new servicing case if required.

Governed terminal actions

Write-off, charge-off, and contract termination are governed commands: human calls carry a LendEasy-Case header naming an open case when case management is enabled, every execution writes a governance record, and maker-checker can park the command for a second approver. Their semantics differ:

  • Charge-off changes accounting classification and may leave a recoverable balance (POST /v1/loans/{loanId}/transactions?command=charge-off).
  • Write-off removes an amount from the receivable under approved accounting policy (?command=writeoff).
  • Contract termination ends the contract under a specific contractual or legal basis (POST /v1/loans/{loanId}?command=contractTermination).

Each action has a dedicated guide in the servicing action catalog. Undo, where supported, is its own command—undowriteoff, undo-charge-off, undoContractTermination—linked to the original; history is never deleted.

Command responses

Every lifecycle command returns the platform envelope rather than the mutated resource:

{ "officeId": 1, "clientId": 412, "loanId": 7204, "resourceId": 7204 }

After a command, read the loan for its canonical state. An Idempotency-Key is optional on mutations; replaying a completed request returns the original result with x-served-from-cache: true, and an in-flight duplicate returns 409 with Retry-After.

With the LendEasy core, its ledger is authoritative. With bring your own core, the binding supplies the authoritative state and acknowledges actions; LendEasy exposes freshness and drift instead of pretending a stale mirror is current.

Unified search across guides, recipes & the API referenceEsc