はじめに
こんにちは、しおです。最近は直接的な開発からは離れて、PM を主にやっています。
今日は、「ビジネス部門の現場にて先行導入された外部サービスがあり、"このサービス内の情報を自社開発の CRM に転記する" という業務の効率化をしたい、という要望が来た。」という状況についての対応策を考えてみたいと思います。
というのも、こういった展開は事業系の会社ではあるあるなのではないかと勝手に思っていまして、私も最近 PM として同じような状況になったことがあるので、その時の思考整理も兼ねて、具体的にどのような連携パターン(プラン)があり得るのか、それぞれのメリット・デメリットをまとめてみました。
※ なお、本記事は実際の事例をベースにしていますが、ブログ用に大幅に構成を変更したフィクションです。記事内で題材としている外部サービスも架空の設定であり、実在する特定の企業・サービスとは一切関係ありません。
想定シナリオ
今回の想定シナリオは、下記の通りです。
- ビジネス部門の施策で、マーケティング施策用の外部ツール(以下、"外部サービス" と呼称)を利用することになった。
- 実証施策のため、いち早いサービス導入とフィードバックが必要になり、現場で先行導入開始。
- 実証施策の流れで、外部サービスの利用が現場に定着する。
- 外部サービスから自社の CRM(以下、"CRM" と呼称)には 手動で必要な情報をコピペして転記する という運用が現場に定着する。
- ゆくゆくは CRM に外部サービスの情報を効率的に同期したいと現場は考えている。
また、連携対象の外部サービスの想定仕様は下記の通りと仮定します。
なお、この仕様が今回の悩みどころです。
- 外部サービスの概要:顧客へのアプローチやアクション履歴を管理するマーケティングツール。
- 外部連携の手段:Webhook と API が用意されている。
- Webhook の仕様
- イベント発火タイミング:顧客による何らかのアクション発生時(リアルタイム)
- 課題:ペイロードに、CRM連携に必要な「顧客メールアドレス」等の個人情報が含まれていない。
- 含まれているのは
event_idとexternal_user_id(外部サービス内のID)のみ。 - つまり、Webhook だけでは「誰がアクションしたのか」が特定できず、事前にIDのマッピングテーブル等を用意しない限り、これ単体での CRM 自動転記は困難。
- 含まれているのは
- API の仕様
- 提供機能:アクション履歴やユーザー情報の取得(
GET /v1/usersGET /v1/activities等) - 課題:検索条件(フィルタリングパラメータ)が貧弱。
- 利用できるパラメータはページネーション用の
pageとlimitのみ。 - 「更新日時」や「登録日」での絞り込みができない。
- つまり、「昨日アクションがあったデータ」だけをサーバーサイドで絞り込む術がなく、リストを総当たりで取得して自社側でループ処理・判定をする必要がある。
- 利用できるパラメータはページネーション用の
- 提供機能:アクション履歴やユーザー情報の取得(
このように、自社の CRM に外部のサービスを連携したいという要望がありつつも、肝心の外部サービスの連携仕様が少ない場合に、どのように対応していくか、ということを考えていこうと思います。
王道パターン:Webhook 利用
まず最初に思いつくのが、外部サービス側で提供されている Webhook を利用したリアルタイム連携でしょうか。

正直、これですんなりいけるのがシンプルなので一番嬉しいです。
ただ、今回のシナリオのように肝心の Webhook 経由で連携される情報に現場で欲しい情報が含まれていなかったり、連携のタイミングや連携条件(フィルタリング等)に不都合があったりすると、どうでしょうか。

今回、私たちが悩まされたのは、まさにそのような状況でした。
Webhook 以外の連携方式を色々考えてみた
ということで、次は外部サービス側の Webhook 等の連携仕様(「情報」「条件」「タイミング」)に左右されないプランをいくつか考えてみようと思います。
プランA:割り切って、自動連携できる範囲のメリットは享受して、残りは手動で対応する
いきなり割り切りプランを提示してしまい大変恐縮なのですが、「少なくとも自動連携できているだけでもありがたい」「提供されていないものは仕方がない」ということで、自動化できる部分は自動化して、それ以外は諦めて手動で対応、もしくは連携を諦めるというプランです。

これを、先述の悩ましい三要素の軸で評価してみましょう。
| 悩ましい要素 | 制約への対応状況 |
|---|---|
| 情報 | ❌ 不足(手動補完) |
| 条件 | ❌ 選べない |
| タイミング | ⭕️ 自動(リアルタイム) |
- 情報:外部サービス側で提供されている情報(ID等)のみを自動で連携し、残りの情報は捨てる。もしくは後から手動で転記する。
- 条件:外部サービス側で提供されている条件(フィルタリングできず、全件飛んでくる)に従って自動で連携し、自社側で情報を取捨選択する。
- タイミング:外部サービス側で提供されているタイミング(リアルタイム)に従って自動で連携する。
外部サービスの仕様で実現できる範囲の自動化をするという省エネプランです。
省エネということで、システムの構築スピードが速いというメリットはありつつ、そうは言っても切り捨てられない情報については引き続き手動での転記をするなどの対応が必要で、現場側の負担が大きい形となってしまうため、出来れば避けたいところです。
プランB:Pull方式(CRM から外部サービス側の API をコール)にしてタイミングを握る
次は、Webhook ではなく API を利用するプランです。CRM 側から外部サービスの API をコールして、必要な情報を取得します。

| 悩ましい要素 | 制約への対応状況 |
|---|---|
| 情報 | 🔺 全件取得でカバー |
| 条件 | 🔺 全件取得でカバー |
| タイミング | ⭕️ 自社で制御可能 |
リアルタイム性が失われる可能性がある一方で、連携のタイミングについては完全にこちらでコントロールできるというメリットがあります。
一方で、今回のように検索条件が乏しい API の場合、「毎回全件取得して、自社側で差分を判定する」といったような実装が必要になり、データ量が増えると API のレートリミットに抵触するリスクや、差分検知ロジックの複雑化(冪等性の担保など)により実装工数が膨れ上がる懸念があります。
プランC:Webhook + API のハイブリッド
プランAの「タイミングの良さ」と、プランBの「情報の網羅性」を組み合わせた、いいとこ取りを目指すプランです。

処理の流れは以下のようになります。
- Webhook 受信:外部サービスから通知を受け取る。
- API コール:受け取った
external_user_idなどの情報をキーにして、外部サービスの API(GET /v1/users/{id}等)を叩きに行く。 - データ保存:API から返ってきた情報を CRM に保存する。
| 悩ましい要素 | 制約への対応状況 |
|---|---|
| 情報 | ⭕️ APIで完全取得(※ これも API の仕様次第ではあるが) |
| 条件 | 🔺 Webhook で絞れなくても、API コール時にフィルタリング |
| タイミング | ⭕️ ほぼリアルタイム |
パッと見では、これが今回のケースにおける「正解」に最も近いように見えます。
ただし、これにも「API のレートリミット(回数制限)」と「実装コスト」という懸念点は存在します。
もし外部サービス側で一括更新などが行われ、Webhook が短時間に大量(例えば数千件)に飛んできた場合、その回数分だけ愚直に API を叩くと、外部サービスの API レートリミットにあっという間に抵触してしまいます。
これを防ぐためには、自社側でジョブキュー等の仕組みを導入し、API コールの流量を制御する実装が必要になります。
プランAやBに比べると、システム構成がリッチになる分、構築コストが高くなってしまうのが悩みどころです。
プランD:ブラウザ拡張/ブックマークレットで「転記しやすい形」に整える(半自動化)
Webhook も API も満足に利用できない、あるいはプランCのようなリッチな実装をする工数が割けない状況で、現場では「外部サービスの画面上に表示されている情報を CRM に転記する」というような運用をしている場合に有効な(⚠ただし飛び道具的な)プランです。

具体的には、下記のような流れを想定しています。
- 画面上の情報を、特定フォーマットでクリップボードにコピーするブラウザ拡張機能やブックマークレットを作成し、現場に配布
- 自社 CRM 側で、上記フォーマットでのデータインポート機能を開発
- 上記機能を用いて、半手動でのデータ転記を実現
| 悩ましい要素 | 制約への対応状況 |
|---|---|
| 情報 | ⭕️ 画面通り取得可 |
| 条件 | ⭕️ 人が目で見て選択 |
| タイミング | 🔺 人の手による |
外部サービス側が変えられない(定数)のであれば、変数である自社サービス側を変えてしまおう、という発想です。一見では既存運用とほぼ変わらないように見えますが、「データ転記という作業の手間を解消」することにフォーカスしています。
「飛び道具的」と表現した通り、やや強引感は否めないとも思いつつも、転記する情報が多い場合などは意外とこれだけでも効果が大きい場合もあると思います。
ただし、外部サービスの画面仕様(DOM構造)が変わると即座に使えなくなるため、メンテナンスコストは考慮する必要がありますし、そもそものブラウザ拡張やブックマークレットの配布方法についても考慮が必要です。
いずれにせよ緊急回避的で、常用するプランではなさそうですね。
おわりに
今回、様々な連携パターン(プランA〜D)を検討してきましたが、痛感したのは「外部連携の難易度は、外部サービスがどのようなインターフェースを用意してくれているかに大きく左右される」という事実です。
理想を言えば、導入前にビジネス部門と開発部門で連携要件と運用をすり合わせ、仕様を踏まえてサービス選定まで行えるのが最も安全です。
とはいえ、スピード重視で先に運用が走ることは現実に起こり得ます。そうなると、「いっそのこと、現場の運用に完全にフィットするシステムを内製で開発してしまえば、連携の悩みもなくなり幸せなのでは」と頭をよぎることもあります。
しかし、マーケティングや営業支援といった特定領域における外部サービスベンダーの知見や機能の充実度、そして何より導入すればすぐに使えるというスピード感は、自社開発では簡単には真似できません。「餅は餅屋」という言葉がある通り、優れた外部サービスを使い倒すことはビジネスを加速させる上で不可欠です。
そう考えると、私たちが直面した連携の難しさは、外部サービスの良し悪しというよりも、「汎用的に作られた優れたサービス」と「自社独自の泥臭い業務フロー」の間に必然的に生じるギャップ なのかもしれません。
だからこそ、私たちエンジニアには そのギャップをどう技術で埋めるか が問われているのだと考えます。
完璧な自動化を前提にせず、どの要素が制約になっているかを見極めること。
API がリッチならプランCで堅牢に、スピード優先ならプランAでまずは動かす、どうしても仕様が噛み合わないならプランDで運用をカバー...。
すべてを自社で作るのでもなく、仕様だからと諦めるのでもなく、手持ちのカードの中で外部サービスの価値を最大限に引き出しつつ、現場の負担を減らす最適な構成を考える。それがエンジニアとしての醍醐味であり、外部サービスとうまく共存していくためのポイントなのだと改めて感じました。

現場の運用を止めずに、最短距離で負担を減らし、段階的に最適に近づけるような設計を今後も推し進めていきたいと考えています!
今回、技術ブログでは5回目の執筆をさせていただきました。
1回目~4回目は、それぞれ下記のような記事を書いたので、お時間ある方はこちらもぜひ読んでいってください!
techblog.styleedge.co.jp techblog.styleedge.co.jp techblog.styleedge.co.jp techblog.styleedge.co.jp
また、スタイル・エッジでは、一緒に働く仲間を絶賛大募集しています。
もし興味を持っていただけましたら、以下の採用サイトも一度覗いてみてください!