WinLayer Docs
Product documentation · Beta behavior. A documented path is not production acceptance; availability still depends on source health, workspace plan, provider setup, and deployed evidence.

Webhooks

Signed events pushed to your HTTPS endpoints when things happen in your workspace.

Register endpoints on /developer. Each endpoint gets a signing secret (whsec_…, shown once). Internal and private-network URLs are rejected (SSRF-guarded); a test ping is one click.

Webhook sequence: a pursuit decision in WinLayer triggers a signed POST (x-winlayer-event and x-winlayer-signature headers) to your endpoint; you verify the HMAC over the raw body timing-safely, ack with 200 fast, then process asynchronously into your systems.
Each attempt is signed; acknowledge fast and process idempotently.

Events

EventFires whenData
opportunity.pursuit.setdecision made{ "signalId", "status": "pursuing" | "watching" | "passed" }
opportunity.pursuit.cleareddecision cleared{ "signalId" }
pingtest buttonA sample payload to verify your receiver.

Delivery format

http
POST https://your-app.com/hooks/winlayer
content-type: application/json
x-winlayer-event: opportunity.pursuit.set
x-winlayer-signature: sha256=8f2a…   // HMAC-SHA256 of the raw body

{ "id": "1d8ca81f-…",
  "event": "opportunity.pursuit.set",
  "data": { "signalId": "43eeed69-…", "status": "pursuing" },
  "sentAt": "2026-07-24T12:00:00.000Z",
  "attempt": 1 }

Verifying the signature

typescript
import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody: string, header: string, secret: string): boolean {
  const expected = "sha256=" +
    createHmac("sha256", secret).update(rawBody).digest("hex");
  return timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}

// verify(req.rawBody, req.headers["x-winlayer-signature"], process.env.WINLAYER_WEBHOOK_SECRET)

Compute the HMAC over the raw request body, before any JSON parsing. Delivery is at least once: transient failures are retried up to five attempts, so deduplicate with the stable payload id. Retry state and terminal failures are visible on /developer.