Webhook / Developer Preview

Next Generation Events
「欲しいフィールドが変わった時だけ・欲しい形で」届くイベント

フィールド単位のトリガー/自前 GraphQL クエリで定義する payload/何が変わったかを示す fields_changed。Webhook の「ノイズ問題」と「追加 API 呼び出し問題」を同時に解決する次世代の仕組み。

このページの構成
  1. 30秒で理解 : Webhook と何が違うのか
  2. 仕組み図解 : イベントが届くまでの 4 ステップ
  3. 4 つのコア機能
  4. 従来 Webhook vs Next Gen Events 比較
  5. 設定例(shopify.app.toml)
  6. 配信ペイロードの中身
  7. 技術者が押さえるべき 5 つのポイント
  8. 業務に活かせる 3 つのユースケース
  9. 提案で使える 1 行サマリ

130秒で理解 : Webhook と何が違うのか

従来の Webhook は「product/update が起きた」を全部送ってきて、受け手が 差分を計算し・必要なフィールドを別 API で取りに行く 必要があった。
Next Generation Events は 「欲しいフィールド」「欲しい形」「現在の状態フィルタ」 を購読時に宣言する。届くものは事前に絞り込まれ、何が変わったかも明示される。

従来 : 全件 + 自前で差分

product/update が title・tag・price のどれで起きたか分からない。固定スキーマで送られ、欲しい項目は別途 GraphQL で取り直す。

Events : 事前に絞り・狙い撃ち

triggers でフィールドを宣言。query で payload を定義。query_filter で現在状態を絞る。fields_changed で何が変わったか明示。

2仕組み図解 : イベントが届くまでの 4 ステップ

① 変更発生 マーチャントが 商品を編集 title / price / tag… ② triggers で判定 変わったフィールドが 購読対象か? variants.price ✓ title ✗ → 破棄 ③ query 実行 あなたの GraphQL を Shopify が実行 query_filter で絞る status:'ACTIVE' のみ ④ アプリへ配信 data + fields_changed + query_variables そのまま処理に使える
② と ③ の 「事前絞り込み」 がポイント。エンドポイントに届く前にノイズが落ちるので、アプリ側で「破棄判定だけのために CPU を使う」が無くなる。

34 つのコア機能

triggers

フィールド単位で購読

product.variants.price を購読すれば、title や tag が変わっても発火しない。価格が変わった時だけ飛んでくる。

GraphQL query

payload を自分で定義

標準の Admin GraphQL クエリで 欲しい形・欲しい項目だけ を指定。固定スキーマに縛られず、配信後に追加 API を叩く必要も無い。

fields_changed

何が変わったか明示

各配信に 変更されたフィールドの完全パスと ID が含まれる。前回値との diff 計算や状態の推測が不要になる。

query_filter

現在状態でフィルタ

クエリ結果の 現在の状態 に基づいて配信可否を決定。例 : product.status:'ACTIVE' で公開中の商品変更だけ受け取る。

4従来 Webhook vs Next Gen Events 比較

項目従来 WebhookNext Generation Events
発火粒度 トピック単位 product/update 全部 フィールド単位 variants.price だけ等
ペイロード形状 固定スキーマ 自前 GraphQL で定義
追加 API 呼び出し 必要(欲しい項目を取りに行く) 不要
何が変わったか 受け手が diff 計算 fields_changed に明示
現在状態での絞り込み 受信後に自前で判定 query_filter で事前絞り
設定の置き場所 管理画面 / API shopify.app.toml(Git 管理)
提供状態 GA developer preview / unstable

5設定例(shopify.app.toml)

価格変更だけを購読し、自前の GraphQL で必要項目を取得、公開中の商品に絞る例。

[events]
api_version = "unstable"

[[events.subscription]]
handle  = "price_sync"
topic   = "Product"
actions = ["update"]
triggers = [
  "product.variants.price",
  "product.variants.compareAtPrice"
]
uri = "/api/events"

query = """
  query priceSync($productId: ID!, $variantsId: ID!) {
    productVariant(id: $variantsId) {
      id
      price
      compareAtPrice
      sku
    }
    product(id: $productId) {
      id
      title
      status
    }
  }
"""

query_filter = "product.status:'ACTIVE'"
設定は shopify.app.toml にコードとして同居。Pull Request でレビューでき、デプロイで反映できる。管理画面の手動操作と差分が出るリスクが消える。

6配信ペイロードの中身

{
  "topic": "Product",
  "action": "update",
  "handle": "price_sync",
  "data": {
    "productVariant": {
      "id": "gid://shopify/ProductVariant/456",
      "price": "24.99",
      "compareAtPrice": "34.99",
      "sku": "SIGNAL-NOT-NOISE"
    },
    "product": {
      "id": "gid://shopify/Product/123",
      "title": "Peace & Quiet Tee",
      "status": "ACTIVE"
    }
  },
  "fields_changed": [
    "product[id: 'gid://shopify/Product/123'].variants[id: 'gid://shopify/ProductVariant/456'].price"
  ],
  "query_variables": {
    "productId": "gid://shopify/Product/123",
    "variantsId": "gid://shopify/ProductVariant/456"
  }
}
data

クエリ結果そのもの

自分で定義したクエリの戻り値が入る。追加で API を叩く必要は無い。

fields_changed

変更されたフィールド

完全パスと ID で表現。...variants[id: ...].price の形。

query_variables

取得に使った変数

どの ID で取りに行ったかが明示。冪等処理やログ突合に有用。

7技術者が押さえるべき 5 つのポイント

unstable

1. unstable API = スキーマ変更前提

developer preview なので API バージョンは unstable 固定。本番投入前にバージョン更新時の影響範囲を CI で検知できる仕組みが必要。

Product Customer

2. 対応トピックは現状 2 つ

記事時点で Product と Customer のみ稼働。Order・Inventory 等は記載なし → 既存 Webhook の置換は段階的にしか進められない。

.toml

3. 設定が IaC 化される

shopify.app.toml に handle/topic/triggers/uri/query/query_filter が全部入る。レビュー・差分・ロールバックが Git で完結。

4. fields_changed は完全パス表記

配列要素を variants[id: 'gid://...'].price で表す独自構文。パーサを書くか、文字列マッチで分岐する設計を最初に決めておくべき。

事前 事後

5. triggers と query_filter は層が違う

triggers =「何が変わったか」での絞り込み(事前条件)。query_filter =「現在の状態」での絞り込み(事後条件)。
例 : 「価格が変わった & 現時点で公開中」のように、両者を組み合わせると Webhook 設計が宣言的に綺麗にまとまる。

8業務に活かせる 3 つのユースケース

Shopify ERP price だけ流す title/tag は無視
USE CASE 1

基幹システム連携の「ノイズ削減」と「コスト削減」

課題
ERP/基幹に価格変更だけ同期したいのに、product/update を全件受けて差分判定 → 不要な処理と API 呼び出しが膨らみ、Cloud Run / Lambda コストが嵩む。
打ち手
triggers に product.variants.pricecompareAtPrice だけ宣言。query に SKU・価格のみ含める。query_filter で status:'ACTIVE' に絞る。
効果
配信件数の削減、追加 API 呼び出しゼロ、ハンドラ実装の単純化。月次の運用コストが目に見えて落ちる。
技術メモ
fields_changed があるため「価格はどの variant か」を一発で特定可能。冪等キーは query_variables の ID で作れる。
CRM / MA email/tag 変更のみ
USE CASE 2

CRM / MA 連携で「同意状態の変化だけ」を拾う

課題
顧客の email・タグ・配信同意の更新だけを MA に流したいが、Customer update Webhook は住所など別の変更でも発火し、CRM 側で誤検知が起きる。
打ち手
Customer トピックでフィールド単位 triggers を宣言。query で MA に必要な項目だけ取得し、query_filter で対象セグメントに限定。
効果
同意撤回・タグ変更といった「業務的に意味のある変化」だけが MA へ届く。MA 側の不要なオートメーション発火が止まる。
技術メモ
Customer は記事時点で対応済みトピック。fields_changed をそのまま CRM の監査ログに残せば、誰がいつ何を変えたかのトレースが容易。
app.toml
USE CASE 3

パートナー開発の「購読定義レビュー」をコードレビューに統合

課題
カスタムアプリで Webhook の購読をエンジニアが管理画面から手動で設定 → 検証環境と本番で設定がズレ、再現できないバグが発生。
打ち手
購読定義を shopify.app.toml に集約。triggers/query/query_filter を Pull Request 上でレビューし、デプロイで複数環境に同一適用。
効果
環境間の購読差分ゼロ、設定変更の理由が Git 履歴に残る、ロールバックが git revert で完結。
技術メモ
unstable API のため、CI で shopify app deploy --dry-run(あるいは同等チェック) を回し、スキーマ変更の影響を早期検知する運用が必要(API 仕様の安定化は未告知 = 記載なし)。

9提案で使える 1 行サマリ

「Webhook の 『全件来る・追加 API が要る・差分は自分で計算』 を一掃する次世代購読モデル。
欲しいフィールドだけ・欲しい形だけ・公開中だけ を宣言で書き、shopify.app.toml に IaC として置ける。
現状 Product / Customer の unstable プレビュー = 新規開発から先行採用、本番置換は段階的に。」