Recevez chaque incident sur votre endpoint.
Un POST JSON signé HMAC à chaque ouverture, mise à jour ou résolution. Intégration directe dans votre stack d'observabilité, sans dépendance à un client mail.
Évènements émis
Trois types couvrent le cycle de vie d'un incident. Aucun heartbeat, aucun event marketing, seulement les changements de statut réels.
incident.openedUn service passe en dégradé, en panne ou en maintenance.incident.updatedNote publique ajoutée par l'équipe pendant l'incident.incident.resolvedLe ou les services sont revenus en opérationnel.
En-têtes HTTP
Chaque requête arrive avec ces en-têtes. Le champ signature n'est présent que si la clé de signature est configurée côté Coffrify.
POST /your/endpoint HTTP/1.1
Host: ops.example.com
Content-Type: application/json
User-Agent: Coffrify-Status-Webhook/1.0
X-Coffrify-Event: incident.opened
X-Coffrify-Timestamp: 1717248000
X-Coffrify-Signature: t=1717248000,v1=5b8c…f3a2Format du payload
Le corps est un objet JSON compact. La clé message contient le dernier commentaire publié par l'équipe (peut être null à l'ouverture).
{
"type": "incident.opened",
"ts": "1717248000",
"incident": {
"id": "8c6a0c5e-…",
"slug": "eu-west-uploads-degraded",
"title": "Uploads dégradés en région eu-west",
"severity": "major",
"summary": "Latence accrue sur les uploads multipart depuis ~ 14:22 UTC.",
"affected_services": ["uploads", "api"],
"url": "https://status.coffrify.com/incident/eu-west-uploads-degraded"
},
"message": null
}Vérification de la signature
HMAC-SHA256 sur « timestamp.body » avec la clé partagée, en hexadécimal. Comparaison en temps constant avec la portion v1 de l'en-tête. Rejet si l'écart entre timestamp et l'heure courante dépasse 5 minutes (anti-replay).
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(rawBody: string, header: string, secret: string): boolean {
const m = /t=(\d+),v1=([0-9a-f]+)/.exec(header);
if (!m) return false;
const [, ts, sig] = m;
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const expected = createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex");
const a = Buffer.from(expected, "hex");
const b = Buffer.from(sig, "hex");
return a.length === b.length && timingSafeEqual(a, b);
}import hmac, hashlib, time
def verify(raw_body: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
ts, sig = parts.get("t"), parts.get("v1")
if not ts or not sig: return False
if abs(time.time() - int(ts)) > 300: return False
expected = hmac.new(
secret.encode(),
f"{ts}.{raw_body.decode()}".encode(),
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, sig)Canal Slack
En abonnant une URL hooks.slack.com, vous recevez à la place un message Block Kit optimisé pour la lecture en canal :
- En-tête coloré par sévérité.
- Sévérité + statut en deux colonnes monospace.
- Résumé de l'incident + dernière mise à jour.
- Bouton « Voir l'incident ».
Livraison & retry
Coffrify attend une réponse 2xx dans les 6 secondes. Pas de retry automatique pour l'instant : un endpoint indisponible manque l'évènement. Surveillez votre uptime et utilisez /incidents pour rattraper l'historique.