Приложение не предоставляет сетевой backend API. Под интеграционным API здесь понимаются стабильные форматы обмена данными:
- JSON-экспорт расчёта;
- share-link с параметрами расчёта в URL;
- правила версионирования этих форматов.
Оба формата сохраняют только исходные параметры кредита и пользовательские настройки. Готовый график платежей, итоги сценариев и промежуточные расчётные поля не экспортируются: принимающая сторона должна пересчитать их локально.
JSON-файл создаётся кнопкой экспорта в приложении. Текущий формат основан на снимке SharedCalculationV1 и дополнительно содержит exportedAt. Перед созданием JSON приложение проверяет обязательные поля кредита и расчётные ограничения, чтобы не распространять заведомо невалидный payload.
Минимальная структура:
{
"version": 1,
"name": "Мой кредит",
"config": {
"principal": 7200000,
"annualRate": 12.4,
"rateChanges": [],
"rateChangeMode": "nextPeriod",
"issueDate": "2026-06-23",
"firstPaymentDate": "2026-07-15",
"firstPaymentInterestOnly": true,
"termMonths": 240,
"paymentDay": 15,
"paymentType": "annuity",
"frequency": "monthly",
"currency": "RUB",
"rounding": "kopecks",
"closeThreshold": 300,
"oneTimeFee": 0,
"monthlyFee": 0,
"earlyRepaymentFeePercent": 0,
"interest": {
"method": "daily",
"dayCountBasis": "actualActual",
"includePaymentDate": true,
"periodStart": "exclusive",
"balanceMoment": "startOfDay"
}
},
"repayments": [],
"repaymentRules": [],
"gracePeriods": [],
"selectedScenario": "combined",
"settings": {
"termUnit": "months",
"displayDecimals": 2,
"theme": "emerald",
"customAccentColor": "#0b9873",
"useCustomAccentColor": false
},
"exportedAt": "2026-07-07T10:00:00.000Z"
}| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
version |
1 |
рекомендуется | Версия формата снимка. Для старых JSON может отсутствовать; если поле указано, принимается только числовое значение 1. |
name |
string |
нет | Название кредита. Ограничение: 500 символов. |
config |
LoanConfig |
да | Основные параметры кредита. |
repayments |
EarlyRepayment[] |
нет | Разовые досрочные платежи. Если отсутствует, считается пустым массивом. |
repaymentRules |
RepaymentRule[] |
нет | Регулярные правила досрочного погашения. Если отсутствует, считается пустым массивом. |
gracePeriods |
GracePeriod[] |
нет | Льготные периоды. Если отсутствует, считается пустым массивом. |
selectedScenario |
string |
нет | Выбранный сценарий. По умолчанию reduceTerm. |
settings |
object |
нет | Настройки отображения. Для старых JSON допускаются эти поля прямо на верхнем уровне. |
exportedAt |
ISO datetime | нет | Время создания файла. При импорте используется только как справочное поле. |
| Поле | Тип / значения |
|---|---|
principal |
number, больше 0 |
annualRate |
number, от 0 до 100 |
rateChanges |
RateChange[], максимум 1000 |
rateChangeMode |
nextPeriod или exactDate |
issueDate |
дата YYYY-MM-DD |
firstPaymentDate |
дата YYYY-MM-DD, строго после issueDate |
firstPaymentInterestOnly |
boolean |
firstPaymentInterestOnlyMode |
addToTerm или withinTerm; для legacy-файлов по умолчанию addToTerm |
termMonths |
integer, от 1 до 1200 |
paymentDay |
integer, от 1 до 31 |
paymentType |
annuity или differentiated |
frequency |
monthly, biweekly или quarterly |
currency |
RUB, USD, EUR или CNY; отсутствующее поле получает RUB, известный legacy-код RUR преобразуется в RUB с предупреждением, другие явные значения отклоняются |
rounding |
kopecks, rubles или bank |
closeThreshold |
number, не меньше 0 |
oneTimeFee |
number, не меньше 0 |
monthlyFee |
number, не меньше 0 |
earlyRepaymentFeePercent |
number, от 0 до 100 |
interest |
InterestConfig |
RateChange:
{
id: string
date: string
annualRate: number
}date должна быть корректной датой YYYY-MM-DD, позже config.issueDate; даты изменений ставки не должны повторяться.
InterestConfig:
{
method: 'annuity' | 'daily'
dayCountBasis: '366' | '360' | 'actual365' | 'actualActual'
includePaymentDate: boolean
periodStart: 'inclusive' | 'exclusive'
balanceMoment: 'startOfDay' | 'endOfDay'
}Legacy-значение 365 при импорте и миграции persisted state преобразуется в эквивалентное actual365. Поле dayCountBasis используется только при method: 'daily'; периодический метод делит номинальную ставку на число платёжных периодов в году.
Разовый досрочный платёж:
{
id: string
date: string
amount: number
enabled?: boolean
amountMode?: 'extra' | 'totalWithFee'
sameDaySequence?: number
operationSource?: 'manual' | 'rule'
sourceRuleId?: string
strategy: 'reduceTerm' | 'reducePayment' | 'full' | 'custom'
source: 'own' | 'subsidy' | 'insurance' | 'other'
sameDayOrder: 'regularFirst' | 'earlyFirst'
interestFirst: boolean
comment?: string
}Ограничения:
- максимум 5000 элементов;
amountможет быть0, чтобы временно отключить платёж без удаления записи;amountMode: 'totalWithFee'допустим только в дату регулярного платежа и только после регулярного списания;- для одной даты допускается только одна активная операция с
amountMode: 'totalWithFee'и положительной суммой; sameDaySequence, если указан, должен быть целым числом не меньше 0 и не должен дублироваться в рамках одной даты.
Правило регулярного досрочного погашения:
{
id: string
name: string
ruleSequence?: number
type: 'weeklyFixed' | 'monthlyFixed' | 'bimonthlyFixed' | 'quarterlyFixed' | 'semiannualFixed' | 'annualFixed' | 'annualBonus' | 'paymentPercent' | 'monthlyTotalPayment'
startDate: string
endDate: string
amount?: number
percent?: number
enabled?: boolean
strategy: 'reduceTerm' | 'reducePayment' | 'full' | 'custom'
source: 'own' | 'subsidy' | 'insurance' | 'other'
sameDayOrder: 'regularFirst' | 'earlyFirst'
interestFirst: boolean
skipMonths: string[]
comment?: string
}Ограничения:
- максимум 5000 правил;
startDateиendDateдолжны быть датамиYYYY-MM-DD,endDateне раньшеstartDate;- для
paymentPercentтребуетсяpercent, для остальных типов требуетсяamount; amountиpercentмогут быть0, чтобы временно заморозить правило;monthlyTotalPaymentвсегда нормализуется кsameDayOrder: 'regularFirst';skipMonthsсодержит строкиYYYY-MM, максимум 1200 элементов.
Льготный период:
{
id: string
startDate: string
endDate: string
type: 'full' | 'interestOnly' | 'reduced' | 'custom'
paymentAmount?: number
extendTerm: boolean
accrueInterest: boolean
capitalizeInterest: boolean
}Ограничения:
- максимум 100 элементов;
endDateне раньшеstartDate;- периоды не должны пересекаться;
paymentAmount, если указан, должен быть неотрицательным.
{
termUnit: 'months' | 'years'
displayDecimals: 0 | 2
theme: 'emerald' | 'ocean' | 'violet' | 'graphite' | 'warm' | 'night'
customAccentColor?: string
useCustomAccentColor?: boolean
}customAccentColor должен быть HEX-цветом вида #0b9873.
Share-link хранит тот же снимок расчёта, что и JSON, но без поля exportedAt. Перед созданием ссылки или короткого кода параметров применяется та же проверка, что и для JSON-экспорта.
Формат URL:
https://example.com/CreditCalc/#calc=<payload>
Формат payload:
v1.<base64url(gzip(utf8-json(SharedCalculationV1)))>
Расшифровка:
- из URL hash берётся значение после
calc=; - проверяется префикс
v1.; - часть после префикса декодируется как Base64URL;
- байты распаковываются через gzip;
- результат читается как UTF-8 JSON;
- JSON проходит ту же нормализацию и валидацию, что и импорт из файла.
Приложение также принимает:
- полный URL с
#calc=...; - строку
calc=...; - сырой payload
v1..... - payload
v1...., внутри которого JSON может не содержать собственного поляversion.
Ограничения share-link:
- единый максимальный размер UTF-8 JSON для импорта, JSON-экспорта и данных до/после распаковки share-link: 8 МиБ;
- максимальная длина закодированного base64url payload: 12 МиБ символов;
- распаковка контролирует размер потоково и останавливается до выделения чрезмерного буфера.
Текущая версия снимка данных: version: 1.
Текущий префикс share-link: v1..
Правила для интеграций:
- Генерируйте
version: 1для новых JSON-файлов и share-link payload. - При чтении JSON не полагайтесь на порядок полей.
- Игнорируйте неизвестные поля на верхнем уровне и внутри объектов, если они не конфликтуют с известной моделью.
- Передавайте даты только в формате
YYYY-MM-DD, месяцы пропуска только в форматеYYYY-MM. - Не экспортируйте готовый график платежей как часть модели обмена: он является производным результатом.
- Для старых данных допускается отсутствие некоторых полей
configиconfig.interest; приложение подставляет значения по умолчанию. - Если поле
currencyотсутствует, приложение используетRUBс предупреждением. Из явных legacy-значений поддерживается толькоRUR → RUB; суммы не конвертируются. Другие неизвестные валюты отклоняются. - Отсутствующие legacy-поля получают документированные defaults. Если финансовое поле присутствует, но содержит значение вне схемы, импорт завершается ошибкой. Преобразования
RUR,amountMode: "total"и отсутствующего legacyamountModeвозвращаются вimportWarnings. - Share-link с неизвестным префиксом, например
v2., должен считаться неподдерживаемым. - JSON или share-link с
version, отличной от1, не следует создавать до появления отдельной миграции формата. - Импорт отклоняет JSON с любой явно указанной неизвестной, строковой или будущей версией. Legacy JSON без
versionтрактуется как версия1; это единственное правило совместимости для отсутствующего поля. - Runtime-схема проецирует только документированные поля. Неизвестные свойства удаляются, комментарии обязаны быть строками, а идентификаторы ограничены 128 символами.
- Повреждённый share payload удаляется из URL hash после первой ошибки, чтобы перезагрузка не запускала его повторно; сообщение показывается глобально с переходом к панели импорта.
При добавлении новой версии формата нужно:
- оставить чтение
version: 1; - добавить явную миграцию из старой структуры в текущую модель;
- сменить префикс share-link только при несовместимом изменении кодирования или структуры payload;
- обновить этот документ вместе с кодом сериализации и импорта.