← StafFixHR home

Payment gateways

How StafFixHR.com charges customers — Razorpay for India, Stripe for everywhere else.

The two-gateway split

India is a card-mandate / UPI-dominant market; the rest of the world is card-recurring / ACH / SEPA. No single gateway handles both well, so we run two side by side, region-routed at checkout:

  • Razorpay — Indian customers. UPI, cards, netbanking, wallets. Settles INR to the Indian bank account. Best Indian DX.
  • Stripe — non-Indian customers. Cards in 135+ currencies, ACH (US), SEPA (EU), Apple Pay, Google Pay. Working recurring across countries. Settles to a Wise USD/EUR account or directly to bank in supported geographies.

The portal's /signup page detects region from Cloudflare's cf_country cookie and shows the right widget. Customer doesn't pick a gateway.

Live mode setup — Razorpay (India)

See the razorpay.com dashboard. Three env vars on Railway:

  • RAZORPAY_KEY_ID
  • RAZORPAY_KEY_SECRET
  • RAZORPAY_WEBHOOK_SECRET

Webhook URL to set on Razorpay's side: https://staffixhr.com/api/public/subscriptions/webhook. Subscribe to payment.captured, payment.failed, subscription.*.

Live mode setup — Stripe (non-India)

  1. Create an account at dashboard.stripe.com/register. Choose India as the business country (Stripe India recently launched and is a valid choice — gives you ₹INR settlement to an Indian bank).
  2. Complete activation — same KYC docs as Razorpay (PAN, GSTIN, bank, director Aadhaar). Stripe India processes activation in 1-3 working days.
  3. Dashboard → Developers → API keys:
    • Copy the Publishable key (starts pk_test_… in test, pk_live_… in live).
    • Copy the Secret key (sk_test_… / sk_live_…) — visible once, regenerate if lost.
  4. Dashboard → Developers → Webhooks → Add endpoint:
    • URL: https://staffixhr.com/api/webhooks/stripe
    • Events: checkout.session.completed, invoice.paid, customer.subscription.updated, customer.subscription.deleted, charge.refunded
    • After saving, click the endpoint and reveal the Signing secret (whsec_…) — that's the third env var.
  5. On Railway, add:
    STRIPE_PUBLISHABLE_KEY=pk_live_xxx
    STRIPE_SECRET_KEY=sk_live_xxx
    STRIPE_WEBHOOK_SECRET=whsec_xxx
  6. Redeploy. The /api/public/subscriptions/gateway-status endpoint will now report stripe.enabled: true.
  7. Test card: 4242 4242 4242 4242, any future date, any CVC. Live amount is real money — start with a $1 test on yourself.

Mock mode (default)

Without the env vars set, both gateways run in MOCK mode: payments are simulated and the portal flows still complete (a tenant is created, subscription marked active), but no real money moves. Useful for local development, demos, and the first hour of testing before you flip to test/live credentials.

Cost comparison

MethodRazorpay (India)Stripe (India)Stripe (US/EU)
Domestic cards2%2% + ₹32.9% + ₹2
UPI0%
International cards3% + ₹33.4% + ₹22.9-3.9% + ₹2
ACH (US bank)0.8% (capped at $5)
SEPA (EU bank)0.8%

Verify rates on each provider's pricing page — they change quarterly.

Refunds — what costs you

On both gateways, the gateway fee from the original transaction is NOT returned when you issue a refund. Plus the same fee is taken on the outbound. Effective cost of a fully-refunded ₹10,000 card payment is ~₹400 (2% in + 2% out). UPI refunds are free both ways.

See the refund policy for the customer-facing rules (when refunds are issued, in what timeframe).

Region routing logic

The portal decides which gateway to use in this order:

  1. If the visitor explicitly clicked an INR price, use Razorpay.
  2. Cloudflare cf_country cookie = IN → Razorpay.
  3. Anything else → Stripe.
  4. If only one gateway is live (the other is in MOCK mode), use the live one regardless of region.

Need help? hr@staffixhr.com.