Launch-readiness teardown

Replay One Signed Webhook Five Times. You Should Still Get One Entitlement.

A customer can complete checkout once while your webhook handler receives the same event more than once. If every delivery creates access again, one purchase can produce duplicate licenses, seats, credits, or subscription records.

The launch check is concrete:

Take one valid, signed order webhook. Deliver the exact same body five times. The result should still be one processed-event record and one intended entitlement.

A webhook signature is necessary. It is not idempotency.

What the signature proves—and what it does not

A valid signature tells your handler that the raw request body matches a message signed with the configured webhook secret. It helps reject forged or modified payloads before they change state.

It does not tell you that the message is new.

Every repeated delivery can carry a valid signature because it is an authentic copy of the same event. A handler that verifies the signature and then blindly calls grantAccess() can still grant access five times.

In the deliberately vulnerable ShipTested example, the handler parses the body and appends an entitlement on every call. Replaying the fixture five times leaves five entries:

same order webhook ×5
entitlements.length === 5

That is the failure we preserve as a reproducible red test.

Define the invariant before the implementation

The fixed example starts with an invariant:

For one accepted order_created event and one expected product variant, repeated sequential delivery changes entitlement state once.

The handler verifies the HMAC signature against the unmodified raw body before mutation. It then checks the fields this teaching fixture expects:

A signed payload for an unexpected variant grants nothing. So does an invalid signature.

After those checks, the example creates a stable key from the event name, resource type, and order ID:

const eventKey = `${eventName}:${order.type}:${order.id}`;

The first accepted delivery records that key and sets the intended entitlement. Later deliveries with the same key return duplicate-no-op.

The five-delivery test

The fixed test signs one raw JSON body once, then sends that same body and signature through the handler five times sequentially.

Its expected outcomes are explicit:

1. granted-once
2. duplicate-no-op
3. duplicate-no-op
4. duplicate-no-op
5. duplicate-no-op

processedEvents.size === 1
entitlements.size === 1

That is stronger evidence than clicking through checkout once and looking at a success page. The test forces the duplicate-delivery path and records the invariant in code.

Clone the teaching harness and run:

npm test
npm run test:launch

The repository contains both the vulnerable reproduction and the fixed sequential replay test. The fixtures use test-only values and contain no live credentials.

What this result actually proves

The test proves that this dependency-free JavaScript model handles five sequential copies of the same signed fixture as one intended entitlement change.

It also demonstrates that four controls solve different problems:

That is the evidence boundary.

What it does not prove

The public example stores processed events in an in-memory Set and entitlements in an in-memory Map. A process restart clears both.

Its five deliveries run in a normal loop. They do not arrive concurrently. The example therefore does not prove that two workers cannot pass a database existence check at the same time.

It also does not prove:

Those are launch checks for the real database-backed application, not claims made by this harness.

In production, the “already processed?” check and the entitlement change need a database-enforced boundary. Use a transaction and appropriate unique constraints so two overlapping deliveries cannot both win. Resolve the buyer against a real internal record. Then test forced failures, concurrent delivery, process restarts, and refund ordering against the deployed database revision.

Do not label the in-memory demonstration production-safe. Do not treat one green sequential replay as a security certification.

Run the smallest useful test

Start with the test that can fail today:

  1. capture one valid test-mode webhook without exposing its secret;
  2. replay the exact body and signature five times in a safe environment;
  3. inspect processed-event and entitlement state;
  4. save the result with the commit and environment tested.

If five deliveries create five grants, keep that reproduction. It is better evidence than a vague feeling that retries are “probably handled.”

Inspect the exact test

Run the broader launch-readiness checklist

Sources: Lemon Squeezy webhook requests and signing requests.

Test this on your own app before you sell it.