Status · webhooks

Jeden Vorfall direkt an Ihren Endpoint.

Signierter JSON-POST bei jedem Vorfall. Direkt in Ihren Observability-Stack.

Abonnieren

Events

Drei Typen decken den Lebenszyklus eines Vorfalls.

  • incident.openedDienst wechselt auf beeinträchtigt, ausgefallen oder Wartung.
  • incident.updatedÖffentliche Notiz vom Team während des Vorfalls.
  • incident.resolvedBetroffene Dienste wieder betriebsbereit.

HTTP-Header

Jede Anfrage enthält folgende Header.

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…f3a2

Payload-Form

Kompaktes JSON-Objekt.

{
  "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
}

Signatur prüfen

HMAC-SHA256 über `timestamp.body`. Konstantzeitvergleich. Replay bei Drift > 5min.

Node.js / TypeScript
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);
}
Python
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)

Slack-Kanal

Bei einer hooks.slack.com-URL erhalten Sie eine Block-Kit-Nachricht:

  • Header farbig nach Schweregrad.
  • Severity + Status.
  • Zusammenfassung + Update.
  • Button zum Vorfall.

Auslieferung & Retry

2xx innerhalb von 6s erwartet. Kein automatisches Retry.

2xx · 6 s · no retry