Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/soker90/finper/llms.txt

Use this file to discover all available pages before exploring further.

The Loans module lets you track personal loans and mortgages with mathematical precision. Finper uses the French amortization method (constant monthly payment), meaning each scheduled payment covers the interest accrued on the outstanding principal plus a growing slice of capital repayment. The module maintains a full amortization table for every loan — combining your real payment history with a projected future schedule — and integrates directly with your Accounts and Transactions so that every payment automatically updates your account balance and spending history.

Data Model

Loan

Core loan record with terms and current state

LoanPayment

Individual payment entry (real, not projected)

LoanEvent

Rate or payment change (e.g. Euribor revision)

Loan Fields

FieldTypeDescription
namestringDescriptive label, e.g. "Mortgage"
initialAmountnumberOriginal principal; never changes after creation
pendingAmountnumberRemaining principal; decremented by each payment
interestRatenumberAnnual nominal rate (TIN) as a percentage, e.g. 3.5 for 3.5%
startDatenumberLoan start date as Unix timestamp (ms)
monthlyPaymentnumberCurrent scheduled monthly payment amount
initialEstimatedCostnumberTotal projected cost computed at creation time (no extra payments)
accountObjectIdAccount from which payments are deducted
categoryObjectIdExpense category for auto-created payment transactions

LoanPayment Fields

FieldTypeDescription
datenumberPayment date as Unix timestamp (ms)
amountnumberTotal amount paid (interest + principal)
interestnumberInterest portion of this payment
principalnumberCapital repaid in this payment
accumulatedPrincipalnumberTotal capital repaid up to and including this payment
pendingCapitalnumberRemaining principal after this payment
typestring"ordinary" (scheduled) or "extraordinary" (early repayment)

LoanEvent Fields

FieldTypeDescription
datenumberEffective date of the change as Unix timestamp (ms)
newRatenumberNew annual TIN (%) from this date onward
newPaymentnumberNew monthly payment amount from this date onward

Endpoints

MethodPathDescription
GET/api/loansList all loans for the current user
POST/api/loansCreate a loan (auto-calculates monthlyPayment and initialEstimatedCost)
GET/api/loans/:idFull detail: loan data + stats + complete amortization table
PUT/api/loans/:idEdit loan fields
DELETE/api/loans/:idDelete a loan and all its payments and events
POST/api/loans/:id/payRecord an ordinary (scheduled) payment
POST/api/loans/:id/amortizeRecord an extraordinary (early capital) payment
POST/api/loans/:id/eventsAdd a rate/payment change event
POST/api/loans/:id/simulate-payoffSimulate lump-sum payoff impact (no data modified)
PUT/api/loans/:id/payments/:paymentIdEdit a recorded payment and recalculate the full chain
DELETE/api/loans/:id/payments/:paymentIdDelete a recorded payment and restore the account balance

Amortization Math

Finper implements the French amortization (constant installment) method throughout. All amounts are rounded to 2 decimal places using Math.round(n * 100) / 100.

Monthly Rate

r = TIN% / 100 / 12
Example: TIN 3.6% → r = 3.6 / 100 / 12 = 0.003

Monthly Payment Formula

C = P × [ r(1+r)^n ] / [ (1+r)^n − 1 ]
Where:
  • C = monthly payment
  • P = outstanding principal
  • r = monthly rate (TIN% / 100 / 12)
  • n = remaining number of months
When the interest rate is zero the formula simplifies to C = P / n.

Amortization Table from GET /api/loans/:id

The detail endpoint returns a unified amortization table that merges real payment history with the projected future schedule. Each row indicates whether it is a real (isProjected: false) or projected (isProjected: true) payment. The projection is always anchored to the date of the last ordinary payment (not today’s date), so the projected schedule stays aligned with the actual payment calendar even after extraordinary payments.

Extraordinary Payments

Use POST /api/loans/:id/amortize to record an early capital repayment. You must specify both the amount and the mode:
The monthly payment stays the same; the loan simply ends sooner because more capital has been paid off.
curl -s -X POST http://localhost:3008/api/loans/64a1f2e3b4c5d6e7f8a9b0c1/amortize \
  -H 'token: <your-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{
    "amount": 5000,
    "mode": "reduceTerm"
  }'
Finper records the payment with interest: 0 and principal: amount, decrements pendingAmount, and keeps monthlyPayment unchanged. The next projected payment date is the same, but the table ends earlier.

Rate Change Events

Use POST /api/loans/:id/events to record a change in interest rate or monthly payment — the typical use case being a variable-rate mortgage revised annually against Euribor.
curl -s -X POST http://localhost:3008/api/loans/64a1f2e3b4c5d6e7f8a9b0c1/events \
  -H 'token: <your-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{
    "date": 1704067200000,
    "newRate": 4.15,
    "newPayment": 812.50
  }'
Adding an event immediately updates the loan’s interestRate and monthlyPayment to the new values. The event itself is stored as an immutable history record, so the amortization table can correctly reflect different rates across different periods.

Payoff Simulator

POST /api/loans/:id/simulate-payoff lets you visualise the impact of making a one-time lump-sum payment without modifying any real data. Pass the hypothetical amount as lumpSum and Finper returns two fully projected scenarios side by side:
ScenarioWhat changes
Option A — Reduce TermSame monthly payment, earlier end date
Option B — Reduce QuotaSame end date, lower monthly payment
curl -s -X POST http://localhost:3008/api/loans/64a1f2e3b4c5d6e7f8a9b0c1/simulate-payoff \
  -H 'token: <your-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{ "lumpSum": 10000 }'
The response includes originalMonthsLeft, originalEndDate, and the full projected table for both options so you can compare total interest cost before committing.

Integration with Accounts

By default (addMovement: true), every ordinary and extraordinary payment automatically:
  1. Deducts the payment amount from the linked account’s balance.
  2. Creates an expense transaction in the linked category, giving you a full audit trail in your transaction history.
When you delete or edit a payment, these side effects are reversed or updated accordingly — the account balance is restored and the associated transaction is removed or adjusted.

Examples

Creating a Loan

curl -s -X POST http://localhost:3008/api/loans \
  -H 'token: <your-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Home Mortgage",
    "initialAmount": 180000,
    "interestRate": 3.5,
    "startDate": 1672531200000,
    "monthlyPayment": 897.34,
    "account": "64a1f2e3b4c5d6e7f8a9b0c1",
    "category": "64a1f2e3b4c5d6e7f8a9b0c3"
  }'
Finper stores pendingAmount = initialAmount and computes initialEstimatedCost by projecting the full amortization schedule from scratch. Both calculated fields are returned in the response.

Recording an Ordinary Payment

curl -s -X POST http://localhost:3008/api/loans/64a1f2e3b4c5d6e7f8a9b0c1/pay \
  -H 'token: <your-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{
    "date": 1704067200000
  }'
Omitting amount uses the current scheduled monthlyPayment. Finper splits it into interest (pendingAmount × r) and principal (payment − interest), updates pendingAmount, deducts from the account balance, and creates an expense transaction — all in one call.

Build docs developers (and LLMs) love