tickstem/heartbeat
May 3, 2026 · View on GitHub
Go SDK for Tickstem — dead-man's switch heartbeat monitoring. Your job pings a URL after each successful run. If the ping stops arriving, Tickstem alerts you by email.
Install
go get github.com/tickstem/heartbeat
Quick start
package main
import (
"context"
"log"
"os"
"github.com/tickstem/heartbeat"
)
func main() {
client := heartbeat.New(os.Getenv("TICKSTEM_API_KEY"))
// Create once — save the token somewhere permanent
hb, err := client.Create(context.Background(), heartbeat.CreateParams{
Name: "daily backup",
IntervalSecs: 86400, // expect a ping every 24h
GraceSecs: 3600, // allow 1h buffer before alerting
})
if err != nil {
log.Fatal(err)
}
log.Printf("ping URL: https://api.tickstem.dev/v1/heartbeats/%s/ping", hb.Token)
}
Then, at the end of every successful job run:
if err := client.Ping(ctx, hb.Token); err != nil {
log.Println("heartbeat ping failed:", err) // non-fatal — don't block the job
}
No API key is required to ping — the token is the credential.
API
Create
hb, err := client.Create(ctx, heartbeat.CreateParams{
Name: "weekly report",
IntervalSecs: 604800, // 7 days
GraceSecs: 7200, // 2h grace
})
| Field | Type | Default | Description |
|---|---|---|---|
Name | string | required | Human-readable label |
IntervalSecs | int | 3600 | Expected ping interval in seconds (60–86400) |
GraceSecs | int | 300 | Buffer after deadline before alerting (0–86400) |
Ping
err := client.Ping(ctx, token)
Call this after each successful run. No auth header — the token is the credential.
Manage
// List all heartbeats
heartbeats, err := client.List(ctx)
// Get one by ID
hb, err := client.Get(ctx, id)
// Update fields
newInterval := 7200
hb, err := client.Update(ctx, id, heartbeat.UpdateParams{
IntervalSecs: &newInterval,
})
// Pause/resume (suppresses alerts without deleting)
hb, err := client.Pause(ctx, id)
hb, err := client.Resume(ctx, id)
// Delete permanently
err := client.Delete(ctx, id)
Ping history
pings, err := client.Pings(ctx, heartbeatID, heartbeat.PingsParams{Limit: 50})
for _, p := range pings {
fmt.Println(p.PingedAt)
}
Error handling
hb, err := client.Create(ctx, params)
if err != nil {
switch {
case heartbeat.IsUnauthorized(err):
// invalid or revoked API key
case heartbeat.IsQuotaExceeded(err):
// heartbeat limit reached for your plan
case heartbeat.IsNotFound(err):
// heartbeat not found
default:
// network error or unexpected status
}
}
Plans
| Plan | Heartbeats |
|---|---|
| Free | 5 |
| Starter | 20 |
| Pro | 100 |
| Business | Unlimited |
License
MIT