5 分钟接入

本指南带你跑完整端到端流程:注册 → 配置支付渠道 → 拿 API Key → 创建一笔测试支付 → 接收 Webhook。

准备工作

  • 一个 Node.js ≥ 18 / Python ≥ 3.9 / Go ≥ 1.21 的后端项目(任意语言也可直接调 REST API
  • 至少一个支付渠道账号:微信支付商户号 / Stripe / Creem 任一(也可以先用测试模式,不配渠道)
  • 一个能从公网访问的回调地址(本地开发可用 ngrokcloudflared

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:

install
npm i @35m/sdk
server.ts
import { 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
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,用来验证请求来源。

app/api/webhooks/35pay/route.ts
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 可能因为重试或网络抖动被投递多次。务必以 sessionIdmetadata.orderId 为唯一键去重,例如在数据库给订单加 UNIQUE 约束, 或先 SELECT 状态再决定是否更新。


下一步