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を、16進数で表したものです。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時間です。5回目の再試行の後、そのエンドポイントは
failingと記録され、新しいイベントの受信を止め、所有者にメールが届きます。
エンドポイントを直したうえで、ダッシュボードか、PATCH /v1/webhooks/{id}に
{"status": "active"}を指定して再度有効にしてください。取りこぼしたイベントは自動では
再送されません。配信ログ(GET /v1/webhooks/{id}/deliveriesまたはダッシュボード)に
すべてのペイロードが残っているので、突き合わせができます。
配信が1回成功すると、失敗の連続はリセットされます。
テスト
テスト送信ボタン(またはPOST /v1/webhooks/{id}/test)は、"data": { "test": true }
を含む本物の署名付きイベントを、本番のイベントと同じ経路で配信します。配信ログには、あなたの
エンドポイントの応答が表示されます。