Heartbeat monitoring is a check where the job reports in, rather than the monitor probing the job. Each run ends with one small HTTP request. The monitor knows when the next one is due, and if it does not arrive inside a grace window, that silence becomes an alert. It is the only kind of monitoring that catches a job that never started, which is how cron jobs, queue workers and scheduled AI agents usually fail.
Uptime monitoring calls your service every minute and alerts when the call fails. That works for something that is always on. A scheduled job is not listening for requests, so there is nothing to probe. Heartbeat monitoring inverts the direction: the job calls in, and the gap is the signal.
A web service or API that answers requests all day wants an uptime check, not a heartbeat. A request-driven agent with no schedule wants run monitoring: every run reports its status and a failed run alerts, but there is no "due" time to miss. Agent Ping does both; this page is about the scheduled case.
A ping, a schedule, a grace window and a sweep. Everything else is a detail of what the ping carries.
The job ends by sending one request with the agent name and a status. ok is the default; fail and timeout are the other two. A job that can run for a long time sends start first and ok or fail at the end, and the duration is the gap between them.
curl 'https://eu.ingest.agentping.io/v1/ping?key=ping_eu_<token>&agent=daily-summary&status=ok'
The token in the URL is a ping token, scoped to one agent and only able to send heartbeats. A leaked ping token can falsify one job's status; a leaked API key would be a full team compromise, so never put one in a URL.
You tell the monitor when the job is meant to fire, in the same cron syntax the job uses. The monitor computes the next expected time after each run. A job with no schedule can still send heartbeats, and its failures still alert, but nothing watches for its absence.
Scheduled jobs do not fire to the second. The grace window is how many minutes past the expected time the monitor waits before calling the run overdue. Set it from the job's real jitter: a nightly batch that sometimes starts 20 minutes late wants 30 to 45 minutes. A window that is too short teaches the team to ignore the channel, which is worse than no monitor.
A sweep runs every minute. When an agent passes its window with no run received, an overdue alert goes to every enabled channel with the agent, how many minutes it is overdue and when a run was last seen. You get one alert per outage, not one per minute: the state is remembered until a run lands again, and then a recovery notice goes out and the slate is clean for the next incident.
{
"event": "agent.overdue",
"subject": "daily-summary is overdue",
"body": "No run received for 31 minutes past the expected window.",
"agent": { "slug": "daily-summary", "id": "agt_…" },
"run": null,
"last_seen_at": "2026-10-22T09:00:42Z",
"minutes_overdue": 31,
"url": "https://agentping.io/agents/agt_…"
}
Slack and Teams get formatted message blocks, PagerDuty gets its own event shape, email gets a digest. The same alert goes to whichever channels the agent has enabled.
Create the agent, copy its ping token, set the schedule and grace window, and add the ping to the job. The success and failure pings target the same agent.
Cron swallows every exit code, so fire the success ping only when the script exits zero and the failure ping only when it does not. The trailing redirect keeps cron's email-on-output behaviour quiet.
0 9 * * * /path/to/daily-summary.sh \ && curl -fsS 'https://eu.ingest.agentping.io/v1/ping?key=ping_eu_<token>&agent=daily-summary&status=ok' > /dev/null 2>&1 \ || curl -fsS 'https://eu.ingest.agentping.io/v1/ping?key=ping_eu_<token>&agent=daily-summary&status=fail' > /dev/null 2>&1
Add an HTTP request as the final step and a second one on the failure path. In GitHub Actions that is a step with if: failure(); in n8n it is an HTTP Request node on the error output. The GitHub Actions, n8n, Make and Zapier recipes have the exact node settings.
Anything with an SDK can send the same heartbeat in one call, with the cost and duration attached, and upgrade to full run tracing later without migrating anything.
import agentping
agentping.init(api_key="apk_…")
agentping.heartbeat("daily-summary", status="ok", cost_usd=0.084, duration_ms=41_892)
Presence is the minimum. A scheduled AI agent has three more questions worth answering on the same request: what it cost, how long it took, and whether the output was any good.
cost_usd if the job knows it, or send provider, model, input_tokens and output_tokens from the response's usage block and Agent Ping prices the run from its rate card. Spend then rolls up per agent, per customer and per month, with a budget alert before the invoice.start ping followed by ok or fail gives every run a duration, so a job that is slowing down week over week is visible before it starts missing its window.curl 'https://eu.ingest.agentping.io/v1/ping?key=ping_eu_<token>&agent=daily-summary&status=ok&provider=openai&model=gpt-5&input_tokens=1240&output_tokens=380'
Cronitor, Healthchecks.io and Dead Man's Snitch do heartbeat monitoring well, and the ping is the same one line. If all you have is cron jobs, any of them is a fine choice.
The difference is what the heartbeat is attached to. A cron monitor records that the job ran. Agent Ping records a run of an agent, with cost, duration, status, optional output and a quality score, in the same dashboard as agents that report through an SDK, OpenTelemetry or a framework hook. When the overdue alert fires, the on-call engineer sees the last successful run and what it cost, and when the job is an AI agent, whether its recent output was drifting before it went quiet. That is the case for using one tool for the fleet instead of a cron monitor for the schedules and something else for the agents.
Create an agent, copy its ping token, paste one line into the job. The free plan has no card and no time limit.
Pulse: AI agent monitoring → Heartbeat docs → Cron recipe → Your AI agent stopped running →