Skip to Content
QuasarWebhooks 回调

Webhook 回调通知 (Webhooks)

当同步至 Quasar 的交易在链上达成终态(成功、失败或被加速替换)时,Quasar 会自动向您应用配置的 Webhook 终端节点发起加密签名的 HTTP POST 请求。每个请求均采用独立的 Endpoint 密钥进行 HMAC-SHA256 验签,使得您的后端可以在无需轮询链上节点的前提下,实现确定性的订单核销与余额变更。


🛠️ 注册与管理 Webhook 节点

登录开发者控制台,在对应应用的 Webhooks 面板下添加订阅节点:

配置字段规范要求与参数说明
URL接收回调的 HTTP 地址。生产环境强制要求 https://,本地调试允许配置单一 localhost 节点。
Events支持全选 *,或针对性订阅:transaction:success, transaction:failed, transaction:replaced。
Transaction type filter* 匹配全量业务类型,或填入在 Pulsar 中定义的具体业务指令(如 SWAP, MINT 等)。
Active停用后将立即挂起所有新事件派发与失败重试。

系统将为该节点生成独有的 签名密钥 (Signing Secret):以 whsec_ 开头的 64 位十六进制字符串(32 字节随机密钥),且端到端加密存储。每个应用最多可创建 500 个接收节点。


📨 回调请求规范与载荷结构

POST /api/webhooks/quasar HTTP/1.1Content-Type: application/jsonUser-Agent: Quasar-Webhook-Worker/1.0 (TuwaIO)x-quasar-signature: 5f3c… (hex HMAC-SHA256 of the body)x-quasar-event: Success
{ "txKey": "0x3a5f…", "hash": "0x3a5f…", "status": "Success", "action": "Success", "txType": "SWAP", "chainId": "1", "timestamp": 1790000000, "metadata": { "tokenIn": "USDC", "tokenOut": "ETH", "amount": 100 }}
载荷字段语义解析
txKey, hashPulsar 交易唯一幂等键以及对应的链上交易哈希(若已产出)。对于 EIP-5792 批次,txKey 为批次 ID,hash 为执行该批次的交易。
status, action最终状态:Success, Failed 或 Replaced;同时同步在 x-quasar-event 响应头中。
txType同步时客户端声明的业务类型字符串。
chainIdCAIP-2 标准网络标识符,例如 EVM 的 "1" 或 Solana 主网的 "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"。
timestampWebhook 投递任务生成的 Unix 时间戳(秒)。
replacedTxHashReplaced 时:占用此交易 nonce 的交易(如已找到)。
replacedReasonReplaced 时:repriced(相同交易、更高手续费,即钱包的 Speed up)、cancelled、replaced(另一笔交易)或 unknown(其 nonce 被无法找到的交易占用,款项可能已转出)。
metadataPulsar 客户端在发起交易时携带的完整业务 Payload。

🔐 服务端 HMAC 验签与幂等处理

HTTP 请求头 x-quasar-signature 是基于完整原始 Body 计算的 HMAC-SHA256 签名。在解析 JSON 之前,必须针对原始字节执行恒定时间 (Constant-Time) 比对,防止时序攻击:

src/app/api/webhooks/quasar/route.ts
import { createHmac, timingSafeEqual } from 'node:crypto'; export async function POST(request: Request) { const secret = process.env.QUASAR_WEBHOOK_SECRET; const signature = request.headers.get('x-quasar-signature'); if (!secret || !signature) { return Response.json({ error: 'Missing signature' }, { status: 401 }); } const body = await request.text(); const expected = Buffer.from(createHmac('sha256', secret).update(body).digest('hex'), 'hex'); const received = Buffer.from(signature, 'hex'); if (received.length !== expected.length || !timingSafeEqual(received, expected)) { return Response.json({ error: 'Invalid signature' }, { status: 401 }); } const event = JSON.parse(body) as { txKey: string; status: string; txType: string; metadata: unknown }; if (event.status === 'Success') { // Fulfill the order, credit the balance, notify the user... } return Response.json({ received: true });}

交易失败的情形:

  • Solana:带有链上错误的交易在确认后立即标记为 Failed,无需等待最终确认。从未上链的签名会在链高度超过其 lastValidBlockHeight 时标记为 Failed(Pulsar 会为通过 signAndSendSolanaTx 发送的交易保存该值;错误信息为 blockhash 已过期),否则在同步一小时后标记。
  • EIP-5792 批次:若您的应用始终未发送其交易哈希,将在同步一小时后标记为 Failed(同步指南)。
请在 10 秒超时窗口内尽快返回 2xx 确认状态;耗时任务请推入异步队列。业务处理逻辑请务必依据 (txKey, status) 实现幂等消费。

🔁 自动重试与投递审计日志

  • 因网络超时或返回非 2xx 状态码失败的投递,系统将进行最多 5 次指数退避重试(起始间隔 1 分钟)。
  • 控制台 Webhook Deliveries 页面记录全量请求流水,敏感关键词(如 secret, key, token)将自动脱敏。
  • 在调试或故障恢复后,可在控制台日志条目上点击一键重新投递,同一投递每分钟最多一次。
  • 追踪器可能跟丢交易,节点也会忘记被替换的哈希。当 Quasar 之后发现它已被打包或被替换时,记录会被更正,端点会再收到一个带有新 status 的 webhook:请以最后一个为准。
  • 投递日志最多保留 3 个月。如需更长的审计记录,请保存您的端点收到的事件。
  • 每次投递仅在首次尝试时消耗 1 个配额点数,后续重试完全免费(参见 配额与速率限制)。

💻 本地无公网 IP 调试 (Local Relay)

Quasar Cloud 无法直连本地 localhost。您可以在控制台配置唯一的本地节点(例如 http://localhost:3000/api/webhooks/quasar),并通过官方 CLI 的 SSE 中继服务实现无缝转发:

# .env.local: QUASAR_WEBHOOK_SECRET=whsec_... (the secret of the localhost endpoint)npx @tuwaio/quasar-sdk listen --forward-to http://localhost:3000/api/webhooks/quasar
最后更新于