Skip to main content

Overview

SkillRise uses webhooks from Clerk and Razorpay to sync data and process payments. Webhooks allow external services to notify your server when events occur.

Active Webhooks

Webhook Security

All webhooks use cryptographic signatures to verify authenticity:
  • Clerk: Uses Svix for signature verification
  • Razorpay: Uses HMAC-SHA256 signatures
Never process webhook events without verifying signatures. Attackers can forge requests to your webhook endpoints.

Clerk Webhooks

Setup

1

Configure webhook in Clerk Dashboard

  1. Go to WebhooksAdd Endpoint
  2. URL: https://your-domain.com/clerk
  3. Subscribe to: user.created, user.updated, user.deleted
  4. Copy the Signing Secret
2

Add secret to environment

server/.env

Implementation

server/controllers/webhooks.js

Headers

Clerk sends these headers for verification:

Razorpay Webhooks

Setup

1

Configure webhook in Razorpay Dashboard

  1. Go to SettingsWebhooksAdd New Webhook
  2. URL: https://your-domain.com/razorpay
  3. Events: payment.captured
  4. Click Create Webhook
  5. Copy the Webhook Secret
2

Add secret to environment

server/.env

Implementation

server/controllers/webhooks.js

Critical: Raw Body Requirement

Razorpay’s HMAC signature is computed over the exact raw bytes sent. You must use express.raw() middleware for the webhook route, not express.json().
server/server.js
Why this matters:
  • express.json() parses and re-stringifies the body, changing bytes
  • Signature verification will fail if bytes are modified
  • express.raw() preserves the exact bytes as a Buffer

Headers

Razorpay sends this header:

Signature Verification Deep Dive

Clerk (Svix)

Clerk uses the Svix library for webhook signatures:
What Svix checks:
  1. Signature matches expected HMAC
  2. Timestamp is recent (prevents replay attacks)
  3. Message ID hasn’t been seen before (prevents duplicate processing)

Razorpay (HMAC-SHA256)

Razorpay uses standard HMAC-SHA256:
Why timingSafeEqual?
  • Prevents timing attacks
  • Regular === comparison leaks information through timing
  • timingSafeEqual always takes the same time, regardless of where strings differ

Webhook Resilience

Idempotency

Webhooks may be delivered multiple times. Make handlers idempotent:

Error Handling

Best practices:
  • Return 200 OK to acknowledge successful processing
  • Return 400 for invalid signatures (don’t retry)
  • Return 500 for transient errors (service will retry)
  • Log all errors for debugging

Retry Logic

Both Clerk and Razorpay retry failed webhooks:

Testing Webhooks Locally

Using ngrok

1

Install ngrok

2

Start your server

3

Expose localhost

Output:
4

Update webhook URLs

  • Clerk: https://abc123.ngrok.io/clerk
  • Razorpay: https://abc123.ngrok.io/razorpay
5

Test webhooks

  • Clerk: Create a user in Clerk Dashboard
  • Razorpay: Make a test payment
  • Check server logs and database

Using Webhook Testing Tools

Clerk:
  • Go to Webhooks → Your endpoint → Testing
  • Click Send Example to send test events
Razorpay:
  • Use Webhook.site to inspect payloads
  • Copy payload and replay via curl:

Monitoring Webhooks

Log All Events

Track Failures

Dashboard Monitoring

Clerk:
  • Go to Webhooks → Your endpoint → Logs
  • View recent deliveries, status codes, and retry attempts
Razorpay:
  • Go to SettingsWebhooks → Click your webhook
  • View Recent Deliveries with response codes

Common Issues

Clerk:
  • Verify CLERK_WEBHOOK_SECRET matches Clerk Dashboard
  • Check headers: svix-id, svix-timestamp, svix-signature
  • Ensure you’re stringifying the body: JSON.stringify(req.body)
Razorpay:
  • Verify RAZORPAY_WEBHOOK_SECRET matches Razorpay Dashboard
  • Critical: Use express.raw(), not express.json()
  • Register webhook route before express.json() middleware
  • Check firewall/security groups allow incoming HTTPS
  • Verify URL is correct (no typos, correct protocol)
  • Test with ngrok to rule out network issues
  • Check webhook is subscribed to correct events
  • Make handlers idempotent (use upsert instead of create)
  • Track processed webhook IDs to skip duplicates
  • Use database unique constraints
  • Webhooks may arrive out of order
  • Use timestamps to order events
  • Design handlers to be order-independent

Security Checklist

1

Always verify signatures

Never process webhook events without cryptographic verification.
2

Use HTTPS in production

Webhook providers require HTTPS for security.
3

Validate event structure

Use Zod or similar to validate webhook payloads before processing.
4

Rate limiting

Apply rate limits to webhook endpoints to prevent abuse.
5

Secret rotation

Rotate webhook secrets periodically (every 90 days).
6

Monitor failures

Set up alerts for webhook failures (email, Slack, etc.).

Resources

Clerk Webhooks

Clerk webhook documentation

Razorpay Webhooks

Razorpay webhook guide

Svix

Svix webhook platform (used by Clerk)

ngrok

Expose localhost for testing