Checkout / оплата Monobank
Метадані
Section titled “Метадані”| Поле | Значення |
|---|---|
| Статус | 🟢 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) |
Призначення
Section titled “Призначення”Єдиний платіжний рейл монетизації Abitly.org поверх Monobank Acquiring API. Через нього проходять три типи покупок (SKU): разовий доступ до PDF-матеріалу/бандла, пакет токенів AI-тьютора, а також підписка на тариф (Free/Pro/Max). Кожен SKU створює інвойс у Monobank, редіректить абітурієнта на хостовану сторінку оплати й активує покупку через підписаний вебхук.
User flow
Section titled “User flow”Окремої сторінки «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):
- Гість тисне «Купити» → модалка з Google-логіном; незавершена покупка відновлюється після входу (
pendingPurchase). - Залогінений: фронт
POSTна create-ендпоінт SKU → api-v2 створює запис ордера й кличе MonobankPOST /api/merchant/invoice/create(MONOBANK_TOKEN, сума в копійках,ccy: 980,basketOrder,validity: 3600). - Monobank повертає
{ invoiceId, pageUrl }→ api-v2 віддаєpaymentUrl→ фронт редіректить наpageUrl(хостована сторінка Monobank). - Абітурієнт оплачує → Monobank шле вебхук на
*/webhook/monobankз заголовкомx-sign; api-v2 верифікує SHA256-підпис проти Monobank pubkey і активує покупку. - Повернення на success-сторінку SKU → пулінг статус-ендпоінта (
paid/processing/failed/timeout/not-found).
Платіжний sequence-флоу вже намальований — див. data-flows: оплата Monobank і деталі провайдера integrations/payments. Останній successful-платіж також тригерить last-touch атрибуцію в lake-house (data-flows: аналітика).
Дані та API
Section titled “Дані та API”Усі три SKU діляться спільним MonobankService (src/api/billing/monobank.service.ts): createInvoice (POST /api/merchant/invoice/create → pageUrl), getInvoiceStatus, verifyWebhookSignature (кеш pubkey 1 год, авто-refresh при ротації ключа).
| SKU | Create / status (api-v2) | Webhook | Entity / стан |
|---|---|---|---|
| Premium (one-off PDF) | POST /premium/create-payment · GET /premium/order-status?orderId · GET /premium/download?orderId&token | POST /premium/webhook/monobank (x-sign) | premiumOrder |
| Tokens (AI-тьютор) | GET /tutor/tokens/packages (public) · POST /tutor/tokens/purchase · GET /tutor/tokens/order-status?orderId | POST /tutor/tokens/webhook/monobank | token-order; кредитує гаманець (walletCreditedAt) |
| Subscription (тариф) | GET /subscriptions/plans (public) · POST /subscriptions/subscribe · change-plan · cancel | POST /subscriptions/webhook/monobank | subscription + subscriptionInvoice |
| Джерело | Ендпоінт / entity | Призначення |
|---|---|---|
| api-v2 | premium / tutor-billing / subscriptions модулі (усі змонтовані в app.module) | створення інвойсів, обробка вебхуків, активація покупок |
| api-v2 | MONOBANK_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 “Зв’язки з іншими фічами”- Навчальні матеріали — поверхня входу для Premium-SKU (
/premium/*); detailed buy-flow задокументований там. - AI-тьютор / плани й білінг — поверхня токенів і опис тарифів Free/Pro/Max (billing змержено в api-v2, але ще нічого не gate-ить).
- Промоакції — знижкові механіки на платіжній поверхні.
- Реферальна програма — 🚧
create-paymentприймаєreferralCode; success-вебхукpremiumнараховує бонус рефереру. - Автентифікація — усі SKU за
JwtAuthGuard; гостьова покупка відновлюється після Google-логіну.
| Репо | Шлях | Примітка |
|---|---|---|
abitly-api-v2 | src/api/billing/monobank.service.ts | спільний клієнт Monobank: invoice, status, верифікація підпису |
abitly-api-v2 | src/api/premium/** | Premium one-off: controller, webhook-controller, service; entity premiumOrder |
abitly-api-v2 | src/api/tutor-billing/** | Tokens: controller /tutor/tokens, webhook, token-packages.config.ts, wallet-reconciler cron |
abitly-api-v2 | src/api/subscriptions/** | Subscription: controller, subscription-billing.service.ts, webhook |
abitly-frontend-v2 | src/api/materials/materials.api.ts | фронт-виклики /premium/create-payment·order-status·download |
abitly-frontend-v2 | src/api/tokens/tokens.api.ts | фронт-виклики /tutor/tokens/packages·purchase·order-status |
abitly-frontend-v2 | materials/success, tutor/purchase/success (роути) | success-сторінки з пулінгом статусу (robots: noindex) |
Обмеження та блокери
Section titled “Обмеження та блокери”- Subscription SKU — без фронтенд-поверхні: контролер
subscriptionsзмонтований іsubscribeреально створює Monobank-інвойс (createInitialInvoice→paymentUrl), але у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.
Історія змін
Section titled “Історія змін”| Дата | Подія | Джерело |
|---|---|---|
TODO: | реліз платіжної поверхні (Premium → Tokens → Subscription backend) | abitly-api-v2 |
| 2026-06-14 | створено картку; 3 SKU звірено з кодом main обох репо + live success-роути | PR Wave 1 |