API Reference
Authentication
All API requests require authentication. Two methods are available: a personal API key (for most integrations) and a JWT token (for web applications and endpoints that don’t yet support the key).
API Key
Create a personal API key from your profile menu. Use the X-API-Key header:
curl -H "X-API-Key: YOUR_API_KEY" \
https://pingzen.dev/api/v1/monitorsTo create an API key: Click on your profile → API Keys → Create New Key
Where X-API-Key works, and where JWT is required
Important
At this time, X-API-Key is accepted only on the monitors endpoints (CRUD, pause/resume, reorder, main statistics, timeline, and CSV export/import). All other endpoints — /workspaces, /alerts, /incidents, /status-pages, /monitor-groups, /probes, /heartbeats (except the no-auth /ping/...), /maintenance, /feedback, /dashboard, /web-push, /scheduled-reports, /webhooks, /webhook-checks, /api-checks, /api-keys, /auth/*, /analytics, /telegram-bot, /alert-channel-configs — currently require a JWT token. This is a divergence from the historical promise of the docs; we’re closing it incrementally.
What X-API-Key covers right now:
/api/v1/monitorsCRUD (GET/POST/PATCH/DELETE), /reorder, /pause, /resume, /reset-stats, /results, /timeline, /status-ranges, /response-time-distribution, /cert-chain, /dnsbl-providers, /export/csv, /import/csv/api/v1/ping/:ping_key/:slugno auth (uses ping_key) — for heartbeatsInside /monitors/*, these still require JWT (known divergence, being fixed): GET /:id/stats, POST /:id/check, GET /:id/sla, GET /:id/sla/export/csv|pdf, GET /:id/dnsbl/provider-history, POST /test.
JWT Token
For web applications and endpoints that don’t accept the API key, use a JWT from /auth/login:
# 1. Obtain a token (pass email and password)
ACCESS=$(curl -sS -X POST https://pingzen.dev/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"you@example.com","password":"…"}' \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["access_token"])')
# 2. Use it as Authorization: Bearer
curl -H "Authorization: Bearer $ACCESS" https://pingzen.dev/api/v1/workspacesThe access token lives for 15 minutes; for long-running integrations use the refresh_token from the same response and the /auth/refresh endpoint.
Endpoints
Complete list of all available API endpoints.
Monitors
Monitor management (22 endpoints, grouped by purpose).
CRUD
/api/v1/monitors— List your monitors/api/v1/monitors— Create a monitor/api/v1/monitors/:id— Get monitor details/api/v1/monitors/:id— Update monitor/api/v1/monitors/:id— Delete monitorOperations
/api/v1/monitors/:id/pause— Pause monitoring/api/v1/monitors/:id/resume— Resume monitoring/api/v1/monitors/:id/check— Run manual check (JWT)/api/v1/monitors/:id/reset-stats— Wipe accumulated history (requires confirm)/api/v1/monitors/reorder— Set custom display order/api/v1/monitors/test— Test a config without saving (JWT)/api/v1/monitors/export/csv— Export monitor configs as CSV (all workspaces or ?workspace_id=; secrets excluded)/api/v1/monitors/import/csv— Bulk-create monitors from a CSV file (multipart; ?dry_run=true to preview, ?on_duplicate=skip|create; max 500 rows / 1 MB)CSV import notes: you only need a url column. Files from StatusCake, the UptimeRobot bulk-upload template, and HetrixTools work as they are (, and ; are both detected). A row is a duplicate when the same URL and protocol already exist in the target workspace; duplicates are skipped by default. Without ?workspace_id=, each row goes to the workspace named in its workspace column, and a row with no workspace goes to your default workspace. Monitor names must be unique in your account, so copying one of your own workspaces into another one needs new names — name clashes go to skipped with the reason. You can import into your own workspaces, and into shared workspaces where you are an editor or owner (viewers get 403 or a per-row error). UptimeRobot number types (1/2/3/4) and StatusCake DoNotFind are supported. Excel files are not accepted — save them as CSV UTF-8 first. The response lists every row as created, skipped, or failed; one bad row does not stop the others.
Stats & history
/api/v1/monitors/:id/stats— Aggregate statistics (JWT)/api/v1/monitors/:id/results— Raw check-result history/api/v1/monitors/:id/timeline— Status change timeline/api/v1/monitors/:id/status-ranges— Run-length-encoded status ranges/api/v1/monitors/:id/response-time-distribution— Response time percentiles (P50/P90/P95/P99)/api/v1/monitors/:id/sla— SLA report (JWT)/api/v1/monitors/:id/sla/export/csv— Export SLA as CSV (JWT)/api/v1/monitors/:id/sla/export/pdf— Export SLA as PDF (JWT)Diagnostics
/api/v1/monitors/:id/cert-chain— Live inspect TLS certificate chain/api/v1/monitors/:id/dnsbl/provider-history— DNSBL per-provider history (JWT)/api/v1/monitors/dnsbl-providers— Default DNSBL provider listAlerts
Alert configuration.
/api/v1/alerts— List alerts/api/v1/alerts— Create alert/api/v1/alerts/:id— Update alert/api/v1/alerts/:id— Delete alert/api/v1/alerts/:id/test— Send test alert/api/v1/alerts/:id/toggle— Toggle alert active/inactive/api/v1/alerts/:id/history— Get alert delivery history/api/v1/alerts/history— All alert delivery history (per workspace)/api/v1/alerts/channels/availability— Available delivery channels (Telegram, Discord, Email, Slack, …)/api/v1/alerts/test-send— Send a test message to an arbitrary channel (without saving an alert)Incidents
Incident management.
/api/v1/incidents— List incidents/api/v1/incidents/stats— Aggregate incident stats (total/ongoing/resolved/MTTR)/api/v1/incidents/:id— Get incident details/api/v1/incidents/:id— Update incident/api/v1/incidents/:id/updates— Add status update/api/v1/incidents/:id/resolve— Resolve incident/api/v1/incidents/:id— Delete incidentStatus Pages
Public status pages.
/api/v1/status-pages— List status pages/api/v1/status-pages— Create status page/api/v1/status-pages/:id— Get status page/api/v1/status-pages/:id— Update status page/api/v1/status-pages/:id— Delete status page/api/v1/status-pages/:id/monitors— Add a monitor to the status page/api/v1/status-pages/:id/monitors/:monitor_id— Remove a monitor from the status page/api/v1/public/status/:slug— Public status (no auth)Workspaces
Workspace management.
/api/v1/workspaces— List your workspaces/api/v1/workspaces/default— Get your default workspace (fastest way to discover workspace_id)/api/v1/workspaces/summary— Compact list (id, name) — handy for dropdowns/api/v1/workspaces— Create workspace/api/v1/workspaces/:id— Update workspace/api/v1/workspaces/:id— Delete workspace/api/v1/workspaces/:id/set-default— Set default workspace/api/v1/workspaces/:id/regenerate-ping-key— Rotate ping_key (existing heartbeat ping URLs stop working)/api/v1/workspaces/:id/members— List workspace members (shared workspaces)/api/v1/workspaces/:id/members— Invite a member by email (owner only)/api/v1/workspaces/:id/members/:id— Change a member's role: editor or viewer (owner only)/api/v1/workspaces/:id/members/:id— Remove a member (owner only)/api/v1/workspaces/:id/invites— Create a one-time invite link, valid 14 days (owner only; works for users without an email)/api/v1/workspaces/invites/accept— Accept an invite link and join the workspace/api/v1/workspaces/:id/leave— Leave a shared workspace (members only; the owner cannot leave)Heartbeats (Cron)
Cron job monitoring.
/api/v1/heartbeats— List heartbeat monitors/api/v1/heartbeats— Create heartbeat monitor/api/v1/heartbeats/:id— Get heartbeat monitor details/api/v1/heartbeats/:id— Update heartbeat monitor/api/v1/heartbeats/:id— Delete heartbeat monitor/api/v1/heartbeats/:id/pause— Pause heartbeat monitor/api/v1/heartbeats/:id/resume— Resume heartbeat monitor/api/v1/heartbeats/:id/regenerate-secret— Regenerate authentication secret/api/v1/heartbeats/:id/stats— Get heartbeat statistics (uptime, ping counts)/api/v1/heartbeats/:id/pings— Get ping history (paginated)/api/v1/ping/:ping_key/:slug— Record ping via GET (no auth, for simple cron jobs)/api/v1/ping/:ping_key/:slug— Record ping via POST (no auth, with optional payload)/api/v1/ping/:ping_key/:slug/start— Record job start signal (no auth)/api/v1/ping/:ping_key/:slug/success— Record job success signal (no auth)/api/v1/ping/:ping_key/:slug/fail— Record job failure signal (no auth)API Keys
API key management.
/api/v1/api-keys— List API keys/api/v1/api-keys— Create API key/api/v1/api-keys/:id— Revoke API keyMaintenance
Maintenance windows.
/api/v1/maintenance— List maintenance windows/api/v1/maintenance— Create maintenance window/api/v1/maintenance/:id— Get maintenance window details/api/v1/maintenance/:id— Update maintenance window/api/v1/maintenance/:id— Delete maintenance window/api/v1/maintenance/:id/cancel— Cancel maintenanceMonitor Groups
Group management (12 endpoints, grouped by purpose).
Group CRUD
/api/v1/monitor-groups— List monitor groups/api/v1/monitor-groups— Create monitor group/api/v1/monitor-groups/:id— Get monitor group details/api/v1/monitor-groups/:id— Update group (name, description, paused flag)/api/v1/monitor-groups/:id— Delete monitor groupMemberships (monitors & tags)
/api/v1/monitor-groups/:id/monitors— Add monitors to group/api/v1/monitor-groups/:id/monitors— Remove monitors from group/api/v1/monitor-groups/:id/tags— Add tags/api/v1/monitor-groups/:id/tags— Remove tagsStatus & stats
/api/v1/monitor-groups/stats— Aggregate stats across all groups/api/v1/monitor-groups/:id/status— Get aggregate group status/api/v1/monitor-groups/:id/status— Update aggregate group statusTelegram Groups
Telegram group alerts.
/api/v1/telegram-groups— List linked Telegram groups/api/v1/telegram-groups/link— Generate deep-link URL for Telegram group/api/v1/telegram-groups/:id— Unlink Telegram groupScheduled Reports
Automated email reports.
/api/v1/scheduled-reports— List scheduled reports/api/v1/scheduled-reports— Create scheduled report/api/v1/scheduled-reports/:id— Get report details/api/v1/scheduled-reports/:id— Update scheduled report/api/v1/scheduled-reports/:id— Delete scheduled report/api/v1/scheduled-reports/:id/pause— Pause report/api/v1/scheduled-reports/:id/resume— Resume report/api/v1/scheduled-reports/:id/run— Run report manually/api/v1/scheduled-reports/:id/toggle— Toggle active flag (pause/resume in one call)/api/v1/scheduled-reports/:id/runs— Report execution historyAlert Channel Configs
Channel credentials (SMTP, Twilio, etc.).
/api/v1/alert-channel-configs— List channel configurations/api/v1/alert-channel-configs— Create channel config/api/v1/alert-channel-configs/:id— Update channel config/api/v1/alert-channel-configs/:id— Delete channel config/api/v1/alert-channel-configs/:id/test— Send a test message via this config/api/v1/alert-channel-configs/:id/activate— Activate (re-enable after auto-disable from a delivery error streak)/api/v1/alert-channel-configs/:id/deactivate— Temporarily disable without deleting/api/v1/alert-channel-configs/channels/:channel— Active config for a channel (telegram, discord, slack, …)Dashboard
Aggregated statistics.
/api/v1/dashboard/stats— Aggregated dashboard statistics/api/v1/dashboard/uptime-summary— Overall uptime summary across all monitors/api/v1/dashboard/alerts-summary— Alerts summary/api/v1/dashboard/incidents— Incidents summary/api/v1/dashboard/combined— All dashboard data in one callWebhooks (Outgoing)
Event webhook delivery (12 endpoints, grouped by purpose).
Webhook CRUD
/api/v1/webhooks— List webhooks/api/v1/webhooks— Create webhook/api/v1/webhooks/:id— Get webhook details/api/v1/webhooks/:id— Update webhook/api/v1/webhooks/:id— Delete webhookActions
/api/v1/webhooks/:id/test— Send a test payload/api/v1/webhooks/:id/secret— Rotate HMAC signing secret (existing signatures stop being accepted on your side)Deliveries & DLQ
/api/v1/webhooks/:id/deliveries— Delivery history/api/v1/webhooks/:id/stats— Aggregate delivery statistics (success/error/p50/p95)/api/v1/webhooks/:id/dlq— Dead Letter Queue: deliveries that failed all retries/api/v1/webhooks/:id/dlq/:dlq_id/retry— Retry a DLQ entry/api/v1/webhooks/:id/dlq/:dlq_id/resolve— Mark a DLQ entry resolved (without retrying)Reference
/api/v1/webhooks/events— Available event types (used when creating a webhook)Webhook Checks (Incoming)
Accept incoming webhooks from external services (10 endpoints + 1 public receiver, grouped by purpose).
Check CRUD
/api/v1/webhook-checks— List incoming webhook checks/api/v1/webhook-checks— Create incoming webhook check/api/v1/webhook-checks/:id— Get webhook check details/api/v1/webhook-checks/:id— Update webhook check/api/v1/webhook-checks/:id— Delete webhook checkCheck operations
/api/v1/webhook-checks/:id/pause— Pause webhook check/api/v1/webhook-checks/:id/resume— Resume webhook check/api/v1/webhook-checks/:id/regenerate-secret— Rotate secret (the existing HMAC signature from the source stops being accepted)Events & stats
/api/v1/webhook-checks/:id/events— Incoming webhook check events/api/v1/webhook-checks/:id/stats— Aggregate stats for an incoming checkPublic receiver (no auth)
/api/v1/webhook-check/:slug— Record a delivery (this URL is what you hand to the external service)Feedback
User feedback and feature requests.
/api/v1/feedback— Submit feedback/api/v1/feedback— List feedback/api/v1/feedback/:id— Get feedback details/api/v1/feedback/:id/status— Update feedback status (admin)/api/v1/feedback/:id— Delete feedback (admin)Web Push
Browser push notifications.
/api/v1/web-push/vapid-public-key— Get VAPID public key/api/v1/web-push/subscriptions— List push subscriptions for the current user/api/v1/web-push/subscribe— Subscribe to push notifications/api/v1/web-push/unsubscribe— Unsubscribe from push notificationsProbe
Probe identification and IP addresses.
/api/v1/probe/ips— Get probe IP addresses (public, no auth)Request Examples
Detailed cURL examples.
List monitors
curl -H "X-API-Key: YOUR_API_KEY" \
https://pingzen.dev/api/v1/monitors?workspace_id=1How to find your workspace_id
The workspace_id field is required in the payload when creating monitors, alerts, reports, and status pages. There are two ways to get it.
Option 1: via UI (fastest). Open the workspaces page — each workspace card shows its ID. For most users it’s 1.
Option 2: via API (for CI/scripts). The /api/v1/workspaces* endpoints currently require JWT, not X-API-Key (see “Where X-API-Key works” above). Steps:
# 1. Log in — get an access_token
ACCESS=$(curl -sS -X POST https://pingzen.dev/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"you@example.com","password":"…"}' \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["access_token"])')
# 2. Default workspace (the one pre-selected in the UI)
curl -sS -H "Authorization: Bearer $ACCESS" \
https://pingzen.dev/api/v1/workspaces/default
# → {"id": 42, "name": "My Workspace", "is_default": true, ...}
# 3. Or a compact list of all (id, name) for dropdowns
curl -sS -H "Authorization: Bearer $ACCESS" \
https://pingzen.dev/api/v1/workspaces/summaryOne-liner “log in → fetch default id” for CI:
ACCESS=$(curl -sS -X POST https://pingzen.dev/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d "{\"email\":\"$EMAIL\",\"password\":\"$PASS\"}" \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["access_token"])')
WORKSPACE_ID=$(curl -sS -H "Authorization: Bearer $ACCESS" \
https://pingzen.dev/api/v1/workspaces/default \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')
echo "$WORKSPACE_ID" # → 42Then plug $WORKSPACE_ID into the POST /api/v1/monitors payload below (that one is an X-API-Key endpoint).
Create a monitor
curl -X POST https://pingzen.dev/api/v1/monitors \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "My Site", "url": "https://example.com", "protocol": "https", "workspace_id": 1, "interval_seconds": 60}'Get monitor
curl -H "X-API-Key: YOUR_API_KEY" \
https://pingzen.dev/api/v1/monitors/123Update monitor
curl -X PATCH https://pingzen.dev/api/v1/monitors/123 \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"interval_seconds": 60, "name": "Updated Name"}'Minimum interval_seconds depends on plan: FREE — 60s, paid — 30s. A value below the plan minimum returns 422 with a descriptive error.
Delete monitor
curl -X DELETE https://pingzen.dev/api/v1/monitors/123 \
-H "X-API-Key: YOUR_API_KEY"Create a heartbeat monitor
Create a heartbeat monitor for cron jobs and scheduled tasks. Returns a unique ping URL and secret. /heartbeats CRUD currently requires JWT (see “Where X-API-Key works”); workspace_id is passed as a query parameter, not in the body:
curl -X POST "https://pingzen.dev/api/v1/heartbeats?workspace_id=$WORKSPACE_ID" \
-H "Authorization: Bearer $ACCESS" \
-H "Content-Type: application/json" \
-d '{"name": "Daily Backup", "expected_interval_seconds": 86400, "grace_period_seconds": 600}'Send heartbeat ping (GET)
Simplest integration — just add to crontab or end of script. No authentication required.
# Simplest: chain with && so ping fires only on success
0 3 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 https://pingzen.dev/api/v1/ping/YOUR_PING_KEY/YOUR_SLUG
# Or just a standalone ping
curl https://pingzen.dev/api/v1/ping/aBcDeFgHiJkLmNoPqR/daily-backupHeartbeat lifecycle signals
Report job lifecycle signals (start/success/fail) with optional payload and duration. Use X-Secret header for authentication.
# Report success with payload and duration
curl -X POST https://pingzen.dev/api/v1/ping/aBcDeFgHiJkLmNoPqR/daily-backup/success \
-H "X-Secret: YOUR_SECRET" \
-H "Content-Type: application/json" \
-d '{"duration_ms": 45000, "payload": {"rows": 500000}}'
# Report failure — triggers instant alert (no waiting for missed interval)
curl -X POST https://pingzen.dev/api/v1/ping/aBcDeFgHiJkLmNoPqR/daily-backup/fail \
-H "X-Secret: YOUR_SECRET" \
-H "Content-Type: application/json" \
-d '{"payload": {"error": "disk full"}}'
# One-liner for cron: success OR fail
/usr/local/bin/backup.sh \
&& curl -fsS -m 10 https://pingzen.dev/api/v1/ping/aBcDeFgHiJkLmNoPqR/daily-backup/success \
|| curl -fsS -m 10 https://pingzen.dev/api/v1/ping/aBcDeFgHiJkLmNoPqR/daily-backup/failCode Examples
Python Example
import requests
# Get your API key from: Profile → API Keys → Create New Key
PINGZEN_API_KEY = "YOUR_API_KEY"
BASE_URL = "https://pingzen.dev/api/v1"
headers = {
"X-API-Key": PINGZEN_API_KEY,
"Content-Type": "application/json"
}
# Create a monitor
monitor_data = {
"name": "My Website",
"url": "https://example.com",
"protocol": "https",
"interval_seconds": 60,
"workspace_id": 1
}
response = requests.post(
f"{BASE_URL}/monitors",
headers=headers,
json=monitor_data
)
print(response.json())
# Get all monitors (response is {monitors: [...], total, page, page_size})
data = requests.get(
f"{BASE_URL}/monitors",
headers=headers,
params={"workspace_id": 1}, # scope to your workspace
).json()
for monitor in data["monitors"]:
print(f"{monitor['name']}: {monitor['status']}")JavaScript Example
// Get your API key from: Profile → API Keys → Create New Key
const PINGZEN_API_KEY = 'pz_abc12345_...';
const BASE_URL = 'https://pingzen.dev/api/v1';
const headers = {
'X-API-Key': PINGZEN_API_KEY,
'Content-Type': 'application/json'
};
// Create a monitor
async function createMonitor() {
const response = await fetch(`${BASE_URL}/monitors`, {
method: 'POST',
headers: headers,
body: JSON.stringify({
name: 'My Website',
url: 'https://example.com',
protocol: 'https',
interval_seconds: 60,
workspace_id: 1
})
});
const data = await response.json();
console.log(data);
}
// Get all monitors (response is {monitors: [...], total, page, page_size})
async function getMonitors() {
const response = await fetch(
`${BASE_URL}/monitors?workspace_id=1`, // scope to your workspace
{ headers: headers },
);
const data = await response.json();
data.monitors.forEach(monitor => {
console.log(`${monitor.name}: ${monitor.status}`);
});
}
createMonitor();
getMonitors();Heartbeat / Cron Monitoring Examples
Monitor cron jobs, scheduled tasks, and background processes. Create a heartbeat monitor, then send pings from your scripts to confirm they ran.
Bash / Cron Job
#!/bin/bash
# === Pattern 1: Chain with && (recommended for cron) ===
# curl runs ONLY if backup succeeds (exit code 0)
# If backup fails — no ping — PingZen alerts after grace period
#
# 0 2 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 https://pingzen.dev/api/v1/ping/YOUR_PING_KEY/YOUR_SLUG
# === Pattern 2: Report both success AND failure (best) ===
# /success on success, /fail on failure — instant alert, no waiting
#
# 0 2 * * * /usr/local/bin/backup.sh \
# && curl -fsS -m 10 https://pingzen.dev/api/v1/ping/YOUR_PING_KEY/YOUR_SLUG/success \
# || curl -fsS -m 10 https://pingzen.dev/api/v1/ping/YOUR_PING_KEY/YOUR_SLUG/fail
# === Pattern 3: Full script with duration and payload ===
PING_KEY="YOUR_PING_KEY"
SLUG="daily-backup"
SECRET="YOUR_SECRET"
PING_URL="https://pingzen.dev/api/v1/ping/$PING_KEY/$SLUG"
SECONDS=0 # Bash built-in timer
# Your backup logic
pg_dump mydb > /backups/mydb_$(date +%F).sql
if [ $? -eq 0 ]; then
# Report success with duration
curl -fsS -m 10 -X POST "$PING_URL/success" \
-H "X-Secret: $SECRET" \
-H "Content-Type: application/json" \
-d "{\"duration_ms\": $((SECONDS * 1000))}"
else
# Report failure — instant alert
curl -fsS -m 10 -X POST "$PING_URL/fail" \
-H "X-Secret: $SECRET" \
-H "Content-Type: application/json" \
-d "{\"payload\": {\"error\": \"pg_dump failed\"}}"
fiPython Heartbeat
import requests
BASE_URL = "https://pingzen.dev/api/v1"
# /heartbeats CRUD currently requires JWT (X-API-Key not yet supported).
# Log in once and reuse the token; refresh via /auth/refresh after 15 minutes.
login = requests.post(
f"{BASE_URL}/auth/login",
json={"email": "you@example.com", "password": "..."},
).json()
ACCESS = login["access_token"]
WORKSPACE_ID = requests.get(
f"{BASE_URL}/workspaces/default",
headers={"Authorization": f"Bearer {ACCESS}"},
).json()["id"]
# Create a heartbeat monitor (workspace_id goes in the query, not the body)
heartbeat = requests.post(
f"{BASE_URL}/heartbeats",
params={"workspace_id": WORKSPACE_ID},
headers={"Authorization": f"Bearer {ACCESS}", "Content-Type": "application/json"},
json={
"name": "Daily Backup",
"expected_interval_seconds": 86400,
"grace_period_seconds": 600,
},
).json()
ping_key = heartbeat["ping_key"] # Workspace secret key
slug = heartbeat["slug"]
secret = heartbeat["secret"] # Save this — shown only once!
ping_url = f"{BASE_URL}/ping/{ping_key}/{slug}"
print(f"Ping URL: {ping_url}")
# Send a ping at the end of your script (no auth needed for the ping itself,
# X-Secret authenticates lifecycle signals)
requests.post(
f"{ping_url}/success",
headers={"X-Secret": secret, "Content-Type": "application/json"},
json={"duration_ms": 12000, "payload": {"status": "ok"}},
)JavaScript Heartbeat
const BASE_URL = 'https://pingzen.dev/api/v1';
// /heartbeats CRUD currently requires JWT (X-API-Key not yet supported).
// Login once, reuse the token; refresh via /auth/refresh after 15 minutes.
async function login(email, password) {
const res = await fetch(`${BASE_URL}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});
return (await res.json()).access_token;
}
async function defaultWorkspaceId(access) {
const res = await fetch(`${BASE_URL}/workspaces/default`, {
headers: { 'Authorization': `Bearer ${access}` },
});
return (await res.json()).id;
}
// Create a heartbeat monitor (workspace_id goes in the query, not the body)
async function createHeartbeat(access, workspaceId) {
const response = await fetch(
`${BASE_URL}/heartbeats?workspace_id=${workspaceId}`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${access}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Nightly Report',
expected_interval_seconds: 86400,
grace_period_seconds: 600,
}),
},
);
const data = await response.json();
console.log('Ping URL:', `${BASE_URL}/ping/${data.ping_key}/${data.slug}`);
console.log('Secret:', data.secret); // Save — shown only once!
return data;
}
// Send heartbeat ping from your cron job (no JWT needed; X-Secret authenticates)
async function sendPing(pingKey, slug, secret) {
await fetch(`${BASE_URL}/ping/${pingKey}/${slug}/success`, {
method: 'POST',
headers: {
'X-Secret': secret,
'Content-Type': 'application/json',
},
body: JSON.stringify({
duration_ms: 5000,
payload: { rows_processed: 1000 },
}),
});
}OpenAPI & AI Agents
PingZen provides machine-readable specifications for AI agent integration and automation tools.
Rate Limits
| Plan | Requests/Hour | Burst Limit |
|---|---|---|
| Free | 100/hour | 10/minute |