# A signing secret per environment

September 13, 2026 · Webhooks · Breaking

Each application used to have one webhook signing secret for both environments. Now sandbox and production each have their own, and every delivery carries an `X-Layout-Environment` header of `sandbox` or `live`.

## What changed

- **Two secrets.** Sandbox kept the secret it already had. Production was given a new one that is different from it.
- **A header that names the environment**, sent with `X-Layout-Signature`, `X-Layout-Event` and `X-Layout-Delivery` on every delivery, retries and replays included.
- **The Webhooks page follows the environment switch**, showing the signing secret for whichever environment is selected. A test delivery is signed with that environment's secret.

## Why it matters

Each environment now has its own signing secret, so trust in sandbox and trust in production are fully separate.

## What to do

Copy the production signing secret from the Webhooks page into your production configuration, then pick the secret by the header before you verify:

```js
const secrets = {
  sandbox: process.env.LAYOUT_WEBHOOK_SECRET_SANDBOX,
  live: process.env.LAYOUT_WEBHOOK_SECRET_LIVE,
};

const secret = secrets[req.headers["x-layout-environment"]];
if (!secret || !verify(req, secret)) return res.status(401).end();
```

`verify` is the signature check from [Verify the signature](https://developer.layout.link/reference/webhooks#verify-the-signature). A handler that only ever sees one environment can keep a single secret, as long as it is that environment's.

## Breaking changes

Yes, for production. A production handler still verifying with the old shared secret rejects every production delivery from this release on. Sandbox verification keeps working unchanged.
