Webhooks

Receive real-time notifications when events occur in Upstat.

How Webhooks Work

Webhooks push event data to your endpoints in real-time:

  1. Configure webhook URL in project settings
  2. Select events to receive
  3. Upstat sends POST requests when events occur
  4. Your endpoint processes the data

![Placeholder: Webhook Configuration Interface]

Setting Up Webhooks

1. Add Webhook Endpoint

Go to SettingsWebhooks and add your endpoint:

  • URL - Your HTTPS endpoint
  • Secret - Used to sign requests (auto-generated)
  • Events - Select which events to receive

2. Verify Requests

All webhook requests include a signature header:

X-Upstat-Signature: sha256=abc123...

Verify the signature to ensure requests are from Upstat:

const crypto = require('crypto');

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

![Placeholder: Webhook Secret and Signature Verification]

Available Events

Monitor Events

monitor.down

{
  "event": "monitor.down",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "uuid": "mon_abc123",
    "name": "Production API",
    "url": "https://api.example.com",
    "status": "down",
    "lastError": "Connection timeout",
    "region": "us-east-1"
  }
}

monitor.recovered

{
  "event": "monitor.recovered",
  "timestamp": "2024-01-15T10:35:00Z",
  "data": {
    "uuid": "mon_abc123",
    "name": "Production API",
    "downtime": 300,
    "status": "up"
  }
}

Incident Events

incident.created

{
  "event": "incident.created",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "uuid": "inc_xyz789",
    "title": "Database connection issues",
    "severity": "P2",
    "status": "open",
    "createdBy": "user@example.com"
  }
}

incident.updated

{
  "event": "incident.updated",
  "timestamp": "2024-01-15T10:45:00Z",
  "data": {
    "uuid": "inc_xyz789",
    "changes": {
      "status": {
        "from": "open",
        "to": "acknowledged"
      }
    },
    "updatedBy": "oncall@example.com"
  }
}

incident.resolved

{
  "event": "incident.resolved",
  "timestamp": "2024-01-15T11:00:00Z",
  "data": {
    "uuid": "inc_xyz789",
    "resolution": "Restarted database service",
    "duration": 1800,
    "resolvedBy": "engineer@example.com"
  }
}

Status Page Events

status.component_updated

{
  "event": "status.component_updated",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "component": "API",
    "previousStatus": "operational",
    "currentStatus": "partial_outage",
    "message": "Investigating elevated error rates"
  }
}

Webhook Delivery

Retry Logic

Failed webhook deliveries are retried with exponential backoff:

  • 1st retry: 30 seconds
  • 2nd retry: 2 minutes
  • 3rd retry: 10 minutes
  • 4th retry: 30 minutes
  • 5th retry: 1 hour

After 5 failed attempts, the webhook is marked as failed.

Delivery Headers

Each webhook includes helpful headers:

X-Upstat-Event: monitor.down
X-Upstat-Signature: sha256=abc123...
X-Upstat-Delivery: del_123abc
X-Upstat-Timestamp: 1640995200
Content-Type: application/json

Testing Webhooks

Test Events

Send test events from the webhook configuration page:

  1. Click Test next to your webhook
  2. Select an event type
  3. Review the test payload
  4. Check your endpoint received it

Development Tools

Use ngrok or similar for local development:

# Expose local port 3000
ngrok http 3000

# Use the HTTPS URL for webhook configuration
https://abc123.ngrok.io/webhooks

![Placeholder: Webhook Test Interface]

Security Best Practices

Always Use HTTPS

Webhooks are only sent to HTTPS endpoints.

Verify Signatures

Always verify the signature before processing:

import hmac
import hashlib

def verify_signature(payload, signature, secret):
    expected = 'sha256=' + hmac.new(
        secret.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(signature, expected)

Respond Quickly

Return 200 OK immediately, process asynchronously:

app.post('/webhook', (req, res) => {
  // Respond immediately
  res.status(200).send('OK');
  
  // Process in background
  processWebhook(req.body);
});

Learn more