## TL;DR
Webhooks are delivered at least once, not exactly once, so a duplicate delivery of an old event will reopen a closed ring case in any handler that treats event arrival as new activity. Deduplicate on the event id and on the business key, ring id plus event type plus source timestamp: if the agent has already processed that event, acknowledge it and change nothing. Reopening a resolved ring should require a new transaction, account, or device link that was not in the original case, and the reopen action should have to cite it.

```text
fraud agent re-opened resolved fraud ring case on duplicate webhook
```

## Use this when
- Resolved ring cases reopen with no new transactions attached.
- Webhook logs show the same event id delivered more than once.
- Reopens cluster after webhook endpoint outages or retries.

## Not for this skill when
- A ring gains a genuinely new linked order or account. Reopen it, citing the new link.
- The case was closed in error by a human or agent. That reopening is a correction, handled through case review.

## Steps
1. Pull one resurrected case and compare the reopening event with the original event history: event id, timestamps, and payload hash. Verify: you can show whether the trigger was a duplicate or new data.
2. Add event deduplication storage: processed event ids retained beyond the vendor retry window, checked before any case mutation. Verify: a replayed event in staging is acknowledged with no state change.
3. Add a business level guard as a second layer: an event whose source timestamp predates the case resolution cannot reopen it. Verify: an old event replayed with a fresh id still cannot reopen the case in staging.
4. Require reopen evidence: the reopen action must attach at least one new linked entity not present at resolution, and log it as the reopen reason. Verify: a staged reopen attempt without new evidence is refused with the reason logged.
5. Sweep currently reopened cases and reclose those whose only trigger was a duplicate, noting the duplicate event id on each. Verify: the reopened queue contains only cases with genuine new evidence.

## Variant phrasings
### duplicate webhook reopened closed fraud case
Webhook phrasing.
### fraud ring case keeps resurrecting agent
Resurrection phrasing.
### idempotent webhook handling fraud agent
Idempotency phrasing.

Compatibility: Stripe, Adyen, Sift, Signifyd, and internal event sources with at least once delivery, and any agent webhook consumer. Retention for dedup storage should exceed the longest vendor retry window you rely on.

## Why it happens
Vendors retry webhooks after timeouts and outages, and they make no promise against duplicates. Agent handlers written as if each delivery were a fresh fact will act on history as if it were news. Resolved cases are the most visible victims because their state change is dramatic, but the same duplicate can double count evidence, alerts, and notes anywhere in the pipeline.

## Edge cases / pitfalls
- Deduplicate on both the transport event id and the business payload. Some sources regenerate ids on retry.
- Acknowledging a duplicate must still return success, or the vendor will keep retrying it.
- Keep a reopen audit report. A sudden rise in legitimate reopens can be the first sign of a ring reactivating.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_QyAkCA5dZjKvV_1dl-tX1w
