The heartbeat client ships in
@peaqos/peaq-os-sdk 0.5.0+ (JS/TS) and peaq-os-sdk 0.5.0+ (Python) under the monetization namespace. It talks to the dedicated peaqOS heartbeat service; the peaq-hosted instance is https://heartbeat.peaq.xyz, and the base URL stays configuration, never a constant.getMonetization / get_monetization), and stop it when the machine opts out.
Push, not poll
The machine is a client of the heartbeat service: it pushes a signed heartbeat out. It does not host an endpoint that others poll, and it never serves its own availability.The 180-second TTL and the interval bound
A valid heartbeat marks the machine online for a fixed presence TTL of 180 seconds. Miss that window and the server flips the machine to offline. To stay online, the machine must heartbeat comfortably more often than the TTL, so the client caps the configured interval:start rejects an interval that is zero, negative, or above the maximum. The exact interval within that bound is caller-supplied configuration.
Offline is server-derived. The client never self-reports offline. Stopping the client simply stops heartbeating; the server observes the absence and lets presence lapse. Operator-initiated maintenance is expressed the same way: stop the client.
Request-signing auth
There is no bearer credential. The server authenticates each heartbeat by verifying thesignature against the publicKey in the payload.
- The machine identity private key is held only by your signer implementation. The client passes it a canonical message and receives a hex signature; the client never handles or logs the raw key.
publicKey,signature,machineId, andsentAtare not secret and are safe to log.
buildCanonicalMessage / build_canonical_message, the single place this format is defined.
Quick start
{ machineId, publicKey, sentAt, signature } and parses { accepted, online, lastHeartbeatAt }, surfaced through the optional result callback.
Fire-and-forget
A failed push, whether a network error or anaccepted: false response, is logged and retried on the next tick. It never throws out of the timer and never blocks the machine’s other operations. Every parsed response reaches the result callback, including rejections.
A hung push cannot stall the loop either. In JS/TS the whole tick (signing plus push) is time-bounded to 30 seconds, or the interval if shorter. In Python the bound is per request: the transport’s 10-second HTTP timeout, with signing cancelled cooperatively rather than forced. A server that accepts the connection but never responds is timed out, logged, and retried on the next tick like any other failure.
stop() is the one exception: it cancels the timer, aborts any in-flight request (including one still signing), and is treated as expected cancellation, not a failure. No error log, no result callback, no retry.
Presence query
checkPresence / check_presence is a standalone one-shot query with no scheduler and no signing. Pass exactly one of machineId or publicKey:
online is false and publicKey / lastHeartbeatAt are null.
Presence only
The heartbeat payload is a pure presence signal: it carries no status field and no queue depth. Presence is binary under this API: online (a valid heartbeat within 180 seconds) or offline (TTL expired). Utilisation states such asbusy are not represented, and maintenance is expressed by stopping the client. Do not add extra fields to the payload.
API summary
Related
- Monetize function: where the heartbeat fits in the flow
- Provisioning SDK reference: provision the provider node first
- Monetization opt-in API

