# agent reused one idempotency key for two invoices: second invoice silently dropped

## TL;DR
Give every distinct invoice its own idempotency key: derive the key from the invoice's unique content (customer + lines + date), never from a shared constant. If an invoice was silently dropped, check whether the key was already used, then reissue with a fresh unique key. One key means one logical operation; sharing it merges two invoices into one.

```text
agent reused one idempotency key for two invoices: second invoice silently dropped
```

## Fix it

1. **Derive the key from the invoice content.** Hash customer id + line items + amounts + billing date, e.g. `inv-[customer_id]-[date]-[short-hash-of-lines]`. Success check: two different invoices produce two different keys.
2. **Never use a constant or run-scoped key.** A key like `daily-invoice-run` or a single UUID generated once per batch guarantees collisions. Success check: code review shows the key built inside the per-invoice loop, not outside it.
3. **Detect a silent drop.** If the API returns an invoice whose lines don't match your request, you reused a key; log the mismatch and reissue. Success check: a mismatch in staging raises an alert instead of passing silently.
4. **Recover the dropped invoice.** Confirm the first invoice is correct and paid/due as intended, then create the second invoice with a fresh unique key. Success check: both customers have their own invoice with matching line items.

## When this applies

- Batch invoice jobs where one request's response came back for a different invoice.
- An invoice is missing and the API log shows a 200 with a different invoice id.

## When it doesn't

- Retries created duplicates; that is the opposite bug (a new key per retry), handled separately.
- The invoice failed validation; check the error response, not the key.

## Compatibility

- Pattern: agent batch-invoicing on Stripe, Chargebee, Xero, QuickBooks, or any API honoring idempotency keys.
- Keys are provider-opaque strings; the derivation scheme is yours to design.

### Variant: monthly billing reused last month's key

The key included the customer but not the period. Same fix: the billing date/period must be part of the key material.

### Variant: two agents shared a key namespace

Both agents generated keys like `invoice-1`. Same fix plus a per-agent or per-job prefix in the key.

## Why it happens

Idempotency keys dedupe by equality: same key means "replay the first request." When an agent reuses a key for a genuinely different invoice, the provider correctly (from its view) returns the original invoice, and the second one never exists.

## Edge cases

- Retrying the SAME invoice must reuse its key; only distinct invoices get distinct keys. Keep the derivation deterministic so retries reproduce the same key.
- Don't put secrets or PII in the key; a hash of the content is enough.

## Provenance

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