Vibe Coding hat die Entwicklung digitaler Produkte grundlegend verändert. Heute ist es nicht mehr nötig, einen Backend-Entwickler einzustellen oder sich selbst in kryptografische Protokolle einzuarbeiten, um auf einer Website Zahlungen über Apple Pay, Google Pay oder Bankkarten zu akzeptieren. Es reicht aus, die Geschäftslogik klar gegenüber einem AI-Agenten (Codex, Antigravity, Cursor oder Claude Code) zu formulieren und ihm den richtigen Kontext der technischen Dokumentation bereitzustellen.
Dieses Handbuch behandelt den gesamten Lebenszyklus der Anbindung von Monobank Internet-Acquiring an Ihr Projekt: vom Durchlaufen des Bank-Compliance-Prozesses und der Einrichtung des Unternehmer-Kontos bis hin zur Generierung eines sicheren Zahlungs-Gateways mit kryptografischer Verifizierung der ECDSA-Signaturen in Webhooks, der Behandlung von Race Conditions im Interface sowie dem Setzen obligatorischer automatisierter Tests.
Video-Version des Handbuchs: Wenn Sie eine visuelle Darstellung bevorzugen, sehen Sie sich das detaillierte Praxis-Video auf YouTube → an, in dem der gesamte Prozess live am Bildschirm gezeigt wird – von der ersten Anfrage bis zur tatsächlichen Abbuchung.
Agent Skills-Paket: Für maximale Genauigkeit bei der Codegenerierung laden Sie das offizielle Wissenspaket für Ihren AI-Assistenten herunter:
Vollständiges Archiv monobank-acquiring.zip herunterladen (38 KB) →
1. Architektur des Hosted Checkout und Zahlungslebenszyklus
Monobank Acquiring funktioniert nach dem Schema Hosted Checkout (Zahlung auf einer geschützten Bankseite). Das bedeutet, dass Ihre Website keine komplexe und teure PCI DSS-Sicherheitszertifizierung benötigt, da der Benutzer die Kartendaten direkt auf der geschützten Domain der Bank eingibt.
Die offizielle Monobank-Dokumentation für AI-Tools ist unter monobank.ua/api-docs/acquiring/dev/ai-tools/docs--ai-prompts → verfügbar. Speichern Sie diesen Link als kanonische Erstquelle für die technischen Anforderungen der Bank.
1.1. Grundlegender Zahlungsfluss
- 1. Erstellung der Rechnung (
invoice/create): Der Kunde wählt auf Ihrer Website ein Produkt oder einen Tarif aus. Der Server-Handler sendet einePOST-Anfrage an die Monobank API mit Betrag, Verwendungszweck der Zahlung und Rückleitungsadresse. Die Bank gibt eine eindeutigeinvoiceIdund den LinkpageUrlzurück. - 2. Umleitung zur Zahlungsseite: Der Kunde wird auf die
pageUrlweitergeleitet, wo er die Bestellung über Apple Pay, Google Pay, die Monobank-App oder durch Eingabe der Bankkartendaten bezahlt. - 3. Empfang des Webhooks: Nach Abschluss der Zahlung sendet Monobank automatisch eine
POST-Anfrage an Ihre vorab konfiguriertewebHookUrlmit dem Transaktionsstatus und einer kryptografischen digitalen Signatur. - 4. Statusfixierung (Terminal States): Ihr Server muss auf zwei finale Status reagieren:
success(Zahlung erfolgreich, Zugriff gewähren oder Bestellung versenden) undfailure(Fehler oder Ablehnung der Zahlung durch die Bank).
Der Status expired (Ablaufdatum des Links überschritten) löst keinen Webhook aus. Wenn der Kunde die Zahlungsseite schließt und nicht zahlt, muss der Bestellstatus über ein Backup-Polling der API überprüft werden.
2. Rechtliche Voraussetzungen und Compliance-Checkliste für Einzelunternehmer (FOP)
Selbst wenn der Zahlungscode fehlerfrei geschrieben ist, aktiviert der Finanzüberwachungs- und Sicherheitsdienst von Monobank die Live-Zahlungsannahme nicht, wenn die Website nicht den Anforderungen der ukrainischen Gesetzgebung und den Regeln der Zahlungssysteme Visa/Mastercard entspricht.
2.1. Bankvoraussetzungen
- Offenes FOP- oder juristisches Personenkonto bei Monobank: Acquiring wird ausschließlich an Geschäftskonten angebunden. Die Annahme kommerzieller Zahlungen auf persönliche schwarze oder weiße Karten von Privatpersonen ist gesetzlich verboten.
- Passende KVED-Codes: In den Registrierungsdaten des FOP müssen Codes für Online-Handel oder Dienstleistungen angegeben sein (z. B.
47.91– Einzelhandel über das Internet,62.01/62.02– Computerprogrammierung und Beratung,85.59– Sonstige Bildungsformen).
2.2. Obligatorische Checkliste der Seiten vor Einreichung zur Moderation
Bevor Sie den Antrag auf Aktivierung des Internet-Terminals stellen, stellen Sie sicher, dass folgende Abschnitte auf Ihrer Website vorhanden sind (üblicherweise im Footer platziert):
- Öffentliches Angebot (Public Offer Agreement): Beschreibung des Vertragsgegenstands, Zeitpunkt des Vertragsschlusses, Rechte und Pflichten der Parteien.
- Datenschutzrichtlinie (Privacy Policy): Klare Formulierung darüber, welche Kundendaten gesammelt werden und wie sie gemäß dem Gesetz „Über den Schutz personenbezogener Daten“ geschützt werden.
- Rückgabe- und Lieferbedingungen: Verfahren für die Rückgabe von Waren oder Geld innerhalb von 14 Tagen gemäß dem Gesetz „Über den Schutz der Verbraucherrechte“, sowie für digitale Produkte/Abonnements – Regeln für den Widerruf der Dienstleistung.
- Vollständige Unternehmensangaben im Website-Footer: Name des FOP oder der GmbH, Steuer-ID / EDRPOU, juristische Adresse, Kontakttelefonnummer und funktionierende Support-E-Mail-Adresse.
- Transparente Preise und Beschreibungen: Jede Zahlungsschaltfläche muss einen festen Betrag in Hrywnja (UAH) und eine verständliche Beschreibung dessen enthalten, wofür der Kunde genau bezahlt.
Wenn auf der Website kein öffentliches Angebot, keine FOP-Angaben vorhanden sind oder statt Preisen Platzhalter wie „nach Vereinbarung“ stehen, lehnt der Sicherheitsdienst von Monobank die Registrierung des Terminals im Prüfprozess ab.
3. Erstellung des Web-Terminals im Monobank Business-Konto
Für die Interaktion mit der Zahlungs-API benötigen Sie einen persönlichen Zugriffsschlüssel – X-Token. Er wird kostenlos im persönlichen Unternehmerkonto generiert.
3.1. Schritt-für-Schritt-Algorithmus zur Kasseneröffnung
- Autorisierung: Gehen Sie zu web.monobank.ua → und melden Sie sich per QR-Code über die Monobank-App auf Ihrem Smartphone an.
- Wechsel zur Kasse: Wählen Sie im linken Navigationsmenü den Abschnitt „Kasse“.
- Tool hinzufügen: Klicken Sie auf die Schaltfläche „+ Tool hinzufügen“ und wählen Sie die Option „Zahlung auf der Website (Eigenentwicklung)“.
- Terminalregistrierung: Geben Sie den Projektnamen ein (z. B.
Meine WebsiteoderHauptterminal) und bestätigen Sie den Vorgang mit der Schaltfläche „Verbinden“. - Generierung des API-Tokens: Öffnen Sie das erstellte Terminal, wechseln Sie zum Reiter „Integrationen / API Keys“, klicken Sie auf „Token erstellen“ und kopieren Sie den generierten Schlüssel.
📍 Navigation im Konto:
web.monobank.ua→Kasse→+ Tool hinzufügen→Zahlung auf der Website (Eigenentwicklung)
Erstellung des Zahlungstools im Monobank Kasse-Konto📍 Empfang des API-Schlüssels:
Kasse→Ihr Terminal→Integration→X-Token erstellen
Modalfenster zur Erstellung und zum Kopieren des X-Token-Zugriffsschlüssels3.2. Eiserne Regeln für die Token-Sicherheit
- Kein Hardcoding im Client-Code:
X-Tokengewährt direkten Zugriff auf die Verwaltung Ihrer Finanzen und Rückerstattungen. Es ist strengstens verboten, ihn in offenem JavaScript/HTML zu speichern oder in öffentlichen GitHub-Repositorien zu veröffentlichen. - Verwendung von Umgebungsvariablen: Speichern Sie das Token ausschließlich in der Datei
.envauf dem Server unter dem NamenMONOBANK_TOKENoder im Secrets-Bereich Ihrer Hosting-Plattform (Vercel, Render, Railway, Replit, Lovable). - Test-Token für die Entwicklung: Für erste Experimente stellt die Bank einen separaten Test-Token auf der Seite api.monobank.ua → bereit, der die Simulation von Transaktionen ohne echte Abbuchungen ermöglicht.
4. Offizielle Monobank AI-Prompts für Vibe-Coder
Das Monobank-Team hat einen Satz offizieller System-Prompts für AI-Agenten entwickelt. Ihr Hauptvorteil liegt in der exakten Übereinstimmung mit den aktuellen Endpunkten der Bank.
Seite der offiziellen Monobank-Dokumentation für AI-ToolsDie wichtigste Anfängerfalle – Betrag in Kopeken: Die Monobank API akzeptiert alle Beträge ausschließlich in minimalen Währungseinheiten (Kopeken). $100\text{ UAH} = 10,000\text{ Kopeken}$. Wenn Sie amount: 100 übergeben, zahlt der Kunde nur 1 Hrywnja.
4.1. Basis-Prompt zur Erstellung der Zahlung
Kopieren Sie diesen Prompt und senden Sie ihn im Chat Ihres AI-Assistenten:
4.2. Prompt zur Einrichtung des Webhook-Handlers
Ohne Webhook erfährt der Server nicht von der erfolgreichen Zahlung, wenn der Kunde den Browser sofort nach der Abbuchung schließt:
5. Skills-Paket monobank-acquiring: Optimierung des Agenten
Wenn man sich auf einen kurzen Prompt beschränkt, schreibt der AI-Assistent einen Basiscode (ca. 6,8 von 10 Punkten): Der Button funktioniert zwar, aber der Code enthält keine Überprüfung der kryptografischen Signaturen, keinen Schutz gegen Preismanipulation und keine Behandlung seltener Netzwerkfehler.
Um Produktionsniveau (9,8–10 Punkte) zu erreichen, wird im Projektstammverzeichnis ein spezialisiertes Skills-Paket monobank-acquiring hinzugefügt.
Audit der Zahlungsintegration: Vergleich der Sicherheit vor und nach Nutzung des Skills5.1. Anatomie und Struktur des Skills-Pakets
| Skill-Datei | Inhalt und zuständige Aufgaben |
|---|---|
SKILL.md | Zentrales Manifest: Basis-Flow, X-Token-Autorisierung, Datentypen und Fehlerbehandlung für 400, 403, 429, 500. |
quickstart.md | Schnellstart: Schritt-für-Schritt-Tutorial zur Erstellung einer Rechnung und zum Fallback-Polling mit fertigen curl-Befehlen. |
invoice.md | Rechnungslebenszyklus: Endpunkte zur Erstellung der Rechnung, Statusprüfung, Stornierung und Ungültigerklärung von Links. |
webhook.md | Kryptografischer Schutz: Mathematisch exakte Verifizierung der ECDSA SHA-256-Signatur aus dem Header x-sign. |
payment.md | Direkte Zahlungen: Abbuchung mit gespeichertem Kartentoken, synchrone Transaktionen und 3DS-Prüfung. |
wallet.md | Kartentokenisierung (Wallet): Sichere Speicherung des Zahlungsmittels des Kunden im Bankspeicher für One-Click-Zahlungen. |
fiscal.md | Quittungen und pRRO: Beschreibung der Warenkorbstruktur basketOrder, Berechnung von Steuern, Rabatten und Export der Quittungen als PDF. |
statement.md | Kontoauszüge und Analysen: Abruf des Registers erfolgreicher Operationen für den gewählten Zeitraum inklusive Berechnung der Bankgebühren. |
merchant.md | Händlerdaten: Abruf des öffentlichen Schlüssels der Bank, Verwaltung von Sub-Merchants und Kassierern. |
examples/ | Fertige Server: Arbeitsbeispiele für Server in 6 populären Sprachen (Node.js, Python, Go, PHP, C#, Java). |
6. Praktische Umsetzung: Dynamischer Zahlungsfluss
Jedes Projekt hat seine eigene Struktur: Manche verkaufen digitale Beratungen mit festen Tarifen, andere haben einen Online-Shop mit dynamischem Warenkorb, wieder andere einen einfachen Landing Page mit einer einzigen Spenden- oder Abonnement-Schaltfläche.
Der häufigste Anfängerfehler besteht darin, den Betrag (z. B. 1000 UAH) hart in den Client-Code des Buttons oder in den Body der POST-Anfrage vom Browser einzubetten. Dieser Ansatz erzeugt eine kritische Sicherheitslücke.
6.1. Sicherheitsprinzip: Dynamischer Preis statt Hardcoding
-
Vertrauen Sie niemals dem Betrag aus dem Browser: Wenn das Client-JavaScript
{ price: 1000 }an den Server sendet, kann ein Angreifer über den Code-Inspektor (DevTools) oder Postman diesen Wert auf{ price: 1 }ändern und den Zugriff für 1 Hrywnja erwerben. -
Server als einzige Wahrheitsquelle (Single Source of Truth): Das Frontend übergibt an das Backend nur die Produkt-ID (
productId), den gewählten Tarif (planId: "pro") oder ein Array von Warenkorb-IDs (items: [{ id: "book_1", qty: 2 }]). -
Automatische Konvertierung in Kopeken: Der Server ruft den aktuellen Preis aus der Konfigurationsdatei oder Datenbank ab und multipliziert ihn selbstständig mit 100:
$$\text{amount} = \text{Math.round}(\text{realPrice} \times 100)$$ Wenn Sie den Preis in der Datenbank ändern oder einen Rabatt ankündigen, wird die Monobank-Rechnung mit dem neuen korrekten Betrag generiert, ohne dass Sie in das Zahlungs-Gateway eingreifen müssen.
6.2. Universeller AI-Prompt zur Anpassung an jedes Projekt
Kopieren Sie diesen Prompt und senden Sie ihn im Chat Ihres AI-Agenten (Codex, Antigravity, Cursor oder Claude Code). Der Agent scannt selbst die Dateien Ihrer Website, findet vorhandene Buttons und Preise und erstellt eine robuste Integration:
Arbeit des AI-Agenten in der IDE mit Analyse der Struktur und Erstellung des dynamischen Endpunkts6.3. Architekturmuster des Backends zur Rechnungsstellung
Hier sind geprüfte Server-Implementierungen für die beiden beliebtesten Web-Stacks:
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. Sichere Webhook-Verarbeitung und kryptografische ECDSA-Signatur
Der verantwortungsvollste Teil jeder finanziellen Integration ist die Verifizierung der Zahlungsbenachrichtigungen. Ein Angreifer könnte eine gefälschte HTTP-Anfrage an Ihre Adresse /api/payment/webhook mit einer falschen Erfolgsmeldung senden.
Um dies zu verhindern, signiert Monobank jeden Webhook mit dem asymmetrischen Algorithmus ECDSA (Kurve secp256r1 / SHA-256) und übergibt die Signatur im HTTP-Header x-sign.
7.1. Warum JSON.stringify die Signaturverifizierung bricht
Kritische rawBody-Falle: Für die Überprüfung der ECDSA-Signatur wird der strikt originale Byte-Stream benötigt, den der Monobank-Server gesendet hat. Wenn Sie versuchen, JSON zu parsen und erneut JSON.stringify(req.body) aufzurufen, ändern sich die Reihenfolge der Schlüssel, Leerzeichen oder Zeilenumbrüche. Dies führt zu einem anderen SHA-256-Hash, und die Signaturprüfung garantiert einen Fehler!
7.2. Implementierung der Webhook-Verifizierung
Unten finden Sie die korrekte Implementierung zum Abrufen des rohen Bodies und zur Verifizierung für Next.js App Router und 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. Lokales Testen von Webhooks (Localhost & Cloudflare Tunnels)
Ein verbreitetes Problem bei Vibe-Codern: Beim Starten des Servers auf http://localhost:3000 kann die Bank den Webhook nicht zustellen, da der lokale Rechner keine öffentliche IP-Adresse im Internet hat.
Monobank sendet Webhooks ausschließlich an öffentliche Adressen mit gültigem HTTPS-Protokoll. Um den vollständigen Zyklus auf Ihrem Computer zu testen, richten Sie einen sicheren Tunnel ein.
8.1. Schneller Tunnel-Start (ohne Registrierung und kostenlos)
Nutzen Sie Cloudflare Tunnel (cloudflared) oder untun:
bash# Миттєвий HTTPS-тунель на 3000 порт без встановлення утиліт npx untun@latest tunnel --port 3000
Nach dem Start erhalten Sie eine temporäre öffentliche HTTPS-Adresse, z. B.:
https://your-tunnel-name.trycloudflare.com
8.2. Einstellung des Webhooks für lokale Tests
Geben Sie im Code zur Rechnungsstellung während der Entwicklung die erhaltene Adresse an:
Nun sendet die Bank bei einer Testzahlung den echten Webhook direkt an Ihren lokalen Server im Terminal, und Sie können sicherstellen, dass die Signatur x-sign die Prüfung erfolgreich passiert.
9. UX der Rückleitungsseite und Lösung der Race Condition
Wenn der Kunde die Rechnung über die Monobank-App oder Apple Pay bezahlt, leitet die Bank ihn sofort auf die redirectUrl (/payment-result?ref=...) weiter.
Der Netzwerk-Webhook vom Bankserver zu Ihrem Server kann jedoch aufgrund von Netzwerk-Routings um 1–2 Sekunden verzögert sein. Wenn die Ergebnis-Seite den Status sofort in der Datenbank prüft, riskiert sie die Anzeige: „Bestellung nicht bezahlt“, was beim Kunden Panik auslöst (Geld wurde von der Karte abgebucht, aber die Website meldet fehlende Zahlung).
9.1. Ingenieursmuster zur Lösung der Race Condition
- Initialer Ladestatus: Die Seite öffnet sich mit neutralem Status: „Zahlung bei der Bank bestätigen...“ und einem animierten Indikator.
- Kurzes Polling (Short Polling): Das Frontend führt bis zu 5 schnelle Anfragen an die eigene API alle 1,5 Sekunden durch (
/api/orders/check-status?ref=...), während darauf gewartet wird, dass der Webhook den Bestellstatus in der Datenbank aufsuccessändert. - Fallback: Wenn der Webhook nach 8 Sekunden nicht eingetroffen ist, sieht der Kunde die Meldung: „Zahlung zur Bearbeitung angenommen. Sobald die Bank die Transaktion bestätigt, wird der Zugriff automatisch freigeschaltet.“
9.2. Fertige React-Komponente der Ergebnis-Seite
10. Erweiterte Funktionen: Integriertes pRRO, Hold und Wallet
Monobank Acquiring bietet ein umfassendes Spektrum an Tools für komplexere Geschäftsmodelle:
Finale Monobank Hosted Checkout-Zahlungsseite mit Apple Pay und Karten10.1. Software-RRO: Kostenloser integrierter Checkbox in der Monobank Kasse
Für die meisten ukrainischen FOPs der Gruppen 2 und 3 ist die Fiscalisierung von Online-Verkäufen eine gesetzliche Anforderung.
Der Hauptvorteil von Monobank für Unternehmer ist die kostenlose integrierte Integration mit dem pRRO-Dienst Checkbox:
- Aktivierung mit einem Klick: Im Konto
web.monobank.uagehen Sie zu den Einstellungen des erstellten Terminals und aktivieren den Schalter „Fiscalisierung über Checkbox“. Monobank erstellt die Kasse kostenlos selbst und signiert die Quittungen mit Ihrer KEP. - Automatische Fiscalisierung: Wenn Sie einen Standard-Warenkatalog mit einheitlichem Steuersatz haben, müssen Sie den Code zur Zahlungsstellung nicht einmal ändern – die Quittung wird automatisch basierend auf dem Feld
destinationim Verwendungszweck gebildet. - Erweiterte Fiscalisierung über API: Wenn Sie Waren mit unterschiedlichen MwSt-Sätzen oder akzisepflichtige Positionen mit UKTZED-Codes verkaufen, übergeben Sie das Array
basketOrderinnerhalb des ObjektsmerchantPaymInfo:
10.2. Zweistufige Zahlung (Hold)
Wenn Sie physische Waren verkaufen, die möglicherweise nicht auf Lager sind, nutzen Sie den Hold-Modus:
- Blockierung: Übergeben Sie
paymentType: "hold"bei der Erstellung der Rechnung. Das Geld wird auf der Karte des Käufers für bis zu 9 Tage eingefroren. - Abbuchung (Finalize): Nach Prüfung der Verfügbarkeit rufen Sie
/api/merchant/invoice/finalizeauf. Sie können den vollen Betrag oder einen geringeren abbuchen (z. B. wenn eine Position fehlt). - Stornierung: Wenn die Ware nicht verfügbar ist, rufen Sie
/api/merchant/invoice/cancelauf – die Zahlung wird storniert, ohne dass für den Käufer Bankgebühren anfallen.
10.3. Kartenspeicherung und Abonnements (Wallet)
Wenn Sie einen SaaS-Dienst mit regelmäßiger monatlicher Abonnementgebühr starten, übergeben Sie saveCardData: true bei der Erstellung der ersten Rechnung. Nach erfolgreicher Zahlung wird im Webhook die walletId zurückgegeben. Nutzen Sie dieses Token für zukünftige automatische Abbuchungen, ohne dass der Kunde die Kartendaten erneut eingeben muss.
11. Sicherheitsmatrix und automatische Tests (Vitest / Jest)
Zahlungen sind der Bereich maximaler finanzieller Verantwortung. Ein Fehler in einem normalen Button führt zu Ärgernis, aber ein Fehler im Zahlungs-Gateway führt zu direkten materiellen Verlusten oder zur Sperrung der Kasse durch die Bank.
Führen Sie vor dem Wechsel in den Live-Betrieb die Sicherheits-Testmatrix durch:
| Sicherheitstest | Was genau geprüft wird | Erwartetes Systemverhalten |
|---|---|---|
| 1. Schutz vor Preisänderung (Price Tampering) | Der Kunde sendet productId: "vip", versucht aber, im Request amount: 100 (1 UAH) zu manipulieren | Der Server ignoriert das Feld amount vom Client, nimmt den realen Preis aus der Konfiguration (2490 UAH = 249 000 Kopeken). Wenn productId gefälscht ist – gibt HTTP 400 zurück. |
| 2. Blockierung ohne Signatur | Auf den Endpunkt /api/payment/webhook kommt eine POST-Anfrage ohne Header x-sign | Die Anfrage wird sofort mit Antwort HTTP 400 Bad Request blockiert. Keine Bestellverarbeitung findet statt. |
| 3. Blockierung gefälschter Signaturen | Ein Angreifer hat eine Fake-Signatur in x-sign mit Status status: "success" gesendet | Die Prüfung crypto.verify(SHA256, ...) gibt false zurück. Der Server antwortet mit HTTP 400/401, Zugriff oder Ware werden nicht gewährt. |
| 4. Idempotenz des Webhooks (Duplicate Delivery) | Monobank hat denselben success-Webhook zweimal oder dreimal hintereinander wegen Netzwerk-Lag gesendet | Zugriff oder Ware werden nur einmal aktiviert. Der wiederholte Webhook löst keine doppelte Ausgabe aus und gibt der Bank HTTP 200 OK zurück. |
| 5. Resistenz gegen Race Conditions | Der Webhook der Bank kam ein, bevor die ursprüngliche HTTP-Anfrage zur Rechnungsstellung in der DB abgeschlossen war | Der Webhook-Handler ist resistent gegen fehlende Datensätze in der DB (nutzt UPSERT oder erstellt die Bestellung on-the-fly). |
| 6. Einhaltung der Rate Limits (Rate Limit Buffer) | Bei Ausfall des Webhooks startet das Status-Polling /api/merchant/invoice/status | Anfragen werden mit einer Pause von mindestens 15 Sekunden ausgeführt, was das Terminal vor der Blockierung HTTP 429 Too Many Requests schützt. |
11.1. Fertiger Satz automatischer Tests für Ihr Projekt
Bitten Sie Ihren AI-Agenten, den folgenden Testsatz zum Projekt hinzuzufügen (monobank-acquiring.test.ts):
12. Finale Ingenieur-Checkliste vor dem Launch
Prüfen Sie Ihr Zahlungsmodul anhand dieser 10 Punkte vor dem Umschalten auf Live-Zahlungen:
- Website-Compliance: Im Footer sind Links zum Öffentlichen Angebot, zur Datenschutzrichtlinie, zu den Rückgabebedingungen und den vollständigen FOP-Angaben mit Steuer-ID hinzugefügt.
- Betrag in Kopeken: Alle Werte
amountsind durchMath.roundmit 100 multipliziert ($1\text{ UAH} = 100\text{ Kopeken}$). - Schlüsselsicherheit: Das Token ist in
.envunter dem NamenMONOBANK_TOKENausgelagert und in.gitignoreaufgenommen. - Preise vom Backend (SSOT): Der Client übergibt nur die Produkt-ID, der Betrag wird ausschließlich aus der DB oder Konfiguration geholt.
- RawBody-Verarbeitung: Der Webhook verifiziert den originalen Text- oder Binärbuffer (
req.text()oderreq.rawBody), um doppeltes Parsen viaJSON.stringifyzu vermeiden. - Kryptografischer Schutz: Der Webhook verifiziert die Signatur
x-signüber den öffentlichen Schlüssel der Bank mit dem AlgorithmusSHA256ECDSA. - Öffentliche URL für Webhook: Der Server ist extern über ein gültiges SSL-Zertifikat HTTPS erreichbar (für lokale Tests eignet sich Cloudflare Tunnel oder ngrok).
- Idempotenz: Der erneute Eingang desselben Webhooks löst keine doppelte Ausgabe von Ware oder Abonnement aus.
- UX der Ergebnis-Seite: Auf
/payment-resultist ein Wartelader und kurzes Status-Polling eingerichtet, um den Nutzer vor Race Conditions zu schützen. - Echte Zahlung von 1–5 UAH: Eine erfolgreiche Testtransaktion mit echter Karte wurde durchgeführt, die Abbuchung und die Anzeige im Bankkonto wurden überprüft.