Skip to main content

Documentation

Complete guide to setting up website monitoring with PingZen. API documentation, code examples, and best practices.

Alert Configuration

PingZen supports multiple alert channels. Configure one or more channels for redundancy.

Telegram

The fastest way to receive notifications (1-2 seconds). One-click setup.

  1. In PingZen go to Alerts → Create Alert → select Telegram
  2. Click 'Connect Telegram' — a link to @pingzen_bot opens automatically
  3. Press Start in Telegram — your account is linked instantly
  4. For group alerts: switch to 'Group Chat' tab and click 'Add Bot to Group'

No need to copy Chat IDs manually — the wizard handles everything. You can also enter a Chat ID manually if needed.

Slack

Integration via Incoming Webhooks for team collaboration.

  1. In Slack go to Settings → Apps → Incoming Webhooks
  2. Click 'Add New Webhook to Workspace'
  3. Select a channel for notifications
  4. Copy the Webhook URL (https://hooks.slack.com/...)
  5. In PingZen create an alert and paste the URL

Create a dedicated #alerts channel for monitoring notifications.

Discord

One-click OAuth setup or paste a Webhook URL.

  1. In PingZen go to Alerts → Create Alert → select Discord
  2. Click 'Connect Discord' — you'll be redirected to Discord
  3. Select your server and channel, then authorize
  4. You're redirected back — the webhook is saved automatically

You can also paste a Webhook URL manually if you prefer. Create it in Discord: Server Settings → Integrations → Webhooks.

Microsoft Teams

Send alerts to Microsoft Teams channels via Incoming Webhook.

  1. 1.In Teams select channel → More options → Connectors
  2. 2.Find 'Incoming Webhook' and click Configure
  3. 3.Name the webhook and copy the URL
  4. 4.In PingZen create an MS Teams alert
  5. 5.Paste the Webhook URL

Mattermost

Slack-compatible webhooks for self-hosted teams.

  1. In Mattermost: Main Menu → Integrations → Incoming Webhooks
  2. Click Add Incoming Webhook
  3. Select a channel and copy the Webhook URL
  4. In PingZen use the Mattermost type

WhatsApp

Receive alerts via WhatsApp through the Twilio API.

  1. Create a Twilio account and set up a WhatsApp Business API
  2. Get your Twilio Account SID, Auth Token, and WhatsApp number
  3. In PingZen create a WhatsApp alert
  4. Enter your WhatsApp phone number (with country code, e.g. +1234567890)

WhatsApp alerts require a Twilio account with WhatsApp Business API enabled.

PagerDuty

Route alerts to PagerDuty for on-call escalation.

  1. In PagerDuty go to Services → Service Directory → select your service
  2. Go to Integrations tab → Add Integration → Events API v2
  3. Copy the Integration Key (routing key)
  4. In PingZen create a PagerDuty alert and paste the routing key

PagerDuty triggers real incidents with escalation policies — ideal for production services.

Browser Push Notifications

Get instant push notifications directly in your browser — no apps or extensions needed.

  1. Go to Settings → Notifications in PingZen
  2. Click 'Enable Push Notifications'
  3. Allow notifications when your browser prompts
  4. Alerts will be delivered even when PingZen is not open

Browser push works on Chrome, Firefox, and Edge. Requires HTTPS.

Email

Reliable email delivery via Resend. No configuration on your side — just enter an email address.

  1. In PingZen go to Alerts → Create Alert → select Email
  2. Enter the recipient email address (personal, team, or a distribution list)
  3. Save the alert — test delivery fires automatically from alerts@alerts.pingzen.dev
  4. Check your inbox (and the spam folder on the first delivery) to confirm

Sent from our dedicated alerts.pingzen.dev subdomain with SPF/DKIM/DMARC set up, so messages land in the inbox reliably. Includes a List-Unsubscribe header for Gmail's one-click unsubscribe button.

Webhook

Send JSON data to your HTTP endpoint for custom integrations (Home Assistant, n8n, Node-RED, IFTTT, your own services).

  1. Create an HTTP endpoint on your server to receive POST requests
  2. In PingZen create a Webhook alert
  3. Enter your endpoint URL
  4. Request method: POST, Content-Type: application/json, User-Agent: PingZen-Alert-Service/1.0
💡

Attached a single webhook to multiple monitors? Jump to "One webhook for multiple monitors", "Home Assistant example", or "ntfy.sh example" below — ready-made recipes with per-monitor routing are there.

JSON Payload Format

POST <your URL>
Content-Type: application/json
User-Agent: PingZen-Alert-Service/1.0

{
  "text": "🔴 My Website - Service Down",
  "body": "URL: https://example.com\nProtocol: HTTPS\nStatus: DOWN\nResponse Time: 5000ms\n\nOpen monitor: https://pingzen.dev/monitors/123?ws=4",
  "priority": "critical",
  "timestamp": "2026-04-22T10:30:00+00:00",
  "source": "pingzen",
  "monitor_url": "https://pingzen.dev/monitors/123?ws=4",
  "monitor_id": 123,
  "monitor_name": "My Website",
  "trigger": "down",
  "status": "down",
  "probes": [
    {"label": "Moscow", "status": "up", "fail_streak": 0},
    {"label": "Istanbul", "status": "down", "fail_streak": 3}
  ]
}

What body looks like once parsed:

URL: https://example.com
Protocol: HTTPS
Status: DOWN
Response Time: 5000ms

Open monitor: https://pingzen.dev/monitors/123?ws=4

Payload fields

FieldDescription
textHeadline: emoji + monitor name + localized status phrase ("Service Down" / "Сервис недоступен", "Service Recovered" / "Сервис восстановлен", "Service Degraded", "Certificate Expiring", etc.). Emoji: 🔴 DOWN/STILL_DOWN, 🟢 RECOVERED, 🟡 DEGRADED, ⚠️ CERTIFICATE_EXPIRING.
bodyMulti-line body: URL, Protocol, Status (uppercase enum value: DOWN/UP/DEGRADED) or Error, Response Time, HTTP Status, Open monitor. Both labels and status words are localized to the monitor's language. The set of included fields is configurable in the alert form under "Message content".
priorityEvent priority (NOT localized — safe for routing): critical (DOWN, STILL_DOWN, CERTIFICATE_EXPIRING — "real outage" bucket), high (DEGRADED, RESPONSE_TIME_HIGH), normal (RECOVERED). Filter on `priority == 'critical'` to catch outages and reminders together without picking up degraded/slow-response events.
timestampEvent time in ISO 8601 (UTC).
sourceAlways "pingzen" — handy for filtering when the same endpoint receives events from multiple sources.
monitor_urlLink to the monitor page in PingZen. Contains the monitor ID in the path /monitors/{id}. ⚠️ Only sent when the alert form's "Monitor link" toggle is enabled (on by default).
monitor_idMonitor ID (integer). Convenient for direct routing — no regex over monitor_url needed. Not present for synthetic alerts (heartbeat).
monitor_nameMonitor name without emoji or status (raw). Same value embedded in text, but as a dedicated field — handy for notification templates.
triggerEvent type (raw enum, NOT localized — best primitive for routing): down, still_down (reminder for a still-down monitor), recovered, degraded, certificate_expiring, response_time_high.
statusCurrent monitor status (raw enum, NOT localized): up, down, degraded, warning, transient, timeout, unknown. ⚠️ For test deliveries (see `test`) status carries the synthetic check-result value, not the live monitor status — do not key automation logic off this field. Use `trigger`.
testPresent (and equal to `true`) ONLY for deliveries triggered by the UI "Test" button. Production alerts omit this key entirely. Filter test deliveries out of any automation that changes entity state — see the Home Assistant example below.
monitorsArray of `{id, name, status, last_check_at}` for EVERY monitor attached to the alert. Present ONLY in test deliveries (alongside `test: true`). Lets HA / n8n automations re-sync ALL entity states from a single Test click instead of needing one click per monitor. Production payloads omit this key — they describe a single check_result via the top-level monitor_id/monitor_name/status fields.
probesArray of `{label, status, fail_streak}` per assigned probe — one entry per probe in `monitor.probe_ids`. Present ONLY for multi-probe monitors (≥2 assigned probes). Single-probe and central-only monitors omit this key. Each entry: `label` is the probe city (e.g. "Istanbul"), `status` is the per-probe check status (up/down/degraded/timeout/error/unknown — NOT localized), `fail_streak` is the consecutive-failure count. Useful for HA / n8n automations that route by region: `{% if probe.status == 'down' and probe.label == 'Istanbul' %}…`.

One webhook for multiple monitors

You can attach the same webhook URL to many monitors (or to a single alert that fires for a group). For routing, use the machine-readable fields: monitor_id (integer) to identify the monitor and trigger ("down" / "still_down" / "recovered" / "degraded" / "certificate_expiring") for the event type. Both fields are NOT localized. Avoid substring-matching text by "DOWN" — text contains a localized phrase ("Service Down" / "Сервис недоступен"), not the bare token "DOWN".

Example: ntfy.sh

ntfy.sh shows a JSON POST as plain text by default, so a bare /<topic> URL surfaces raw JSON on your phone. Use ntfy's inline templating in the query string — PingZen forwards the URL untouched, so no proxy or bridge is needed. The mapping below converts each PingZen field into the matching ntfy parameter.

Field mapping
PingZen fieldntfy paramNotes
monitor_name?t= (title)Shown as the bold notification title.
body?m= (message)Multi-line message body (URL + status + response time).
trigger ("down" / "recovered" / …)?p= (priority 1–5)down / still_down → 5 (urgent), recovered → 3 (default), others → 4 (high). ntfy requires a number, so use a Go-template if/else.
trigger (as-is)?tags= (emoji/text tags)ntfy renders matching emojis (warning, white_check_mark) automatically.
Basic recipe
URL
https://ntfy.sh/my-pingzen-topic?template=yes&t={{.monitor_name}}&m={{.body}}&p={{if eq .trigger "down"}}5{{else if eq .trigger "still_down"}}5{{else if eq .trigger "recovered"}}3{{else}}4{{end}}&tags={{.trigger}}
Paste this single line into the PingZen webhook URL field. Replace my-pingzen-topic with your own topic name — ntfy creates topics on the fly, so picking a random unguessable string acts as the password.
What you'll see on your phone
MyAPInow

🔴 My Website - Service Down URL: https://example.com Status: DOWN · 5000 ms

⚠️tag: down · priority: urgent
Self-hosted ntfy — only the host changes
URL
https://ntfy.example.com/my-pingzen-topic?template=yes&t={{.monitor_name}}&m={{.body}}
Protected topic with access token
URL
https://ntfy.sh/my-pingzen-topic?template=yes&t={{.monitor_name}}&m={{.body}}&auth=tk_AgQdq7mVBoFD37zQVxrGuMzfp3KuG

Example: Home Assistant

Example automation: routes by monitor_id for per-monitor logic and by trigger for event type (down / still_down / recovered). All fields are locale-independent — works the same for EN and RU monitors.

# configuration.yaml — automations
# 1. Real alerts (DOWN / still_down / recovered / degraded …)
- alias: PingZen alert
  trigger:
    platform: webhook
    webhook_id: pingzen
    allowed_methods: [POST]
    local_only: false
  # IMPORTANT: skip "Test" button deliveries so they don't change entity state.
  # Test payloads carry "test": true (production payloads omit the key).
  condition:
    - "{{ trigger.json.test | default(false) == false }}"
  variables:
    monitor_id: "{{ trigger.json.monitor_id | int(0) }}"
    event:      "{{ trigger.json.trigger }}"   # down | still_down | recovered | degraded | certificate_expiring
  action:
    - choose:
        # Router: react to the first DOWN only, ignore reminders
        - conditions: "{{ monitor_id == 123 and event == 'down' }}"
          sequence:
            - service: light.turn_on
              target: { entity_id: light.kitchen }
              data: { flash: short }
        # NAS: react to the first DOWN AND to reminder pings
        - conditions: "{{ monitor_id == 456 and event in ['down', 'still_down'] }}"
          sequence:
            - service: notify.mobile_app
              data:
                title: "{{ trigger.json.text }}"
                message: "{{ trigger.json.body }}"
        # Any monitor recovered → log it
        - conditions: "{{ event == 'recovered' }}"
          sequence:
            - service: logbook.log
              data:
                name: "PingZen"
                message: "{{ trigger.json.monitor_name }} recovered"
      default:
        - service: persistent_notification.create
          data:
            title: "{{ trigger.json.text }}"
            message: "{{ trigger.json.body }}"

# 2. Sync state from Test click — iterates the monitors array and sets
#    every entity to match PingZen (handy after HA restart or when entity
#    state drifts from reality).
- alias: PingZen sync from Test click
  trigger:
    platform: webhook
    webhook_id: pingzen
    allowed_methods: [POST]
    local_only: false
  # ONLY run on Test deliveries that include the monitors array
  condition:
    - "{{ trigger.json.test | default(false) == true }}"
    - "{{ 'monitors' in trigger.json }}"
  action:
    - repeat:
        for_each: "{{ trigger.json.monitors }}"
        sequence:
          # Adjust this entity_id template to match your naming convention
          - service: "{{ 'input_boolean.turn_on' if repeat.item.status == 'up' else 'input_boolean.turn_off' }}"
            target:
              entity_id: "input_boolean.pingzen_{{ repeat.item.id }}"

Tips

  • Webhook URL must be HTTPS (HTTP is allowed only for localhost — for local development).
  • Timeout is 30 seconds, up to 3 retries with exponential backoff on 5xx errors and network failures. No retries on 401/403 — check credentials.
  • For static-token auth, embed the secret in the URL (e.g. ?token=...) — query parameters are preserved and arrive at your endpoint. Home Assistant and n8n support this out of the box.
  • The body fields are configurable in the alert form under "Message content" — you can disable any field, including the monitor link. Disabling "Monitor link" also removes the monitor_url field from the payload.
  • For routing, use the machine-readable fields (NOT localized): monitor_id to identify the monitor, trigger for event type. The text field is localized — substring-matching it ("DOWN", "UP") is unreliable.
  • Reminder notifications (repeated alerts about a still-down monitor) arrive with trigger="still_down" and priority="critical" (same bucket as the first DOWN — the "real outage" signal). Use trigger in ['down', 'still_down'] for finer routing when the reaction differs.
  • The "Test" button in the alert form sends a payload with "test": true plus a [TEST] prefix in text and a (Test notification) line at the top of body. ALWAYS filter test deliveries out of automations that change entity state — see the condition block in the example above.
  • For test deliveries, status = "up" while trigger = "down" is intentional: the synthetic check_result is UP, but the trigger simulates the most common alert path (DOWN). Don't drive automation logic off body or status for test events — use trigger and the test field.

Alert Triggers

Choose which events should send notifications:

DOWN

Service Down (DOWN)

Sent when a monitor transitions to DOWN status after confirmation (default: 3 consecutive failures).

UP

Recovery (RECOVERED)

Sent when a monitor recovers after being down.

DEGRADED

Degradation (DEGRADED)

Sent when service is degraded (incl. PageSpeed score below threshold).

SSL

SSL Expiring

Sent 14 days before SSL certificate expiration.

How alerts fire

Triggers in PingZen are edge-driven — they react to state transitions, not to the current state. This is the most common source of confusion when a dashboard shows 'Critical' but no notifications arrive.

Without 'Send reminders while down'

10:00  monitor goes DOWN  → 1× DOWN alert sent
10:01–next day              → silence (still DOWN, no transition)
next day  monitor recovers → 1× RECOVERED alert sent

If a monitor stays DOWN for 5 days you'll get exactly two messages — one at the start, one at the end.

With 'Send reminders while down' enabled

10:00  DOWN                     → 1× DOWN
10:05  still DOWN               → STILL_DOWN (5 min rung)
10:20  still DOWN               → STILL_DOWN (15 min)
11:20  still DOWN               → STILL_DOWN (1 hour)
15:20, 19:20, 23:20, …          → STILL_DOWN every 4 hours
recovery                        → 1× RECOVERED, schedule resets

The escalation ladder restarts every time the monitor recovers and falls again.

Common gotcha

If your dashboard shows 'Critical' but you're not getting alerts, check that 'Send reminders while down' is on for that alert. The 'Down' trigger by itself fires only at the moment of failure, not periodically.

Message Settings

Customize which information is included in alert notifications. By default most fields are enabled. You can toggle each field per alert.

URL — the monitored endpoint address
Protocol — HTTP, TCP, DNS, etc.
Response time — check duration in milliseconds
HTTP status code — response status (e.g. 200, 502)
Error message — failure details or timeout reason
Account info — your email or account name (disabled by default for privacy)
Downtime duration — how long the monitor was down (shown only on recovery)
Monitor link — clickable link to open the monitor page in PingZen
Checked from — probe location (city, country, provider) or the central-server marker (disabled by default)

Disable fields you don't need to keep notifications concise. 'Account info' is disabled by default for privacy; 'Checked from' is disabled by default to avoid noise for users who don't use external probes.

Heartbeat Monitor Alerts

Alerts work with both regular monitors and heartbeat monitors. When creating an alert, you can select heartbeat monitors in the 'Heartbeat Monitors' section below the regular monitor list.

One alert can watch both regular and heartbeat monitors at the same time. The monitor count shows the total of both types.

Reminder Alerts

Enable the 'Send reminders while down' toggle to receive periodic notifications while a monitor stays down. Reminder intervals escalate automatically: 5 min → 15 min → 1 hour → then every 4 hours. The schedule resets when the monitor recovers.

Reminders are disabled by default. Enable them for critical services where you need persistent escalation — without this toggle, an outage that lasts days produces only two messages (the initial DOWN and the eventual RECOVERED).

Cooldown Period

Minimum time between repeated alerts for the same issue. Prevents notification spam during unstable connections. Default: 5 minutes. Recovery alerts always bypass cooldown.

Recommended: 5-15 minutes for production environments.

Alert History

The 'History' tab on the Alerts page shows a log of all sent notifications: timestamp, trigger type, channel, target, and delivery status (sent/failed). Failed deliveries include error details.

Use alert history to verify that notifications are being delivered correctly and to diagnose delivery failures.

Alerts API

Manage alerts programmatically via REST API.

GET/api/v1/alerts

List Alerts

POST/api/v1/alerts

Create Alert

PATCH/api/v1/alerts/:id

Update Alert

DELETE/api/v1/alerts/:id

Delete Alert

POST/api/v1/alerts/:id/test

Test Alert

Common Questions

What protocols can I monitor?

PingZen supports 23 protocols: HTTP/HTTPS, WebSocket (WS/WSS), TCP, UDP, ICMP Ping, gRPC, DNS, WHOIS, SSL certificates, Email (SMTP/IMAP/POP3), FTP/FTPS, DNSBL, PageSpeed, SOCKS5, MTProxy, API Check, and Transaction. You can monitor websites, APIs, servers, databases, and any network service.

How fast can I get alerts?

Telegram alerts are delivered within 1-2 seconds of detection. Slack and Discord notifications arrive almost instantly. You can configure multiple alert channels for redundancy.

Can I organize monitors by project?

Yes! PingZen supports workspaces, which let you organize monitors by project, environment, or team. Each workspace can have its own alert configurations and team members.

Is there an API for automation?

Absolutely. PingZen provides a full REST API with OpenAPI documentation. You can create, update, and delete monitors programmatically.

How do status pages work?

Status pages are public, branded pages showing your services' uptime. You can display real-time status and allow customers to subscribe for updates.

What happens if I reach my monitor limit?

We'll notify you when approaching your limit. You can pause some monitors or contact us for increased capacity. We never stop monitoring without warning, ensuring your critical services stay protected.

Ready to stop missing downtime?

Join thousands of teams who trust PingZen. Setup takes 30 seconds.