Skip to main content
The Webhook adapter sends the full notification payload as a JSON POST request to any HTTP endpoint. It is the most flexible channel — use it to integrate with PagerDuty, Opsgenie, Discord (via webhook), custom dashboards, or any service that accepts JSON webhooks.

Configuration

{
  "settings": {
    "notifications": {
      "channels": {
        "webhook-alerts": {
          "type": "webhook",
          "url": "https://events.pagerduty.com/v2/enqueue",
          "headers": {
            "Authorization": "Token token=${PD_TOKEN}"
          }
        }
      }
    }
  }
}
FieldTypeRequiredDescription
type"webhook"YesChannel type
urlstringYesTarget URL for the POST request
headersRecord<string, string>NoCustom headers added to every request
Both url and individual header values support ${ENV_VAR} syntax:
{
  "type": "webhook",
  "url": "${WEBHOOK_ENDPOINT}",
  "headers": {
    "Authorization": "Bearer ${WEBHOOK_TOKEN}",
    "X-Source": "polpo"
  }
}

Payload Format

Every notification is sent as a JSON object with Content-Type: application/json:
{
  "id": "notif_abc123",
  "event": "task:transition",
  "severity": "critical",
  "title": "Task failed: migrate-database",
  "body": "Task migrate-database transitioned to failed after 3 retries",
  "data": { "taskId": "task_xyz", "from": "in_progress", "to": "failed" },
  "timestamp": "2025-01-15T10:30:00.000Z",
  "ruleId": "failed-tasks"
}
FieldTypeDescription
idstringUnique notification ID
eventstringSource event name
severitystringinfo, warning, or critical
titlestringNotification title
bodystringNotification body text
dataobjectFull source event payload
timestampstringISO-8601 timestamp
ruleIdstringID of the rule that triggered this notification

Attachments

When a notification rule has includeOutcomes: true, task outcomes are included in the same JSON payload under an attachments array. File content is base64-encoded for JSON transport.
{
  "id": "notif_abc123",
  "event": "task:transition",
  "severity": "info",
  "title": "Task completed: generate-report",
  "body": "...",
  "data": { "..." },
  "timestamp": "...",
  "ruleId": "completed-tasks",
  "attachments": [
    {
      "label": "Generated Report",
      "type": "file",
      "filename": "report.pdf",
      "mimeType": "application/pdf",
      "size": 48230,
      "contentBase64": "JVBERi0xLjQK..."
    },
    {
      "label": "Build Log",
      "type": "text",
      "text": "Step 1: Compiled successfully\nStep 2: Tests passed..."
    }
  ]
}
Each attachment can include:
FieldTypeDescription
labelstringHuman-readable label
typestringAttachment type (file, text, url)
filenamestringOriginal filename (if file-based)
mimeTypestringMIME type
sizenumberFile size in bytes
textstringText content (for text-type attachments)
urlstringURL reference (for url-type attachments)
contentBase64stringBase64-encoded binary content

Connectivity Test

The test() check validates that the configured url is a parseable URL. It does not make a network call — to verify end-to-end delivery, use the Send Direct API.

Error Handling

If the target server responds with a non-2xx status code, the webhook adapter throws an error with the HTTP status and status text. The notification router will emit a notification:failed event with the error details.

Setup

  1. Get the endpoint URL from your target service (PagerDuty, Opsgenie, custom server, etc.)
  2. Set any required auth tokens as environment variables
  3. Add to Polpo config:
    {
      "type": "webhook",
      "url": "https://your-endpoint.example.com/hook",
      "headers": {
        "Authorization": "Bearer ${WEBHOOK_TOKEN}"
      }
    }
    
  4. Verify delivery using the Send Direct API or by triggering a test event