Skip to main content

ChannelConfig Interface

Defines a webhook endpoint for alert notifications.
interface ChannelConfig {
  type: "webhook";
  url: string;
  headers?: Record<string, string>;
}

Fields

type
'webhook'
required
Channel typeCurrently only "webhook" is supported. Future versions may support email, Slack, PagerDuty, etc.
url
string
required
Webhook endpoint URLPongo sends POST requests with alert payloads to this URL. Must be HTTPS in production.
headers
Record<string, string>
Custom HTTP headers for webhook requestsUse for authentication tokens, content type, or custom routing headers.Example:
headers: {
  "Authorization": "Bearer token",
  "X-Custom-Header": "value"
}

ChannelsConfig Type

Map of channel IDs to configurations.
type ChannelsConfig = Record<string, ChannelConfig>
Channel IDs are referenced in AlertConfig.channels arrays.

channels() Helper

Type-safe wrapper for channel configuration.
function channels(config: ChannelsConfig): ChannelsConfig

Usage

pongo/channels.ts
import { channels } from "../src/lib/config-types";

export default channels({
  "ops-team": {
    type: "webhook",
    url: process.env.OPS_WEBHOOK_URL!,
  },
});

Webhook Payload

Pongo sends this JSON payload to webhook URLs:
interface WebhookPayload {
  event: "alert.fired" | "alert.resolved";
  alert: {
    id: string;
    name: string;
    monitorId: string;
    monitorName: string;
    severity: "critical" | "warning" | "info";
  };
  timestamp: string;  // ISO 8601
  snapshot: {
    consecutiveFailures: number;
    consecutiveSuccesses: number;
    lastStatus: string;
    lastResponseTimeMs: number | null;
    lastMessage: string | null;
  };
  checkResult: {
    id: string;
    status: string;
    responseTimeMs: number;
    message: string | null;
    checkedAt: string;  // ISO 8601
  };
  region?: string;
  firingRegions?: string[];
  healthyRegions?: string[];
}

Example Payload: Alert Fired

{
  "event": "alert.fired",
  "alert": {
    "id": "api-down",
    "name": "API Down",
    "monitorId": "api",
    "monitorName": "Production API",
    "severity": "critical"
  },
  "timestamp": "2026-03-04T10:30:00.000Z",
  "snapshot": {
    "consecutiveFailures": 3,
    "consecutiveSuccesses": 0,
    "lastStatus": "down",
    "lastResponseTimeMs": 5234,
    "lastMessage": "HTTP 503"
  },
  "checkResult": {
    "id": "check_xyz789",
    "status": "down",
    "responseTimeMs": 5234,
    "message": "HTTP 503",
    "checkedAt": "2026-03-04T10:30:00.000Z"
  },
  "region": "us-east-1",
  "firingRegions": ["us-east-1", "eu-west-1"],
  "healthyRegions": ["ap-southeast-1"]
}

Example Payload: Alert Resolved

{
  "event": "alert.resolved",
  "alert": {
    "id": "api-down",
    "name": "API Down",
    "monitorId": "api",
    "monitorName": "Production API",
    "severity": "critical"
  },
  "timestamp": "2026-03-04T10:35:00.000Z",
  "snapshot": {
    "consecutiveFailures": 0,
    "consecutiveSuccesses": 2,
    "lastStatus": "up",
    "lastResponseTimeMs": 234,
    "lastMessage": null
  },
  "checkResult": {
    "id": "check_abc123",
    "status": "up",
    "responseTimeMs": 234,
    "message": null,
    "checkedAt": "2026-03-04T10:35:00.000Z"
  }
}

Real Examples

Basic Webhook

pongo/channels.ts
import { channels } from "../src/lib/config-types";

export default channels({
  "ops-team": {
    type: "webhook",
    url: "https://hooks.example.com/alerts",
  },
});

Webhook with Authentication

pongo/channels.ts
import { channels } from "../src/lib/config-types";

export default channels({
  "ops-team": {
    type: "webhook",
    url: process.env.OPS_WEBHOOK_URL!,
    headers: {
      "Authorization": `Bearer ${process.env.WEBHOOK_TOKEN}`,
    },
  },
});

Multiple Channels

pongo/channels.ts
import { channels } from "../src/lib/config-types";

export default channels({
  "ops-team": {
    type: "webhook",
    url: process.env.OPS_WEBHOOK_URL!,
    headers: {
      "Authorization": `Bearer ${process.env.OPS_TOKEN}`,
    },
  },
  "engineering": {
    type: "webhook",
    url: process.env.ENG_WEBHOOK_URL!,
    headers: {
      "Authorization": `Bearer ${process.env.ENG_TOKEN}`,
    },
  },
  "pagerduty": {
    type: "webhook",
    url: "https://events.pagerduty.com/v2/enqueue",
    headers: {
      "Authorization": `Token token=${process.env.PAGERDUTY_TOKEN}`,
      "Content-Type": "application/json",
    },
  },
});

Slack Webhook

pongo/channels.ts
import { channels } from "../src/lib/config-types";

export default channels({
  "slack-ops": {
    type: "webhook",
    url: process.env.SLACK_WEBHOOK_URL!,
  },
});

Discord Webhook

pongo/channels.ts
import { channels } from "../src/lib/config-types";

export default channels({
  "discord-ops": {
    type: "webhook",
    url: process.env.DISCORD_WEBHOOK_URL!,
  },
});

Custom Headers for Routing

pongo/channels.ts
import { channels } from "../src/lib/config-types";

export default channels({
  "internal-api": {
    type: "webhook",
    url: "https://internal.example.com/webhook",
    headers: {
      "X-Service": "pongo",
      "X-Environment": process.env.NODE_ENV!,
      "X-API-Key": process.env.INTERNAL_API_KEY!,
    },
  },
});

Webhook Integration Guide

Receiving Webhooks

Your webhook endpoint should:
  1. Accept POST requests with JSON payload
  2. Respond with 2xx status code (200-299)
  3. Process payload asynchronously if needed
  4. Handle both alert.fired and alert.resolved events

Example Express Handler

app.post("/webhook/pongo", express.json(), (req, res) => {
  const payload: WebhookPayload = req.body;
  
  if (payload.event === "alert.fired") {
    console.log(`Alert fired: ${payload.alert.name}`);
    console.log(`Severity: ${payload.alert.severity}`);
    console.log(`Monitor: ${payload.alert.monitorName}`);
    console.log(`Status: ${payload.checkResult.status}`);
    console.log(`Message: ${payload.checkResult.message}`);
  } else if (payload.event === "alert.resolved") {
    console.log(`Alert resolved: ${payload.alert.name}`);
  }
  
  res.status(200).json({ received: true });
});

Retry Behavior

Pongo retries failed webhook deliveries:
  • Retries on 5xx errors or network failures
  • Does not retry on 4xx client errors
  • Exponential backoff between retries
  • Maximum 3 retry attempts

Security

  1. Use HTTPS URLs in production
  2. Validate webhook signatures (coming soon)
  3. Use authentication headers
  4. Whitelist Pongo IP addresses if needed

File Location

Channel configuration must be in:
pongo/channels.ts
This file is required even if empty. Use the starter template:
pongo/channels.ts
import { channels } from "../src/lib/config-types";

export default channels({
  // Add your channels here
});

Build docs developers (and LLMs) love