Webhooks
Receive real-time events and verify the X-PIE-Signature-256 HMAC.
Receiving events
Register a webhook subscription with an HTTPS endpoint and the events you care about. When something happens, PIE POSTs a JSON payload to your URL and retries with backoff on failure. Your endpoint should respond 2xx quickly (within 10 seconds) and do any heavy work asynchronously.
See the webhook events reference for the full list of event types.
Delivery headers
Each delivery carries three headers:
X-PIE-Event— the event name (e.g.product.published).X-PIE-Delivery— a unique delivery id, useful for idempotency and dedupe.X-PIE-Signature-256— an HMAC signature of the raw body, prefixedsha256=.
Verifying the signature
When you create a subscription, PIE returns a signing secret (shown once). PIE signs the raw request body with HMAC-SHA256 using that secret and sends the hex digest in X-PIE-Signature-256. Recompute it and compare with a constant-time check — reject anything that doesn't match:
import { createHmac, timingSafeEqual } from "node:crypto";
// `rawBody` MUST be the exact bytes received — verify BEFORE JSON.parse.
function verify(rawBody, header, secret) {
const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(header ?? "");
const b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}
app.post("/webhooks/pie", (req, res) => {
const sig = req.header("X-PIE-Signature-256");
if (!verify(req.rawBody, sig, process.env.PIE_WEBHOOK_SECRET)) {
return res.sendStatus(401);
}
const event = req.header("X-PIE-Event");
const payload = JSON.parse(req.rawBody);
// … enqueue and return fast …
res.sendStatus(202);
});
Verify the signature against the raw request bytes, before parsing — re-serialising the JSON can change whitespace and key order and break the HMAC. Return 2xx only after you have safely accepted the delivery; any other status triggers a retry.