LastSeenDocs

Sending heartbeats

The ping URL, what you can send with a heartbeat, and what LastSeen answers.

Each heartbeat monitor has its own ping URL, made from its key:

https://ping.lastseen.io/YOUR-KEY

A request to it, GET or POST, is a heartbeat. The key is the only credential, so there's nothing else to send: no headers, no account ID.

Signals #

URLWhat it says
/YOUR-KEYI'm alive.
/YOUR-KEY/failSomething's wrong. The monitor goes down at once, and you're alerted.
/YOUR-KEY/startI've just started (a reboot, a job beginning). It's noted in the monitor's history; the status doesn't change.

A heartbeat after a /fail brings the monitor back up, with a recovery alert.

Sending a reading #

A heartbeat can carry a value: a number or a short piece of text. The monitor's page graphs numbers, and value rules can alert on them.

With GET, in the query string:

curl "https://ping.lastseen.io/YOUR-KEY?v=21.5"

With POST, as JSON:

curl -X POST https://ping.lastseen.io/YOUR-KEY -H "Content-Type: application/json" \
  -d '{"v": 21.5, "seq": 1042, "up": 86400}'
FieldMeaning
v (or value)The reading: a number, text or true/false. Up to 64 bytes on the Free plan.
seqA counter that goes up by one each heartbeat. Gaps show as lost heartbeats; a reset shows as a restart.
upSeconds since the device started. A drop shows as a restart.

Any other fields in a JSON body are kept with the reading. A body can be at most 1024 bytes.

Values #

On a monitor's page, value rules alert on what a monitor reports, not just on silence: num > 30, value == "ERROR", or "hasn't changed for 45 minutes". Each rule can require several readings in a row before it trips, so one noisy sample doesn't wake anyone. Value alerts go to the same channels and follow the same snooze as down alerts.

What LastSeen answers #

StatusBodyMeaning
200okRecorded.
200ok, payload ignored: …The heartbeat counted; the reading didn't (malformed, or too long for the plan).
404unknown ping keyNo monitor has this key: a typo, or the key was replaced.
413body over 1024 bytesThe body is too big.
429rate limitedToo many pings; Retry-After says how many seconds to wait.
503temporarily unavailable, retryOur side; try again shortly.

Rate limits #

Each monitor may send 2 heartbeats a minute, with bursts of up to 5, which is why the shortest interval is 30s. /fail and /start have their own allowance of 1 a minute (bursts of 3), so a chatty device can't use up the one message that matters most.

From a cron job #

Ping at the end of the job, so the heartbeat means it finished:

0 2 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 --retry 3 https://ping.lastseen.io/YOUR-KEY > /dev/null

To report failures as well, wrap the job with our script. It runs the job, then sends a heartbeat if it succeeded, or /fail with the exit status if it didn't (which alerts at once). The job's own exit status is passed on:

curl -fsSo /usr/local/bin/lastseen-run https://app.lastseen.io/examples/lastseen-run.sh && chmod +x /usr/local/bin/lastseen-run
0 2 * * * /usr/local/bin/lastseen-run YOUR-KEY /usr/local/bin/backup.sh

For a job that runs at set times rather than every few minutes, watch it on its cron schedule.

From code #

Python, with only the standard library:

import urllib.request

urllib.request.urlopen("https://ping.lastseen.io/YOUR-KEY?v=21.5", timeout=10)

A fuller example, with retries, is at app.lastseen.io/examples/heartbeat.py. For ESP32 and ESP8266, the LastSeen Arduino library handles retries, seq and up for you.

HTTPS or plain HTTP #

ping.lastseen.io answers on both https:// and plain http://. Use HTTPS wherever you can. Plain HTTP is there for small devices like the ESP8266, for which TLS costs too much memory; the Arduino library uses it.

Keys #

The key is 26 characters, and LastSeen stores it hashed. Admins can show it again on the monitor's page. Rotate key on the monitor's page makes a new one and stops the old one at once; the monitor's history notes who rotated it.