## TL;DR

Network retries turn one bill create into two bills unless the API can recognize the retry. Send an idempotency key (vendor ID plus invoice number plus a hash of key fields) with every create; on conflict, fetch the existing bill instead of failing. This makes every integration safe to retry.

## Steps

1. Derive the key from vendor, invoice number, and amount hash.
   Expected: A stable key per bill.
2. Send it on every create (header or field per the API).
   Expected: Server-side dedup.
3. On conflict responses, fetch the existing record.
   Expected: Graceful recovery.
4. Never regenerate the key on retry.
   Expected: The key is the identity.
5. Log key collisions for monitoring.
   Expected: Visibility.

## When to use

- API bill creation
- Retry-safe integrations
- Exactly-once semantics

## When not to use

- Payment idempotency (different layer)
- Manual bill entry
- Non-retryable operations

## Compatibility

APIs with idempotency support (Stripe-style keys, NetSuite external IDs); ERP-agnostic pattern.

## Variant phrasings

### idempotent bill creation

### bill create retry safety

### exactly once vendor bill

## Root cause

Distributed systems retry. Without idempotency, a retry after a timeout creates a second bill for an invoice that already posted.

## Edge cases

- Key scope must match the API's uniqueness scope
- Amount changes need a new key (it is a different bill)
- Legacy APIs without key support need client-side check-then-create

## Provenance

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