Webhooks de la feuille de route

Abonnez votre service aux changements de la feuille de route publique Nexus AI. Quand une fonctionnalité est livrée, activée ou désactivée, nous envoyons un POST signé à votre endpoint — en temps réel, plutôt que de poller le flux RSS.

Événements

Vous choisissez les types à recevoir à l’inscription.

  • flag.rolled_out — la fonctionnalité atteint 100 % des clients.
  • flag.enabled — activée en déploiement progressif (partiel).
  • flag.disabled — désactivée en production.

Structure du payload

{
  "id": "evt_lq8x3a_marketplace.public",
  "type": "flag.rolled_out",
  "created_at": "2026-05-27T14:00:00.000Z",
  "data": {
    "flag_key": "marketplace.public",
    "status": "launched",
    "rollout_percentage": null,
    "reason": "GA",
    "url": "https://nexus-os.ca/roadmap#marketplace.public"
  }
}

En-têtes : X-Nexus-Event, X-Nexus-Event-Id, X-Nexus-Signature.

Vérifier la signature

X-Nexus-Signature vaut sha256=<hex> où le hex estHMAC-SHA256(corps_brut, votre_secret). Comparez en temps constant. Le secret (whsec_…) vous est montré une seule fois à la création de l’abonnement.

Node.js (Express)
import crypto from 'crypto';

// Express raw-body handler — Nexus signs the EXACT bytes it sent.
app.post('/webhooks/nexus', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.header('X-Nexus-Signature');        // "sha256=<hex>"
  const expected = 'sha256=' + crypto
    .createHmac('sha256', process.env.NEXUS_WEBHOOK_SECRET)  // whsec_...
    .update(req.body)                                        // raw Buffer
    .digest('hex');

  const ok = signature && crypto.timingSafeEqual(
    Buffer.from(signature), Buffer.from(expected),
  );
  if (!ok) return res.status(401).send('bad signature');

  const event = JSON.parse(req.body.toString('utf8'));
  // event.type: 'flag.rolled_out' | 'flag.enabled' | 'flag.disabled'
  console.log(event.type, event.data.flag_key, event.data.status);
  res.sendStatus(200);
});
Python (Flask)
import hmac, hashlib, os
from flask import Flask, request, abort

app = Flask(__name__)

@app.post("/webhooks/nexus")
def nexus_webhook():
    raw = request.get_data()                       # exact bytes
    signature = request.headers.get("X-Nexus-Signature", "")
    expected = "sha256=" + hmac.new(
        os.environ["NEXUS_WEBHOOK_SECRET"].encode(),
        raw, hashlib.sha256,
    ).hexdigest()

    if not hmac.compare_digest(signature, expected):
        abort(401)

    event = request.get_json()
    # event["type"]: flag.rolled_out | flag.enabled | flag.disabled
    print(event["type"], event["data"]["flag_key"], event["data"]["status"])
    return "", 200

Important : signez le corps brut reçu, pas un JSON re-sérialisé — la ré-sérialisation change les octets et invalide la signature.

Réessais & fiabilité

  • Répondez 2xx sous quelques secondes pour confirmer la réception.
  • En cas d’échec, nous réessayons avec backoff exponentiel : 5 min → 30 min → 2 h → 6 h (5 tentatives).
  • Après épuisement des tentatives, l’abonnement est automatiquement suspendu — recréez-le une fois votre endpoint réparé.
  • Chaque livraison porte le même X-Nexus-Event-Id : traitez-le de façon idempotente.