Products & templates
A product is the rulebook behind every loan — schedule, interest, Reg Z charge classification, disclosure, statements, and overpayment limits defined once and frozen onto each loan at origination.
A product is where a lender’s policy is written down once instead of being re-argued loan by loan. It supplies the defaults and hard constraints new obligations resolve against, and the moment a loan resolves them they are frozen onto that loan. Look the terms up from the product at servicing time instead, and a pricing decision taken on a Tuesday afternoon quietly rewrites contracts signed last year.
Everything a lender governs about an obligation’s behavior is configured here: the schedule cadence and term, how interest accrues and payments allocate, which charges may attach and how each is classified under Regulation Z, how APR is disclosed, when statements generate, and how far an overpayment may run before the servicing guard rejects it.
Three families; the choice is not a toggle
Consumer installment
- Principal accrues interest and amortizes through installments
- Daily, weekly, biweekly, semimonthly or monthly progressive schedule
- Personal and point-of-sale installment lending
BNPL purchase plan
- Purchase financing, optional checkout down payment, consumer finance charges
- Short progressive schedule, often biweekly or monthly
- Pay-in-4 and longer purchase plans
Merchant advance
- Receivables bought for a purchase price; remittance follows verified sales
- Projected sales and remittance, not fixed consumer installments
- Business-purpose working-capital funding
One product, two policy blocks
A consumer product is created in one request at POST /v1/loanproducts and carries two blocks: the native calculation settings—the math that must not drift between schedule preview and servicing—and the LendEasy lmsConfig policy that governs disclosure and statements. The sections below walk each policy surface conceptually; the exact request payload appears under the native block’s encoding.
The server owns the allocation order
The native block pins the calculation choices that must not drift between schedule preview and servicing:
- repayment frequency (
repaymentEveryplus its frequency type) and term; - interest rate per period, declining-balance interest type, and the interest-calculation period;
- equal-installment amortization;
transactionProcessingStrategyCode—the server owns the payment-allocation order for due, overdue, and in-advance money; andloanScheduleType: "PROGRESSIVE"with interest recalculation disabled.
Progressive schedules are required for consumer products in the public catalog. They recalculate after dated transactions and schedule modifications while preserving posted history—a schedule regenerated from scratch would lose the record of which installment each past payment satisfied, and with it every answer to “what did my money go to?”
Charges carry immutable Reg Z classification
The native block attaches charges by id from the charge-definition catalog at /v1/charges. Charge definitions are themselves built from two blocks: the native charge settings plus an lmsConfig with a financeChargeFlag (FINANCE_CHARGE, NOT_FINANCE_CHARGE, or EXCLUDED) and a legalBasis citation.
A charge definition without its classification reports configurationStatus: "MISSING" and cannot be attached to products or loans, so an APR-enabled product can never reference an unclassified fee.
Four fields carry the Reg Z posture
lmsConfig states it outright: productClass: "COVERED_CONSUMER" marks the product as covered consumer credit, aprEnabled requires a finalized disclosure at approval, aprRounding pins the disclosed scale, and aprTolerancePolicy (REGULAR or IRREGULAR) records the accuracy class the product asserts.
See APR & disclosures for Harbor’s worked calculation.
Every loan on the product gets statements
statementEnabled schedules due-date statements for every loan on the product, and statementLeadDays sets how many days before each due date the statement job generates them. An optional overpaymentTolerance bounds how far a payment may exceed the outstanding balance before the overpayment guard rejects it—unbounded, a borrower’s mistyped extra zero becomes a credit balance the lender then has to chase them to give back.
The statement is the notice artifact
For variable preauthorized consumer debits, the statement is what tells the borrower what is coming, so the lead time must satisfy Regulation E § 1005.10(d): a FULL_DUE autopay enrollment is rejected unless the product’s statement lead leaves at least the ten-day advance-notice window. Per-rail payment failure handling is tenant-level policy, not product configuration—see autopay failure policies.
Merchant products expose no APR settings
They configure purchase-price and purchased-amount bounds, remittance-rate limits, permitted sales sources, reporting cadence, projection method, reconciliation tolerances, grace windows, near-breach indicators, breach rules, and payment allocation. The consumer-only APR and installment-interest settings are simply absent, so nobody can configure a receivables purchase as though it disclosed an APR.
A product edit binds the next loan
GET /v1/loanproducts returns the product list with each product’s lmsConfig and a derived configurationStatus—CONFIGURED or MISSING. A product whose LendEasy configuration is MISSING cannot originate loans, which turns a half-finished setup into a rejected origination rather than a live loan whose disclosure nobody can produce at approval. GET /v1/loanproducts/template returns the option catalogs, including the product-class, APR-rounding, and APR-tolerance options, and GET /v1/loanproducts/{productId} returns one product.
PUT /v1/loanproducts/{productId} is a full replacement of both blocks—native settings and lmsConfig together. Product changes take effect for the next origination, never for existing loans: the terms a loan resolved at origination are frozen on the loan, not looked up from the product at servicing time. There is no separate draft, validate, or activate lifecycle and no product versioning—a single write defines the behavior of every loan created after it, so treat edits to a live product as a governed operational change.
The native block keeps its own encoding
A single create submits both blocks in one request. The native block is keyed fineract and uses the engine’s own wire encoding, including integer-coded enumerations for the frequency, amortization, interest, and accounting options shown conceptually above; GET /v1/loanproducts/template returns the option catalogs to build these payloads against, so nobody has to memorize which integer means “monthly.”
curl -X POST "$BASE/v1/loanproducts" \
-H "Authorization: Bearer $TOKEN" \
-H "LendEasy-Tenant: demo-lender" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: create-harbor-product-01" \
-d '{
"fineract": {
"name": "Harbor 18-month personal loan",
"shortName": "HBR18",
"currencyCode": "USD",
"principal": 8400.0,
"numberOfRepayments": 18,
"repaymentEvery": 1,
"repaymentFrequencyType": 2,
"interestRatePerPeriod": 13.25,
"interestRateFrequencyType": 3,
"amortizationType": 1,
"interestType": 0,
"interestCalculationPeriodType": 1,
"transactionProcessingStrategyCode": "advanced-payment-allocation-strategy",
"loanScheduleType": "PROGRESSIVE",
"isInterestRecalculationEnabled": false,
"accountingRule": 1,
"charges": [{ "id": 12 }]
},
"lmsConfig": {
"productClass": "COVERED_CONSUMER",
"aprEnabled": true,
"aprRounding": "NEAREST_0_01_PERCENT_HALF_UP",
"aprTolerancePolicy": "REGULAR",
"statementEnabled": true,
"statementLeadDays": 10
}
}'
{ "resourceId": 3 }