DEV Community

Jackson Wood
Jackson Wood

Posted on

When Your API Integration Works in Testing but Dies in Production

Let me tell you about a bug that wasn't really a bug.

A team I worked with wired up three payment processors behind a single checkout API. One unified interface, one processPayment() call, clean abstraction. Tests passed. Demo looked great.
Production lasted about a week before it broke.

The actual problem

One processor returned a state the other two didn't have: authorized_not_captured. The shared interface only knew success / failed. So every transaction in that intermediate state either silently failed or got double-charged on retry.

Nobody wrote bad code here. The abstraction was just built on an assumption — "these three APIs are functionally the same" — that held up in testing and fell apart the moment real-world state transitions showed up.

The fix wasn't a patch

The team didn't add a special case. They had to stop normalizing too early — handle each processor's actual state machine individually, and only collapse to a unified outcome at the very last step. More code, less elegant-looking, way more correct.
The questions that should've been asked before any code was written

What's the system of record when two integrated systems disagree on state?

What happens on partial failure — not "API down," but "API returned something we didn't expect"?

Who owns versioning when a third party changes their response shape without warning?

Are we testing failure states, or just the happy path?

If you're building or reviewing an integration right now, that list is more useful than another REST vs GraphQL comparison.

Takeaway

A demo proves the happy path works. Production proves whether you mapped the unhappy ones. Most integration failures I've seen trace back to skipping that mapping step, not to bad implementation.
Curious if others have a similar "worked in staging, exploded in prod" integration story — always good to compare notes on what actually breaks.

Top comments (0)