SentinelScan-WSS / docs /RAZORPAY_SETUP.md
grateful790's picture
Add Razorpay checkout with platform fee and INR/USD pricing
335a9ba
|
Raw History Blame Contribute Delete
5.59 kB

Razorpay Payments Setup (India + International)

LarShield pricing uses Razorpay for one-time plan purchases:

  • INR checkout for Indian customers (UPI, cards, netbanking, wallets)
  • USD checkout for international customers (international cards)
  • A platform fee is added on top of the plan price at checkout

1. What the customer pays

Line item Calculation
Service price Plan price from subscription_tiers
Platform fee PLATFORM_FEE_PERCENT (default 2%) of the service price
GST PLATFORM_FEE_GST_PERCENT (default 18%) of the platform fee, INR only
Total Service + platform fee + GST

Example (Quick Scan, INR):

Service price        Rs.499.00
Platform fee (2%)    Rs.  9.98
GST (18%)            Rs.  1.80
Total payable        Rs.510.78

USD checkouts add the 2% platform fee only (no Indian GST).

All amounts are recalculated server-side in minor units (paise/cents). The browser never sends an amount.

2. Create the Razorpay account

  1. Sign up at https://dashboard.razorpay.com/signup.
  2. Complete KYC (business PAN, bank account) to move from Test to Live.
  3. Enable international payments: Dashboard -> Account & Settings -> Payment methods -> International payments -> Request activation.
  4. Enable UPI / wallets / netbanking under Payment methods if they are not already on.

3. Get the API keys

Dashboard -> Account & Settings -> API Keys -> Generate Key.

You get:

Key ID       rzp_test_xxxxxxxxxxxx   (or rzp_live_...)
Key Secret   xxxxxxxxxxxxxxxxxxxxxxxx

Store the Key ID and Key Secret only on the server (HF Secrets). The Key ID is sent to the browser as part of the order response; the Secret is never exposed.

4. Configure the webhook

Dashboard -> Account & Settings -> Webhooks -> Add New Webhook.

  • URL: https://<your-space>.hf.space/api/billing/webhook
  • Secret: choose a strong random string, save it as RAZORPAY_WEBHOOK_SECRET
  • Active events:
    • payment.captured
    • order.paid
    • payment.failed

The webhook is the safety net: if the customer closes the tab after paying, the webhook still activates the plan. Fulfilment is idempotent (same payment is never credited twice).

5. Environment variables

Set these in Hugging Face Space -> Settings -> Secrets (or in .env locally):

RAZORPAY_KEY_ID=rzp_test_xxxxxxxxxxxx
RAZORPAY_KEY_SECRET=xxxxxxxxxxxxxxxxxxxxxxxx
RAZORPAY_WEBHOOK_SECRET=whsec_your_random_secret

PLATFORM_FEE_PERCENT=2
PLATFORM_FEE_GST_PERCENT=18
USD_TO_INR_RATE=88

Then Factory Rebuild the Space.

6. How the flow works

Pricing card "Get Started"
        |
        v
POST /api/billing/quote          -> service + fee + GST + total (displayed in modal)
        |
        v
POST /api/billing/create-order   -> Razorpay order created, pending Payment row saved
        |
        v
Razorpay Checkout (UPI / card / netbanking / wallet / international card)
        |
        v
handler -> POST /api/billing/verify-payment
             - HMAC SHA256 signature check
             - amount + currency + order id confirmed with Razorpay
             - organization tier upgraded
             - +3 scan credits added
             - audit log written
        |
        v
Success modal and page reload

Fallback: Razorpay webhook (payment.captured / order.paid)
          performs the same activation if the browser never returns.

7. Test cards

Razorpay test mode:

Method Details
Card (success) 4111 1111 1111 1111, any future expiry, CVV 123
Card (failure) 5104 0600 0000 0008
UPI (success) success@razorpay
UPI (failure) failure@razorpay

Test mode does not move real money.

8. What gets written to the database

payments row:

Column Meaning
amount Total charged (service + fee + GST), minor units
base_amount Service price, minor units
platform_fee Platform fee, minor units
tax_amount GST, minor units
currency INR or USD
razorpay_order_id Razorpay order id
razorpay_payment_id Razorpay payment id (unique - idempotency)
status created -> successful / failed
tier_id quick / advanced / deep

On success the app also:

  • sets organizations.subscription_tier to the purchased tier
  • adds +3 to organization_scan_quotas for that scan type
  • writes an audit_logs entry

9. Admin controls

Super Admin -> Dashboard -> Dynamic Billing Control edits USD and INR prices. The API is PUT /api/billing/tiers/<tier_id> and accepts:

{
  "monthly_price": 499,
  "yearly_price": 4990,
  "monthly_price_inr": 49900,
  "yearly_price_inr": 499000
}

All values are minor units.

10. Troubleshooting

Symptom Cause / fix
Payment gateway is not configured yet RAZORPAY_KEY_ID / RAZORPAY_KEY_SECRET missing in Space Secrets, or Space not rebuilt
Could not start the payment Invalid keys, or the Razorpay account is not activated for that currency
International cards fail International payments not enabled in Razorpay Dashboard
Payment succeeds but plan not upgraded Webhook URL/secret wrong, or verify-payment never reached. Open Razorpay Dashboard -> Payments, copy pay_... id, then contact support; the audit log will show whether fulfilment ran
Invalid payment signature Wrong RAZORPAY_KEY_SECRET for the key id used to create the order
Old INR price shown Update the tier in Super Admin -> Dynamic Billing Control