跳到主要内容

Stripe 支付接入指南

功能状态

Stripe 支付集成尚未开放。本文根据接入方案说明准备工作与代码示例,控制台配置与函数路由以上线后的实际实现为准。

本文介绍 Stripe Checkout 托管支付页的接入流程:服务端创建支付会话,网页跳转至 Stripe 收银台,业务侧通过 Webhook 确认支付结果。

本文不涉及 Elements 自定义收银台或 Connect 分账。托管支付页跳转不需要配置 stripePublishableKey。

适用客户端​

本指南采用网页跳转方式,主要适用于 Web 客户端:

客户端类型接入方式
PC Web桌面浏览器跳转到 Stripe 托管支付页
移动 Web(H5)手机浏览器跳转到 Stripe 托管支付页

原生 App 可通过系统浏览器打开支付页,支付后的 App 回跳需自行对接。本文不覆盖 iOS/Android 原生支付 SDK,也不使用微信小程序的 wx.requestPayment 或 wx.requestVirtualPayment。

前置条件​

  • 已创建云开发环境,具备创建集成与部署 HTTP 云函数的权限。
  • 已有可用的 Stripe 账户。账户开通地区与收款资格以 Stripe 支持地区为准。
  • 已准备订单与商品数据,商品价格由服务端维护。
  • 已准备支付成功与取消后的网页地址。

第一步:准备支付凭证​

登录 Stripe Dashboard,选择测试环境或生产环境。

配置项必填获取位置与用途
stripeSecretKey是“Developers → API keys”,用于服务端调用 Stripe API,可使用 sk_test_…、sk_live_… 或具备所需权限的受限密钥 rk_…
stripeWebhookSecret接收回调时必填为本次集成创建 Webhook 端点后,获取该端点的 whsec_… 签名密钥,详见登记 Webhook
stripeApiVersion否显式指定服务端请求的 Stripe API 版本,需与 SDK 和代码使用的字段兼容
Webhook 密钥需在创建端点后获取

与其他集成的凭证准备顺序不同,需先创建集成取得回调 URL,再在 Stripe 创建对应的 Webhook 端点。随后获取该端点的 whsec_… 密钥,回填集成配置。每个端点的密钥独立,不能复用其他端点或其他集成的 Webhook 密钥。

服务端密钥与 Webhook 签名密钥用途不同,不能相互替代。密钥只保存在集成配置或服务端环境变量中,不写入网页代码。

测试环境与生产环境的密钥、Webhook 端点及支付对象分别管理,不能混用。使用受限密钥时,需授予实际调用接口所需的权限。

第二步:创建集成并配置回调​

创建集成​

  1. 进入云开发平台/集成中心,选择“Stripe 支付”。
  2. 填写集成名称与 stripeSecretKey,按需填写 stripeApiVersion,提交创建。
  3. 等待平台自动生成 HTTP 云函数与回调 URL,并将凭证配置注入云函数。
  4. 在集成详情页查看生成的云函数,复制完整回调 URL,用于下一步登记 Webhook。

首次创建时无需手动创建或关联云函数,也无需申请回调域名。生成的函数名形如 <集成名>-<随机串>,调用时使用详情页显示的实际名称。通用创建流程可参考集成中心使用流程。

登记 Webhook​

  1. 进入 Stripe Dashboard/Workbench/Webhooks,创建事件目标。
  2. 填入集成中心提供的完整 HTTPS 回调 URL。方案约定的回调路径为 /stripe/webhook。
  3. 选择需要接收的事件,保存端点。
  4. 在本次新建端点的详情中获取 whsec_… 签名密钥,返回集成中心,更新 stripeWebhookSecret 并保存。
  5. 确认集成配置、端点环境与函数关联一致,再发送测试事件。
事件业务处理
checkout.session.completed检查会话支付状态,已支付时执行幂等发货
checkout.session.async_payment_succeeded延迟支付成功,重新核验状态并发货
checkout.session.async_payment_failed延迟支付失败,更新订单状态,不发货
checkout.session.expired会话过期,更新对应未支付订单
payment_intent.succeeded支付成功事件,结合订单关联处理;避免与会话事件重复发货
payment_intent.payment_failed记录支付失败信息
charge.refunded核对退款金额与状态,更新业务退款记录
charge.dispute.created记录争议并通知业务人员处理

Stripe 使用一个 Webhook 端点接收不同类型的事件,通过 event.type 分发。回调内容是 JSON,无需执行微信支付回调中的 AES 解密。

第三步:创建 Checkout Session​

以下路径采用接入方案中的示例约定,部署时以云函数实际路由为准:

路由用途
POST /stripe/create_session创建 Checkout Session,返回 sessionId 与支付页 url
GET /stripe/retrieve_session按 Session ID 查询支付会话
POST /stripe/create_refund方案中的退款接口,需确认函数实现与密钥权限后使用
POST /stripe/webhook接收支付与退款等事件

服务端创建会话​

服务端先校验用户身份与订单归属,再读取订单金额或 Stripe Price ID。不要直接使用前端提交的金额创建支付会话。

以下示例依赖 stripe Node.js SDK,接收服务端已核验的订单对象。stripePriceId、quantity 与用户标识均来自业务订单,而非未校验的请求体。

const stripe = require('stripe')(process.env.stripeSecretKey, {
...(process.env.stripeApiVersion
? { apiVersion: process.env.stripeApiVersion }
: {}),
});

async function createCheckoutForOrder(order) {
if (!order.id || !order.userId || !order.stripePriceId || !order.paymentAttemptId) {
throw new Error('Missing order information');
}
if (!Number.isInteger(order.quantity) || order.quantity < 1) {
throw new Error('Invalid quantity');
}

const metadata = {
orderId: String(order.id),
userId: String(order.userId),
};

const session = await stripe.checkout.sessions.create(
{
mode: 'payment',
line_items: [{ price: order.stripePriceId, quantity: order.quantity }],
success_url: 'https://example.com/result?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://example.com/cart',
client_reference_id: String(order.id),
metadata,
payment_intent_data: { metadata },
},
{ idempotencyKey: `checkout:${order.id}:${order.paymentAttemptId}` },
);

return { sessionId: session.id, url: session.url };
}

同一次支付尝试使用相同的幂等键与请求参数。重新发起支付尝试时,使用业务侧持久化的新 paymentAttemptId,并保存 Session ID 与订单的关联。

顶层 metadata 属于 Checkout Session,不会自动复制到 PaymentIntent。如需在支付事件中读取同样的订单信息,另行设置 payment_intent_data.metadata。

配置金额与跳转地址​

  • 使用预建商品价格时,传入 line_items[].price,如 price_…。
  • 使用动态价格时,在 line_items[].price_data 中设置 currency、unit_amount 与 product_data,由服务端计算金额。
  • unit_amount 使用币种最小货币单位:20 美元传 2000;500 日元传 500,不能对所有币种统一乘以 100。特殊币种规则见 Stripe 币种文档。
  • 托管支付页使用 success_url 和 cancel_url。使用服务端固定地址或白名单地址,不接受任意前端回跳 URL。
  • {CHECKOUT_SESSION_ID} 由 Stripe 替换为实际会话 ID,结果页可据此向服务端查询状态。

第四步:网页跳转支付​

网页提交业务订单号,服务端创建会话后返回支付页地址。接口应配置身份认证;下例假设网页通过同源接口调用集成函数,并使用现有登录会话。

async function startCheckout(orderId) {
const response = await fetch('/stripe/create_session', {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ orderId }),
});

const result = await response.json();
if (!response.ok || !result.url) {
throw new Error(result.message || 'Unable to create checkout session');
}

window.location.assign(result.url);
}

跨域调用时,按实际域名、路由、登录方式与跨域规则调整请求。不要将 stripeSecretKey 或 stripeWebhookSecret 发送给浏览器。

支付结果

success_url 只用于网页展示,不能作为发货依据。最终状态由服务端核验,Webhook 驱动订单更新与发货。

第五步:处理支付结果​

验证回调来源​

集成方案由网关代验签,业务函数处理转发的事件。函数应只接收可信网关请求,不能另开免鉴权公网入口接受任意事件 JSON。

自建回调或本地调试时,使用 Stripe SDK 验签。Webhook 路由必须先于 express.json() 注册,保留原始请求体。

const express = require('express');
const stripe = require('stripe')(process.env.stripeSecretKey);
const app = express();

app.post('/stripe/webhook', express.raw({ type: 'application/json' }), (req, res) => {
try {
const event = stripe.webhooks.constructEvent(
req.body,
req.headers['stripe-signature'],
process.env.stripeWebhookSecret,
);
res.json({ received: true, eventId: event.id });
} catch (error) {
res.status(400).send('Invalid webhook signature');
}
});

app.use(express.json());

此代码仅演示验签,不包含订单处理。生产环境需在返回 2xx 前完成可靠的事件入库或持久化队列投递;持久化失败时返回非 2xx,让 Stripe 重试。

更新订单与发货​

  1. 按 event.id 持久化去重,防止同一通知重复处理。
  2. 通过 Session ID 或业务订单号查询订单,核对用户、币种、金额与支付对象的关联。
  3. 收到 checkout.session.completed 时,检查 payment_status。paid 可发货;unpaid 等待后续结果;no_payment_required 按业务规则处理。
  4. 延迟支付通过 checkout.session.async_payment_succeeded 确认成功,失败事件不发货。
  5. 使用数据库事务或原子更新记录发货状态。以业务订单或 Session ID 保证履约幂等,避免不同事件重复触发发货。

返回 2xx 不代表业务已经到账或发货完成。事件入库后,耗时的发货与通知逻辑可异步执行,并记录失败供重试。

验证结果​

在 Stripe 测试环境完成一次支付,检查:

  • 创建会话接口返回 Session ID 与 Checkout URL。
  • 支付后,Webhook 端点投递记录显示 2xx,云函数收到对应事件。
  • 业务订单按服务端核验结果更新,发货记录只产生一次。
  • 重发同一事件,不会重复发货。
  • 支付取消或会话未支付,不会误标记为已支付。

不要通过生产环境密钥创建真实收费订单来验证测试链路。

常见问题​

Webhook 验签失败​

检查端点的 whsec_… 是否与集成配置一致、原始请求体是否被改写。网关已验签并转发后的事件不能再用改写后的 JSON 重算原始签名。

支付完成但订单未更新​

在 Stripe Dashboard 的端点详情查看事件投递记录与响应码,确认事件已订阅、端点环境正确、集成函数关联正确。延迟支付还需等待异步成功事件。

本地回调调试​

使用 Stripe CLI 将测试事件转发到本地回调路由:

stripe listen --forward-to localhost:3000/stripe/webhook

使用命令输出的临时 Webhook 签名密钥。它不同于 Dashboard 端点密钥,不要将其回填到线上集成。

切换测试与生产环境​

分别准备服务端密钥与 Webhook 端点签名密钥。切换集成配置时,同步核对 Price ID 等支付对象的所属环境。

相关文档​