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