幂等性Idempotency
所有 POST 业务接口支持 Idempotency-Key。网络超时后放心重试——同一 Key 不会产生第二笔订单、第二笔代付或第二次提现。Every business POST accepts an Idempotency-Key. Retry after timeouts safely — one key can never create a second order, payout or withdrawal.
统一资源模型、幂等写操作、签名 Webhook 与完整沙盒。测试与生产环境只差一个 API Key——示例中的每个端点和字段都来自真实接口。One resource model, idempotent writes, signed webhooks and a full sandbox. Test and production differ only by API key — every endpoint and field below comes from the real interface.
沙盒环境下从创建订单到 Webhook 通知,全链路可在十分钟内跑通。From order creation to webhook delivery, the whole sandbox flow runs in about ten minutes.
在商户后台「API Keys」分别创建测试(ak_test_…)与生产(ak_live_…)Key。完整 Key 仅在创建时展示一次,之后只显示前缀——请立即妥善保存。生产 Key 支持来源 IP 限制与权限 Scope。Create test (ak_test_…) and live (ak_live_…) keys in the dashboard. The full key is shown once at creation and only the prefix afterwards — store it safely. Live keys support IP allowlists and permission scopes.
curl -X POST https://api.apexpayment.com/v1/payment-orders \
-H "X-API-Key: ak_test_…" \
-H "Idempotency-Key: 2c6a7e1f-9b34-4d2e-a1c5-8f0d6b21e4a7" \
-H "Content-Type: application/json" \
-d '{
"merchantOrderId": "sub_20260904_00318",
"amountMinor": 24900,
"country": "BR",
"paymentMethod": "pix",
"description": "Ebook monthly subscription",
"expiresInMinutes": 30,
"callbackUrl": "https://your-app.example/apex/return"
}'
{
"id": "po_8f2a91c4", // 平台订单 ID,用于查询/退款/取消
"orderNo": "APO20260904-003187",
"status": "pending",
"amountMinor": 24900, // 最小货币单位:BRL 分
"feeMinor": 523, // 手续费先算清,成交即明示
"qrPayload": "00020126…5802BR", // EMV 风格,直接渲染二维码
"copyPaste": "00020126…5802BR", // Pix Copy&Paste 同源
"expiresAt": "2026-09-04T14:32:00Z"
}
X-Apex-Event: payment_order.paid
X-Apex-Event-Id: evt_7d1f92aa
X-Apex-Signature: 9f2ab3…(HMAC-SHA256(secret, rawBody) 的 hex,请用原始报文验签)
X-Apex-Merchant-Id: mch_1a2b3c
{
"id": "evt_7d1f92aa",
"eventType": "payment_order.paid",
"createdAt": "2026-09-04T14:07:46Z",
"data": { "orderId": "po_8f2a91c4", "merchantOrderId": "sub_20260904_00318" }
}
处理成功返回 2xx;非 2xx 视为投递失败,自动按下方策略重试。事件以 eventId 幂等,请据此去重。Return any 2xx to acknowledge; non-2xx triggers the retry schedule below. Events are idempotent by eventId — deduplicate on it.
订阅你关心的事件,验证签名,剩下的交给投递系统:失败自动重试,五次尝试后进入死信,可在后台手动重放。Subscribe to the events you care about, verify signatures, and let the delivery system work: automatic retries, dead-lettering after five attempts, and manual replay from the dashboard.
| 投递尝试Attempt | 时间点Timing | 策略Policy |
|---|---|---|
| 1 | 即时immediate | 业务变更后经 Outbox 队列发出sent via outbox queue after the change |
| 2 | +60s | 指数退避;共 5 次尝试,全部失败后事件标记 dead,后台可人工重放。Exponential backoff; after five failed attempts the event is marked dead and can be replayed manually. |
| 3 | +5min | |
| 4 | +30min | |
| 5 | +2h |
import crypto from "node:crypto";
const expected = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(rawBody) // 必须用未解析的原始报文
.digest("hex");
const ok = crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(req.headers["x-apex-signature"])
);
所有 POST 业务接口支持 Idempotency-Key。网络超时后放心重试——同一 Key 不会产生第二笔订单、第二笔代付或第二次提现。Every business POST accepts an Idempotency-Key. Retry after timeouts safely — one key can never create a second order, payout or withdrawal.
错误永远长一个样:type / code / message / retryable,外加 requestId。凭 requestId 可以直接定位服务端日志。Errors always look the same — type / code / message / retryable, plus requestId. Hand a requestId to support and the server log is found.
金额一律用最小货币单位整数(amountMinor),链上资产用高精度十进制。API 层面拒绝浮点数,从源头消灭精度事故。Amounts are integer minor units (amountMinor); on-chain assets use high-precision decimals. Floats are rejected at the API layer — precision incidents die at the source.
新增国家、新增支付方式不改变既有 API 结构;状态只增不改。版本化路径 /v1,废弃字段提前公告。New countries and methods never reshape the existing API; states are only added. Versioned /v1 paths, deprecated fields announced ahead.
| HTTP | 场景Meaning | retryable |
|---|---|---|
| 400 | 参数错误(金额越界、状态不允许该操作等)Bad request (limit exceeded, invalid state transition) | false |
| 401 | API Key 无效或已吊销Invalid or revoked API key | false |
| 403 | 权限不足 / 来源 IP 不在白名单Insufficient scope / IP not allowlisted | false |
| 404 | 资源不存在Resource not found | false |
| 409 | 冲突(重复商户订单号、状态竞争)Conflict (duplicate merchantOrderId, race on state) | false |
| 429 | 限流,请按 Retry-After 退避Rate limited — back off per Retry-After | true |
| 500 | 服务端错误,凭 requestId 反馈给我们Server error — report with the requestId | true |
沙盒完整模拟上游通道:创建订单即生成 EMV 风格二维码,模拟「支付成功 / 过期 / 失败」三种回调,账本、余额、Webhook、对账全部真实运转。联调通过后,换一枚 ak_live_ Key 即上生产。The sandbox fully simulates the upstream channel: orders render EMV-style QR payloads, and paid / expired / failed callbacks drive a real ledger, balances, webhooks and reconciliation. When testing passes, swap to an ak_live_ key and go live.
沙盒访问方式随商户审核通过后在开通邮件中提供。Sandbox access details are provided in the onboarding email after KYB approval.
# 1. 创建订单(测试 Key)
POST /v1/payment-orders → "status": "pending"
# 2. 在模拟收银台点击「支付成功」
POST /sandbox/simulate/po_8f2a91c4 { "event": "paid" }
# 3. 平台自动完成:
order → PAID
ledger → DR 通道清算 / CR 商户余额 +24,377.00
fee → CR 平台收入 +523.00
webhook → payment_order.paid (signed)
balance → available +24,377.00
企业账号审核通过后即可创建沙盒 Key,文档里的示例可以原样运行。Once your company account is approved you can create sandbox keys — the samples on this page run as-is.