Two identical POST requests carrying the same Idempotency-Key arrive at the same instant on two different instances. Walk through why wrapping the check-then-insert in a database transaction doesn't prevent a double-charge, and what does.
At the default READ COMMITTED isolation level, both instances can run SELECT ... WHERE key = ?, both see no row (because neither has committed yet), and both proceed to charge and insert — two charges. A transaction only guarantees that its own reads and writes are consistent with each other; it says nothing about what a simultaneously-running transaction on another instance is doing, so wrapping the check-then-insert in BEGIN/COMMIT doesn't close that window, it just makes it feel safer than it is. A unique index on the key column does close it, because uniqueness is enforced at the point of the physical write itself — the second insert to actually reach that point fails on the constraint, and that failure is the signal that another request already owns this key.