API Reference
One endpoint, one POST request. Send JSON to your channel's webhook URL and we handle notifications, formatting, and delivery.
Send Alert
Trigger a new alert in a specific channel. This is the primary endpoint for sending notifications from your application.
curl -X POST https://zenhook.dev/api/webhook/abc123def456 \
-H "Content-Type: application/json" \
-d '{
"title": "New User Signup",
"level": "success",
"emoji": "馃帀",
"source": "My App",
"message": "[email protected] just joined your workspace.",
"linkUrl": "https://myapp.com/admin/users/42",
"linkText": "View Profile"
}'Path Parameters
Request Body
info, success, warning, error. Defaults to info."馃殌"), a name ("rocket"), or a shortcode (":rocket:"). Names and shortcodes are translated on ingest. Unknown names are dropped rather than rendered as literal text. Known names: 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.label and value.linkUrl is set.url plus an optionaltype(image,video, oraudio) andname caption. Zenhook fetches each URL and re-hosts the file on its own CDN — your media loads fast and your source URLs stay private. Supported: PNG, JPEG, GIF, WebP, AVIF, MP4, WebM, MP3, WAV, M4A, Ogg (SVG is rejected). Max 10 MB per image, 25 MB audio, 50 MB video.multipart/form-data with apayload part carrying the same JSON fields, plus one file part per attachment. The simplest client is a title and a file:curl -X POST https://zenhook.dev/api/webhook/YOUR_TOKEN \
-F 'payload={"title":"Build failed","level":"error"}' \
-F 'file=@./screenshot.png'Responses
Alert received and queued for delivery.
{
"success": true,
"alertId": "clx1234567890abcdef",
"queuedAt": "2024-03-22T12:00:00Z"
}Workflow notifications
A deploy or release is one process, not five alerts. Add aworkflow block and every POST that carries the samerunId updates a single alert in place: the card shows each step live, and the feed never fills with intermediate noise.
# 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" }
]
}
}'States: the run is running, passed or failed; each step is pending, running, done, failed or skipped. Send the FULL steps array every time; the server replaces, it never merges.
Notification policy: the first POST notifies (started), running updates are silent, and the terminal state notifies once and resurfaces the alert as unread. The alert level is derived from the state, so a failed run can never claim success.
Metering: one process is one billable event, counted at the first POST. Updates are free.
On failure: pass workflow.error with the log tail; it renders on the card so the failure can be diagnosed from a phone.
Structured Data
Use the fields array to include rich metadata displayed in the dashboard and email alerts.
{
"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"
}Reading alerts back out
The webhook endpoint above is public and write-only, anyone with the channel token can post into it. To list alerts, mark them read, or build an integration that consumes them, use the authenticated Read API with a Bearer token.