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 API manages personal loans using the French amortization model (constant monthly payment). Each loan tracks a live pendingAmount that decreases with every payment. Ordinary payments follow a monthly schedule; extraordinary payments (early capital repayments) can either shorten the term (reduceTerm) or lower the monthly quota (reduceQuota). Rate-change events model variable-rate renegotiations such as Euribor reviews. Every payment automatically updates the linked account balance and generates an expense transaction.

GET /api/loans

List all loans belonging to the authenticated user. The response is a flat array — no amortization table is included at this level.
curl http://localhost:3008/api/loans \
  -H 'token: <your-jwt>'
Response 200
[
  {
    "_id": "64a1f...",
    "name": "Car Loan",
    "initialAmount": 12000,
    "pendingAmount": 9400.50,
    "interestRate": 4.5,
    "startDate": 1672531200000,
    "monthlyPayment": 310.25,
    "initialEstimatedCost": 13458.00,
    "account": "64a0e...",
    "category": "64a0f...",
    "user": "alice"
  }
]

POST /api/loans

Create a new loan. pendingAmount is set automatically to initialAmount; initialEstimatedCost is calculated from the full projected amortization table at creation time — you do not supply either field.

Body parameters

name
string
required
Descriptive label for the loan (e.g. "Mortgage", "Car Loan").
initialAmount
number
required
Original principal. Must be a positive number. This value never changes after creation.
interestRate
number
required
Annual nominal interest rate (TIN) expressed as a percentage — e.g. 3.5 means 3.5%. Must be ≥ 0 (0 = interest-free loan).
startDate
number
required
Loan start date as a Unix timestamp in milliseconds. The first projected payment falls exactly on this date.
monthlyPayment
number
required
Initial monthly quota. Must be positive. Used to project the full amortization table and calculate initialEstimatedCost.
account
string
required
ID of the account from which payments will be deducted.
category
string
required
ID of the expense category used when auto-creating payment transactions.
pendingAmount is derived from initialAmount automatically. initialEstimatedCost is computed by projecting the complete amortization schedule at creation time. Both are forbidden in the request body — the API returns HTTP 422 if either is provided.
curl -X POST http://localhost:3008/api/loans \
  -H 'token: <your-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Car Loan",
    "initialAmount": 12000,
    "interestRate": 4.5,
    "startDate": 1672531200000,
    "monthlyPayment": 310.25,
    "account": "64a0e...",
    "category": "64a0f..."
  }'
Response 201 — the created loan object.

GET /api/loans/:id

Retrieve full loan detail including the historical payment list, the projected future payment schedule, and a statistics summary.
id
string
required
Loan ID.
curl http://localhost:3008/api/loans/64a1f... \
  -H 'token: <your-jwt>'
Response 200
{
  "_id": "64a1f...",
  "name": "Car Loan",
  "initialAmount": 12000,
  "pendingAmount": 9400.50,
  "interestRate": 4.5,
  "startDate": 1672531200000,
  "monthlyPayment": 310.25,
  "initialEstimatedCost": 13458.00,
  "account": "64a0e...",
  "category": "64a0f...",
  "payments": [...],
  "projectedPayments": [...],
  "stats": {
    "paidPrincipal": 2599.50,
    "paidInterest": 180.75,
    "pendingPrincipal": 9400.50,
    "estimatedPendingInterest": 678.00,
    "totalCostToDate": 2780.25,
    "estimatedTotalCost": 13238.25,
    "savedByExtraordinary": 219.75,
    "estimatedEndDate": 1735689600000,
    "currentPayment": 310.25,
    "currentRate": 4.5
  }
}

Stats fields

paidPrincipal
number
Sum of principal across all real (historical) payments.
paidInterest
number
Sum of interest across all real payments.
pendingPrincipal
number
Current loan.pendingAmount — the live capital still owed.
estimatedPendingInterest
number
Sum of interest across all projected future payments.
totalCostToDate
number
Sum of amount (principal + interest) across all real payments.
estimatedTotalCost
number
totalCostToDate plus the sum of all projected future payment amounts.
savedByExtraordinary
number
initialEstimatedCost − estimatedTotalCost. A positive value shows how much interest has been saved through extraordinary early repayments.
estimatedEndDate
number
Unix timestamp (ms) of the last projected payment. null if the loan is fully paid.
currentPayment
number
Monthly quota currently in effect (from the most recent event, or loan.monthlyPayment).
currentRate
number
Annual interest rate currently in effect (from the most recent event, or loan.interestRate).

PUT /api/loans/:id

Edit basic loan metadata. All fields are optional; only the provided fields are updated. This endpoint does not recalculate the projected amortization table — use payment and event endpoints to affect the financial schedule.
id
string
required
Loan ID.
name
string
New descriptive label.
account
string
Replace the linked account ID.
category
string
Replace the linked category ID.
curl -X PUT http://localhost:3008/api/loans/64a1f... \
  -H 'token: <your-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{"name": "Refinanced Car Loan"}'
Response 200 — the updated loan object.

DELETE /api/loans/:id

Delete a loan and cascade-delete all of its payments and events.
id
string
required
Loan ID.
This operation does not restore account balances or remove the transactions that were generated by past payments. If you need a full revert, delete individual payments first via DELETE /api/loans/:id/payments/:paymentId.
curl -X DELETE http://localhost:3008/api/loans/64a1f... \
  -H 'token: <your-jwt>'
Response 204 — no content.

POST /api/loans/:id/pay

Record an ordinary (scheduled monthly) payment. The interest and principal split is calculated automatically from the current pendingAmount and interestRate. The account balance is decremented and an expense transaction is created unless addMovement is set to false.
id
string
required
Loan ID.
date
number
Payment date as a Unix timestamp (ms). Defaults to now.
amount
number
Override the calculated quota. Must be positive. Useful for final partial payments.
addMovement
boolean
Whether to deduct from the account and create an expense transaction. Defaults to true.
curl -X POST http://localhost:3008/api/loans/64a1f.../pay \
  -H 'token: <your-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{"date": 1675209600000}'
Response 201 — the created payment object.

POST /api/loans/:id/amortize

Record an extraordinary payment (early capital repayment). The full amount goes to principal (interest = 0). Choose a mode to determine whether the remaining term shortens or the monthly quota decreases.
id
string
required
Loan ID.
amount
number
required
Capital amount to repay early. Must be positive.
mode
string
required
How the loan is restructured after early repayment. One of reduceTerm or reduceQuota.
  • reduceTerm: keeps the same monthly payment, shortens the remaining term.
  • reduceQuota: keeps the same remaining term, recalculates a lower monthly payment.
date
number
Payment date as a Unix timestamp (ms). Defaults to now.
addMovement
boolean
Whether to deduct from the account and create an expense transaction. Defaults to true.
ModeMonthly paymentMonths remaining
reduceTermUnchangedDecreases
reduceQuotaDecreasesUnchanged
curl -X POST http://localhost:3008/api/loans/64a1f.../amortize \
  -H 'token: <your-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{
    "amount": 2000,
    "mode": "reduceTerm",
    "date": 1675209600000
  }'
Response 201 — the created extraordinary payment object.

POST /api/loans/:id/events

Record a rate-change event — a point in time from which a new interest rate and monthly payment apply. This models variable-rate renegotiations (e.g. annual Euribor + spread reviews).
id
string
required
Loan ID.
date
number
required
Effective date of the new conditions, as a Unix timestamp (ms).
newRate
number
required
New annual nominal interest rate (TIN%) from this date onwards. Must be ≥ 0.
newPayment
number
required
New monthly payment amount from this date onwards. Must be positive.
Adding an event immediately updates loan.interestRate and loan.monthlyPayment to the new values. Events are immutable history; they cannot be edited, only added.
curl -X POST http://localhost:3008/api/loans/64a1f.../events \
  -H 'token: <your-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{
    "date": 1704067200000,
    "newRate": 3.9,
    "newPayment": 295.00
  }'
Response 201 — the created event object.

POST /api/loans/:id/simulate-payoff

Simulate the financial impact of making a one-time lump-sum capital payment without modifying any real data. Returns two comparison scenarios so you can decide whether to reduce the term or reduce the quota before committing.
id
string
required
Loan ID.
lumpSum
number
required
Hypothetical lump-sum amount to apply. Must be a positive integer.
curl -X POST http://localhost:3008/api/loans/64a1f.../simulate-payoff \
  -H 'token: <your-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{"lumpSum": 3000}'
Response 200
{
  "lumpSum": 3000,
  "originalMonthsLeft": 36,
  "originalEndDate": 1767225600000,
  "optionA": {
    "label": "reduceTerm",
    "monthsLeft": 26,
    "endDate": 1751328000000,
    "totalInterest": 410.20,
    "monthlySaving": 0,
    "interestSaving": 267.80
  },
  "optionB": {
    "label": "reduceQuota",
    "monthsLeft": 36,
    "endDate": 1767225600000,
    "newMonthlyPayment": 227.50,
    "monthlySaving": 82.75,
    "interestSaving": 220.10
  }
}
lumpSum
number
The hypothetical payment amount used in the simulation.
originalMonthsLeft
number
Projected months remaining before the simulation.
originalEndDate
number
Projected end date before the simulation (Unix ms).
optionA
object
Scenario where the lump sum is applied with reduceTerm — same quota, shorter loan life.
optionB
object
Scenario where the lump sum is applied with reduceQuota — same term, lower monthly payment.

PUT /api/loans/:id/payments/:paymentId

Edit an existing payment. Triggers a full forward-pass recalculation of accumulatedPrincipal and pendingCapital for every subsequent payment using a bulkWrite. Also updates loan.pendingAmount and, for ordinary payments, synchronises the linked expense transaction.
id
string
required
Loan ID.
paymentId
string
required
Payment ID.
date
number
New payment date (Unix ms).
amount
number
New total payment amount.
interest
number
New interest portion (min 0).
principal
number
New principal portion (min 0).
type
string
Payment type: ordinary or extraordinary.
At least one of date, amount, interest, principal, or type must be provided. The request returns HTTP 422 if only internal fields (user, paymentId) are supplied without any editable field.
curl -X PUT http://localhost:3008/api/loans/64a1f.../payments/64b2g... \
  -H 'token: <your-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{"amount": 320.00, "date": 1675296000000}'
Response 200 — the updated payment object.

DELETE /api/loans/:id/payments/:paymentId

Delete a payment. Reverts the account balance (adds back the payment amount) and removes the linked expense transaction (for ordinary payments). Restores loan.pendingAmount by the principal portion of the deleted payment.
id
string
required
Loan ID.
paymentId
string
required
Payment ID.
curl -X DELETE http://localhost:3008/api/loans/64a1f.../payments/64b2g... \
  -H 'token: <your-jwt>'
Response 204 — no content.

Account integration

Every ordinary and extraordinary payment with addMovement: true (the default) performs two side-effects atomically:
  1. Decrements account.balance by the payment amount.
  2. Creates an expense Transaction linked to loan.category.
Deleting a payment reverses both operations. Editing a payment with a changed amount or date updates the linked transaction accordingly.

Build docs developers (and LLMs) love