Webhook

Webhook は、Space で何かが起きたとき(例: Content の作成・公開)にあらかじめ定めた動作を自動で実行する設定です。動作は 2 つのうちいずれかです。外部 URL へ HTTP リクエストを送るか(url)、Space 内の Script を実行します(script)。外部システム連携や自動化に使います。たとえば商品 Content が公開されるたびに社内の通知サーバーを呼び出したり、定めておいた Script で後続の作業を実行するように構成できます。

urlscriptちょうど 1 つだけ 指定します。両方を指定したり、両方を空にすると拒否されます。Webhook は CMA では Space の下位リソースであり、パスは /spaces/{spaceId}/webhooks を基準とします。

リソース構造

以下は Webhook「商品変更通知」の単一取得レスポンスです。sys(システム属性)とともに、送信先・購読イベント・トリガー条件といった設定フィールドを持ちます。

{
  "sys": {
    "id": "3trmXRM3RqbgSnifyg7PWhk01Examp",
    "type": "Webhook",
    "space": { "sys": { "id": "HnQ32YiH", "type": "Refer", "targetType": "Space" } },
    "createdBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
    "createdAt": "2026-06-18T11:30:00.000Z",
    "updatedBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
    "updatedAt": "2026-06-18T11:30:00.000Z",
    "version": 1
  },
  "name": "商品変更通知",
  "filters": [
    { "doc": "sys.contentType.sys.id", "op": "EQ", "value": "3trmXRLdJF4GBlAjtcuoZ7Pnxj8dlA" }
  ],
  "headers": [
    { "key": "X-Source", "value": "weegloo", "secret": false }
  ],
  "httpBasicUsername": "dailywear",
  "topics": ["Content.Create", "Content.Publish"],
  "transformation": { "method": "POST", "contentType": "application/json", "includeBody": true },
  "url": "https://api.dailywear.example/webhooks/products",
  "activate": true,
  "runAs": "HookOwner"
}

主なキー:

  • sys.id: Webhook の一意な識別子です。単一取得・修正・削除パスの {webhookId} に入ります。
  • url: イベントが発生したときに呼び出す外部の対象 URL です。script とちょうど 1 つだけ指定します。
  • script: 外部呼び出しの代わりに実行する Script の参照です。url とちょうど 1 つだけ指定します。上の例にはありません。下の url と script(択一) で説明します。
  • runAs: script がどのユーザーとして実行されるかです。下の runAs で説明します。
  • topics: どのイベントを購読するかを定めた配列です。下の topics で形式を説明します。
  • filters: 購読したイベントのうち、実際にトリガーする条件です。下の filters で説明します。
  • transformation: url へ送るリクエストの形(メソッド・本文など)を変える設定です。下の transformation で説明します。

システム属性(sys)

すべての Webhook は共通のシステム属性を sys オブジェクトに格納します。spacecreatedByupdatedByRefer の形({ "sys": { "id", "type": "Refer", "targetType" } })で入ります。

属性タイプ説明
idstringリソースの一意な識別子。
typestringリソースの種類。Webhook は常に "Webhook"
spaceRefer<Space>この Webhook が属する Space
createdByRefer<User>作成したユーザー。
createdAtstring (date-time)作成時刻。
updatedByRefer<User>最後に修正したユーザー。
updatedAtstring (date-time)最後の修正時刻。
versioninteger (≥1)リソースのバージョン。修正のたびに 1 ずつ上がります。

Webhook は設定リソースなので、公開という概念がありません。ContentContent Type と違い、publisharchivestatus のような公開状態の属性を持たず、変更追跡用の version だけを持ちます。オン・オフは公開ではなく、本文フィールド activate で制御します。

本文属性

Webhook の本文(作成・修正時に送り、レスポンスで返ってくる設定値)は次のフィールドで構成されます。

フィールドタイプ必須説明
namestring (1~64)Webhook の名前。
urlstring (url)イベント発生時に呼び出す外部の対象 URL。script と択一。下の url と script(択一) を参照。
scriptRefer<Script>外部呼び出しの代わりに実行する Script の参照。url と択一。下の url と script(択一) を参照。
runAsWebhookRunAsscript を実行するユーザー。HookOwner(既定)または EventUser。下の runAs を参照。
activatebooleanオンかどうか。false の場合はイベントが発生しても実行しません。
topicsstring[]購読するイベントの配列。下の topics を参照。
filtersFilter[]トリガー条件の配列。空にすると購読したすべてのイベントがトリガーします。下の filters を参照。
headersWebhookHeader[] (0~30)url 呼び出しに載せて送る HTTP ヘッダーの配列。
httpBasicUsernamestring (1~32)url 呼び出しの HTTP Basic 認証のユーザー名。
httpBasicPasswordstring (1~32)url 呼び出しの HTTP Basic 認証のパスワード。書き込み専用です。応答には表示されません。
transformationTransformationurl へ送るリクエストのカスタマイズ。下の transformation を参照。

△ を付けた urlscriptちょうど 1 つだけ 指定します。両方を指定したり、両方を空にすると拒否されます。

headers の各項目は key(必須)・value(必須)・secret(任意、boolean)で構成されます。secrettrue にすると、その値は送信記録でマスクされた状態で残ります(下の WebhookLog を参照)。ただし、この Webhook を取得すると値は原文で表示されます。 応答から外れるのは httpBasicPassword だけなので、secret ヘッダーに置いた値はこの Webhook を読めるロールには見えるものとみなし、そのロールを狭く保ってください。

topics

topics の各項目は {リソース}.{アクション} 形式です。例: Content.CreateContent.PublishMedia.Create

アクションは次のいずれか、またはリソースのすべてのアクションを意味する * です(例: Content.*)。

アクション意味
Allすべてのアクション。
Create作成。
Read取得。
Edit編集。
Save保存(修正)。修正イベントは Save です。Update ではありません
Delete削除。
Publish公開。
Unpublish公開停止。
Archiveアーカイブ。
Unarchiveアーカイブ解除。

filters

filters は、購読した topics のうち実際に Webhook をトリガーする条件を絞り込む配列です。各フィルターは次の形です。

{ "doc": "sys.contentType.sys.id", "op": "EQ", "value": "3trmXRLdJF4GBlAjtcuoZ7Pnxj8dlA" }
  • doc: 比較するフィールドのパス。sys.idsys.contentType.sys.idsys.createdBy.sys.idsys.updatedBy.sys.id のいずれかです。
  • op: 比較演算子。EQNEINNOT_INREGEXNOT_REGEX のいずれかです。
  • value: 比較する値。EQNEREGEXNOT_REGEX には文字列を、INNOT_IN には文字列の配列を渡します。

複数のフィルターを置くと、すべてを満たしたときにトリガーします(AND)。filters を空にすると、購読した topics のすべてのイベントがトリガーします。

transformation

transformationurl へ送る HTTP リクエストの形を変えます(script を使う Webhook には適用されません)。指定しない場合は、リソースのペイロード全体が既定の POST でそのまま送られます。

キータイプ説明
methodstringHTTP メソッド。GETPOSTPUTDELETEPATCH のいずれか。
contentTypestringリクエスト本文の Content-Type。本文はこの形式でシリアライズされます(下記)。
bodyobject送る本文を JSON Pointer テンプレートで構成するオブジェクト。
includeBodybooleanトリガーとなったリソースの本文を一緒に送るかどうか。

本文がどの形式で送られるか

contentType が本文のシリアライズ形式を決めます。比較では大文字・小文字と ;charset=… のようなパラメーターを無視し、先頭の部分だけを見ます。指定しない場合や値が空の場合は application/json で送ります。includeBodyfalse の場合、または methodGET の場合は本文を送らず、そのときは Content-Type も付きません。

Webhook が送る本文は常にオブジェクトです。body テンプレートがオブジェクトであり、テンプレートを置かない場合はトリガーされたリソース全体がそのまま送られるためです。

宣言した contentType実際に送られる Content-Type送られる本文
(なし)application/jsonJSON
application/json宣言値のままJSON
application/x-www-form-urlencoded宣言値のままproduct[sku]=TUMBLER-500&product[price]=24000
text/plainapplication/jsonJSON
その他(text/xml など)宣言値のままJSON

text/plain はオブジェクトを格納できないため、格納できる形式に訂正して送ります。ヘッダーの宣言と実際の本文が食い違うことはありません。本文をテキストで受け取る必要がある対象なら contentType では解決しないため、受け取る側の契約を確認してください。

form-urlencoded はオブジェクトをブラケットキーに、配列をインデックスに展開します。

本文展開されるキーと値
{ "product": { "sku": "TUMBLER-500", "price": 24000 } }product[sku]=TUMBLER-500&product[price]=24000
{ "tags": ["kitchen", "insulated"] }tags[0]=kitchen&tags[1]=insulated
{ "items": [{ "sku": "TUMBLER-500" }] }items[0][sku]=TUMBLER-500
{ "memo": null }memo=

キーと値は UTF-8 でパーセントエンコードされて送られます。上の表はキーの構造を示すためにデコードした形です。値に &+ が入っていても、ペアの区切り文字や空白と誤解されることはなく、そのまま伝えられます。

ネストをブラケットキーに展開する表記は広く使われている慣例であり、形式そのものの規格ではありません。 受け取る側が product[sku] をネストしたオブジェクトに復元するかどうかを確認し、復元しない場合はフラットなキーで body テンプレートを構成してください。

フォームで送る transformation の例です。

"transformation": {
  "method": "POST",
  "contentType": "application/x-www-form-urlencoded",
  "includeBody": true,
  "body": {
    "sku": "{ /payload/fields/sku/ko-KR }",
    "price": "{ /payload/fields/price/ko-KR }"
  }
}

skuTUMBLER-500price24000Content がトリガーすると、本文は sku=TUMBLER-500&price=24000 として送られます。

url と script(択一)

Webhook がトリガーされると、2 つのうちいずれかを実行します。url を指定すると、その外部 URL へ HTTP リクエストを送ります(リクエストの形は transformationheadershttpBasic* で決めます)。script を指定すると、外部へ送らず Space 内の Script を 1 つ実行します。

  • url: 外部の対象 URL(http/https)。プライベートネットワーク・ループバックなどブロックされた対象は拒否されます。
  • script: 実行する ScriptRefer

2 つは ちょうど 1 つだけ 指定する必要があります。両方を指定したり、両方を空にすると拒否され、返ってくるコードはパスごとに異なります(エラー を参照)。

"script": { "sys": { "id": "3trmXRMZcTAjDnphewjj1AaxYcaxlK", "type": "Refer", "targetType": "Script" } }

トリガーされると Script は委任された権限で実行され、statement ごとのリソース権限は実行時に再検査されません。何が許可されるかは Script を作成する時点ですでに検査されます。詳しい実行・権限モデルは Script の実行セマンティクス、制約、セキュリティ を参照してください。

runAs

runAsscriptどのユーザーとして実行されるか を定めます。この ID は、実行中に作成または修正されるリソースの createdBy/updatedBy になり、Script 内の createdBy: ":self" フィルターもこの ID を基準に解決されます。帰属(attribution)であって、権限の境界ではありません。何ができるかは Script を作成する時点の権限検査で決まります。

実行するユーザー
HookOwnerWebhook を作成したユーザー(sys.createdBy)。既定値。
EventUserそのイベント(変化)を起こしたユーザー、すなわちトリガーとなったリソースの sys.updatedBy

url だけを使う Webhook では runAs は無視されます。指定しない場合は HookOwner です。

WebhookLog

Webhook が 1 回送信を試みるたびに、記録が 1 つ残ります。取得専用で、作成・修正・削除エンドポイントはありません。パスは /spaces/{spaceId}/webhooks/{webhookId}/logs です。

{
  "sys": {
    "id": "3trmXRM3RqbgSnifyg7PWhc01Exam",
    "type": "WebhookLog",
    "space": { "sys": { "id": "HnQ32YiH", "type": "Refer", "targetType": "Space" } },
    "requestId": "3trmXRM3qWnLb7Vd1yPcYs04kKrjq",
    "statusCode": 200,
    "errors": [],
    "eventType": "Create",
    "url": "https://api.dailywear.example/webhooks/products",
    "requestAt": "2026-06-18T11:35:00.100Z",
    "responseAt": "2026-06-18T11:35:00.350Z",
    "request": {
      "url": "https://api.dailywear.example/webhooks/products",
      "method": "POST",
      "headers": { "Content-Type": "application/json", "X-Source": "weegloo" },
      "body": "{\"sys\":{\"type\":\"Content\"}}"
    },
    "response": {
      "url": "https://api.dailywear.example/webhooks/products",
      "headers": { "Content-Type": "application/json" },
      "body": "{\"ok\":true}",
      "statusCode": 200
    },
    "createdBy": { "sys": { "id": "3trmXRM3RqbgSnifyg7PWhk01Examp", "type": "Refer", "targetType": "Webhook" } },
    "createdAt": "2026-06-18T11:35:00.350Z",
    "updatedBy": { "sys": { "id": "3trmXRM3RqbgSnifyg7PWhk01Examp", "type": "Refer", "targetType": "Webhook" } },
    "updatedAt": "2026-06-18T11:35:00.350Z"
  }
}

すべての値が sys の中にあり、本文属性はありません。値のないキーはレスポンスから外れます。

どの Webhook が残した記録かは sys.createdBy が指します。ユーザーではなくその WebhookRefer であり、sys.updatedBy も同じ Webhook です。

属性タイプ説明
idstring記録の一意な識別子。
typestring常に "WebhookLog"
spaceRefer<Space>この記録が属する Space
requestIdstringこの送信試行の追跡識別子。
statusCodeinteger受け取ったレスポンスの HTTP ステータスコード。
errorsstring[]失敗理由のリスト。URL へ送る Webhook の記録では 常に空です(ステータスコードが失敗を示します)。scriptScript を実行する Webhook の記録にのみ、その Script の失敗メッセージが入ります。
eventTypestringこの送信を引き起こした アクション名 です(例: CreatePublish)。topics に書く Content.Create の形ではなく、後ろのアクションだけが入ります。
urlstring送信先の URL。
requestAtstring (date-time)リクエストを送った時刻。
responseAtstring (date-time)レスポンスを受け取った時刻。
requestobject送ったリクエスト。下位構造は下にあります。一覧取得では外れます。
responseobject受け取ったレスポンス。下位構造は下にあります。一覧取得では外れます。
createdByRefer<Webhook>この記録を残した Webhook
createdAtstring (date-time)記録の作成時刻。
updatedByRefer<Webhook>createdBy と同じです。
updatedAtstring (date-time)createdAt と同じです。

requestresponse はそれぞれ次のキーを持ちます。

  • request: url(リクエストを送った対象 URL)・method(HTTP メソッド)・headers(送ったヘッダーのマップ)・body(送った本文の文字列)。
  • response: url(レスポンスを受け取った URL)・headers(受け取ったヘッダーのマップ)・body(受け取った本文の文字列)・statusCode(受け取ったステータスコード)。

scriptScript を実行する Webhook の記録は形が違います。送る宛先がないため url がなく、requestmethod"SCRIPT" に固定されます。requestbody にはその送信を引き起こした payload が、responsebody にはその Script が返した値(または失敗メッセージ)が入ります。

secret をオンにしたヘッダーの値はマスクされて保存されます。実際の値は記録に残りません。

長い本文は縮めて保存されます。 requestbody は 65,536 文字、responsebody は 8,192 文字が基準です。それより長い場合は 前後を残して中間を省略 し、省略された文字数をその場所に書き込みます。本文が JSON の場合は構造を壊さないよう、長い文字列の値だけを同じ方式で縮めるため、キーと短い値はそのまま残ります。

成功と失敗を分ける基準は連携方式ごとに異なります。 URL へ送る Webhook は、レスポンスが 2xx または 3xx なら成功です。scriptScript を実行する Webhook は、statusCode が 400 より小さく errors が空のときに成功です。この判定 1 つが、下の保存期間と 送信状態 の成功率を合わせて決めます。

一覧取得は requestresponse を外して返します。 一覧エンドポイントの select の既定値が -sys.response,-sys.request だからです。送ったリクエストと受け取ったレスポンスの本文まで見るには、単一取得を使うか、select を直接指定してその既定値を上書きする必要があります。

成功した送信の記録は 1 時間後、失敗した送信の記録は 3 日後に消えます。有効期限を収めたフィールドはレスポンスになく、時が来ると記録は自然に消えます。それより長く保管する必要がある値は、受け取る側のサーバーに別途保存するか、script で実行する Script から Content として残してください。

エラー

Webhook を扱うときに出会うコードです。すべてのリソースに共通するコードは 共通エラー を参照してください。

コード条件
WGL400042作成(POST)・全体修正(PUT)で urlscript を両方指定したか、両方空にしました。
WGL422061部分修正(PATCH)で urlscript を両方指定したか、両方空にしました。
WGL422050url がプライベートネットワーク・ループバックのようにブロックされた対象を指しています。

API

以下のすべてのエンドポイントの基準 URL は https://cma.weegloo.com/v1 で、Authorization ヘッダーに CMA を認証する Bearer トークンが必要です。修正(PUT)と部分修正(PATCH)は、楽観的同時実行制御のために X-Weegloo-Version ヘッダー(現在のリソースの sys.version)を一緒に送る必要があります。

  • Content: Webhook をトリガーする本文データ。
  • Media: Webhook をトリガーできるファイルリソース。
  • Script: script で実行する宣言型のバックエンドエンドポイント。実行・権限モデルを含む。
  • SpaceRole: Script の実行(Execute)権限などを持つロール設定。