Overview
SkillRise integrates Razorpay for payment processing with a robust webhook-based enrollment system. The architecture ensures reliable course enrollment even when frontend verification fails.Payment Architecture
The webhook serves as a reliable fallback mechanism, ensuring enrollment completes even if the frontend verification fails due to network issues or browser closure.
Purchase Model
Purchase Schema
server/models/Purchase.js
Purchase Status Flow
1
created
Initial state when purchase record is created before Razorpay order.
2
pending
Razorpay order created, waiting for payment completion.
3
completed
Payment verified, user enrolled in course.
4
failed
Payment failed or was cancelled by user.
5
refunded
Payment was refunded to the user.
Razorpay Service
Create Order
Generate a Razorpay order with purchase metadata:server/services/payments/razorpay.service.js
The
purchaseId is stored in Razorpay’s notes field, allowing the webhook to identify which internal purchase to complete.Verify Payment Signature
Verify payment authenticity using HMAC-SHA256:server/services/payments/razorpay.service.js
Purchase Completion Service
Idempotent Enrollment
The core enrollment logic is idempotent and centralized:server/services/payments/order.service.js
The
$addToSet operator ensures that calling this function multiple times won’t create duplicate enrollments.Webhook Handler
Razorpay Webhook Verification
Securely handle Razorpay payment capture webhooks:server/controllers/webhooks.js
1
Signature Verification
Verify the webhook signature using the raw body before parsing JSON.
2
Event Filtering
Only process
payment.captured events to avoid handling incomplete payments.3
Purchase ID Extraction
Extract the internal purchase ID from Razorpay’s notes field.
4
Complete Enrollment
Call the idempotent
completePurchase function to enroll the user.Express Middleware Configuration
The webhook endpoint requires special body parsing:server/server.js
The raw body parser must be applied before the JSON parser to preserve the original request body for signature verification.
Environment Variables
.env
Payment Flow States
Checkout Initiated
Checkout Initiated
Purchase record created with
status: 'created'. Razorpay order generated and checkout modal opened.Payment Processing
Payment Processing
User completes payment on Razorpay. Status updated to
pending while awaiting capture.Frontend Verification
Frontend Verification
Frontend receives payment success and calls verify endpoint. If successful, enrollment completes immediately.
Webhook Backup
Webhook Backup
Razorpay sends
payment.captured webhook. If frontend verification failed, webhook ensures enrollment completes.Enrollment Complete
Enrollment Complete
User added to course’s
enrolledStudents array and course added to user’s enrolledCourses array.Security Features
HMAC Signature Verification
All webhook requests are verified using HMAC-SHA256 signatures.
Timing-Safe Comparison
Signature comparison uses timing-safe functions to prevent timing attacks.
Idempotent Operations
Purchase completion can be called multiple times safely without duplicate enrollments.
Raw Body Verification
Webhook signatures are verified on raw body to prevent tampering.
Error Handling
- Payment Failed
- Webhook Replay
- Invalid Signature
- Missing Purchase ID
If payment fails, the purchase status remains
created or changes to failed. User is not enrolled.Best Practices
Next Steps
Course Management
Understand the course structure that users purchase
Analytics
Track purchase conversions and revenue
Authentication
Secure user accounts and payment authorization