Événements sortants
Tout fait métier magot (paiement, recharge, gel de carte, demande, mission, règle modifiée, décision d'autorisation, écart de solde) est écrit dans un journal immuable. La banque s'y abonne : magot lui pousse chaque événement par webhook signé, pour son CRM, son anti-fraude ou son reporting.
Abonnement
Un abonnement = une URL HTTPS de la banque, un secret de signature, et optionnellement une liste de types. Créé par l'exploitation magot :
tsx scripts/add-event-subscription.ts <tenant> https://si.banque.example/magot [--types PaymentSettled,CardFrozen] [--from-start]
Par défaut, la livraison commence aux événements à venir ; --from-start
livre tout l'historique de l'établissement.
Requête
POST https://si.banque.example/magot
Content-Type: application/cloudevents+json
Magot-Subscription-Id: <uuid>
Magot-Event-Id: <tenant>:<séquence>
Magot-Timestamp: <secondes Unix>
Magot-Signature: v1=<HMAC-SHA256 hex de "<timestamp>.<corps>", clé = secret>
Corps au format CloudEvents 1.0 :
{
"specversion": "1.0",
"id": "5f0c…:4812",
"source": "https://api.magot.ch/tenants/5f0c…",
"type": "ch.magot.PaymentSettled.v1",
"subject": "child/9a41…",
"time": "2026-09-27T14:02:11.482Z",
"datacontenttype": "application/json",
"magotsequence": 4812,
"data": { "amountCents": 450, "merchant": "Kiosque", "category": "food", "balanceCents": 3200 }
}
La signature se vérifie exactement comme celle du webhook d'autorisation entrant (issuer-webhook.md) : même schéma, secret propre à l'abonnement. La banque rejette tout message hors d'une fenêtre de ±5 min.
Garanties
- Ordre : par établissement, dans l'ordre du journal (
magotsequencestrictement croissant). - Au moins une fois : un événement est renvoyé tant que la banque n'a pas
répondu
2xx. Un doublon reste possible (coupure juste après l'accusé) : la banque dédoublonne parid. - Aucun événement sauté : un échec (
non-2xx, timeout de 10 s, erreur réseau, redirection) bloque la suite de l'abonnement sur cet événement. Nouvel essai après 10 s, 20 s, 40 s… jusqu'à 1 h entre deux essais, sans limite de durée : la file reprend dans l'ordre dès que la banque répond. - Les redirections ne sont jamais suivies : seule l'URL enregistrée est appelée.
Catalogue (v1)
Montants en centimes, entiers. subject désigne l'enfant (child/<id>), la
demande (money_request/<id>), la mission (mission/<id>) ou le pot
(pot/<id>).
| Type | data |
|---|---|
TopUpReceived | amountCents, label, balanceCents — argent arrivé (recharge, demande, mission) |
TopUpPending | transferId, amountCents, label, purpose — virement demandé à la banque |
TopUpRejected | transferId, amountCents, label, purpose, reason |
MilestoneReached | milestoneCents, balanceCents |
PaymentSettled | amountCents, merchant, category, balanceCents |
PaymentDeclined | amountCents, merchant, reason |
RoundUpSwept | amountCents, potId, potAmountCents, balanceCents |
AuthorizationApproved / AuthorizationDeclined | idempotencyKey, amountCents, merchant, mcc, cardRef, reason |
RequestCreated | childId, amountCents, reason, emoji |
RequestApproved | childId, amountCents |
RequestDeclined | childId |
MissionCreated | childId, title, rewardCents |
MissionCompleted | childId |
MissionValidated | childId, rewardCents |
PotCreated | childId, name, emoji, targetCents |
PotDeposit / PotWithdraw | childId, amountCents, potAmountCents, balanceCents |
PotGoalReached | childId, targetCents |
PotsReordered | childId, potIds |
ChildCreated | childId, displayName, birthDate, mode |
CardIssued | issuer (carte émise chez l'émetteur, ou registre interne) |
CardFrozen / CardUnfrozen | issuerSynced (si un émetteur est branché) |
RulesChanged | les règles modifiées (daily_limit_cents, txn_limit_cents, blocked_categories, round_ups_enabled) |
BalanceMismatch / BalanceReconciled | issuerBalanceCents, magotBalanceCents, differenceCents |
Évolution : un champ peut être ajouté à un type v1 (la banque ignore
les champs inconnus) ; tout retrait ou changement de sens crée un type v2,
publié en parallèle pendant la transition.
Données personnelles : data contient des libellés saisis par la
famille (motif d'une demande, nom d'un pot, titre de mission). La banque
peut restreindre l'abonnement aux seuls types dont elle a besoin (--types).