Payout Webhook
每当 payout 状态变更时,A55 会向您在该 payout 上设置的 webhook_url 发送 POST。载荷有意保持精简——使用 payout_uuid 从 查询 Payout 获取完整 payout。
webhook_url 在 创建 Payout 请求体中按 payout 提供。私有和 localhost URL 会被拒绝。
载荷字段
| 字段 | 类型 | 说明 |
|---|---|---|
payout_uuid | UUID | payout 唯一标识符 |
status | string | 新的 payout 状态(见下表) |
transaction_reference | string | 创建时发送的幂等键 |
external_id | string | provider 的 payout id |
type_payout | string | payout 通道(pix、bank_transfer、ted、spei、cash_pickup) |
payment_code | string 或 null | 现金提取码(仅现金 payout) |
authorization_code | string 或 null | provider 授权码(如可用) |
载荷示例
{
"payout_uuid": "9b1f0c88-3a3c-4f2f-9d6e-1f0a2d4e88c1",
"status": "realized",
"transaction_reference": "PAY-2048",
"external_id": "MN-20260616-0001",
"type_payout": "pix",
"payment_code": null,
"authorization_code": "AUTH-55812"
}
所有可能的状态
| 状态 | 说明 |
|---|---|
pending | 已创建,等待处理 |
issued | 已发送至 provider |
realized | 已确认并结算 |
returned | 被接收银行退回 |
canceled | 已取消 |
error | 处理失败 |
expired | 已过期 |
获取完整 payout 详情
Webhook 载荷设计上是精简的。收到后,使用 Bearer 令牌调用 API 以获取完整的 payout 对象:
curl "https://api.a55.tech/api/v1/bank/wallet/payout/{payout_uuid}/{wallet_uuid}/" \
-H "Authorization: Bearer $ACCESS_TOKEN"
Webhook 是触发器,API 是事实来源
使用 Webhook 知晓 payout 何时变更,然后调用 GET /api/v1/bank/wallet/payout/{payout_uuid}/{wallet_uuid}/ 获取 fee、confirmed_date、destination 等完整详情。
处理器示例
- Python (Flask)
- JavaScript (Express)
from flask import Flask, request, jsonify
app = Flask(__name__)
processed = set()
@app.route("/webhooks/a55/payouts", methods=["POST"])
def payout_webhook():
data = request.get_json()
payout_uuid = data.get("payout_uuid")
status = data.get("status")
# 去重
if payout_uuid in processed:
return jsonify(status="duplicate"), 200
processed.add(payout_uuid)
if status == "realized":
mark_payout_settled(payout_uuid)
elif status in ("returned", "error", "expired"):
flag_payout_failure(payout_uuid, status)
return jsonify(status="accepted"), 200
const express = require("express");
const app = express();
app.use(express.json());
const processed = new Set();
app.post("/webhooks/a55/payouts", (req, res) => {
const { payout_uuid, status } = req.body;
// 立即响应
res.sendStatus(200);
// 去重
if (processed.has(payout_uuid)) return;
processed.add(payout_uuid);
if (status === "realized") {
markPayoutSettled(payout_uuid);
} else if (["returned", "error", "expired"].includes(status)) {
flagPayoutFailure(payout_uuid, status);
}
});
最佳实践
| 实践 | 原因 |
|---|---|
立即返回 200 | 避免超时和重复投递 |
| 在后台处理 | 保持响应时间较低 |
按 payout_uuid 去重 | 安全处理重投的 Webhook |
| 通过 API 获取完整详情 | Webhook 载荷设计上是精简的 |
| 使用公开可达的 URL | 私有/localhost URL 会被拒绝 |