Webhooks


Layout POSTs a signed event when an order you initiated changes state. Delivery is fire-and-forget with retry, and never delays or alters an order.

Subscribe

Add a subscription in the console with a notification URL and the events you care about. HTTPS only, and never a private or internal host. Your signing secret is on the Webhooks page.

Verify the signature

Every payload is signed HMAC-SHA256 over the timestamp and the raw body, in an X-Layout-Signature header. Verify it, and check the timestamp to bound replay, before trusting a payload.

import crypto from "node:crypto";

function verify(req, secret) {
  const [t, sig] = req.headers["x-layout-signature"].split(",");
  const ts = t.slice(2), signature = sig.slice(2);
  const expected = crypto
    .createHmac("sha256", secret)
    .update(ts + "." + req.rawBody)
    .digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  return fresh && crypto.timingSafeEqual(
    Buffer.from(signature), Buffer.from(expected)
  );
}

Delivery and retries

  • Return 2xx quickly. Anything else is retried with exponential backoff, up to 5 attempts.
  • After the last attempt a delivery is dead-lettered; replay it from the delivery log.
  • Deliveries can arrive out of order or more than once — key on the order id and the event, and make handlers idempotent.

Payload minimalism

Default payloads carry ids, state, and totals only. Card data never appears in a webhook. Richer cart detail is available behind an explicit data agreement.