负载格式
每次 Webhook 投递都是一个带有 JSON 请求体的 POST 请求。请求头携带用于防重放保护、签名校验和重试跟踪的元数据。
请求体
每个事件使用相同的信封:
{
"id": "evt_8c1f2a3b4d",
"type": "strategy.deployed",
"created_at": "2026-04-29T12:00:00.000Z",
"data": { ... }
}
| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 唯一事件标识,格式为 evt_<10-12 hex>。用于幂等去重。 |
type | string | 事件类型;取下文枚举的某个值。 |
created_at | string | ISO 8601 UTC 时间戳,精度到毫秒,表示事件在服务端生成的时间。 |
data | object | 与事件类型相关的负载。各类型的 schema 详见下文。 |
请求头
| 请求头 | 说明 |
|---|---|
X-PipAI-Event-Id | 唯一事件 ID。与 body.id 相同。用于幂等。 |
X-PipAI-Event-Type | 事件类型。与 body.type 相同。便于在不解析请求体的情况下进行路由。 |
X-PipAI-Webhook-Id | 本次投递所属的 Webhook 订阅(例如 wh_2a4f10)。当一个端点服务多个订阅时很有用。 |
X-PipAI-Delivery-Id | 每次投递的唯一标识。同一 event_id 作为重试再次投递时,多次尝试间会复用同一个 Delivery ID。 |
X-PipAI-Delivery-Attempt | 整型尝试计数,从 1 开始。在重试计划中递增到 10 后会放弃投递。 |
X-PipAI-Timestamp | 投递时的 Unix 毫秒(ms)。用于在签名校验时计算重放窗口。 |
X-PipAI-Signature | 十六进制编码的 HMAC-SHA256(webhook_secret, "{timestamp}.{raw_body}")。详见 签名校验。 |
事件类型
通配符订阅(strategy.*、backtest.*、account.* 或 *)在注册时也被接受——参见 创建 Webhook。
| 事件类型 | 说明 | 数据 schema |
|---|---|---|
strategy.created | 策略以 draft 状态被创建。 | strategy.created |
strategy.deployed | 策略已部署到生产环境(如果 dry_run 则为模拟交易)。 | strategy.deployed |
strategy.paused | 策略被暂停;不会再开新仓。 | strategy.paused |
strategy.stopped | 策略已停止(终态,不可恢复)。 | strategy.stopped |
strategy.position_opened | 策略开了一个新仓位。 | strategy.position_opened |
strategy.position_closed | 一个开仓被平仓;PnL 已最终确定。 | strategy.position_closed |
strategy.order_filled | 策略下的订单成交(全部或部分)。 | strategy.order_filled |
strategy.error | 策略遇到不可恢复的错误并已停止。 | strategy.error |
backtest.job_done | 一个回测任务成功完成。 | backtest.job_done |
backtest.job_failed | 一个回测任务因错误中止。 | backtest.job_failed |
account.balance_low | 受监控的资产余额降到配置阈值以下。 | account.balance_low |
account.api_key_rotated | 账户上的某个 API 密钥已轮换。 | account.api_key_rotated |
各事件数据 schema
strategy.created
{
"strategy_id": "strat_8f2a1b",
"name": "BTC grid 1h",
"status": "draft"
}
strategy.deployed
{
"strategy_id": "strat_8f2a1b",
"name": "BTC grid 1h",
"capital": "10000.00",
"leverage": 3,
"deployed_at": "2026-04-29T12:00:00.000Z"
}
strategy.paused
{
"strategy_id": "strat_8f2a1b",
"status": "paused"
}
strategy.stopped
{
"strategy_id": "strat_8f2a1b",
"status": "stopped"
}
strategy.position_opened
{
"strategy_id": "strat_8f2a1b",
"position_id": "pos_19acb2",
"symbol": "BTCUSDT",
"side": "long",
"entry_price": "67234.50",
"qty": "0.05",
"leverage": 3,
"opened_at": "2026-04-29T12:00:01.245Z"
}
strategy.position_closed
{
"strategy_id": "strat_8f2a1b",
"position_id": "pos_19acb2",
"symbol": "BTCUSDT",
"side": "long",
"entry_price": "67234.50",
"exit_price": "68110.00",
"qty": "0.05",
"exit_qty": "0.05",
"pnl": "43.78",
"leverage": 3,
"opened_at": "2026-04-29T12:00:01.245Z",
"closed_at": "2026-04-29T13:42:18.880Z"
}
strategy.order_filled
{
"strategy_id": "strat_8f2a1b",
"order_id": "ord_3c9df4",
"symbol": "BTCUSDT",
"side": "buy",
"type": "limit",
"price": "67234.50",
"qty": "0.05",
"filled_at": "2026-04-29T12:00:01.180Z"
}
strategy.error
{
"strategy_id": "strat_8f2a1b",
"error_code": "ORDER_REJECTED",
"message": "Exchange rejected order: insufficient margin"
}
backtest.job_done
{
"job_id": "bt_4d2e7c1f",
"metrics": {
"total_return": "0.184",
"sharpe": "1.62",
"max_drawdown": "-0.073",
"win_rate": "0.541",
"total_trades": 312,
"profit_factor": "1.78"
}
}
完整的指标定义参见 回测指标 参考文档。
backtest.job_failed
{
"job_id": "bt_4d2e7c1f",
"error_code": "TIMEOUT",
"message": "Job exceeded maximum runtime of 30 minutes"
}
account.balance_low
{
"asset": "USDT",
"balance": "12.50",
"threshold": "100.00"
}
阈值通过创建 Webhook 时的 balance_low_threshold 按 Webhook 配置——参见 创建 Webhook。
account.api_key_rotated
{
"key_id": "key_7a91c2",
"rotated_at": "2026-04-29T12:00:00.000Z"
}
确认
你的端点必须在收到请求后的 10 秒 内返回 2xx HTTP 状态。任何其他结果——非 2xx 响应、响应过慢、TLS 错误或连接失败——都会被视为投递失败,并按 概览 中的计划进入重试队列。
响应体会被忽略。空的 200 OK 即可。
如果你需要在响应事件时执行较重的工作,请同步确认并将工作分发到后台队列。在处理事件期间一直占用连接,会让投递工作线程饥饿,并触发不必要的重试。