5 分钟接入
本指南带你跑完整端到端流程:注册 → 配置支付渠道 → 拿 API Key → 创建一笔测试支付 → 接收 Webhook。
准备工作
- 一个 Node.js ≥ 18 / Python ≥ 3.9 / Go ≥ 1.21 的后端项目(任意语言也可直接调 REST API)
- 至少一个支付渠道账号:微信支付商户号 / Stripe / Creem 任一(也可以先用测试模式,不配渠道)
- 一个能从公网访问的回调地址(本地开发可用
ngrok或cloudflared)
1. 注册并登录
打开 登录页 用手机号注册一个商户账户。 首次登录会先跳到 /onboarding 让你填一个店铺名(客户付款时会显示「已支付给 X」,不填会显示成手机号,影响信任)—— 填完即进入控制台。
2. 配置支付渠道
在控制台进入 支付渠道,选择你已有的渠道并填入凭据:
- 微信支付:商户号 mchid、API v3 密钥、商户证书
- Stripe:Secret Key(
sk_...)+ Webhook Signing Secret - Creem:API Key + Webhook Secret
每种渠道可以加多份配置(如「主号」+「个体户副号」),每份用
label 区分。 其中一份会被标记为默认。SDK 不指定时走默认那份;要明确指定走哪份, REST 用 providerHints。没有真实渠道也可以先跑通流程:35pay 内置一个
mock provider,用 sk_test_ Key 时会自动启用, 无需任何渠道配置即可模拟支付成功 / 失败。3. 拿到 API Key
进入 API Keys 创建一个 Key。Key 有两种环境:
sk_test_xxx— 测试模式,走 mock provider,不产生真实交易sk_live_xxx— 生产模式,走你配置的真实渠道
Secret Key 只在创建时显示一次,请立刻保存到你的环境变量里(如
PAY_SECRET_KEY)。 泄露的 Key 请立即在控制台撤销并重新生成。4. 创建一笔支付
用 SDK:
npm i @35m/sdkimport { createPay } from '@35m/sdk'
const pay = createPay({
apiKey: process.env.PAY_SECRET_KEY!, // sk_test_xxx
})
const session = await pay.createCheckout({
amount: 9900, // 最小单位:CNY 是分(99.00 → 9900),JPY 等是 ×1
currency: 'CNY',
description: '追思视频套餐',
metadata: { orderId: 'order_123' }, // 透传给 webhook
// successUrl 不传 → 客户付完落到 35pay 收据页 /r/{recordId}
// 传了 → sync 中转模式:客户落地时 webhook 已处理,本地直接读 paid,无需 polling
successUrl: 'https://your.site/orders/123',
})
// 把用户重定向到 35pay 托管收银台
return Response.redirect(session.url, 303)不用 SDK 也可以,直接 HTTP 调用:
curl https://pay.35team.com/api/v1/checkout \
-H "Authorization: Bearer sk_test_xxx" \
-H "Content-Type: application/json" \
-d '{
"amount": 9900,
"currency": "CNY",
"description": "追思视频套餐",
"metadata": { "orderId": "order_123" }
}'响应:
{
"id": "sess_01HXYZ...",
"status": "pending",
"url": "https://pay.35team.com/c/sess_01HXYZ...",
"amount": 9900,
"currency": "CNY",
"expiresAt": "2026-04-28T07:00:00.000Z",
"mode": "test"
}5. 接收 Webhook
在 Webhooks 添加一个 endpoint URL,选择要订阅的事件 (目前支持 payment.paid / payment.failed / refund.succeeded)。 创建后会得到一个 Signing Secret,用来验证请求来源。
import { Pay } from '@35m/sdk'
export async function POST(req: Request) {
const sig = req.headers.get('x-35pay-signature')
const body = await req.text()
if (!sig || !Pay.verifyWebhookSignature(body, sig, process.env.PAY_WEBHOOK_SECRET!)) {
return new Response('invalid signature', { status: 401 })
}
const event = JSON.parse(body) as {
type: 'payment.paid' | 'payment.failed' | 'refund.succeeded'
data: { sessionId: string; metadata: Record<string, unknown> }
}
if (event.type === 'payment.paid') {
await markOrderPaid(event.data.metadata.orderId as string)
}
return new Response('ok')
}Webhook 必须在 5 秒内返回 2xx,否则会被认为失败并重试。建议先入队再异步处理业务逻辑, 避免阻塞响应。
幂等
同一个 sessionId 可能因为重试或网络抖动被投递多次。务必以 sessionId 或metadata.orderId 为唯一键去重,例如在数据库给订单加 UNIQUE 约束, 或先 SELECT 状态再决定是否更新。
下一步
- 查 完整 API 参考
- 看 Webhook 事件清单 与重试策略
- 准备上线?过一遍 测试与上线 checklist