How to Integrate Payment Services Like Razorpay, Stripe and More in Web Apps

July 4, 202525 min readDevelopment

Hey everyone! I'm Ganesh and in this comprehensive guide, I'll walk you through how to integrate popular payment gateways like Razorpay, Stripe and more into your web applications. We'll focus on how to use them securely and efficiently using frontend frameworks like React/Next.js and backend setups like Node.js, Django, etc.

Table of Contents

  1. 01.Why Secure Payment Integration Matters
  2. 02.Payment Gateway Workflow
  3. 03.Setting Up Razorpay
  4. 04.Setting Up Stripe
  5. 05.React/Next.js Integration
  6. 06.Backend Implementation
  7. 07.Webhook Handling
  8. 08.Security Best Practices
  9. 09.Testing & Error Handling
  10. 10.Production Deployment
  11. 11.Advanced Features
  12. 12.Real-World Case Studies

Integrating payments might sound complicated at first, but once you get the basic structure and security principles right, it becomes an easy and reusable process. So whether you're working on a small e-commerce site or a SaaS platform, this blog will help you understand:

  • Security First:Why we need to integrate payments securely
  • Core Workflow:The fundamental process of any payment gateway
  • Gateway Setup:Setting up Razorpay, Stripe with examples
  • Implementation:Implementing them in React, Node.js, Django
  • Security Measures:Protecting sensitive data and user information
  • Real Experience:Tips based on personal integration experience

1. Why Secure Payment Integration Matters

As developers, it's easy to plug in a payment SDK and call it a day. But when real money is involved, so is real responsibility. Payment security isn't just about protecting data—it's about building trust with your users and ensuring compliance with financial regulations.

Critical Security Requirements

PCI DSS Compliance:Payment details can't be exposed to the frontend
Data Integrity:Prevent tampering with amount/transaction details
Gateway-Hosted Fields:Use Stripe Elements or Razorpay Checkout for PCI compliance
User Trust:Security directly impacts user confidence and conversion rates

Personal Experience

When I built my first app with Razorpay, I made the rookie mistake of putting the secret key on the client side. A friend pointed it out and I quickly learned how critical it is to handle all sensitive operations server-side.

Key Lesson:Only the backend should talk to the payment API using secret keys.

2. Payment Gateway Workflow

Understanding the payment flow is crucial for building secure and reliable payment systems. Here's how the process works across different components:

Payment Integration Flow

01.
User → Frontend:User clicks "Pay Now" button
02.
Frontend → Backend:Request payment session with amount and user details
03.
Backend → Payment Gateway:Create order/session using secret API key
04.
Backend → Frontend:Return order_id/session_id to frontend
05.
Frontend → Payment Gateway:Open payment form with order details
06.
Payment Gateway → Backend:Send webhook with payment confirmation
07.
Backend → Database:Store transaction details for audit trail

Frontend (React/Next.js)

User initiates payment
Fetch payment session from backend
Load gateway SDK with session data

Backend (Node.js/Django)

Generate order/session with secret key
Return session ID to frontend
Verify payment via webhooks

Payment Gateway

Process payment securely
Handle PCI compliance
Send webhook confirmations

Production Considerations

Store transaction details in database for audit trails
Use hosted checkout pages to reduce PCI compliance burden
Implement proper error handling and retry mechanisms

3. Setting Up Razorpay

Razorpay is one of India's leading payment gateways, offering comprehensive payment solutions with excellent developer experience. Let's set it up step by step.

Quick Setup Steps

01.
Dashboard Access:Go to Razorpay Dashboard
02.
Account Creation:Create a test account and get your API Key ID and Secret
03.
Payment Modes:Enable required payment modes (cards, UPI, netbanking, wallets)
04.
Webhook Setup:Add webhook URLs under Settings → Webhooks
05.
Testing:Use sandbox environment for safe testing

Razorpay Features

Instant refunds and partial refunds
Recurring payments and subscriptions
Full-featured sandbox environment
Multiple payment methods support
Comprehensive webhook system
Excellent documentation and SDKs

Razorpay Webhooks

Webhooks help confirm transactions on the backend even if the frontend doesn't send confirmation properly. You can register these key webhook events:

payment.authorized

Payment is authorized but not captured

payment.failed

Payment attempt failed

order.paid

Order payment is successful

Django Example of Webhook Handler:
@csrf_exempt
def razorpay_webhook(request):
    payload = request.body
    signature = request.headers.get('X-Razorpay-Signature')
    try:
        razorpay_client.utility.verify_webhook_signature(
            payload, signature, "YOUR_SECRET")
        data = json.loads(payload)
        # Process payment authorized event
        return JsonResponse({'status': 'ok'})
    except:
        return JsonResponse({'status': 'failed'}, status=400)

React Implementation with Promises & Toasts

import { toast } from 'react-toastify';
const openRazorpay = async () => {
  try {
    const res = await fetch('/api/create-order', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ amount: 500 })
    });
    const data = await res.json();

    const options = {
      key: process.env.REACT_APP_RAZORPAY_KEY_ID,
      amount: data.amount,
      order_id: data.id,
      handler: function (response) {
        toast.success('Payment Successful!');
      },
      prefill: { name: 'Ganesh', email: 'ganesh@example.com' }
    };

    const rzp = new window.Razorpay(options);
    rzp.open();
  } catch (err) {
    toast.error('Something went wrong');
  }
};

4. Setting Up Stripe

Stripe is a global payment platform that offers comprehensive payment solutions with excellent developer experience and extensive documentation. Let's explore its setup and advanced features.

Stripe CLI for Webhook Testing

Stripe CLI is essential for testing webhooks locally during development.

stripe listen --forward-to localhost:5000/webhook

Advanced Backend (Node.js with Express)

app.post('/webhook', express.raw({type: 'application/json'}), (request, response) => {
  const sig = request.headers['stripe-signature'];
  let event;
  try {
    event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret);
  } catch (err) {
    response.status(400).send('Webhook Error: ' + err.message);
    return;
  }
  // Handle event
  if (event.type === 'checkout.session.completed') {
    const session = event.data.object;
    // Mark order paid in DB
  }
  response.status(200).end();
});

Recurring Payments / Subscriptions

const customer = await stripe.customers.create({
  email: 'ganesh@example.com'
});

const subscription = await stripe.subscriptions.create({
  customer: customer.id,
  items: [{ price: 'price_1Nxyz...' }],
});

You can even manage cancellations, upgrades and invoice previews with Stripe's subscription API.

Stripe Features

Apple Pay, Google Pay support
Comprehensive test card suite
Multi-currency support
Payment Intents API
3D Secure authentication
Global payment methods

5. Security Measures

Security is paramount when handling payments. Here are the essential security measures you must implement to protect your application and users.

CSRF Protection

Especially in Django or Express apps. This prevents attackers from initiating payments from unauthorized sessions.

Input Sanitization

Don't trust frontend amount values. Instead, fetch from DB using item ID on the server.

Webhook Signature Verification

All gateways offer secret signing for webhooks. Always verify signatures before trusting the event.

Rate Limiting & Logging

Protect your payment endpoints with rate-limiting libraries like express-rate-limit or Django middleware.

Critical Security Practices

Audit Logging: Log all transaction attempts with metadata (IP, timestamp, user ID, browser info)
HTTPS Everywhere: Always use HTTPS for all payment-related communications
API Key Rotation: Rotate your API keys if you suspect they are compromised
PCI Compliance: Follow PCI DSS guidelines for handling payment data

6. Django Backend Integration

Django provides excellent support for payment integrations with its robust ORM, security features and extensive ecosystem. Here's how to implement Stripe integration with Django.

Stripe Session Creation

import stripe
stripe.api_key = settings.STRIPE_SECRET

def create_checkout_session(request):
    session = stripe.checkout.Session.create(
        payment_method_types=['card'],
        line_items=[{
            'price_data': {
                'currency': 'usd',
                'unit_amount': 1500,
                'product_data': {
                    'name': 'Ganesh Python Course',
                },
            },
            'quantity': 1,
        }],
        mode='payment',
        success_url='http://localhost:3000/success',
        cancel_url='http://localhost:3000/cancel',
    )
    return JsonResponse({'id': session.id})

7. Webhooks and Event Handling

Webhooks are critical in modern payment integrations for reliable transaction processing and real-time updates. They ensure your application stays synchronized with payment gateway events.

Critical Webhook Events

01.
Failed Payments:Capture and handle payment failures
02.
Delayed Payments:Confirm netbanking/UPI transactions
03.
Disputes & Chargebacks:Track and handle payment disputes
04.
Refunds:Process and confirm refunds

Webhook Best Practices

Always respond with 2xx status code to acknowledge receipt
Implement retry logic for failed webhook deliveries
Store event types and responses in your DB for processing/debugging
Verify webhook signatures to ensure authenticity

8. Multi-Currency and International Support

Both Stripe and Razorpay support international cards, but they handle currency conversion differently. Stripe handles currency conversion on the fly, while Razorpay primarily supports INR with some international options.

Stripe Multi-Currency

Automatic currency conversion
135+ currencies supported
Real-time exchange rates
Payment Intents API for dynamic pricing

Razorpay International

INR primary currency
International card support
Limited currency options
Focus on Indian market

Implementation Best Practices

01.
Currency Preference:Ask user currency preference on frontend
02.
Exchange Rate APIs:Use APIs like Fixer.io or ExchangeRate-API
03.
Price Display:Display converted price with original pricing note
04.
Stripe Features:Automatic local currency presentation via Payment Intents API

9. Handling Refunds and Subscriptions

Refunds and subscriptions are essential features for any payment system. Both Stripe and Razorpay provide comprehensive APIs for handling these operations.

Stripe Refund

const refund = await stripe.refunds.create({ 
  payment_intent: 'pi_1...', 
  amount: 500 
});

Razorpay Refund

razorpay.payments.refund(payment_id, { 
  amount: 5000 
});

Refund Best Practices

Always notify users of refunds via email or SMS
Log refund reasons for future analysis and customer support
Support partial refunds for subscription cancellations
Implement refund policies and communicate them clearly

10. Final Deployment Tips

Based on real-world experience, here are the essential deployment tips to ensure your payment integration works smoothly in production.

Production Setup

01.
Enable Production Mode:Switch to production mode in both Stripe/Razorpay dashboards
02.
HTTPS & SSL:Use HTTPS and SSL certificate (Let's Encrypt works fine)
03.
Environment Files:Use environment-specific .env files (.env.development, .env.production)
04.
Database Schema:Store transactions in a proper schema with user references

Additional Deployment Considerations

  • Backup webhook logs and transaction metadata
  • Add UI status indicators: loader, error messages, success page
  • Use Try/Catch blocks in every async payment-related call
  • Set up a cron job to reconcile payments nightly
  • Monitor for suspicious activity (such as repeated failed payments)
  • Consider using fraud detection tools provided by your payment gateway

Conclusion

Payment gateway integration isn't rocket science, but it requires careful implementation. With providers like Razorpay, Stripe and others offering detailed SDKs and docs, you can build a seamless payment experience.

Remember: frontend handles the interface; backend handles the security.

If you're building a startup, e-commerce project, or freelancing — this guide will save you weeks of trial and error. If you're stuck at any point or want help testing a specific integration, feel free to drop a message — I'm Ganesh and I'd love to help you debug or improve your app securely.

Until next time, keep coding and keep building!

Visualizing the Payment Flow

Understanding the payment flow is crucial for successful integration. Here are visual representations of how the frontend, backend and payment gateway interact.

Payment Flow Diagram

Here's a simple diagram showing how the frontend, backend and payment gateway interact:

graph TD;
  A[User] -->|Clicks Pay| B(Frontend)
  B -->|Request order/session| C(Backend)
  C -->|Create order/session with secret key| D(Payment Gateway)
  D -->|Order/session ID| C
  C -->|Order/session ID| B
  B -->|Open SDK/Popup| D
  D -->|Payment Result| C
  C -->|Verify & Update DB| E[Database]
  D -->|Webhook (optional)| C

Webhook Event Flow

Sequence diagram showing webhook processing:

sequenceDiagram
  participant Gateway
  participant YourServer
  participant DB
  Gateway->>YourServer: POST /webhook (event)
  YourServer->>YourServer: Verify signature
  alt Valid event
    YourServer->>DB: Update payment status
    YourServer-->>Gateway: 200 OK
  else Invalid event
    YourServer-->>Gateway: 400 Error
  end

Choosing the Right Payment Gateway

Selecting the right payment gateway is crucial for your business success. Different gateways excel in different regions and use cases.

Global Gateways

Stripe: Global coverage, excellent docs
PayPal: International one-off payments
Square: US/CA/AU/JP/UK focused

Regional Gateways

Razorpay: India market leader
PayU: Emerging markets
MercadoPago: Latin America

Selection Criteria

Supported countries and currencies
Fees and settlement times
Features: subscriptions, refunds, webhooks
Ease of integration and documentation

Recommendations

Global SaaS/E-commerce: Stripe is the best choice
India-focused: Razorpay is popular and reliable
International one-off: PayPal works well

Case Study: A Real Integration Challenge

Real-world experiences provide valuable lessons. Here's a case study from an actual integration project that highlights the importance of security practices.

The Challenge

When integrating Stripe for a SaaS client, we once missed verifying webhook signatures. A malicious actor sent fake payment events, causing our system to mark unpaid orders as paid.

Lesson: Never trust incoming webhooks blindly!

The Solution

Always verify webhook signatures
Log all webhook events for audit trails
Implement proper error handling for invalid events
Set up monitoring for suspicious activity

Common Pitfalls

Learning from others' mistakes can save you time and prevent security issues. Here are the most common pitfalls developers encounter when integrating payment gateways.

Security Pitfalls

Exposing secret keys in frontend code
Not verifying webhook signatures
Trusting amount from the frontend

Implementation Pitfalls

Not handling failed/cancelled payments
Forgetting to enable production mode
Not using HTTPS in production

Critical Warning

Never log or expose full card numbers or CVVs anywhere in your system.

Production Checklist

Before going live with your payment integration, ensure you've completed this comprehensive checklist to avoid common issues and ensure a smooth launch.

Security Setup

Enable production mode in payment dashboard
Use HTTPS and valid SSL certificate
Store API keys in .env files
Verify all webhook signatures

Testing & Monitoring

Log all payment attempts and errors
Test with real cards before launch
Set up email/SMS notifications
Back up transaction and webhook logs

Next.js API Routes Integration

Next.js provides excellent support for payment integrations through its API routes. You can securely handle payment logic in /pages/api/ or /app/api/ routes.

Stripe Payment Intent API Route

Example for creating a Stripe Payment Intent:

// pages/api/create-payment-intent.js
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

export default async function handler(req, res) {
  if (req.method !== 'POST') return res.status(405).end();
  try {
    const { amount, currency } = req.body;
    const paymentIntent = await stripe.paymentIntents.create({
      amount,
      currency,
    });
    res.status(200).json({ clientSecret: paymentIntent.client_secret });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
}

On the frontend, fetch clientSecret from this endpoint and use Stripe.js to complete the payment.

React Payment Form Example

Here's a complete React component example for integrating Stripe payments in your frontend application.

Complete React Payment Form

import { useState } from 'react';
import { loadStripe } from '@stripe/stripe-js';
import { Elements, CardElement, useStripe, useElements } from '@stripe/react-stripe-js';

const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_KEY);

function CheckoutForm() {
  const stripe = useStripe();
  const elements = useElements();
  const [status, setStatus] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();
    setStatus('Processing...');
    const res = await fetch('/api/create-payment-intent', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ amount: 500, currency: 'usd' })
    });
    const { clientSecret } = await res.json();
    const result = await stripe.confirmCardPayment(clientSecret, {
      payment_method: { card: elements.getElement(CardElement) }
    });
    if (result.error) setStatus('Payment failed: ' + result.error.message);
    else if (result.paymentIntent.status === 'succeeded') setStatus('Payment successful!');
  };

  return (
    <form onSubmit={handleSubmit}>
      <CardElement />
      <button type="submit">Pay</button>
      <div>{status}</div>
    </form>
  );
}

export default function PaymentPage() {
  return (
    <Elements stripe={stripePromise}>
      <CheckoutForm />
    </Elements>
  );
}

Webhook Handler in Next.js

Webhooks are essential for reliable payment processing. Here's how to implement a secure webhook handler in Next.js API routes.

Next.js Webhook Handler

// pages/api/webhook.js
import { buffer } from 'micro';
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

export const config = { api: { bodyParser: false } };

export default async function handler(req, res) {
  if (req.method !== 'POST') return res.status(405).end();
  const sig = req.headers['stripe-signature'];
  const buf = await buffer(req);
  let event;
  try {
    event = stripe.webhooks.constructEvent(buf, sig, process.env.STRIPE_WEBHOOK_SECRET);
  } catch (err) {
    return res.status(400).send('Webhook Error: ' + err.message);
  }
  // Handle event
  if (event.type === 'payment_intent.succeeded') {
    // Update DB, send email, etc.
  }
  res.status(200).json({ received: true });
}

Managing Environment Variables

Proper secret management is crucial for security. Always store API keys in environment variables and never commit them to version control.

Environment Variables Setup

Store your API keys in .env.local (never commit this file):

STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_STRIPE_KEY=pk_test_...
RAZORPAY_KEY_ID=rzp_test_...
RAZORPAY_KEY_SECRET=your_secret_here
WEBHOOK_SECRET=whsec_your_webhook_secret

Access them in your code with process.env.STRIPE_SECRET_KEY (backend) and process.env.NEXT_PUBLIC_STRIPE_KEY (frontend).

Security Best Practices

Never commit .env.local to version control
Use different keys for development and production
Rotate keys regularly and monitor for unauthorized access
Use secret management services in production (AWS Secrets Manager, etc.)

Error Handling & Testing

Robust error handling and comprehensive testing are essential for a reliable payment system. Here's how to implement proper error handling and testing strategies.

Error Handling

Use try/catch in all async payment code
Show clear error messages to users
Log all errors and failed transactions
Implement retry mechanisms for transient failures

Testing Strategies

Test with sandbox/test cards
Use Stripe CLI for webhook testing
Test both success and failure scenarios
Implement automated payment flow tests

Pro Tips

Always test your payment flow with both successful and failed transactions
Use Razorpay Webhook Simulator for local testing
Monitor payment success rates and error patterns
Set up alerts for payment failures and webhook errors

Accessibility & PCI Compliance

Ensuring your payment forms are accessible and PCI compliant is not just good practice—it's essential for legal compliance and user experience.

Accessibility

Use ARIA labels and keyboard navigation
Show clear focus states and error messages
Ensure high color contrast ratios
Support screen readers and assistive technologies

PCI Compliance

Never handle raw card data yourself
Use gateway-hosted fields or popups
Stripe Elements and Razorpay Checkout are PCI compliant
Both gateways are PCI DSS Level 1 compliant

Important Notes

Using hosted solutions keeps your app out of PCI scope
This greatly reduces your compliance burden

Real-World Scenarios & Pro Tips

Beyond basic integration, there are several advanced scenarios and best practices that will make your payment system production-ready and scalable.

Advanced Features

Handle partial refunds (not just full refunds)
Support disputes/chargebacks via webhooks
Implement subscription management
Handle recurring payments and billing cycles

Operational Excellence

Retry failed webhooks and log all events
Send email/SMS notifications for status changes
Reconcile payments nightly with cron jobs
Monitor payment success rates and trends

Frequently Asked Questions

Here are answers to the most common questions developers have when implementing payment integrations.

Can I use multiple gateways in one app?

Yes! Route users to the gateway that fits their region or preference. Many apps use Stripe for global users and Razorpay for Indian users.

How do I handle failed payments?

Listen for failure events, show clear messages to users and allow them to retry. Always log failed transactions for analysis.

Is it safe to store card data?

No. Always use gateway-hosted fields or popups to avoid PCI scope. Never store raw card data in your database.

How do I test webhooks locally?

Use Stripe CLI (stripe listen) or Razorpay's webhook simulator. These tools forward webhook events to your local development environment.

Further Learning & Resources

Continue your learning journey with these comprehensive resources and official documentation.

Advanced Security Practices


Modern payment gateways use tokenization and vaulting to ensure that sensitive card data never touches your servers. When a user enters their card details, the gateway returns a token that represents the card, which you can safely store and use for future payments or subscriptions. Always use Content Security Policy (CSP) headers to prevent XSS attacks on your payment pages and set HTTP headers like Strict-Transport-Security and X-Content-Type-Options for extra protection. Rotate your webhook secrets and API keys regularly and store them in a secure secrets manager (not in your codebase or plain .env files).

Testing & QA for Payment Flows


Automate your payment flow tests using tools like Cypress or Playwright. Simulate real user journeys: successful payments, failed payments, 3D Secure authentication and cancellations. Both Stripe and Razorpay provide a wide range of test cards for different scenarios. Use their webhook simulators or Stripe CLI to test webhook handling locally and in CI. Always test edge cases, such as network failures, duplicate submissions and slow responses.

Handling Edge Cases


Sometimes a payment succeeds but the webhook fails to reach your server. Always reconcile your database with the payment gateway dashboard daily. Use idempotency keys to prevent double payments if a user retries a transaction. Handle timeouts and user cancellations gracefully, showing clear status messages and allowing users to retry. If a webhook fails, implement a retry mechanism and alert your team for manual intervention if needed.

Scaling Payments for Growth


As your business grows, payment volume increases. Use idempotency keys for all payment and refund requests to prevent duplicates. For SaaS platforms, consider multi-tenant strategies: separate payment accounts per tenant, or use connected accounts (Stripe Connect). For subscriptions, handle proration, upgrades, downgrades and dunning (failed payment recovery) automatically. Queue payment events and process them asynchronously if you expect high traffic.

UX/UI Best Practices


Design a frictionless checkout: use progress indicators, clear error states and mobile-friendly layouts. Always show a loading spinner during payment processing. For accessibility, ensure your forms are keyboard-navigable, have proper ARIA labels and maintain high color contrast. Localize your payment flows by supporting multiple languages, currencies and address formats. Show users a clear summary before they confirm payment and provide instant feedback on success or failure.

Legal & Compliance


Stay up to date with regulations like GDPR (data privacy), SCA (Strong Customer Authentication in Europe) and local laws. Always obtain user consent for storing payment methods. Handle chargebacks and disputes by keeping detailed records, responding promptly and communicating clearly with users. Generate and store invoices/receipts for every transaction and make them easily accessible to users for tax and compliance purposes.

Integrating with Accounting/ERP


Sync your payment data with accounting tools like QuickBooks or Xero using their APIs or third-party connectors. Automate invoice generation and reconciliation to reduce manual work and errors. For larger businesses, integrate with ERP systems to keep your financial records, inventory and payments in sync.

Emerging Payment Methods


Stay ahead by supporting new payment methods: UPI (India), Buy Now Pay Later (BNPL) services and even crypto payments. Evaluate new methods based on your audience and region. Most gateways let you enable new methods with minimal code changes. Monitor adoption and feedback to decide which methods to keep or expand.

Real-World Case Studies


Case 1: A SaaS startup once faced a major issue when a webhook endpoint went down during a product launch. Payments were processed, but user accounts weren't upgraded. The team quickly built a reconciliation script to match gateway records with their database and issued manual upgrades and apologies. Lesson: Always monitor webhook health and have a reconciliation plan.

Case 2: An e-commerce site saw a spike in double payments during a flash sale. Investigation revealed users were clicking "Pay" multiple times due to slow responses. Adding idempotency keys and a loading spinner solved the issue. Lesson: UX and backend safeguards go hand in hand.

Developer Resources