Features

Everything between a log line and an acknowledged alert.

Deduplication that folds 40,000 repeats into one counter. Rules you declare instead of regex you babysit. Escalation ladders that stop only at ack, on-call rotations that pick whose phone rings, and delivery you can audit line by line — all in a single Go binary.

a complete paging policy
curl -s $PT/v1/projects/payments/rules \
  -H "Authorization: Bearer $API_KEY" \
  -d '{
    "name": "worker-crashes",
    "match": { "min_level": 400, "tags": ["prod"] },
    "fire_after": { "count": 5, "window_minutes": 10 },
    "escalations": [
      { "schedules": ["payments-oncall"] },
      { "after_minutes": 15, "repeat_minutes": 15,
        "accounts": ["[email protected]"] }
    ]
  }'

The core

Built to page you once — and only when it's real

40,000 repeats become one alert

Pingtower strips the variable parts of each message to recover its shape, then hashes it — so the same failure bumps a counter on one alert instead of flooding a channel. Or group by keys like a username, and get one alert per affected account.

Rules you declare, not regex you babysit

Match on level, source, tags, or message shape; add conditions on structured keys; set thresholds like “fire after 5 hits in 10 minutes” or “only when 3 different sources see it.” One engine, no separate monitor concept.

Escalation that doesn't give up

Ladders move an unacked alert up level by level — Slack first, on-call push later — repeating on the schedule you set until someone acks. Acked alerts hold their place; quiet ones auto-resolve.

Delivery you can audit

Every notification is a durable outbox row, delivered at-least-once and logged per integration — a restart never drops a page. Webhooks are HMAC-SHA256 signed, and failing channels surface their errors instead of hiding them.

Paranoid where it counts

Tenant-supplied URLs pass an SSRF guard — no private ranges, no redirects, DNS-rebinding pinned. Delivery secrets are AES-256-GCM encrypted at rest, tokens compare in constant time, and everything lands in an audit log.

A single binary and a SQLite file

One Go binary, zero CGO, stdlib HTTP, pure-Go SQLite in WAL mode. Each tenant is its own database file, so a backup is a file copy. Self-host the daemon with a handful of flags on any box you own — ingest, rules, escalation, and webhook delivery all run there. The iOS app and its push notifications are hosted by us.

Runbooks that run themselves

Attach an HTTP action to a rule and it fires the moment the alert opens or escalates — restart the worker, flush the queue, open a ticket. Credentials are sealed at rest, every run is logged with status and response, and you can test-fire before you trust it.

Your whole team, one tower

Organizations with owner, admin, and member roles; email invites; API keys you can mint and revoke per tenant. Belong to several orgs with one account, switch between them in the app — and every sensitive change lands in the audit log.

On-call

It doesn't page everyone. It pages whoever's on shift.

Build rotations from your project's members: layers take timed shifts, restrictions carve out business hours and nights in your timezone, and a later layer overrides the ones below — nights on top of a daytime base. When an alert fires, the push goes to the phone of whoever is on shift. Everyone else sleeps.

  • Layered rotations — daytime base, night shift on top
  • One-off overrides for swaps and vacations
  • Your phone stays quiet unless you're on call
  • DST-safe shifts in your schedule's own timezone

The last mile

The best rule engine is worthless if nobody wakes up.

Every feature above ends at the same place: a native iOS app whose critical alerts sound through Silent mode and Focus — and one swipe in the app acknowledges the alert and stops the ladder for everyone.

Try it

Zero to paged in minutes.

Hosted and free while Pingtower is in pre-release — or download a signed binary and run the whole data plane on your own box. Either way, the first alert is one curl away.