/ Integration

Webhooks

A JSON POST to your endpoint on failure and recovery

Webhooks

Assert sends an HTTP POST to your endpoint when a monitor fails, recovers, or slows past its threshold. The payload carries the assertion that failed, the expected value, the value your API returned, the region that ran the check, and the time. Route it into whatever you already run.

A failure re-runs across regions before the POST goes out. Assert sends one alert per incident and posts a monitor.recovered event when the assertion passes again. Routing is per monitor. Webhooks are on every paid plan.

Setup Guide

Step 1: Create Your Endpoint

Create an HTTP endpoint that accepts POST requests:

// Express.js example
app.post('/webhooks/ApiAssert', (req, res) => {
  const payload = req.body;

  console.log('Alert received:', payload.event);
  console.log('Monitor:', payload.monitor.name);

  // Process the alert...

  res.status(200).send('OK');
});

Step 2: Add Webhook in Assert

  1. Go to AlertsChannels in your Assert dashboard
  2. Click Add ChannelWebhook
  3. Enter your endpoint URL
  4. Add authentication headers if your endpoint requires them
  5. Click Save

Step 3: Test the Webhook

Click Send Test. Assert posts a sample payload to your endpoint.

Step 4: Assign to Monitors

Open each monitor. Add the webhook channel under Alert Channels.

Payload Format

Assert sends JSON payloads with this structure:

{
  "event": "monitor.failed",
  "timestamp": "2024-12-11T14:34:00Z",
  "monitor": {
    "id": "mon_abc123",
    "name": "Production API",
    "url": "https://api.example.com/health",
    "method": "GET",
    "interval": 60
  },
  "check": {
    "id": "chk_xyz789",
    "status_code": 500,
    "response_time_ms": 2340,
    "region": "us-east",
    "checked_at": "2024-12-11T14:34:00Z"
  },
  "failure": {
    "type": "assertion",
    "message": "$.status expected 'success', got 'error'",
    "assertion": {
      "path": "$.status",
      "operator": "equals",
      "expected": "success",
      "actual": "error"
    }
  },
  "alert": {
    "id": "alt_def456",
    "state": "triggered",
    "consecutive_failures": 3
  }
}

Event Types

Event Description
monitor.failed The monitor fails a check
monitor.recovered The monitor passes again
monitor.degraded The response time exceeds your threshold
test You send a test from the dashboard

Authentication

Bearer Token

Add a Bearer token header:

Header: Authorization
Value: Bearer your-secret-token

Custom Headers

Add any custom headers your endpoint requires:

X-API-Key: your-api-key
X-Webhook-Source: ApiAssert

Signature Verification

Assert signs every payload with HMAC-SHA256. Check the signature before you trust the request:

const crypto = require('crypto');

function verifySignature(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your handler:
const signature = req.headers['x-ApiAssert-signature'];
if (!verifySignature(req.body, signature, process.env.WEBHOOK_SECRET)) {
  return res.status(401).send('Invalid signature');
}

Use Cases

Trigger CI/CD Pipeline

Restart services when health checks fail:

# GitHub Actions workflow
on:
  repository_dispatch:
    types: [ApiAssert-alert]

jobs:
  restart:
    runs-on: ubuntu-latest
    steps:
      - run: ./scripts/restart-service.sh

Update Status Page

Post to your status page when monitors fail:

app.post('/webhooks/ApiAssert', async (req, res) => {
  if (req.body.event === 'monitor.failed') {
    await statusPage.createIncident({
      name: `${req.body.monitor.name} is down`,
      status: 'investigating'
    });
  }
  res.send('OK');
});

Forward to Slack in Your Own Format

Transform the payload and post it to Slack:

app.post('/webhooks/ApiAssert', async (req, res) => {
  const { monitor, check, failure } = req.body;

  await fetch(process.env.SLACK_WEBHOOK, {
    method: 'POST',
    body: JSON.stringify({
      blocks: [
        {
          type: 'header',
          text: { type: 'plain_text', text: `🚨 ${monitor.name}` }
        },
        {
          type: 'section',
          text: { type: 'mrkdwn', text: failure.message }
        }
      ]
    })
  });

  res.send('OK');
});

Retry Policy

Assert retries a failed delivery, up to 3 attempts in total, with exponential backoff of 10s, 30s, 90s. Each request times out after 10 seconds. Any 2xx response code counts as a success.

Troubleshooting

Not receiving webhooks?

  • Check that your endpoint is reachable from the public internet
  • Check that your firewall allows incoming POST requests
  • Check the URL, including the protocol

Getting 4xx/5xx errors?

  • Check your endpoint logs
  • Check the authentication headers
  • Check that your endpoint returns 2xx on success

Payload not what you expected?

  • Use Send Test to see the exact payload format
  • Check the API changelog for recent changes

Next Steps

Route the alert.

Five monitors, thirty-second checks, no card, no call.