Certificate Issues
Many holders fund one asset and share the income it produces. Each certificate is an undivided share of a real thing — a leased building, a fleet, a portfolio of instalment sales — not a claim on the issuer for principal plus interest.
The distinction shows up in three places the API enforces:
- The issue must be backed.
underlying_asset_valuemay not be less thantotal_value. You cannot issue more paper than there is asset behind it. - Distributions are income, not coupons.
POST /profitdivides what the asset actually earned among the certificates outstanding. A period that earned nothing distributes nothing, and there is no accrued obligation left behind. - Failure has a name. A missed distribution is not silently indistinguishable from a made one:
POST /defaultexists, and a defaulted issue says so.
Base path: /api/v1/pfp/certificate-issues · Religious reading: Sukuk
Backing types
backing_type names the contract whose income the certificates share:
| Value | The certificates are backed by |
|---|---|
lease | Rental income from a leased asset |
managed_investment | A managed venture's profit |
partnership | A share in a joint venture |
installment_sale | A portfolio of instalment receivables |
manufacturing | An asset under construction, paid in stages |
forward_purchase | Goods paid for now and delivered later |
Statuses
draft ──submit──> under_review ──review──> review_passed
│ │ │
│ └──reject──> rejected │
│ │
└──────────── offering ───────────────────────┘
│
v
offering ──subscribe──> (holders record subscriptions)
│
close_subscription (optional)
v
subscribed
│ activate ← also reachable directly from offering
v
active ──mature──> matured ──redeem──> redeemed
│ │
│ └──default──> defaulted
├──redeem_early──> redeemed
└──default──> defaulted
| Status | Meaning |
|---|---|
draft | Terms recorded |
under_review | Submitted for approval |
review_passed | A conclusion is attached |
rejected | Terminal. Requires a reason |
offering | The subscription window is open |
subscribed | Window closed, not yet placed |
active | Placed; certificates are outstanding and earning |
matured | The maturity date has arrived |
redeemed | Bought back; all positions closed |
defaulted | Obligations not met. Requires a reason |
In the secular reading offering is reachable from draft as well as review_passed.
Create an issue
POST /api/v1/pfp/certificate-issues
{
"name": "Kazan Logistics Park — Series A",
"region": "RU",
"currency": "RUB",
"backing_type": "lease",
"underlying_asset": "Logistics complex, 12 400 m², Kazan, lease to Magnit until 2032",
"underlying_asset_type": "real_estate",
"underlying_asset_value": "1800000000",
"total_value": "1500000000",
"certificate_value": "1000000",
"expected_yield": 9,
"maturity_months": 60,
"min_subscription": 5,
"max_subscription": 300,
"profit_distribution_frequency": "quarterly",
"redemption_mode": "bullet",
"early_redemption_allowed": true,
"early_redemption_penalty": "20000"
}
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | ✅ | Issue name |
region | string | ✅ | Issue region |
backing_type | enum | ✅ | See the table above |
underlying_asset | string | ✅ | Description, longer than 10 characters |
underlying_asset_value | string | ✅ | Minor units. Must be at least total_value |
total_value | string | ✅ | Minor units. Must divide by certificate_value exactly |
certificate_value | string | ✅ | Minor units — the face value of one certificate |
expected_yield | integer | ✅ | Whole percent, 1–50 |
maturity_months | integer | ✅ | 1–360 |
min_subscription | integer | — | Minimum certificates per application |
max_subscription | integer | — | Ceiling per holder, across all their applications |
profit_distribution_frequency | enum | — | monthly | quarterly | semi_annually | annually |
redemption_mode | enum | — | bullet | amortizing | callable |
early_redemption_allowed | boolean | — | Gates redeem_early |
early_redemption_penalty | string | — | Minor units |
subscription_start, subscription_end | date | — | May also be set at offering |
originator_id, spv_id, product_id | uuid | — | |
underlying_asset_type, metadata | — | — |
certificates_total is derived as total_value / certificate_value, and the division must be exact.
The issue code
Each issue gets an isin field. It is not a real ISIN. A genuine ISIN is issued by a national numbering agency; the platform cannot invent one and does not pretend to. The code here is sixteen characters where ISO 6166 specifies exactly twelve, so that it cannot be mistaken for an exchange-issued identifier:
RUCRT4A7F1C9E2B3
│ │ │ └── Luhn check digit
│ │ └── ten random hex characters
│ └── three characters naming the reading: CRT secular, SKK religious
└── two-character region code
Use it internally. If the issue is listed, replace it with the real ISIN from the numbering agency.
Running a subscription
Open the window
POST /api/v1/pfp/certificate-issues/{id}/offering
{ "subscription_start": "2026-09-01", "subscription_end": "2026-10-15" }
Both dates are required. draft or review_passed → offering.
Record a subscription
POST /api/v1/pfp/certificate-issues/{id}/subscribe
{ "investor_id": "b7d1e044-92a3-4c58-8f10-3ea6c9d27b45", "certificates": 50 }
Six conditions are checked, in this order:
certificatesmust be a positive integer.- The issue must be at
offering— a draft, a matured or a redeemed issue does not accept subscriptions. - Today must be inside the subscription window. A closed window rejects.
certificatesmust be at leastmin_subscription.max_subscriptionis checked against the holder's total position, not against the single application. Two applications each at the ceiling are refused, because together they exceed it. The error names how much the holder already holds.certificatesmust not exceed what is still unsubscribed.
Close the window (optional)
POST /api/v1/pfp/certificate-issues/{id}/close_subscription
No body. offering → subscribed. Refused if nobody subscribed.
This step is optional — it exists so the gap between collecting applications and placing the issue is visible in reporting. activate accepts an issue directly from offering as well.
Place the issue
POST /api/v1/pfp/certificate-issues/{id}/activate
{ "issue_date": "2026-10-20" }
issue_date is optional and defaults to today. Refused if there are no subscriptions — an issue with no holders cannot be placed. Sets certificates_outstanding from what was subscribed and computes the maturity date.
offering or subscribed → active.
Distribute income
POST /api/v1/pfp/certificate-issues/{id}/profit
{ "total_profit": "33750000", "period_end_date": "2026-12-31" }
Only from active. The amount is divided by certificates_outstanding, floored, and recorded:
{
"profit_distributions": [
{
"date": "2026-12-31",
"total_profit": "33750000",
"per_certificate": "22500",
"certificates_outstanding": 1500
}
],
"total_profit_distributed": "33750000",
"actual_yield": 9,
"next_distribution_date": "2027-03-31"
}
actual_yield is recomputed on every distribution: it is what the issue has actually paid, against expected_yield, which is what was hoped for at launch. Both are whole percent. When they diverge, the second number is the one that is true.
Zero and negative amounts are refused. period_end_date is optional and defaults to today.
Ending an issue
Maturity
POST /api/v1/pfp/certificate-issues/{id}/mature
No body. active → matured, but only if the maturity date has actually arrived. Calling it early is refused.
Redemption
POST /api/v1/pfp/certificate-issues/{id}/redeem
{ "redemption_date": "2031-10-20" }
Only from matured. Closes every holder's position and sets certificates_outstanding to zero.
Early redemption
POST /api/v1/pfp/certificate-issues/{id}/redeem_early
{ "redemption_date": "2029-06-01" }
Only from active, and only if early_redemption_allowed was set at creation. Otherwise:
{
"error": "unprocessable_entity",
"details": {
"early_redemption_allowed": ["досрочный выкуп условиями не предусмотрен"]
}
}
Default
POST /api/v1/pfp/certificate-issues/{id}/default
{ "reason": "Lessee insolvent; no rental income since 2028-04" }
Available from active and from matured — an issue can fail before its term or fail to pay at redemption. The reason is stored in metadata.default_reason.
List and read
GET /api/v1/pfp/certificate-issues
| Query parameter | Values |
|---|---|
status | any status above |
region | issue region |
type | any backing_type |
investor_id | uuid — issues in which this holder has a subscription |
env | test | prod |
GET /api/v1/pfp/certificate-issues/{id}