
HubSpotへの文字起こし:検証済みの統合パス
Summarize this article with:
HubSpotのConversation Intelligence(Sales Hub Professional、1シートあたり月額90ドル)は、ネイティブダイヤラー、Zoom、Google Meet経由の通話を自動で文字起こしします。外部ダイヤラーからの通話、アップロードされた録音、対応範囲外の言語については、Calls API経由で文字起こしを送り込む必要があります。このガイドでは両方のパスを解説します。ネイティブCIに頼るべきケースと、webhookからエンゲージメントまでのパイプラインを自前で構築すべきケース、修正済みのアソシエーションIDと動作するエンドツーエンドのハンドラーも紹介します。
HubSpotに通話の文字起こしを取り込む最速の道は、通話の発信元によって変わります。 チームがHubSpotのネイティブ通話ツール、Zoom、Google Meetから発信しているなら、ProfessionalおよびEnterpriseプランではHubSpot組み込みのConversation Intelligenceが自動で文字起こしを処理します。外部ダイヤラーを使っている場合、サードパーティプラットフォームで着信を受けている場合、Gong、Zoom Cloud、S3バケットから録音を遡って取り込みたい場合は、Calls API経由で自分で文字起こしを送り込む必要があります。
このガイドでは両方のパスを扱います。
ネイティブのConversation Intelligenceで十分なケース
HubSpot Sales Hub Professional(年払いで1シートあたり月額90ドル)にはConversation Intelligenceが含まれ、アカウントあたり月最大1,500時間の文字起こしが利用できます。以下の方法で行われた通話は自動的に文字起こしされます:
- HubSpotの内蔵通話ツール
- ネイティブのZoom連携(ミーティング録画が自動同期)
- Google Meet(ProfessionalおよびEnterprise)
- HubSpotマーケットプレイスに掲載されている一部のサードパーティ通話プロバイダー
これらのシナリオでは、コードを1行も書かずにコンタクトのタイムラインに文字起こしが添付されます。マネージャーはコンタクトを開き、アクティビティフィードをスクロールして、通話直後に文字起こしを読んだり検索したりできます。
制限点:CIはユーザーごとに有料のSales HubまたはService Hubシートを必要とし、サポート対象リスト外のダイヤラーからの通話は文字起こしできず、ファイルシステムから手動でアップロードした録音も処理できません。
私見: チーム全体がすでにHubSpotのダイヤラーか、HubSpot経由のZoomを使っているなら、ネイティブCIが明らかな選択肢です。後述のAPIパスはギャップとなるケース向けです。
APIパスが必要なケース
APIレシピがカバーするのは:
- HubSpot外で録音された通話(Gongのエクスポート、Zoom Cloud単体、外部ダイヤラー、対面録音)。
- 過去の録音の一括バックフィル。
- 文字起こしエンジンを自分で制御したい言語や話者数のケース。
- 全営業担当者にSales Hub Professionalのシート料金を払えないチーム。
ワークフローはシンプルです:
- 営業担当者が通話を録音する(Zoom単体、外部ダイヤラー、アップロード音声)。
- 録音がアクセス可能なストレージ(S3、Cloudflare R2、Google Drive)に保存される。
- 自分のシステムがそのファイルを文字起こしAPIに送信する。
- 完了時にwebhookがハンドラーへ飛ぶ。
- ハンドラーが通話をHubSpotのコンタクトと商談に紐付ける。
- 文字起こしがHubSpotのCall Engagementとしてコンタクトのタイムラインに添付される。
- 必要に応じて、抽出されたシグナル(次のステップ、感情、懸念事項)で商談プロパティを更新する。
コード量は約200行。ほとんどのレベニューオプスチームは当日中に稼働させられます。
ステップ1:HubSpotプライベートアプリのセットアップ
HubSpotで:「設定」→「連携」→「プライベートアプリ」→「プライベートアプリを作成」。
名前を「Transcription Integration」にして、以下のスコープを要求します:
crm.objects.contacts.readcrm.objects.contacts.writecrm.objects.deals.readcrm.objects.deals.writecrm.objects.calls.writecrm.schemas.calls.read
アクセストークンを保存し、環境変数の HUBSPOT_TOKEN に設定します。
ステップ2:文字起こしwebhookの受信
文字起こし完了時に発火するハンドラーです。トレードオフについては文字起こしのwebhook vs ポーリングを参照してください。
import express from 'express';
import { Client as HubSpotClient } from '@hubspot/api-client';
import crypto from 'crypto';
const app = express();
const hubspot = new HubSpotClient({ accessToken: process.env.HUBSPOT_TOKEN });
app.post(
'/webhooks/transcript',
express.raw({ type: 'application/json' }),
async (req, res) => {
const sig = req.header('X-CATT-Signature');
const expected = crypto
.createHmac('sha256', process.env.TRANSCRIPT_WEBHOOK_SECRET)
.update(req.body)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return res.status(401).send('Bad signature');
}
const event = JSON.parse(req.body.toString());
if (event.event !== 'job.completed') return res.sendStatus(200);
await processCompletedTranscription(event.data);
res.sendStatus(200);
}
);

CRMのコンタクトや商談へ振り分けられる完成した文字起こし。
ステップ3:通話をHubSpotのコンタクトにマッチング
コンタクトのマッチングは、ほとんどのチームが過小評価する部分です。使えるシグナルは3つ:
電話番号。 ダイヤラーが発信番号を取得しているなら最良のシグナルです。検索前に正規化します:数字以外の文字をすべて除去すれば、「+55 11 99999-8888」と「551199998888」が同じレコードにマッチします。
async function findContactByPhone(phone) {
const digits = phone.replace(/\D/g, '');
const result = await hubspot.crm.contacts.searchApi.doSearch({
filterGroups: [{
filters: [{ propertyName: 'phone', operator: 'EQ', value: digits }]
}],
limit: 1
});
return result.results[0] ?? null;
}
メールアドレス。 通話がカレンダーで予定されていた場合、招待に参加者のメールアドレスが含まれています。それを使ってコンタクトを探します:
async function findContactByEmail(email) {
const result = await hubspot.crm.contacts.searchApi.doSearch({
filterGroups: [{
filters: [{ propertyName: 'email', operator: 'EQ', value: email }]
}],
limit: 1
});
return result.results[0] ?? null;
}
担当者とタイムスタンプによるフォールバック。 電話番号もメールアドレスも使えない場合(コールドコール、共有回線)、通話時刻頃にアクティブだった担当者のオープンな商談にフォールバックします。信頼性は下がりますが、文字起こしを完全に失うのを避けるのに役立ちます。
ステップ4:HubSpotのCall Engagementを作成
マッチングできたら、文字起こしをCall Engagementとして書き込みます。通話からコンタクトへの正しいアソシエーションタイプIDは194です。通話から商談への正しいIDは220です(195は誤りで、サイレントに失敗するか誤った関連付けが作られます)。
async function attachTranscriptToContact(contactId, dealId, data) {
const durationMs = data.duration_seconds * 1000;
const call = await hubspot.crm.objects.calls.basicApi.create({
properties: {
hs_timestamp: new Date().toISOString(),
hs_call_title: `Recorded call (${Math.round(data.duration_seconds / 60)} min)`,
hs_call_body: data.transcript,
hs_call_duration: String(durationMs),
hs_call_status: 'COMPLETED',
hs_call_direction: 'OUTBOUND',
hs_call_summary: data.summary ?? ''
},
associations: [
{
to: { id: contactId },
types: [{ associationCategory: 'HUBSPOT_DEFINED', associationTypeId: 194 }]
},
...(dealId
? [{
to: { id: dealId },
types: [{ associationCategory: 'HUBSPOT_DEFINED', associationTypeId: 220 }]
}]
: [])
]
});
return call.id;
}
hs_call_body フィールドに文字起こしテキストを入れます。長い通話の場合、テキストがHubSpotのプロパティごとの文字数上限に収まるかテストしてください(HubSpotドキュメントによると、現在の fieldType: textarea の上限値はproperties APIで確認してください)。非常に長い文字起こしの場合は、別のカスタムプロパティを使うか、全文を外部に保存してリンクを張ってください。
ステップ5:商談シグナルの抽出(任意)
文字起こしのレスポンスにサマリーが含まれる場合や、テキストに対してLLM処理を実行したい場合は、構造化されたシグナルを商談プロパティに送り込めます。まずHubSpotでカスタムプロパティを作成し(設定→プロパティ→商談)、次に更新します:
async function updateDealFromTranscript(dealId, transcript, summary) {
await hubspot.crm.deals.basicApi.update(dealId, {
properties: {
last_call_summary: summary ?? '',
last_call_date: new Date().toISOString().split('T')[0]
// Add your custom properties here: last_call_sentiment, next_steps, etc.
}
});
}
構造化された抽出(BANTシグナル、懸念事項、意思決定者)には、このステップの前に文字起こしテキストに対して別のLLM呼び出しを実行します。ミーティング文字起こしツールなら、この更新にそのまま流し込める整形済みサマリーを生成できます。
エンドツーエンドのハンドラー
async function processCompletedTranscription(data) {
const meta = await getCallMetadata(data.audio_filename);
const contact =
(await findContactByPhone(meta.phone)) ??
(await findContactByEmail(meta.email));
if (!contact) {
await logUnmatchedCall(data, meta);
return;
}
const deal = await getActiveDealForContact(contact.id);
await attachTranscriptToContact(contact.id, deal?.id ?? null, data);
if (deal && data.summary) {
await updateDealFromTranscript(deal.id, data.transcript, data.summary);
}
await notifyRep(meta.rep_email, contact, data);
}
getCallMetadata 関数は、録音ファイル名またはメタデータサイドカーファイルから電話番号、メールアドレス、担当者を取得します。正確なソースは使用している通話プラットフォームによります。
マッチしなかった通話の扱い
通話の5〜15%はコンタクトのマッチングに失敗すると想定してください:コールドアウトリーチ、まだHubSpotにいない新規リード、共有回線での通話などです。
オプションA: 通話から新しいコンタクトを作成します。最初のプロパティに電話番号を設定し、ライフサイクルステージを「Lead」にして、後でSDRに情報を充実させてもらいます。
オプションB: マッチしなかった通話を「Unmatched transcripts」カスタムオブジェクトに記録し、週次トリアージ用のSDRキューに振り分けます。
オプションC: 文字起こしを自社のデータベースに保存し、その通話はHubSpotをスキップします。一部の通話(間違い電話、ロボットダイヤル)は本物のノイズです。
ネイティブCIが拾えない部分をこの方法が補完する
すでにSales Hub Professionalを使っているチームにとって、APIパスは特定のギャップで価値を発揮します:
- 外部ダイヤラー: Outreach、Salesloft、HubSpotのパートナーリストにないVoIPシステムからの通話は、CIを完全にスキップします。APIパスならこれらを捕捉できます。
- 過去データのバックフィル: CIは今後の通話しか処理しません。APIパスなら1年分のZoom Cloud録画を一晩で取り込めます。
- 言語対応範囲: CIの文字起こし言語サポートは専用の文字起こしAPIより狭いです。英語以外中心のチームには、独立した文字起こしレイヤー(2026年のベスト音声認識API参照)の方が精度が出ます。
- HubSpotユーザー以外の通話: CIはユーザーごとの有料シートを必要とします。契約社員、オフショアのコーラー、別ツールを使うパートナー担当者の通話はCIの文字起こしになりません。APIパスなら彼らの録音も問わず処理できます。
この方法のコスト vs Gong
この統合以前、通話の文字起こしインテリジェンスを求めるチームが通常検討していたのは:
- Gong: 年間5,000〜50,000ドルのプラットフォーム料金に加えて、1シートあたり年間約1,400〜2,000ドル(非公開、エンタープライズ見積もり)。10人の営業チームなら年間20,000〜35,000ドルを見込んでください。
- 手動メモ: 担当者が各通話後にサマリーを入力します。不完全で、遅く、好意的な詳細に偏ります。
APIパスのコスト:
- 文字起こしAPIのサブスクリプション(定額プランは個人ユーザーで月額15ドル未満から、そこからスケール)。
- HubSpotはすでに持っているもの。
- エンジニアリングのセットアップ1日。
トレードオフは正直に言うとこうです:GongとChorusは文字起こしの上にコーチング分析、キーワードトラッキング、商談予測を構築しています。APIパスは土台を提供し、分析レイヤーはあなた自身(またはHubSpot独自のAIツールのような安価なアドオン)に委ねます。
専用のconversation intelligenceサブスクリプションなしで、コンタクトと商談にきれいな文字起こしを添付したいだけなら、ConvertAudioToTextのミーティング文字起こしツールがファイルやURLの直接送信に対応しており、上記のハンドラーにきれいにマッピングされる構造化出力を返します。
Zapierによる代替案
ZapierにはHubSpotマーケットプレイスに掲載されているネイティブのHubSpotアプリがあります。非技術系チーム向けのフローは:
- トリガー:Webhook(文字起こしのjob.completedイベント)。
- FilterまたはFormatter:電話番号を正規化。
- Search:電話番号かメールアドレスでHubSpotコンタクトを検索。
- アクション:文字起こしテキストでHubSpotのCall Engagementを作成。
これで単純なケースはカバーできます。エッジケース、特にコールドコールのコンタクトマッチングとマッチしない通話のフォールバックロジックは、カスタムコードの方がうまく扱えます。
本番運用での落とし穴
電話番号の正規化。 「+55 11 99999-8888」のような国際番号は、HubSpotで検索する前に数字以外を除去する必要があります。normalizePhone(str) ヘルパーを作り、すべての照会の前に全番号を通しましょう。
複数拠点・共有電話回線。 複数の担当者が同じ番号を共有している場合、電話番号ベースのマッチングは曖昧になります。メールアドレスかカレンダーの文脈にフォールバックしてください。
Webhookの信頼性。 HubSpotにまだ記録されていない完了済み文字起こしジョブをポーリングする日次の突合ジョブを作りましょう。ハンドラーのダウンタイムがあると、そうしなければ抜けが生じます。
HubSpotでの通話権限。 通話レコードはデフォルトでコンタクトアクセス権を持つ誰でも閲覧できます。機密性の高い営業通話については、本番稼働前にHubSpotのチームとロールで制限をかけてください。
アソシエーションIDのテスト。 本番に接続する前に、サンドボックスのコンタクトと商談に対してテスト通話の作成を実行してください。返された通話IDをログに残し、エンゲージメントがコンタクトと商談両方のタイムラインに表示されることを確認します。
よくある質問
HubSpotは通話をネイティブに文字起こしできますか?
はい。ただしSales Hub Professional(年払いで1シートあたり月額90ドル)またはEnterpriseプランのみです。HubSpotのネイティブダイヤラー、Zoom連携、Google Meet連携、および一部のサードパーティ通話プロバイダー経由の通話は自動的に文字起こしされます。外部ダイヤラーからの通話やアップロードされた音声ファイルには、別途APIでの送信パスが必要です。
外部の録音をアップロードしてHubSpotに文字起こしさせることはできますか?
はい。ただし制限があります。HubSpotのcalling extensions APIはWAV、FLAC、MP4ファイルを受け付けますが、音声はマルチチャンネル(話者ごとに別チャンネル)である必要があり、文字起こしは有料のSales HubまたはService Hubシートを持つユーザーに対してのみ実行されます。フローとしては、録音URL用の認証済みエンドポイントを登録し、hs_call_sourceをINTEGRATIONS_PLATFORMに設定して通話を記録した後、/recordings/readyエンドポイントを呼び出して処理をトリガーします。
通話を商談(deal)に関連付けるための正しいHubSpotアソシエーションタイプIDは何ですか?
通話から商談への正しいアソシエーションタイプIDは195ではなく220です。通話からコンタクトへは194です。どちらもassociationCategoryはHUBSPOT_DEFINEDに設定します。195を使うとサイレントに失敗するか、誤った関連付けが作成されます。
コードなしで文字起こしをHubSpotに送る方法はありますか?
ZapierにはHubSpotマーケットプレイスに掲載されているネイティブのHubSpotアプリがあります。文字起こし完了時にwebhookトリガーを設定し、HubSpotアクションでエンゲージメントを作成できます。制限はコンタクトのマッチングです。Zapierは単純なメールアドレスや電話番号の照会は処理できますが、コールドコールや共有電話回線のようなエッジケースにはフォールバックロジック付きのカスタムコードが必要です。
参考情報源
- HubSpot Sales Hub 料金ページ - 2026年7月確認
- 通話の録音と文字起こしの確認 - HubSpotナレッジベース - 2026年7月確認
- HubSpot Calling Extensions:録音と文字起こしAPI - 2026年7月確認
- HubSpot Calls Engagement API v3 - アソシエーションタイプID - 2026年7月確認
- Gong Pricing 2026 - 2026年7月確認
- Zapier HubSpot連携 - HubSpotマーケットプレイス - 2026年7月確認
Try transcription free
Convert any audio or video to clean, unwatermarked text — speaker labels, timestamps, and AI summaries included. First 10 minutes free, no account.
Related Articles
How to Add Timestamps to a Transcript
Learn how to add timestamps to a transcript with an audio-to-text tool, then export timestamped SRT or VTT subtitle files for easy navigation and editing.
How to Transcribe a Conference Talk to Text
Learn how to transcribe a conference talk or keynote to text, label speakers, and export SRT, VTT, or TXT using a straightforward upload or URL workflow.