Lese-API

Der Webhook-Endpunkt ist öffentlich und kann nur schreiben, so senden deine Apps Alerts hinein. Um Alerts wieder auszulesen (für eine CLI, einen Sync mit einem anderen Tool, die Anbindung an ein Dashboard), nutze die authentifizierte API mit einem Bearer-Token.

Authentifizierung

Alle Lese-Endpunkte brauchen einen Bearer-Token. Ein Token ist an genau ein Paar (Nutzer, Workspace) gebunden; der Channel-Zugriff des Nutzers (auch auf private Channels, zu denen er gehört) wird automatisch übernommen.

Token erzeugen

In der Web-App: Einstellungen → API-Tokens → Neuer Token. Der vollständige Token wird beim Erstellen einmal angezeigt, kopiere ihn sofort. Zenhook speichert nur einen SHA-256-Hash, ein verlorener Token lässt sich also nicht wiederherstellen (widerrufe ihn und erstelle einen neuen).

Token-Format
zhk_<48 Hex-Zeichen>
# Beispiel: zhk_a1b2c3d4e5f6...

Token senden

bash
curl https://zenhook.dev/api/channels \
  -H "Authorization: Bearer zhk_..."

Channels auflisten

Gibt die Channels zurück, auf die der Nutzer des Tokens zugreifen kann (jeden öffentlichen Channel und jeden privaten Channel, in dem er ausdrücklich Mitglied ist). Jeder Channel enthält ein Feld _count.alerts mit der persönlichen Zahl ungelesener Alerts des Nutzers.

GEThttps://zenhook.dev/api/channels

Antworten

200 OK
json
[
  {
    "id": "clx_chan_1",
    "name": "production-errors",
    "slug": "production-errors",
    "icon": "🔴",
    "isPrivate": false,
    "webhookToken": "abc123...",
    "_count": { "alerts": 3 }
  }
]

Alerts eines Channels auflisten

Seitenweise, die neuesten zuerst. Jeder Alert enthält einen Boolean isRead, berechnet für den aufrufenden Nutzer; einen Alert als gelesen zu markieren, betrifft nur deinen eigenen Status.

GEThttps://zenhook.dev/api/channels/{id oder slug}/alerts

Nutze den slug des Channels statt seiner ID und lies einen Channel mit einem einzigen Aufruf über seinen Namen, ohne vorher etwas nachzuschlagen:

bash
curl https://zenhook.dev/api/channels/deploys/alerts \
  -H "Authorization: Bearer zhk_..."

Query-Parameter

cursorstring
Alert-ID, die auf der vorherigen Seite als nextCursor zurückkam. Lass sie für die erste Seite weg.
limitnumber
1 bis 100. Standard ist 50.
levelenum
Filter nach Schweregrad: info, success, warning, error.
afterstring
Alert-ID. Gibt nur neuere Alerts zurück, gedacht für Polling.

Antworten

200 OK
json
{
  "alerts": [
    {
      "id": "clx_alert_1",
      "channelId": "clx_chan_1",
      "title": "Build fehlgeschlagen",
      "level": "ERROR",
      "emoji": "🔴",
      "message": "npm install nach 300 s abgebrochen",
      "fields": [{ "label": "Branch", "value": "main" }],
      "linkUrl": "https://github.com/org/repo/actions/runs/123",
      "isRead": false,
      "createdAt": "2026-04-27T14:32:11.000Z"
    }
  ],
  "nextCursor": "clx_alert_42",
  "hasMore": true
}

Als gelesen markieren

Der Lesestatus gilt pro Nutzer. Einen Alert als gelesen zu markieren, legt eine Zeile für den Nutzer des Tokens an; die Zähler der anderen Mitglieder des Workspaces bleiben unverändert.

PATCHhttps://zenhook.dev/api/alerts/{id}
bash
curl -X PATCH https://zenhook.dev/api/alerts/clx_alert_1 \
  -H "Authorization: Bearer zhk_..." \
  -H "Content-Type: application/json" \
  -d '{ "isRead": true }'

Alle Alerts als gelesen markieren

POSThttps://zenhook.dev/api/alerts/mark-all-read

Der Body ist optional. Gib { "channelId": "..." } an, um es auf einen Channel zu begrenzen; lass ihn weg, um jeden zugänglichen Channel als gelesen zu markieren. Idempotent, eine Wiederholung ändert nichts.

Einen einzelnen Alert abrufen

GEThttps://zenhook.dev/api/alerts/{id}

Gibt denselben Aufbau wie der Listen-Endpunkt zurück, dazu name / slug des Channels.

Fehler

401 Unauthorized: Bearer-Token fehlt oder ist ungültig, oder der Nutzer des Tokens ist kein Mitglied des Workspaces mehr. Der Body nennt den Grund, du musst also nie raten:

json
{
  "error": "Unauthorized",
  "reason": "token_env_var_unset",
  "message": "The client sent the literal string \"undefined\", so the variable holding it is unset. Node does not read a .env file on its own: run node --env-file=.env your-script.mjs, or export the variable before running it.",
  "docs": "https://zenhook.dev/de/docs/api/read"
}
  • no_credentials: gar kein Authorization-Header.
  • malformed_authorization_header: Der Header ist nicht Bearer <token>.
  • token_env_var_unset: Dein Client hat einen leeren Token oder wörtlich undefined gesendet. Die Variable mit dem Token ist nicht gesetzt.
  • invalid_token_format: Der Token ist nicht zhk_ + 48 Hex-Zeichen.
  • unknown_token: Der Token wurde widerrufen oder beim Kopieren abgeschnitten.
  • not_a_workspace_member: Der Token ist gültig, aber sein Nutzer hat den Workspace verlassen.

404 Not Found: Die Ressource existiert nicht oder der Nutzer des Tokens hat keinen Zugriff (z. B. ein privater Channel, in dem er nicht ist). Beide Fälle sehen absichtlich gleich aus, damit Token-Inhaber private Channels nicht durchprobieren können.

429 Too Many Requests: Limit erreicht. Warte und versuche es erneut.