Платный checkout через Platform API и confirmation URL.
Платежи
Поток
1. Пользователь выбирает платную plan_price
2. createPayment(plan_price_id, return_url)
3. API создаёт платёж у провайдера + pending в Platform
4. Приложение открывает confirmation_url
5. Webhook → succeeded → права / период подписки
(если webhook не дошёл: worker ~1 мин, или getMyEntitlements / syncPayment)
6. Приложение обновляет entitlements (+ кэш)
Если webhook не дошёл, а в ЮKassa уже succeeded, Platform сам закрывает pending:
- worker каждую минуту (
POST /v1/internal/payments/reconcile) getMyEntitlements()после return- SDK
syncPayment(payment_id)/POST /v1/payments/{id}/sync
Тот же путь, что webhook: проверка в ЮKassa → finalize_yookassa_payment. Ручная кнопка в админке Платежи → Сверить с ЮKassa остаётся для отладки.
Правила
- Нужны JWT + public key
- Секреты провайдера не в клиенте
- Free не оплачивается
- После return —
getMyEntitlements()(сам сверит pending). ОпциональноsyncPayment(payment_id)
Ошибка free: free_plan_offline.
discount_percent — только UI; в оплату идёт amount.
Webhook (прод)
URL в кабинете ЮKassa: YOUR_API_URL/v1/webhooks/yookassa (хост API, не маркетинг).
Finalize читает токен из platform_config.yookassa_webhook_token (≥24 символов на проде). Env YOOKASSA_WEBHOOK_TOKEN — запасной, если в БД токен ещё слабый. URL webhook в кабинете ЮKassa должен отвечать 2xx только после того, как платёж найден у нас; иначе ЮKassa повторит запрос.
Сверка (admin)
POST /v1/payments/{paymentId}/sync
POST /v1/payments/sync-pending
Отмена в ЮKassa → статус canceled. Если тариф уже выдан вручную (admin/license), сверка только закрывает pending без повторной выдачи.