For AI agents
Set up Pingtower for your user
This page is written for AI agents setting up Pingtower on a user’s behalf. Machine-readable companions: /llms.txt, this page as markdown at /agents/index.md, the API reference as markdown, and the OpenAPI spec — generated from the server’s own route table and gated against drift, so it cannot describe a contract the server does not keep.
What Pingtower is — and is not
Log-driven alerting: the user’s services POST structured log events, the server collapses repeats by message shape, evaluates declarative rules, and escalates until a human acknowledges. It is not an uptime prober: there are no HTTP/TCP/ping checks and no heartbeat, so it cannot detect a service that has stopped logging. If your user asked for uptime monitoring, tell them that before setting anything up.
Division of labor
You can do the entire server side end to end: install, account, tenant, keys, project, source, rules, and verification. Only the human can install the iOS app on their phone and redeem a pairing code. Finish with the explicit handoff in the last step.
Secrets discipline: the account password, the ptk_ API key, and the
pti_ ingest token are each shown exactly once at creation — there is no
route that reads them back, only rotation. Capture them into the user’s
secret store as they appear. Never write them into the repo, and don’t echo
them into files you leave behind.
Choose a plane
Recommended: hosted. The fastest path to a working setup is the hosted service — no server to install or maintain. Set:
PT=https://api.pingtower.com
and skip straight to bootstrap. Only self-host (step 1) when the user explicitly wants their alert data on their own box.
1. Install the server (self-hosted)
Download the signed release for the box’s architecture, verify it, and
refuse to run it if either check fails. Checksums are on the
get-started page; the release public key is
pingtower-release.pub.
case "$(uname -m)" in x86_64) arch=amd64 ;; aarch64|arm64) arch=arm64 ;; esac
curl -fsSLO https://www.pingtower.com/dist/pingtower-linux-$arch
curl -fsSLO https://www.pingtower.com/dist/pingtower-linux-$arch.minisig
curl -fsSLO https://www.pingtower.com/dist/pingtower-release.pub
minisign -Vm pingtower-linux-$arch -p pingtower-release.pub
Install it with a dedicated system user and a systemd unit:
sudo install -m 0755 pingtower-linux-$arch /usr/local/bin/pingtower
sudo useradd --system --home /var/lib/pingtower --shell /usr/sbin/nologin pingtower
sudo mkdir -p /var/lib/pingtower
sudo chown pingtower:pingtower /var/lib/pingtower
/etc/systemd/system/pingtower.service:
[Unit]
Description=pingtower
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=pingtower
Group=pingtower
ExecStart=/usr/local/bin/pingtower \
-listen 127.0.0.1:8391 \
-data-dir /var/lib/pingtower
Restart=on-failure
RestartSec=2
TimeoutStopSec=20
LimitNOFILE=65536
UMask=0077
NoNewPrivileges=yes
ProtectSystem=strict
ReadWritePaths=/var/lib/pingtower
ProtectHome=yes
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
The daemon speaks plain HTTP on localhost and expects a reverse proxy to
terminate TLS. With Caddy, /etc/caddy/Caddyfile:
alerts.example.com {
reverse_proxy 127.0.0.1:8391
}
Start it and verify before going further:
sudo systemctl daemon-reload
sudo systemctl enable --now pingtower
curl -s http://127.0.0.1:8391/healthz
Useful flags: -retain-days, -max-logs-per-source, -backup-dir, and
-secret-key to seal integration credentials at rest (pingtower -h lists
them all).
2. Bootstrap: account, tenant, API key
Use the human’s real email — it is how they will log in from the iOS app.
# Create the account. Returns 201 with a pts_ session token.
curl -s "$PT/v1/signup" \
-H 'Content-Type: application/json' \
-d '{"email":"[email protected]","password":"…"}'
# → {"account":{…},"token":"pts_…"}
SESSION=pts_…
# Create the tenant. Returns 201 with the tenant id every later call needs.
curl -s "$PT/v1/tenants" \
-H "Authorization: Bearer $SESSION" \
-H 'Content-Type: application/json' \
-d '{"name":"Acme"}'
# → {"id":"<tid>","name":"Acme","role":"owner"}
# Mint the API key. No body. Returns 201; the token is shown only once.
curl -s -X POST "$PT/v1/tenants/<tid>/keys" \
-H "Authorization: Bearer $SESSION"
# → {"id":"…","token":"ptk_<tenant>_…"}
Token prefixes are the plane: pts_ manages the account, ptk_ reads and
configures everything, pti_ may only call /v1/ingest. They are mutually
exclusive — one kind can never be mistaken for another.
3. Project, source, rule
API=ptk_…
curl -s "$PT/v1/projects" \
-H "Authorization: Bearer $API" \
-d '{"name":"demo"}'
# Returns the source's pti_ ingest token, shown only once.
# retain_logs:true keeps events readable via logtail — useful for debugging.
curl -s "$PT/v1/projects/demo/sources" \
-H "Authorization: Bearer $API" \
-d '{"name":"api","retain_logs":true}'
# → {"name":"api","token":"pti_<tenant>_…"}
# Alert on every error-or-worse event, renotifying every 15 minutes
# until acked.
curl -s "$PT/v1/projects/demo/rules" \
-H "Authorization: Bearer $API" \
-d '{"name":"errors","match":{"min_level":400},"renotify_minutes":15}'
The API reference covers richer rules (tag, source, and shape matchers, key conditions, thresholds, escalation ladders), integrations (webhook, Slack, Telegram), runbook actions, on-call schedules, and incident reports.
4. Wire the user’s services
Anything that can POST JSON can be a source — add this where the user’s app
already logs errors. Levels are HTTP-ish: 100 debug, 200 info, 300 warn,
400 error, 500 critical. Put variable data in keys (it powers identifier
grouping); repeated messages dedup by shape into one alert with a count.
curl -s "$PT/v1/ingest" \
-H "Authorization: Bearer pti_<tenant>_…" \
-d '{"message":"payment failed","level":400,
"keys":{"order":"o_123"},"tags":["billing"]}'
5. Verify end to end
Do not report success on wiring alone — prove the pipeline. Send an event that matches the rule, watch it become an alert, then ack it:
# Returns 202 {"alerted":true,"template_id":"…"} when a rule matched.
curl -s "$PT/v1/ingest" \
-H "Authorization: Bearer pti_<tenant>_…" \
-d '{"message":"agent setup verification","level":400}'
# The alert appears here with an id.
curl -s "$PT/v1/pull?cursor=0" -H "Authorization: Bearer $API"
# Ack it so the verification doesn't keep renotifying.
curl -s -X POST "$PT/v1/alerts/<id>/ack" -H "Authorization: Bearer $API"
Only after the alert shows up in /v1/pull tell the user the setup works.
6. Hand off to the human
Tell the user, concretely:
- Where their tokens are — which secret store holds the API key and ingest token, and that the tokens cannot be read back, only rotated.
- What alerts when — the rules you created and their renotify cadence.
- Get the iOS app — it is not on the App Store yet. Until then, webhook, Slack, and Telegram integrations deliver alerts.
- Pairing for phone push (self-hosted only) — paging a phone through
the iOS app needs a pingtower.com account paired to the box: running
pingtower pair --email [email protected]on the server prints a one-shot code the human redeems in the app. Apple push for the App Store app can only be sent by pingtower.com; everything else stays on their box.