Everything you need to wire your first cron job in under five minutes. The HTTP API is intentionally tiny — three endpoints — so you can integrate from any language without an SDK.

Concepts

A monitor is one scheduled job you want to watch. Every monitor has a UUID — that UUID is also the secret in its ping URL. Treat it as a credential.

Monitors transition through four states:

StatusMeaning
newCreated, no ping received yet.
upLast expected ping arrived on time.
latePast next_expected_at + grace. Alert fires.
downYou explicitly POSTed /fail for the last run.

Ping API

Three endpoints, all accept GET, POST, and HEAD. POST lets you attach up to 10KB of captured output (stdout/stderr) — anything past 10KB is truncated, not rejected.

POST /ping/<uuid> — heartbeat

The simplest case. Tells us "the job ran successfully right now". Equivalent to POST /ping/<uuid>/success.

curl -fsS -m 10 --retry 5 https://cronheart.com/ping/<uuid>

POST /ping/<uuid>/start — run started

Send before the job runs. Lets us track duration and surface "job stuck" warnings if a /start isn't followed by a terminal event within the grace period.

POST /ping/<uuid>/success — run finished cleanly

Send when the job exits 0. Pair with /start to get a duration column on the dashboard.

POST /ping/<uuid>/fail — run errored

Send when the job exits non-zero. Drives alert delivery immediately — no need to wait for the next scheduled window.

Bash recipe with start + result reporting

UUID=<your-monitor-uuid>
BASE=https://cronheart.com/ping/$UUID
curl -fsS -m 10 --retry 3 "$BASE/start"
if /usr/bin/php /app/bin/console hourly:rollup; then
    curl -fsS -m 10 --retry 3 --data-binary @<(tail -c 8000 ./run.log) "$BASE/success"
else
    curl -fsS -m 10 --retry 3 --data-binary @<(tail -c 8000 ./run.log) "$BASE/fail"
fi

Schedule formats

Pick whichever matches how you actually run the job:

  • Cron — standard 5-field expression (*/5 * * * *). UI shows the next 5 runs as you type.
  • Interval — "every N seconds" / "every N minutes" / "every N hours". Use this when you don't want to think in cron for "run every 6 hours".
  • Simple — daily at HH:MM, hourly at MM, etc. Best for non-developers who configure monitors via the UI.

Alerts & channels

An alert fires the moment a monitor transitions to late or down — no fixed-window batching, so the time-to-page is "the scanner sweep that detected it" (≤ 30 s) plus the channel transport latency. Anti-flap dedupe makes sure a recovering job doesn't double-page you.

Configure channels per project. Currently supported:

  • Email (default)
  • Telegram bot (set up via /start with the bot)
  • Slack incoming webhook
  • Discord incoming webhook
  • Generic webhook with HMAC-SHA256 signature

Status badges

Every monitor exposes a public read-only SVG at /badge/<uuid>.svg. Drop it into your README to show the world your nightly-rollup is healthy.

![status](https://cronheart.com/badge/<uuid>.svg)

The badge URL is the only public surface that exposes the monitor UUID. We deliberately don't expose ping metadata in the badge — only the colour-coded status — so a stolen badge URL can't be replayed as a ping.

Changelog

Coming soon — weekly release notes will live here.

Privacy & security

Monitor UUIDs are treated as per-monitor secrets and never logged at INFO+ on the request path. Audit logs (login, failed logins, impersonation, admin actions) live in a dedicated channel and rotate daily. Email and pings transit over TLS only.

Terms

Standard SaaS terms apply. Replace this page with your final legal copy before launch.