Heartbeat monitor
Heartbeat monitors flip the usual model. Instead of PathWatch
calling your service, your service calls PathWatch on a schedule.
If the ping doesn’t arrive within the expected window, the monitor
flips to down and your normal alerting fires.
Use it for things PathWatch can’t reach from outside: cron jobs, batch workers, scheduled Lambdas, queue consumers, backup scripts.
How it works
- Create a heartbeat monitor in the WebUI. PathWatch issues a
unique URL:
https://api.pathwatch.app/heartbeat/<token>. - Add a
curl(or any HTTP client) to the end of your job pointing at that URL. - The monitor expects a ping every N seconds. If `now - last_ping
expected_interval + grace_period
, the monitor isdown` and alerts fire through whatever rules you’ve attached.
The token is monitor-scoped — exposing it lets anyone ping that specific monitor (a minor inconvenience, not a security issue). Tokens can be rotated from the monitor settings.
Configuration
| Field | Type | Default | Notes |
|---|---|---|---|
| Expected interval | seconds | — | How often you intend to ping. Minimum 60 s. Required. |
| Grace period | seconds | 0 | Tolerance on top of the interval before going down. Set this to your job’s worst-case duration. |
| Failure status | enum | down | What status the monitor reports when a ping is missed. degraded if a missed cron isn’t a full outage. |
| Payload rules | array | [] | Optional. Inspect the JSON body of each ping and alert on the contents (see below). Max 20 rules. |
Pinging the endpoint
Any HTTP method works. GET is the simplest:
curl -fsS https://api.pathwatch.app/heartbeat/<token>For richer signals, POST JSON with metrics or state:
curl -fsS -X POST \ -H 'Content-Type: application/json' \ -d '{"records_processed": 1247, "duration_ms": 31200, "status": "ok"}' \ https://api.pathwatch.app/heartbeat/<token>Form-encoded bodies and query parameters on GET are also accepted.
Per-token rate limit: 1 ping per 5 seconds. Body cap: 16 KB.
Payload rules
If you POST JSON, you can have PathWatch assert on the contents.
Each rule targets a field (dot-notation for nested values) and runs
one operator against it. If any rule fails, the check is down
(or degraded if the rule’s status is set that way).
| Operator | Compares against |
|---|---|
equals / not_equals | A single string, number, or boolean |
greater_than / less_than | A number |
between / not_between | Two numbers — inclusive range |
one_of / not_one_of | An array of strings or numbers |
Example: alert if a worker’s queue depth crosses a threshold:
{ "field": "queue_depth", "operator": "less_than", "value": 10000, "label": "Queue depth under 10k", "status": "degraded"}A failed rule’s label (or the field name if no label) appears in
the alert message so the responder knows which assertion fired.
Status mapping
| Outcome | Status |
|---|---|
Ping arrives inside expected_interval + grace_period, all payload rules pass | up |
Ping arrives but a payload rule with status: "degraded" fails | degraded |
Ping arrives but a payload rule with status: "down" fails | down |
| No ping arrives within the window | down (or degraded if failure_status: "degraded") |
Common patterns
Cron jobs — curl at the end of the script. Set the interval
to your cron cadence and the grace period to your worst-case job
runtime.
Long-running jobs that report mid-flight — POST progress
metrics periodically. Use payload rules to alert on stalls
(progress_percent not advancing, error_count > 0).
Backups — POST {"bytes_written": N, "duration_ms": M} so
both the “did it run” and “did it finish what we expect” questions
are covered by a single monitor.
Worker queues — set expected_interval to the worker’s poll
interval. If the worker dies, the monitor goes down within one
interval + grace.