Get downtime alerts in Discord

  • integrations
  • webhook
  • discord

Can I point a YoPingMe webhook straight at Discord?

No, and this page does not pretend otherwise. YoPingMe's webhook channel sends one fixed JSON payload (documented in full below). Discord's webhook endpoint expects its own shape - a content string or embeds array - and returns 400 for anything else. The bridge is a relay of about 30 lines that runs free on Cloudflare Workers: it reshapes the payload into a Discord embed and forwards it.

You need: a Discord server where you can manage webhooks, a free Cloudflare account, and a YoPingMe monitor.

Step 1: create the Discord webhook

In Discord, open your server settings, then Integrations, then Webhooks. Create one, pick the channel alerts should land in, and copy the webhook URL. Treat that URL as a secret - anyone who has it can post to your channel.

Step 2: create the relay Worker

In the Cloudflare dashboard, create a new Worker (Workers and Pages, then Create). Replace its code with:

export default {
  async fetch(request, env) {
    if (request.method !== 'POST') {
      return new Response('expected POST', { status: 405 });
    }
    const body = await request.text();
    const alert = JSON.parse(body);
    const look = {
      down: { title: 'Down', color: 0xed4245 },
      up: { title: 'Recovered', color: 0x57f287 },
      still_down: { title: 'Still down', color: 0xfee75c },
    }[alert.event] ?? { title: alert.event, color: 0x5865f2 };

    const discord = await fetch(env.DISCORD_WEBHOOK_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        embeds: [{
          title: `${look.title}: ${alert.monitor}`,
          description: alert.cause ?? '',
          color: look.color,
          fields: [{ name: 'Target', value: alert.target }],
          timestamp: alert.sequence_at,
        }],
      }),
    });

    // A non-2xx answer makes YoPingMe retry, so a Discord hiccup is
    // covered by the same retry schedule as everything else.
    return new Response(null, { status: discord.ok ? 200 : 502 });
  },
};

This recipe is written for Cloudflare Workers for one reason: the free tier. Cloudflare's published free-tier limit, checked 2026-08-07, is 100,000 requests a day, and your alerts will not dent it.

Step 3: set the Worker's secret

The Worker needs one value. In the Worker's settings, add it as a secret (not a plaintext variable):

  • DISCORD_WEBHOOK_URL: the URL from step 1.

With the wrangler CLI instead: wrangler secret put DISCORD_WEBHOOK_URL.

Step 4: add the channel in YoPingMe

In the YoPingMe dashboard, add an alert channel of type webhook. The URL is your Worker's URL. Attach the channel to your monitors.

Keep the Worker URL private

There is no shared secret between YoPingMe and the relay. The Worker's URL is the credential - exactly like the Discord webhook URL it wraps. Anyone who has either URL can post an embed to that channel, so treat the Worker URL the same way you already treat the Discord one: do not commit it, paste it into a public issue, or share it outside your team. If it ever leaks, create a new Worker (a new name gets a new URL), point its DISCORD_WEBHOOK_URL secret at the same Discord channel, repoint YoPingMe's alert channel at the new Worker URL, then delete the old Worker. That is how you rotate it.

Step 5: send a test alert

Simulate what YoPingMe sends:

WORKER_URL='https://your-relay.example.workers.dev'
BODY='{"event":"down","idempotency_key":"test-1","incident_id":"inc-test","monitor":"my site","target":"https://example.com","cause":"HTTP 500","sequence_at":"2026-08-07T12:00:00Z"}'
curl -sS -X POST "$WORKER_URL" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: test-1' \
  --data "$BODY"

A red "Down: my site" embed should appear in your channel.

The webhook payload

This is the full contract, the same one every webhook receiver gets, verified against the dispatcher on 2026-08-07:

Field Value
event down, up, or still_down
idempotency_key Stable per delivery; duplicates of a retried alert carry the same key
incident_id Groups the down, still_down, and up alerts of one incident
monitor The monitor's name
target The URL or host being checked
cause What failed; present on down and still_down
sequence_at RFC 3339 timestamp; orders events within an incident

Headers: Content-Type: application/json, Idempotency-Key (same value as the body field), and X-YoPingMe-Signature: sha256=<hex HMAC-SHA-256 of the raw body>. YoPingMe generates the signing secret itself when you create the channel and never exposes it again, so the header is always present but is not something this recipe verifies - see "Keep the Worker URL private" above for how the relay is secured instead.

Delivery: 10 second timeout, then retries - up to 5 attempts over about 10 minutes of doubling backoff. Delivery is at-least-once: if Discord or your relay answers slowly, you may get the same alert twice, which is what idempotency_key is for. The relay above forwards duplicates as-is; a busy channel that wants exactly-once display can remember recent keys in Workers KV, which is more machinery than most alert channels need.