Documentation Index
Fetch the complete documentation index at: https://docs.waffo.ai/llms.txt
Use this file to discover all available pages before exploring further.
认证概述
Waffo Pancake 支持两种 API 访问认证方式:
| 方式 | 使用场景 | 说明 |
|---|
| API Key | 服务端到服务端调用 | 使用 RSA-SHA256 签名的永久认证方式 |
| Store Slug | 公开结账流程 | 使用 X-Store-Slug 和 X-Environment 请求头的公开访问方式 |
API Key 认证
API Key 提供基于 RSA-SHA256 签名的永久服务端到服务端认证。私钥始终保存在您的服务器上。
请求头
X-Merchant-Id: MER_2aUyqjCzEIiEcYMKj7TZtw
X-Timestamp: 1705312200
X-Signature: BASE64_ENCODED_SIGNATURE
Content-Type: application/json
API Key 认证不需要 X-Environment 请求头。 每个 API Key 在创建时已绑定到 test 或 prod 环境。系统通过验证签名成功的密钥来确定环境。
使用 SDK(推荐)
import { WaffoPancake } from "@waffo/pancake-ts";
const client = new WaffoPancake({
merchantId: process.env.WAFFO_MERCHANT_ID!,
privateKey: process.env.WAFFO_PRIVATE_KEY!,
});
// All requests are automatically signed
const { store } = await client.stores.create({ name: "My Store" });
签名算法(手动集成)
如果您不使用 SDK,需要自行实现 RSA-SHA256 请求签名:
1. Build the canonical request:
canonicalRequest = METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + SHA256_BASE64(BODY)
2. Sign with RSA-SHA256:
signature = RSA-SHA256(canonicalRequest, privateKey)
3. Base64 encode:
X-Signature = Base64(signature)
手动签名示例
const crypto = require('crypto');
const MERCHANT_ID = 'MER_2aUyqjCzEIiEcYMKj7TZtw';
const PRIVATE_KEY = `-----BEGIN RSA PRIVATE KEY-----
...your private key...
-----END RSA PRIVATE KEY-----`;
async function callApiWithSignature(method, path, body) {
const timestamp = Math.floor(Date.now() / 1000).toString();
const bodyStr = JSON.stringify(body);
const bodyHash = crypto.createHash('sha256').update(bodyStr).digest('base64');
// Build canonical request
const canonicalRequest = `${method}\n${path}\n${timestamp}\n${bodyHash}`;
// RSA-SHA256 sign
const signature = crypto.sign('sha256', Buffer.from(canonicalRequest), PRIVATE_KEY).toString('base64');
const response = await fetch(`https://api.waffo.ai${path}`, {
method,
headers: {
'Content-Type': 'application/json',
'X-Merchant-Id': MERCHANT_ID,
'X-Timestamp': timestamp,
'X-Signature': signature
},
body: bodyStr
});
return response.json();
}
// Usage
const result = await callApiWithSignature('POST', '/v1/actions/store/create-store', {
name: 'My Store'
});
私钥安全
- 切勿在客户端代码中暴露私钥
- 不要将私钥提交到版本控制系统
- 将私钥存储在环境变量中
- 定期轮换密钥,尤其是团队人员变动后
- 时间戳必须在服务器时间的 5 分钟以内
Store Slug 认证
对于面向公众的结账流程,使用 Store Slug 认证。这允许访客在无需 API Key 凭证的情况下创建结账会话和查询公开的门店数据。
请求头
X-Store-Slug: my-awesome-store-k8x2m9ab
X-Environment: test | prod
Content-Type: application/json
curl -X POST https://api.waffo.ai/v1/actions/checkout/create-session \
-H "X-Store-Slug: my-awesome-store-k8x2m9ab" \
-H "X-Environment: test" \
-H "Content-Type: application/json" \
-d '{"productId": "PROD_4cWAslE1GKkGeaOMl9Vbmy", "productType": "onetime", "currency": "USD"}'
创建 API Key
进入开发者页面
导航至 Dashboard → Merchant → Integration → API Keys
创建 API Key
点击 “Create API Key” 生成新的 RSA 密钥对。公钥会自动发送到服务器。
命名和配置
为其设置一个描述性名称(例如 “Production Server”),并选择目标环境(Test 或 Production)。
删除 API Key 是即时且不可逆的操作。使用已删除密钥签名的所有请求都将返回 401 Unauthorized。
认证方式对比
| 功能 | API Key | Store Slug |
|---|
| 服务端使用 | 是 | 否 |
| 客户端使用 | 否 | 是 |
| 需要 X-Environment | 否 | 是 |
| 签发 Session Token | 是 | 否 |
| 创建 Checkout Session | 是 | 是 |
| 商品管理 | 是 | 否 |
| GraphQL 查询 | 是 | 是(仅公开数据) |
| 有效期 | 永久(密钥控制) | - |
认证错误
| 状态码 | 错误 | 解决方案 |
|---|
| 401 | Invalid signature | 检查签名算法、私钥和时间戳新鲜度(5 分钟窗口) |
| 401 | Invalid or expired token | 重新认证或使用有效的 API Key |
| 403 | Insufficient permissions | 检查角色是否有权访问该端点 |
| 400 | Missing authentication | 确保所需的请求头已提供 |
{
"data": null,
"errors": [
{
"message": "Invalid signature",
"layer": "gateway"
}
]
}
安全最佳实践
- 切勿暴露私钥 — 不要放在客户端代码、版本控制或公开仓库中
- 使用 HTTPS 进行所有 API 请求
- 验证 Webhook 签名 以防止伪造请求
- 分离测试和生产密钥 — 为每个环境创建独立的密钥
- 定期轮换密钥,尤其是团队成员变动后
- 监控 API 使用情况 — 在 Dashboard 中查看异常活动