Webhooks
Recevez les events de votre tenant en push HTTP — catalogue, vérification de signature HMAC-SHA256, retries, replay.
Les webhooks Architecture Platform livrent en push HTTP les événements qui se produisent dans votre tenant (création d'application, mise à jour, soumission de DAS…). Ils suppriment le besoin de polling sur l'API publique et permettent des intégrations temps-réel avec vos systèmes downstream (n8n, Zapier, Slack via middleware, ETL custom).
Catalogue d'événements (V1)
Trois event types initiaux, couvrant ~80 % des cas d'usage :
| Event type | Quand | Payload data |
|---|---|---|
application.created | Une Business Application est créée dans le référentiel | { code, name, domaine, type, status } |
application.updated | Au moins un champ d'une application a changé | { code, changed_fields: [...] } |
das.submitted | Un Document d'Architecture Synthétique est soumis | { das_id, app_code } |
D'autres events (notice.published, session.scheduled, agent.created, etc.) sont sur la roadmap — ouvrez une demande sur le portail si vous avez besoin de l'un d'eux en priorité.
Configuration côté tenant
Un tenant-admin enregistre une subscription par endpoint :
Format du payload
Chaque requête POST envoie un body JSON enveloppé, calqué sur les conventions Stripe / GitHub :
{
"id": "evt_550e8400-e29b-41d4-a716-446655440000",
"type": "application.created",
"created_at": "2026-06-25T10:00:00Z",
"data": {
"code": "BAP-001",
"name": "Salesforce Sales Cloud",
"domaine": "CRM",
"type": "Application transverse",
"status": "ACTIVE"
}
}Headers HTTP
Chaque requête POST sortante transporte cinq headers :
| Header | Description |
|---|---|
Content-Type | application/json |
X-Arch-Signature | hex digest HMAC-SHA256 — voir vérification ci-dessous |
X-Arch-Timestamp | epoch seconds UTC du signing (anti-replay) |
X-Arch-Event | le event_type (ex. application.created) |
X-Arch-Event-Id | UUID idempotency key — identique pour toutes les subscriptions du même event domain |
X-Arch-Delivery-Id | UUID de cette tentative spécifique (utile pour log / support) |
Vérification de la signature
Crucial. Sans vérification, n'importe qui peut envoyer une fausse requête sur votre endpoint.
L'algorithme : HMAC-SHA256(secret, timestamp + "." + body), encodé en hex. Identique au format des webhooks Stripe.
Node.js (TypeScript)
import crypto from "crypto";
import express from "express";
const app = express();
const SECRET = process.env.ARCH_WEBHOOK_SECRET!;
// IMPORTANT : récupérer le body brut, pas le JSON parsé,
// sinon la signature ne match plus (ordre des clés, espacement).
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.header("X-Arch-Signature") ?? "";
const timestamp = req.header("X-Arch-Timestamp") ?? "";
const body = req.body.toString("utf8");
// Anti-replay : refuser tout timestamp > 5 min de drift.
const drift = Math.abs(Date.now() / 1000 - Number(timestamp));
if (drift > 300) return res.status(401).send("timestamp drift");
const expected = crypto
.createHmac("sha256", SECRET)
.update(`${timestamp}.${body}`)
.digest("hex");
// Comparaison en temps constant — évite les timing attacks.
const sigBuf = Buffer.from(signature, "hex");
const expBuf = Buffer.from(expected, "hex");
if (sigBuf.length !== expBuf.length || !crypto.timingSafeEqual(sigBuf, expBuf)) {
return res.status(401).send("bad signature");
}
const event = JSON.parse(body);
console.log("Received event:", event.type, event.id);
res.status(200).send("ok");
});Python (Flask)
import hmac, hashlib, os, time
from flask import Flask, request
app = Flask(__name__)
SECRET = os.environ["ARCH_WEBHOOK_SECRET"]
@app.post("/webhook")
def webhook():
signature = request.headers.get("X-Arch-Signature", "")
timestamp = request.headers.get("X-Arch-Timestamp", "0")
body = request.get_data(as_text=True)
# Anti-replay
if abs(time.time() - int(timestamp)) > 300:
return "timestamp drift", 401
expected = hmac.new(
SECRET.encode(),
f"{timestamp}.{body}".encode(),
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(signature, expected):
return "bad signature", 401
event = request.get_json(force=True)
print(f"Received event: {event['type']} {event['id']}")
return "ok", 200Toujours valider la signature avant de traiter le payload. Un endpoint webhook public sans vérification est une porte d'entrée pour de l'injection arbitraire dans votre système downstream.
Idempotence
Chaque event domain produit un seul X-Arch-Event-Id — partagé entre les subscriptions si vous en avez plusieurs. Stockez l'event_id côté consommateur et ignorez les replays (même event_id déjà traité).
CREATE TABLE webhook_events_received (
event_id VARCHAR(64) PRIMARY KEY,
event_type VARCHAR(64) NOT NULL,
received_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);Retries automatiques
Si votre endpoint ne renvoie pas un 2xx (timeout, 4xx, 5xx), Architecture Platform retry avec un backoff exponentiel facteur 5 :
| Tentative | Délai après l'échec précédent |
|---|---|
| 1 (immédiat) | — |
| 2 | 1 min |
| 3 | 5 min |
| 4 | 25 min |
| 5 | 2 h 05 |
| 6 | 10 h 25 |
Au bout de 6 tentatives échouées, l'event passe en status EXHAUSTED (terminal) — il n'est plus retenté automatiquement. Vous pouvez le replay manuellement depuis /admin/webhooks (timeline → bouton « Replay »).
Auto-disable
Après 10 échecs consécutifs sur une même subscription (quel que soit l'event), la subscription passe enabled=false automatiquement pour éviter le DDoS accidentel d'un endpoint cassé. Le tenant-admin doit la ré-activer explicitement après avoir corrigé l'endpoint cible.
Replay manuel
Depuis /admin/webhooks, la timeline « Livraisons récentes » liste les 50 derniers events. Le bouton Replay par ligne :
- Repasse l'event en status
PENDING - Tente immédiatement la delivery (sans attendre le prochain tick scheduler)
- Met à jour le status (DELIVERED / FAILED)
Use case : votre endpoint était KO 30 min pendant une fenêtre de maintenance, vous le ré-activez et voulez ré-envoyer les events manqués sans attendre que le backoff exponentiel les rattrape.
Bonnes pratiques
- Toujours répondre rapidement (200 OK en < 5 s) — votre endpoint doit accuser réception puis traiter en arrière-plan. Sinon vous risquez un timeout côté Architecture Platform (read timeout = 15 s).
- Logguer le
X-Arch-Delivery-Id— permet à notre support de cross-référencer une tentative depuis votre log si problème. - Tester en local avec smee.io ou ngrok — tunneler vers
localhostpour développer la vérification de signature avant deploy. - Endpoint dédié par event type si la logique métier diverge fortement (sinon un seul endpoint avec un
switchsurevent.typeest plus simple).
Roadmap
- v0.1.78 — events additionnels :
notice.published,session.scheduled,agent.created,agent.updated. - v0.1.79 — filtres avancés côté subscription (par domaine, par code application).
- v0.2 — webhooks "système" globaux pour platform-admins (cross-tenant) :
tenant.created,subscription.activated, etc.