PingParrot / Webhook Guide
Home / Webhook Guide

Webhook Integration Guide

Connect PingParrot to Slack, Microsoft Teams, Zapier, Make, Discord, and any other tool using webhooks.

Overview

Webhooks let PingParrot push real-time notifications to external tools the moment something happens — a page is sent, acknowledged, cancelled, or escalated. Instead of polling an API, your tools receive an HTTP POST the instant the event fires.

Native

Slack and Teams are natively supported — no middleware needed. PingParrot formats the message in each platform's own format.

Generic JSON

For custom apps, Zapier, Make, n8n, or any HTTP endpoint. The full page payload is sent as JSON.

Secure

Generic webhooks support HMAC-SHA256 signatures so your server can verify requests genuinely came from PingParrot.

Adding a Webhook

  1. 1

    Go to Integrations → Webhooks in the sidebar.

  2. 2

    Choose a Destination: Generic JSON, Slack, or Microsoft Teams.

  3. 3

    Paste the endpoint URL for your chosen destination.

  4. 4

    Select which events should trigger the webhook.

  5. 5

    For Generic JSON webhooks, optionally add a secret to enable request signing.

  6. 6

    Click Add Webhook. PingParrot will start posting to your URL immediately.

Auto-disable: If a webhook fails 10 times in a row, PingParrot automatically disables it to prevent noise. Re-enable it from the Webhooks page once the issue is resolved.

Events

Each webhook can subscribe to one or more of these events:

Event When it fires
page.sent A page is created and delivery begins.
page.acknowledged A recipient or admin acknowledges the page.
page.cancelled A page is cancelled before acknowledgement.
page.expired The page expires without being acknowledged.
page.escalated An escalation rule fires and the page moves to the next step.

Slack

PingParrot formats messages natively for Slack using Block Kit — no middleware or Zapier account required.

What it looks like

🚨 DB server is down

Priority
Critical
Status
Active
Sent by
Sarah Chen

PingParrot · New Page

Setup steps

  1. 1

    In Slack, go to Apps → Manage Apps → Incoming Webhooks (or search "Incoming WebHooks" in the app directory).

  2. 2

    Click Add to Slack, choose the channel you want pages to appear in, and click Authorise.

  3. 3

    Copy the Webhook URL — it looks like https://hooks.slack.com/services/T.../B.../...

  4. 4

    In PingParrot, go to Webhooks, select Slack as the destination, paste the URL, choose your events, and click Add Webhook.

Tip: Create one webhook per Slack channel. For example, route page.sent to #alerts and page.acknowledged to #on-call.

Microsoft Teams

PingParrot posts MessageCards directly to Teams channels — no Power Automate or third-party account needed.

What it looks like

🚨 DB server is down

PingParrot · New Page

Priority
Critical
Status
Active
Sent by
Sarah Chen

Setup steps

  1. 1

    In Microsoft Teams, open the channel you want to receive alerts in.

  2. 2

    Click the ••• (More options) next to the channel name → Connectors.

  3. 3

    Find Incoming Webhook, click Configure, give it a name like "PingParrot", and click Create.

  4. 4

    Copy the Webhook URL — it looks like https://xxx.webhook.office.com/webhookb2/...

  5. 5

    In PingParrot, go to Webhooks, select Teams as the destination, paste the URL, choose your events, and click Add Webhook.

Note: Microsoft is retiring the Incoming Webhook connector for some tenants. If it's unavailable, use the Zapier or Make integration with the "Post a message in Teams" action instead.

Zapier

Use Zapier to connect PingParrot pages to thousands of apps — PagerDuty, Jira, email, SMS, Discord, and more.

  1. 1

    In Zapier, click Create Zap → Trigger → Webhooks by Zapier → Catch Hook.

  2. 2

    Copy the Custom Webhook URL Zapier gives you.

  3. 3

    In PingParrot, add a Generic JSON webhook with that URL and select your events.

  4. 4

    Send a test page in PingParrot — Zapier will capture the payload so you can map fields.

  5. 5

    Add your Action step (e.g. "Send a Slack message", "Create Jira issue", "Send SMS via Twilio").

  6. 6

    Map the fields: page.subject, page.priority, page.sender.name, etc.

  7. 7

    Turn on your Zap.

Make (formerly Integromat)

Make is a powerful automation platform with a generous free tier — great for complex multi-step workflows.

  1. 1

    In Make, create a new Scenario and add a Webhooks → Custom webhook module as the trigger.

  2. 2

    Click Add to create the webhook and copy the URL.

  3. 3

    In PingParrot, add a Generic JSON webhook with that URL.

  4. 4

    Send a test page — Make will detect the data structure automatically.

  5. 5

    Add modules for your destination: Microsoft Teams → Create a message, Slack → Create a message, or any other app.

  6. 6

    Map page.subject, page.priority, event, and other fields to your action.

  7. 7

    Activate the scenario.

Discord

Discord supports incoming webhooks natively, but expects its own JSON format. Use Zapier or Make as a bridge, or a small custom relay.

Via Zapier / Make (recommended)

Follow the Zapier or Make steps above, then choose Discord → Send a channel message as the action. Map page.subject and page.priority into the message body.

Via a small relay (advanced)

If you have a server, a small script can receive PingParrot's Generic JSON payload and repost it to Discord's webhook URL:

// Express.js example
app.post('/relay', (req, res) => {
  const { event, page } = req.body;
  fetch(DISCORD_WEBHOOK_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      content: `${page.priority === 'critical' ? '🚨' : '🔔'} **${page.subject}** — ${event}`
    })
  });
  res.sendStatus(200);
});

Custom / Generic

Use Generic JSON to integrate with any HTTP endpoint — your own backend, n8n, Pipedream, or anything else that can receive a POST request.

n8n: Add a Webhook trigger node, copy the URL into PingParrot as a Generic JSON webhook, then connect it to any n8n action (Teams, Slack, email, database, etc.).

Generic JSON Payload Reference

All Generic JSON webhooks send the same structure. Fields that don't apply to the event will be null.

{
  "event": "page.acknowledged",       // page.sent | acknowledged | cancelled | expired | escalated
  "triggered_at": "2026-07-06T12:00:00+00:00",

  "page": {
    "id": 42,
    "subject": "DB server is down",
    "priority": "critical",            // low | normal | high | critical
    "status": "acknowledged",
    "delivery_mode": "single",         // single | group | broadcast | oncall
    "created_at": "2026-07-06T11:58:00+00:00",

    "sender": {
      "name": "Sarah Chen",
      "email": "[email protected]"
    },

    "acknowledged_by": {               // null unless event is page.acknowledged
      "name": "James Nguyen",
      "email": "[email protected]"
    },

    "cancelled_by": null               // null unless event is page.cancelled
  }
}

Field reference

Field Type Description
event string The event name that triggered this webhook.
triggered_at ISO 8601 UTC timestamp of when the event occurred.
page.id integer Unique identifier for the page.
page.subject string The subject/title of the page.
page.priority string low, normal, high, or critical.
page.status string Current status: active, acknowledged, cancelled, or expired.
page.delivery_mode string How the page was sent: single, group, broadcast, or oncall.
page.sender object|null Name and email of who sent the page.
page.acknowledged_by object|null Populated on page.acknowledged events.
page.cancelled_by object|null Populated on page.cancelled events.

Signature Verification

When a secret is set on a Generic JSON webhook, every request includes an X-PingParrot-Signature header. The value is sha256=<hmac> where the HMAC is computed over the raw request body using your secret as the key.

Verify it server-side to ensure the request came from PingParrot and wasn't tampered with:

Node.js

const crypto = require('crypto');

function verifySignature(body, secret, signature) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(body)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

// In your Express route:
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-pingparrot-signature'];
  if (!verifySignature(req.body, process.env.WEBHOOK_SECRET, sig)) {
    return res.status(401).send('Invalid signature');
  }
  const payload = JSON.parse(req.body);
  // handle payload...
  res.sendStatus(200);
});

PHP

$body      = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_PINGPARROT_SIGNATURE'] ?? '';
$expected  = 'sha256=' . hash_hmac('sha256', $body, $_ENV['WEBHOOK_SECRET']);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

$payload = json_decode($body, true);
// handle $payload...

Python

import hmac, hashlib

def verify_signature(body: bytes, secret: str, signature: str) -> bool:
    expected = 'sha256=' + hmac.new(
        secret.encode(), body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

# In your Flask route:
@app.route('/webhook', methods=['POST'])
def webhook():
    sig = request.headers.get('X-PingParrot-Signature', '')
    if not verify_signature(request.data, WEBHOOK_SECRET, sig):
        abort(401)
    payload = request.json
    # handle payload...

Always use a timing-safe comparison (crypto.timingSafeEqual, hash_equals, hmac.compare_digest) rather than === to prevent timing attacks.

Need help?

Contact us and we'll help you get set up.