Le vibecoding a radicalement transformé le développement de produits numériques. Aujourd'hui, pour intégrer sur un site la réception de paiements via Apple Pay, Google Pay ou cartes bancaires, il n'est plus nécessaire d'engager un développeur backend ni de maîtriser soi-même les protocoles cryptographiques. Il suffit de formuler clairement la logique métier à votre agent IA (Codex, Antigravity, Cursor ou Claude Code) et de lui fournir le contexte technique approprié issu de la documentation officielle.
Ce guide détaille l'intégralité du cycle de vie de l'intégration de l'acquiring en ligne Monobank dans votre projet : depuis la conformité bancaire et la configuration du tableau de bord entrepreneur jusqu'à la génération d'une passerelle de paiement sécurisée avec vérification cryptographique des signatures ECDSA dans les webhooks, la gestion des conditions de course (race conditions) dans l'interface et la mise en place d'une suite de tests automatisés obligatoires.
Version vidéo du guide : Si vous préférez un format visuel, consultez la vidéo pratique détaillée sur YouTube →, où tout le processus est démontré en direct, de la première requête au débit réel des fonds.
Pack de compétences agentiques : Pour une précision maximale de la génération de code, téléchargez le pack de connaissances officiel pour votre assistant IA :
Télécharger l'archive complète monobank-acquiring.zip (38 Ko) →
1. Architecture Hosted Checkout et cycle de vie du paiement
Monobank Acquiring fonctionne selon le schéma Hosted Checkout (paiement sur une page sécurisée de la banque). Cela signifie que votre site n'a pas besoin d'une certification de sécurité PCI DSS complexe et coûteuse, car l'utilisateur saisit les données de carte directement sur le domaine sécurisé de la banque.
La documentation officielle de Monobank pour les outils IA est disponible à l'adresse monobank.ua/api-docs/acquiring/dev/ai-tools/docs--ai-prompts →. Enregistrez ce lien comme source canonique des exigences techniques de la banque.
1.1. Flux de paiement de base
- 1. Création de la facture (
invoice/create) : Le client sélectionne un produit ou un tarif sur votre site. Le handler serveur envoie une requêtePOSTà l'API Monobank avec le montant, l'objet du paiement et l'URL de retour. La banque renvoie uninvoiceIdunique et un lienpageUrl. - 2. Redirection vers la page de paiement : Le client est redirigé vers le
pageUrl, où il paie la commande via Apple Pay, Google Pay, l'application Monobank ou la saisie des données de sa carte bancaire. - 3. Réception du Webhook : Après la finalisation du paiement, Monobank envoie automatiquement une requête
POSTà votrewebHookUrlpréalablement configuré, contenant le statut de la transaction et une signature numérique cryptographique. - 4. Fixation du statut (Terminal States) : Votre serveur doit réagir aux deux statuts finaux :
success(paiement réussi, on accorde l'accès ou on expédie la commande) etfailure(erreur ou rejet du paiement par la banque).
Le statut expired (expiration du lien) ne génère pas de webhook. Si le client ferme la page de paiement sans payer, l'état de la commande doit être vérifié via un polling API de secours.
2. Prérequis juridiques et checklist de conformité du site pour les entrepreneurs individuels (FOP)
Même si le code de paiement est irréprochable, le service de surveillance financière et de sécurité de Monobank n'activera pas la réception de paiements en production si le site ne respecte pas la législation ukrainienne et les règles des systèmes de paiement Visa/Mastercard.
2.1. Prérequis bancaires
- Compte professionnel ouvert chez Monobank (FOP ou personne morale) : L'acquiring est connecté exclusivement aux comptes professionnels. Il est interdit par la loi d'accepter des paiements commerciaux sur une carte personnelle (noire ou blanche) d'un particulier.
- Codes NACE (KVED) appropriés : Les données d'enregistrement du FOP doivent inclure des codes d'activité pour le commerce en ligne ou les services (par exemple,
47.91— Vente au détail par internet,62.01/62.02— Programmation informatique et conseil,85.59— Autres formes d'enseignement).
2.2. Checklist obligatoire des pages avant soumission à la modération
Avant de demander l'activation du terminal de paiement en ligne, assurez-vous que votre site contient les sections suivantes (généralement placées dans le footer) :
- Offre publique (Contrat public) : Description de l'objet du contrat, moment de la conclusion, droits et obligations des parties.
- Politique de confidentialité (Privacy Policy) : Formulation claire indiquant quelles données clients sont collectées et comment elles sont protégées conformément à la Loi « Sur la protection des données personnelles ».
- Conditions de remboursement et de livraison : Procédure de retour de marchandise ou de fonds dans les 14 jours selon la Loi « Sur la protection des droits des consommateurs », et pour les produits/services numériques ou abonnements — les règles de résiliation du service.
- Coordonnées complètes de l'entrepreneur dans le footer : Nom du FOP ou de la SARL, numéro fiscal / code EDRPOU, adresse juridique, numéro de téléphone de contact et e-mail professionnel du support.
- Prix transparents et descriptions : Chaque bouton de paiement doit afficher un montant fixe en hryvnias (UAH) et une description claire de ce que le client achète exactement.
Si le site ne comporte pas d'offre publique, de coordonnées du FOP, ou si les prix sont remplacés par des mentions « à convenir », le service de sécurité de Monobank rejettera l'enregistrement du terminal lors de la phase de vérification.
3. Création d'un terminal web dans le tableau de bord Monobank Business
Pour interagir avec l'API de paiement, vous avez besoin d'une clé d'accès personnelle — X-Token. Elle est générée gratuitement dans le tableau de bord personnel de l'entrepreneur.
3.1. Algorithme pas à pas pour ouvrir la caisse
- Autorisation : Rendez-vous sur web.monobank.ua → et connectez-vous via QR code avec l'application Monobank sur smartphone.
- Accès à la caisse : Dans le menu de navigation gauche, sélectionnez la section « Caisse ».
- Ajout d'un outil : Cliquez sur le bouton « + Ajouter un outil » et choisissez l'option « Paiement sur site (développement propre) ».
- Enregistrement du terminal : Entrez le nom du projet (par exemple,
Mon siteouTerminal principal) et confirmez l'opération via le bouton « Connecter ». - Génération du token API : Ouvrez le terminal créé, allez dans l'onglet « Intégrations / Clés API », cliquez sur « Créer un token » et copiez la clé générée.
📍 Navigation dans le tableau de bord :
web.monobank.ua→Caisse→+ Ajouter un outil→Paiement sur site (développement propre)
Création d'un outil de paiement dans le tableau de bord Monobank Kasa📍 Obtention de la clé API :
Caisse→Votre terminal→Intégration→Créer X-Token
Fenêtre modale de création et copie du token d'accès X-Token3.2. Règles strictes de sécurité des tokens
- Aucun hardcoding dans le code client : Le
X-Tokendonne un accès direct à la gestion de vos finances et aux remboursements. Il est catégoriquement interdit de le stocker dans du JavaScript/HTML public ou de le publier dans des dépôts GitHub publics. - Utilisation de variables d'environnement : Stockez le token uniquement dans un fichier
.envsur le serveur sous le nomMONOBANK_TOKENou dans la section Secrets de votre plateforme d'hébergement (Vercel, Render, Railway, Replit, Lovable). - Token de test pour le développement : Pour les premiers essais, la banque fournit un token de test distinct sur la page api.monobank.ua →, permettant de simuler des transactions sans débit réel de fonds.
4. Prompts IA officiels Monobank pour les vibecoders
L'équipe Monobank a développé un ensemble de prompts système officiels pour les agents IA. Leur principal avantage est une correspondance exacte avec les endpoints actuels de la banque.
Page de la documentation officielle Monobank pour les outils IAPiège principal pour les débutants — le montant en kopecks : L'API Monobank accepte tous les montants exclusivement en unités minimales de devise (kopecks). $100\text{ UAH} = 10,000\text{ kopecks}$. Si vous transmettez amount: 100, le client ne paiera que 1 hryvnia.
4.1. Prompt de base pour la création de paiement
Copiez ce prompt et envoyez-le dans le chat de votre assistant IA :
4.2. Prompt pour la configuration du handler Webhook
Sans webhook, le serveur ne connaîtra pas le fait du paiement réussi si le client ferme le navigateur immédiatement après le débit :
5. Pack de compétences monobank-acquiring : amélioration de l'agent
Si vous vous limitez à un court prompt, l'assistant IA écrira un code basique (environ 6,8 sur 10) : le bouton fonctionnera, mais le code ne contiendra pas la vérification des signatures cryptographiques, la protection contre la falsification de prix ni la gestion des erreurs réseau rares.
Pour atteindre un niveau production (9,8–10 points), un pack de compétences spécialisé monobank-acquiring est ajouté à la racine du projet.
Audit de l'intégration de paiement : comparaison de sécurité avant et après utilisation du skill5.1. Anatomie et structure du pack de compétences
| Fichier Skill | Contenu et responsabilités |
|---|---|
SKILL.md | Manifeste central : flux de base, autorisation X-Token, types de données et gestion des erreurs 400, 403, 429, 500. |
quickstart.md | Démarrage rapide : tutoriel pas à pas pour créer une facture et un fallback-polling avec des commandes curl prêtes à l'emploi. |
invoice.md | Cycle de vie des factures : endpoints de création de facture, vérification de statut, annulation et invalidation des liens. |
webhook.md | Protection cryptographique : vérification mathématiquement précise de la signature ECDSA SHA-256 issue du header x-sign. |
payment.md | Paiements directs : débits via token de carte sauvegardé, transactions synchrones et vérification 3DS. |
wallet.md | Tokenisation de cartes (Wallet) : stockage sécurisé du moyen de paiement du client dans le coffre de la banque pour des paiements en un clic. |
fiscal.md | Reçus et pRRO : description de la structure du panier basketOrder, calcul des taxes, remises et export des reçus en PDF. |
statement.md | Extraits et analytics : obtention du registre des opérations réussies pour une période choisie avec calcul des frais bancaires. |
merchant.md | Données marchand : obtention de la clé publique de la banque, gestion des sous-marchands et caissiers. |
examples/ | Serveurs prêts : exemples fonctionnels de serveurs dans 6 langages populaires (Node.js, Python, Go, PHP, C#, Java). |
6. Implémentation pratique : flux de paiement dynamique
Chaque projet a sa propre structure : certains vendent des consultations numériques avec des tarifs fixes, d'autres ont une boutique en ligne avec un panier dynamique, d'autres encore un simple landing page avec un seul bouton de don ou d'abonnement.
L'erreur principale des débutants est de « coder en dur » le montant (par exemple, 1000 UAH) directement dans le code client du bouton ou dans le corps de la requête POST venant du navigateur. Cette approche crée une vulnérabilité de sécurité critique.
6.1. Principe de sécurité : prix dynamique plutôt que hardcoding
-
Ne faites jamais confiance au montant venant du navigateur : Si le JavaScript client envoie
{ price: 1000 }au serveur, un attaquant peut, via l'inspecteur de code (DevTools) ou Postman, modifier cette valeur en{ price: 1 }et acheter l'accès pour 1 hryvnia. -
Le serveur est la seule source de vérité (Single Source of Truth) : Le frontend transmet au backend uniquement l'identifiant du produit (
productId), le tarif choisi (planId: "pro") ou un tableau d'identifiants du panier (items: [{ id: "book_1", qty: 2 }]). -
Conversion automatique en kopecks : Le serveur récupère le prix actuel depuis un fichier de configuration ou la base de données et le multiplie lui-même par 100 :
$$\text{amount} = \text{Math.round}(\text{realPrice} \times 100)$$ Si vous changez le prix dans la base ou annoncez une remise, la facture Monobank sera générée avec le nouveau montant correct sans intervention dans la passerelle de paiement.
6.2. Prompt IA universel pour l'adaptation à tout projet
Copiez ce prompt et envoyez-le dans le chat de votre agent IA (Codex, Antigravity, Cursor ou Claude Code). L'agent scannera lui-même les fichiers de votre site, trouvera les boutons et prix existants et construira une intégration robuste :
Travail de l'agent IA dans l'IDE avec analyse de la structure et création d'un endpoint dynamique6.3. Template architectural backend pour la création de facture
Voici des implémentations serveur éprouvées pour les deux stacks web les plus populaires :
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. Traitement sécurisé des webhooks et signature cryptographique ECDSA
La partie la plus critique de toute intégration financière est la vérification des notifications de paiement. Un attaquant peut envoyer une requête HTTP falsifiée à votre URL /api/payment/webhook avec un faux message de succès.
Pour éviter cela, Monobank signe chaque webhook à l'aide de l'algorithme asymétrique ECDSA (courbe secp256r1 / SHA-256) et transmet la signature dans le header HTTP x-sign.
7.1. Pourquoi JSON.stringify casse la vérification de signature
Piège critique du rawBody : Pour vérifier la signature ECDSA, il faut strictement le flux d'octets original envoyé par le serveur Monobank. Si vous essayez de parser le JSON puis de rappeler JSON.stringify(req.body), l'ordre des clés, les espaces ou les sauts de ligne changeront. Cela produira un hash SHA-256 différent, et la vérification de signature retournera garanti une erreur !
7.2. Implémentation de la vérification du webhook
Ci-dessous, l'implémentation correcte pour récupérer le corps brut et vérifier la signature pour Next.js App Router et 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. Test local des webhooks (Localhost & Cloudflare Tunnels)
Problème courant chez les vibecoders : lors du lancement du serveur sur http://localhost:3000, la banque ne peut pas livrer le webhook, car la machine locale n'a pas d'adresse IP publique sur Internet.
Monobank envoie les webhooks exclusivement vers des adresses publiques avec un protocole HTTPS valide. Pour tester le cycle complet sur votre ordinateur, ouvrez un tunnel sécurisé.
8.1. Démarrage rapide du tunnel (sans inscription et gratuit)
Utilisez Cloudflare Tunnel (cloudflared) ou untun :
bash# Миттєвий HTTPS-тунель на 3000 порт без встановлення утиліт npx untun@latest tunnel --port 3000
Après le lancement, vous obtiendrez une URL HTTPS publique temporaire, par exemple :
https://your-tunnel-name.trycloudflare.com
8.2. Configuration du webhook pour le test local
Dans le code de création de facture, pendant le développement, indiquez l'URL obtenue :
Maintenant, lors d'un paiement de test, la banque enverra un vrai webhook directement sur votre serveur local dans le terminal, et vous pourrez vérifier que la signature x-sign passe bien la vérification.
9. UX de la page de retour et résolution de la condition de course (Race Condition)
Quand le client paie la facture via l'application Monobank ou Apple Pay, la banque le redirige vers l'URL redirectUrl (/payment-result?ref=...) immédiatement.
Cependant, le webhook réseau depuis le serveur de la banque vers votre serveur peut prendre 1 à 2 secondes de retard à cause du routage réseau. Si la page de résultat vérifie immédiatement le statut dans la base de données, elle risque d'afficher : « Commande non payée », ce qui paniquera le client (les fonds sont débités de la carte, mais le site signale l'absence de paiement).
9.1. Pattern d'ingénierie pour résoudre la race condition
- État initial de chargement : La page s'ouvre avec un statut neutre : « Confirmation du paiement auprès de la banque... » et un indicateur animé.
- Polling court (Short Polling) : Le frontend effectue jusqu'à 5 requêtes rapides vers votre propre API toutes les 1,5 secondes (
/api/orders/check-status?ref=...), attendant que le webhook change le statut de la commande ensuccessdans la base. - Fallback : Si après 8 secondes le webhook n'est pas arrivé, le client voit le message : « Paiement accepté en traitement. Dès que la banque confirmera la transaction, l'accès s'ouvrira automatiquement ».
9.2. Composant React prêt à l'emploi pour la page de résultat
10. Fonctionnalités avancées : pRRO intégré, hold et Wallet
Monobank Acquiring offre une gamme complète d'outils pour des modèles de business plus complexes :
Page finale de paiement Monobank Hosted Checkout avec Apple Pay et cartes10.1. RRO logiciel : Checkbox intégré gratuit dans la Caisse Monobank
Pour la plupart des FOP ukrainiens de groupes 2 et 3, la fiscalisation des ventes en ligne est une obligation légale.
Le principal avantage de Monobank pour les entrepreneurs est l'intégration gratuite et native avec le service pRRO Checkbox :
- Activation en un clic : Dans le tableau de bord
web.monobank.ua, allez dans les paramètres du terminal créé et activez le switch « Fiscalisation via Checkbox ». Monobank crée gratuitement la caisse et signe les reçus avec votre KEPP (signature électronique qualifiée). - Fiscalisation automatique : Si vous avez un catalogue standard avec un taux identique, vous n'avez même pas besoin de modifier le code de création de paiement — le reçu est formé automatiquement selon le champ
destinationdans l'objet du paiement. - Fiscalisation avancée via API : Si vous vendez des produits avec des taux de TVA différents ou des articles soumis à accise avec codes UKTZED, transmettez le tableau
basketOrderà l'intérieur de l'objetmerchantPaymInfo:
10.2. Paiement en deux étapes (Hold)
Si vous vendez des biens physiques qui peuvent être en rupture de stock, utilisez le mode hold :
- Blocage : Transmettez
paymentType: "hold"lors de la création de la facture. Les fonds sont gelés sur la carte de l'acheteur pour une durée allant jusqu'à 9 jours. - Débit (Finalize) : Après vérification de la disponibilité du produit, appelez
/api/merchant/invoice/finalize. Vous pouvez débiter soit le montant total, soit un montant inférieur (par exemple, si un article manque). - Annulation : Si le produit n'est pas disponible, appelez
/api/merchant/invoice/cancel— le paiement est annulé sans aucun frais bancaire pour l'acheteur.
10.3. Sauvegarde de cartes et abonnements (Wallet)
Si vous lancez un service SaaS avec un abonnement mensuel récurrent, transmettez saveCardData: true lors de la création de la première facture. Après le paiement réussi, le webhook retournera un walletId. Utilisez ce token pour les prochains débits automatiques sans ressaisie des données de carte par le client.
11. Matrice de sécurité et tests automatisés (Vitest / Jest)
Le paiement est la zone de responsabilité financière maximale. Une erreur dans un bouton classique provoque de l'agacement, mais une erreur dans la passerelle de paiement entraîne des pertes matérielles directes ou le blocage de la caisse par la banque.
Avant de passer en production, lancez la matrice de tests de sécurité :
| Test de sécurité | Ce qui est vérifié | Comportement attendu du système |
|---|---|---|
| 1. Protection contre la modification de prix (Price Tampering) | Le client envoie productId: "vip", mais tente d'imposer dans la requête amount: 100 (1 UAH) | Le serveur ignore le champ amount du client, prend le prix réel de la config (2490 UAH = 249 000 kopecks). Si le productId est falsifié — retourne HTTP 400. |
| 2. Blocage sans signature | Une requête POST arrive sur l'endpoint /api/payment/webhook sans le header x-sign | La requête est bloquée immédiatement avec une réponse HTTP 400 Bad Request. Aucun traitement de commande n'a lieu. |
| 3. Blocage des fausses signatures | Un attaquant a envoyé une fausse signature dans x-sign avec le statut status: "success" | La vérification crypto.verify(SHA256, ...) retourne false. Le serveur retourne HTTP 400/401, l'accès ou le produit n'est pas délivré. |
| 4. Idempotence du webhook (Duplicate Delivery) | Monobank a envoyé le même webhook success deux ou trois fois consécutives à cause d'un lag réseau | L'accès ou le produit est activé une seule fois. Le webhook répété ne provoque pas de double délivrance, retournant à la banque HTTP 200 OK. |
| 5. Résistance à la race condition | Le webhook de la banque arrive avant que la requête HTTP initiale de création de facture ne termine son écriture en base | Le handler du webhook est robuste à l'absence d'enregistrement en BDD (utilise UPSERT ou crée la commande à la volée). |
| 6. Respect des rate limits (Rate Limit Buffer) | En cas d'échec du webhook, un polling de statut /api/merchant/invoice/status est lancé | Les requêtes sont exécutées avec une pause d'au moins 15 secondes, protégeant le terminal du blocage HTTP 429 Too Many Requests. |
11.1. Suite de tests automatisés prête pour votre projet
Demandez à votre agent IA d'ajouter la suite de tests suivante au projet (monobank-acquiring.test.ts) :
12. Checklist d'ingénierie final avant lancement
Vérifiez votre module de paiement sur ces 10 points avant de basculer vers les paiements en production :
- Conformité du site : Le footer contient des liens vers l'Offre Publique, la Politique de Confidentialité, les Conditions de Retour et les coordonnées complètes du FOP avec numéro fiscal.
- Montants en kopecks : Toutes les valeurs
amountsont multipliées par 100 ($1\text{ UAH} = 100\text{ kopecks}$) viaMath.round. - Sécurité de la clé : Le token est extrait dans
.envsous le nomMONOBANK_TOKENet ajouté au.gitignore. - Prix depuis le backend (SSOT) : Le client transmet uniquement l'identifiant du produit, le montant est pris exclusivement depuis la base ou la config.
- Traitement rawBody : Le webhook vérifie le buffer texte ou binaire original (
req.text()oureq.rawBody), évitant le double parsing viaJSON.stringify. - Protection cryptographique : Le webhook vérifie la signature
x-signvia la clé publique de la banque avec l'algorithmeSHA256ECDSA. - URL publique pour le webhook : Le serveur est accessible de l'extérieur via un certificat SSL HTTPS valide (pour les tests locaux, Cloudflare Tunnel ou ngrok conviennent).
- Idempotence : La réception répétée du même webhook ne provoque pas de double délivrance de produit ou d'abonnement.
- UX de la page de résultat : Sur
/payment-result, un loader d'attente et un polling court du statut sont configurés pour protéger l'utilisateur contre la race condition. - Paiement réel de 1–5 UAH : Une transaction de test réussie a été effectuée avec une vraie carte, le débit des fonds et leur affichage dans le tableau de bord bancaire ont été vérifiés.