Leitfaden
Webhooks: 22 Ereignisse, signiert zugestellt
Welche Ereignisse Zuuna verschickt, wie die Signatur geprüft wird (HMAC-SHA256 über den Rohbody) und was bei fehlgeschlagenen Zustellungen passiert.
Webhooks sind die Gegenrichtung zur API: Statt dass dein Skript alle paar Minuten fragt, ob sich etwas geändert hat, ruft Zuuna dich an, sobald es passiert. Für einen Chat-Bot, eine Pipeline oder ein n8n-Workflow ist das der Unterschied zwischen „läuft sofort“ und „läuft irgendwann“.
Was ein Ereignis auslöst
Du hinterlegst eine URL und wählst die Ereignisse, die dich interessieren. Passiert eines davon, schickt Zuuna einen POST mit JSON-Body an diese URL — signiert, damit du prüfen kannst, dass er wirklich von uns kommt.
Der Ereignis-Katalog
22 Ereignisse in fünf Gruppen:
| Ereignis | Bedeutung |
|---|---|
card.created | Karte angelegt |
card.moved | Karte in eine andere Spalte bewegt |
card.assignee_added | Jemand wurde zugewiesen |
card.label_added | Epic zugeordnet |
card.priority_changed | Priorität geändert |
card.due_approaching | Fälligkeit rückt näher |
card.due_arrived | Fälligkeit erreicht |
card.comment_added | Kommentar geschrieben |
card.archived | Karte archiviert |
card.restored | Karte wiederhergestellt |
card.deleted | Karte gelöscht |
git.branch_created | Branch angelegt |
git.commit_pushed | Commit verknüpft |
git.pr_opened | Pull Request geöffnet |
git.pr_merged | Pull Request gemerged |
ci.passed | Build erfolgreich |
ci.failed | Build fehlgeschlagen |
time.logged | Zeit gebucht |
release.created | Release angelegt |
release.published | Release veröffentlicht |
release.unpublished | Veröffentlichung zurückgenommen |
release.deleted | Release gelöscht |
Die Header
Jede Zustellung trägt drei Header: X-Zuuna-Event mit dem Namen des Ereignisses, X-Zuuna-Delivery mit einer eindeutigen ID für genau diese Zustellung, und X-Zuuna-Signature mit der Signatur.
Signatur prüfen
Die Signatur ist ein HMAC-SHA256 über den Rohbody, mit dem Secret des Endpunkts als Schlüssel, im Format sha256=<hex>.
# Node — verify X-Zuuna-Signature against the RAW body
import { createHmac, timingSafeEqual } from "crypto";
function verify(rawBody, header, secret) {
const expected = "sha256=" + createHmac("sha256", secret)
.update(rawBody) // the raw bytes, NOT JSON.parse'd and re-stringified
.digest("hex");
const a = Buffer.from(header ?? "", "utf8");
const b = Buffer.from(expected, "utf8");
return a.length === b.length && timingSafeEqual(a, b);
}
Über den Rohbody, nicht über neu serialisiertes JSON. Wer den Body parst und wieder zu JSON macht, ändert womöglich Schlüsselreihenfolge oder Leerzeichen — die Signatur stimmt dann nie, und der Fehler sieht aus wie ein falsches Secret. Und vergleiche zeitkonstant, nicht mit ===.
Wiederholungen und Fehler
Antworte mit 2xx, sobald du den Body entgegengenommen hast — nicht erst, wenn deine Verarbeitung fertig ist. Fehlgeschlagene Zustellungen werden wiederholt; was tatsächlich rausging und was zurückkam, steht im Zustellprotokoll in der App. Zum Ausprobieren gibt es einen Test-Aufruf, der eine Beispiel-Zustellung an deine URL schickt.
Weiter
Die REST-API ist die Abfragerichtung, die CLI deckt den Git-Fall fertig ab. Für Zapier, Make oder n8n brauchst du keine eigene Integration — eine URL und ein Secret genügen; siehe Integrationen.
Häufige Fragen
Wie prüfe ich, dass ein Webhook wirklich von Zuuna kommt?
Über den Header X-Zuuna-Signature: ein HMAC-SHA256 über den Rohbody mit dem Secret des Endpunkts, im Format sha256=hex. Wichtig ist der ROHE Body — wer ihn parst und neu serialisiert, bekommt nie eine passende Signatur.
Welche Ereignisse gibt es?
22 Stück, gruppiert nach Karte (angelegt, bewegt, zugewiesen, kommentiert, archiviert …), Git (Branch, Commit, PR geöffnet und gemerged), CI (bestanden, fehlgeschlagen), Zeit und Release.
Was passiert, wenn mein Endpunkt gerade nicht erreichbar ist?
Die Zustellung wird wiederholt. Was rausging und was zurückkam, steht im Zustellprotokoll in der App — inklusive Statuscode und Antwortkörper.
Brauche ich für Zapier oder n8n eine eigene Integration?
Nein. Beide nehmen einen signierten Webhook entgegen und rufen die REST-API auf. Eine URL, ein Secret und die Ereignisse, die dich interessieren.