Référence API
Un seul endpoint, une seule requête POST. Envoyez du JSON à l'URL de webhook de votre canal et nous gérons les notifications, la mise en forme et la distribution.
Envoyer une alerte
Déclenchez une nouvelle alerte dans un canal spécifique. C'est l'endpoint principal pour envoyer des notifications depuis votre application.
curl -X POST https://zenhook.dev/api/webhook/abc123def456 \
-H "Content-Type: application/json" \
-d '{
"title": "New signup",
"level": "success",
"emoji": "🎉",
"source": "My App",
"actor": {
"id": "42",
"name": "Jane Doe",
"email": "[email protected]",
"plan": "Pro"
},
"linkUrl": "https://myapp.com/admin/users/42",
"linkText": "View Profile"
}'Paramètres de chemin
Corps de la requête
info, success, warning, error. Par défaut info."🚀"), un nom ("rocket"), ou un shortcode (":rocket:"). Les noms et shortcodes sont convertis à l'ingestion. Les noms inconnus sont ignorés plutôt qu'affichés comme texte littéral. Noms reconnus : rocket · siren · warning · check · cross · fire · bug · zap · bell · tada · sparkles · envelope · chat · phone · megaphone · wave · eyes · heart · thumbsup · office · door · house · factory · lock · unlock · key · link · package · gear · wrench · shield · money · chart · clock · hourglass · flag · star · target · pin · tag · computer · server · database · cloud · bulb · gem · anchor · pick · bank.{ name, email, id, plan, company, location, avatarUrl, url }, un sous-ensemble, ou simplement une chaîne. user est aussi accepté. À partir du seul email, Zenhook déduit le nom affiché, les initiales, la société derrière un domaine professionnel, et le Gravatar si la personne en a un.label et value.name est accepté à la place de label, et une valeur peut être un nombre ou un booléen.linkUrl est défini.url et, en option, untype(image,video ouaudio) et une légendename. Zenhook récupère chaque URL et réhéberge le fichier sur son propre CDN — vos médias se chargent vite et vos URLs sources restent privées. Formats acceptés : PNG, JPEG, GIF, WebP, AVIF, MP4, WebM, MP3, WAV, M4A, Ogg (le SVG est refusé). Max 10 Mo par image, 25 Mo audio, 50 Mo vidéo.multipart/form-data avec une partpayload portant les mêmes champs JSON, plus une part fichier par pièce jointe. Le client le plus simple, c'est un titre et un fichier :curl -X POST https://zenhook.dev/api/webhook/YOUR_TOKEN \
-F 'payload={"title":"Build failed","level":"error"}' \
-F 'file=@./screenshot.png'Pas de multipart possible ? Passez les octets en base64 dansattachments[].data. Formats, limites et traitement des fichiers sont surEnvoyer des images et des fichiers.
Les erreurs sont des documents RFC 9457, servis en application/problem+json. Brancher surtype, afficher title. L'ancien champ error reste present, pour que les integrations ecrites avant continuent de fonctionner.
{
"type": "https://zenhook.dev/problems/unknown-token",
"title": "Invalid webhook token",
"status": 404,
"error": "Invalid webhook token"
}Envoyez un en-tete Idempotency-Key et un renvoi de la meme requete rend la premiere reponse au lieu de creer une seconde alerte, pendant 24 h. La relecture porte Idempotency-Replayed: true. Un renvoi pendant que la premiere requete tourne encore recoit un 409 plutot qu'un doublon. A poser sur tout ce qui reessaie apres un delai depasse, un script de deploiement en premier.
Réponses
Alerte reçue et mise en file d'attente pour distribution.destination nomme l'espace de travail et le canal auxquels le token correspond, pour qu'une intégration mal branchée se voie dans la réponse plutôt que des jours plus tard, dans le mauvais canal.
{
"success": true,
"alertId": "clx1234567890abcdef",
"destination": {
"workspace": { "id": "ws_...", "name": "Acme Corp" },
"channel": { "id": "ch_...", "name": "deploys", "slug": "deploys" }
}
}Notifications de workflow
Un déploiement ou une release est un seul processus, pas cinq alertes. Ajoutez un blocworkflow et chaque POST portant le mêmerunId met à jour une seule alerte : la carte montre chaque étape en direct, et le flux ne se remplit jamais de bruit intermédiaire.
# every POST of a run carries the same runId
curl -X POST https://zenhook.dev/api/webhook/YOUR_TOKEN \
-H "Content-Type: application/json" \
-d '{
"title": "myapp deploy",
"workflow": {
"runId": "myapp-20260722-1015",
"state": "running",
"steps": [
{ "name": "test", "state": "done", "seconds": 46, "info": "716 tests" },
{ "name": "build", "state": "running" },
{ "name": "deploy", "state": "pending" }
]
}
}'États : le run est running, passed ou failed ; chaque étape est pending, running, done, failed ou skipped. Envoyez le tableau d'étapes COMPLET à chaque fois ; le serveur remplace, il ne fusionne jamais.
Politique de notification : le premier POST notifie (démarré), les mises à jour en cours sont silencieuses, et l'état final notifie une fois et refait remonter l'alerte comme non lue. Le niveau est dérivé de l'état : un run échoué ne peut jamais prétendre avoir réussi.
Facturation : un processus est un seul événement, compté au premier POST. Les mises à jour sont gratuites.
En cas d'échec : passez workflow.error avec la fin du log ; elle s'affiche sur la carte pour diagnostiquer depuis un téléphone.
Données structurées
Utilisez le tableau fields pour inclure des métadonnées riches affichées dans le tableau de bord et les alertes par e-mail.
{
"title": "Build Failed",
"level": "error",
"fields": [
{ "label": "Branch", "value": "main" },
{ "label": "Commit", "value": "abc123f" },
{ "label": "Author", "value": "John Smith" },
{ "label": "Error", "value": "npm install timed out after 300s" }
],
"attachments": [
{ "url": "https://ci.example.com/runs/123/screenshot.png", "type": "image" }
],
"linkUrl": "https://github.com/org/repo/actions/runs/123",
"linkText": "View Logs"
}Relire les alertes
L'endpoint de webhook ci-dessus est public et en écriture seule, toute personne disposant du jeton du canal peut y publier. Pour lister les alertes, les marquer comme lues ou construire une intégration qui les consomme, utilisez l' API de lecture authentifiée avec un jeton Bearer.