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."}
設定手順
- まず非公開のスプレッドシートで合成データを使用します。たとえば
salesとsupportという2つのタブを作成します。各タブのA1:D1にtype,name,email,requestをこの順序で配置します。 - そのスプレッドシートにアクセスできる、認可済みのGoogle接続を選択します。両方の書き込みノードでSpreadsheet IDを設定し、各Rangeを対応するタブに割り当てます:
'sales'!A:Dと'support'!A:D。 - Universal Webhookで
POST、Platform API Key認証、POSTレスポンスモードのFrom Flowを設定します。サーバーなどの信頼できるシステムからリクエストを送信します。Webhook認証のガイドを参照してください。 - 各JSON OperationsノードをJQ Expressionに設定し、クエリフィールドを表示した状態にします。入力の有効・拒否を判定するVerification Routerと、営業・サポートを判定するVerification Routerを1つずつ使用します。
- 書き込みには
RAWを使用し、Include Object Headersを無効にします。成功時のレスポンスを200 OK、検証時のレスポンスを422 Unprocessable Entityに設定し、コンテンツタイプをapplication/jsonにします。 - 実データを送る前に、以下の全ケースを実行し、リクエストごとに両方のタブを確認します。提示された本番テストでは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 | 検証済みの結果 |
検証用ルーター rejected | 422 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キーの削除も確認済みです。
| ケース | 期待結果 | 確認されたHTTP | 行数/本文/判定 |
|---|---|---|---|
| T01 有効なsales | 200; sales +1, support +0 | 200 | sales 0 -> 1; support 0 -> 0データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T02 有効なsupport | 200; sales +0, support +1 | 200 | sales 1 -> 1; support 0 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T03 typeの欠落 | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T03 nameの欠落 | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T03 emailの欠落 | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T03 requestの欠落 | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T04 typeの型不一致 | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T04 nameの型不一致 | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T04 emailの型不一致 | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T04 requestの型不一致 | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T05 不正なJSON | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T06 キーの欠落 | 403; sales +0, support +0 | 403 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。プラットフォームの本文は省略。合格 |
| T07 不正なキー | 403; sales +0, support +0 | 403 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。プラットフォームの本文は省略。合格 |
| T08 拒否されたtype "other" | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T08 拒否されたtype "Sales" | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T08 拒否されたtype "sales " | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T08 拒否されたtype " support" | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T08 拒否されたtype "" | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T09 不正なemail | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T09b 空白を含むemail | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T10 空白のみのname | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T10 空白のみのrequest | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T11 オブジェクト以外の本文 null | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T11 オブジェクト以外の本文 [] | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T11 オブジェクト以外の本文 42 | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T11 オブジェクト以外の本文 "\"plain text\"" | 422; sales +0, support +0 | 422 | sales 1 -> 1; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T12 別のsales入力 | 200; sales +1, support +0 | 200 | sales 1 -> 2; support 1 -> 1データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T13 別のsupport入力 | 200; sales +0, support +1 | 200 | sales 2 -> 2; support 1 -> 2データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T14a 重複送信の1回目 | 200; sales +0, support +1 | 200 | sales 2 -> 2; support 2 -> 3データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T14b 重複送信の2回目 | 200; sales +0, support +1 | 200 | sales 2 -> 2; support 3 -> 4データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T15 RAWでの数式に似たテキスト | 200; sales +1, support +0 | 200 | sales 2 -> 3; support 4 -> 4データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T16 Unicodeと余分なフィールド | 200; sales +0, support +1 | 200 | sales 3 -> 3; support 4 -> 5データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T17 偽装された振り分けフィールド | 422; sales +0, support +0 | 422 | sales 3 -> 3; support 5 -> 5データ行。両タブの確認が合格。レスポンス形式が一致。合格 |
| T18 全必須フィールドの欠落 | 422; sales +0, support +0 | 422 | sales 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回のノード実行を見込みます。認証失敗時には、グラフ内のノードは実行されない想定です。これらは設計上の回数であり、実測使用量は未測定。トランザクションログの確認が必要です。選択されなかった分岐は、下流のノードを実行せずに停止すると仮定しています。
| 成功したリクエスト数 | ノード実行回数/Flowi Tokens | 前提 |
|---|---|---|
| 100 | 800 | 再試行なし。リクエストごとに振り分け先を1つ選択 |
| 1,000 | 8,000 | 再試行なし。Plusの月間10,000トークン以内 |
| 10,000 | 80,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への連携リファレンス、コンポーネントカタログ、その他の活用例を参照してください。