Skip to main content

Overview

SkillRise uses Stripe for processing course payments (Note: The codebase actually uses Razorpay as the payment provider, not Stripe. This documentation covers the Razorpay implementation).
The README mentions Stripe, but the actual implementation uses Razorpay. This is common in Indian e-learning platforms. The documentation below covers the actual Razorpay implementation.

Features

  • Secure checkout: Razorpay embedded payment UI
  • Multiple payment methods: Cards, UPI, Netbanking, Wallets
  • Webhook verification: HMAC-SHA256 signature validation
  • Order tracking: Purchase status management
  • Fallback enrollment: Webhook ensures enrollment even if frontend fails

Environment Variables

Server Configuration

Add these to your server/.env file:
server/.env
Get your keys from the Razorpay Dashboard. Create an account and generate API keys under SettingsAPI Keys.

Setup Instructions

1

Create Razorpay Account

  1. Go to Razorpay
  2. Sign up for an account
  3. Complete KYC verification (required for live mode)
  4. Start with Test Mode for development
2

Generate API Keys

  1. Go to SettingsAPI Keys
  2. Click Generate Test Keys (or Generate Live Keys for production)
  3. Copy the Key ID and Key Secret
  4. Add them to server/.env:
3

Configure Webhooks

  1. Go to SettingsWebhooks
  2. Click Add New Webhook
  3. Enter your webhook URL:
    • Development: Use ngrokhttps://your-ngrok-url.ngrok.io/razorpay
    • Production: https://your-domain.com/razorpay
  4. Select events:
    • payment.captured
  5. Click Create Webhook
  6. Copy the Webhook Secret and add it to server/.env:
4

Install Dependencies

Payment Flow

The payment flow consists of three steps:
  1. Create Order: Backend creates a Razorpay order
  2. Process Payment: Frontend opens Razorpay checkout modal
  3. Verify Payment: Backend verifies signature and completes enrollment
  4. Webhook Fallback: Razorpay webhook ensures enrollment even if step 3 fails

1. Create Order

When a user initiates a purchase, the backend creates a Razorpay order:
server/services/payments/razorpay.service.js
API Endpoint:

2. Frontend Integration

Open Razorpay checkout modal on the frontend:
client/src/components/Checkout.jsx
Load Razorpay script:
client/index.html

3. Verify Payment Signature

The backend verifies the payment signature using HMAC-SHA256:
server/services/payments/razorpay.service.js
API Endpoint:

4. Webhook Implementation

Webhook acts as a reliable fallback if the frontend verification fails (network drop, browser close, etc.):
server/controllers/webhooks.js
Register webhook route:
server/server.js
Razorpay webhook signature is computed over the exact raw bytes. The webhook route must use express.raw() middleware, not express.json(). Apply express.json() after the webhook route.

Rate Limiting

Protect payment endpoints from abuse:
server/server.js

Testing Payments

Test Cards

Razorpay provides test cards for development: Test card details:
  • CVV: Any 3 digits
  • Expiry: Any future date
  • Name: Any name

Test UPI

Use success@razorpay as the UPI ID in test mode.

Testing Webhooks Locally

1

Install ngrok

2

Start your server

3

Expose localhost

Copy the HTTPS URL (e.g., https://abc123.ngrok.io)
4

Update Razorpay webhook URL

In Razorpay Dashboard → Settings → Webhooks:
5

Test payment

Make a test purchase using a test card. Check:
  • Server logs for webhook event
  • MongoDB for completed purchase
  • User enrollment in course

Production Checklist

1

Switch to Live Mode

  • Complete KYC verification in Razorpay Dashboard
  • Generate Live API Keys
  • Update RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET with live keys
2

Update Webhook URL

Replace ngrok URL with your production domain:
3

Enable HTTPS

Razorpay requires HTTPS for webhooks in production. Use:
  • Let’s Encrypt (free SSL)
  • Cloudflare (free SSL + CDN)
  • Your hosting provider’s SSL
4

Test End-to-End

  • Make a real small payment (₹1)
  • Verify enrollment completes
  • Check webhook logs
  • Test refund flow

Common Issues

  • Ensure you’re using express.raw() middleware for the webhook route
  • Verify RAZORPAY_WEBHOOK_SECRET matches the secret in Razorpay Dashboard
  • Check that the webhook route is registered before express.json()
  • Confirm headers x-razorpay-signature is being sent
  • Check server logs for errors in completePurchase() function
  • Verify MongoDB connection is active
  • Ensure the purchaseId is correctly stored in Razorpay order notes
  • Check that the webhook is subscribed to payment.captured event
  • Razorpay amounts are in paise (smallest currency unit)
  • Convert rupees to paise: amount * 100
  • Example: ₹2999 → 299900 paise
  • Both frontend verification and webhook can trigger enrollment
  • Ensure completePurchase() is idempotent (checks if already completed)
  • Add unique constraints on Purchase model

Security Best Practices

Verify Signatures

Always verify webhook signatures using crypto.timingSafeEqual() to prevent timing attacks.

Use HTTPS

Never send API keys or handle payments over HTTP. Always use HTTPS in production.

Rate Limiting

Apply strict rate limits to payment endpoints to prevent abuse and fraud attempts.

Secure Keys

Never commit API keys to git. Use environment variables and keep secrets secure.

Resources

Razorpay Docs

Official Razorpay documentation

Payment Gateway

Web integration guide

Webhooks

Webhook integration guide

Test Cards

Test card numbers