Webhook entitlement decision matrix
Payment webhook bugs often happen after signature verification, when the handler decides whether to grant access, extend a renewal, deliver a license, schedule cancellation, or ignore an event.
Open the free matrix builderDecision matrix
| Event | State | Handler decision | Write model | Regression test |
|---|---|---|---|---|
| order_created | paid | Grant one-time access | purchase entitlement + processed event | Paid order grants exactly once under duplicate replay. |
| order_created | pending, failed, refunded | Hold or revoke access | order audit record, no active entitlement | Unpaid or refunded order does not grant access. |
| license_key_created | created | Deliver license key | license entitlement with redacted key reference | License delivery is idempotent and masks the key in logs. |
| subscription_created | active or trialing | Activate subscription | subscription entitlement + current period | Subscription create maps customer to the correct plan. |
| subscription_payment_success | paid | Extend renewal | invoice payment + renewed entitlement window | Retrying the same invoice does not extend twice. |
| subscription_cancelled | ends_at present | Schedule cancellation | subscription status + scheduled access end | Cancellation keeps access until the configured end date. |
| payment_failed | past_due or failed | Pause risky side effects | dunning state, no destructive delete | Failed payment does not erase entitlement history. |
| unknown_event | unmapped | Quarantine and acknowledge | raw event sample + alert | Unknown events are stored for review and do not run side effects. |
Release rule
Verify the signature first, persist an idempotency key, then run the entitlement decision once. Duplicate deliveries should return success without repeating the side effect.
What to test in CI
Every row should have a fixture and a duplicate replay test. The most important checks are paid order grants once, unpaid order grants nothing, renewal extends once, cancellation respects the end date, and unknown events are quarantined without customer-facing side effects.
FAQ
Should a webhook grant access before signature verification?
No. Verify the raw-body signature first, persist a stable idempotency key, then run the entitlement decision exactly once.
Should duplicate payment webhooks extend subscriptions twice?
No. Duplicate deliveries should return success after confirming the idempotency key already ran, without repeating license delivery, access grants, emails, or renewal extension.
Use the free sample before wiring production checkout
Download a public sample pack with fake Lemon Squeezy fixtures, signature tests, contract checks, duplicate replay tests, and CI skeletons. The Pro Kit preview shows the full paid package structure without exposing the private archive.