Webhook

スマートフォンがアクティビティを追加したとき、またはユーザーがオフにしたり削除したりしたときに、バックエンドに送られる署名付きの呼び出し。

Webhookエンドポイントは、サービスがPOSTを送るURLです。エンドポイントはダッシュボードで追加します。それぞれに専用の署名シークレット(whs_と48桁の16進数)があり、識別子を付けられます。同じチーム内の2つのエンドポイントに同じ識別子は使えません。URLはhttpまたはhttpsにする必要があります。

識別子によるルーティング

webhookIdentifierを付けて開始したアクティビティは、すべてのイベントをその識別子を持つ1つのエンドポイントに送ります。付けずに開始したアクティビティは、識別子のないすべてのエンドポイントにイベントを送ります。一致するエンドポイントがないイベントは破棄されます。

テストもこの方法で行います。別のテスト環境はありません。本番のエンドポイントは識別子なしのままにして、テスト用のアクティビティはテスト用エンドポイントの識別子を付けて開始します:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
curl -X POST https://api.webliveactivity.com/api/start \
  -H 'Content-Type: application/json' \
  -H 'x-api-key: wla_your_key' \
  -d '{
  "widgetContainerId": "acme-orders",
  "webhookIdentifier": "staging",
  "brand": {
    "title": "Order #1234"
  },
  "state": {
    "layout": "progress",
    "primaryText": "Order received",
    "progress": 0.1
  }
}'

イベント

イベント送信されるタイミング
activeスマートフォンがアクティビティを開いて画面に表示された(スマートフォンごとに1回)、またはユーザーがアプリで再びオンにした。
removedユーザーがアプリでアクティビティをオフにした、削除した、またはアプリのデータを消去した。

POST /api/endと再起動ではWebhookは送られません。

配信

各イベントは、JSON本文を持つ1回のPOSTです:

1
2
3
4
5
6
7
8
{
  "activityId": "act-8f2cqa4mx7rd",
  "group": "order-tracker",
  "event": "active",
  "active": true,
  "webhookIdentifier": "staging",
  "at": "2026-07-30T14:25:19.991Z"
}
フィールド意味
activityIdアクティビティ。reuse: trueの場合は、startが返したIDではなく、そのスマートフォン専用のコピーです。
groupアクティビティのグループ。設定されていない場合は""。
eventactiveまたはremoved。
activeその時点でアクティビティが画面に表示されているかどうかのフラグ。このフラグではなく、eventに基づいて処理します。
webhookIdentifierstartで指定した識別子。設定されていない場合はnull。
atイベントが発生した時刻(ISO形式)。

ヘッダーは3つです:

ヘッダー意味
X-WebActivities-Eventイベント名:activeまたはremoved。
X-WebActivities-Timestampこの試行が送信された時刻のUnixエポック秒。再試行のたびに新しくなります。古いタイムスタンプは拒否してください。
X-WebActivities-Signature下記のHMAC署名。

署名の検証

署名は、タイムスタンプと未加工のリクエスト本文を、エンドポイントのシークレットをキーとしてHMAC-SHA256で計算したものです。タイムスタンプは署名対象のペイロードに含まれるので、傍受した配信を新しいタイムスタンプで再送することはできません。

1
2
3
4
5
6
7
8
9
10
11
12
const { createHmac, timingSafeEqual } = require('node:crypto');

// rawBody is the request body EXACTLY as received, before any JSON parsing.
const verify = (secret, headers, rawBody) => {
  const timestamp = headers['x-webactivities-timestamp'];
  const expected = 'sha256=' + createHmac('sha256', secret)
    .update(timestamp + '.' + rawBody)
    .digest('hex');
  const presented = Buffer.from(headers['x-webactivities-signature']);
  return expected.length === presented.length &&
    timingSafeEqual(Buffer.from(expected), presented);
};

誤った署名から正しい署名の情報が漏れないよう、定数時間で比較します(timingSafeEqual)。また、リプレイを防ぐため、タイムスタンプをローカルの時計と照合します。

再試行

  • エンドポイントは8秒以内に2xxで応答する必要があります。リダイレクトは失敗とみなされます。
  • 失敗した配信は、1分、2分、4分、8分の間隔をあけて、合計5回試行されます。
  • プライベートアドレスや内部アドレスを指すURLは拒否されます。
  • ダッシュボードの配信ログには90日間のすべての配信が表示され、そこから再送信もできます。

すばやく応答する

まずイベントを保存して200を返し、そのあとで処理します。リクエスト内で時間のかかる処理をすると、8秒のタイムアウトに達し、再試行が重複して届くおそれがあります。再試行は順不同で届くことがあるので、イベントの実際の時刻にはatフィールドを使います。

ライブアクティビティを​「開発」せずに​作り始めませんか?

今日から​作り始めませんか?

App Storeへの申請も、ネイティブのコードベースの保守も不要です。リンクひとつでアクティビティがユーザーの画面に届き、使いやすいAPIで最新の状態を保てます。

毎月7,000回の無料プッシュ付き

Movistar RidersMovistar Ridersテロリスト9
マップOverpass
12HeroicHeroicカウンターテロリストCSGOCSGO eスポーツライブで見る
8 PM
洗濯中8:00 PMまでに完了
洗濯床掃除昼食
Domino's調理中
912
Movistar RidersMovistar Ridersテロリスト9
マップOverpass
12HeroicHeroicカウンターテロリストCSGOCSGO eスポーツライブで見る
ライブ
ライブを見るMolyのねこカメラ3秒前に更新ねこカメラ
ただいま焼き上げ中Matがご注文の品を焼いています。Domino's
調理中移動中配達完了
思考中
APIエンドポイントを調査中Foodscoutの変更を準備中
思考中作業中完了
あと30分でお届けMatが急いで向かっています。Domino's
移動中配達完了
GTA00:00
GTA00:00:00GTA VI
San Francisco Shockホーム1
マップMidtown
3
Dallas FuelアウェイOverwatch Leagueライブで見る
United 1423ゲートB22 · 座席14C · SFO → JFK
搭乗中飛行中到着
搭乗中
あと6分で到着Marcus · Toyota CamryToyota Camry
移動中到着
6分
Movistar RidersMovistar Ridersテロリスト9
マップOverpass
12HeroicHeroicカウンターテロリストCSGOCSGO eスポーツライブで見る
8 PM
洗濯中8:00 PMまでに完了
洗濯床掃除昼食
Domino's調理中
912
Movistar RidersMovistar Ridersテロリスト9
マップOverpass
12HeroicHeroicカウンターテロリストCSGOCSGO eスポーツライブで見る
ライブ
ライブを見るMolyのねこカメラ3秒前に更新ねこカメラ
ただいま焼き上げ中Matがご注文の品を焼いています。Domino's
調理中移動中配達完了
思考中
APIエンドポイントを調査中Foodscoutの変更を準備中
思考中作業中完了
あと30分でお届けMatが急いで向かっています。Domino's
移動中配達完了
GTA00:00
GTA00:00:00GTA VI
San Francisco Shockホーム1
マップMidtown
3
Dallas FuelアウェイOverwatch Leagueライブで見る
United 1423ゲートB22 · 座席14C · SFO → JFK
搭乗中飛行中到着
搭乗中
あと6分で到着Marcus · Toyota CamryToyota Camry
移動中到着
6分
Movistar RidersMovistar Ridersテロリスト9
マップOverpass
12HeroicHeroicカウンターテロリストCSGOCSGO eスポーツライブで見る
8 PM
洗濯中8:00 PMまでに完了
洗濯床掃除昼食
Domino's調理中
912
Movistar RidersMovistar Ridersテロリスト9
マップOverpass
12HeroicHeroicカウンターテロリストCSGOCSGO eスポーツライブで見る
ライブ
ライブを見るMolyのねこカメラ3秒前に更新ねこカメラ
ただいま焼き上げ中Matがご注文の品を焼いています。Domino's
調理中移動中配達完了
思考中
APIエンドポイントを調査中Foodscoutの変更を準備中
思考中作業中完了
あと30分でお届けMatが急いで向かっています。Domino's
移動中配達完了
GTA00:00
GTA00:00:00GTA VI
San Francisco Shockホーム1
マップMidtown
3
Dallas FuelアウェイOverwatch Leagueライブで見る
United 1423ゲートB22 · 座席14C · SFO → JFK
搭乗中飛行中到着
搭乗中
あと6分で到着Marcus · Toyota CamryToyota Camry
移動中到着
6分