Safekeeping Deposits
A demand account. The holder puts money in, takes it out whenever they want, and the amount is guaranteed — no return is promised, and none is owed.
The account may still pay something. POST /bonus records a payment to the holder, and that is exactly what it is called: a bonus, not a return. It is the account-keeper's right, not the holder's entitlement. Its size is decided when it is paid; it is not announced in advance, not accrued, and not owed. An amount promised in advance would be interest with a friendlier name, and the product would become a different product.
Two consequences for your integration: there is no rate field anywhere on this account, and there is no approval stage — a demand account opens without a third party's conclusion in either reading.
Base path: /api/v1/pfp/safekeeping-deposits · Religious reading: Wadiah
Two custody forms
custody_type | The keeper may use the funds | Principal |
|---|---|---|
safekeeping_only | No — pure custody | Held, untouched |
guaranteed | Yes | Guaranteed at face value |
guaranteed is the ordinary current-account arrangement: the funds are used, and the holder is guaranteed to get back exactly what was put in. safekeeping_only is custody in the strict sense.
The response carries a derived boolean guaranteed alongside custody_type, so you do not have to know which enum value implies the guarantee.
Statuses
pending ──activate──> active ──block──> blocked
│ <──unblock──┘
│
└──close──> closed
| Status | Meaning |
|---|---|
pending | Created, not yet open |
active | Open; deposits, withdrawals and bonuses are accepted |
blocked | Frozen. Requires a reason |
closed | Terminal |
There is no under_review, no review_passed and no rejected. This product has no approval stage in either reading — a transition asking for one would mean the account had been confused with a financing contract.
Open an account
POST /api/v1/pfp/safekeeping-deposits
{
"customer_id": "8f2a1c44-0b6e-4d51-9a3f-1c8e5b7d2a90",
"region": "RU",
"currency": "RUB",
"custody_type": "guaranteed",
"initial_amount": "0",
"minimum_balance": "100000",
"account_id": "d4b7e211-8c05-4f39-a6be-7213c9e0f584",
"opened_by": "branch-kzn-04"
}
| Field | Type | Required | Notes |
|---|---|---|---|
customer_id | uuid | ✅ | The holder |
region | string | ✅ | Account region |
currency | string | ✅ | ISO 4217 |
custody_type | enum | ✅ | safekeeping_only | guaranteed |
initial_amount | string | ✅ | Minor units. Zero is allowed (^\d+$) |
minimum_balance | string | — | Minor units. Zero allowed |
account_id | uuid | — | A linked operational account |
opened_by | string | — | Free text |
metadata | object | — | Returned untouched |
initial_amount and minimum_balance are the two amount fields in this product family that accept "0". An account is often opened empty and funded afterwards, and a threshold of zero is a real setting.
Note the difference between the two zeros in a response: "minimum_balance": null means there is no minimum, "minimum_balance": "0" means the minimum is zero. current_balance is never null — a newly opened account has a balance of "0", not an absent one.
Money in and out
All three require the account to be active. On a pending, blocked or closed account they are refused.
Deposit
POST /api/v1/pfp/safekeeping-deposits/{id}/deposit
{ "amount": "50000000" }
Adds to current_balance and total_deposits, increments transactions_count.
Withdraw
POST /api/v1/pfp/safekeeping-deposits/{id}/withdraw
{ "amount": "12000000" }
Adds to total_withdrawals. Refused if it would take the balance below minimum_balance.
Bonus
POST /api/v1/pfp/safekeeping-deposits/{id}/bonus
{ "amount": "180000", "reason": "Year-end appreciation" }
amount is required, reason optional. Accumulates in total_bonus_received and appends to bonus_history.
This is a payment made at the keeper's discretion. Nothing in the account announces it in advance, and a holder who receives one this year has no claim to one next year.
Freezing and closing
POST /api/v1/pfp/safekeeping-deposits/{id}/activate # no body, pending → active
POST /api/v1/pfp/safekeeping-deposits/{id}/block # reason required
POST /api/v1/pfp/safekeeping-deposits/{id}/unblock # no body
POST /api/v1/pfp/safekeeping-deposits/{id}/close # closed_by optional
List and read
GET /api/v1/pfp/safekeeping-deposits
| Query parameter | Values |
|---|---|
status | pending | active | blocked | closed |
region | account region |
customer_id | uuid |
type | safekeeping_only | guaranteed |
min_balance | minor units, ^\d+$ — accounts at or above this balance |
env | test | prod |
An omitted filter adds no condition. Sending an empty string for one — which is what an unfilled form field produces — is treated the same way, so a partially filled search form does not collapse the result set to nothing.
GET /api/v1/pfp/safekeeping-deposits/{id}
{
"data": {
"id": "7c0b8a1e-0a5e-4a3f-9b6d-2f1f3a4b5c6d",
"deposit_number": "SFK-G-RU-20260823-1B4E07",
"status": "active",
"custody_type": "guaranteed",
"guaranteed": true,
"currency": "RUB",
"current_balance": "38180000",
"initial_amount": "0",
"minimum_balance": "100000",
"total_deposits": "50000000",
"total_withdrawals": "12000000",
"total_bonus_received": "180000",
"bonus_history": [
{ "date": "2026-12-31", "amount": "180000", "reason": "Year-end appreciation" }
],
"bonus_rate_annualized": 0,
"transactions_count": 3
}
}
bonus_rate_annualized is a rear-view mirror
The response includes an annualised figure for the bonuses actually paid, computed from the account's age. It is a report on the past, not a rate. It appears only once the account has an opening date; before then it is 0.
Do not present it to a holder as what the account pays. Nothing about a bonus paid last year commits anyone to a bonus next year, and a number displayed next to a percent sign will be read as a promise no matter what label sits beside it.