19-production-discoveries

Three things sandbox couldn't tell me about my payment SDK.

19-production-discoveries

Three things sandbox couldn't tell me about my payment SDK.

Sandbox passed. All tests green. I deployed to production and within a week production told me three things sandbox never had.

1. "Canceled" with one L.
The official docs said the status enum was CANCELLED — the British spelling. Sandbox always returned exactly that. In production, the gateway sometimes returns "Canceled" (US spelling, one L). My SDK normalizes both to a single CANCELLED type now. Without that, downstream code with strict enum matching would crash on a perfectly valid status.

2. Multibanco refunds settle asynchronously.
In sandbox, you call refund and you get "refunded" immediately. In production, Multibanco refunds settle hours later — sometimes the next day — via a separate webhook with method "RB:PT" linked to the original transaction. So you can't just await client.refund() and assume it's done. The state moves on a different channel.

3. Pay By Link expires silently.
The hosted Pay By Link URL is generated with an expiration. In production, when it expires, there is no webhook telling you. The link just becomes a generic 404 page. Your customer sees "page not found" — that's the user-facing failure mode. The SDK now tracks the expiration itself and emits a logical "expired" event when the deadline passes, so the merchant can re-send.

Each of these is one quiet sentence in the SDK changelog now. Each cost real time to discover. None of them was in the sandbox specification.

The sandbox is a model of the gateway. The gateway is a model of reality. Reality wins.

What did production teach you that sandbox didn't?

Repo: github.com/bilouro/eupago-python

P.S. New tech post every Wednesday.

#OpenSource #Python #SoftwareArchitecture

Comments