跳到正文
LinkProfit

Webhook

带签名的事件投递:可用事件、用 JavaScript 和 Python 验证 X-LinkProfit-Signature、重试机制与失败状态。

更新于 2026年8月13日

Webhook 以 JSON POST 请求的形式把事件推送到你的端点,无需轮询。可以在控制台中注册端点(设置 → Webhook),也可以通过 POST /v1/webhooks 注册;签名密钥只在创建时显示一次。

事件

| 事件 | 触发时机 | 适用范围 | |---|---|---| | link.created / link.updated / link.deleted | 短链接发生变更——通过控制台、API 或批量导入 | 工作区端点和合作伙伴端点 | | domain.pending_ssl | DNS 已验证,证书正在签发 | 工作区和合作伙伴 | | domain.activated | 该域名开始承载流量 | 工作区和合作伙伴 | | domain.error | 开通失败,详情见载荷内容 | 工作区和合作伙伴 | | click.threshold | 达到每月可统计点击量上限的 80% / 100% | 工作区和合作伙伴 | | conversion.created | 记录了一笔转化:归因到某次点击的订单、注册或自定义转化目标 | 工作区和合作伙伴 | | workspace.subscribed | 客户支付了订阅的第一张账单 | 仅合作伙伴 | | workspace.past_due | 客户付款失败 | 仅合作伙伴 | | workspace.suspended | 客户被暂停(催缴或人工操作) | 仅合作伙伴 | | payment.succeeded | 客户付款已结清,附带费用明细 | 仅合作伙伴 | | payment.refunded | 某笔付款已退款 | 仅合作伙伴 |

投递内容

POST /your/endpoint HTTP/1.1
Content-Type: application/json
X-LinkProfit-Event: link.created
X-LinkProfit-Delivery: dlv_8Yq2…
X-LinkProfit-Signature: t=1755081600,v1=5f8a2c…
{
  "id": "dlv_8Yq2…",
  "type": "link.created",
  "created_at": "2026-08-13T10:00:00.000Z",
  "data": { "id": "lnk_…", "domain": "go.your-brand.com", "slug": "x7f2q1z", "url": "https://example.com" }
}

请在 10 秒内返回任意 2xx 响应。其他任何情况——包括超时——都算作失败,并会安排重试。投递可能乱序到达,极少数情况下还会重复到达两次:请按 id 去重。

验证签名

签名是用你的端点密钥对 `${t}.${rawBody}` 计算的 HMAC-SHA256,并以十六进制编码。请始终针对原始请求体进行验证,且要在任何 JSON 解析之前完成;同时拒绝早于 5 分钟的时间戳。

import { createHmac, timingSafeEqual } from "node:crypto";

function verifySignature(secret, rawBody, header, toleranceSeconds = 300) {
  const parts = Object.fromEntries(
    header.split(",").map((piece) => piece.split("=", 2)),
  );
  if (!parts.t || !parts.v1) return false;
  if (Math.abs(Date.now() / 1000 - Number(parts.t)) > toleranceSeconds) return false;

  const expected = createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`)
    .digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1);
  return a.length === b.length && timingSafeEqual(a, b);
}
import hashlib
import hmac
import time


def verify_signature(secret: str, raw_body: bytes, header: str, tolerance: int = 300) -> bool:
    parts = dict(piece.split("=", 1) for piece in header.split(",") if "=" in piece)
    timestamp, signature = parts.get("t"), parts.get("v1")
    if not timestamp or not signature:
        return False
    if abs(time.time() - int(timestamp)) > tolerance:
        return False

    expected = hmac.new(
        secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

重试与失败状态

第一次尝试是立即进行的。失败后按固定的时间表重试:1 分钟 → 5 分钟 → 30 分钟 → 2 小时 → 12 小时。第五次重试之后,该端点会被标记为 failing,不再接收新事件,并且所有者会收到一封邮件。

修复端点之后,在控制台中重新启用它,或者调用 PATCH /v1/webhooks/{id} 并传入 {"status": "active"}。错过的事件不会自动重放——投递日志(GET /v1/webhooks/{id}/deliveries 或控制台)会展示每一条载荷,方便你自行核对补齐。

一次成功投递会重置连续失败的计数。

测试

发送测试按钮(或 POST /v1/webhooks/{id}/test)会通过与生产事件完全相同的链路,投递一条真实的、带签名的事件,其中 "data": { "test": true }——投递日志会显示你的端点返回的响应。