Set up by API

One token is enough to set up a project from a script or an AI agent: a channel for its events, monitors for its pages and jobs, a site for its visits and feedback.

The token

Create it in Settings, API Tokens. It belongs to one workspace, so everything below lands in that workspace. Adding or changing a site takes the token of an owner or an admin.

How tokens work

Create a channel

A channel receives your app's events. name is required; description, icon, color and isPrivate are optional.

bash
curl -X POST "https://zenhook.dev/api/channels" \
  -H "Authorization: Bearer $ZENHOOK_TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"my-app","description":"Sign-ups and errors"}'

The answer holds webhookToken: your app posts to https://zenhook.dev/api/webhook/ followed by that token. Anyone with this address can post to the channel, so keep it with your secrets. POST /api/channels/:id/regenerate-token replaces it. Free holds 3 channels: one more answers 403 with CHANNEL_LIMIT_REACHED.

Monitor an address

Zenhook requests the address and alerts you when it goes down. url is required; name defaults to the host name.

bash
curl -X POST "https://zenhook.dev/api/monitors" \
  -H "Authorization: Bearer $ZENHOOK_TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"example.com","url":"https://example.com"}'

A workspace watches each URL once: a second monitor on it answers 409. Free holds 3 monitors and Pro 20: one more answers 403 with MONITOR_LIMIT_REACHED. An address on a private network answers 400 with PRIVATE_TARGET_REQUIRES_PUSH: use a PUSH monitor, below. Monitor alerts land in the workspace's Monitors channel, which you do not choose.

How checks work

Monitor a scheduled job

A PUSH monitor works the other way round: your job reports to Zenhook, and the monitor goes down when the reports stop. It also covers a service on a private network.

bash
curl -X POST "https://zenhook.dev/api/monitors" \
  -H "Authorization: Bearer $ZENHOOK_TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"Nightly backup","url":"https://backup.example.com/nightly",
       "type":"PUSH","heartbeatInterval":3600,"heartbeatGrace":86400}'

url is required here too and must be unique, because it names what is watched: Zenhook does not request it. heartbeatGrace is how long the monitor can stay silent, in seconds: 60 to 86400, and never less than twice heartbeatInterval (30 to 3600). A job that runs every 6 hours needs a grace above 21600.

The answer gives heartbeatToken, once, and heartbeatCommand, a ready command that requests the url from where it runs and reports the result. Or report from the end of your job:

bash
curl -X POST "https://zenhook.dev/api/monitors/heartbeat" \
  -H "Authorization: Bearer $ZENHOOK_HEARTBEAT_TOKEN" -H "Content-Type: application/json" \
  -d '{"status":"UP"}'

status is UP (the default) or DOWN. responseTime in milliseconds, statusCode and errorMessage are optional. The answer is 204.

Add a site

This adds the domain to Analytics and returns it under site, with its id and its key. feedback turns on feedback; analytics is on by default. Adding a domain twice returns the existing site. A workspace holds 20 sites during the alpha.

bash
curl -X POST "https://zenhook.dev/api/sites" \
  -H "Authorization: Bearer $ZENHOOK_TOKEN" -H "Content-Type: application/json" \
  -d '{"domain":"example.com","feedback":true}'

Then read what to paste, with the domain or the id:

bash
curl "https://zenhook.dev/api/sites/example.com/setup" \
  -H "Authorization: Bearer $ZENHOOK_TOKEN"

snippet is the line for the <head> of your pages, buttonSnippet the same line with our feedback button, privacyParagraph the paragraph for your privacy page. agentInstructions is all of it, written for an AI agent.

To change a site later, send PATCH /api/sites/:id with analytics or feedback set to true or false. This address takes the site's id, not its domain.

Feedback from every site of the workspace lands in its one Feedback channel, with the site in each event's source.

Events, goals and reading the numbers