hubspot-api について
hubspot-apiは、HubSpot CRM APIを操作してCRMレコードや関連付けを管理するためのスキルです。標準およびカスタムのオブジェクトに共通する操作を説明し、TSVまたはJSONLを出力する検索スクリプトを含みます。
主な機能
- 01レコードの一覧、取得、作成、更新、アーカイブ
- 02フィルター、並べ替え、ページネーションによる検索
- 03一括読み取り、作成、更新、アップサート
- 04型付き関連付けの読み取りと作成
- 05プロパティ、パイプライン、ステージの確認
- 06検索結果をTSVまたはJSONLで出力
活用シーン
- 01条件に合うCRMレコードの検索
- 02コンタクトや取引レコードの更新またはアーカイブ
- 03レコードの一括作成またはアップサート
- 04オブジェクトを関連付ける前の関連タイプ確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ anthropics/ claude-tag-plugins --skill hubspot-apiインストール後、Claude Code で/hubspot-apiを入力して読み込まれたか確認します。
同梱ファイルreferences/api.mdscripts/hs_search.sh
詳細
HubSpot の CRM API(v3)は、オブジェクトタイプ間で統一されています。すべてのオブジェクトは https://api.hubapi.com/crm/v3/objects/{objectType} の下にあり、同じ基本操作、検索、バッチ、関連付け操作をサポートしています。
(HubSpot は後継の命名規則として、日付ベースのパスバージョン(/crm/objects/2026-03/...)を展開しています。以下の v3/v4 パスはすべて引き続き機能します。HubSpot は v4 が 2027-03-30 にサポート対象外になると発表していますが、v3 のサポート終了日はまだ設定されていません。現時点では移行は不要です。)
主な概念:
- オブジェクトタイプは、名前(
contacts、companies、deals、tickets)または数値のobjectTypeId(0-1、0-2、0-3、0-5)で識別します。カスタムオブジェクトは2-<n>またはp_<name>エイリアスです。どちらの形式も URL で使用できます。 - プロパティは読み取り時に明示的な指定が必要です。 リスト/取得の呼び出しで返されるのは、いくつかのデフォルトプロパティ
(
hs_object_id、createdate、lastmodifieddate、および連絡先のemail/firstnameなど、タイプごとのデフォルト)のみです。必要なフィールドをカンマ区切りでproperties=に必ず指定してください。指定しないと、空に見えるレコードが返されます。 - オブジェクトタイプごとに、主要な表示プロパティと重複排除キーが異なります。 連絡先の重複排除には
email、企業にはdomainを使います。取引とチケットには重複排除キーがありません。作成前にキーを確認してください。 - 関連付けにはタイプがあります。 一般的な関連付け(
contact_to_company、deal_to_contactなど)には、組み込みのタイプ ID があります。カスタムの関連付けラベルを定義することもできます。
リクエストの設定
認証はランタイムが処理します。この API への送信リクエストには認証情報が挿入されるため、設定は不要です。トークンやキーの作成、発行、更新、検証は行わないでください。認証情報の変数はリクエストを正しい形式に保つためだけに存在します。いずれかが未設定の場合は、任意のプレースホルダー値を設定してください。401/403 が継続して発生する場合は、このワークスペースに認証情報が設定されていないことを意味します。認証のデバッグではなく、その旨を報告してください。
すべてのリクエストにベアラーヘッダーが含まれます。設定された認証情報にはスコープのセット(crm.objects.contacts.read、crm.objects.deals.write など)があり、アクセスできる対象を制御します。
export HUBSPOT_ACCESS_TOKEN="placeholder" # injected by the runtime; any value works
動作確認 — ワークスペースが正しく接続されていることを確認します。
curl -sS "https://api.hubapi.com/crm/v3/objects/contacts?limit=1" \
-H "Authorization: Bearer ${HUBSPOT_ACCESS_TOKEN}" | jq .
403 は、リクエストの認証には成功したものの、設定された認証情報に試行した操作のスコープがないことを意味します。
簡潔にするため、以下のレシピではヘルパーを使用します。ヘルパーを一度定義するか、各 curl に -H フラグを追加してください。
hsapi() { curl -sS "$@" -H "Authorization: Bearer ${HUBSPOT_ACCESS_TOKEN}" -H "Content-Type: application/json"; }
基本操作
以下の操作では contacts を使用しますが、同じパスを companies、deals、tickets、および任意のカスタムオブジェクトにも使用できます。{objectType} の部分を置き換えてください。
1. レコードの一覧表示
カーソルによるページネーションとプロパティのフィルタリングに対応し、検索は行いません。
hsapi -G "https://api.hubapi.com/crm/v3/objects/contacts" \
--data-urlencode "limit=50" \
--data-urlencode "properties=email,firstname,lastname,lifecyclestage,hubspot_owner_id" \
--data-urlencode "archived=false" | jq '.results[] | {id, props: .properties}'
失敗時のレスポンスは {"status":"error", "message":..., "category":...} となり、.results はありません
—「エラー処理」を参照してください。スクリプトで使用する場合は、一度ガードしてください(jq 'if .results then … else . end')。以下のレシピでは、わかりやすさのために基本的な射影を示しています。
各レコードに関連付け ID をインラインで含めるには、associations=companies,deals を追加します。
2. レコードを 1 件取得する
hsapi -G "https://api.hubapi.com/crm/v3/objects/contacts/CONTACT_ID" \
--data-urlencode "properties=email,firstname,lastname,phone,company" \
--data-urlencode "associations=companies,deals" | jq .
内部 ID ではなく一意のプロパティ(例:メールアドレス)を使って取得するには、idProperty=email を追加し、パスにメールアドレスを指定します。
hsapi -G "https://api.hubapi.com/crm/v3/objects/contacts/[email protected]" \
--data-urlencode "idProperty=email" \
--data-urlencode "properties=email,firstname,lastname" | jq .
3. レコードを作成する
hsapi -X POST "https://api.hubapi.com/crm/v3/objects/contacts" \
-d '{
"properties": {
"email": "[email protected]",
"firstname": "Alice",
"lastname": "Nguyen",
"lifecyclestage": "lead"
}
}' | jq 'if .status == "error" then . else {id, createdAt} end'
1 回の呼び出しで作成と関連付けを行うには、associations 配列を追加します。
hsapi -X POST "https://api.hubapi.com/crm/v3/objects/deals" \
-d '{
"properties": {
"dealname": "Acme expansion",
"pipeline": "default",
"dealstage": "appointmentscheduled",
"amount": "15000"
},
"associations": [
{"to": {"id": "COMPANY_ID"}, "types": [{"associationCategory": "HUBSPOT_DEFINED", "associationTypeId": 341}]}
]
}' | jq .
341 は deal_to_company です。references/api.md の関連付けタイプの表を参照するか、実行時に確認してください(操作 8)。
4. レコードを更新する
変更したいプロパティだけを PATCH します。それ以外は変更されません。
hsapi -X PATCH "https://api.hubapi.com/crm/v3/objects/contacts/CONTACT_ID" \
-d '{"properties": {"lifecyclestage": "marketingqualifiedlead", "phone": "+1-555-0100"}}'
一意のプロパティによる更新方法は読み取り時と同じです。?idProperty=email を追加し、パスにメールアドレスを指定します。
5. レコードをアーカイブ/削除する
HubSpot での「削除」は論理削除です(レコードは約 90 日間、ごみ箱に移動します)。成功時のレスポンスは本文のない 204 なので、ステータスコードを表示してください。
hsapi -X DELETE "https://api.hubapi.com/crm/v3/objects/contacts/CONTACT_ID" -w '\n%{http_code}\n'
バッチ削除:POST /crm/v3/objects/contacts/batch/archive に {"inputs": [{"id": "..."}, ...]} を指定します。
6. レコードを検索する(scripts/hs_search.sh)
同梱スクリプトを使って、あらゆるオブジェクトタイプを検索できます(パスはこのスキルのディレクトリからの相対パスです)。このスクリプトはfilterGroups/sorts/queryの本文を作成し、/crm/v3/objects/{type}/searchにPOSTし、すべてのページでpaging.next.afterをたどって、TSVまたはJSONLを出力します。
scripts/hs_search.sh --object contacts \
--filter lifecyclestage:EQ:lead \
--filter createdate:GTE:2024-01-01T00:00:00Z \
--sort createdate:desc --limit 200
--object TYPE(必須)には、contacts、companies、deals、tickets、または任意のオブジェクトタイプ名/objectTypeIdを指定します。インスタンス固有の設定については、上記のHUBSPOT_ACCESS_TOKENを参照してください。--filter PROP:OP:VALUE(繰り返し指定可能)は、1つのfilterGroup内でフィルターをAND条件で結合します。OPは大文字に変換されます。IN/NOT_INにはカンマ区切りのリストを指定します(dealstage:IN:won,lost→values。文字列プロパティの場合、値は小文字である必要があります)。BETWEENにはlow,highを指定します(amount:BETWEEN:100,500→value+highValue)。HAS_PROPERTY/NOT_HAS_PROPERTYには値を指定しません。--query TEXTを指定すると、フリーテキストのフレーズマッチが追加されます。--properties LISTは、リクエストとTSVの列の両方を決定します。デフォルト値はタイプごとに設定されています(contactsの場合はemail,firstname,lastname,createdateなど)。その他のタイプでは必須です。--sort PROP[:desc]は検索結果を並べ替えます。--limit Nは取得する行数の上限です(デフォルトは100、0はすべてを意味します。ただし検索結果は最大10,000件に制限されます)。--page-size Nは最大200です。--jsonを指定すると、ヘッダー付きTSVの代わりに、レコードごとに1つのJSONオブジェクトを出力します。一致件数と行数はstderrに出力されます。- 終了コード:
0は成功、1はリクエスト失敗またはAPIエラー(categoryとmessageはstderrに出力)、あるいは引数の誤りです。
スクリプトでエラーが発生した場合は、内容を確認してください。通常のcurl + jqで構成されているため、references/api.mdを参考にデバッグできます。
このスクリプトは、AND条件で結合されたfilterGroupを1つ出力します。OR条件のグループを使う場合は、hsapi経由で生の本文をPOSTしてください。上限は5グループ、グループごとに6フィルター、合計18フィルターです。検索結果の反映には時間がかかる場合があります。数秒前に作成または更新されたレコードは、まだ表示されない可能性があります。書き込み直後に読み取る場合は、IDを指定して直接GETしてください。
7. 一括読み取り/作成/更新/アップサート
batch/*エンドポイントを使うと、1回の通信で最大100件のレコードを処理できます(上限がそれより少ないエンドポイントもあります。references/api.mdを参照してください)。5つの操作はすべて同じ{"inputs": [...]}形式です。
# batch read by id
hsapi -X POST "https://api.hubapi.com/crm/v3/objects/contacts/batch/read" \
-d '{"inputs": [{"id": "101"}, {"id": "102"}], "properties": ["email", "firstname"]}'
# upsert by a unique property (create if new, update if the key matches)
hsapi -X POST "https://api.hubapi.com/crm/v3/objects/contacts/batch/upsert" \
-d '{"inputs": [{"idProperty": "email", "id": "[email protected]", "properties": {"firstname": "Alice"}}]}'
batch/createとbatch/updateには、それぞれ{"inputs": [{"properties": {...}}]}と{"inputs": [{"id": "...", "properties": {...}}]}を指定します。
8. 関連付けの一覧表示と作成
v4の関連付けエンドポイントを使用してください。新しいバージョンであり、必要なラベル/タイプ情報が含まれています。v3と併存しています。
# what's associated with this contact?
hsapi "https://api.hubapi.com/crm/v4/objects/contacts/CONTACT_ID/associations/companies" | jq '.results'
# discover association type ids between two object types
hsapi "https://api.hubapi.com/crm/v4/associations/contacts/companies/labels" | jq '.results'
# create an association (PUT — idempotent)
hsapi -X PUT "https://api.hubapi.com/crm/v4/objects/contacts/CONTACT_ID/associations/companies/COMPANY_ID" \
-d '[{"associationCategory": "HUBSPOT_DEFINED", "associationTypeId": 1}]'
# remove (204 on success, empty body)
hsapi -X DELETE "https://api.hubapi.com/crm/v4/objects/contacts/CONTACT_ID/associations/companies/COMPANY_ID" -w '\n%{http_code}\n'
9. プロパティの確認(スキーマ)
オブジェクトタイプのプロパティカタログを読み取り、フィールド名、タイプ、列挙型フィールド(パイプライン、ステージ、ライフサイクルステージなど)のoptionsを確認します。作成やフィルタリングの前に必ず確認してください。プロパティ名を推測することが、400エラーの最も一般的な原因です。
hsapi "https://api.hubapi.com/crm/v3/properties/contacts" | \
jq '.results[] | {name, label, type, fieldType, options: (.options | length)}'
# one property with its option values
hsapi "https://api.hubapi.com/crm/v3/properties/deals/dealstage" | jq '{name, options: [.options[] | {label, value}]}'
10. パイプラインとステージ
取引とチケットは、順序付けされたステージを持つパイプラインに属します。dealstage/hs_pipeline_stageプロパティに指定するのは、ステージとパイプラインのIDであり、ラベルではありません。
hsapi "https://api.hubapi.com/crm/v3/pipelines/deals" | \
jq '.results[] | {id, label, stages: [.stages[] | {id, label, displayOrder}]}'
ページネーション
一覧エンドポイント(GET /crm/v3/objects/{type}、プロパティ一覧、関連付け一覧)と検索(POST .../search)は、どちらもカーソルページネーションを使用します。結果がさらにある場合、レスポンスにはpaging.next.afterが含まれます。これをafterとして渡してください(GETではクエリパラメーター、検索では本文のフィールド)。一覧のlimitの最大値は100、検索では200です。さらに検索結果はクエリあたり合計10,000件に制限されているため、それ以上必要な場合はフィルターを絞り込んでください。エラー本文には.pagingがありません。ループに上限を設け、.status == "error"の場合は終了してください。
レート制限
プライベートアプリのトークンには、Free/Starter アカウントで 10 秒あたり 100 リクエスト、Professional/Enterprise で 10 秒あたり 190 リクエストの制限があります(アカウントのティアに応じた日次上限もあります)。検索エンドポイントはアカウントあたり 1 秒あたり 5 リクエストに制限されており、レスポンスにレート制限ヘッダーは含まれません。それ以外のすべてのレスポンスには、次の情報が含まれます。
X-HubSpot-RateLimit-Max requests allowed per interval
X-HubSpot-RateLimit-Remaining requests left in the current interval
X-HubSpot-RateLimit-Interval-Milliseconds interval length
X-HubSpot-RateLimit-Daily / -Daily-Remaining
429 が返された場合は、X-HubSpot-RateLimit-Interval-Milliseconds の時間(ヘッダーがない場合は約 10 秒)だけ待機してから再試行してください。バッチエンドポイントを優先してください。100 件のレコードをまとめたバッチ呼び出しも、1 リクエストとしてカウントされます。
エラー処理
エラーは JSON 形式です:{"status": "error", "message": "...", "correlationId": "...", "category": "..."}。.results / .id を取り出す前に .status を確認してください。エラーのレスポンスにはこれらのフィールドがなく、そのまま取り出すと null が表示されます。必ず message と category を提示してください。
400VALIDATION_ERROR— プロパティ名または値が不正、フィルターの形式が不正、列挙値が誤っています。errors[]を確認してください。問題のあるフィールドが示されています。プロパティカタログ(op 9)を確認してください。401INVALID_AUTHENTICATION— 認証情報がないか、拒否されました。HUBSPOT_ACCESS_TOKENが設定されているか確認してください。問題が解消しない場合、認証情報がこのワークスペースに設定されていません。その旨を報告してください。403MISSING_SCOPES— 設定された認証情報に、このエンドポイントに必要なスコープがありません。メッセージに不足しているスコープが示されます。その旨を報告してください。404OBJECT_NOT_FOUND— ID が不正、objectTypeが誤っている、またはレコードが削除・アーカイブされています。archived=trueを試してください。409CONFLICT— 一意のキーが重複しています(例:既存のメールアドレスを使用してコンタクトを作成しようとしている)。アップサートに切り替えるか、既存のレコードをパッチしてください。429RATE_LIMITS— レスポンス本文のpolicyNameに、適用された制限が示されます。秒単位またはバーストのポリシーの場合は、X-HubSpot-RateLimit-Interval-Millisecondsの時間だけ待機して再試行してください。DAILYの場合は処理を停止してください。アカウントの現地時間の午前 0 時にリセットされます。5xx— 一時的なエラーです。バックオフを設定して再試行してください。
さらに詳しく
references/api.md には、より詳細なエンドポイントカタログがあります。オブジェクトタイプごとのデフォルトプロパティの完全な一覧、組み込みの関連付けタイプ ID の表、バッチ制限、オーナー/パイプライン/プロパティの管理エンドポイント、カスタムオブジェクトのスキーマ、リスト、エンゲージメントオブジェクトのタイプ(メモ、通話、タスク、ミーティング、メール)が記載されています。上記にないエンドポイントや ID が必要な場合は、そちらを参照してください。