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).
zhk_<48 hex chars>
# example: zhk_a1b2c3d4e5f6...Envoyer le jeton
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.
Réponses
[
{
"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{
"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
id,name, bot etrole.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.messageIddu parent, son author et un courtexcerpt. Sans lui, une réponse se lit comme une phrase sans sujet.attachments, et aucun texte n'est inventé pour combler le vide.Les retours en un appel
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.
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 :
curl https://zenhook.dev/api/channels/deploys/alerts \
-H "Authorization: Bearer zhk_..."Paramètres de requête
nextCursor dans la page précédente. Omettez-le pour la première page.info, success, warning, error.Réponses
{
"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.
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
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
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.