LendEasy/Docs
Get API keys
RecipesLendingPreview a schedule

Preview a schedule

Calculate Harbor's repayment schedule from the exact application body without persisting a loan—and reconcile the installment components to the contract totals.

Time
~4 min
Surface
LMS API
Steps
2
Gate
Pure calculation · nothing persisted
EndpointsPOST /v1/loans?command=calculateLoanSchedule

A schedule preview answers “what would this contract look like?” without creating a loan. Send the application body with command=calculateLoanSchedule: the ledger computes the schedule and persists nothing. Because the calculation evaluates the product’s current configuration, re-running the same body after a product change can produce a different schedule.

1

Submit the application body

No mutation
POST/v1/loans?command=calculateLoanSchedule

The body is the same one used for loan creation—same term fields, same charges, same dateFormat and locale—so the preview you show is the schedule you would originate.

curl -X POST "$BASE/v1/loans?command=calculateLoanSchedule" \
  -H "Authorization: Bearer $TOKEN" \
  -H "LendEasy-Tenant: demo-lender" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": 412,
    "productId": 3,
    "loanType": "individual",
    "principal": 8400.00,
    "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",
    "dateFormat": "yyyy-MM-dd",
    "locale": "en",
    "charges": [{ "chargeId": 12, "amount": 252.00 }]
  }'
{
  "currency": { "code": "USD" },
  "loanTermInDays": 548,
  "totalPrincipalExpected": 8400.00,
  "periods": [
    {
      "period": 1,
      "dueDate": [2026, 9, 12],
      "principalDue": 424.39,
      "interestDue": 92.75,
      "feeChargesDue": 0.00,
      "totalDueForPeriod": 517.14,
      "principalLoanBalanceOutstanding": 7975.61
    },
    {
      "period": 2,
      "dueDate": [2026, 10, 12],
      "principalDue": 429.08,
      "interestDue": 88.06,
      "feeChargesDue": 0.00,
      "totalDueForPeriod": 517.14,
      "principalLoanBalanceOutstanding": 7546.53
    }
  ]
}

Native responses serialize dates as [year, month, day] arrays. The response above is trimmed to the first two of eighteen repayment periods.

2

Reconcile the preview

Fail before origination
CHECKclient-side assertions

Do not validate only the first installment. Assert the whole schedule:

sum(period.principalDue)              = 8,400.00
sum(period.interestDue)               =   908.52
sum(period.feeChargesDue)             =     0.00
sum(period.totalDueForPeriod)         = 9,308.52
last principalLoanBalanceOutstanding  =     0.00
18 due dates are strictly increasing and match the monthly calendar policy

The $252.00 prepaid finance charge affects amountFinanced and APR, but it is collected at disbursement and therefore does not appear as an installment fee. That distinction is a deliberate disclosure classification, not missing schedule money.

Harbor's first installment

A schedule preview is not a Regulation Z disclosure and is not the schedule of record. Origination creates the loan; the authoritative schedule is then embedded in the loan at GET /v1/loans/{loanId}?associations=repaymentSchedule, and the APR disclosure is finalized automatically at approval.
Unified search across guides, recipes & the API referenceEsc