ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

如何用 Razorpay Orders 与签名验证在 InsForge 中实现支付和订阅

如何用 Razorpay Orders 与签名验证在 InsForge 中实现支付和订阅 如何用 Razorpay Orders 与签名验证在 InsForge 中实现支付和订阅【免费下载链接】InsForgeThe all-in-one, open-source backend platform for agentic coding. InsForge gives your coding agent database, auth, storage, compute, hosting, and AI gateway to ship full-stack apps end-to-end.项目地址: https://gitcode.com/GitHub_Trending/in/InsForge在 InsForge 中接入 Razorpay 时你不需要自己保管 Razorpay Key Secret 来发起支付后端通过 InsForge 创建 Razorpay Order 或 Subscription前端用返回的checkoutOptions打开 Razorpay CheckoutCheckout 回调返回razorpay_signature后再由后端完成签名验证。Razorpay 与 Stripe 不同它没有托管跳转式 Checkout——整个链路是后端建单 → 前端拉起 Checkout → 后端验签。本文覆盖一次性订单、订阅创建与签名验证两条路径以及如何用 webhook 事件完成可靠的支付履约。适用前提已有 InsForge 项目和对应的 TypeScript 前端拥有自己的 Razorpay 账号并已申请test和live环境的 Key ID / Key SecretRazorpay 只能向公网 HTTPS 地址投递 webhook。本地开发localhost需要公网隧道或直接使用已部署的后端。支付模型与数据表接入前先明确 Razorpay 各概念在 InsForge 中的落点后续步骤会反复引用这些表Razorpay 概念在 InsForge 中的含义Item带金额的售卖单元镜像在payments.razorpay_itemsPlan围绕 Item 的周期性订阅定义镜像在payments.razorpay_plansOrder一次性支付对象通过POST /api/payments/razorpay/{environment}/orders创建镜像在payments.razorpay_ordersPaymentProvider 支付结果由 webhook 和 sync 投影到payments.transactionsSubscription绑定到 Plan 的 Razorpay 订阅镜像在payments.razorpay_subscriptionsWebhook 事件provider razorpay的已验证事件记录在payments.webhook_events对一次性商品Razorpay Order 可以只带金额、币种和 receipt 创建但 InsForge 文档建议为可售卖商品先创建 Razorpay Item这样同步后目录在 InsForge 和 Razorpay 两侧都可见。把 Order 当作一次支付尝试而不是你的商品目录。准备条件1. 配置 Razorpay 密钥在 Dashboard 的Payments - Settings或 admin API中配置test和live两套 Razorpay Key ID 与 Key Secret。InsForge 会在不存在时自动生成 webhook 签名密钥。Provider 密钥只保存在服务端不要写进前端代码。2. 手动注册 Razorpay WebhookRazorpay 普通商户 API 密钥不支持自动注册 webhook必须到 Razorpay Dashboard 手动创建打开 InsForge Dashboard - Payments - Settings - Webhooks复制其中的 Razorpay Webhook URL 和 Webhook Secret在 Razorpay Dashboard 用复制到的 URL 和 secret 创建 webhook勾选 InsForge 支持的事件并保存。InsForge 处理的事件包括payment.authorized、payment.captured、payment.failed、order.paid、invoice.paid、invoice.expired、refund.created、refund.processed、refund.failed以及subscription.created、subscription.activated、subscription.charged、subscription.updated、subscription.cancelled、subscription.paused、subscription.resumed、subscription.halted、subscription.completed、subscription.expired。webhook 创建完成后完成一笔测试支付确认事件能投递到 InsForge。3. 安装 SDK 并初始化客户端npm install insforge/sdklatestimport { createClient } from insforge/sdk; const insforge createClient({ baseUrl: https://your-project.insforge.app, anonKey: your-anon-key });上面代码块中baseUrl换成你的 InsForge 项目地址anonKey可用npx insforge/cli secrets get ANON_KEY获取或在 Dashboard 点击Install打开API Keys查看可选用于未登录请求。SDK 会带着当前 InsForge 用户 token 调用 Razorpay 运行时路由不要用 Provider 密钥直接调用这些路由。一次性订单创建 Order、打开 Checkout 并验证签名完整的一次性支付分四步创建应用侧待支付订单 → 通过 InsForge 创建 Razorpay Order → 前端打开 Razorpay Checkout → 回调中验证签名。第一步创建 Razorpay Ordertype 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);第一个参数test表示测试环境开发期一直传testreceipt、subject.id、customerEmail、notes.order_id在文档示例中引用了应用侧的order和当前用户对象需要替换为你应用自己的订单记录 ID 和用户信息如果后续 webhook 履约逻辑要读取notes.order_id创建 Order 时必须带上notes: { order_id: ... }文档示例中的notes字段就是这个用途。SDK 封装的是POST /api/payments/razorpay/{environment}/orders。响应中的checkoutOptions带有 Razorpay Checkout 原生字段key、order_id等key只是公开的 Razorpay Key ID密钥不会下发给前端。第二步前端加载 Razorpay Checkoutfunction loadRazorpayCheckout(): Promisevoid { 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); }); }第三步打开 Checkout 并在回调中验证签名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 webhook 事件驱动。订阅创建 Subscription 并验证授权支付签名订阅路径与一次性订单类似但前置条件是先创建或同步一个 Razorpay Plan。Plan 围绕一个 Razorpay Item 定义周期性扣款它不等价于 Stripe Price。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);文档示例中的planId: plan_123、totalCount: 12、subject.id、customerEmail需要替换为你自己已创建/已同步的 Plan ID、扣款期数和计费主体信息。SDK 封装的是POST /api/payments/razorpay/{environment}/subscriptions。响应中的checkoutOptions.subscription_id用于打开 Checkout回调返回razorpay_subscription_id、razorpay_payment_id、razorpay_signature后验证的是授权支付的签名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();如果 webhook 触发器后续需要应用侧标识创建订阅时也要传递 Razorpaynotes。订阅的 RLS 策略要求创建订阅会校验payments.razorpay_subscriptions上的INSERT策略取消、暂停、恢复校验同一张表的UPDATE策略。PostgreSQL 还会对INSERT/UPDATE ... RETURNING返回的行应用SELECT策略——当策略探测需要返回该行时要给同一计费主体保留对应的SELECT可见性。只授予用户策略检查所需的表访问权限Provider 侧变更仍然走后端。通过后端路由管理订阅Razorpay 没有 Stripe Billing Portal 的对应物InsForge 提供取消、暂停、恢复的后端路由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);文档示例中的sub_123替换为你的订阅 ID。对共享计费主体开放这些操作前建议先加应用级 RLS 或服务端成员检查。用 Webhook 事件完成可靠履约不要只凭 Checkout 回调或签名验证就标记订单已支付、发放积分或激活订阅。履约应该基于payments.webhook_events中已验证的事件行而且不要给payments.razorpay_subscriptions这类 Provider 镜像表挂履约触发器——sync 和 webhook 投影会独立于 Provider 事件投递更新这些行。InsForge 文档给出的订单履约触发器示例针对文档中的示例表public.orders请按你的业务表调整字段CREATE OR REPLACE FUNCTION public.fulfill_razorpay_order() RETURNS TRIGGER AS $$ BEGIN IF NEW.provider razorpay AND NEW.event_type IN (payment.captured, order.paid, invoice.paid) AND NEW.processing_status processed AND COALESCE( NEW.payload - payload - payment - entity - notes - order_id, NEW.payload - payload - invoice - entity - notes - order_id ) IS NOT NULL THEN UPDATE public.orders SET status paid, paid_at COALESCE(NEW.processed_at, NOW()) WHERE id::text COALESCE( NEW.payload - payload - payment - entity - notes - order_id, NEW.payload - payload - invoice - entity - notes - order_id ) AND status pending; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql SECURITY DEFINER; CREATE TRIGGER fulfill_razorpay_order_from_webhook AFTER INSERT OR UPDATE ON payments.webhook_events FOR EACH ROW EXECUTE FUNCTION public.fulfill_razorpay_order();这个触发器从事件 payload 的notes.order_id中找到你的订单——这就是前面创建 Order 时必须传notes: { order_id: ... }的原因。注意事件之间没有顺序保证先优先从事件 payload 解析计费主体对其他表的查询只作为兜底。结果验证方式签名验证成功verifyOrder/verifySubscription的error为null。回调中error非空时应抛错中断不要放行。webhook 投递按文档建议完成一笔测试支付确认 Razorpay 事件出现在payments.webhook_eventsprovider razorpay。订单状态更新检查你应用侧订单表如示例中的public.orders在履约触发器执行后从pending变为paid且paid_at已写入。对账投影payments.transactions会收录支付、发票、订单、订阅、退款等 Provider 引用 ID方便到 Razorpay Dashboard 反查源记录。但它只是仪表盘/报表投影不要把payments.transactions当主业务状态面向用户的订单、积分和权益状态应放在你自己应用表里。边界与限制test / live 环境第一个参数传test用于开发只有在开发者明确批准上线 Razorpay 变更且 live 环境的 Items、Plans、webhook 都已配置后才切换到live。密钥边界Razorpay Key Secret 和 webhook secret 绝不能出现在前端代码里前端只能拿到公开的 Razorpay Key ID即checkoutOptions.key。webhook 必须手动创建且只能投递到公网 HTTPS 地址localhost 需要公网隧道或已部署后端否则收不到事件。签名验证不替代 webhook它只覆盖即时回调掉单场景靠 webhook 履约。Provider 是财务事实源Stripe 或 Razorpay 始终是扣款、发票、退款、争议和税务等财务操作的事实源InsForge 不是支付处理方或 merchant of record不替代 Provider Dashboard。继续深入Razorpay Payments 核心概念模型表、事件清单和履约示例的完整说明TypeScript Razorpay Payments SDKSDK 各 helper 的参考Payments 概览共享表结构和跨 Provider 履约模型SDK 安装与 anon key 获取。【免费下载链接】InsForgeThe all-in-one, open-source backend platform for agentic coding. InsForge gives your coding agent database, auth, storage, compute, hosting, and AI gateway to ship full-stack apps end-to-end.项目地址: https://gitcode.com/GitHub_Trending/in/InsForge创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表