快速开始
通过单次 POST 请求注册销售。
curl https://vcr.am/api/v1/sales \
-H "X-API-Key: $VCR_AM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"cashier": { "id": 1 },
"items": [{
"offer": { "externalId": "SKU-001" },
"department": { "id": 1 },
"quantity": "1",
"price": "20000",
"unit": "pc"
}],
"amount": { "nonCash": "20000" },
"buyer": {
"type": "individual",
"receipt": { "email": "buyer@example.com", "language": "en" }
}
}'无需税务凭证即可开始
沙盒收银机在创建时立即获得注册号——无需与税务机关交换证书,无需等待。基础 URL、接口和密钥机制完全相同;唯一的区别是收据带有 TEST 标记且从不上报。
专为生产环境集成而构建
您的系统必须提供的内容
在进行对接之前,请确保每笔销售都包含国家税务局(SRC)所需的数据。
身份验证
每个请求都必须在 X-API-Key 请求头中包含您的 API 密钥。唯一的例外是 GET /exchange-rate,该接口公开开放,无需密钥。
X-API-Key: your_api_key在您的收银机设置中生成和轮换 API 密钥。
对您的 API 密钥保密
幂等性
财政收据无法更正,只能退款后重新开具。因此重复开票是本 API 代价最高的错误,而支付回调重复触发是常态而非例外。请在每个 POST 请求中发送 Idempotency-Key 头:重复的相同请求将返回原收据,而不会再开一张。
Idempotency-Key: 3f6b2c1e-9a84-4d77-9f2a-1c5e0b7d8a63没有该请求头就没有保护
为每一次预期的财政操作生成一个 UUID,在首次调用前与订单一并存储,之后每次重试都复用它。不要单独使用订单号——一个订单可以合理地产生多份财政文件。也不要每次尝试都新生成 UUID,那会使该机制失去意义。
重放的响应与原响应逐字节相同,并带有 Idempotent-Replay: true 头。在把响应当作新开具的文件之前,请先检查它。
无状态的处理器尚未存储任何内容,因此应推导幂等键而非生成。这样两次投递会算出相同的键,第二次即为重放。不要从支付服务商的事件 ID 推导:同一订单的另一个事件会产生不同的键并再次开票。
import { v5 as uuidv5 } from "uuid";
const NAMESPACE = "6f1d1a58-0d0c-4a1e-9a1a-2f9a7b3c4d5e";
const key = uuidv5(`${order.id}:sale`, NAMESPACE);
await fetch("https://vcr.am/api/v1/sales", {
method: "POST",
headers: {
"X-API-Key": process.env.VCR_API_KEY,
"Idempotency-Key": key,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});幂等键在 30 天内可重放——足以让月度对账的重跑得到重放而不是再开一张。同一个键配不同的请求体返回 422;首个请求仍在处理时复用同一个键返回 409,这意味着等待后用同一个键重试,而不是换一个新键。被结构校验拒绝的请求体不会消耗幂等键:该请求从未到达业务操作,因此修正字段后用同一个键重试即可。
错误
错误使用标准 HTTP 状态码以及包含详细信息的 JSON 主体。
| 状态 | 名称 | 触发时机 |
|---|---|---|
400 | 错误请求 | 载荷格式错误或架构验证失败。 |
401 | 未授权 | API 密钥缺失或无效。 |
403 | 禁止访问 | 该收银机尚不能上报文件:未获得注册号,或未在税务机关激活。 |
404 | 未找到 | 所请求的资源不存在。 |
409 | 冲突 | 税务机关基于内容拒绝了该文件、内联商品与已有商品冲突,或使用同一 Idempotency-Key 的请求仍在处理中。被拒绝时会返回 `pending`:文件已保存,因此应排除原因而不是重新发送。 |
422 | 幂等键被复用 | 同一个 Idempotency-Key 配了不同的请求体。新文件需要新的键。 |
500 | 内部错误 | 我们方发生意外故障。请使用指数退避重试。 |
502 | 税务机关不可达 | 文件已保存,响应中带有 `pending`。请先读取 `pending.mayResubmit`:false 表示重发会产生第二张收据——改为轮询 `pending.statusUrl`。 |
延伸阅读
继续构建
即将上架 WordPress.org 插件目录