Heartbeat monitors

The push URL, the grace period, and what a missed ping produces.

Heartbeat monitors

A heartbeat monitor is passive: instead of upzero probing a target, your own cron job, scheduler or worker pushes to upzero on a schedule you define, and upzero watches for pushes stopping.

Creating one

Heartbeat monitors take no url. heartbeat_period is how often you expect to push, in seconds (60-86400); grace_period is extra slack before a missed push counts against you (60-3600). Both default to 300 and 60 if omitted.

curl -X POST https://api.up0.io/api/v1/me/monitors \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Nightly backup job",
    "type": "heartbeat",
    "interval_seconds": 300,
    "config": { "heartbeat_period": 3600, "grace_period": 300 }
  }'

The response includes config.heartbeat_token, a UUID generated once at creation time. That token, not the monitor's own id, is the credential your job pushes with. There is no way to view it again through the API after creation, so save it when you create the monitor.

The push URL

curl -X POST https://api.up0.io/api/v1/heartbeat/<HEARTBEAT_TOKEN>

No Authorization header is required, since the token in the URL is the credential. If you do send an X-API-Key header, it must be a valid key belonging to the monitor's own organization and scoped heartbeats:write; a bad or under-scoped key is rejected rather than silently ignored.

A successful push returns {"status": "ok"} and nothing else. There is no payload beyond the token, so a heartbeat monitor cannot carry a job's exit code or output today, only that it ran.

Add the push to your job

At the end of whatever the job does, whether or not it succeeded on its own terms, call the push URL. A common pattern is curl -fsS --retry 3 <url> || true at the very end of the script, so a transient network blip on the push itself doesn't fail the job.

Watch it go up

A brand-new heartbeat monitor starts pending. It does not go down immediately just because no push has arrived yet. See "what missed produces" below for exactly when that changes.

Confirm a missed push is caught

Stop pushing (or wait past heartbeat_period + grace_period) and check that the monitor's status turns down. This is the behaviour that matters: a heartbeat monitor only proves anything once you have seen it detect an absence, not just a presence.

What "missed" produces

Every 60 seconds, the same worker that writes probe checks also looks at every heartbeat monitor:

  • If a push has been seen, it compares the age of the most recent push against heartbeat_period + grace_period. Within that window, the check is up; past it, down.
  • If no push has ever been seen at all, the monitor is left alone until it is older than heartbeat_period + grace_period since creation. A brand-new monitor is not marked down before its own job has had a reasonable chance to run once. Once it crosses that age with still no push, it is marked down.

Either way, the transition writes a normal check row (status: "down", with no response_time_ms or status_code, since those only apply to probed types). A monitor recovers to up on the very next push that arrives, no matter how long it was down.

Walking this live: a heartbeat monitor created with heartbeat_period: 120, grace_period: 60 went down when its 180-second window closed with no push registered yet, then recovered to up within one worker tick of the next push arriving, and went down again once pushes stopped and that same 180-second window elapsed again.

Where the push actually goes

A push does not update anything directly. It writes a metric to the platform's internal Pushgateway, the regional Prometheus scrapes that gateway on its own cycle, and the 60-second worker above reads the scraped value the same way it reads probe results. None of that plumbing is something you configure or need to know to use heartbeat monitors. It only explains why a push can take a few seconds to be reflected in the monitor's status rather than being instantaneous.

On this page