Razorpay Webhook
Webhooks
Razorpay Webhook
Handle payment events from Razorpay payment gateway
POST
Razorpay Webhook
Overview
This webhook endpoint receives payment events from Razorpay. It serves as a reliable fallback mechanism to complete course enrollments even if the frontend verification fails due to network issues or browser closures.This endpoint ensures that successful payments always result in course enrollment, regardless of client-side failures.
Authentication
Webhook Signature Verification
Razorpay uses HMAC SHA-256 signatures to verify webhook authenticity. The signature is computed over the raw request body bytes. Required Header:x-razorpay-signature: HMAC SHA-256 signature of the raw request body
Security Implementation Details
- Raw Body Requirement: The endpoint uses
express.raw()middleware to preserve the exact bytes sent by Razorpay - Timing-Safe Comparison: Uses
crypto.timingSafeEqual()to prevent timing attacks - Secret Storage: Webhook secret is stored in
RAZORPAY_WEBHOOK_SECRETenvironment variable
Event Types
payment.captured
Fired when a payment is successfully captured by Razorpay. Action: Completes the purchase and enrolls the user in the course. Payload Example:event: Event type identifierpayload.payment.entity.id: Razorpay payment IDpayload.payment.entity.notes.purchaseId: Internal SkillRise purchase ID
The
purchaseId is stored in Razorpay’s notes field when creating the order. This links Razorpay payments to internal purchase records.Request Format
Headers
| Header | Type | Required | Description |
|---|---|---|---|
x-razorpay-signature | string | Yes | HMAC SHA-256 signature of raw body |
Content-Type | string | Yes | Must be application/json |
Body
Response Format
Success Response
Status Code:200 OK
Error Response
Status Code:400 Bad Request
Processing Logic
Payment Completion Flow
- Signature Verification: Verify the webhook is from Razorpay
- Parse Event: Convert raw body to JSON after verification
- Check Event Type: Process only
payment.capturedevents - Extract IDs: Get
purchaseIdfrom notes andpaymentIdfrom entity - Complete Purchase: Call
completePurchase(purchaseId, paymentId)service - Acknowledge: Return success response
Idempotency
ThecompletePurchase service handles duplicate webhook deliveries:
- If the purchase is already completed, the operation is idempotent
- Razorpay may retry webhook delivery, so duplicate events are handled gracefully
Event Filtering
- Only
payment.capturedevents trigger purchase completion - Other event types are acknowledged but not processed
- Missing
purchaseIdorpaymentIdis silently ignored
Error Handling
Signature Validation Errors
Causes:- Missing
x-razorpay-signatureheader - Signature mismatch (tampered payload or wrong secret)
400 Bad Request with error message
Razorpay Behavior: Will retry webhook delivery with exponential backoff
Missing Data
Causes:purchaseIdnot present in payment notespaymentIdmissing from payment entity
200 OK with {"received": true}
Behavior: Event is acknowledged to prevent retries, but no action is taken
Database Errors
IfcompletePurchase() throws an error:
- Error propagates and causes webhook to fail
- Razorpay will retry the webhook
- Purchase completion will be attempted again
Security Best Practices
- Raw Body Preservation: Never parse the request body before signature verification
- Timing-Safe Comparison: Use
crypto.timingSafeEqual()to prevent timing attacks - Secret Rotation: Periodically rotate
RAZORPAY_WEBHOOK_SECRET - HTTPS Only: Configure Razorpay to only send webhooks to HTTPS endpoints
- IP Whitelisting: Consider restricting access to Razorpay’s webhook IP addresses
Middleware Requirements
This endpoint requires special Express middleware configuration:Configuration
Razorpay Dashboard Setup
- Log into your Razorpay Dashboard
- Navigate to Settings > Webhooks
- Click Create New Webhook
- Enter your endpoint URL:
https://yourdomain.com/razorpay - Select events to subscribe to:
payment.captured
- Set a strong secret and copy it
- Save the webhook configuration
Environment Variables
Keep this secret secure and never commit it to version control. Use environment-specific secrets for development, staging, and production.
Fallback Architecture
This webhook serves as a critical fallback in the payment flow:- Reliability: Enrollment completes even if user closes browser
- Network Resilience: Works despite frontend connectivity issues
- Idempotency: Handles both frontend and webhook completion safely
Implementation Reference
Location:server/controllers/webhooks.js:64
Related Services
- completePurchase:
server/services/payments/order.service.js- Handles purchase completion and enrollment - Payment Verification: See frontend payment verification flow for the primary completion path