## TL;DR
The first import probably succeeded on the server while its response was lost to the timeout, so the retry imported the same statement again and every transaction doubled. Clean up by identity, not by eyeballing: the duplicate set shares bank transaction identifiers, an import batch or a created timestamp with the original set. Where the platform supports it, delete or reverse the second import batch as a unit; where it does not, match duplicates pairwise on identifier, date and amount and remove one of each pair, taking care with legitimately repeated transactions (identical amounts on the same day are common and are not duplicates unless their bank identifiers also match). Then make the import idempotent: check for an existing batch covering the statement's identifier and date range before importing, and store the statement fingerprint so a retry after any failure first asks whether the import already landed.

```text
agent retried the statement import after a timeout and created a second copy of every October transaction
```

## Use this when
- Every transaction for a period, here October, appears twice after an import was retried following a timeout.
- The duplicates share identical amounts, dates and bank references.
- Downstream matching or reconciliation has not yet consumed the duplicates, or has consumed only one set.

## Not for this skill when
- Only a handful of transactions are duplicated from manual re-entry. Remove those individually as a normal correction.
- The bank genuinely sent each transaction twice in separate files with different identifiers. Escalate to the bank and dedupe by their confirmed error.

## Steps
1. Halt matching and reconciliation automation on the account until deduplication is complete. Verify: no agent consumes duplicates while you clean up
2. Group the period's transactions by bank transaction identifier and import batch to prove the duplication pattern and its exact scope. Verify: duplicate pairs are enumerated by identifier, not guessed from amounts
3. Check whether any duplicates were already matched or reconciled, and unmatch those before removal. Verify: removal will not corrupt completed matches
4. Delete or reverse one complete duplicate set, preferring whole-batch removal where the platform supports it. Verify: each bank identifier now appears exactly once for the period
5. Reconcile the month, then implement idempotency: statement fingerprint check before import and batch recording after, and test with a deliberate retry. Verify: the month ties, and a test retry is refused as already imported

## Variant phrasings
### agent retried statement import timeout created duplicate every transaction
The retry-duplication symptom.
### idempotent bank statement import fingerprint batch check retry safe
The idempotency-design phrasing.
### remove duplicate imported transactions bank identifier dedupe October
The cleanup procedure search.

Compatibility: Agent and connector bank imports into NetSuite, Xero, QuickBooks, SAP and reconciliation platforms, from files, bank APIs and aggregators such as Plaid.

## Why it happens
Distributed systems cannot distinguish a lost request from a lost response: the timeout told the agent the import might have failed, while the server had in fact committed it. A retry without an idempotency key or a pre-check is then a second, fully valid import. Statement imports are especially exposed because the same file can be legitimately re-presented by banks and aggregators, so the receiver, not the sender, must own duplicate defence - and amount-plus-date matching is too weak, because real life repeats amounts daily.

## Edge cases / pitfalls
- Keep one duplicate pair's full records in the incident log as evidence of the pattern before deletion.
- If duplicates reached a filed period, follow the prior-period correction process rather than silent deletion.
- Aggregators sometimes regenerate transaction identifiers; combine identifier, amount, date and running balance in the fingerprint where identifiers are unstable.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_DhoH0ZRwc3rXJl-KMDSbpA
