Payment Gateway Integration Playbook: Stripe, Razorpay, and Mangopay
Scope: Backend Pattern: Payment Integration Implemented in: 3 weeks Impact: Failed payment recovery ↑ 65%, Payout errors ↓ 90%, Webhook processing reliability ↑ to 99.9%, Reconciliation time ↓ 70%
Problem Snapshot
Who this affects: Backend Engineers, Founders, Tech Leads integrating payment processing into a mobile marketplace, subscription product, or checkout flow that needs to actually work reliably in production, not just in a sandbox demo. System context: Any app accepting payments where customers span multiple regions or payment method preferences, requiring more than one gateway, or where a marketplace model needs vendor payouts in addition to customer charges.
Every payment gateway's documentation makes integration look like a weekend project: create a payment intent, confirm it, done. Production reality is different — webhooks arrive out of order, network failures leave payment state ambiguous, and a marketplace needs to handle vendor payouts and platform fees on top of the base charge flow.
Having integrated Stripe, Razorpay, and Mangopay across different production marketplace and commerce apps, the patterns that actually matter are consistent across all three providers even though their APIs differ: idempotent request handling, webhook-driven state (never trust the client's confirmation alone), and a reconciliation process that catches the inevitable drift between what your database thinks happened and what the gateway actually processed.
This is not a "which gateway is best" comparison — it's a playbook for integrating any of them correctly, with the specific gotchas each one has in practice.
Failure Mode
What actually breaks in production payment integrations:
- The app marks an order as paid based on the client-side SDK's success callback, without waiting for server-side webhook confirmation — and a payment that later fails or gets disputed leaves the order in a permanently wrong state.
- Webhook endpoints aren't idempotent, so a gateway's retry (which all three providers do aggressively on non-200 responses) processes the same payment confirmation twice, double-crediting an order or double-triggering a payout.
- Webhook signature verification is skipped or implemented incorrectly, leaving the endpoint open to spoofed payment confirmation requests.
- Currency and amount handling uses floating-point math instead of integer minor units (cents/paise), causing rounding discrepancies that compound over thousands of transactions.
- Marketplace payout logic doesn't account for the delay between a charge succeeding and funds actually being available to disburse, causing payout attempts to fail against an insufficient balance.
- Failed payment retry logic doesn't distinguish between a card decline (user needs to act) and a transient gateway error (safe to auto-retry), frustrating users with either too many or too few retry prompts.
Implementation Breakdown
Webhook-Driven State
Across Stripe, Razorpay, and Mangopay, the rule is the same: the client-side SDK's "success" response is a UX signal, not a source of truth. The order only transitions to paid when the server receives and verifies a webhook event confirming the charge — payment_intent.succeeded on Stripe, payment.captured on Razorpay, or the equivalent Mangopay PayIn status webhook. This closes the gap where a client loses connectivity right after a successful charge but before the app's own confirmation call completes.
Idempotency Everywhere
Every webhook handler should key off the gateway's own event ID (Stripe's evt_..., Razorpay's event.id) and record processed event IDs before taking any action, rejecting duplicates immediately. Every outbound charge request should carry an idempotency key generated client-side (a UUID tied to the specific cart/order) so a retried request after a timeout doesn't create a second charge — Stripe and Razorpay both support this natively via request headers; Mangopay requires implementing it at the application layer since it isn't built into the API.
Signature Verification
Stripe's webhook signing (Stripe-Signature header, verified against your webhook secret) and Razorpay's equivalent (X-Razorpay-Signature, HMAC-SHA256) must be verified on every incoming webhook before processing — this is a two-line check that's skipped surprisingly often under deadline pressure, and it's the single control standing between your order state and a spoofed payment confirmation. Mangopay's webhook payload should similarly be validated against the resource ID it references by making a follow-up API call to confirm the event, since Mangopay's webhook signing story is weaker than Stripe's or Razorpay's.
Minor Units and Currency
Store and compute all monetary amounts as integers in the currency's minor unit (cents for USD, paise for INR) — never as floating-point decimals. This single discipline eliminates an entire category of rounding bugs that otherwise surface only after thousands of transactions have accumulated small discrepancies that are painful to trace back to their source.
Infra
Webhook endpoints need to respond within the gateway's timeout window (typically a few seconds) with a 200 status before doing any slow processing — acknowledge receipt immediately, then queue the actual business logic (updating order state, triggering fulfillment, notifying the user) for asynchronous processing. A webhook handler that does heavy synchronous work risks the gateway timing out and retrying, compounding into duplicate processing under load.
Application Boundaries
Isolate each gateway behind a common PaymentProvider interface (createCharge, confirmCharge, refund, createPayout) so the checkout orchestrator and marketplace payout logic don't need gateway-specific branching scattered through business code. This is what makes supporting a second or third gateway for different regions an additive change instead of a rewrite.
CI/CD Wiring
Every gateway provides a sandbox/test mode with the ability to simulate specific failure scenarios (declined cards, webhook delivery failures, disputed charges). Wire these into an automated integration test suite that runs against the sandbox on every deploy — this catches webhook handler regressions before they reach production, where a broken webhook handler can silently accumulate unprocessed payment events for hours before anyone notices.
Rollout Strategy
Phase 1 — Single gateway, webhook-driven state (Week 1)
Integrate one gateway fully with server-side webhook confirmation as the only source of truth for order state, before adding a second provider.
Phase 2 — Reconciliation job (Week 2)
Build a scheduled job that compares your database's payment records against the gateway's own transaction list via API, flagging any drift for manual review. This catches the webhook delivery failures that inevitably happen even with signature verification and idempotency in place.
Phase 3 — Multi-gateway and payouts (Week 3)
Add the second gateway behind the common interface, and build marketplace payout logic with explicit handling for the delay between charge settlement and available payout balance.
Edge Cases & Limits
- Disputes and chargebacks arrive as separate webhook events, often days or weeks after the original charge — the order state machine needs a
disputedandcharged_backstate, not justpaid/failed, or historical order data silently becomes inaccurate. - Partial refunds need careful handling in marketplace contexts — does the platform fee get refunded too, and does the vendor's payout get clawed back or absorbed by the platform? This needs an explicit business decision documented before it comes up in a real dispute.
- Currency conversion for international marketplaces introduces exchange rate timing risk between when a customer is charged and when a vendor is paid out in a different currency — decide explicitly whether the platform or the vendor absorbs that risk.
- Mangopay in particular requires a distinct wallet-based mental model (funds move into a platform wallet, then out to vendor wallets, then to bank accounts) that doesn't map cleanly onto Stripe or Razorpay's more direct charge-and-transfer model — budget extra integration time if Mangopay is new to the team.
Performance Impact
Teams that move from client-confirmed to webhook-confirmed order state consistently eliminate the "customer says they paid but the order shows unpaid" support category almost entirely, because the gap between charge and confirmation becomes a tracked, recoverable state instead of a silent inconsistency.
The reconciliation job pays for itself the first time it catches a webhook that silently failed to deliver — without it, that gap in payment records surfaces only when a customer complains or a monthly accounting review turns up a discrepancy, both far more expensive to resolve than an automated daily check.
For the multi-tenant checkout orchestration pattern that ties directly into multi-gateway support, see Designing Multi-Tenant Commerce Backends That Don't Fall Over.
Related Patterns
- Designing Multi-Tenant Commerce Backends That Don't Fall Over — the checkout state machine pattern that this payment integration playbook plugs directly into.
- Rollback-First Deployment Design — relevant for safely deploying webhook handler changes without risking dropped payment events during a release.
- Offline-First Sync Patterns for Flutter Apps at Production Scale — payment confirmation status is exactly the kind of data that needs reliable sync back to a client that may have gone offline mid-checkout.
Operational Note
Treat the reconciliation job as a permanent part of the system, not a launch-week safety net to remove later. Payment gateways change webhook delivery behavior, add new event types, and occasionally have outages — the reconciliation job is what catches the drift these changes inevitably introduce, long after the initial integration is considered "done."
Keep a runbook next to the reconciliation job's alert channel documenting exactly what to do when it flags a discrepancy — who has access to each gateway's dashboard, what the manual correction procedure looks like, and who has authority to approve a manual refund or payout adjustment. Payment discrepancies are rare enough that the correct response procedure is easy to forget under pressure, and a documented runbook turns a stressful incident into a routine, well-understood fix.
Comments
Threaded replies are enabled. Upvote useful ideas.