基于已有的 checkout session 创建一次性购买订单,并返回托管的 PSP 支付 URL。
POST /v1/actions/onetime-order/create-order
认证方式: Session Token — 见 Customer Endpoints(customer 或 shopper 角色)
收银台流程
- 商户首先调用 创建 Checkout Session 锁定产品版本、价格与币种,拿到
sessionId
- 买家进入托管收银台页(或商户自建页面)确认账单信息
- 调用此接口完成下单 — 服务端冻结价格、根据
billingDetail 计算税额、写入订单并创建 PSP checkout
- 买家跳转到返回的
checkoutUrl 完成支付
- 价格快照:下单时冻结价格,后续产品调价不影响本订单
- 税额计算:根据
billingDetail(国家、US/CA 的州、EU 企业的 VAT)计算税额
- PSP 容错:PSP 调用失败时订单会自动回滚,可以安全重试
- 邮箱规范化:服务端在税额计算、订单存储、Session 回写以及 PSP 调用前会对
buyerEmail 做 trim().toLowerCase() 规范化,Foo@Bar.COM 与 foo@bar.com 视为同一买家
请求体
| 字段 | 类型 | 必需 | 说明 |
|---|
checkoutSessionId | string | 是 | 由「创建 Checkout Session」返回的会话 ID |
billingDetail | object | 条件 | 买家账单信息(见下)。Session 中未预填时必填 |
buyerEmail | string | 条件 | 买家邮箱。Session 中未预填时必填;session token 已携带买家身份时被忽略 |
buyerIp | string | 否 | 买家 IP 地址(用于细化税额计算) |
successUrl | string | 否 | 覆盖 session 上配置的支付成功跳转 URL |
storeId、productId、currency 已锁定在 checkout session 上,请求体中传入会被忽略。
Billing Detail 对象
| 字段 | 类型 | 必需 | 说明 |
|---|
country | string | 是 | ISO 3166-1 alpha-2 国家代码 |
isBusiness | boolean | 是 | 是否企业购买 |
postcode | string | 否 | 邮编 |
state | string | 条件 | US 与 CA 必填 |
businessName | string | 条件 | isBusiness 为 true 时必填 |
taxId | string | 条件 | EU 国家 + isBusiness 为 true 时必填(VAT 税号) |
请求示例
import { WaffoPancake } from "@waffo/pancake-ts";
const client = new WaffoPancake({
sessionToken: window.WAFFO_SESSION_TOKEN, // 由商户门户注入
environment: "prod",
});
const result = await client.orders.createOnetime({
checkoutSessionId: "cs_550e8400-e29b-41d4-a716-446655440000",
buyerEmail: "customer@example.com",
billingDetail: {
country: "US",
isBusiness: false,
state: "CA",
},
successUrl: "https://example.com/thank-you",
});
console.log(result.checkoutUrl); // "https://checkout.stripe.com/c/pay/cs_xxx"
成功响应 (200)
{
"data": {
"checkoutUrl": "https://checkout.stripe.com/c/pay/cs_xxx"
}
}
响应字段
| 字段 | 类型 | 说明 |
|---|
checkoutUrl | string | 托管 PSP 支付 URL — 引导买家跳转此处完成支付 |
错误响应
重试策略:4xx 一律不要重试 — 修正请求后重发。5xx 指数退避重试(起步 5s,最多 3 次)。
| 状态码 | errors[0].message | 含义 | 推荐处理 |
|---|
| 400 | Invalid JSON body | 请求体不是合法 JSON | 修正请求体后重新提交 |
| 400 | Missing required field: checkoutSessionId | 未提供 checkoutSessionId | 修正请求体后重新提交 |
| 400 | Session product type mismatch: expected onetime | Session 是订阅产品创建的 | 重新创建一次性 session 再重试 |
| 400 | Environment mismatch between request and session | X-Environment 与 session 环境不一致 | 使用匹配的环境后重新提交 |
| 400 | Missing billingDetail: provide in request body or pre-fill in checkout session | 请求和 session 都没有 billingDetail | 提供 billingDetail 后重新提交 |
| 400 | State is required for US/CA | billingDetail 校验失败 | 修正 billingDetail 后重新提交 |
| 400 | Missing buyerEmail: provide in request body or pre-fill in checkout session | 请求和 session 都没有买家邮箱 | 提供 buyerEmail 后重新提交 |
| 401 | Authentication failed | Session token 无效、过期或格式错误 | 通过 Issue Session Token 重新签发 |
| 403 | Session does not belong to this store | Session 属于其他门店 | 使用调用方门店的 session |
| 409 | Checkout session invalid, please re-enter checkout | Session 不存在或已过期 | 重新创建 checkout session 并重启流程 |
| 500 | Internal server error | 服务端意外失败 | 指数退避重试(起步 5s,最多 3 次) |