Heartbeats
A monitor expects an HTTP request at a set interval. When none arrives before the interval and its grace period elapse, it sends an alert to the channel you chose. The pattern is also called cron job monitoring, or a dead man’s switch: nothing polls your job from outside, so it works for processes that expose no endpoint at all.
A channel
Where alerts are delivered: a Telegram chat or a WhatsApp number. You set one up once and reuse it across any number of monitors.
A monitor
One process you are watching: a worker, a job, a daemon. It holds the interval a heartbeat is expected on, and the channel to alert when one does not arrive.
Step 1
Create a channel
Create a channel and choose which provider delivers its alerts.
Telegram
Create a bot with @BotFather, paste its token and the chat ID. Sending costs nothing, and the bot can post to a group or to a single topic. Telegram’s guide.
Enter your number and type the code sent to it. There is no bot or token to create.
Step 2
Create a monitor
Create a monitor and say how often you expect a report and how much delay is tolerable. A process that reports every minute might allow 30 seconds of grace; an hourly backup might allow 5 minutes.
You get a token, once. It authenticates every heartbeat and identifies which monitor is reporting, so the request carries nothing else.
Save it somewhere your job can read it, the same way you would any other secret. If you lose it, open the monitor and regenerate it: the old one stops working immediately.
export PROCESSDUTY_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."Step 3
Periodically send the heartbeat
One POST with the token in an Authorization header. No request body.
curl
curl -fsS -X POST https://processduty.ai/api/heartbeat \
-H "Authorization: Bearer $PROCESSDUTY_TOKEN"Node.js
await fetch("https://processduty.ai/api/heartbeat", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.PROCESSDUTY_TOKEN}` },
});Python
requests.post(
"https://processduty.ai/api/heartbeat",
headers={"Authorization": f"Bearer {os.environ['PROCESSDUTY_TOKEN']}"},
timeout=10,
)Go
req, _ := http.NewRequest("POST", "https://processduty.ai/api/heartbeat", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PROCESSDUTY_TOKEN"))
http.DefaultClient.Do(req)Ruby
uri = URI("https://processduty.ai/api/heartbeat")
Net::HTTP.post(uri, "", "Authorization" => "Bearer #{ENV['PROCESSDUTY_TOKEN']}")PHP
$ch = curl_init("https://processduty.ai/api/heartbeat");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("PROCESSDUTY_TOKEN")],
]);
curl_exec($ch);Crontab
0 * * * * /opt/backup.sh && curl -fsS -X POST https://processduty.ai/api/heartbeat -H "Authorization: Bearer $PROCESSDUTY_TOKEN"Step 4
What the endpoint returns
204Reported. The interval starts again from now.
401The token is wrong, was regenerated, or the monitor was deleted. Retrying will not help.
The first heartbeat is what arms a monitor. Until one arrives it sits as Waiting for first heartbeat and can never be late, so something you have not deployed yet cannot alert.
Step 5
When a heartbeat is late
A monitor is late once interval + grace passes with no report. Checks run every minute, so the alert reaches that monitor’s channel shortly after, carrying the message configured on it.
You get one alert per outage, not one per check. If the job starts reporting again, a recovery message follows, unless that is disabled on the monitor.
Common questions
What is a heartbeat monitor?
A heartbeat monitor waits for a signal instead of sending one. Your job reports after each run, and the monitor alerts you when a report does not arrive on schedule. The pattern is also called a dead man's switch.
How is heartbeat monitoring different from uptime monitoring?
An uptime monitor polls a URL from the outside, so it only covers something publicly reachable. A heartbeat monitor is told by the job itself, which covers cron entries, queue workers, backups and daemons that expose no endpoint at all.
How do I monitor a cron job?
Create a monitor with the interval your crontab already uses, then append one curl call to the crontab line so it runs after your script. Chaining it with && means a failed script sends no heartbeat, and the monitor alerts.
What happens if my job finishes late?
Each monitor has a grace period on top of its interval. A monitor is late only once the interval plus its grace period passes with no report, so ordinary variance does not wake anyone. An hourly backup might allow five minutes of grace.
How often can a heartbeat be expected?
Any interval from one second to seven days, with a grace period of up to one day on top of it.
Do I need to install an agent?
No. A heartbeat is one POST request carrying a bearer token and no body, so anything that can make an HTTP call can report: curl, a shell script, Node.js, Python, Go, Ruby, PHP, or a line in a crontab.
Will I be alerted repeatedly during an outage?
No. You get one alert per outage rather than one per check, plus an optional recovery message when reports start arriving again.
Where do the alerts arrive?
In a Telegram chat, group or topic, or at a WhatsApp number. A channel is set up once and reused across any number of monitors.
The first monitor takes about two minutes to set up.