Skip to content
All articles
Security12 June 2026·7 min read

Rotating a webhook secret without dropping an event

The secret is shared with a system you do not deploy. Changing it is a two-party operation, and the only safe version overlaps.

Paycux security engineering

A webhook signature is a shared secret arrangement: you hold a value, the receiver holds the same value, and every delivery carries a signature computed over the payload. It works well, and it has the property every shared secret has — it must be changeable, and changing it requires two systems that are not deployed together to agree on a moment.

Treated as a single edit it is an outage. The sender starts signing with the new secret at the instant the receiver is still verifying with the old one, every delivery fails verification, and the events in flight are rejected by an endpoint doing exactly what it was told to do.

Send both signatures during the overlap

The mechanism that makes this safe is a header that can carry more than one signature. A delivery during the transition includes a signature under the old secret and one under the new, and a receiver that accepts if any signature matches any secret it holds will accept the delivery regardless of which side has finished moving.

A common shape is a header carrying a timestamp and a list of versioned signatures, for example Paycux-Signature: t=<unix seconds>, v1=<hex>, v1=<hex>. The signature is computed over the timestamp and the raw body joined by a separator, and the receiver checks every candidate. Because verification is a comparison rather than a decryption, accepting several is not a weakening: an attacker still has to produce a value that matches a secret they do not have.

  • Design the header to hold multiple signatures from the first version, not as a later addition
  • Sign the raw bytes of the body, before any parsing or re-serialisation
  • Include the timestamp in the signed material so it cannot be altered independently
  • Compare in constant time, and reject deliveries whose timestamp is outside a narrow window

The order of operations is the whole plan

Rotation is four steps and they only work in one sequence. Generate the new secret and make it visible to the receiver while it is not yet in use. Wait for the receiver to add it to the set they accept. Begin signing with both. Once you are satisfied nothing is failing, stop signing with the old secret and remove it.

The waiting between the second and third steps is the part people compress, and it is the part that makes the rotation safe. There is no way for you to know the receiver has deployed their change except by them telling you, so the interface has to let them say so — a confirmation in the dashboard, or a test delivery they can verify against the new secret before anything live depends on it.

You cannot observe the other system's deploy. The overlap window is how you avoid having to.

One secret per endpoint

A single account-wide secret shared across every endpoint means a leak from any one of them compromises all of them, and rotating it forces every receiver to move together. Since the receivers are often different teams, or different companies, that coordination is the reason rotations get postponed indefinitely.

Scope the secret to the endpoint. Each destination has its own value, each can be rotated independently, and a compromise is contained to one integration. It also makes revocation a decision rather than a negotiation: turning off one endpoint's secret does not require asking anyone else's permission or waiting for their release schedule.

Compromise is a different plan, and it should be written already

Planned rotation optimises for zero dropped events. Responding to a leaked secret optimises for the opposite: the old value must stop being accepted immediately, and some deliveries will fail. Trying to run the graceful procedure during an incident gives you the worst of both, because the overlap you are politely observing is the window the attacker is using.

Build both paths. Rotate with overlap should be a button; revoke now should be a separate button that says plainly what it will break. Then make replay cheap — a way to re-deliver events from a time range once the receiver is ready — so the cost of the emergency path is a few minutes of catching up rather than permanently lost events.

  • Separate secrets per endpoint, so a rotation is never a cross-team negotiation
  • Offer a test delivery signed with the new secret before it carries live traffic
  • Keep an immediate revocation path that is distinct from graceful rotation
  • Provide replay for a time range, so the emergency path does not lose events permanently

Everything here, already built

Sign-in, enterprise SSO, directory provisioning, roles and an audit trail behind one API. Start with the quickstart and have a working sign-in this afternoon.

Start selling to enterprise customers

Create an account, point sign-in at Paycux, and get back to the part of the product that is actually yours.