Skip to content

API биллинга

Эти публичные endpoints управляют тарифом account, балансом, project add-ons, купонами, referral-программой и продлением. Callback-ручки платежных провайдеров не входят в публичный API.

GET /api/billing/overview

Возвращает обзор биллинга текущего account.

GET /api/billing/wallet/overview

Возвращает обзор баланса и кошелька account.

POST /api/billing/wallet/crypto-topup

Создает пополнение баланса криптовалютой. Если передан returnUrl или cancelUrl, API устанавливает в нём query-параметр externalReference с точным идентификатором созданного пополнения, заменяя прежнее значение. Сохраните этот идентификатор при возврате от платежного провайдера.

POST /api/billing/wallet/topup/refresh

Обновляет статус пополнения, точно указанного через topupId или externalReference. Используйте идентификатор из ответа создания или URL возврата; не определяйте пополнение как самое последнее. Страница возврата не должна вызывать refresh, если идентификатор отсутствует, повторяется или конфликтует с другим идентификатором.

POST /api/billing/account-plan/balance-purchase

Покупает или улучшает тариф account за баланс кошелька.

Тело запроса:

ПолеОбязательноеОписание
planIdДаЦелевой тариф: advanced или pro.
durationMonthsДаПериод оплаты: 1, 3, 6 или 12 месяцев.
autoRenewНетВключать ли автоматическое продление полученной подписки. Если поле не передано, используется false.
requestIdНетКлюч идемпотентности из 8-128 unreserved-символов RFC 3986: A-Z, a-z, 0-9, ., _, ~ и -. Его можно не передавать для обратной совместимости, но для новых клиентов он рекомендуется.

Используйте один стабильный requestId для одного подтверждённого пользователем намерения. После timeout или другого неопределённого результата повторите запрос с теми же payload и requestId. Точный повтор возвращает исходные subscriptionId и invoiceId без второго списания с кошелька. Повторное использование этого requestId с другими planId, durationMonths или autoRenew отклоняется. Для нового намерения покупки создайте новый requestId. Без requestId запрос по-прежнему принимается для обратной совместимости, но отдельные HTTP-попытки не являются retry-safe и идемпотентными.

СлучайОбязательное поведение
same-intentПередать same-requestId с same-payload.
exact-replayВернуть original-subscriptionId и original-invoiceId с no-second-debit.
conflicting-payloadЗапрос rejected.
new-intentСоздать new-requestId.
missing-requestIdСохраняется backward-compatible, но запрос not-retry-safe и not-idempotent-across-HTTP-attempts.

Ответ: HTTP 200 OK.

ПолеОбязательноеОписание
subscriptionIdДаИдентификатор активированной подписки.
invoiceIdДаИдентификатор оплаченного счёта.

POST /api/billing/account-plan/checkout

Создает checkout для тарифа account.

POST /api/billing/account-plan/crypto-checkout

Создает прямой crypto checkout для тарифа account.

POST /api/billing/project-addon/balance-purchase

Покупает add-on бесплатного доступа к project за баланс кошелька.

Тело запроса:

ПолеОбязательноеОписание
projectFullnameДаПолное имя project, для которого приобретается add-on.
addonCodeДаИдентификатор add-on: project-free-access.
durationMonthsДаПериод оплаты: 1, 3, 6 или 12 месяцев.
autoRenewНетВключать ли автоматическое продление полученной подписки. Если поле не передано, используется false.
requestIdНетКлюч идемпотентности из 8-128 unreserved-символов RFC 3986: A-Z, a-z, 0-9, ., _, ~ и -. Его можно не передавать для обратной совместимости, но для новых клиентов он рекомендуется.

Используйте один стабильный requestId для одного подтверждённого пользователем намерения. После timeout или другого неопределённого результата повторите запрос с тем же requestId и тем же полным payload, включая projectFullname, addonCode, durationMonths и autoRenew. Точный повтор возвращает исходные subscriptionId и invoiceId без второго списания с кошелька. Повторное использование этого requestId после изменения любого из перечисленных полей отклоняется. Для нового намерения покупки создайте новый requestId. Без requestId запрос по-прежнему принимается для обратной совместимости, но отдельные HTTP-попытки не являются retry-safe и идемпотентными.

СлучайОбязательное поведение
same-intentПередать same-requestId с same-full-payload: projectFullname, addonCode, durationMonths и autoRenew.
exact-replayВернуть original-subscriptionId и original-invoiceId с no-second-debit.
conflicting-payloadЗапрос с изменённым projectFullname, addonCode, durationMonths или autoRenew отклоняется (rejected).
new-intentСоздать new-requestId.
missing-requestIdСохраняется backward-compatible, но запрос not-retry-safe и not-idempotent-across-HTTP-attempts.

Ответ: HTTP 200 OK.

ПолеОбязательноеОписание
subscriptionIdДаИдентификатор активированной подписки add-on проекта.
invoiceIdДаИдентификатор оплаченного счёта.

POST /api/billing/project-addon/checkout

Создает checkout для project add-on.

Если соответствующий hosted checkout всё ещё ожидает оплаты, повторный запрос возвращает существующие subscriptionId, invoiceId и externalReference вместе с новой подписанной формой checkout. Отправляйте последнюю полученную форму.

СлучайОбязательное поведение
pending-hosted-retryВернуть существующие subscriptionId, invoiceId и externalReference с новой подписанной формой checkout.

POST /api/billing/project-addon/crypto-checkout

Создает прямой crypto checkout для project add-on.

Если ожидающий checkout уже связан с заказом провайдера, повторный запрос возвращает те же providerOrderId и paymentUrl. Если создание заказа или сохранение связи завершилось с неопределённым результатом, checkout остаётся в pending-состоянии и блокирует новую попытку. Сначала отмените его или дождитесь reconciliation.

СлучайОбязательное поведение
pending-linked-order-retryВернуть те же providerOrderId и paymentUrl.
ambiguous-provider-creation-or-linkageСохранить fail-closed-pending; требуется cancel-or-reconcile-before-new-attempt.

POST /api/billing/coupon/redeem

Активирует купон для платного тарифа аккаунта.

Тело запроса:

ПолеОбязательноОписание
codeДаКод купона. Начальные и конечные пробелы удаляются (trim), регистр не учитывается (case-insensitive).

Оплаченный купоном период тарифа применяется только один раз. В зависимости от текущего оплаченного периода активация продлевает его, накладывает применимый период или начинает новый период.

Сценарий активацииОбязательное поведение
code-normalizationПрименяются trim и сопоставление case-insensitive.
same-account-retryВозвращаются same-couponId, same-subscriptionId и same-invoiceId с no-second-application.
unavailable-or-unsafeКупон со статусом redeemed-by-another-account, deleted, invalid или с unsafe-subscription-lineage должен завершаться как fail-closed.
paid-account-plan-periodВыполняется extend, overlay или начинается new-term, as-applicable.

Ответ: HTTP 200 OK.

ПолеОбязательноОписание
couponIdДаИдентификатор активированного купона.
subscriptionIdДаИдентификатор полученной подписки на тариф аккаунта.
invoiceIdДаИдентификатор оплаченного купоном счёта.

POST /api/billing/coupon/gift-purchase

Покупает подарочный купон за баланс кошелька.

Тело запроса:

ПолеОбязательноОписание
planIdДаПлатный тариф аккаунта: advanced или pro.
durationMonthsДаСрок действия купона: 1, 3, 6 или 12 месяцев.
requestIdНетКлюч идемпотентности из 8-128 unreserved-символов RFC 3986: A-Z, a-z, 0-9, ., _, ~ и -. Его можно не передавать для обратной совместимости, но для новых клиентов он рекомендуется.

В рамках одного аккаунта используйте один стабильный requestId для одной подтверждённой покупки подарка. После таймаута или другого неизвестного результата повторите запрос с тем же тарифом и сроком.

Сценарий покупкиОбязательное поведение
same-intentПередать same-requestId, same-planId и same-durationMonths.
exact-replayВозвращаются same-couponId и same-code с no-second-debit и no-second-referral-reward.
conflicting-payloadПовторное использование идентификатора запроса с другим тарифом или сроком будет rejected.
new-intentСоздать new-requestId.
missing-requestIdСохраняется backward-compatible, но запрос not-retry-safe и not-idempotent-across-HTTP-attempts.

Ответ: HTTP 200 OK.

ПолеОбязательноОписание
couponIdДаИдентификатор купленного подарочного купона.
codeДаКод для передачи получателю купона.

GET /api/billing/referral/overview

Возвращает обзор referral-баланса и ссылки.

POST /api/billing/referral/link/create

Создает referral-ссылку.

POST /api/billing/referral/claim

Активирует referral-код.

POST /api/billing/subscription/update-renewal

Обновляет настройку автоматического продления.

POST /api/billing/crypto-checkout/refresh

Обновляет статус crypto checkout.

Для project add-on поздняя оплата после отмены checkout или переноса project не активирует повторно подписку и бесплатный доступ. Платёж направляется на reconciliation или refund.

Случай жизненного циклаОбязательное поведение
late-payment-after-cancel-or-project-transferСохранить no-reactivation; применить reconciliation-or-refund.

POST /api/billing/crypto-checkout/cancel

Отменяет crypto checkout.

Отмена окончательна для активации project add-on. Если оплата обнаружена позже, в том числе после переноса project, подписка и бесплатный доступ не активируются повторно, а платёж направляется на reconciliation или refund.

Случай жизненного циклаОбязательное поведение
late-payment-after-cancel-or-project-transferСохранить no-reactivation; применить reconciliation-or-refund.