Webhook
解析会话完成时的异步通知,无需轮询 API——订阅方式、投递验证,以及一个 n8n 集成示例。
与其不断轮询 GET /me/scrapes/{id} 等待 status 变为 completed,不如订阅一个 URL,
我们会在完成的那一刻主动向它发送 POST 请求。目前存在一种事件:scrape_session.completed。
POST /webhooks 端点。每个账户最多可拥有 5 个有效订阅。事件负载是一个指针,而不是数据本身
{
"event": "scrape_session.completed",
"user_id": "3e2f9a10-df34-4b8a-9c31-8e1d2f6a7b90",
"scrape_session_id": "b1f8b6b0-2f7d-4a1a-9a3c-2f6d8e9a1234",
"status": "completed",
"stats": { "total": 40, "pending": 0, "processing": 0, "merged": 38, "rejected": 1, "flagged": 1 },
"url": "https://data.marketninja.ru/v1/me/scrapes/b1f8b6b0-2f7d-4a1a-9a3c-2f6d8e9a1234/products"
}我们特意不把解析到的数据直接嵌入事件本身——要获取数据,请请求 url 字段中的地址
(授权方式与本站其他所有接口相同,都使用 Bearer 认证,且这次调用会计入您平常的每日配额,
与直接调用该端点完全一样)。这样设计有两个原因:每日数据配额只会在这一个端点上被计算,
并且这种精简的负载能保证同一个 webhook 无论会话中有 1 件商品还是 10,000 件商品,
处理起来都是一样的。
user_id 用于标识该事件属于您哪一个 Market Ninja 账户——如果您曾把多个账户的 webhook
指向同一个 URL(例如一个共用的自动化入口),这个字段可以帮助您区分它们。
验证投递
每个请求都携带两个请求头:
X-Marketninja-Event: scrape_session.completedX-Marketninja-Signature: t=1735689600,v1=5257a869e7bcd1d2...
签名是基于 ${timestamp}.${rawBody} 计算的 HMAC-SHA256,使用创建订阅时仅显示一次的
签名密钥。请务必用收到的原始请求体字符串进行校验——绝不要用重新序列化后的
JSON.stringify(JSON.parse(body)) 来比对:这无法保证字节级一致(字段顺序、空白字符等),
会导致校验悄无声息地失败。
import crypto from "node:crypto";
function isValidSignature(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(
signatureHeader.split(",").map((p) => p.split("="))
);
const expected = crypto
.createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(parts.v1),
Buffer.from(expected)
);
}t 是否过旧(通常几分钟的容差就足够)——我们这一侧不会对时间戳做任何容差限制。投递、重试与放弃时机
- 任何
2xx响应都会被视为投递成功——响应体不会被读取。 - 我们不会跟随重定向——
3xx会被当作明确的失败处理。 - 每次尝试的超时时间为 5 秒。
- 失败的尝试(网络错误、超时、
429或5xx)会按退避计划重试:大致间隔为 1 分钟、 5 分钟、30 分钟、2 小时、6 小时,最后再等 24 小时——最多重试 7 次,总跨度约为一天半—— 之后这一次具体的投递会被标记为永久失败。如果429响应带有Retry-After请求头, 会优先按该值执行,而不是固定计划。 - 任何其他非
2xx响应(例如400、404)会立即被视为永久失败——我们默认重试不会 改变您的端点给出的判断。 - 如果某个订阅累计了足够多次连续失败,它会被自动禁用——被禁用的订阅无法重新启用, 只能在扩展程序的设置页面重新创建一个新订阅。
https:// 地址访问——如果 target_url 解析为私有地址、回环地址或链路本地地址,我们会在创建订阅时就拒绝它(并且每次投递前都会重新检查)。如果要测试本地服务器,需要先搭建一个隧道(如 ngrok、Cloudflare Tunnel 等)。示例:在 n8n 中触发 LLM 价格分析
一个常见的用法:收到通知、取出数据、交给 LLM 处理、再把结果发送到某处。整个流程中, 只有两个节点是 Market Ninja 特有的;之后的一切完全由您自行决定。
-
一个 Webhook 节点作为触发器——
HTTP Method: POST,路径可任意选择。这就是您在 注册订阅时要填入的目标 URL。 -
紧接其后的一个 HTTP Request 节点,配置为对事件中的
url字段发起GET请求, 并使用 Bearer 认证:- URL:
{{ $json.body.url }} - Authentication:Generic Credential Type → Bearer Auth,凭证中保存您的某个
mn_live_...API 密钥。
其输出格式为
{ data: [...], meta: {...} }——与GET /me/scrapes/{id}/products始终返回的格式完全一致:每条提交记录一项,product字段在尚未合并时为null。 - URL:
-
接下来,您可以对
$json.data做任何真正需要的处理——例如用 LLM 节点生成价格趋势摘要、 发送 Slack/Telegram 通知、写入数据库,或者把这几步串联起来。这部分完全与 Market Ninja 无关,按普通 n8n 工作流的方式搭建即可。
200,无论后续工作流是否成功执行。我们这一侧显示的「已投递」状态,只能确认您的 Webhook 节点收到了通知——自动化本身是否成功执行,请以您自己工作流的执行历史为准。Last updated on