> ## Documentation Index
> Fetch the complete documentation index at: https://docs.insforge.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Razorpay 支付 SDK

> 从 TypeScript 应用创建 Razorpay 订单和订阅

<CodeGroup>
  ```bash npm theme={null}
  npm install @insforge/sdk@latest
  ```

  ```bash yarn theme={null}
  yarn add @insforge/sdk@latest
  ```

  ```bash pnpm theme={null}
  pnpm add @insforge/sdk@latest
  ```
</CodeGroup>

```javascript theme={null}
import { createClient } from '@insforge/sdk';

const insforge = createClient({
  baseUrl: 'https://your-app.insforge.app',
  anonKey: 'your-anon-key'  // Optional: for public/unauthenticated requests
});
```

Find the anon key with `npx @insforge/cli secrets get ANON_KEY`, or in the dashboard: click **Install** and open **API Keys**.

## 概述

TypeScript SDK 为生成的应用前端公开 Razorpay 运行时助手：

* `insforge.payments.razorpay.createOrder(...)`
* `insforge.payments.razorpay.verifyOrder(...)`
* `insforge.payments.razorpay.createSubscription(...)`
* `insforge.payments.razorpay.verifySubscription(...)`
* `insforge.payments.razorpay.cancelSubscription(...)`
* `insforge.payments.razorpay.pauseSubscription(...)`
* `insforge.payments.razorpay.resumeSubscription(...)`

Razorpay 不返回托管的 Checkout URL。后端创建 Razorpay 订单或订阅并返回 `checkoutOptions`。浏览器加载 Razorpay Checkout 并使用这些选项打开它。

<Note>
  有关提供商设置、手动 webhook、数据库表和履行模式，请参见 [Razorpay 支付](/core-concepts/payments/razorpay)。
</Note>

## SDK 设置

```typescript theme={null}
import { createClient } from '@insforge/sdk';

const insforge = createClient({
  baseUrl: 'https://your-project.insforge.app',
  anonKey: 'your-anon-key'
});

declare global {
  interface Window {
    Razorpay?: new (options: Record<string, unknown>) => { open: () => void };
  }
}

```

SDK 使用当前 InsForge 用户令牌调用 Razorpay 运行时路由。不要使用提供商密钥调用这些路由。

## 加载 Razorpay Checkout

```typescript theme={null}
function loadRazorpayCheckout(): Promise<void> {
  return new Promise((resolve, reject) => {
    if (window.Razorpay) {
      resolve();
      return;
    }

    const script = document.createElement('script');
    script.src = 'https://checkout.razorpay.com/v1/checkout.js';
    script.onload = () => resolve();
    script.onerror = () => reject(new Error('Failed to load Razorpay Checkout'));
    document.body.appendChild(script);
  });
}
```

## 一次性订单

首先创建一个应用拥有的待处理订单。然后通过 InsForge 创建 Razorpay 订单：

Razorpay 订单可以是仅金额的，但为一次性可售产品创建 Razorpay 商品是一个好做法，因为同步的商品使目录在 InsForge 和 Razorpay 中可见。将订单视为付款尝试。

```typescript theme={null}
type CreateRazorpayOrderResponse = {
  order: {
    id: string;
    orderId: string | null;
    status: string;
  };
  checkoutOptions: {
    key: string;
    amount: number;
    currency: string;
    order_id: string;
    name?: string | null;
    description?: string | null;
    callback_url?: string | null;
    prefill: {
      name?: string | null;
      email?: string | null;
      contact?: string | null;
    };
  };
};

const { data: orderResponse, error } =
  await insforge.payments.razorpay.createOrder('test', {
    amount: 50000,
    currency: 'INR',
    receipt: order.id,
    subject: { type: 'team', id: teamId },
    customerEmail: user.email,
    notes: { order_id: order.id }
  });

if (error) throw error;
if (!orderResponse) throw new Error('Razorpay order creation returned no data');
```

如果您的 webhook 触发器读取 `notes.order_id`，请在创建订单时传递 `notes: { order_id: ... }`。

打开 Razorpay Checkout 并验证返回的签名：

```typescript theme={null}
await loadRazorpayCheckout();

const RazorpayCheckout = window.Razorpay;
if (!RazorpayCheckout) {
  throw new Error('Razorpay Checkout failed to load');
}

const checkout = new RazorpayCheckout({
  ...orderResponse.checkoutOptions,
  handler: async (response: {
    razorpay_order_id: string;
    razorpay_payment_id: string;
    razorpay_signature: string;
  }) => {
    const { error } = await insforge.payments.razorpay.verifyOrder('test', {
      orderId: response.razorpay_order_id,
      paymentId: response.razorpay_payment_id,
      signature: response.razorpay_signature
    });

    if (error) throw error;
  }
});

checkout.open();
```

签名验证保护即时的浏览器回调。持久履行仍应来自已验证的 Razorpay webhook 事件。

## 订阅

首先创建或同步一个 Razorpay 计划。然后通过 InsForge 创建订阅：

```typescript theme={null}
type CreateRazorpaySubscriptionResponse = {
  subscription: {
    subscriptionId: string;
    status: string;
  };
  checkoutOptions: {
    key: string;
    subscription_id: string;
    name?: string | null;
    description?: string | null;
    callback_url?: string | null;
    prefill: {
      name?: string | null;
      email?: string | null;
      contact?: string | null;
    };
  };
};

const { data: subscriptionResponse, error } =
  await insforge.payments.razorpay.createSubscription('test', {
    planId: 'plan_123',
    totalCount: 12,
    subject: { type: 'team', id: teamId },
    customerEmail: user.email
  });

if (error) throw error;
if (!subscriptionResponse) throw new Error('Razorpay subscription creation returned no data');
```

当 webhook 触发器稍后需要应用标识符时，传递 Razorpay 订阅 `notes`。

使用返回的订阅 ID 打开 Razorpay Checkout：

```typescript theme={null}
await loadRazorpayCheckout();

const RazorpayCheckout = window.Razorpay;
if (!RazorpayCheckout) {
  throw new Error('Razorpay Checkout failed to load');
}

const checkout = new RazorpayCheckout({
  ...subscriptionResponse.checkoutOptions,
  handler: async (response: {
    razorpay_subscription_id: string;
    razorpay_payment_id: string;
    razorpay_signature: string;
  }) => {
    const { error } = await insforge.payments.razorpay.verifySubscription('test', {
      subscriptionId: response.razorpay_subscription_id,
      paymentId: response.razorpay_payment_id,
      signature: response.razorpay_signature
    });

    if (error) throw error;
  }
});

checkout.open();
```

## 管理订阅

Razorpay 不提供 Stripe 计费门户的等价物。使用后端路由进行订阅管理：

```typescript theme={null}
await insforge.payments.razorpay.cancelSubscription('test', 'sub_123', {
  cancelAtCycleEnd: false
});

await insforge.payments.razorpay.pauseSubscription('test', 'sub_123');

await insforge.payments.razorpay.resumeSubscription('test', 'sub_123');
```

订阅创建检查 `payments.razorpay_subscriptions` 上的 `INSERT` 策略。取消、暂停和恢复检查同一表上的 `UPDATE` 策略。PostgreSQL 还将 `SELECT` 策略应用于 `INSERT/UPDATE ... RETURNING` 返回的行，因此当策略探测需要返回行时，为同一计费主体添加匹配的 `SELECT` 可见性。在为共享主体公开这些控件之前，添加应用特定的 RLS 或服务器端成员资格检查。

## 履行

不要仅从 Checkout 处理程序标记订单已付款、授予积分或激活订阅。使用 `payments.webhook_events` 中已验证的 Razorpay webhook 事件。不要将履行触发器附加到提供商镜像表，如 `payments.razorpay_subscriptions`。

创建带有 RLS 的应用拥有的履行表，然后从 webhook 触发器更新它们。有关触发器示例，请参见 [Razorpay 支付](/core-concepts/payments/razorpay)。

## 生产/测试环境

在开发时将 `'test'` 作为第一个 SDK 参数传递。仅在开发者明确批准生产 Razorpay 更改并配置了生产商品、计划和 webhook 后才切换到 `'live'`。

<Warning>
  永远不要将 Razorpay Key Secret 或 webhook 密钥放在前端代码中。前端仅接收作为 `checkoutOptions.key` 的公共 Razorpay Key ID。
</Warning>
