## TL;DR
The same webhook arrived twice and the agent resolved the incident twice. Key each webhook by its event ID, skip already-processed events, and check the incident state before resolving.

## The query
```text
agent double-resolved the same servicenow incident: webhook dedupe
```

## Use this when
- incidents show two resolution entries
- webhook logs show duplicate deliveries
- the agent acts twice on one event

## Not for
- duplicate incidents created from one event
- manual double-resolution by humans
- email notification duplicates

## Steps
1. Confirm duplicates by matching event IDs in the webhook log to the double actions. Expected output: the same event ID appears twice.
2. Store processed event IDs with a TTL and skip any event already seen. Expected output: the second delivery is acknowledged but ignored.
3. Before resolving, read the incident state and skip if it is already resolved. Expected output: the state check prevents the second resolution.
4. Return success on duplicates so the sender stops retrying. Expected output: the retry storm ends.
5. Monitor for skipped duplicates to catch sender-side bugs. Expected output: a metric shows dedupe working.

## Applies to
ServiceNow webhooks, any webhook-driven agent, idempotency-key patterns.

## Variant phrasings
### Duplicates from two different integrations
Normalize to one event stream or namespace the dedupe keys per source.

### Resolution partially applied twice
Make the resolution action itself idempotent, not just the webhook handler.

## Why it happens
Webhook senders retry on timeouts, and networks deliver twice. Without dedupe, every retry becomes a second action.

## Edge cases
- Size the dedupe store TTL beyond the maximum retry window.
- Dedupe keys must include the event type, not just the incident ID.
- Log skipped duplicates; silent drops hide integration problems.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_I287AyIf5OsoHFOLMDyrRw
