「問い合わせ受付」ワークフローは、Webの問い合わせをGoogleスプレッドシート「問い合わせ一覧」に残してSlackの #問い合わせ に知らせるところまでできています。この記事では、その問い合わせを社内の顧客管理(kintone・Salesforce・HubSpot)にも入れます。同じ人から2回目の問い合わせが来ても顧客が2人に増えないよう、既にいれば更新し、いなければ登録する形で作ります。逆向きの、顧客管理で何か起きたらn8nを動かす方法も3つそれぞれで書きます。前提はn8n 2.44.7(2026年10月時点の安定版)がn8n.example.co.jpのような独自ドメインとHTTPSで動いていることです。HTTP Requestノードの基本は「n8nで外部サービスとつなぐ:Webhook・HTTP Request・API」に書いています。
この記事の内容
先に決めること
どこを正にするか
顧客の情報は顧客管理を正にし、スプレッドシート「問い合わせ一覧」は受けた記録に役割を下げます。担当者や対応状況を両方で直す運用は、数週間で食い違います。
同じ人をどう見分けるか
新規か更新かを決める鍵はメールアドレスにします。会社名は「株式会社サンプル」と「(株)サンプル」のように揺れ、氏名には同姓同名がいます。照合の前に、前後の空白を落として小文字にそろえます。
上書きする項目と、しない項目
| 項目 | 新規のとき | 既存のとき |
|---|---|---|
| 会社名・氏名 | 入れる | 入れる(新しい情報とみなす) |
| 最新の問い合わせ・最終問い合わせ日 | 入れる | 上書きする |
| 担当者・対応状況・商談の段階 | 初期値に任せる | 触らない |
担当者や商談の段階を連携で上書きすると、営業が手で直した内容が問い合わせのたびに消えます。顧客管理には連携専用のユーザーかAPIの鍵を用意し、個人のアカウントでつながないようにします。担当者が辞めてアカウントを止めた日に連携も止まるからです。
3つの顧客管理の比べ方
専用ノードの有無
| サービス | n8nのノード | 顧客管理側から動かすトリガー | ノードで足りないとき |
|---|---|---|---|
| kintone | 無い | 無い | HTTP Requestで kintone REST API を呼ぶ |
| Salesforce | 「Salesforce」(Lead・Contact・Task・Search など12種) | 「Salesforce Trigger」(一定間隔で取りに行く) | HTTP Request の「Predefined Credential Type」で同じCredentialを使う |
| HubSpot | 「HubSpot」(Contact・Company・Deal・Engagement など) | 「HubSpot Trigger」(開発者用アプリが要る) | 同上 |
kintoneにはコミュニティ製のノードもありますが、公式ではなく、n8nの版が上がったときに動き続ける保証がありません。HTTP RequestならAPIの仕様どおりに書けます。
認証の方式
| サービス | 方式 | n8nのCredential | 鍵の範囲 |
|---|---|---|---|
| kintone | APIトークン | 「Header Auth」(Name に X-Cybozu-API-Token) | アプリごと。閲覧・追加・編集などを選ぶ |
| Salesforce | OAuth2(またはOAuth2 JWT) | 「Salesforce OAuth2 API」 | ログインしたユーザーの権限 |
| HubSpot | サービスキー(またはOAuth2) | 「HubSpot Service Key」 | 鍵を作るときに選んだスコープ |
HubSpotはUIで作る非公開アプリ(private app)を従来型の扱いに移し、サービスキーを勧めています。サービスキーは2026年10月時点で公開ベータです。HubSpotノードの「Authentication」に残っている「API Key」は、HubSpot側で廃止済みなので使いません。Credentialの共有と権限は「n8nの認証情報(Credential):OAuth2・APIキー・共有と権限」に書いています。
つなぐ手間と上限
| kintone | Salesforce | HubSpot | |
|---|---|---|---|
| 準備 | APIトークンを生成し、アプリを更新 | External Client App を作り、OAuthでつなぐ | サービスキーを作り、スコープを選ぶ |
| 新規か更新か | 重複禁止のフィールドを鍵にUPSERTで1回 | 先に検索(SOQL)してIfで分ける | 「Create or Update」がメールで判定 |
| 顧客管理側から動かす | アプリのWebhook | Salesforce Trigger、またはフローからHTTPで呼ぶ | ワークフローの「Send a webhook」 |
| APIの上限 | 1アプリ1日10,000件(スタンダードコース)、同時100まで(1ドメイン) | 24時間あたり100,000件+ライセンス数に応じた分(Enterprise など) | 10秒に100〜190件(1アプリ)、1日250,000件から(アカウント全体) |
問い合わせが1日20件ほどなら、どれも上限は問題になりません。当たるのは一定間隔で取りに行く作りのときで、1分ごとなら取りに行くだけで1日1,440回になります。


ワークフローの形
受けたデータを整える「Edit Fields (Set)」の名前を「整形」に変え、ここから顧客管理へ入れる枝を分けます。スプレッドシートとSlackの間に直列で入れないのは、顧客管理が落ちていても記録と通知を止めないためです。後ろのノードからは {{ $('整形').item.json['メール'] }} で受けた値を取れます。この書き方は「n8nの式(Expression)とデータの扱い:$json・ノードの参照・日付・JSON」に書いています。「整形」には照合用のメールを足します。
| 項目 | 式 |
|---|---|
| メール | {{ $json.body.email.trim().toLowerCase() }} |
kintoneに入れる
例は「顧客管理」アプリ(アプリID 12)に、会社名・氏名・メール・最新の問い合わせ・最終問い合わせ日・登録元・対応状況のフィールドがある形で、フィールドコードはフィールド名と同じ日本語にしてあります。
メールを重複禁止にし、APIトークンを作る
UPSERTモード(あれば更新、無ければ登録)の鍵にできるのは、「値の重複を禁止する」を設定した「文字列(1行)」か「数値」のフィールドだけです。
- アプリの設定の「フォーム」タブで、メールのフィールドの「値の重複を禁止する」にチェックを入れる。既に重複があると設定できないので先に片付ける。
- 「設定」タブの「カスタマイズ/サービス連携」から「APIトークン」を開き、「生成する」を押す。
- 「アクセス権」で「レコード閲覧」「レコード追加」「レコード編集」にチェックを入れる。UPSERTは追加と編集の両方が要る。
- 「保存」を押し、「アプリを更新」まで押す。押し忘れるとトークンが効かない。
- n8nで「Header Auth」のCredentialを作り、Nameに
X-Cybozu-API-Token、Valueにトークンを入れる。
APIトークンで入れたレコードは、作成者が「Administrator」になります。「登録元」に Web問い合わせ と入れておくと、後で数えられます。cybozu.comでIPアドレスの制限をかけている会社は、n8nのサーバーのIPを許可するか、Basic認証のヘッダーを足します。
UPSERTで登録か更新を1回でやる
1件用のAPIではなく、複数のレコードを更新するAPI(records.json)に "upsert": true を付けます。
- 「整形」の後ろにHTTP Requestを足し、名前を「kintoneに登録」にする。
- 「Method」を
PUT、「URL」をhttps://example.cybozu.com/k/v1/records.jsonにする。 - 「Authentication」を「Generic Credential Type」、「Generic Auth Type」を「Header Auth」にし、上のCredentialを選ぶ。
- 「Send Body」をオンにし、「Body Content Type」を「JSON」、「Specify Body」を「Using JSON」にして下を入れる。
{
"app": 12,
"upsert": true,
"records": [
{
"updateKey": { "field": "メール", "value": "{{ $json['メール'] }}" },
"record": {
"会社名": { "value": {{ JSON.stringify($json['会社名']) }} },
"氏名": { "value": {{ JSON.stringify($json['氏名']) }} },
"最新の問い合わせ": { "value": {{ JSON.stringify($json['本文']) }} },
"最終問い合わせ日": { "value": "{{ $now.setZone('Asia/Tokyo').format('yyyy-LL-dd') }}" },
"登録元": { "value": "Web問い合わせ" }
}
}
]
}

メールがあればそのレコードが更新され、無ければ新しく作られます。record に書かなかったフィールドは、更新なら元の値のまま、新規ならアプリの初期値になります。対応状況を書かないのはこのためです。返事の records[0].operation が INSERT(新規)か UPDATE(更新)かで結果が分かります。1件用のAPI(record.json)にはupsertの指定がありません。
新規か既存かで通知を変える
- 「kintoneに登録」の後ろにIfを足す。
- 条件を
{{ $json.records[0].operation }}がINSERTと等しい(String の「is equal to」)にする。 - trueのSlackには「新しいお客様」、falseには「既存のお客様から再度」と書き分ける。
- 文面にレコードのURL
https://example.cybozu.com/k/12/show#record={{ $json.records[0].id }}を入れる。

既存のデータに重複が残っていてメールを重複禁止にできないときは、先に探します。HTTP Requestを GET で records.json に向け、「Send Query Parameters」で app に 12、query に メール = "{{ $json['メール'] }}" limit 2 を入れます。0件なら追加、1件なら records[0].$id.value で更新、2件ならどちらを直すか機械では決められないのでSlackで人に確かめます。値に " や \ が入るときは \" のようにエスケープします。
Salesforceに入れる
Salesforceは、まだ商談になっていない人をリード(Lead)、取引のある会社の人を取引先責任者(Contact)で持つのが標準です。取引先責任者かリードにいればToDoを足し、どちらにもいなければリードを作ります。
つなぐ
Credentialは「Salesforce OAuth2 API」、Salesforce側は「アプリケーションマネージャー」の「New External Client App」で作ります。手順は「n8nで外部サービスとつなぐ:Webhook・HTTP Request・API」と同じで、コールバックURLはセルフホストなら https://n8n.example.co.jp/rest/oauth2-credential/callback、n8n Cloudなら https://oauth.n8n.cloud/oauth2/callback です。つなぐときにログインしたユーザーの権限がそのままn8nの権限になるので、リード・取引先責任者・ToDoの作成と参照だけを許可した連携専用のユーザーでつなぎます。Professional EditionはAPIを有効にした契約でないとつながらないので、先に確かめます。
取引先責任者とリードを探す
- 「整形」の後ろにSalesforceノードを足し、名前を「取引先責任者を探す」にする。
- 「Resource」を「Search」、「Operation」を「Query」にし、「Query」に下の1つ目を入れる。
- ノードの「Settings」で「Always Output Data」(結果が無くても空のアイテムを出す)をオンにする。
- 後ろにIfを足し、
{{ $json.Id }}が空でない(String の「is not empty」)を条件にする。 - falseの出口に、2つ目のSOQLで同じ形の「リードを探す」とIfをもう1組置く。
SELECT Id, Name, AccountId FROM Contact WHERE Email = '{{ $('整形').item.json['メール'] }}' LIMIT 1
SELECT Id, Name FROM Lead WHERE Email = '{{ $('整形').item.json['メール'] }}' AND IsConverted = false LIMIT 1

3を忘れると、見つからなかったときにSearchが何も出さず、そこでワークフローが終わります。新しいお客様ほど登録されない、という気づきにくい壊れ方です。IsConverted = false は取引先責任者に変換済みのリードを拾わないためです。
Lead にも「Create or Update」(upsert)があり、「Match Against」で照合する項目を選べます。選べるのは外部IDかIDルックアップの性質を持つ項目だけで、同じ値が2件以上あるとSalesforceはエラーを返します。リードと取引先責任者の両方を見るなら、探してから分けるほうが確実です。
いなければリード、いればToDo
- 「リードを探す」の後ろのIfのfalseにSalesforceノードを足し、「Resource」を「Lead」、「Operation」を「Create」にする。
- 「Company」に会社名、「Last Name」に氏名を入れる。
- 「Additional Fields」から「Email」「Description」「Lead Source Name or ID」を足し、メール・本文と、一覧から「Web」を選ぶ。
- 2つのIfのtrueを、Salesforceノード「ToDoを足す」にまとめてつなぐ。「Resource」は「Task」、「Operation」は「Create」。
- 「Status Name or ID」を一覧から選び、「Additional Fields」で「Who ID」に
{{ $json.Id }}、「Subject Name or ID」にWeb問い合わせ、「Description」に本文を入れる。

リードの必須は「Last Name」(姓)と「Company」です。フォームが姓と名を分けていないなら、氏名をまるごと「Last Name」に入れます。空白で割って姓と名にする式は、「山田太郎」のように空白の無い入力で崩れます。「Who ID」はToDoを付ける人(リードか取引先責任者)のIDです。
HubSpotに入れる
HubSpotはメールアドレスでコンタクトを見分けるので、「Create or Update」が新規と更新を1回でやります。
- HubSpotで「Development」の「Keys」から「Service keys」を開き、「Create service key」を押す(スーパー管理者か開発者ツールの権限が要る)。
- 「Add new scope」で
crm.objects.contacts.readとcrm.objects.contacts.writeを選び、「Update」、「Create」と押す。 - キーを「Show」で表示してコピーし、n8nの「HubSpot Service Key」のCredentialに貼る。
- 「整形」の後ろにHubSpotノードを足し、「Credential」で上のCredentialを選び、「Resource」を「Contact」、「Operation」を「Create or Update」にする。
- 「Email」にメール、「Contact Properties」から「Company Name」「Last Name」「Message」を足して会社名・氏名・本文を入れる。

返事にはコンタクトのID vid と、新しく作ったかどうかの isNew が入り、Ifで通知を分けられます。対応のタスクは、後ろのHubSpotノードで「Resource」を「Engagement」、「Type」を「Task」にし、「Associations」の「Contact IDs」に {{ $json.vid }} を入れて作ります。Engagementで作れるのは通話・メール・会議・タスクで、メモ(ノート)はありません。
「Lifecycle Stage Name or ID」(ライフサイクルステージ)は入れません。APIからは前の段階に進めることしかできず、戻すには先に値を空にする必要があるので、商談中のお客様の段階を連携が動かす事故になります。サービスキーは半年ごとの入れ替えが勧められていて、「Rotate and expire later」なら古いキーは7日後に切れます。その間にCredentialを差し替えます。
顧客管理の側から動かす
kintoneで対応状況が「完了」になったらSlackに知らせる、Salesforceでリードができたらシートに足す、といった逆向きの連携です。
kintoneのWebhook
- n8nでWebhookを置き、「HTTP Method」を
POST、「Path」を推測されにくい長い文字列にする。 - kintoneのアプリの設定の「設定」タブ、「カスタマイズ/サービス連携」から「Webhook」を開いて追加する。
- URLの欄にn8nのProduction URLを貼り、先頭の
https://を消す。 - 通知を送信する条件で「レコードの編集」などを選び、有効にして保存し、「アプリを更新」を押す。
届く内容は body.type(ADD_RECORD・UPDATE_RECORD・UPDATE_STATUS など)、body.app.id、body.record で、値は {{ $json.body.record['対応状況'].value }} のように取ります。kintoneのWebhookにはヘッダーで鍵を付ける設定が無いので、Pathを長くし、最初のIfで body.app.id が 12 かを確かめます。1アプリに10個まで、通知はドメイン全体で1分に60回までで、CSVの読み込み、一括削除、複数のレコードを扱うREST APIでの操作では送られません。n8nが同じアプリを1件用のAPIで更新すると、その通知がまた届いて繰り返し動くことがあるので、n8nからの更新は上の records.json の形で書きます。裏返すと、n8nが records.json で入れた登録や更新ではkintoneのWebhookは動きません。新しいお客様の通知は、kintoneのWebhookで拾わずに「問い合わせ受付」の中で出します。
Salesforce
| 方法 | 速さ | 向いている場面 |
|---|---|---|
| n8nの「Salesforce Trigger」 | 取りに行く間隔しだい | 数分の遅れが許される通知・転記 |
| フローの「HTTP Callout」でn8nのWebhookを呼ぶ | フローが動いたとき | 条件をSalesforce側で絞りたい |
「Salesforce Trigger」はn8nが一定間隔で取りに行くノードで、「Trigger On」で「Lead Created」などを選び、「Poll Times」で間隔を決めます。取りに行くたびにAPIを使うので、毎分にせず5〜10分にします。間隔を待たずに動かしたいときは、フローのHTTP Calloutでn8nのProduction URLを呼びます。認証は名前付き認証情報(と外部認証情報)で行い、フローの側ではリクエストヘッダーを足せないので、n8nの「Header Auth」で確かめる鍵は認証情報の側に持たせます。300以上のステータスが返るとエラーになり、フローの障害パスに流れます。フローの作り方は姉妹サイトのSalesforce自作ガイドに書いています。アウトバウンドメッセージもn8nのWebhookで受けられます。SOAPで送られ、受け取れなければ最大24時間、間隔を空けて送り直され、過ぎると捨てられます。受け取ったことを返す応答が要り、n8n側でSOAPのXMLを読み解く手間もかかるので、新しく作るならHTTP Calloutのほうが組みやすいです。n8nがSalesforceを更新すると「Lead Updated」がその更新も拾うので、最終更新者が連携専用のユーザーなら止めるIfを入れます。
HubSpotのワークフロー
HubSpotのワークフローの「Send a webhook」アクションで呼びます。使えるのはData HubのProfessionalかEnterpriseです(2026年10月時点)。
- n8nでWebhookを置き、「Authentication」を「Header Auth」にして、Nameに
X-Hubspot-Key、Valueに長いランダムな文字列を入れたCredentialを選ぶ。 - HubSpotの「Automation」の「Workflows」でワークフローを開き、「+」から「Data ops」の「Send a webhook」を選ぶ。
- メソッドを
POST、URLにn8nのProduction URL(HTTPSのみ)を入れる。 - 認証でAPIキーを選び、名前に
X-Hubspot-Key、値に1と同じ文字列を入れて、ヘッダーで送る設定にする。 - テストを送り、n8nのExecutionsに届いたのを確かめてから保存する。
失敗した送信は最長3日まで送り直されますが、4XXの返事は送り直されません(429だけは送り直す)。n8nが落ちていても3日以内に戻れば取りこぼさない一方、鍵の設定違いで401を返していた間の分は戻りません。n8nの「HubSpot Trigger」は、HubSpotの開発者アカウントでアプリを作って「HubSpot Developer API」のCredentialを用意する必要があり、2つ目のトリガーを有効にすると前のトリガーが止まります。ワークフローの契約が無いなら、Schedule TriggerとHubSpotノードの「Get Recently Created/Updated」で取りに行きます。
応用
「n8nでAIエージェントを作る:ChatGPT・Claude・Geminiをつなぐ」で判定した問い合わせの種類を、顧客管理の選択肢の項目にも入れられます。AIの答えは選択肢と1文字でも違うと入らないので、間にSwitchを置いて決まった選択肢に寄せ、当たらないものは「その他」にします。顧客管理へ入れる部分はサブワークフローに切り出しておくと、顧客管理を替えても「問い合わせ受付」本体は直さずに済みます(「n8nの定期実行とサブワークフロー:Schedule Triggerと部品化」)。スプレッドシート「問い合わせ一覧」には全件を残し、顧客管理のノードが失敗したらエラーの出口からSlackに知らせます。流し直すときの元の記録になります。シート側の重複は「n8nとGoogleスプレッドシート連携:読み書き・更新・重複を防ぐ」、エラー通知は「n8nを止めずに運用する:アップデート・バックアップ・エラー通知・脆弱性」に書いています。
できないことと、その代わり
| できないこと | 代わりの手 |
|---|---|
| kintoneを専用ノードで扱う | HTTP Requestで kintone REST API を呼ぶ |
| kintoneのWebhookにヘッダーの鍵を付ける | Pathを推測されにくくし、body.app.id を確かめる |
| CSV読み込みや一括操作をkintoneのWebhookで拾う | Schedule Triggerで 更新日時 > "2026-10-26T00:00:00+09:00" のクエリで取りに行く |
| Salesforce Triggerで間隔を待たずに動かす | フローのHTTP Calloutでn8nのWebhookを呼ぶ |
| HubSpot Triggerを複数のワークフローで使う | ワークフローの「Send a webhook」か、Scheduleで取りに行く |
| HubSpotノードでメモ(ノート)を作る | HTTP RequestのPredefined Credential TypeでAPIを呼ぶ |
| 表記の揺れた会社名を機械で同じ会社とみなす | メールで照合し、会社のまとめは人が画面でやる |
よく詰まるところ
| 症状 | 原因 | 直し方 |
|---|---|---|
| kintoneで一部の項目だけ空 | フィールド名で書いた。存在しないフィールドコードは無視される | 設定画面でフィールドコードを確かめる。フィールド名を変えてもコードは変わらない |
| kintoneのドロップダウンでエラー | 選択肢と全角・半角や空白が違う | 選択肢の文字をコピーして使う |
| kintoneで権限エラー | トークンのアクセス権不足、または「アプリを更新」を押していない | 追加と編集にチェックを入れ、アプリを更新する |
| ルックアップのあるアプリでエラー | 参照先のアプリのトークンが無い | 参照先のトークンも X-Cybozu-API-Token にカンマ区切りで並べる(9個まで) |
| kintoneのWebhookが届かない | アプリを更新していない、Test URLのまま | アプリを更新し、Production URLに替える |
| Salesforceで新しいお客様だけ登録されない | Searchが0件で何も出さず止まった | 「Always Output Data」をオンにする |
| Salesforceで選択リストのエラー | 実際に出会った例では、画面の表示ラベルを送っていた | 一覧から選ぶか、選択リスト値のAPI参照名を送る |
| Salesforceでリードの作成が重複のエラーで止まる | 実際に出会った例では、組織の重複ルールが同じメールのリードを止めていた | 探してから分ける作りにする。ルールは外さない |
| n8n CloudからSalesforceにつなげない | 連携ユーザーにアプリを承認する権限が無い | プロファイルに「Approve Connected Apps for Non-Admins」を付ける |
| HubSpotのカスタムプロパティに入らない | 表示名を書いた | プロパティの設定で内部名と選択肢の内部の値を確かめる |
| HubSpotが429を返す | 10秒あたりの上限。検索は1秒5回まで | HTTP RequestのBatchingで間隔を空け、Retry On Failを足す |
| 作った直後のHubSpotのコンタクトが検索に出ない | 検索に出るまで少し時間がかかる | 検索せず「Create or Update」の返事の vid を使う |
詰まったら、Executionsで失敗した実行を開き、顧客管理のノードの出力にあるエラーの本文を読みます。kintoneなら code と message に原因が書かれています。SalesforceとHubSpotも、エラーの本文に相手のサービスが返した理由が出ます。
次にやること
- n8nで外部サービスとつなぐ:Webhook・HTTP Request・API
- n8nとGoogleスプレッドシート連携:読み書き・更新・重複を防ぐ
- n8nの認証情報(Credential):OAuth2・APIキー・共有と権限
- n8nの式(Expression)とデータの扱い:$json・ノードの参照・日付・JSON