Webhook 通知
汎用 Webhook を使って、任意の HTTPS エンドポイントにインシデント通知を JSON 形式で送信できます。自社のシステムや自動化ツールとの連携に便利です。
- HTTPS 必須: HTTP(非暗号化)の URL は使用できません
- パブリックエンドポイント: プライベートネットワークの URL はブロックされます
- 署名検証用シークレット: 1 文字以上の任意の文字列
外部サービス側の準備
Section titled “外部サービス側の準備”- インターネットから到達できる HTTPS エンドポイントを用意し、
POSTの JSON ボディを受け取れるようにする - Manako と受信側だけが共有する署名検証用シークレットを生成する
- 受信時に raw リクエストボディと
X-Manako-Signatureを使って HMAC-SHA256 署名を検証する - 正常に受理したときは 2xx を返す。3xx リダイレクトは追従されません
Manako での設定
Section titled “Manako での設定”- ダッシュボードで「設定」>「連携」を開き、Webhook の「設定」を選択
- 名前に識別しやすい名前を入力
- Webhook URL (HTTPS) に受信先 URL を入力
- Secret に受信側と共有するシークレットを入力
- 「追加」を選択
通知は POST リクエストとして送信されます。Content-Type は application/json です。
共通フィールド
Section titled “共通フィールド”すべてのイベントに含まれるフィールド:
| フィールド | 型 | 説明 |
|---|---|---|
event | string | イベント種別 |
teamId | string | チーム ID |
timestamp | string | ISO 8601 形式のタイムスタンプ |
monitorName、monitorId、incidentId はインシデントイベントに含まれます。メンテナンスイベントは代わりに monitorIds と monitorNames を含みます。
イベント別追加フィールド
Section titled “イベント別追加フィールド”| イベント | フィールド | 型 | 説明 |
|---|---|---|---|
incident.created | monitorUrl | string | 監視対象の URL |
incident.created | severity | string | 重大度("critical" または "warning") |
incident.created / incident.resolved | title | string | undefined | 手動インシデントのタイトル(自動インシデントでは省略) |
maintenance.started | monitorIds, monitorNames, maintenanceUntil | string[] / string | 対象モニターと終了予定時刻 |
maintenance.ended | monitorIds, monitorNames | string[] | 対象モニター |
ペイロード例
Section titled “ペイロード例”{ "event": "incident.created", "monitorName": "API Server", "monitorId": "01JWAB1234567890ABCDEF", "teamId": "01JWAB0987654321FEDCBA", "incidentId": "01JWABINCIDENT12345678", "monitorUrl": "https://api.example.com/health", "severity": "critical", "timestamp": "2025-01-15T10:30:00.000Z"}{ "event": "incident.resolved", "monitorName": "API Server", "monitorId": "01JWAB1234567890ABCDEF", "teamId": "01JWAB0987654321FEDCBA", "incidentId": "01JWABINCIDENT12345678", "timestamp": "2025-01-15T10:45:00.000Z"}通知リクエストには X-Manako-Signature ヘッダーが付与されます。リクエストボディの HMAC-SHA256 署名をシークレットで検証することで、リクエストが Manako から送信されたものであることを確認できます。
署名のフォーマットは sha256=\{hex_digest\} です。
検証コード例
Section titled “検証コード例”import crypto from "node:crypto";
function verifySignature(body, secret, signature) { const expected = "sha256=" + crypto.createHmac("sha256", secret).update(body).digest("hex"); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(signature), );}
// Express の例app.post("/webhook", express.text({ type: "application/json" }), (req, res) => { const signature = req.headers["x-manako-signature"]; if (!verifySignature(req.body, process.env.WEBHOOK_SECRET, signature)) { return res.status(401).send("Invalid signature"); } const payload = JSON.parse(req.body); console.log(`Event: ${payload.event}, Monitor: ${payload.monitorName}`); res.status(200).send("OK");});import hashlibimport hmacimport os
def verify_signature(body: bytes, secret: str, signature: str) -> bool: expected = "sha256=" + hmac.new( secret.encode(), body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, signature)
# Flask の例@app.route("/webhook", methods=["POST"])def webhook(): signature = request.headers.get("X-Manako-Signature", "") if not verify_signature( request.get_data(), os.environ["WEBHOOK_SECRET"], signature ): return "Invalid signature", 401 payload = request.get_json() print(f"Event: {payload['event']}, Monitor: {payload['monitorName']}") return "OK", 200トラブルシューティング
Section titled “トラブルシューティング”- 設定時に URL エラーになる: HTTPS で公開され、DNS 解決後もプライベート/予約済みアドレスに到達しない URL が必要です。
- 受信側がリダイレクトする: Manako は
redirect: "manual"で送信するため、最終受信 URL を直接設定してください。 - 署名が一致しない: JSON を再シリアライズせず、受信した raw body に対して
sha256={hex}を計算します。Manako に保存した Secret と同じ値を使ってください。 - テストは届くが通常通知が届かない: テストの
eventはtestです。通常通知ではモニター個別の通知先関連付けも確認してください。関連付けがすべて無効でもチーム全体へはフォールバックしません。 - 短時間の通知が途中から届かない: 同じモニターで 10 分以内に 3 回を超える状態変化があるとフラップ抑制が働きます。
- 重複して見える: 同じインシデント・チャンネル・イベント種別の送信済み再試行はスキップされ、DB の UNIQUE 制約も重複記録を防ぎます。失敗または処理中の記録は再試行されます。
「Test」は実際に event: "test" の署名付きリクエストを送り、成功後は 60 秒のクールダウンがあります。1つの Webhook の失敗は他チャンネルの送信を止めません。
フラップ抑制とインシデント単位の送信済み判定はインシデント通知に適用されます。メンテナンス通知はこれらを使わず、有効かつ確認済みのチームチャンネルへ送信されます。