Signed webhooks

Each workflow has a URL https://outcomeos.cloud/hooks/w/<workflow_id> and each outcome has https://outcomeos.cloud/hooks/outcomes/<outcome_id>. Both require:

X-OutcomeOS-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256(secret, "<t>.<raw body>")>

Requests older than 5 minutes are rejected (signature_invalid). Bodies are limited to 1 MB. A workflow webhook returns 202 with an execution_id as soon as the execution is queued.

Duplicates

Send Idempotency-Key (or set the trigger's idempotency path, e.g. {{trigger.body.event_id}}). A repeated key returns the original execution with "duplicate": true instead of running twice.

import crypto from "node:crypto";
const body = JSON.stringify({ lead_id: "lead_123", qualified: true, event_id: "evt_1" });
const t = Math.floor(Date.now() / 1000);
const v1 = crypto.createHmac("sha256", process.env.WEBHOOK_SECRET).update(`${t}.${body}`).digest("hex");
await fetch(WEBHOOK_URL, { method: "POST", body, headers: {
  "Content-Type": "application/json",
  "X-OutcomeOS-Signature": `t=${t},v1=${v1}`,
}});