Founder & Lead Engineer, RAITHub
RAITHub ships and tests production software. See QA as a Service or talk to us.
Use your payment gateway's test mode with its test cards. Every major gateway has a sandbox where no real money moves. In Stripe, use test mode, card 4242 4242 4242 4242 for a success, published decline cards for failures, and a 3D Secure card for authentication. Then test refunds, duplicate payments and webhooks. The point is to hit the paths real users will, not just the success case.
If you would rather have payments tested end to end for you, see how RAITHub would test this below, or the pre-launch QA overview.
What does "test mode" give me?
A full copy of the payment flow where no card is charged. Stripe's documentation describes test mode as a way to "simulate payments" using test cards that behave like real ones without moving money (Stripe testing docs). You get test API keys, test cards for every outcome, and test webhooks, so you can run the whole checkout, subscription and refund journey against your staging app before a single real customer pays.
The common mistake is testing only the success card and declaring payments done. The expensive bugs live in the paths that do not succeed, and those are the ones this post is about. The AI-built-app angle on the same problem is in testing payments in an AI-built app.
Which payment cases should I actually test?
Test every outcome a real customer can produce, not just the one you hope for. These are the cases that cost money or trust when they are wrong.
| Case | How to trigger it in test mode | What should happen |
|---|---|---|
| Successful payment | Card 4242 4242 4242 4242 (Stripe) | Order or subscription is created once, receipt sent |
| Declined payment | A published decline card, e.g. 4000 0000 0000 0002 | Clear error, no order created, user can retry |
| 3D Secure challenge | Card 4000 0027 6000 3184, which requires authentication | User completes the challenge; a failed challenge creates no order |
| Refund | Refund a test payment from the dashboard | Access or goods revoked, refund recorded, customer notified |
| Duplicate payment | Submit the form twice, or replay a webhook | The customer is charged and provisioned once, not twice |
That 3D Secure card is a good example of a path nothing tests unless someone decides to: it requires authentication on every transaction, so it catches flows that silently assume a frictionless charge. Payments are one item on the broader list in what to test before taking real users.
Free checklist
AI-Built App Launch Readiness Checklist
25 checks before you let real users in. Enter your email and we’ll reveal it below (and send you a copy).
One email, the checklist, no spam. By submitting you agree we can email you this checklist and reply to your enquiry.
How do I test webhooks without going live?
Webhooks are where payments quietly break, because a webhook can arrive late, out of order or twice. A gateway can return a 200 to the browser while the webhook that actually grants access never completes; the failure mode is covered in a webhook returned 200 but the subscription did not update. Test webhooks locally by forwarding them to your app:
stripe listen --forward-to localhost:3000/api/webhooks/stripe
# in another terminal, fire a specific event:
stripe trigger payment_intent.succeeded
Then make your handler idempotent, so replaying the same event does not provision twice:
// reject an event you have already processed
const seen = await db.webhookEvent.findUnique({ where: { id: event.id } })
if (seen) return new Response('ok', { status: 200 })
await db.webhookEvent.create({ data: { id: event.id } })
// ...then grant access exactly once
A fuller end-to-end walkthrough is in testing payments and webhooks.
Can I test payments entirely myself?
Yes, for the core cases, and you should. Budget two to four focused hours to walk a success, a decline, a 3D Secure challenge, a refund and a double payment through test mode. The main risk of doing it alone is incomplete coverage: it is easy to test the success path and the obvious decline, and miss the out-of-order webhook, the refund that does not revoke access, or the double-submit that charges twice. Treat idempotency and refund-revocation as the parts most worth a second opinion, because they are the ones that quietly lose money after launch.
Buy, build or hire?
| Route | Choose this when |
|---|---|
| Test it yourself in test mode | You know the gateway, have a few hours, and will cover declines, refunds and duplicates, not just the success card |
| A freelancer for one pass | You want another set of eyes on the payment journeys for one launch |
| Automated payment tests | You charge on every release and want test-mode payments covered in CI so a change cannot break checkout silently |
| A managed QA audit | Money is central to the product and you want every payment case verified end to end, with a report |
How RAITHub would test this
RAITHub tests the full money path in test mode, including the cases that are easy to skip.
- Every outcome: successful, declined, 3D Secure, refunded and duplicate payments, in the gateway's test mode, on desktop and real phones.
- Webhooks properly: late, out-of-order and replayed events, with a check that provisioning happens exactly once.
- Automation you keep: test-mode payment tests gated in your CI, so checkout cannot break silently on the next change.
- A ranked report: each issue with steps, evidence and a suggested fix.
Timeline: payment testing is scoped and dated before it starts, as part of a pre-launch audit or a monthly plan. For proof of the method, PropDesk runs 1,024 automated tests over a SaaS with Stripe rent collection. You receive the report, any tests in your repository, and full IP with an NDA. See QA as a Service. The next step is a free 15-minute audit, then a written fixed quote; RAITHub publishes no rates.
Charging real cards soon? Ask for a payments test pass.
Frequently asked questions
How do I test payments without using real money?
Use your gateway's test mode with its test cards. In Stripe, switch to test mode and use published test cards for success, decline and 3D Secure outcomes, then test refunds, duplicate payments and webhooks. No real money moves, and the flow behaves like production.
What test card should I use for a successful payment?
Stripe documents 4242 4242 4242 4242 for a straightforward success in test mode, with separate published cards for declines and for 3D Secure authentication. Always test at least one decline and one 3D Secure card too, not only the success case.
How do I test a declined or failed payment?
Use a published decline test card so the gateway returns a failure. Check that your app shows a clear error, creates no order, and lets the user retry. A silent failure that looks like success is one of the most expensive payment bugs.
How do I test webhooks without going live?
Forward test-mode webhooks to your local app, for example with the Stripe CLI, and trigger specific events. Make the handler idempotent so replaying the same event does not provision twice, and test late and out-of-order delivery, since those are where webhooks break.
Do I need to test refunds?
Yes. A refund must revoke the access or goods it paid for, record the refund and notify the customer. A refund that takes the money back but leaves the customer with access, or vice versa, is a common and costly gap that only a deliberate refund test catches.
Is test mode safe to use on my live app?
Test mode uses separate test API keys and never charges a real card, so it is safe. The risk is mixing test and live keys by mistake, so keep them clearly separated per environment and confirm you are in test mode before running payment tests.
Related posts
Ready to discuss your project?
Book a free 15-minute technical audit with our engineering team.