FREE WEBHOOK STATE-MACHINE SIMULATOR | 72H DEDUP & MONOTONIC WATERMARK
Free Webhook Replay & Out-of-Order State Machine Simulator
Test how your billing and entitlement state machine handles delayed out-of-order webhooks, duplicate retries within a 72-hour (259,200s) idempotency window, and stale replays so a delayed customer.subscription.updated (active) never resurrects a canceled subscription.
1. Configure Webhook Delivery Sequence
Select a real-world webhook ordering trap or edit the JSON arrival sequence (1–10 events) to evaluate monotonic watermark enforcement.
2. Monotonic Watermark Verdict & Step-by-Step Trace
Compares RevClamp's monotonic lastAppliedCreatedSec state machine against a naive webhook handler that blindly overwrites DB state on arrival.
[BLOCK_REVOKED_OR_EXPIRED] • Final Status:
Out-of-Order Trap Caught: Applied canceled (Tier: free)1/2 events • Stale Ignored: 1 • Duplicates Dropped: 0 • Naive Handler Bug: RESURRECTED_CANCELED_SUBSCRIPTION.
{
"ok": true,
"simulationDryRun": true,
"scenarioPreset": "out_of_order_stale_update_after_cancel",
"nowSec": 1760001200,
"idempotencyWindowSec": 259200,
"totalEventsEvaluated": 2,
"appliedCount": 1,
"duplicateDroppedCount": 0,
"staleOutOfOrderDroppedCount": 1,
"expiredWindowDroppedCount": 0,
"finalStatus": "canceled",
"finalTier": "free",
"finalPeriodEndSec": 1760001000,
"lastAppliedCreatedSec": 1760001000,
"finalEntitlementDecision": "BLOCK_REVOKED_OR_EXPIRED",
"naiveFinalStatus": "active",
"naiveFinalTier": "growth_59",
"naiveHandlerBug": "RESURRECTED_CANCELED_SUBSCRIPTION",
"steps": [
{
"stepIndex": 1,
"eventId": "evt_cancel_1000",
"eventType": "customer.subscription.deleted",
"createdSec": 1760001000,
"ageSeconds": 200,
"incomingStatus": "canceled",
"incomingTier": "free",
"decision": "APPLIED_MONOTONIC_STATE_TRANSITION",
"applied": true,
"reason": "Monotonic transition applied (watermark advanced to 1760001000).",
"stateAfterStep": {
"billingStatus": "canceled",
"tier": "free",
"lastAppliedCreatedSec": 1760001000
}
},
{
"stepIndex": 2,
"eventId": "evt_update_0950",
"eventType": "customer.subscription.updated",
"createdSec": 1760000950,
"ageSeconds": 250,
"incomingStatus": "active",
"incomingTier": "growth_59",
"decision": "STALE_OUT_OF_ORDER_TRANSITION_IGNORED",
"applied": false,
"reason": "Event createdSec (1760000950) is older than latest applied watermark (1760001000).",
"stateAfterStep": {
"billingStatus": "canceled",
"tier": "free",
"lastAppliedCreatedSec": 1760001000
}
}
]
}
3. 5-Gate Webhook State-Machine Protection Matrix
Why signature verification alone is insufficient: webhook queues in Stripe, Shopify, and Lemon Squeezy guarantee at-least-once delivery, not in-order or exactly-once delivery.
| Webhook Anomaly | Naive Handler Failure Mode | RevClamp State-Machine Guard | Deterministic Decision Code |
|---|---|---|---|
| Delayed Out-of-Order Update After Cancel | Overwrites canceled with active, leaking unpaid API/SaaS access |
Rejects state regressions where event.createdSec < lastAppliedCreatedSec |
STALE_OUT_OF_ORDER_TRANSITION_IGNORED |
| Duplicate Retry Within 72 Hours | Fires duplicate entitlement webhooks, emails, or ledger credits | Tracks seen_billing_events in SQLite WAL for 72h (90d for billing) |
DUPLICATE_EVENT_IDEMPOTENT_NOOP |
| Ancient Queue Replay (> 72h Old) | Mutates current tenant state using an expired historical snapshot | Enforces nowSec - createdSec <= idempotencyWindowSec bound |
EXPIRED_OUTSIDE_72H_DEDUP_WINDOW |
Cancel With Future ends_at Period |
Locks out paid customer immediately before paid billing period ends | Transitions to cancel_at_period_end until nowSec >= currentPeriodEndSec |
APPLIED_MONOTONIC_STATE_TRANSITION |
Cancel With Terminal expired / unpaid |
Grants unintended grace period to already-expired subscriptions | Evaluates terminal expired/unpaid before cancel_at_period_end |
BLOCK_REVOKED_OR_EXPIRED |