API de lecture

Le point de terminaison webhook est public et en écriture seule, c'est ainsi que vos applications poussent les alertes vers Zenhook. Pour relire les alertes (créer une CLI, synchroniser avec un autre outil, intégrer un tableau de bord), utilisez l'API authentifiée avec un jeton Bearer.

Authentification

Tous les points de terminaison de lecture nécessitent un jeton Bearer. Les jetons sont limités à une seule paire(utilisateur, espace de travail) : l'accès aux canaux de l'utilisateur (y compris les canaux privés dont il fait partie) est hérité automatiquement.

Générer un jeton

Depuis le tableau de bord : Paramètres → Jetons API → Nouveau jeton. Le jeton complet n'est affiché qu'une seule fois à la création, copiez-le immédiatement. Zenhook ne stocke qu'un hachage SHA-256, donc un jeton perdu ne peut pas être récupéré (révoquez-le et créez-en un nouveau).

Format du jeton
zhk_<48 hex chars>
# example: zhk_a1b2c3d4e5f6...

Envoyer le jeton

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

Lister les canaux

Renvoie les canaux auxquels l'utilisateur du jeton peut accéder (tous les canaux publics ainsi que tout canal privé dont il est explicitement membre). Chaque canal inclut un champ_count.alerts contenant son nombre personnel de messages non lus.

GEThttps://zenhook.dev/api/channels

Réponses

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

Canaux Discord

Un canal connecté à Discord renvoie les mêmes objets alerte, plus trois champs qui permettent à un agent de reconstituer la conversation. C'est la forme à lire quand vous voulez qu'une IA collecte les retours d'une communauté.

Nouveau ? Lisez le guide
json
{
  "id": "clx_alert_1",
  "message": "Le fait de pouvoir activer finement les notifications...",
  "createdAt": "2026-07-19T17:29:14.439Z",
  "author":  { "id": "1108...", "name": "Heri", "bot": false, "role": "member" },
  "replyTo": { "messageId": "1528...", "author": "Ayk", "excerpt": "..." },
  "attachments": [{ "url": "https://cdn.discordapp.com/...", "mime": "image/png" }]
}

Champs supplémentaires

authorobject
Qui a écrit le message : id,name, bot etrole.
author.rolestring
owner désigne la personne qui gère le serveur Discord : ses messages sont la voix de l'éditeur, pas un retour utilisateur.bot désigne un bot ou un webhook.member désigne tous les autres, et c'est le vrai retour utilisateur. Filtrez dessus avant de compter ou de résumer quoi que ce soit.
replyToobject | null
Présent quand le message est une réponse : le messageIddu parent, son author et un courtexcerpt. Sans lui, une réponse se lit comme une phrase sans sujet.
messagestring | null
Le texte tel quel, avec les mentions Discord résolues en noms. Null quand le message ne contient qu'un fichier : la pièce jointe est dansattachments, et aucun texte n'est inventé pour combler le vide.

Les retours en un appel

bash
curl -s "https://zenhook.dev/api/channels/feedback/alerts?limit=50" \
  -H "Authorization: Bearer zhk_..." \
  | jq '[.alerts[] | select(.author.role == "member")]'

Lister les alertes d'un canal

Paginé, du plus récent au plus ancien. Chaque alerte inclut un booléen isRead calculé pour l'utilisateur appelant, marquer une alerte comme lue n'affecte que votre propre état.

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

Utilisez le slug du canal plutôt que son id et lisez un canal par son nom en un seul appel, sans rien à chercher au préalable :

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

Paramètres de requête

cursorstring
ID d'alerte renvoyé comme nextCursor dans la page précédente. Omettez-le pour la première page.
limitnumber
1-100. Par défaut 50.
levelenum
Filtrer par niveau : info, success, warning, error.
afterstring
ID d'alerte. Renvoie les alertes strictement plus récentes, utilisé pour le polling.

Réponses

200 OK
json
{
  "alerts": [
    {
      "id": "clx_alert_1",
      "channelId": "clx_chan_1",
      "title": "Build Failed",
      "level": "ERROR",
      "emoji": "🔴",
      "message": "npm install timed out after 300s",
      "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
}

Marquer comme lu

L'état de lecture est propre à chaque utilisateur. Marquer une alerte comme lue insère une ligne limitée à l'utilisateur du jeton, les nombres de messages non lus des autres membres de l'espace de travail ne sont pas affectés.

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 }'

Marquer toutes les alertes comme lues

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

Le corps est facultatif. Passez { "channelId": "..." } pour limiter à un seul canal ; omettez-le pour marquer comme lus tous les canaux accessibles. Idempotent, relancer est sans effet.

Récupérer une seule alerte

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

Renvoie la même structure d'alerte que le point de terminaison de liste, plus le name / slug du canal.

Erreurs

401 Unauthorized, jeton Bearer manquant ou invalide, ou l'utilisateur du jeton n'est plus membre de l'espace de travail.

404 Not Found, la ressource n'existe pas ou l'utilisateur du jeton ne peut pas y accéder (par exemple un canal privé dont il n'est pas membre). Les deux cas sont confondus volontairement afin que les détenteurs de jeton ne puissent pas énumérer les canaux privés.

429 Too Many Requests, limite de débit atteinte. Patientez puis réessayez.