Network failures happen. Clients retry. Your API must handle duplicate requests:
Idempotent operations: Same request, same result. GET, PUT, DELETE are naturally idempotent. POST usually isn't.
Idempotency keys: Client sends unique ID with request. Server checks if already processed. Return cached response if duplicate.
POST /payments
Idempotency-Key: abc-123
{amount: 100}
Stripe uses this pattern. Without it, retried payment requests could charge customers multiple times.