Кредиты¶
Кредит — внутренняя валюта сервиса. Цена эффекта (cost) указана в кредитах; при
генерации они резервируются и списываются, при сбое — возвращаются. Кредиты
начисляются бонусами (приветственные при регистрации), через админку и покупкой
пакетов за деньги (см. Оплата).
Баланс¶
curl "$BASE_URL/v1/credits/balance" -H "Authorization: Bearer $TOKEN"
# {"balance": 1120, "plan_credits": 500, "plan_expires_at": "2026-11-05T14:00:00Z"}
Тот же balance отдаёт и GET /v1/me — для общего профиля отдельный запрос не нужен.
balance- сколько можно потратить, всё вместе.plan_credits- какая часть этого числа пришла по подписке и сгорит вместе с её периодом. Это доляbalance, а не второй кошелёк: складывать их не нужно.plan_expires_at- когда эта доля сгорит.null, если подписки нет.
У того, кто не подписан, plan_credits равен 0, и показывать нечего. Тратятся кредиты
плана первыми, поэтому купленный пакет не расходуется, пока есть чему сгореть.
Кредит один, типов у него нет. Баланс — одно число: неважно, куплены кредиты, подарены при регистрации или заработаны на своём эффекте, тратятся они одинаково. Единственное различие - срок: кредиты плана живут до конца оплаченного периода, все остальные не сгорают никогда. Правило про заработок авторов от этого не зависит: автору капает процент только с генераций тех, кто хоть раз покупал кредиты (см. свои эффекты). Проверяется это по истории платежей, а не по происхождению конкретного кредита.
История операций (ledger)¶
Каждое движение кредитов — отдельная запись в журнале:
{
"items": [
{ "id": "…", "amount": -5, "kind": "reserve", "reference": "<generation_id>", "created_at": "…" },
{ "id": "…", "amount": 5, "kind": "refund", "reference": "<generation_id>", "created_at": "…" },
{ "id": "…", "amount": 50, "kind": "welcome", "reference": null, "created_at": "…" }
],
"total": 3, "limit": 20, "offset": 0
}
amount— знаковое: списание отрицательное, начисление положительное.kind— тип операции:welcome(приветственные при регистрации),purchase(покупка пакета за деньги, см. Оплата),purchase_revoke(отзыв купленного при возврате денег),reserve(списание под генерацию),refund(возврат при сбое),referral_bonus/referral_earned(реферальные бонусы, см. Реферальная программа),effect_earned(доля автора за чужую генерацию его эффектом, см. Свои эффекты),effect_revoked(отзыв этой доли, если кредиты за ту генерацию вернули пользователю),plan_expired(сгорел остаток кредитов плана: период закончился или подписка закрыта). Период подписки приходит той же записьюpurchase, что и пакет.reference— связанная сущность (обычноgeneration_id; уeffect_earned— id эффекта), либоnull.
Одна операция — одна запись. Списание под генерацию всегда одна строка reserve,
возврат — одна строка refund с тем же reference.
Как это связано с генерацией¶
создание генерации → reserve (баланс − cost)
успех → (доп. записи нет — резерв и есть итоговое списание)
сбой / таймаут → refund (баланс + cost)
Списание происходит сразу при создании генерации одной записью reserve. При
успехе ничего не дописывается: зарезервированное и есть итоговая стоимость. При
сбое/таймауте сумма возвращается записью refund (сама генерация остаётся в статусе
failed — отдельного статуса «возвращено» нет).
Резерв атомарный: если на балансе меньше cost, генерация не создаётся —
402 insufficient_credits. Подробнее о статусах — Генерация и realtime.
Возврат приходит туда, откуда списали: кредиты плана возвращаются в plan_credits и
сгорят вместе с периодом. Если подписка к моменту возврата уже закрыта, они возвращаются
несгораемыми: за сбой на нашей стороне пользователь не платит.