← Files InsForgeARCHIVED FILE

skills/insforge-cli/references/payments/razorpay.md

6.46 KB · Oct 5, 2026 · 18:29 UTC

↓ Download file

# npx @insforge/cli payments razorpay

Use this reference when configuring or inspecting Razorpay payment infrastructure. For app order/subscription code, load `skills/insforge/payments/razorpay.md`.

## Setup Flow

Always start with status:

```bash
npx @insforge/cli payments razorpay status
```

If Razorpay is unconfigured, add Key ID and Key Secret. `config set` validates the keys and automatically syncs provider state when the key or account changes. Use `status` again after setup to verify key/account/sync/webhook health:

```bash
npx @insforge/cli payments razorpay config set --environment test --key-id rzp_test_xxx --key-secret xxx
npx @insforge/cli payments razorpay status
```

Use `sync` later to manually refresh mirrored provider data or retry a failed sync:

```bash
npx @insforge/cli payments razorpay sync --environment test
```

Use `--environment test` while building. Use `live` only after explicit production approval. Do not store Razorpay keys with generic `secrets` commands.

## Webhooks

Razorpay does not support InsForge-style automatic webhook registration with only API keys. Configure webhooks manually in the Razorpay Dashboard.

From the InsForge dashboard (Dashboard -> Payments -> Settings -> Webhooks), copy:

- Webhook URL, for example `/api/webhooks/razorpay/test`
- Webhook secret

Razorpay can only deliver webhooks to a public HTTPS URL. Localhost will not receive Razorpay webhooks.

Create a webhook in the Razorpay Dashboard with that URL and secret, and select these events:

- `payment.authorized`
- `payment.captured`
- `payment.failed`
- `subscription.created`
- `subscription.activated`
- `subscription.charged`
- `subscription.updated`
- `subscription.cancelled`
- `subscription.paused`
- `subscription.resumed`
- `subscription.halted`
- `subscription.completed`
- `subscription.expired`
- `refund.created`
- `refund.processed`
- `refund.failed`
- `invoice.paid`
- `invoice.expired`
- `order.paid`

Durable fulfillment belongs on `payments.webhook_events`, not Razorpay Checkout callback verification and not `payments.transactions`.

## Catalog

Razorpay catalog concepts are not Stripe concepts:

- Item: the sellable thing plus amount/currency.
- Plan: recurring billing definition around an Item.
- Order: one-time payment attempt.
- Subscription: recurring agreement created from a Plan.

Commands:

```bash
npx @insforge/cli payments razorpay catalog --environment test
npx @insforge/cli payments razorpay items list --environment test
npx @insforge/cli payments razorpay items create --environment test --name "Pro Plan" --amount 200000 --currency inr
npx @insforge/cli payments razorpay items update item_123 --environment test --active false
npx @insforge/cli payments razorpay plans list --environment test
npx @insforge/cli payments razorpay plans create --environment test --period monthly --interval 1 --item-name "Pro Plan" --item-amount 200000 --item-currency inr
```

Do not map Razorpay Plans to Stripe Prices. A Razorpay Plan is a subscription billing definition that wraps an Item.

## Admin Reads

Use these for inspection and debugging:

```bash
npx @insforge/cli payments razorpay customers --environment test
npx @insforge/cli payments razorpay subscriptions --environment test
npx @insforge/cli payments razorpay subscriptions --environment test --subject-type team --subject-id team_123
npx @insforge/cli payments razorpay transactions --environment test
npx @insforge/cli payments razorpay transactions --environment test --limit 20 --json
```

`--subject-type` and `--subject-id` are app billing subjects passed to InsForge, such as `team:team_123` or `user:user_123`. They are not Razorpay customer, order, payment, plan, or subscription IDs.

## RLS For Runtime App Code

Before building Razorpay Checkout UI, add app-specific RLS to the Razorpay runtime authorization tables:

- `payments.razorpay_orders`: `INSERT` for one-time order creation. Add `SELECT` only if the app reads order attempts.
- `payments.razorpay_subscriptions`: `INSERT` for subscription creation.
- `payments.razorpay_subscriptions`: `UPDATE` policy for cancel, pause, and resume authorization. The backend only probes `updated_at`; frontend users do not directly mutate provider state columns.

Example shape:

```sql
ALTER TABLE payments.razorpay_orders ENABLE ROW LEVEL SECURITY;
ALTER TABLE payments.razorpay_subscriptions ENABLE ROW LEVEL SECURITY;

CREATE POLICY "team admins create razorpay orders"
ON payments.razorpay_orders
FOR INSERT
TO authenticated
WITH CHECK (
  subject_type = 'team'
  AND public.is_team_billing_admin(subject_id)
);

CREATE POLICY "team admins create razorpay subscriptions"
ON payments.razorpay_subscriptions
FOR INSERT
TO authenticated
WITH CHECK (
  subject_type = 'team'
  AND public.is_team_billing_admin(subject_id)
);

CREATE POLICY "team admins manage razorpay subscriptions"
ON payments.razorpay_subscriptions
FOR UPDATE
TO authenticated
USING (
  subject_type = 'team'
  AND public.is_team_billing_admin(subject_id)
)
WITH CHECK (
  subject_type = 'team'
  AND public.is_team_billing_admin(subject_id)
);
```

For user-owned billing, use `subject_type = 'user' AND subject_id = auth.uid()::text`.

## Fulfillment Trigger

Create triggers on `payments.webhook_events` and update app-owned tables:

```sql
CREATE OR REPLACE FUNCTION public.fulfill_razorpay_billing_event()
RETURNS TRIGGER AS $$
BEGIN
  IF NEW.provider = 'razorpay'
     AND NEW.processing_status = 'processed'
     AND NEW.event_type IN ('payment.captured', 'order.paid', 'invoice.paid') THEN
    -- Update public.orders, public.team_entitlements, or an app-owned outbox.
    NULL;
  END IF;

  RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE TRIGGER fulfill_razorpay_billing_event
  AFTER INSERT OR UPDATE ON payments.webhook_events
  FOR EACH ROW
  EXECUTE FUNCTION public.fulfill_razorpay_billing_event();
```

Make fulfillment idempotent. For email, warehouse, CRM, or other external side effects, write an app-owned outbox row and process it asynchronously.

## Common Mistakes

| Mistake | Fix |
|---------|-----|
| Expecting `payments razorpay webhooks configure` | Configure Razorpay webhooks manually in the Razorpay Dashboard |
| Treating Checkout callback verification as fulfillment | Fulfill from `payments.webhook_events` |
| Expecting a hosted Checkout redirect URL | Use Razorpay Checkout.js in the app |
| Treating Razorpay Plans as Stripe Prices | Use Razorpay Items and Plans natively |
| Letting any authenticated user manage subscriptions | Add app-specific `UPDATE` RLS on `payments.razorpay_subscriptions` |

SHA-256: 0c227152df37764ee0a3df28c4d4024af1eb871f4938d0ed2e7b8f810eeddda8