核心概念
与 Owem Pay API 集成的基本概念。
安全架构
API 采用三层独立保护机制。所有层级均为必需。
第一层 -- API Key + Secret
每个集成方都会收到一对凭证(client_id 和 client_secret)。Secret 从不以明文存储 -- 我们只保存哈希值。当请求到达时,发送的 secret 会与存储的哈希进行比对。如果不匹配,请求会在到达业务逻辑之前被立即拒绝。
第二层 -- 逐请求 HMAC-SHA512 签名
除 API Key 外,每个交易类请求 (POST) 还需在 hmac 头中发送 HMAC-SHA512 签名。
流程如下:
- 集成方将请求体序列化为 JSON
- 使用
client_secret作为密钥生成 HMAC-SHA512 哈希 - 将十六进制格式的哈希值放在
hmac头中发送
服务端使用相同方法重新计算哈希并与接收到的值进行比较。如果内容中任何字节在传输过程中被篡改(例如中间人攻击),签名将不匹配,请求会被以 401 错误拒绝。此比较采用恒定时间比较(constant-time comparison),防止通过时序攻击逐字节推断签名。
第三层 -- 强制 IP 白名单
每个 API Key 只能从预先授权的 IP 地址使用。即使有人获取了凭证,也无法从其他 IP 使用 API。未授权 IP 的请求会收到 403 Forbidden。
附加保护
| 保护措施 | 描述 |
|---|---|
| 频率限制 | 每 IP 60,000 次请求/分钟。未认证端点:5 次/分钟 |
| Cloud Armor (WAF) | 保护 GKE 集群的 Web 应用防火墙 |
| 强制 HTTPS | 所有连接均使用 TLS 1.2 或更高版本 |
| HSTS | 已启用 HTTP 严格传输安全 |
完整详情:认证 | HMAC-SHA512
为什么选择 HMAC 而非 mTLS?
mTLS(双向 TLS)通过 X.509 证书在连接层添加认证。这是一个有效的保护层,但在我们的场景中,逐请求 HMAC 提供了同等或更适当的保护:
| 方面 | mTLS | HMAC-SHA512 |
|---|---|---|
| 验证对象 | 连接(TLS 通道) | 每个单独的请求 |
| 载荷完整性 | 否 -- 连接可信则请求直接通过 | 是 -- 请求体的任何更改都会导致请求被拒绝 |
| 运维管理 | 复杂:证书签发、轮换、吊销、CRL/OCSP | 简单:生成新密钥对、更新、废止旧密钥 |
| 常见事故 | 证书过期或管理不当 | 罕见 -- 密钥是字符串,无复杂生命周期 |
TLS 已保证传输加密。HMAC 作为附加层,保证载荷的完整性和真实性 -- 这是 mTLS 本身无法覆盖的。
货币金额
Owem Pay API 根据方向使用两种不同的单位:
| 方向 | 单位 | 比例 | R$ 30.00 示例 |
|---|---|---|---|
| 发送的请求(request body) | centavos(分) | BRL x 100 | 3000 |
| 接收的响应(response body) | 基本单位 | BRL x 10,000 | 300000 |
快速换算
- 发送时:将雷亚尔金额乘以 100。R$ 30.00 =
3000 - 读取响应时:除以 10,000。
300000/ 10,000 = R$ 30.00 - 切勿使用浮点数 -- 始终使用整数
参考表
| BRL 金额 | 请求(centavos) | 响应(基本单位) |
|---|---|---|
| R$ 1.00 | 100 | 10000 |
| R$ 30.00 | 3000 | 300000 |
| R$ 150.50 | 15050 | 1505000 |
| R$ 1,000.00 | 100000 | 10000000 |
注意
请求中的 3000(R$ 30.00)在响应中变为 300000。两者表示相同的 BRL 金额,只是使用了不同的单位。如果将响应除以 100 而非 10,000,您将得到 R$ 3,000.00 而非 R$ 30.00。
External ID
external_id 字段是一个可选标识符,由您在自己的系统中定义,用于追踪交易。它在 cash-in 和 cash-out 端点中被接受,并在所有关联的响应和 webhook 中返回。
| 属性 | 值 |
|---|---|
| 是否必填 | 否 |
| 最大长度 | 128 个字符 |
| 允许字符 | 字母数字、.、_、:、- |
| 正则表达式 | ^[a-zA-Z0-9._:\-]+$ |
| 示例 | "order-9876"、"invoice-4521"、"ref:2026-03-07:001" |
除了在响应中返回外,您还可以通过 external_id 查询交易:
GET /api/external/transactions/ref/{external_id}追踪
使用 external_id 将 Owem Pay 交易与您系统中的订单、发票或记录关联。重复值不会被拒绝,但建议保持唯一性以便于对账。
幂等性
写入请求 (POST) 接受 Idempotency-Key 头以避免重复处理。如果在 24 小时内发送具有相同密钥的第二个相同请求,API 将返回缓存的原始响应而非重新处理。
Idempotency-Key: unique-request-id-123| 属性 | 值 |
|---|---|
| 头 | Idempotency-Key |
| 最大长度 | 256 个字符 |
| 缓存 TTL | 24 小时 |
| 适用范围 | 仅 POST(cash-in、cash-out、refund、webhooks、CPF) |
| 重放响应 | 头 X-Idempotent-Replay: true |
重要
幂等性密钥考虑方法 + 路径 + 密钥。对不同端点使用相同密钥的两个请求被视为不同的操作。
交易状态
Cash In(收款)
| 状态 | 描述 |
|---|---|
active | QR Code 已生成,等待付款 |
pending | 检测到付款,处理中 |
completed | 付款已确认并入账 |
failed | 付款失败 |
cancelled | QR Code 已过期(24小时)或已取消 |
Cash Out(付款)
| 状态 | 描述 |
|---|---|
pending_approval | 等待审批(创建+审批流程) |
processing | 已发送至 SPI,等待清算 |
completed | 清算成功 |
failed | 被 SPI 拒绝或处理出错 |
refunded | 已退回(全额或部分) |
端到端 ID (E2E ID)
PIX 交易在巴西央行生态系统中的唯一标识。标准格式:
E{ISPB}{YYYYMMDDHHMM}{序号}示例: E37839059202603071530000001
| 组成部分 | 值 | 描述 |
|---|---|---|
E | 固定前缀 | 标识为 E2E ID |
37839059 | Owem Pay 的 ISPB | 8 位数字 |
202603071530 | UTC 日期和时间 | YYYYMMDDHHMM(12 位) |
000001 | 序号 | 6 位数字 |
E2E ID 由 Owem Pay 自动生成,并在每次 PIX 操作的响应中返回。用于在机构间追踪交易。
PIX 密钥类型
| 类型 | 格式 | 示例 | 个人限额 | 企业限额 |
|---|---|---|---|---|
cpf | 11 位数字 | 12345678901 | 1 | -- |
cnpj | 14 位数字 | 12345678000190 | -- | 1 |
email | 有效邮箱 | contato@empresa.com.br | 5 | 20 |
phone | +55 + 区号 + 号码 | +5511999998888 | 5 | 20 |
evp | UUID v4(随机密钥) | a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d | 5 | 20 |
响应格式
所有 API 响应遵循以下格式:
成功
{
"worked": true,
...
}错误
{
"worked": false,
"detail": "错误描述"
}worked 字段表示操作是否成功(true)或失败(false)。出错时,detail 字段描述原因。