Webhookリクエストの振り分け:Google Sheetsのタブへ種類別に保存

Webhookリクエストの振り分けを行うこのモデル不要のテンプレート設計は、営業のリクエストを営業用タブへ、サポートのリクエストをサポート用タブへ送ります。受け取ったフィールドを検証し、選択したタブに1行を追加して、書き込み後に振り分け先を返します。未対応の種類はHTTP 422で拒否します。

状態:2026年10月9日にAI Flowi Workflow 1.9.2で本番テスト済み(34件中34件合格)

執筆:Ai Flowi · 作成日:。本番テストのバージョンと日付:AI Flowi Workflow 1.9.2; 2026年10月9日 (MYT)。

実行する処理

認証付きのHTTP POSTで{type,name,email,request}を受け取ります。小文字で完全一致するsalesまたはsupportのみ受け付けます。4つのフィールドをこの順序で、対応するGoogle Sheetsのタブに保存します。明示的な振り分けを使用し、AIや言語モデルによる文章の分類は行いません。

対象ユーザー

フォームや社内システムですでにリクエストを営業またはサポートに分類しており、1つのスプレッドシートで別々のキューを管理したい小規模チーム向けです。送信側で認証情報を非公開に保てる必要があります。

入力例

{"type":"sales","name":"Example Sender","email":"sender@example.com","request":"Please send product information."}

設定手順

  1. まず非公開のスプレッドシートで合成データを使用します。たとえばsalesとsupportという2つのタブを作成します。各タブのA1:D1にtype,name,email,requestをこの順序で配置します。
  2. そのスプレッドシートにアクセスできる、認可済みのGoogle接続を選択します。両方の書き込みノードでSpreadsheet IDを設定し、各Rangeを対応するタブに割り当てます:'sales'!A:Dと'support'!A:D。
  3. Universal WebhookでPOST、Platform API Key認証、POSTレスポンスモードのFrom Flowを設定します。サーバーなどの信頼できるシステムからリクエストを送信します。Webhook認証のガイドを参照してください。
  4. 各JSON OperationsノードをJQ Expressionに設定し、クエリフィールドを表示した状態にします。入力の有効・拒否を判定するVerification Routerと、営業・サポートを判定するVerification Routerを1つずつ使用します。
  5. 書き込みにはRAWを使用し、Include Object Headersを無効にします。成功時のレスポンスを200 OK、検証時のレスポンスを422 Unprocessable Entityに設定し、コンテンツタイプをapplication/jsonにします。
  6. 実データを送る前に、以下の全ケースを実行し、リクエストごとに両方のタブを確認します。提示された本番テストでは34件すべてが合格しました。

ノード接続とフィールドの対応

提案するグラフは12ノード、11接続で構成されます。使用するコンポーネントはAI Flowi Workflow 1.9.2のコンポーネントカタログにあります。営業用とサポート用の書き込みノードは、Append Rowsを2つ配置したものです。JSON Operationsが本文を検証して{verified:true,route:TYPE,values:[[TYPE,NAME,EMAIL,REQUEST]]}を生成します。検証に成功すると、2つ目のクエリが{verified:(.route == "sales"),values:.values}を生成します。種類別ルーターはVerifiedを営業用の書き込みへ、Rejectedをサポート用の書き込みへ送ります。この2つ目のRejected出力は、有効なサポートリクエストを表します。不正な入力はすでに最初のルーターで分岐しています。

出力元から入力先への接続
出力元入力先目的
Universal Webhook request_data検証用JSON Operations dataリクエストの全体データ。読み取り対象:.body
検証用JSON Operations data_output検証用Verification Router verification_result検証済みの結果
検証用ルーター rejected422 Webhook Response body_data書き込みなし
検証用ルーター verified種類判定用JSON Operations data振り分け用の真偽値を生成
種類判定用JSON Operations data_output種類判定用Verification Router verification_result営業またはサポート
種類別ルーター verified営業用の書き込み values営業用タブのみ
種類別ルーター rejectedサポート用の書き込み valuesサポート用タブのみ
各書き込み result対応する振り分け先レスポンス用JSON Operations dataそれぞれ独立した2つの接続
各振り分け先レスポンス用JSON Operations data_output対応する200 Webhook Response body_dataそれぞれ独立した2つの接続

列Aにはbody.type、列Bにはbody.name、列Cにはbody.email、列Dにはbody.requestが入ります。余分な入力フィールドは無視します。受け付けた文字列は渡されたとおりに保存します。振り分け先を返すレスポンスでは、書き込み結果が更新行数1を示していることを確認してから、{"route":"sales"}または{"route":"support"}のみを返します。

設定するクエリ

検証用のJSON Operationsノードに次のクエリを設定します。

(.body) as $b
| if ($b|type) != "object" then {verified:false,error:"Request body must be a JSON object with type, name, email and request."}
  else ([
    (if $b.type == "sales" or $b.type == "support" then empty else "type must be sales or support" end),
    (if ($b.name|type) == "string" then (if ($b.name|test("\\S")) then empty else "name is required and must be non-blank text" end) else "name is required and must be non-blank text" end),
    (if ($b.email|type) == "string" then (if ($b.email|test("^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$")) then empty else "email is required and must be a valid address" end) else "email is required and must be a valid address" end),
    (if ($b.request|type) == "string" then (if ($b.request|test("\\S")) then empty else "request is required and must be non-blank text" end) else "request is required and must be non-blank text" end)
  ]) as $errs
  | if ($errs|length) > 0 then {verified:false,error:"Validation failed",details:$errs}
    else {verified:true,route:$b.type,values:[[$b.type,$b.name,$b.email,$b.request]]} end
  end

種類を判定するクエリには{verified:(.route == "sales"),values:.values}を使用します。営業用レスポンスのクエリには次を使用します。

if .updates.updatedRows == 1 then {route:"sales"} else error("Append did not confirm one row") end

サポート用レスポンスのクエリでは、"sales"を"support"に置き換えます。更新行数がない場合や正しくない場合は、プラットフォームのエラーとして実行が停止し、成功時の振り分け先は返されません。

機密情報を除去したリクエストとレスポンスの例

これらのレスポンス例は、合成データによる本番テストの結果と一致しています。WebhookからコピーしたProduction EndpointにJSONを送信し、非公開のプラットフォーム認証情報をリクエストヘッダーに含めます。ここには認証情報や非公開のエンドポイントは掲載していません。

POST [your Production Endpoint]
Content-Type: application/json

{"type":"support","name":"Example Sender","email":"sender@example.com","request":"Help with setup."}

Expected HTTP 200
{"route":"support"}
{"type":"other","name":"Example Sender","email":"sender@example.com","request":"Help with setup."}

Expected HTTP 422
{"verified":false,"error":"Validation failed","details":["type must be sales or support"]}

検証と失敗時の動作

本文はJSONオブジェクトでなければなりません。typeはsalesまたはsupportと完全一致する必要があります。nameとrequestは、空白以外の文字を含む文字列でなければなりません。emailは、@が1つあり、ドメインにドットを含み、空白を含まない基本的なアドレスパターンに一致する文字列である必要があります。これは構文のみの検証であり、メールボックスの所有者やメールの配信可否は確認しません。テストしたケースでは、JSONフィールドの型が不正な場合、フィールドが欠けている場合、空白のみのテキスト、未対応の種類は422を返し、どちらのタブも変更されませんでした。不正なJSONは422を返しました。プラットフォーム認証情報の欠落や不正な認証情報は403を返しました。

Googleへの書き込み失敗:レビューしたバージョン1.9.2には、フロー内のGoogleエラー分岐がありません。Google Sheetsのエラーによりグラフが停止し、スプレッドシートの詳細を含む未加工のプラットフォームエラーが返ることがあります。成功時レスポンスの必要な項目だけを取り出す処理では、この失敗を捕捉しません。使用前にアクセス権と範囲を確認してください。呼び出し側のアプリケーションは、未加工のレスポンスをエンドユーザーに公開せずにエラーを処理する必要があります。

テスト結果

本番テスト34件すべてが合格しました。内訳は、受け付けたリクエスト8件、検証による拒否24件、認証による拒否2件です。各リクエスト後に、両方のタブの確認が合格しました。データ行数はsalesが0、supportが0から、salesが3、supportが5になりました。同一のサポートリクエストを再送すると、別の行が追加されました。一時APIキーの削除も確認済みです。

本番テスト結果 — 2026年10月9日 MYT
ケース期待結果確認されたHTTP行数/本文/判定
T01 有効なsales200; sales +1, support +0200sales 0 -> 1; support 0 -> 0データ行。両タブの確認が合格。レスポンス形式が一致。合格
T02 有効なsupport200; sales +0, support +1200sales 1 -> 1; support 0 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T03 typeの欠落422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T03 nameの欠落422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T03 emailの欠落422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T03 requestの欠落422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T04 typeの型不一致422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T04 nameの型不一致422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T04 emailの型不一致422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T04 requestの型不一致422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T05 不正なJSON422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T06 キーの欠落403; sales +0, support +0403sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。プラットフォームの本文は省略。合格
T07 不正なキー403; sales +0, support +0403sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。プラットフォームの本文は省略。合格
T08 拒否されたtype "other"422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T08 拒否されたtype "Sales"422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T08 拒否されたtype "sales "422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T08 拒否されたtype " support"422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T08 拒否されたtype ""422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T09 不正なemail422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T09b 空白を含むemail422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T10 空白のみのname422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T10 空白のみのrequest422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T11 オブジェクト以外の本文 null422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T11 オブジェクト以外の本文 []422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T11 オブジェクト以外の本文 42422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T11 オブジェクト以外の本文 "\"plain text\""422; sales +0, support +0422sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T12 別のsales入力200; sales +1, support +0200sales 1 -> 2; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格
T13 別のsupport入力200; sales +0, support +1200sales 2 -> 2; support 1 -> 2データ行。両タブの確認が合格。レスポンス形式が一致。合格
T14a 重複送信の1回目200; sales +0, support +1200sales 2 -> 2; support 2 -> 3データ行。両タブの確認が合格。レスポンス形式が一致。合格
T14b 重複送信の2回目200; sales +0, support +1200sales 2 -> 2; support 3 -> 4データ行。両タブの確認が合格。レスポンス形式が一致。合格
T15 RAWでの数式に似たテキスト200; sales +1, support +0200sales 2 -> 3; support 4 -> 4データ行。両タブの確認が合格。レスポンス形式が一致。合格
T16 Unicodeと余分なフィールド200; sales +0, support +1200sales 3 -> 3; support 4 -> 5データ行。両タブの確認が合格。レスポンス形式が一致。合格
T17 偽装された振り分けフィールド422; sales +0, support +0422sales 3 -> 3; support 5 -> 5データ行。両タブの確認が合格。レスポンス形式が一致。合格
T18 全必須フィールドの欠落422; sales +0, support +0422sales 3 -> 3; support 5 -> 5データ行。両タブの確認が合格。レスポンス形式が一致。合格

ダウンロード

インポート可能なワークフローのダウンロード:提供なし。インポートしたコピーのテストは未実施。上記のノード対応表は、本番テスト済みの設定を記載しています。エクスポートを共有する前に、Googleアカウントの詳細、接続識別子、Spreadsheet ID、非公開のエンドポイント、ワークスペース識別子を削除してください。

必要な設定

  • AI Flowi Workflowのワークスペースと、送信側で保持するプラットフォーム認証情報。
  • 認可済みのGoogle接続、非公開スプレッドシートのSpreadsheet ID、設定済みの2つのタブ範囲。
  • 両方のタブの1行目に見出しtype,name,email,requestを配置し、書き込み先の表には結合セルを使用しないこと。
  • JQクエリを表示した状態、POSTの有効化、From Flowレスポンスモード、RAW書き込み、上記のレスポンスステータス設定。

テストしたバージョンと日付

本番テスト済みバージョン:AI Flowi Workflow 1.9.2。本番テスト日:2026年10月9日 (MYT)。検証の証拠は、このグラフと合成テストデータを対象としています。インポートしたコピーの結果は記録されていません。

使用量と費用の前提

ノードの実行1回につき1 Flowi Tokenを使用します。プラン:Goは年払いで月額USD8から(月払いUSD10)、全5プランでPro 500まで。全プランは料金ページに掲載しています。

振り分けが成功した場合は、Webhook、検証クエリ、検証ルーター、種類判定クエリ、種類別ルーター、選択した書き込み、選択したレスポンスクエリ、選択したレスポンスの計8回のノード実行を見込みます。入力を拒否した場合は4回のノード実行を見込みます。認証失敗時には、グラフ内のノードは実行されない想定です。これらは設計上の回数であり、実測使用量は未測定。トランザクションログの確認が必要です。選択されなかった分岐は、下流のノードを実行せずに停止すると仮定しています。

リクエストごとに書き込みが1回成功するとした設計上の推定
成功したリクエスト数ノード実行回数/Flowi Tokens前提
100800再試行なし。リクエストごとに振り分け先を1つ選択
1,0008,000再試行なし。Plusの月間10,000トークン以内
10,00080,000再試行なし。Plusの月間10,000トークンを70,000超過

モデルや有料のサードパーティAPIを使用するコンポーネントはありません。既存のGoogleアカウントとSheetsへのアクセス権があることを前提としています。サードパーティAPIやモデルの使用料はプランに含まれません。該当するアカウントの料金や割り当ては別途適用されます。不正なリクエストは拒否側の経路を通り、再試行が成功するたびにノード実行8回と1行が追加されます。本番テストでの読み戻しには追加のノード実行が必要ですが、これらのリクエスト別シナリオには含めていません。超過料金は想定していません。

計画した34件のテストスイートは、再試行なしでWebhook側のノード実行160回と読み戻し側のノード実行70回、合計230 Flowi Tokensを見込みます。インポートしたコピーを再テストすると、同じ使用量が再度発生します。これらは推定値です。テストで実際に使用した量は未測定です。

制限事項

  • 本番テスト34件は合格しています。インポートしたコピーの動作とエディターの自動保存は未検証です。
  • 対応する種類は2つのみです。分類、種類の自動修正、重複排除、並行リクエスト間のキュー順序制御はありません。
  • 再送すると別の行が追加されます。書き込み成功後にレスポンスがタイムアウトすると、送信側の再試行で重複する可能性があります。
  • RAWは、この書き込み時の数式評価を防ぎます。後でエクスポートしたり別のアプリケーションに読み込んだりする場合は、スプレッドシートのテキストを信頼できない入力として扱ってください。
  • 制御されたGoogleエラーレスポンス、自動再試行、独自のレート制限、メールボックスの検証は含まれません。Googleの割り当て、シートの上限、プラットフォームのペイロード上限が適用されます。

次の手順

自身の非公開タブでテストを再実行してください。機密情報を除去したインポート用コピーを検証し、送信側でタイムアウトや重複をどう扱うかを決め、実際のリクエストを使う前にスプレッドシートへのアクセス失敗をテストしてください。WebhookからGoogle Sheetsへの連携リファレンス、コンポーネントカタログ、その他の活用例を参照してください。