deal-management について
HubSpot CLIでパイプライン管理、MQLの取引化、取引ステージの一括更新、停滞案件の抽出、取引のクローズを行うためのスキルです。プレビューと確認を伴う手順も扱います。
主な機能
- 01ポータル固有のパイプラインとステージの確認
- 02MQLコンタクトの取引化
- 03取引の一括ステージ更新や再割り当て
- 04停滞案件の検索と更新
- 05確認手順付きの取引クローズ
活用シーン
- 01既存取引のない接続済みMQLの選別
- 02複数取引のステージ変更
- 03最近の活動がない未クローズ取引の特定
- 04クローズ日を設定した取引のクローズ
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ hubspot/ agent-cli-skills --skill deal-managementインストール後、Claude Code で/deal-managementを入力して読み込まれたか確認します。
同梱ファイルresources/lifecycle-stage-progression.mdresources/stalled-deal-queries.md
詳細
リソース
| ファイル | 使用するタイミング |
|---|---|
resources/lifecycle-stage-progression.md | ライフサイクルステージの API 値 + ディールの移動と対になるコンタクト側の更新。 |
resources/stalled-deal-queries.md | 動的な日付を使用した、停滞中 / 活動なし / クローズ予定日を過ぎたディール向けのフィルタークックブック。 |
基礎
まず bulk-operations/SKILL.md を読んでください — JSONL のパイピング、バッチ読み取り、ページネーション、そしてドライラン / ダイジェスト / 確認のフローはそこにあります。整形のレシピは bulk-operations/resources/json-patterns.md にあります。hubspot <command> --help が信頼できる情報源です。オブジェクトタイプは複数形です(contacts、deals、companies)。プロパティの参照には hubspot properties list --type deals を使用してください — プロパティのテーブルをハードコードしないでください。
1. パイプラインとステージを検出する
パイプラインとステージの ID はポータル固有です。常に実行時に検出してください — ポータルをまたいでハードコードしないでください。
hubspot pipelines list --type deals --format jsonl
# {"id":"default","label":"Sales Pipeline","displayOrder":0,"stages":[...]}
# {"id":"a1b2c3d4-0000-0000-0000-000000000000","label":"Enterprise Pipeline","displayOrder":1,"stages":[...]}
hubspot pipelines stages --type deals --pipeline default --format jsonl
# {"id":"appointmentscheduled","label":"Appointment Scheduled","displayOrder":0,"metadata":{"isClosed":"false","probability":"0.2"}}
# {"id":"qualifiedtobuy","label":"Qualified To Buy","displayOrder":1,"metadata":{"isClosed":"false","probability":"0.4"}}
# ...
# {"id":"closedwon","label":"Closed Won","displayOrder":5,"metadata":{"isClosed":"true","probability":"1.0"}}
# {"id":"closedlost","label":"Closed Lost","displayOrder":6,"metadata":{"isClosed":"true","probability":"0.0"}}
pipelines list/get は各パイプラインの stages を埋め込むため、1 回の呼び出しでディールの dealstage GUID を変換するために必要なステージ ID -> ラベルのマップが得られます:
hubspot pipelines get --type deals default --format jsonl \
| jq -r '.stages[] | "\(.id)\t\(.label)"'
ラベルから特定のステージ ID を取得します:
QUALIFIED=$(hubspot pipelines stages --type deals --pipeline default --format jsonl \
| jq -r 'select(.label=="Qualified To Buy") | .id')
上記に示した ID(appointmentscheduled、closedwon など)は HubSpot の標準 default ディールパイプラインのステージです — ただしポータルでは名前変更や削除が可能なため、毎回自分のものを検出してください。
2. MQL をディールとして認定する
ディールを持たない接続済みの MQL を検索し、それぞれについてディールを作成し、コンタクト + 企業に関連付け、ライフサイクルを進めます。
# 1. find ready MQLs
hubspot objects search --type contacts \
--filter "lifecyclestage=marketingqualifiedlead AND hs_lead_status=CONNECTED AND num_associated_deals=0" \
--properties email,firstname,lastname,company,hubspot_owner_id
# 2. for one contact: company lookup, deal create, associate, promote
hubspot associations list --from contacts:<contact_id> --to companies # → <company_id>
hubspot objects create --type deals \
--property "dealname=Acme Corp - Inbound" \
--property pipeline=default --property dealstage=qualifiedtobuy \
--property amount=0 --property hubspot_owner_id=<owner_id>
# returns {"id":"<deal_id>","ok":true,...}
hubspot associations create --from deals:<deal_id> --to contacts:<contact_id>
hubspot associations create --from deals:<deal_id> --to companies:<company_id>
# lifecycle promote — objects update is irreversible, so dry-run then confirm with the contact ID
hubspot objects update --type contacts <contact_id> \
--property lifecyclestage=salesqualifiedlead --property hs_lead_status=OPEN_DEAL --dry-run
hubspot objects update --type contacts <contact_id> \
--property lifecyclestage=salesqualifiedlead --property hs_lead_status=OPEN_DEAL \
--digest <hash> --confirm <contact_id>
バルクパターン — 多数の MQL を一度に
objects create は stdin の各行に対して 1 行の結果を、入力順に返します。関連付けのために両方のストリームをキャプチャし、行で結合します:
# 1. snapshot MQLs to a file (preserves order for the join)
hubspot objects search --type contacts \
--filter "lifecyclestage=marketingqualifiedlead AND hs_lead_status=CONNECTED AND num_associated_deals=0" \
--properties email,firstname,lastname,company,hubspot_owner_id \
> /tmp/mqls.jsonl
# 2. one deal per MQL — output preserves order
jq -c '{properties:{
dealname: ((.properties.firstname // "") + " " + (.properties.lastname // "") + " - " + (.properties.company // "Unknown")),
pipeline:"default", dealstage:"qualifiedtobuy", amount:"0", dealtype:"newbusiness",
hubspot_owner_id:(.properties.hubspot_owner_id // "")
}}' /tmp/mqls.jsonl \
| hubspot objects create --type deals > /tmp/deals.jsonl
# 3. abort if any create failed — paste would zip null deal IDs onto real contacts
jq -e 'select(.ok==false)' /tmp/deals.jsonl > /dev/null && { echo "Some deal creates failed — inspect /tmp/deals.jsonl" >&2; exit 1; }
# 4. pair contact <-> new deal by line for the association call
paste <(jq -r '.id' /tmp/mqls.jsonl) <(jq -r '.id' /tmp/deals.jsonl) \
| jq -cR 'split("\t") | {from:("deals:" + .[1]), to:("contacts:" + .[0])}' \
| hubspot associations create
# 5. promote lifecycle on every contact — objects update is irreversible, so dry-run then re-pipe with the digest/confirm
jq -c '{id, properties:{lifecyclestage:"salesqualifiedlead", hs_lead_status:"OPEN_DEAL"}}' /tmp/mqls.jsonl \
| hubspot objects update --type contacts --dry-run \
| tee /tmp/promote.preview.jsonl
digest=$(jq -r 'select(.digest != null) | .digest' /tmp/promote.preview.jsonl)
confirm=$(jq -r 'select(.digest != null) | .target.id' /tmp/promote.preview.jsonl) # batch: row count
jq -c '{id, properties:{lifecyclestage:"salesqualifiedlead", hs_lead_status:"OPEN_DEAL"}}' /tmp/mqls.jsonl \
| hubspot objects update --type contacts --digest "$digest" --confirm "$confirm"
企業の関連付けには、hubspot associations list --from contacts:<id> --to companies によるコンタクトごとの個別パスが必要です — コンタクトは企業を 0 社または複数社持つ可能性があります。
事前認定チェックは検索のフィルターにすぎません: メールがある、企業がある、オープンなディールがない、オーナーがいる — これらはすべて --filter に既に含まれています。完全なステージ進行とコンタクト側の更新については resources/lifecycle-stage-progression.md を参照してください。
3. 一括で進めるまたは再割り当てする
# move every deal in one stage to the next — 1. preview
hubspot objects search --type deals --filter "dealstage=qualifiedtobuy" \
| jq -c '{id, properties:{dealstage:"presentationscheduled"}}' \
| hubspot objects update --type deals --dry-run \
| tee /tmp/advance.preview.jsonl
# 2. lift the digest + confirm (present at every size)
digest=$(jq -r 'select(.digest != null) | .digest' /tmp/advance.preview.jsonl)
confirm=$(jq -r 'select(.digest != null) | .target.id' /tmp/advance.preview.jsonl) # batch: row count; single: record ID
# 3. execute — re-pipe the SAME inputs plus --digest/--confirm
hubspot objects search --type deals --filter "dealstage=qualifiedtobuy" \
| jq -c '{id, properties:{dealstage:"presentationscheduled"}}' \
| hubspot objects update --type deals --digest "$digest" --confirm "$confirm"
# reassign open deals from one rep to another — same three steps
OLD=$(hubspot owners list --format jsonl | jq -r 'select(.email=="[email protected]") | .id')
NEW=$(hubspot owners list --format jsonl | jq -r 'select(.email=="[email protected]") | .id')
hubspot objects search --type deals --filter "hubspot_owner_id=$OLD AND hs_is_closed!=true" \
| jq -c "{id, properties:{hubspot_owner_id:\"$NEW\"}}" \
| hubspot objects update --type deals --dry-run \
| tee /tmp/deal-reassign.preview.jsonl
digest=$(jq -r 'select(.digest != null) | .digest' /tmp/deal-reassign.preview.jsonl)
confirm=$(jq -r 'select(.digest != null) | .target.id' /tmp/deal-reassign.preview.jsonl)
hubspot objects search --type deals --filter "hubspot_owner_id=$OLD AND hs_is_closed!=true" \
| jq -c "{id, properties:{hubspot_owner_id:\"$NEW\"}}" \
| hubspot objects update --type deals --digest "$digest" --confirm "$confirm"
ドライランはどのサイズでもダイジェストを出力します(confirm = バッチの場合は行数、単一の場合はレコード ID)。プレビュー行から取得した --digest <hash> --confirm <value> で再パイプします。完全なフローは bulk-operations/SKILL.md にあります。
4. 停滞しているディールを見つける
動的な日付を使用したフィルタークックブックは resources/stalled-deal-queries.md にあります。中核となるクエリ:
# open deals with no activity in 30 days (macOS / Linux date examples in resources)
hubspot objects search --type deals \
--filter "hs_last_activity_date<$(date -v-30d +%Y-%m-%d) AND hs_is_closed!=true" \
--properties dealname,dealstage,closedate,hubspot_owner_id,hs_last_activity_date
結果を更新(クローズ予定日の延長、ステージの移動、フラグの設定)またはタスク作成にパイプします。停滞しているディールに対するフォローアップタスク / 通話 / メモについては sales-execution スキルを参照してください — ここでアクティビティオブジェクトのプロパティ処理を重複させないでください。
# extend close dates for everything past due
hubspot objects search --type deals \
--filter "closedate<$(date +%Y-%m-%d) AND hs_is_closed!=true" \
| jq -c '{id, properties:{closedate:"2026-06-30"}}' \
| hubspot objects update --type deals --dry-run
5. クローズ
クローズはステージの更新 + closedate(YYYY-MM-DD)です。hs_is_closed と hs_is_closed_won は読み取り専用です — HubSpot がステージから導出します。
# single — objects update is irreversible, so dry-run then confirm with the deal ID
hubspot objects update --type deals <deal_id> \
--property dealstage=closedwon --property closedate=2026-05-15 --dry-run
hubspot objects update --type deals <deal_id> \
--property dealstage=closedwon --property closedate=2026-05-15 --digest <hash> --confirm <deal_id>
# bulk — preview first, then re-pipe with the digest/confirm from the preview (confirm = row count)
hubspot objects search --type deals --filter "dealstage=contractsent AND hubspot_owner_id=<owner_id>" \
| jq -c '{id, properties:{dealstage:"closedwon", closedate:"2026-05-15"}}' \
| hubspot objects update --type deals --dry-run \
| tee /tmp/close.preview.jsonl
digest=$(jq -r 'select(.digest != null) | .digest' /tmp/close.preview.jsonl)
confirm=$(jq -r 'select(.digest != null) | .target.id' /tmp/close.preview.jsonl)
hubspot objects search --type deals --filter "dealstage=contractsent AND hubspot_owner_id=<owner_id>" \
| jq -c '{id, properties:{dealstage:"closedwon", closedate:"2026-05-15"}}' \
| hubspot objects update --type deals --digest "$digest" --confirm "$confirm"
勝敗分析(クローズ理由、勝率、ARR の集計)は sales-reporting スキルにあります。
既知の制約
- バルク MQL → ディールには 2 パスのシェルフローが必要です: 関連付けは
objects createの出力から構築する必要があり、同じパイプ内では行えません。 lifecyclestageはほとんどのポータル設定で前進のみです — 後退する遷移は拒否される場合があります。closedateは日付文字列(YYYY-MM-DD)です。日時のアクティビティプロパティ(hs_last_activity_date)も</>の比較のために日付文字列を受け付けます。hubspot sequencesは Sales Hub のシーケンス(list/get/enrollments)を読み取りますが、読み取り専用です — CLI はコンタクトをシーケンスに登録できないため、代わりにsales-executionを介してフォローアップタスクを作成してください。sequences enrollments <contact_id>はディールのコンタクトに関する勝敗のコンテキストに役立ちます。