Cron job monitoring
A cron job that stops running produces no error to catch. PostDeploy inverts the check: your job pings a URL, and silence past the schedule plus its grace period is the alert. Start, finish and fail pings also catch jobs that fail loudly or hang forever.
Why scheduled jobs need a different kind of check
Uptime checks poll something and interpret the answer. A scheduled job has nothing to poll: when it stops being scheduled, there is no failing request, no error page and no exception. The observable fact is that nothing happened, and nothing is hard to notice.
A heartbeat treats silence as the signal. Your job reports in when it runs, and PostDeploy alerts when a report does not arrive on time. That catches the decommissioned server whose crontab went with it, the commented-out schedule line, the container that stopped being scheduled, and the job that hangs forever without exiting.
The minimum setup
Create a heartbeat monitor, copy its token, and append one curl call to your job. The && matters: it ties the ping to the job's exit status, so a failing backup never reports success.
The -f flag makes curl fail on an HTTP error, -s silences progress output, and -S still prints errors. Inside cron, where any output becomes mail, that combination is what you want.
# Ping only if the job succeeded.
0 3 * * * /usr/local/bin/backup.sh && curl -fsS https://ingest.postdeploy.dev/h/hb_YOUR_TOKEN
Reporting failure as well as success
The one-liner above tells PostDeploy nothing when the job fails; it simply stays silent until the grace period expires. To alert immediately on failure, report the exit code instead. Append it as a path segment: 0 is a success, anything else is a failure that opens an incident right away, bypassing the failure threshold.
In a shell, $? holds the exit status of the previous command, so a single line covers both outcomes. Use ; rather than && here, because the ping has to run whether or not the job succeeded.
# 0 reports success, any other exit code opens an incident.
0 3 * * * /usr/local/bin/backup.sh; curl -fsS "https://ingest.postdeploy.dev/h/hb_YOUR_TOKEN/$?"
Catching a job that hangs
A job that never exits never pings, and a plain heartbeat only notices once the schedule and grace period have passed. Sending a start ping first narrows that window: set an expected duration on the monitor, and PostDeploy marks the run as hung when more than twice that duration passes without a finish.
Send the start ping before the work and the finish ping after it. A ping with no state parameter is treated as a finish, so existing one-liners keep working unchanged.
curl -fsS "https://ingest.postdeploy.dev/h/hb_YOUR_TOKEN?state=start"
/usr/local/bin/backup.sh
curl -fsS "https://ingest.postdeploy.dev/h/hb_YOUR_TOKEN?state=finish"
Checking that the ping actually works
A heartbeat you never tested is a guess. The two failures worth ruling out before you trust it are a token that is not recognised, and egress that is blocked, which is common in containers and CI runners: the job succeeds, and the ping never leaves the network.
heartbeat-doctor is an open-source CLI that sends one ping and explains the result, and separately checks a crontab line for the mistakes that let a job fail silently. It works with any provider, needs no account, and masks the token in its output so a result can be pasted into an issue. Run it with npx: heartbeat-doctor ping YOUR_URL
# Verify the URL from your terminal before trusting the monitor.
npx heartbeat-doctor ping "https://ingest.postdeploy.dev/h/hb_YOUR_TOKEN"
# Check the crontab line itself for silent-failure patterns.
npx heartbeat-doctor cron "0 3 * * * /usr/local/bin/backup.sh; curl -fsS https://ingest.postdeploy.dev/h/hb_YOUR_TOKEN/\$?"
What the ping accepts
GET and POST behave identically, so wget, a fetch() call, or any HTTP client works exactly as curl does. Possession of the hb_ token is the authentication, so no header or API key is needed, and the URL should be treated as a secret.
A recognised token always returns 202, including when the monitor is paused, in which case nothing is recorded. An unrecognised token returns 404.
Questions
What happens if my job runs late rather than not at all?
Each heartbeat has an interval and a grace period. A ping that arrives within the grace period is on time. Past it, PostDeploy opens an incident. Set the grace period to the longest delay you consider normal for that job.
Do I need to install an agent?
No. The monitoring is one outbound HTTPS request made by the job itself, so anything that can run curl, wget or an HTTP client can ping a heartbeat. There is nothing to install and nothing inbound to open.
Does a heartbeat use one of my uptime monitors?
No. Cron and heartbeat jobs have their own allowance on every plan, 200 on the trial, separate from the 100 uptime and API monitors.
Can I report why a job failed?
You can send a short message with the ping as a msg query parameter, and the exit code through the path form. PostDeploy does not capture the job's full output or logs.
Ship your next project with one toolkit, not three.
Sign up and every feature described on this page is yours on the trial. No credit card.
Create your first heartbeat