Skip to content
Translated page. The English version is the source of truth.

POST /apiv2/reports/webhooks

注册一个 URL,当报告准备就绪时 NETTS 将主动调用该地址,无需您轮询状态。

这些端点与订单 Webhook相互独立。在其中一处注册不会订阅另一处的通知,反之亦然。两者的传输格式(签名、请求头、重试机制)完全相同,因此针对其中一个编写的处理程序也可以直接用于另一个。

端点基础 URL

https://netts.io/apiv2/reports/webhooks

请求头

请求头必填描述
X-API-KEY来自控制台的 API 密钥
X-Real-IP密钥白名单中的地址

主端点与备用端点

每个账户最多可配置两个端点。primary(主端点)接收所有通知。仅当主端点的推送尝试次数耗尽后,才会使用 backup(备用端点)——并且备用端点使用其自身独立的密钥进行签名,而非主端点的密钥。

注册

bash
curl -s -X POST 'https://netts.io/apiv2/reports/webhooks' \
  -H 'X-API-KEY: your-api-key' \
  -H 'X-Real-IP: 203.0.113.10' \
  -H 'Content-Type: application/json' \
  -d '{"url": "https://example.com/netts/reports", "role": "primary"}'
json
{
  "status": "success",
  "code": 10000,
  "data": {
    "id": 1,
    "url": "https://example.com/netts/reports",
    "role": "primary",
    "is_active": true,
    "created_at": "2026-09-06 17:05:12+00:00",
    "updated_at": "2026-09-06 17:05:12+00:00",
    "secret": "whsec_<64 hex characters>"
  }
}

密钥仅在此处显示一次。 之后将永远无法再次获取——无论是通过列表接口还是读取接口。收到后请立即保存。如果丢失,必须轮换生成新密钥:

bash
curl -s -X POST 'https://netts.io/apiv2/reports/webhooks/1/rotate-secret' \
  -H 'X-API-KEY: your-api-key' -H 'X-Real-IP: 203.0.113.10'

密钥轮换会立即生效,旧密钥将无法通过验证。如果您无法接受服务中断,请先部署新密钥。

管理

方法路径操作
GET/apiv2/reports/webhooks列出您的端点(不包含密钥)
GET/apiv2/reports/webhooks/{id}读取单个端点
PATCH/apiv2/reports/webhooks/{id}修改 url,或通过 is_active: false 暂停接收
DELETE/apiv2/reports/webhooks/{id}删除端点

URL 必须是公网 HTTPS 地址。环回地址、私有地址和链路本地地址都会被拒绝,URL 中包含凭证也会被拒绝。任何被拒绝的情况都会返回 422 状态码及具体原因。该检查会在每次推送前立即重新执行,因此若端点域名后续解析为私有地址,将停止接收推送。

推送内容

json
{
  "event": "report.ready",
  "delivery_id": 4,
  "order_id": "REPxxxxxxxxxxxx",
  "order_type": "statement",
  "client_request_id": "stmt-2026-09-usdt",
  "status": "done",
  "format": "csv",
  "download_url": "/apiv2/reports/REPxxxxxxxxxxxx/download",
  "expires_at": "2026-10-06 15:48:04+00:00",
  "artifact": { "sha256": "…", "size_bytes": 696 },
  "confirmed_at": "2026-09-06T15:48:04Z"
}
字段描述
eventreport.ready — 处理程序的路由键
delivery_id去重键。 同时作为 X-Netts-Delivery 请求头发送
order_id将报告加入队列时获取的订单号
order_typestatementbalance_at_date
download_url获取文件的相对路径,基于 https://netts.io
artifact.sha256校验和,便于您校验下载的文件
confirmed_atUTC 时间

所有时间戳均为 UTC。

验证签名

X-Netts-Signature: sha256=<hex>
X-Netts-Timestamp: <unix seconds>
X-Netts-Delivery:  <delivery_id>

签名是对 "<timestamp>." + 原始请求体 计算的 HMAC-SHA256,使用接收该请求的端点对应的密钥进行计算。请在固定时间内进行比对,并拒绝时间戳超出 ±5 分钟窗口的任何请求。

python
import hmac, hashlib, time

def verify(raw_body: bytes, sig_header: str, ts_header: str, secret: str) -> bool:
    if abs(time.time() - int(ts_header)) > 300:      # 防重放
        return False
    signed = f"{ts_header}.".encode() + raw_body
    expected = "sha256=" + hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig_header)

请使用接收到该请求的 URL 所属的密钥进行签名校验:主端点与备用端点的密钥不同。

至少一次推送

网络响应丢失会触发重试,因此同一事件可能会送达两次。

  1. 依据 delivery_id 去重。 重复收到的通知在您侧必须作为无操作(no-op)处理。
  2. 处理业务前先验证签名,切勿后置验证。
  3. 仅在成功保存事件后才返回 2xx 任何其他响应或超时都会被视为失败并触发重试。

针对单个端点的重试间隔依次为:1 分钟、5 分钟、15 分钟、1 小时、6 小时和 24 小时——共尝试 6 次,历时略超过 31 小时。当这些尝试耗尽且您配置了 backup 时,推送将转至备用端点,并使用备用端点自有的密钥重新开始该重试计划。在整个过程中 delivery_id 保持不变,因此在主端点失败而在备用端点成功的事件仍然是同一个事件。

不会跟随重定向。

速率限制

每个端点 每秒 10 次请求,所有客户端共享此配额。

错误响应

注册成功返回 201,删除成功返回无响应体的 204,其余正常情况返回 200

HTTP 状态码含义
401密钥缺失或无效,或者来源 IP 未在白名单中
404您的账户中不存在该端点
409请求的角色已被占用 — role primary is already taken
422URL 被拒绝,或者 PATCH 请求体中未包含可修改的内容
429超出速率限制

被拒绝的 URL 会返回 422 并附带明确原因,以便您可以直接向输入该地址的人员展示:

json
{"status": "error", "code": -4, "msg": "url: Value error, invalid webhook_url: resolved address 127.0.0.1 is not public"}

提示文案包括 only https:// URLs are allowedcredentials in URL are not allowed 以及 resolved address <ip> is not public。最后一项在注册时会进行解析,并在每次推送前立即重新解析,因此若主机名后续指向私有地址,将停止接收推送。

相关内容