Webhook
Webhook を使うと、LabelGrid アカウント内でイベントが発生したときにリアルタイムで通知を受け取れます。Webhook でワークフローを自動化したり、外部システムと連携したりできます。
開発者の方へ: Webhook は API からプログラムで管理することもできます。エンドポイントと例については、LabelGrid API ドキュメントをご覧ください。
Webhook のしくみ
Section titled “Webhook のしくみ”- Webhook を設定する - URL と、どのイベントを受け取るかを指定します
- イベントが発生する - たとえば、リリースがストアに配信されます
- LabelGrid が POST リクエストを送信する - あなたのサーバーがイベントデータを受け取ります
- システムがそれを処理する - イベントに応じてワークフローを自動化します
Webhook へのアクセス
Section titled “Webhook へのアクセス”- 右上のプロフィールアイコンをクリックします
- ドロップダウンメニューから Webhooks を選択します
Webhook の作成
Section titled “Webhook の作成”- Create Webhook をクリックします
- この Webhook を識別するための Name を入力します
- 通知を受け取りたい URL を入力します
- この Webhook をトリガーする Events を選択します
- Create をクリックします
Webhook シークレット
Section titled “Webhook シークレット”Webhook を作成すると、シークレットキー が発行されます。受信したリクエストが実際に LabelGrid からのものかを検証するために使います。
- シークレットは安全に保管してください
- 受信リクエストの署名を検証してください
- 漏えいした場合は、シークレットを再生成してください
利用できるイベント
Section titled “利用できるイベント”次のイベントを受け取るように Webhook を設定できます。イベント識別子 は、ペイロードの event プロパティと X-Webhook-Event ヘッダーに表示される値です。
| イベント識別子 | 説明 |
|---|---|
delivery.completed | リリースが配信先へ正常に配信されたときに発生します |
delivery.failed | 配信先への配信が失敗したときに発生します |
takedown.completed | テイクダウンのリクエストが完了したときに発生します |
release.review.status_changed | リリースの審査ステータスが変わったときに発生します |
release.distributed | リリースが配信されたときに発生します |
payment.statement_ready | 支払い明細が閲覧できる状態になったときに発生します |
1 つの Webhook で複数のイベントを選ぶことも、イベントの種類ごとに別々の Webhook を作ることもできます。
Webhook の管理
Section titled “Webhook の管理”Webhook の一覧表示
Section titled “Webhook の一覧表示”Webhook の一覧には、次の情報が表示されます。
| 列 | 説明 |
|---|---|
| Name | 自分で付けた Webhook の名前 |
| URL | 通知の送信先 |
| Events | 設定したイベントの数 |
| Status | 有効か無効か |
| Success / Fail | 配信の成功回数と失敗回数 |
| Last Triggered | Webhook が最後に呼び出された時刻 |
Webhook の編集
Section titled “Webhook の編集”- Webhook の行で Edit の操作をクリックします
- 名前、URL、イベントを変更します
- Save をクリックします
有効化/無効化
Section titled “有効化/無効化”Webhook を削除せずに、有効・無効を切り替えられます。
- Active - Webhook が通知を受け取ります
- Inactive - Webhook は一時停止され、通知は送信されません
Webhook の削除
Section titled “Webhook の削除”- Webhook の行で Delete の操作をクリックします
- 削除を確定します
Webhook のテスト
Section titled “Webhook のテスト”本番で Webhook に頼る前に、テストしておきましょう。
- Webhook の Test の操作をクリックします
- LabelGrid が指定の URL にテスト用ペイロードを送信します
- エンドポイントがそれを正しく受信・処理できたかを確認します
Webhook ログの表示
Section titled “Webhook ログの表示”Webhook の動作を監視し、問題を調査できます。
- Webhook の View Logs の操作をクリックします
- すべての Webhook 配信の履歴が表示されます
各ログエントリーには、次の情報が表示されます。
| 項目 | 説明 |
|---|---|
| Event Type | この配信をトリガーしたイベント |
| Response Status | あなたのサーバーが返した HTTP ステータスコード |
| Duration | リクエストにかかった時間 |
| Attempt | 再試行の回数 |
| Timestamp | 配信が発生した時刻 |
Webhook ペイロードの形式
Section titled “Webhook ペイロードの形式”イベントが発生すると、LabelGrid は指定の URL に JSON ペイロードを含む POST リクエストを送信します。
{ "event": "delivery.completed", "timestamp": "2026-05-05T10:00:00+00:00", "webhook_id": "123", "data": { // Event-specific data }}timestamp フィールドは ISO 8601 形式です。webhook_id は設定した Webhook の ID で、X-Webhook-Id ヘッダーと一致します。
イベントペイロード
Section titled “イベントペイロード”data オブジェクトの構造は event の種類によって異なります。以下のフィールド型はすべて、ペイロードにシリアライズされた状態の JSON 型です。
delivery.completed
Section titled “delivery.completed”リリースの配信が最終的な成功状態に達したときに、配信先ごとに 1 回発生します。
{ "event": "delivery.completed", "timestamp": "2026-05-18T10:00:00+00:00", "webhook_id": "123", "data": { "distro_queue_id": 456, "release_id": 789, "release_cat": "ABC123", "outlet_id": 12, "outlet_name": "Spotify", "status": "complete" }}| フィールド | 型 | 説明 |
|---|---|---|
distro_queue_id | integer | この配信処理の内部キュー ID |
release_id | integer | 配信されたリリース |
release_cat | string | null | リリースのカタログ参照番号 |
outlet_id | integer | 配信先の ID |
outlet_name | string | null | 配信先の表示名(例: "Spotify") |
status | string | このイベントでは常に "complete" |
delivery.failed
Section titled “delivery.failed”リリースの配信が最終的な失敗状態に達したときに、配信先ごとに 1 回発生します。ペイロードは delivery.completed と同じで、message フィールドが追加されます。
{ "event": "delivery.failed", "timestamp": "2026-05-18T10:00:00+00:00", "webhook_id": "123", "data": { "distro_queue_id": 456, "release_id": 789, "release_cat": "ABC123", "outlet_id": 12, "outlet_name": "Spotify", "status": "error", "message": "Outlet rejected the delivery: missing ISRC." }}| フィールド | 型 | 説明 |
|---|---|---|
status | string | error、fault、rejected、batch_exception のいずれか |
message | string | null | 配信先または配信パイプラインからの失敗理由 |
takedown.completed
Section titled “takedown.completed”テイクダウンのリクエストが成功したときに、配信先ごとに 1 回発生します。delivery.completed と同じ構造に、takedown: true のフラグが追加されます。
{ "event": "takedown.completed", "timestamp": "2026-05-18T10:00:00+00:00", "webhook_id": "123", "data": { "distro_queue_id": 456, "release_id": 789, "release_cat": "ABC123", "outlet_id": 12, "outlet_name": "Spotify", "status": "complete", "takedown": true }}release.distributed
Section titled “release.distributed”リリースが distributed(配信済み)の配信状態に移行したときに、リリースごとに 1 回発生します。発生するのは distributed への移行時のみで、すでに配信済みのリリースをその後に保存しても発生しません。
{ "event": "release.distributed", "timestamp": "2026-05-18T10:00:00+00:00", "webhook_id": "123", "data": { "release_id": 789, "release_cat": "ABC123", "release_title": "Summer EP", "delivery_status": "distributed" }}release.review.status_changed
Section titled “release.review.status_changed”リリースが審査ステータスの間を移動するたびに発生します。
{ "event": "release.review.status_changed", "timestamp": "2026-05-18T10:00:00+00:00", "webhook_id": "123", "data": { "release_id": 789, "release_cat": "ABC123", "release_title": "Summer EP", "previous_status": "to_review", "new_status": "approved" }}| フィールド | 型 | 説明 |
|---|---|---|
previous_status | string | 変更前のステータス。draft、to_review、approved、rejected、require_changes、audit のいずれか |
new_status | string | 変更後のステータス。値の範囲は同じ |
payment.statement_ready
Section titled “payment.statement_ready”支払い明細が生成され、閲覧できる状態になったときに発生します。
{ "event": "payment.statement_ready", "timestamp": "2026-05-18T10:00:00+00:00", "webhook_id": "123", "data": { "payment_request_id": 1024, "invoice_number": "INV-2026-001", "period": "2026-04-30", "amount": 1234.56, "total_due_usd": 1234.56, "currency": "USD" }}| フィールド | 型 | 説明 |
|---|---|---|
payment_request_id | integer | 内部の支払いリクエスト ID |
invoice_number | string | 明細の請求書参照番号 |
period | string | null | 対象期間の末日(ISO 8601 の日付形式 YYYY-MM-DD) |
amount | number | currency で表した明細金額 |
total_due_usd | number | USD に換算した明細合計 |
currency | string | ISO 4217 の通貨コード(既定は USD) |
Webhook 署名の検証
Section titled “Webhook 署名の検証”すべての Webhook 配信には署名が付与されており、それが実際に LabelGrid から送られたものかを検証できます。イベントを処理する前に、必ず署名を検証してください。
リクエストヘッダー
Section titled “リクエストヘッダー”すべての Webhook の POST リクエストには、次のヘッダーが含まれます。
| ヘッダー | 説明 |
|---|---|
X-Webhook-Signature | 生のリクエストボディの HMAC-SHA256。小文字の 16 進数で、アルゴリズムの接頭辞は付きません |
X-Webhook-Timestamp | 配信の ISO 8601 タイムスタンプ(ボディ内の timestamp プロパティと同じ値) |
X-Webhook-Event | イベント識別子(例: delivery.completed) |
X-Webhook-Id | 配信を受け取る Webhook の ID |
User-Agent | LabelGrid-Webhooks/1.0 |
Content-Type | application/json |
アルゴリズム
Section titled “アルゴリズム”- アルゴリズム: HMAC-SHA256
- エンコーディング: 小文字の 16 進数
- 接頭辞: なし。値は
sha256=...ではなく、16 進ダイジェストそのものです - 署名対象: 生の JSON リクエストボディ全体(ボディ自体にタイムスタンプがプロパティとして含まれるため、タイムスタンプも暗黙的に署名されます)
- JSON のパースや変換を行う前に、生のリクエストボディ を読み取ります。パース済みの JSON を再シリアライズすると、バイト列が変わって署名が一致しなくなることがあります。
HMAC-SHA256(raw_body, your_webhook_secret)を計算し、小文字の 16 進ダイジェストを取得します。- 定数時間比較を使って
X-Webhook-Signatureと照合します。 - (推奨)
X-Webhook-Timestampがリプレイ許容時間より古い場合は、リクエストを拒否します。許容時間は 5 分を目安にしてください。
PHP の例
Section titled “PHP の例”$rawBody = file_get_contents('php://input');$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
$expected = hash_hmac('sha256', $rawBody, $webhookSecret);
if (! hash_equals($expected, $signature)) { http_response_code(401); exit('Invalid signature');}
// Reject deliveries older than 5 minutesif (abs(time() - strtotime($timestamp)) > 300) { http_response_code(401); exit('Stale delivery');}
$payload = json_decode($rawBody, true);// ... process the eventhttp_response_code(200);Node.js の例
Section titled “Node.js の例”const crypto = require('crypto');
// Express: capture raw body BEFORE any JSON middlewareapp.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => { const rawBody = req.body; // Buffer const signature = req.header('X-Webhook-Signature') || ''; const timestamp = req.header('X-Webhook-Timestamp') || '';
const expected = crypto .createHmac('sha256', webhookSecret) .update(rawBody) .digest('hex');
const sigBuf = Buffer.from(signature, 'hex'); const expBuf = Buffer.from(expected, 'hex');
if (sigBuf.length !== expBuf.length || !crypto.timingSafeEqual(sigBuf, expBuf)) { return res.status(401).send('Invalid signature'); }
if (Math.abs(Date.now() - new Date(timestamp).getTime()) > 5 * 60 * 1000) { return res.status(401).send('Stale delivery'); }
const payload = JSON.parse(rawBody.toString('utf8')); // ... process the event res.sendStatus(200);});Python の例
Section titled “Python の例”import hmac, hashlibfrom datetime import datetime, timezone
raw_body = request.get_data() # Flask: bytes, before any JSON parsingsignature = request.headers.get('X-Webhook-Signature', '')timestamp = request.headers.get('X-Webhook-Timestamp', '')
expected = hmac.new( webhook_secret.encode('utf-8'), raw_body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, signature): return ('Invalid signature', 401)
delivery_time = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))if abs((datetime.now(timezone.utc) - delivery_time).total_seconds()) > 300: return ('Stale delivery', 401)
return ('', 200) # process the event, then ackよくある落とし穴
Section titled “よくある落とし穴”- ハッシュ化の前にボディを再シリアライズする。 JSON を自動でパースするフレームワーク(Express の
express.json()、Laravel の既定のリクエストボディなど)は、元のバイト列を失います。まず生のボディを取得してください。 - 定数時間でない比較(
==、===)を使う。 タイミング攻撃を受ける可能性があります。常にhash_equals(PHP)、crypto.timingSafeEqual(Node)、hmac.compare_digest(Python)、または使用言語の同等のものを使ってください。 sha256=の接頭辞を期待する。 ヘッダーの値は接頭辞のない 16 進ダイジェストそのものです。- タイムスタンプのチェックを省く。 これを省くと、漏えいした署名がいつまでもリプレイされる恐れがあります。
制限と信頼性
Section titled “制限と信頼性”リクエストの制限
Section titled “リクエストの制限”| 制限 | 値 |
|---|---|
| リクエストのタイムアウト | 10 秒 |
| 最大ペイロードサイズ | 64 KB |
| ユーザーあたりの最大 Webhook 数 | 10 |
エンドポイントが 10 秒以内に応答しない場合、その配信は失敗として扱われ、再試行されます。
再試行スケジュール
Section titled “再試行スケジュール”エンドポイントが 2xx 以外のステータスを返すかタイムアウトした場合、LabelGrid は指数バックオフで再試行します。
| 試行 | 再試行までの待機時間 |
|---|---|
| 1 → 2 | 30 秒 |
| 2 → 3 | 1 分 |
| 3 → 4 | 2 分 |
| 4 → 5 | 4 分 |
| 5 → 6 | 8 分 |
| 6 → 7 | 16 分 |
| 7 → 8 | 32 分 |
| 8 → 9 | 64 分 |
| 9 → 10 | 128 分 |
各間隔には 0〜30 秒のジッターが含まれます。10 回試行しても成功しない場合(合計で約 4.5 時間が経過)、その配信は恒久的な失敗として記録され、それ以上の再試行は行われません。
Webhook の配信失敗が 累計 100 回 に達すると、その Webhook は自動的に無効化されます。エンドポイントを修正したうえで、Webhook の一覧から手動で再有効化してください。無効化された Webhook を再有効化すると、失敗回数がリセットされます。
信頼性のためのベストプラクティス
Section titled “信頼性のためのベストプラクティス”- 2xx レスポンス を素早く(10 秒以内に)返す
- 確認応答を返したあとで、データを非同期に処理する
- すべてのリクエストで署名を検証する(Webhook 署名の検証 を参照)
- Webhook の一覧で失敗回数を監視する
- イベントの取りこぼしを調査するときは、配信ログを確認する
通知の自動化
Section titled “通知の自動化”- リリースが公開されたら Slack にメッセージを送る
- 配信が失敗したらチームにメールを送る
- 社内ダッシュボードを更新する
ワークフローの自動化
Section titled “ワークフローの自動化”- リリースが配信されたらマーケティングキャンペーンを開始する
- 新しいコンテンツが利用可能になったらウェブサイトを更新する
- 外部のプロジェクト管理ツールにステータスを同期する
監視とアラート
Section titled “監視とアラート”- 配信失敗を即座にアラートで受け取る
- 配信の進捗をリアルタイムで追跡する
- 審査ステータスの変化を監視する
トラブルシューティング
Section titled “トラブルシューティング”Webhook がイベントを受け取らない
Section titled “Webhook がイベントを受け取らない”- ステータスを確認する - Webhook は Active になっていますか?
- URL を確認する - エンドポイントはインターネットからアクセスできますか?
- イベントを確認する - 正しいイベントが選択されていますか?
- ログを確認する - エラーは記録されていませんか?
失敗回数が多い
Section titled “失敗回数が多い”- エンドポイントを確認する - 200 OK を返していますか?
- 応答時間を確認する - タイムアウト内に応答していますか?
- エラーメッセージを確認する - 何が失敗していますか?
- 手動でテストする - テスト用 Webhook を送ってみる
シークレットの再生成
Section titled “シークレットの再生成”Webhook シークレットが漏えいした場合:
- Webhook の設定で Regenerate Secret をクリックします
- 新しいシークレットでアプリケーションを更新します
- 古いシークレットはただちに無効になります
サポートが必要ですか?
Section titled “サポートが必要ですか?”Webhook についてご不明な点がありましたら、サポートチームにお問い合わせください。