Vibe coding fundamentalnie zmienił sposób tworzenia cyfrowych produktów. Dziś, aby dodać na stronę obsługę płatności przez Apple Pay, Google Pay lub karty bankowe, nie trzeba już zatrudniać backend developera ani samodzielnie zgłębiać kryptograficznych protokołów. Wystarczy precyzyjnie sformułować logikę biznesową dla swojego agenta AI (Codex, Antigravity, Cursor lub Claude Code) i dostarczyć mu odpowiedni kontekst z dokumentacji technicznej.
W tym poradniku omówiono pełny cykl życia integracji e-commerce z Monobank Acquiring: od przejścia compliance banku i konfiguracji konta przedsiębiorcy, przez generowanie bezpiecznej bramki płatniczej z weryfikacją podpisów ECDSA w webhookach, obsługę race condition w interfejsie, aż po zestaw obowiązkowych testów automatycznych.
Wersja wideo poradnika: Jeśli preferujesz format wizualny, obejrzyj szczegółowe praktyczne wideo na YouTube →, gdzie cały proces został pokazany na żywo, od pierwszego promptu do rzeczywistego pobrania środków.
Pakiet skillsów agentowych: Aby zapewnić maksymalną precyzję generowania kodu, pobierz oficjalny pakiet wiedzy dla swojego asystenta AI:
Pobierz pełne archiwum monobank-acquiring.zip (38 KB) →
1. Architektura Hosted Checkout i cykl życia płatności
Monobank Acquiring działa w modelu Hosted Checkout (płatność na zabezpieczonej stronie banku). Oznacza to, że Twoja strona nie wymaga skomplikowanej i kosztownej certyfikacji bezpieczeństwa PCI DSS, ponieważ dane kart użytkowników są wprowadzane bezpośrednio na zabezpieczonym domenie banku.
Oficjalna dokumentacja Monobank dla narzędzi AI jest dostępna pod adresem monobank.ua/api-docs/acquiring/dev/ai-tools/docs--ai-prompts →. Zapisz ten link jako kanoniczne źródło wymagań technicznych banku.
1.1. Podstawowy flow płatności
- 1. Utworzenie rachunku (
invoice/create): Klient na Twojej stronie wybiera produkt lub plan taryfowy. Handler serwera wysyła żądaniePOSTdo API Monobank z kwotą, opisem płatności i adresem zwrotnym. Bank zwraca unikalnyinvoiceIdoraz linkpageUrl. - 2. Przekierowanie do strony płatności: Klient zostaje przekierowany na
pageUrl, gdzie opłaca zamówienie za pomocą Apple Pay, Google Pay, aplikacji Monobank lub wpisując dane karty bankowej. - 3. Otrzymanie Webhooka: Po zakończeniu płatności Monobank automatycznie wysyła żądanie
POSTna wcześniej skonfigurowanywebHookUrlze statusem transakcji i kryptograficznym podpisem cyfrowym. - 4. Utrwalenie statusu (Terminal States): Twój serwer musi reagować na dwa końcowe statusy:
success(pomyślna płatność – udostępniamy dostęp lub wysyłamy zamówienie) orazfailure(błąd lub odrzucenie płatności przez bank).
Status expired (wygasł czas ważności linku) nie generuje webhooka. Jeśli klient zamknął stronę płatności i nie zapłacił, stan zamówienia należy sprawdzać poprzez rezerwowe odpytywanie API (polling).
2. Wymagania prawne i checklista compliance strony dla jednoosobowej działalności gospodarczej (JDG/FOP)
Nawet jeśli kod płatności jest napisany bezbłędnie, dział monitoringu finansowego i bezpieczeństwa Monobank nie aktywuje produkcyjnego przyjmowania płatności, jeśli strona nie spełnia wymogów ukraińskiego prawa oraz zasad systemów płatniczych Visa/Mastercard.
2.1. Warunki bankowe
- Otwarte konto JDG (FOP) lub spółki w Monobank: Acquiring jest podłączany wyłącznie do kont firmowych. Przyjmowanie płatności komercyjnych na osobistą czarną lub białą kartę osoby fizycznej jest zabronione przez prawo.
- Odpowiednie kody PKD (KVED): W danych rejestracyjnych JDG muszą być wskazane kody działalności dla handlu internetowego lub usług (np.
47.91– Handel detaliczny przez Internet,62.01/62.02– Programowanie komputerowe i konsultacje,85.59– Inne rodzaje edukacji).
2.2. Obowiązkowa checklista stron przed złożeniem wniosku o moderację
Zanim złożysz wniosek o aktywację terminala internetowego, upewnij się, że na Twojej stronie znajdują się następujące sekcje (zazwyczaj umieszczane w stopce):
- Publiczna oferta (Umowa publiczna): Opis przedmiotu umowy, moment zawarcia kontraktu oraz praw i obowiązków stron.
- Polityka prywatności (Privacy Policy): Jasne sformułowanie, jakie dane klientów są zbierane i jak są chronione zgodnie z ustawą Ukrainy „O ochronie danych osobowych”.
- Warunki zwrotu pieniędzy i dostawy: Procedura zwrotu towaru lub środków w ciągu 14 dni zgodnie z ustawą Ukrainy „O ochronie praw konsumentów”, a dla produktów cyfrowych/subskrypcji – zasady rezygnacji z usługi.
- Pełne dane firmy w stopce strony: Nazwa JDG lub Spółki z o.o., NIP / KRS (EDRPOU), adres siedziby, kontaktowy numer telefonu oraz służbowy e-mail supportu.
- Przejrzyste ceny i opisy: Każdy przycisk płatności musi mieć stałą kwotę w hrywnach (UAH) oraz czytelny opis tego, za co dokładnie płaci klient.
Jeśli na stronie brakuje oferty, danych JDG lub zamiast cen widnieją placeholdery typu „do ustalenia”, dział bezpieczeństwa Monobank odrzuci rejestrację terminala na etapie weryfikacji.
3. Tworzenie terminala webowego w panelu Monobank Business
Aby integrować się z API płatności, potrzebujesz osobistego klucza dostępu — X-Token. Jest on generowany bezpłatnie wewnątrz panelu klienta biznesowego.
3.1. Algorytm krok po kroku otwierania kasy
- Autoryzacja: Przejdź na web.monobank.ua → i zaloguj się za pomocą kodu QR przez aplikację Monobank na smartfonie.
- Przejście do kasy: W lewym menu nawigacyjnym wybierz sekcję «Kasa».
- Dodanie narzędzia: Kliknij przycisk «+ Dodaj narzędzie» i wybierz opcję «Płatności na stronie (własna implementacja)».
- Rejestracja terminala: Wpisz nazwę projektu (np.
Moja stronalubGłówny terminal) i potwierdź operację przyciskiem «Podłącz». - Generowanie tokena API: Otwórz utworzony terminal, przejdź do zakładki «Integracje / Klucze API», kliknij «Utwórz token» i skopiuj wygenerowany klucz.
📍 Nawigacja w panelu:
web.monobank.ua→Kasa→+ Dodaj narzędzie→Płatności na stronie (własna implementacja)
Tworzenie narzędzia płatniczego w panelu Monobank Kasa📍 Pozyskanie klucza API:
Kasa→Twój terminal→Integracja→Utwórz X-Token
Okno modalne tworzenia i kopiowania tokenu dostępu X-Token3.2. Żelazne zasady bezpieczeństwa tokenów
- Żadnych hardkodów w kodzie klienckim:
X-Tokendaje bezpośredni dostęp do zarządzania Twoimi finansami i zwrotami. Jego przechowywanie w jawnym JavaScript/HTML lub publikacja w publicznych repozytoriach GitHub jest surowo zabroniona. - Wykorzystanie zmiennych środowiskowych: Przechowuj token wyłącznie w pliku
.envna serwerze pod nazwąMONOBANK_TOKENlub w sekcji Secrets Twojej platformy hostingowej (Vercel, Render, Railway, Replit, Lovable). - Token testowy do developmentu: Do początkowych eksperymentów bank udostępnia osobny token testowy na stronie api.monobank.ua →, który pozwala symulować transakcje bez pobierania realnych środków.
4. Oficjalne prompty AI Monobank dla vibe coderów
Zespół Monobank przygotował zestaw oficjalnych promptów systemowych dla agentów AI. Ich główną zaletą jest dokładna zgodność z aktualnymi endpointami banku.
Strona oficjalnej dokumentacji Monobank dla narzędzi AIGłówna pułapka dla początkujących – kwota w kopiejkach: API Monobank przyjmuje wszystkie kwoty wyłącznie w minimalnych jednostkach waluty (kopiejkach). $100\text{ UAH} = 10,000\text{ kopiejek}$. Jeśli przekażesz amount: 100, klient zapłaci tylko 1 hrywnę.
4.1. Podstawowy prompt do tworzenia płatności
Skopiuj ten prompt i wyślij go na czat swojego asystenta AI:
4.2. Prompt do konfiguracji handlerów Webhook
Bez webhooka serwer nie dowie się o fakcie pomyślnej płatności, jeśli klient zamknie przeglądarkę tuż po pobraniu środków:
5. Pakiet skillsów monobank-acquiring: wzmacnianie agenta
Jeśli ograniczysz się tylko do krótkiego promptu, asystent AI napisze podstawowy kod (około 6.8/10): przycisk zadziała, ale kod nie będzie zawierał weryfikacji podpisów kryptograficznych, ochrony przed podmianą ceny ani obsługi rzadkich błędów sieciowych.
Aby uzyskać poziom produkcyjny (9.8–10 punktów), do katalogu głównego projektu dodaje się wyspecjalizowany pakiet skillsów monobank-acquiring.
Audyt integracji płatniczej: porównanie bezpieczeństwa przed i po użyciu skillu5.1. Anatomia i struktura pakietu skillsów
| Plik skillu | Co zawiera i za jakie zadania odpowiada |
|---|---|
SKILL.md | Centralny manifest: podstawowy flow, autoryzacja X-Token, typy danych oraz obsługa błędów 400, 403, 429, 500. |
quickstart.md | Szybki start: krok po kroku tutorial tworzenia faktury i fallback-pollingu z gotowymi komendami curl. |
invoice.md | Cykl życia rachunków: endpointy tworzenia faktury, sprawdzania statusu, anulowania i unieważniania linków. |
webhook.md | Zabezpieczenia kryptograficzne: matematycznie dokładna weryfikacja podpisu ECDSA SHA-256 z nagłówka x-sign. |
payment.md | Płatności bezpośrednie: pobieranie środków zapisanym tokenem karty, transakcje synchroniczne oraz weryfikacja 3DS. |
wallet.md | Tokenizacja kart (Wallet): bezpieczne przechowywanie środka płatniczego klienta w skarbcu banku do płatności jednym kliknięciem. |
fiscal.md | Paragony i pRRО: opis struktury koszyka basketOrder, kalkulacja podatków, rabatów oraz eksport paragonów do PDF. |
statement.md | Wyciągi i analityka: pobieranie rejestru udanych operacji za wybrany okres z kalkulacją prowizji bankowych. |
merchant.md | Dane merchant'a: pobieranie klucza publicznego banku, zarządzanie submerchantami i kasjerami. |
examples/ | Gotowe serwery: działające przykłady serwerów w 6 popularnych językach (Node.js, Python, Go, PHP, C#, Java). |
6. Realizacja praktyczna: dynamiczny flow płatności
Każdy projekt ma swoją strukturę: ktoś sprzedaje cyfrowe konsultacje ze stałymi stawkami, ktoś inny prowadzi sklep internetowy z dynamicznym koszykiem, a jeszcze inny ma prosty landing page z jednym przyciskiem dotacji lub subskrypcji.
Głównym błędem początkujących jest sztywne „zaszywanie” kwoty (np. 1000 UAH) bezpośrednio w kodzie klienckim przycisku lub w body żądania POST z przeglądarki. To podejście tworzy krytyczną lukę bezpieczeństwa.
6.1. Zasada bezpieczeństwa: dynamiczna cena zamiast hardcode'u
-
Nigdy nie ufaj kwocie z przeglądarki: Jeśli JavaScript po stronie klienta wysyła na serwer
{ price: 1000 }, atakujący przez Inspektor Kodu (DevTools) lub Postman może podmienić tę wartość na{ price: 1 }i kupić dostęp za 1 hrywnę. -
Serwer jest jedynym źródłem prawdy (Single Source of Truth): Frontend przekazuje na backend jedynie identyfikator produktu (
productId), wybrany plan (planId: "pro") lub tablicę identyfikatorów koszyka (items: [{ id: "book_1", qty: 2 }]). -
Automatyczna konwersja na kopiejki: Serwer pobiera aktualną cenę z pliku konfiguracyjnego lub bazy danych i sam mnoży ją przez 100:
$$\text{amount} = \text{Math.round}(\text{realPrice} \times 100)$$ Jeśli zmienisz cenę w bazie lub ogłosisz rabat, rachunek Monobank zostanie wygenerowany z nową poprawną kwotą bez ingerencji w bramkę płatniczą.
6.2. Uniwersalny prompt AI do adaptacji pod dowolny projekt
Skopiuj ten prompt i wyślij go na czat swojego agenta AI (Codex, Antigravity, Cursor lub Claude Code). Agent sam przeskanuje pliki Twojej strony, znajdzie istniejące przyciski i ceny oraz zbuduje solidną integrację:
Praca agenta AI w IDE z analizą struktury i tworzeniem dynamicznego endpointu6.3. Szablon architektury backendu do tworzenia faktury
Oto sprawdzone realizacje serwerowe dla dwóch najpopularniejszych stacków webowych:
typescript// app/api/checkout/create-invoice/route.ts import { NextResponse } from "next/server"; const PRODUCTS_CATALOG: Record<string, { title: string; priceUah: number }> = { plan_starter: { title: "Тариф Starter", priceUah: 490 }, plan_pro: { title: "Тариф Pro", priceUah: 990 }, plan_vip: { title: "Тариф VIP", priceUah: 2490 }, }; export async function POST(req: Request) { try { const { productId } = await req.json(); // 1. Валідація: ціна формується виключно на бекенді const product = PRODUCTS_CATALOG[productId]; if (!product) { return NextResponse.json({ error: "Обраний товар або тариф не знайдено" }, { status: 400 }); } const amountInKopecks = Math.round(product.priceUah * 100); const orderReference = `order_${productId}_${Date.now()}`; const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://mysite.com"; // 2. Запит до Monobank API const response = await fetch("https://api.monobank.ua/api/merchant/invoice/create", { method: "POST", headers: { "X-Token": process.env.MONOBANK_TOKEN!, "Content-Type": "application/json", }, body: JSON.stringify({ amount: amountInKopecks, ccy: 980, // Гривня (ISO 4217) merchantPaymInfo: { reference: orderReference, destination: `Оплата: ${product.title}`, comment: `Замовлення ${orderReference}`, }, redirectUrl: `${siteUrl}/payment-result?ref=${orderReference}`, webHookUrl: `${siteUrl}/api/payment/webhook`, validity: 3600, // Рахунок діє 1 годину }), }); const data = await response.json(); if (!response.ok) { return NextResponse.json({ error: data.errText || "Помилка створення рахунку в банку" }, { status: response.status }); } return NextResponse.json({ checkoutUrl: data.pageUrl, invoiceId: data.invoiceId }); } catch (error) { return NextResponse.json({ error: "Внутрішня помилка ініціалізації платежу" }, { status: 500 }); } }
7. Bezpieczna obróbka webhooków i podpis kryptograficzny ECDSA
Najważniejszą częścią każdej integracji finansowej jest weryfikacja powiadomień o płatności. Atakujący może wysłać spreparowane żądanie HTTP na Twój adres /api/payment/webhook z fałszywą wiadomością o sukcesie.
Aby temu zapobiec, Monobank podpisuje każdy webhook za pomocą algorytmu asymetrycznego ECDSA (krzywa secp256r1 / SHA-256) i przekazuje sygnaturę w nagłówku HTTP x-sign.
7.1. Dlaczego JSON.stringify łamie weryfikację podpisu
Krytyczna pułapka rawBody: Do weryfikacji podpisu ECDSA potrzebny jest surowo oryginalny strumień bajtów, który wysłał serwer Monobank. Jeśli spróbujesz sparsować JSON i ponownie wywołać JSON.stringify(req.body), kolejność kluczy, spacje lub znaki nowej linii mogą się zmienić. To doprowadzi do innego hasha SHA-256, a weryfikacja podpisu gwarantowanie zwróci błąd!
7.2. Implementacja weryfikacji webhooka
Poniżej znajduje się poprawna implementacja pobierania surowego body i weryfikacji dla Next.js App Router oraz Express:
typescript// app/api/payment/webhook/route.ts import { NextResponse } from "next/server"; import crypto from "crypto"; let cachedPubKey: string | null = null; async function getMonobankPubKey(token: string): Promise<string> { if (cachedPubKey) return cachedPubKey; const res = await fetch("https://api.monobank.ua/api/merchant/pubkey", { headers: { "X-Token": token }, next: { revalidate: 86400 }, // Кешуємо публічний ключ на 24 години }); const data = await res.json(); cachedPubKey = `-----BEGIN PUBLIC KEY-----\n${data.key}\n-----END PUBLIC KEY-----`; return cachedPubKey; } export async function POST(req: Request) { const signature = req.headers.get("x-sign"); if (!signature) { return new NextResponse("Missing x-sign header", { status: 400 }); } // 1. Отримуємо сире незмінене тіло запиту у вигляді тексту const rawBody = await req.text(); try { const pubKey = await getMonobankPubKey(process.env.MONOBANK_TOKEN!); // 2. Верифікуємо підпис ECDSA SHA-256 const verifier = crypto.createVerify("SHA256"); verifier.update(rawBody); const isValid = verifier.verify(pubKey, Buffer.from(signature, "base64")); if (!isValid) { console.error("Вебхук відхилено: недійсний підпис x-sign"); return new NextResponse("Invalid signature", { status: 400 }); } // 3. Парсимо дані тільки після успішної перевірки криптографії const payload = JSON.parse(rawBody); const { invoiceId, status, amount, reference } = payload; if (status === "success") { // Тут активуємо замовлення в базі даних з перевіркою на дублікати (ідемпотентність) console.log(`Замовлення ${reference} (${invoiceId}) оплачено на суму ${amount / 100} грн`); } return new NextResponse("OK", { status: 200 }); } catch (error) { console.error("Помилка обробки вебхука:", error); return new NextResponse("Internal verification error", { status: 500 }); } }
8. Testowanie lokalne webhooków (Localhost & Cloudflare Tunnels)
Częsty problem vibe coderów: przy uruchomieniu serwera na http://localhost:3000 bank nie może dostarczyć webhooka, ponieważ lokalna maszyna nie posiada publicznego adresu IP w internecie.
Monobank wysyła webhooki wyłącznie na publiczne adresy z ważnym protokołem HTTPS. Aby przetestować pełny cykl na swoim komputerze, przepchnij bezpieczny tunel.
8.1. Szybkie uruchomienie tunelu (bez rejestracji i za darmo)
Skorzystaj z Cloudflare Tunnel (cloudflared) lub untun:
bash# Миттєвий HTTPS-тунель на 3000 порт без встановлення утиліт npx untun@latest tunnel --port 3000
Po uruchomieniu otrzymasz tymczasowy publiczny adres HTTPS, np.:
https://your-tunnel-name.trycloudflare.com
8.2. Konfiguracja webhooka do testów lokalnych
W kodzie tworzenia faktury podczas developmentu wskaż otrzymany adres:
Teraz przy płatności testowej bank wyśle prawdziwy webhook prosto na Twój lokalny serwer w terminalu, a Ty będziesz mógł upewnić się, że podpis x-sign pomyślnie przechodzi weryfikację.
9. UX strony powrotnej i rozwiązywanie race condition
Gdy klient opłaca rachunek przez aplikację Monobank lub Apple Pay, bank natychmiast przekierowuje go na adres redirectUrl (/payment-result?ref=...).
Jednakże webhook sieciowy z serwera banku do Twojego serwera może opóźnić się o 1–2 sekundy ze względu na trasowanie sieciowe. Jeśli strona wyniku natychmiast sprawdzi status w bazie danych, ryzykuje wyświetlenie komunikatu: „Zamówienie nieopłacone”, co wywoła panikę u klienta (środki zostały pobrane z karty, a strona informuje o braku płatności).
9.1. Wzorzec inżynierski rozwiązania race condition
- Stan początkowy ładowania: Strona otwiera się z neutralnym statusem:
„Potwierdzamy płatność w banku...”oraz animowanym wskaźnikiem. - Krótki polling (Short Polling): Frontend wykonuje do 5 szybkich zapytań do własnego API co 1.5 sekundy (
/api/orders/check-status?ref=...), czekając, aż webhook zmieni status zamówienia w bazie nasuccess. - Fallback: Jeśli w ciągu 8 sekund webhook nie dotarł, klient widzi komunikat: „Płatność przyjęta do przetworzenia. Gdy tylko bank potwierdzi transakcję, dostęp zostanie otwarty automatycznie”.
9.2. Gotowy komponent React strony wyniku
10. Zaawansowane możliwości: wbudowane pRRО, holdy i Wallet
Monobank Acquiring oferuje pełen zakres narzędzi dla bardziej złożonych modeli biznesowych:
Końcowa strona płatności Monobank Hosted Checkout z Apple Pay i kartami10.1. Programowe RRO: darmowy wbudowany Checkbox w Kasie Monobank
Dla większości ukraińskich JDG grup 2. i 3. fiskalizacja sprzedaży online jest wymogiem prawnym.
Główną przewagą Monobank dla przedsiębiorców jest bezpłatna wbudowana integracja z serwisem pRRО Checkbox:
- Aktywacja jednym kliknięciem: W panelu
web.monobank.uaprzejdź do ustawień utworzonego terminala i aktywuj przełącznik „Fiskalizacja przez Checkbox”. Monobank sam, bezpłatnie, tworzy kasę i podpisuje paragony Twoim KEP (Elektronicznym Podpisem Kwalifikowanym). - Automatyczna fiskalizacja: Jeśli masz standardowy katalog towarów ze stałą stawką, nawet nie musisz zmieniać kodu tworzenia płatności – paragon jest automatycznie formułowany na podstawie pola
destinationw opisie płatności. - Rozszerzona fiskalizacja przez API: Jeśli sprzedajesz towary z różnymi stawkami VAT lub pozycje akcyzowe z kodami UKT ZEД, przesyłaj tablicę
basketOrderwewnątrz obiektumerchantPaymInfo:
10.2. Dwuetapowa płatność (Hold)
Jeśli sprzedajesz towary fizyczne, które mogą być niedostępne w magazynie, użyj trybu holdowania:
- Blokada: Przekaż
paymentType: "hold"podczas tworzenia faktury. Środki są zamrażane na karcie kupującego na okres do 9 dni. - Pobranie (Finalize): Po sprawdzeniu dostępności towaru wywołaj
/api/merchant/invoice/finalize. Możesz pobrać zarówno pełną kwotę, jak i mniejszą (np. jeśli brakowało jednej pozycji). - Anulowanie: Jeśli towaru nie ma, wywołaj
/api/merchant/invoice/cancel– płatność jest anulowana bez żadnych prowizji bankowych dla kupującego.
10.3. Zapisywanie kart i subskrypcje (Wallet)
Jeśli uruchamiasz serwis SaaS z regularną miesięczną subskrypcją, przekaż saveCardData: true podczas tworzenia pierwszej faktury. Po pomyślnej płatności w webhooku zwrócony zostanie walletId. Używaj tego tokenu do następnych automatycznych pobrań bez ponownego wpisywania danych karty przez klienta.
11. Macierz bezpieczeństwa i testy automatyczne (Vitest / Jest)
Płatności to strefa maksymalnej odpowiedzialności finansowej. Błąd w zwykłym przycisku powoduje irytację, ale błąd w bramce płatniczej prowadzi do bezpośrednich strat materialnych lub blokady kasy przez bank.
Przed przejściem w tryb produkcyjny uruchom macierz testów bezpieczeństwa:
| Test bezpieczeństwa | Co dokładnie jest sprawdzane | Oczekiwane zachowanie systemu |
|---|---|---|
| 1. Ochrona przed zmianą ceny (Price Tampering) | Klient wysyła productId: "vip", ale próbuje podmienić w żądaniu amount: 100 (1 UAH) | Serwer ignoruje pole amount od klienta, pobiera realną cenę z konfiguracji (2490 UAH = 249 000 kopiejek). Jeśli productId jest sfałszowany – zwraca HTTP 400. |
| 2. Blokada bez podpisu | Na endpoint /api/payment/webhook nadchodzi żądanie POST bez nagłówka x-sign | Żądanie jest natychmiast blokowane odpowiedzią HTTP 400 Bad Request. Nie następuje żadna obróbka zamówienia. |
| 3. Blokada fałszywych podpisów | Atakujący wysłał fake'owy podpis w x-sign ze statusem status: "success" | Weryfikacja crypto.verify(SHA256, ...) zwraca false. Serwer zwraca HTTP 400/401, dostęp lub towar nie są wydawane. |
| 4. Idempotentność webhooka (Duplicate Delivery) | Monobank wysłał ten sam webhook success dwukrotnie lub trzykrotnie z powodu opóźnienia sieciowego | Dostęp lub towar są aktywowane tylko raz. Powtórzony webhook nie powoduje duplikacji wydania, zwracając bankowi HTTP 200 OK. |
| 5. Odporność na race condition | Webhook od banku dotarł szybciej niż zakończyło się pierwotne żądanie HTTP tworzenia faktury w bazie | Handler webhooka jest odporny na brak rekordu w DB (używa UPSERT lub tworzy zamówienie „w locie”). |
| 6. Przestrzeganie rate-limitów (Rate Limit Buffer) | Przy awarii webhooka uruchamia się polling statusu /api/merchant/invoice/status | Zapytania są wykonywane z pauzą nie mniejszą niż 15 sekund, co chroni terminal przed blokadą HTTP 429 Too Many Requests. |
11.1. Gotowy zestaw testów automatycznych dla Twojego projektu
Poproś swojego agenta AI o dodanie następującego zestawu testów do projektu (monobank-acquiring.test.ts):
12. Finalna checklista inżynierska przed startem
Sprawdź swój moduł płatniczy według tych 10 punktów przed przełączeniem na płatności produkcyjne:
- Compliance strony: W stopce dodano linki do Publicznej Oferty, Polityki Prywatności, Warunków Zwrotu oraz pełne dane JDG z NIP.
- Kwoty w kopiejkach: Wszystkie wartości
amountpomnożone przez 100 ($1\text{ UAH} = 100\text{ kop}$) przezMath.round. - Bezpieczeństwo klucza: Token wyniesiony do
.envpod nazwąMONOBANK_TOKENi dodany do.gitignore. - Ceny z backendu (SSOT): Klient przekazuje tylko identyfikator produktu, kwota jest pobierana wyłącznie z bazy lub konfiguracji.
- Obsługa rawBody: Webhook weryfikuje oryginalny bufor tekstowy lub binarny (
req.text()lubreq.rawBody), unikając podwójnego parsowania przezJSON.stringify. - Zabezpieczenie kryptograficzne: Webhook weryfikuje podpis
x-signza pomocą klucza publicznego banku algorytmemSHA256ECDSA. - Publiczny URL dla webhooka: Serwer jest dostępny z zewnątrz przez ważny certyfikat SSL HTTPS (do testów lokalnych pasuje Cloudflare Tunnel lub ngrok).
- Idempotentność: Ponowne nadejście tego samego webhooka nie powoduje podwójnego wydania towaru lub subskrypcji.
- UX strony wyniku: Na
/payment-resultskonfigurowano loader oczekiwania i krótki polling statusu, aby chronić użytkownika przed race condition. - Realna płatność 1–5 UAH: Przeprowadzono udaną transakcję testową prawdziwą kartą, sprawdzono pobranie środków i wyświetlenie w panelu bankowym.