Перейти до вмісту

Checkout / оплата Monobank

ПолеЗначення
Статус🟢 prod (Premium one-off + Tokens) · 🚧 Subscription SKU — backend готовий, фронтенд-поверхні немає
Поверхніweb (бот платежів ще не має)
Доступністьпотрібен акаунт (усі три SKU за JwtAuthGuard); каталоги/пакети — публічні
ВласникTODO:
Останнє підтвердження2026-06-14 · код:main (abitly-api-v2: premium, tutor-billing, subscriptions, billing/monobank.service; abitly-frontend-v2: materials.api, tokens.api) + browse (/uk/materials, /uk/tutor, /uk/materials/success, /uk/tutor/purchase/success → 200)

Єдиний платіжний рейл монетизації Abitly.org поверх Monobank Acquiring API. Через нього проходять три типи покупок (SKU): разовий доступ до PDF-матеріалу/бандла, пакет токенів AI-тьютора, а також підписка на тариф (Free/Pro/Max). Кожен SKU створює інвойс у Monobank, редіректить абітурієнта на хостовану сторінку оплати й активує покупку через підписаний вебхук.

Окремої сторінки «checkout» немає — це наскрізна поверхня, точки входу якої належать конкретним фічам:

  • Premium (разовий PDF): https://abitly.org/uk/materials/{slug} → «Купити» → /uk/materials/success (пулінг).
  • Tokens (AI-тьютор): https://abitly.org/uk/tutor → купівля пакета → /uk/tutor/purchase/success (пулінг).
  • Subscription (тариф): фронтенд-поверхні немає (нема роуту /pricing·/plans — обидва віддають catch-all головну; нема API-клієнта). Ендпоінти існують у api-v2, але не викликаються з вебу — див. «Обмеження».

Спільний кістяк усіх трьох SKU (на прикладі Premium):

  1. Гість тисне «Купити» → модалка з Google-логіном; незавершена покупка відновлюється після входу (pendingPurchase).
  2. Залогінений: фронт POST на create-ендпоінт SKU → api-v2 створює запис ордера й кличе Monobank POST /api/merchant/invoice/create (MONOBANK_TOKEN, сума в копійках, ccy: 980, basketOrder, validity: 3600).
  3. Monobank повертає { invoiceId, pageUrl } → api-v2 віддає paymentUrl → фронт редіректить на pageUrl (хостована сторінка Monobank).
  4. Абітурієнт оплачує → Monobank шле вебхук на */webhook/monobank з заголовком x-sign; api-v2 верифікує SHA256-підпис проти Monobank pubkey і активує покупку.
  5. Повернення на success-сторінку SKU → пулінг статус-ендпоінта (paid / processing / failed / timeout / not-found).

Платіжний sequence-флоу вже намальований — див. data-flows: оплата Monobank і деталі провайдера integrations/payments. Останній successful-платіж також тригерить last-touch атрибуцію в lake-house (data-flows: аналітика).

Усі три SKU діляться спільним MonobankService (src/api/billing/monobank.service.ts): createInvoice (POST /api/merchant/invoice/createpageUrl), getInvoiceStatus, verifyWebhookSignature (кеш pubkey 1 год, авто-refresh при ротації ключа).

SKUCreate / status (api-v2)WebhookEntity / стан
Premium (one-off PDF)POST /premium/create-payment · GET /premium/order-status?orderId · GET /premium/download?orderId&tokenPOST /premium/webhook/monobank (x-sign)premiumOrder
Tokens (AI-тьютор)GET /tutor/tokens/packages (public) · POST /tutor/tokens/purchase · GET /tutor/tokens/order-status?orderIdPOST /tutor/tokens/webhook/monobanktoken-order; кредитує гаманець (walletCreditedAt)
Subscription (тариф)GET /subscriptions/plans (public) · POST /subscriptions/subscribe · change-plan · cancelPOST /subscriptions/webhook/monobanksubscription + subscriptionInvoice
ДжерелоЕндпоінт / entityПризначення
api-v2premium / tutor-billing / subscriptions модулі (усі змонтовані в app.module)створення інвойсів, обробка вебхуків, активація покупок
api-v2MONOBANK_TOKEN + *_WEBHOOK_URL / *_REDIRECT_URL (per-SKU)креди й callback-и Monobank — назви в environments

Токен-пакети жорстко зашиті в tutor-billing/token-packages.config.ts: small_250 (250 ток., дефолт 49 грн), best_1000 (1000, 149 грн), power_2000 (2000, 249 грн); ціни перекриваються env TOKENS_{250,1000,2000}_PRICE_KOPEKS. Плани — seeded free/pro/max (price_coins у копійках), див. docs/modules/subscriptions/ у api-v2.

Зв’язки з іншими фічами

Section titled “Зв’язки з іншими фічами”
РепоШляхПримітка
abitly-api-v2src/api/billing/monobank.service.tsспільний клієнт Monobank: invoice, status, верифікація підпису
abitly-api-v2src/api/premium/**Premium one-off: controller, webhook-controller, service; entity premiumOrder
abitly-api-v2src/api/tutor-billing/**Tokens: controller /tutor/tokens, webhook, token-packages.config.ts, wallet-reconciler cron
abitly-api-v2src/api/subscriptions/**Subscription: controller, subscription-billing.service.ts, webhook
abitly-frontend-v2src/api/materials/materials.api.tsфронт-виклики /premium/create-payment·order-status·download
abitly-frontend-v2src/api/tokens/tokens.api.tsфронт-виклики /tutor/tokens/packages·purchase·order-status
abitly-frontend-v2materials/success, tutor/purchase/success (роути)success-сторінки з пулінгом статусу (robots: noindex)
  • Subscription SKU — без фронтенд-поверхні: контролер subscriptions змонтований і subscribe реально створює Monobank-інвойс (createInitialInvoicepaymentUrl), але у abitly-frontend-v2 немає ні роуту тарифів (/pricing·/plans віддають catch-all головну сторінку), ні API-клієнта subscriptions. SKU недоступний абітурієнту з вебу → 🚧.
  • Тарифи нічого не gate-ять: billing Free/Pro/Max змержено в api-v2, але feature-резолвер ще не обмежує жодну фічу — фактично платними є лише Premium-PDF і Tokens (див. plans-billing).
  • /premium/download позначений @ApiExcludeEndpoint, віддає файл лише за одноразовим token + orderId, Cache-Control: private, no-store.
  • Вебхуки SkipThrottle + @ApiExcludeController; підпис обов’язковий (SHA256 проти Monobank pubkey). Типові проблеми вебхука — integrations/payments.
  • MONOBANK_TOKEN — лише SSM SecureString; у доках/коді тільки назва змінної.
  • DTO create-token-purchase має застарілий example: 'best_1500' — реальні slug-и small_250·best_1000·power_2000 (token-packages.config.ts). TODO: синхронізувати приклад у Swagger.
ДатаПодіяДжерело
TODO:реліз платіжної поверхні (Premium → Tokens → Subscription backend)abitly-api-v2
2026-06-14створено картку; 3 SKU звірено з кодом main обох репо + live success-роутиPR Wave 1