Recevoir des webhooks
Les webhooks vous poussent les événements en temps réel, au lieu de vous obliger à interroger l'API. Déclarez une URL, choisissez les événements qui vous intéressent et vérifiez chaque livraison grâce à sa signature HMAC.
S'abonner
Créez un abonnement via l'API Webhooks en indiquant l'URL de votre endpoint et les eventTypes à recevoir. Vous recevrez en retour un secret de signature : conservez-le ; il sert à vérifier chaque livraison.
curl -H "Authorization: Bearer vokse_sk_…" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -X POST https://api.vokse.ai/households/current/webhooks/subscriptions \ -d '{"url":"https://example.com/hooks/vokse","eventTypes":["transaction.created","budget.overrun"]}'Types d'événements
La liste complète et à jour des types d'événements est servie depuis /meta/webhook-events. Voici le catalogue actuel :
- transaction.created : une transaction a été enregistrée.
- recurrence.materialised : une récurrence a généré sa transaction planifiée.
- bank.sync.completed : une connexion bancaire a terminé sa synchronisation.
- budget.overrun : une catégorie a dépassé son budget du mois.
- spending.anomaly : une dépense inhabituelle a été détectée.
- goal.reached : un objectif d'épargne a été atteint.
- insight.generated : une nouvelle analyse IA est disponible.
Vérifier la signature
Chaque livraison transporte un en-tête X-Vokse-Signature de la forme t=<timestamp>,v1=<signature>. La signature est un HMAC-SHA256, calculé avec votre secret de signature, sur le timestamp, un point, puis le corps brut de la requête. Reconstituez cette chaîne à partir des octets exacts reçus, recalculez le HMAC, comparez-le à v1 en temps constant et rejetez les timestamps trop anciens.
import crypto from 'node:crypto';// X-Vokse-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256>function verify(rawBody, signatureHeader, signingSecret) { const parts = new Map( signatureHeader.split(',').map((kv) => kv.split('=')), ); const t = parts.get('t'); const v1 = parts.get('v1'); const expected = crypto .createHmac('sha256', signingSecret) .update(`${t}.${rawBody}`) // timestamp, a dot, the exact bytes received .digest('hex'); if (!t || !v1 || v1.length !== expected.length) return false; // freshness: reject stale timestamps to block replays if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));}Nouvelles tentatives et livraison
Répondez en 2xx en quelques secondes pour accuser réception. Les réponses 5xx et les timeouts sont réessayés avec un backoff exponentiel, jusqu'à cinq tentatives ; une réponse 4xx est considérée comme définitive et n'est jamais réessayée. Après plusieurs échecs consécutifs, l'abonnement est automatiquement mis en pause et le propriétaire du foyer en est notifié.