Razorpay Integration

Complete Razorpay payment integration — fee collection, plan subscriptions, webhook handling

Overview

OptiCRM uses Razorpay for two payment flows:

  1. Fee Collection - Schools collect fees from parents via online payment
  2. Plan Subscriptions - Schools pay for their OptiCRM subscription

Fee Collection Architecture

Hybrid Payment Model

Each institution chooses one of three modes:

ModeHow It WorksMoney Flow
OWN_RAZORPAYInstitution enters own API keysDirect to school's bank
PLATFORM_LINKEDOnboards as Razorpay Route sub-merchantAuto-split with commission
GATEWAY_NONEOnline payments disabledCash/cheque only

Payment Flow

  1. Parent opens /portal/fees and clicks "Pay Now"
  2. Frontend calls POST /api/portal/payments with action: create-order
  3. Server resolves institution's gateway config
  4. Creates Razorpay order via API
  5. Returns orderId and key to frontend
  6. Frontend opens Razorpay Checkout modal
  7. Parent completes payment (card/UPI/netbanking)
  8. Frontend calls POST /api/portal/payments with action: verify
  9. Server verifies HMAC-SHA256 signature
  10. On success: Payment marked SUCCESS, Invoice updated, Receipt generated, GL journal entries created

API: Create Order

POST /api/portal/payments
Content-Type: application/json
 
{
  "action": "create-order",
  "invoiceId": "clx..."
}

Response:

{
  "data": {
    "orderId": "order_xxx",
    "amount": 2500000,
    "key": "rzp_live_xxx"
  }
}

API: Verify Payment

POST /api/portal/payments
Content-Type: application/json
 
{
  "action": "verify",
  "orderId": "order_xxx",
  "paymentId": "pay_xxx",
  "signature": "hmac_signature_hex"
}

Gateway Configuration

Configure own Razorpay:

PATCH /api/admin/payment-gateway
{ "action": "configure-own", "keyId": "rzp_live_xxx", "keySecret": "secret", "webhookSecret": "secret" }

Create linked account:

PATCH /api/admin/payment-gateway
{ "action": "request-linked", "name": "...", "email": "...", "pan": "...", "bankAccount": {...} }

Plan Subscriptions

Plans

PlanMonthlyAnnualKey Features
FreeINR 0INR 050 students, basic modules
StarterINR 999INR 9,990500 students, academics, HR
ProfessionalINR 2,999INR 29,990Unlimited, all modules, AI
EnterpriseINR 9,999INR 99,990Everything, API, white-label

API: Get Plans

GET /api/plan/subscribe

Returns current plan, trial status, and all available plans with pricing.

API: Upgrade

POST /api/plan/subscribe
{ "planName": "PROFESSIONAL", "billingCycle": "monthly" }

If Razorpay configured: returns payment link URL. If not: activates directly.

API: Usage

GET /api/plan/usage

Returns current usage vs plan limits for students, staff, objects, reports, emails, SMS.

Webhook

POST /api/webhooks/razorpay
X-Razorpay-Signature: hmac_hex
 
{ "event": "payment.captured", "payload": {...} }

Handles:

  • payment.captured - Mark payment SUCCESS, update invoice
  • payment.failed - Mark payment FAILED
  • refund.processed - Mark payment REFUNDED

Signature verified against both platform and institution webhook secrets.

Security

  • API keys encrypted with AES-256-GCM in database
  • Webhook signatures verified with HMAC-SHA256
  • Payment verification idempotent via Redis (24h TTL)
  • Each institution's keys are isolated
  • Platform keys used only for PLATFORM_LINKED mode

Test Cards

CardResult
4111 1111 1111 1111Success
5267 3181 8797 5449Success (Mastercard)
4000 0000 0000 0002Decline

UPI: success@razorpay | OTP: 1234

Environment Variables

RAZORPAY_KEY_ID=rzp_test_xxx        # Platform Razorpay key
RAZORPAY_KEY_SECRET=xxx             # Platform secret
RAZORPAY_WEBHOOK_SECRET=xxx         # Webhook signature secret

Institution-specific keys are stored encrypted in the Institution model.