Skip to main content
PercherPercher

Event webhooks

Signed deploy.failed / app.crashed / domain.expiring

Percher POSTs signed JSON payloads to your webhook URL when events happen. Useful for Discord/Slack bots, on-call pagers, or custom dashboards.

Events

Setup

Settings → Notifications → paste your receiver URL. A signing secret is generated and shown once — copy it into your receiver's PERCHER_WEBHOOK_SECRET env var. Changing the URL rotates the secret; clearing the URL clears the secret.

Verifying signatures

Every delivery carries X-Percher-Signature: sha256=<hex> — HMAC-SHA256 of ${timestamp}.${body}. Reject anything older than a few minutes for replay protection.

// Node / Bun receiver
import { createHmac, timingSafeEqual } from "node:crypto";

function verify(secret, req, body) {
  const sig = req.headers.get("X-Percher-Signature") ?? "";
  const ts = req.headers.get("X-Percher-Timestamp") ?? "";
  const expected = createHmac("sha256", secret)
    .update(`${ts}.${body}`)
    .digest("hex");
  const provided = sig.replace(/^sha256=/, "");
  if (expected.length !== provided.length) return false;
  return timingSafeEqual(Buffer.from(expected), Buffer.from(provided));
}

Deliveries are best-effort with a 5-second timeout. 5xx responses are logged but not retried — queue events in your receiver if you need retries or ordering guarantees.

← PrevCost optimization insightsNext →Billing & plans
Percher — AI-native app hosting