Webhooks -- Vue d'ensemble
Les webhooks permettent à votre application de recevoir des notifications en temps réel sur les événements de la plateforme Minha Konta. Quand un événement se produit, Minha Konta envoie un HTTP POST à l'URL enregistrée.
Comment ça fonctionne
- Enregistrez une URL de webhook dans votre compte
- Quand un événement se produit (ex. : PIX reçu), Minha Konta envoie un HTTP POST à votre URL
- Votre application traite la notification et répond avec un status
2xx(200, 201 ou 204)
Événements disponibles
Minha Konta livre des événements de PIX, TEF entre comptes Minha Konta et test opérationnel de webhook. D'autres produits (boleto, comptes et STA) ne sont pas dans le périmètre. Toute tentative d'abonnement à des événements hors du tableau ci-dessous est rejetée avec events: contains invalid events: ....
| Événement | Status body | Description | Déclenchement |
|---|---|---|---|
pix.charge.created | created | QR code généré ou cash-in initié | Actif |
pix.charge.paid | paid | PIX reçu et liquidé | Actif |
pix.charge.expired | expired | QR code expire sans paiement | Actif |
pix.charge.cancelled | cancelled | QR code annulé avant le paiement | Enregistré, pas encore déclenché |
pix.payout.queued | queued | PIX envoye mis en file par limite operationnelle. Retry automatique avec TTL maximum 2h | Actif |
pix.payout.processing | processing | PIX envoyé, en attente de confirmation BACEN | Actif |
pix.payout.held | processing | PIX envoyé retenu pour analyse chez l'agent de règlement (autorisation/anti-fraude). Règle ou rejette ensuite — ne pas renvoyer | Actif |
pix.payout.confirmed | settled | PIX envoyé et confirmé (terminal) | Actif |
pix.payout.failed | rejected | PIX envoyé rejeté par le SPI (terminal) | Actif |
pix.payout.returned | returned | PIX envoyé remboursé | Actif |
pix.refund.requested | requested | Demande de remboursement reçue (infraction BACEN) ; blocage conservatoire créé sur le solde du client | Actif |
pix.refund.completed | settled / completed | Analyse de la défense finalisée et remboursement exécuté (ou libéré) | Actif |
pix.return.received | settled | Remboursement PIX reçu (crédit) | Actif |
pix.infraction.created | ACKNOWLEDGED | Infraction PIX signalee par la contrepartie via BACEN DICT ; peut exiger une analyse et une defense MED | Actif |
pix.infraction.resolved | CLOSED / CANCELLED | Infraction resolue par decision finale ou annulation de la contrepartie | Actif |
pix.infraction.defense_submitted | defense_submitted | Défense soumise par le merchant (portail ou API) ; attend l'analyse BACEN | Actif |
tef.transfer.sent | settled | TEF entre comptes Minha Konta liquidée pour le compte d'origine | Actif |
tef.transfer.received | settled | TEF entre comptes Minha Konta liquidée pour le compte de destination | Actif |
tef.transfer.failed | failed | TEF entre comptes Minha Konta rejetée ou non liquidée | Actif |
webhook.test | test | Test manuel. Disponible uniquement via Admin/Merchant portal - l'External API n'expose pas d'endpoint pour déclencher un test | Déclenchement manuel (pas External API) |
pix.charge.cancelled n'est pas encore déclenché
L'événement est dans l'enum et peut être souscrit, mais le système n'a pas de flux d'annulation de QR code aujourd'hui. Si vous vous abonnez, le POST /webhooks répond 201 normalement - mais aucune notification n'arrivera. Continuez à surveiller pix.charge.expired pour le cycle naturel de vie du QR.
Sécurité
Chaque notification inclut des headers de sécurité et d'identification pour la validation :
| Header | Description |
|---|---|
X-Minha Konta-Signature | Signature HMAC-SHA256 du payload (préfixe sha256=). Dans des cas rares (webhook enregistré sans secret), la valeur littérale est unsigned - voir note ci-dessous |
X-Minha Konta-Timestamp | Unix timestamp en secondes de l'envoi |
X-Minha Konta-Event-Id | UUID unique de la delivery (pour déduplication) |
X-Minha Konta-Event-Type | Type de l'événement (ex. : pix.charge.paid) |
Content-Type | Toujours application/json |
User-Agent | Toujours Minha Konta-Webhook/1.0 - utilisez pour le whitelisting dans firewalls/WAF. L'évolution future suivra le pattern Minha Konta-Webhook/{version} ; filtrez par préfixe Minha Konta-Webhook/ pour être immunisé aux nouvelles versions |
Signature unsigned quand le webhook n'a pas de secret
Si le webhook a ete enregistre sans champ secret dans un enregistrement legacy, le header X-Minha Konta-Signature peut valoir unsigned. Cela desactive la validation HMAC de votre cote. Si vous recevez unsigned, enregistrez un nouveau webhook avec secret explicite et supprimez l'ancien.
SHA256 dans les webhooks vs SHA512 dans l'API
L'API utilise HMAC-SHA512 pour authentifier les requêtes que vous envoyez. Les webhooks envoyés par Minha Konta utilisent HMAC-SHA256 dans la signature X-Minha Konta-Signature. Ce sont des algorithmes différents -- chacun dans son contexte.
Validation de la signature
Validez la signature pour garantir que la notification a été envoyée par Minha Konta :
const crypto = require('crypto');
function validateWebhook(rawBody, timestamp, signature, secret) {
// rawBody is the RAW request body string (before any JSON parse)
// timestamp is unix seconds (e.g., 1712160000)
const message = `${timestamp}.${rawBody}`;
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(message)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}Utilisez le body RAW, pas re-sérialisé
Vous devez utiliser le corps exact de la requête HTTP tel que les octets sont arrivés dans votre application. Si vous faites JSON.parse puis JSON.stringify, les octets résultants ne seront pas identiques à ceux qu'Minha Konta a utilisé pour signer, et la validation échouera.
En Express/Node : utilisez express.raw({ type: 'application/json' }) ou gardez le body avant tout middleware de parse.
Dans d'autres frameworks : configurez pour capturer le raw body avant le middleware JSON.
Tri des clés dans les WEBHOOKS : PAS nécessaire
Pour la validation des webhooks (HMAC-SHA256) vous N'avez PAS besoin de trier les clés - utilisez le body raw tel que reçu dans le HTTP request d'Minha Konta.
⚠️ Attention - différence vs envoi de requêtes : Dans la signature HMAC-SHA512 des REQUÊTES que vous envoyez, le tri alphabétique des clés EST obligatoire (le serveur Minha Konta réordonne avant de valider). Ne confondez pas les deux scénarios :
- Webhook reçu (HMAC-SHA256) : validez le body raw sans réordonner
- Request envoyée (HMAC-SHA512) : triez vos clés alphabétiquement avant de signer
Validez toujours
Ne traitez jamais un webhook sans valider la signature. Cela protège contre les requêtes falsifiées.
De plus, validez que le X-Minha Konta-Timestamp est dans ± 5 minutes de l'heure actuelle (protection anti-replay - le serveur ne rejette pas les webhooks « anciens » par défaut ; cette vérification appartient à votre endpoint comme défense en profondeur) et dédupliquez les événements par X-Minha Konta-Event-Id (protection contre les retries).
Retry Policy
Si votre URL retourne un status différent de 2xx (ou timeout après 30 s), Minha Konta effectue jusqu'à 8 tentatives avec backoff exponentiel. Le total du temps entre la première et la huitième tentative est d'environ 7h45min :
| Tentative | Délai depuis la tentative précédente | Temps cumulé |
|---|---|---|
| 1re | - (immediat) | ~50-200 ms |
| 2e | 30 secondes | ~30 s |
| 3e | 2 minutes | ~2,5 min |
| 4e | 10 minutes | ~12,5 min |
| 5e | 30 minutes | ~42,5 min |
| 6e | 1 heure | ~1,75 h |
| 7e | 2 heures | ~3,75 h |
| 8e | 4 heures | ~7,75 h |
Après 8 tentatives sans succès, le webhook_delivery est marqué avec le status failed et n'est pas renvoyé automatiquement. Vous pouvez demander un replay manuel au support Minha Konta en fournissant le X-Minha Konta-Event-Id (ou avoir un opérateur avec accès admin qui replay via le portail).
Status d'une delivery
Chaque delivery passe par les status : pending (créée, en attente de livraison) → delivered (2xx reçu) OU failed (8 tentatives épuisées) OU expired (replay protection).
A propos d'expired : quand une tentative de livraison devient trop ancienne avant l'envoi, elle peut etre abandonnee et marquee comme expired. Cela empeche que des retraitements tardifs declenchent des notifications anciennes. Les replays manuels demandes au support Minha Konta suivent un flux controle et peuvent renvoyer l'evenement au client.
Durabilité
Avant de tenter la premiere livraison, l'evenement est persiste pour retry. En cas de defaillance pendant la livraison, le systeme reprend automatiquement au prochain retry - aucun evenement n'est perdu.
Idempotence
Votre application doit être idempotente : si elle reçoit le même événement plus d'une fois (identifié par X-Minha Konta-Event-Id), elle doit le traiter sans dupliquer les effets.
Replay manuel via admin
Si une delivery a échoué et que vous devez la renvoyer, l'équipe Minha Konta peut exécuter un replay manuel via le dashboard admin. Contactez le support avec le event_id de la delivery.
Livraisons dupliquées (race condition connue)
Le systeme peut utiliser plus d'un chemin de livraison pour accelerer la premiere notification et maintenir un retry durable. Dans les scenarios de forte concurrence, vous pouvez recevoir le meme payload 2 fois via HTTP, mais avec le meme X-Minha Konta-Event-Id - c'est le meme evenement, pas un retry.
Pour éviter l'impact dupliqué :
- Dédupliquez par
X-Minha Konta-Event-Id(recommandé - UUID unique par delivery, stable dans les retries et dans la race condition ci-dessus) - Ou alternativement dédupliquez par
end_to_end_id+event_typequand cela a du sens pour l'événement
C'est un comportement attendu, pas une erreur. Les retries légitimes (après 5xx/timeout) réutilisent également le même X-Minha Konta-Event-Id.
External ID dans les webhooks
Quand une transaction a été créée avec external_id, ce champ est inclus dans le payload du webhook à l'intérieur de l'objet data. Utilisez-le pour corréler l'événement avec la commande dans votre système sans avoir besoin de faire une consultation supplémentaire.
Exigences de l'endpoint
- L'URL doit utiliser HTTPS (sauf si
allow_insecure: truedans l'enregistrement) - Doit repondre avec le status
2xxdans les 30 secondes - Le body de la réponse est ignoré
- Recommandé de répondre rapidement (
200 OKimmédiat) et traiter l'événement de façon asynchrone de votre côté ; les délais longs réduisent le throughput et augmentent la chance de retries
Étapes suivantes
- Enregistrer Webhook -- créer, lister et supprimer des webhooks
- Payloads des événements -- exemples de chaque type d'événement
