ブログ · · 約 7 分で読めます

Webhook Admin で最初の Webhook を送るまで(Node)

Webhook Admin に登録してから、Node.js で顧客と送信先を作り、Webhook を送り、配信の記録で確かめ、受け側で署名を検証するまでの手順を、npm の webhookadmin と fetch のコードで示します。

要点

  • 登録・プロジェクト・API キー・顧客と送信先・送信の 5 つの手順で、最初の Webhook が届きます。
  • Node の送る側のコードは、npm の webhookadmin を使うと、顧客と送信先の作成から送信と記録の確認までで約 20 行です。
  • Free プランは月 5 万通・1 プロジェクトまで無料で、テスト環境の送信と送信先への試し送信は数えません。

Webhook Admin で最初の Webhook を送るまでの手順は 5 つです。登録、プロジェクトの作成、API キーの発行、顧客と送信先の登録、送信です。Node.js なら、npm の webhookadmin を使って、顧客と送信先の作成から送信・記録の確認までを約 20 行で書けます。この記事では、各手順と、SDK を使わない書き方、受け側での署名の検証までを通しで示します。

手順の全体

  1. 登録する
  2. プロジェクトを作る
  3. API キーを発行する
  4. 顧客と送信先を登録する
  5. 送信する

このあと、配信の記録で届いたことを確かめ、受け側で署名を検証します。

1. 登録

https://app.webhookadmin.com/signup で、メールアドレス・Google・GitHub のどれかで登録します。メールアドレスのときは、ログイン用のリンクがメールで届きます(15 分間有効)。最初のログインで組織(会社やチームの単位)を作ります。プラン・請求・メンバーは組織ごとです。

2. プロジェクト

送る側のサービス 1 つにつき、プロジェクトを 1 つ作ります。プロジェクトには本番とテストの 2 つの環境があります。

環境 API キー 送信数
本番 sk_live_… 月の上限と料金の対象
テスト sk_test_… 数えない

最初はテスト環境で試し、動いたら本番の API キーに差し替えます。

3. API キー

管理画面の「API キー」で、環境ごとに作ります。キーの値は作成したときに 1 回だけ表示されます。権限は次の 5 つから選びます。

権限 できること
messages:send メッセージの送信
messages:retry 送信のやり直し
logs:read 配信の記録・顧客・送信先の参照
endpoints:write 送信先の登録・変更・削除、署名の鍵の切り替え
consumers:write 顧客の登録

この記事のコードは顧客と送信先の作成から記録の確認までを行うので、5 つすべてを付けたキーを使います。本番のサービスに組み込むときは、送信だけを行うサーバーには messages:send だけを付けます。有効期限は 30 日・90 日・1 年・なしから選べ、期限の 7 日前に組織の Owner と Admin へメールで知らせます。

キーは環境変数に入れておきます。SDK は WEBHOOK_ADMIN_API_KEY を読みます。

npm install webhookadmin
export WEBHOOK_ADMIN_API_KEY=sk_test_...

4〜5. 顧客と送信先の登録、送信

顧客は Webhook を受け取る側の会社や利用者で、external_id に自社のサービスでの顧客の ID を入れます。送信先は、その顧客が Webhook を受け取る URL です。送るときは、顧客の external_id・イベントの種類・本文を渡すと、その顧客の送信先のうち、そのイベントを受け取るものすべてに届きます。

import { WebhookAdmin } from 'webhookadmin';

const wha = new WebhookAdmin(); // WEBHOOK_ADMIN_API_KEY(sk_test_…)を読む

// 顧客(external_id は自社のサービスでの顧客の ID)
const consumer = await wha.consumers.create({ external_id: 'cus_1024', name: 'Example Inc.' });

// 送信先(secret はこのときだけ返る)
const endpoint = await wha.endpoints.create({
  consumer_id: consumer.id,
  url: 'https://example.com/webhooks',
  event_types: ['invoice.paid'],
});
console.log(endpoint.secret); // whsec_… を受け側に渡す

// 送信(同じ Idempotency-Key は 24 時間、同じメッセージを返す)
const { id } = await wha.messages.send(
  { consumer: 'cus_1024', event_type: 'invoice.paid', payload: { invoice_id: 'inv_88', amount: 128000 } },
  { idempotencyKey: 'inv_88-paid' },
);

// 記録で確かめる
const message = await wha.messages.get(id);
const d = message.deliveries[0];
console.log(d?.status, d?.attempts[0]?.response_status, d?.attempts[0]?.response_head);

送信先の登録の条件は次のとおりです。

  • URL は https で、ポートは 443 か 8443 です。テスト環境でも同じです。手元のサーバーで受けるときは、ngrok や cloudflared のトンネルで https の URL を付けます(ローカルで試す方法の記事)。
  • IP アドレスを直接書いた URL、社内向けの名前、社内のアドレスを指す名前は登録できません(422)。
  • event_types を省くと、すべてのイベントを送ります。
  • secret は作成したときだけ返ります。後から見るときは管理画面か、developer 以上の権限で取得します。

送信の応答は 202 Accepted と { id, deliveries } です。deliveries は、そのイベントが届けられる送信先の数です。external_id の顧客が無いときは、その場で顧客を作ります(送信先が無いので deliveries は 0)。

Idempotency-Key を付ける理由

送信の API を呼ぶ自社のサーバーも、ネットワークのエラーで同じ呼び出しを 2 回行うことがあります。Idempotency-Key が同じ送信は、24 時間のあいだ最初のメッセージの id を返し、2 通目を作りません。請求書の ID とイベントの種類のように、業務の上で 1 回しか起きない組み合わせから作ります。SDK は、キーを省いた場合も自動で 1 つ作り、再試行のときに同じキーを送ります。

SDK を使わない書き方

公開 API は JSON の HTTP API なので、fetch からも呼べます。

const res = await fetch('https://api.webhookadmin.com/v1/messages', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.WEBHOOK_ADMIN_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': 'inv_88-paid',
  },
  body: JSON.stringify({
    consumer: 'cus_1024',
    event_type: 'invoice.paid',
    payload: { invoice_id: 'inv_88', amount: 128000 },
  }),
});
console.log(res.status, await res.json()); // 202 { id: 'msg_…', deliveries: 1 }

SDK は、この呼び出しに次のことを足しています。429 のときは retry-after まで待って再試行する、5xx と接続のエラーのときは安全に繰り返せる呼び出しだけを再試行する、Idempotency-Key を自動で付ける、応答とエラーに型を付ける、の 4 つです。

配信の記録での確認

届いたかどうかは、管理画面の「配信記録」か GET /v1/messages/{id} で確かめます。送信先ごとに、試行の時刻・応答のコード・応答の本文の先頭 1,024 バイト・所要時間・エラーが残ります。失敗していれば、応答の本文を見て受け側を直し、記録から送り直します(POST /v1/deliveries/{id}/retry)。

送信先への試し送信(POST /v1/endpoints/{id}/test)を使うと、業務のイベントを起こさずに、その送信先だけに webhook.test を送れます。試し送信は使用量に数えません。

受け側での署名の検証

送信先には、Standard Webhooks の形式の署名を付けて送ります。受け側は、手順 4 で受け取った whsec_… を使って、生の本文とヘッダーで検証します。

import express from 'express';
import { Webhook } from 'webhookadmin';

const wh = new Webhook(process.env.WEBHOOK_SECRET!); // whsec_…
const app = express();

// 署名は届いた本文そのもので検証するので、JSON に変換する前の本文を受け取る
app.post('/webhooks', express.raw({ type: 'application/json' }), async (req, res) => {
  try {
    const event = await wh.verify(req.body, req.headers); // { type, timestamp, data }
    console.log(event.type, event.data);
    res.sendStatus(204);
  } catch {
    res.sendStatus(400);
  }
});

app.listen(3000);

受け側は Webhook Admin の SDK でなくても、Standard Webhooks の公式ライブラリ(Node・Python・Go・Ruby など)で検証できます。ヘッダーと署名の作り方は署名検証のドキュメントにあります。受け側で重複を弾くときは webhook-id ヘッダーを使います。再送でも同じ値が付きます。

無料の範囲

項目 Free プラン
本番の送信 月 5 万通(上限に達すると翌月 1 日(UTC)まで新しい送信を受け付けない)
プロジェクト 1 つ
配信の記録の保存 7 日
公開 API 1 分 600 回
テスト環境の送信・再送・試し送信 数えない

顧客向けの画面と固定の送信元 IP は Starter プランからです。プランごとの値は料金表にあります。

次に読むもの

ここまでの手順は無料で試せます。https://app.webhookadmin.com/signup から登録し、テスト環境の API キーで最初の 1 通を送ってみてください。

よくある質問

無料でどこまで使えますか。

Free プランは、本番の送信が月 5 万通まで、プロジェクトが 1 つ、配信の記録の保存が 7 日、公開 API は 1 分 600 回までです。テスト環境の送信、再送、送信先への試し送信は月の通数に数えません。顧客向けの画面と固定の送信元 IP は Starter プランからです。

SDK を使わずに送れますか。

送れます。公開 API は JSON の HTTP API なので、fetch や curl から POST /v1/messages を呼べば送れます。SDK は、429 や 5xx のときの再試行、Idempotency-Key の自動の付与、型を足したものです。

テスト環境の送信は数えられますか。

数えられません。プロジェクトには本番とテストの 2 つの環境があり、sk_test_ で始まる API キーで送ったものはテスト環境の送信として扱われ、月の上限と料金の対象になりません。

関連記事