Zum Inhalt springen

Webhooks

Nur ausgehend. Opini sendet einen POST mit JSON-Body an eine URL, die dir gehört, sobald etwas Wichtiges passiert: Ein Roadmap-Eintrag wird ausgeliefert, ein Kommentar wartet, ein Release erscheint, eine Rückfrage wird beantwortet. Füg eine Discord-Webhook-URL ein, und Nachrichten landen ohne eine Zeile Code in deinem Kanal.

Was sie sind

Drei häufige Wünsche, die Webhooks direkt erfüllen:

  • „Sag meinem Discord-Kanal Bescheid, wenn ein neuer Kommentar auf Freigabe wartet.“
  • „Starte meine Deploy-Pipeline, wenn wir ein Release veröffentlichen.“
  • „Benachrichtige den Support-Kanal, wenn eine Rückfrage beantwortet wird.“

Immer derselbe Baustein: Opini, ruf diese URL auf, wenn X passiert, mit JSON, das ich lesen kann. Webhooks gelten pro Projekt, höchstens 10 pro Projekt.

Einen anlegen

Öffne im Dashboard Einstellungen → Webhooks. Füll aus:

  • URL: https:// oder http:// (aber bitte https://). Keine Zugangsdaten in der URL.
  • Name: etwas Lesbares, z. B. ops-discord oder deploy-pipeline. Erscheint in der Webhook-Liste und im Zustellungsverlauf.
  • Events: wähl die gewünschten Arten, gruppiert nach Eintrag (Kommentare, Roadmap-Einträge, Releases, Rückfragen, Feedback).
  • Discord-kompatibel: einschalten, wenn die URL ein Discord-Kanal-Webhook ist. Siehe unten.
  • Signatur-Geheimnis: (optional) erzeug eines, um Anfragen mit HMAC-SHA256 zu signieren. Wird beim Anlegen einmal gezeigt; bei Verlust neu erzeugen.

Ein Button Test-Event senden in jeder Zeile schickt ein Beispiel-Event an die URL, damit du prüfen kannst, ob sie erreichbar ist, bevor du dich darauf verlässt.

Events

Erste Liste; unbekannte Arten bekommen beim Anlegen ein 422:

ArtWird ausgelöst, wenn
comment.pendingEin neuer Kommentar auf Moderation wartet.
comment.approvedEin Admin einen Kommentar freigibt.
comment.rejectedEin Kommentar abgelehnt wird.
umbrella.createdEin Roadmap-Eintrag angelegt wird (Entwurf oder veröffentlicht).
umbrella.movedEin Roadmap-Eintrag die Statusspalte wechselt.
umbrella.shippedDie Zielspalte „ausgeliefert“ oder „erledigt“ ist. Zusätzlich zu umbrella.moved.
umbrella.publishedEin Roadmap-Eintrag zum ersten Mal öffentlich wird (erscheint in der öffentlichen Roadmap-API).
umbrella.unpublishedEin Roadmap-Eintrag von der öffentlichen Roadmap genommen wird.
release.publishedEin Release veröffentlicht wird.
release.unpublishedEin Release offline genommen wird.
follow_up.askedEin Admin eine Rückfrage sendet.
follow_up.answeredDie Person auf eine Rückfrage antwortet.
feedback.receivedNeues Feedback in der Triage landet (Widget oder API).

Webhooks sehen nur Events nach ihrer Erstellung, nichts rückwirkend. Das ist Absicht: Monate an Änderungen an eine frisch abonnierte URL nachzuspielen, will fast nie jemand.

Aufbau der Daten

Der Rohmodus ist Standard. Jede Anfrage hat denselben Umschlag; das Objekt data hängt von der Event-Art ab.

json
{
  "event_id":    "01JSAE...",
  "event_kind":  "comment.pending",
  "occurred_at": "2026-04-24T07:03:11Z",
  "project": { "id": "prj_...", "slug": "acme" },
  "entity": {
    "kind": "comment",
    "id":   "cmt_...",
    "url":  "https://opini.dev/app/orgs/<org>/projects/<project>/moderation"
  },
  "data": {
    "body":           "This is the comment body...",
    "umbrella_id":    "umb_...",
    "umbrella_title": "Dark mode",
    "author_name":    "anon-dolphin"
  }
}

Discord-kompatibler Modus

Schalte Discord-kompatibel ein, und die Daten werden zu {content, embeds}, dem Format, das Discords Webhook-API erwartet. Keine Middleware nötig.

json
{
  "content": "New comment pending approval on **Dark mode**",
  "embeds": [{
    "title": "Dark mode",
    "description": "This is the comment body, truncated to 300 chars...",
    "url": "https://opini.dev/app/orgs/<org>/projects/<project>/moderation",
    "color": 16730759
  }]
}

Die Farben hängen von der Art ab: wartende Kommentare bernstein, Freigaben grün, ausgelieferte Einträge violett, alles andere im Markenblau. Beschreibungen sind auf 300 Zeichen begrenzt (Discord erlaubt 4096, wir bleiben kurz, damit das Embed überschaubar bleibt).

Signatur und Header

Wenn du ein Signatur-Geheimnis einrichtest, trägt jede Anfrage:

  • X-Opini-Signature: sha256=<hex>: HMAC-SHA256 des rohen Bodys, mit dem Geheimnis als Schlüssel.
  • X-Opini-Event: <event_kind>: die Event-Art, für schnelles Routing.
  • X-Opini-Delivery: <delivery_id>: eine eindeutige ID pro Zustellversuch. Nutz sie, um Wiederholungen beim Empfänger zu erkennen.

Discord prüft diese Header nicht, sie stören bei einem Discord-kompatiblen Webhook also nicht. Ein neues Geheimnis erzeugt einen neuen Wert; der alte gilt sofort nicht mehr.

Zustellungsverlauf

Klick auf eine Webhook-Zeile, und ein Seitenbereich zeigt die letzten 100 Zustellversuche. Jede Zeile zeigt Event-Art, Status (2xx grün, 4xx bernstein, 5xx oder Netzwerkfehler rot), Dauer und wie lange es her ist. Aufgeklappt siehst du eine Zusammenfassung von Anfrage und Antwort.

Versuche jenseits der letzten 100 werden automatisch gelöscht: Das ist kein vollständiges Audit-Log, sondern ein Blick auf „was in den letzten Stunden passiert ist“.

Wiederholungen und Limits

  • 3 Versuche, exponentiell verzögert. 1 s → 4 s → 16 s. Nach drei Versuchen vermerkt Opini die fehlgeschlagene Zustellung und macht weiter.
  • 5 Sekunden Timeout pro Anfrage. Ein langsamer Endpunkt zählt als Fehler.
  • 10 Webhooks pro Projekt. Brauchst du mehr, fass zusammen: Die meisten Teams landen bei Chat, Pipeline und einem Debug-Endpunkt.
  • Deaktivierte Webhooks werden übersprungen. Schalte einen Webhook beim Debuggen lieber aus, statt ihn zu löschen: Der Zustellungsverlauf bleibt.

Webhooks feuern bei Änderungen an Kommentaren, Roadmap-Einträgen, Releases und Rückfragen.