Aller au contenu
Obtenir une clé

Démarrer

Webhooks

Nodium vous appelle quand quelque chose se passe. Signé, repris, journalisé.

Ce que vous recevez

JSON

{ "id": "evt_5f1c0a9e2b7d4c3a8e6f1b2c3d4e5f60", "event": "message.received", "workspace_id": "…", "occurred_at": "2026-09-18T09:12:44.120Z", "data": { "message_id": "…", "conversation_id": "…", "contact_id": "…", "channel_type": "whatsapp", "type": "text", "text": "Hello, is my order ready?" }}
  • id est l'identifiant de l'événement : il reste le même quand une livraison est reprise ou relivrée. Dédoublonnez dessus.
  • En-têtes : X-Nodium-Event (le nom de l'événement), X-Nodium-Delivery (cette livraison), X-Nodium-Signature.
  • Répondez un 2xx en moins de 10 secondes. Faites le travail ensuite.

Les événements

Vérifier la signature

X-Nodium-Signature: t=<secondes>,v1=<hex>. La signature vaut HMAC-SHA256(secret, "<t>.<corps brut>"). Pendant un changement de secret, l'en-tête porte deux v1= — acceptez l'appel si l'une correspond. Refusez un appel de plus de 5 minutes.

Node.js

import crypto from 'node:crypto'// rawBody: the request body exactly as received, before any JSON parsing.export function verifyNodium(rawBody, header, secret) { const parts = header.split(',') const t = parts.find(p => p.startsWith('t='))?.slice(2) const signatures = parts.filter(p => p.startsWith('v1=')).map(p => p.slice(3)) if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex') return signatures.some(sig => sig.length === expected.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)))}

Python

import hmac, hashlib, timedef verify_nodium(raw_body: bytes, header: str, secret: str) -> bool: parts = header.split(",") t = next((p[2:] for p in parts if p.startswith("t=")), None) signatures = [p[3:] for p in parts if p.startswith("v1=")] if not t or abs(time.time() - int(t)) > 300: return False expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest() return any(hmac.compare_digest(sig, expected) for sig in signatures)

Reprises, journal, relivraison

  • Un appel qui échoue ou ne répond pas 2xx est repris après 1 min, 5 min, 30 min, 2 h et 12 h — six essais en tout — puis marqué failed.
  • GET /webhooks/deliveries liste chaque livraison avec ce que votre serveur a répondu et l'erreur. C'est ce qui tranche « on n'a rien reçu ».
  • POST /webhooks/deliveries/{id}/redeliver la renvoie, même charge, même id.
  • POST /webhooks/{id}/rotate-secret donne un nouveau secret ; l'ancien signe encore 24 h, le temps de déployer sans perdre d'appel.
  • POST /webhooks/{id}/test envoie tout de suite un appel d'essai signé et dit ce qui est revenu.