What a payment sandbox will not let you test
A sandbox proves your request is well formed. It does not prove settlement timing, issuer behaviour, or failures that show up only with real cards.
A green sandbox run is evidence that your request matches the provider’s test API. It is not evidence that the integration will behave in production. Teams treat those as the same fact, and the bugs that escape are boringly predictable: a webhook that never arrives late, a decline that no test card produces, a settlement file whose shape you have never seen.
This is the list of what to stop expecting the sandbox to prove, and what to put in its place. It assumes you can get keys at all. For Gulf gateways that is often the harder problem, and it is written up separately in getting sandbox access as a non-resident.
What a sandbox is actually for
Use it to lock down the things that are properties of the API, not of the cardholder’s bank:
- Authentication, and which key type is accepted where.
- The happy-path request and the documented error body.
- Signature verification, against a vector you computed yourself or one the provider published. The webhook signature guide is built that way on purpose: the tests need no network and no credentials.
- Your idempotency and ordering code, by replaying recorded bodies. You do not need the gateway online to prove a stale event cannot rewind a capture.
Record the raw webhook payloads the sandbox does send. Those fixtures are more useful than the sandbox six months later, because you can replay the awkward ones on demand.
What it will not prove
| You wanted to know | Why the sandbox cannot tell you | What to do instead |
|---|---|---|
| Whether a real issuer will decline this card | Test cards are scripted. They are not a bank. | A small production pilot, with alerts, before you call it done. |
| 3-D Secure as a cardholder will see it | The challenge page is the issuer’s ACS, not the gateway’s. | Test the states your API must handle. Do not treat a sandbox challenge screen as the production one. See 3-D Secure 2. |
| That webhooks arrive in order, or on time | Sandboxes are unloaded, and many have a “send test webhook” button that fires once, immediately. | Replay fixtures out of order in CI. Measure production lag; do not assume the button. |
| Settlement amounts, fees, and timing | Test payments often never settle. There is no file. | Parse a real file from the first production day, in a job that cannot move money until it matches. See reconciliation. |
| Rate limits | The sandbox is not their production edge. | Honour Retry-After if you ever see one. Do not encode a guessed limit as a constant and call it measured. |
| Key and account gates | A test account that someone inside the company created does not tell you what a new merchant will be asked for. | Write down the signup, dated. Requirements move. |
The last row is why a guide written only from the public docs is not a guide. The docs say the endpoint exists. They rarely say that registration demanded a local mobile number before you could call it.
What to fake, and what not to
Fake the gateway in CI. Do not fake it as a single happy response.
A useful fake returns, on demand:
- a signature-valid webhook, then the same event id again
- the same payment moving pending → captured, delivered backwards
- a timeout after you have accepted the request, so the retry test can prove it does not create a second charge
- a 429 with
Retry-After
A fake that only returns 201 will keep the build green while the production handler falls over the first duplicate. That fake is how the retry guide gets skipped.
Do not fake the parts you are claiming to have verified. If the post says a header is hex, the test should check hex. If you have not called the sandbox, say you have not. A synthetic payload you invented is a test of your parser against your own imagination.
A practical split
- CI, no network. Fixtures, signature vectors, state machine, idempotency store. This runs on every commit.
- Sandbox, manual, dated. One happy path and the documented declines, against the current API version. Re-run when they announce a break, not on a cron that will start failing for unrelated reasons and get ignored.
- Production, constrained. One merchant, low limits, logs on signature failure and on any payment that is captured in your database and absent from the next settlement file.
Skip step 3 and you have tested the brochure.
Failure modes
| Symptom | Cause | Fix |
|---|---|---|
| Works in sandbox, first real card hangs | 3-D Secure challenge never exercised | Handle the pending-authentication state |
| Works in sandbox, production webhooks 401 | Test secret shipped, or a proxy rewrote the body | Separate secrets; verify raw bytes |
| CI green, duplicate orders in week one | Fake never sent the same event twice | Fixture the duplicate |
| “Tested” settlement | No file was ever parsed | Block go-live on one real file |
Production checklist
- CI covers duplicate events, reversed events, and a timeout-then-retry
- Sandbox notes are dated, including what you could not do
- No production secret in the sandbox config, and the reverse
- First production week watched against the settlement file
- A written line for anything the sandbox simply does not offer
Sources
- Stripe: testing — scripted test cards and the boundary of what those cards represent. Checked 26 September 2026.
- Getting sandbox access to Gulf gateways as a non-resident — the access limits that come before any of this applies.
Stripe’s test cards are a published catalogue, which is why they can be cited. Where a Gulf provider has not published an equivalent, this post does not invent one.