Leases
The owner buys an asset, keeps title to it, and rents out its use. Rent is earned for the use of a thing that exists and is owned — not for the passage of time over a sum of money.
Ownership is not a formality here: it comes with costs. Insurance, major repairs, the risk that the asset is destroyed — these sit with the owner for as long as the owner holds title, and the API has a dedicated transition for recording them. A lease in which the user bears every ownership cost while the owner bears none is a loan against collateral, described in leasing vocabulary.
Base path: /api/v1/pfp/leases · Religious reading: Ijara
Two forms
lease_type | Ends with | Purchase option |
|---|---|---|
operating | The asset comes back to the owner | None |
finance | Title passes to the lessee | Mandatory — purchase_option_price is required at creation |
The form determines which ending is legal. An operating lease cannot be closed by transfer of ownership, and a finance lease cannot be closed by return — closing a finance lease by return would strip the lessee of the purchase right it has been paying towards. The API refuses both.
Choosing finance sets purchase_option to true automatically and makes purchase_option_price required and positive.
Statuses
draft ──submit──> under_review ──review──> review_passed
│ │ │
│ └──reject──> rejected │
│ │
└──────────── acquire ────────────────────────┘
│
v
asset_acquired ──activate──> active
│
┌──────────────────────────┼──────────────────┐
│ (finance) │ (operating) │
v v v
transfer_pending ──transfer──> completed terminated
^
└── return (operating)
| Status | Meaning |
|---|---|
draft | Terms recorded |
under_review | Submitted for approval |
review_passed | A conclusion is attached |
rejected | Terminal. Requires a reason |
asset_acquired | The owner holds title and the ownership documents |
active | The asset is with the lessee; rent is running |
transfer_pending | Finance lease only — the term is over, title transfer is being formalised |
completed | Returned (operating) or transferred (finance) |
terminated | Ended early. Requires a reason |
In the secular reading acquire is reachable from draft as well as review_passed.
Create a lease
POST /api/v1/pfp/leases
{
"customer_id": "8f2a1c44-0b6e-4d51-9a3f-1c8e5b7d2a90",
"region": "RU",
"currency": "RUB",
"lease_type": "finance",
"asset_type": "equipment",
"asset_description": "CNC milling machine DMG MORI CMX 1100 V",
"asset_cost": "1450000000",
"lease_term_months": 48,
"monthly_rental": "3600000",
"advance_rental": "7200000",
"security_deposit": "10000000",
"residual_value": "290000000",
"purchase_option_price": "290000000",
"asset_location": "Kazan, Industrial Park B"
}
| Field | Type | Required | Notes |
|---|---|---|---|
customer_id | uuid | ✅ | The lessee |
region | string | ✅ | Contract region |
lease_type | enum | ✅ | operating | finance |
asset_description | string | ✅ | The asset must exist and be identifiable at signing |
asset_cost | string | ✅ | Minor units, above zero |
lease_term_months | integer | ✅ | 1–240 periods of 30 days |
monthly_rental | string | ✅ | Minor units, above zero |
purchase_option_price | string | conditional | Required when lease_type is finance |
asset_type | enum | — | vehicle | equipment | real_estate | aircraft | vessel | machinery |
advance_rental | string | — | Paid up front, added to the total due |
security_deposit | string | — | Held, not rent |
residual_value | string | — | Expected value at term end |
asset_serial_number, asset_location, asset_specifications | — | — | Identification of the specific thing |
currency, product_id, metadata | — | — |
The asset must be identifiable. asset_description must be substantive — anything ten characters or shorter is refused. This is not pedantry: renting out an unspecified future object is a bet, not a lease, and the contract would be void in the jurisdictions this product is built for. Use asset_serial_number and asset_location to pin down the specific thing.
total_rentals_due is derived: monthly_rental × lease_term_months + advance_rental.
Acquire the asset
POST /api/v1/pfp/leases/{id}/acquire
{
"ownership_documents": ["purchase-invoice-8812.pdf", "customs-decl-4471.pdf"],
"asset_serial_number": "DMG-CMX1100V-2026-0417",
"asset_registration": "RU-EQ-2026-88120",
"insurance_policy": "SOGAZ-EQ-2026-11904",
"insurance_expires": "2027-09-01"
}
ownership_documents is required — a non-empty list. This is the transition that records that the owner actually owns the thing, and it will not accept an empty hand.
draft or review_passed → asset_acquired.
Hand over and start
POST /api/v1/pfp/leases/{id}/activate
{ "delivery_date": "2026-09-15" }
delivery_date is optional and defaults to today. The lease term and the whole payment schedule are counted from it — rent starts when the lessee gets the asset, not when the contract was signed.
asset_acquired → active.
The schedule
Generated at activation. The first row falls one period after the start date, not on it: rent is paid for a month of use that has already happened.
{
"payment_schedule": [
{ "payment_number": 1, "due_date": "2026-10-15", "amount": "3600000", "status": "pending" },
{ "payment_number": 2, "due_date": "2026-11-14", "amount": "3600000", "status": "pending" }
]
}
Periods are 30 days, so due dates drift relative to the calendar. Every row carries the full monthly_rental — unlike an instalment sale, nothing is divided here, so there is no rounding remainder. The schedule therefore sums to monthly_rental × lease_term_months; advance_rental, if any, is on top of it and is not a schedule row.
Running the lease
Rent received
POST /api/v1/pfp/leases/{id}/payment
{ "amount": "3600000" }
Adds to total_rentals_paid and advances the schedule.
Arrears
POST /api/v1/pfp/leases/{id}/arrears
{ "amount": "7200000" }
Records the overdue amount. Zero is a valid value and clears the delinquency — this is the one amount field in the product family that accepts "0" (^(0|[1-9]\d*)$ rather than ^[1-9]\d*$).
As with instalment sales, recording arrears does not add anything to what is owed.
Owner's expense
POST /api/v1/pfp/leases/{id}/expense
{
"amount": "4500000",
"description": "Spindle bearing replacement, works order 2211",
"type": "maintenance"
}
This is the transition that makes the owner an owner. Insurance premiums, major repairs, statutory inspections — the costs that follow title rather than use.
description is required and must not be blank. An expense with no stated purpose cannot be justified to the lessee, and it is exactly that justification which distinguishes an owner's cost from a charge quietly passed through to the lessee. type defaults to maintenance.
Expenses accumulate in total_owner_expenses and are listed in owner_expenses.
Ending the lease
Which ending is available depends on lease_type.
Operating lease — return
POST /api/v1/pfp/leases/{id}/return
No body. active → completed, and return_date is set to today. Refused on a finance lease.
Finance lease — transfer of title
Two steps, because the term ending and the paperwork completing are not the same day.
POST /api/v1/pfp/leases/{id}/transfer_pending
No body. active → transfer_pending. Refused on an operating lease.
POST /api/v1/pfp/leases/{id}/transfer
No body. Moves the contract to completed and sets transfer_date.
Two conditions are enforced, and both matter:
- The lease must be a
financelease. - The rent must be paid in full. If
total_rentals_paidis short oftotal_rentals_due, the transfer is refused and the response names the outstanding amount:
{
"error": "unprocessable_entity",
"details": {
"total_rentals_paid": ["аренда выплачена не полностью: остаток 7200000"]
}
}
transfer is reachable from both active and transfer_pending, so the intermediate step can be skipped when the paperwork is immediate.
Early termination
POST /api/v1/pfp/leases/{id}/terminate
{ "reason": "Lessee ceased operations" }
Only an active lease can be terminated. A lease already completed by transfer or return cannot be moved to terminated — that would erase the record of an ending that actually took place.
List and read
GET /api/v1/pfp/leases
| Query parameter | Values |
|---|---|
status | any status above |
region | contract region |
type | operating | finance |
customer_id | uuid |
arrears | true — only active leases currently in arrears |
ending_in_days | integer — only active leases whose term ends within N days |
env | test | prod |
The last two are built for operational review: ?arrears=true gives the collections queue, ?ending_in_days=60 gives the leases needing a renewal or transfer decision this quarter.
GET /api/v1/pfp/leases/{id}