关于 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 错误表示此工作区未配置凭据——请报告此情况,而不是排查身份验证问题。
每个请求都会携带 bearer 标头。已配置的凭据具有一组作用域
(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 表示请求已通过身份验证,但已配置的凭据缺少执行所尝试操作所需的作用域。
为简洁起见,以下示例使用一个辅助函数。定义一次,或将 -H 标志添加到每条 curl 命令中:
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');为清晰起见,以下示例展示的是未经处理的投影。
添加 associations=companies,deals,即可在每条记录中内联关联 ID。
2. 获取一条记录
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'
若要在一次调用中创建并建立关联,请添加 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 发送请求,遍历所有页面中的 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(可重复)会在一个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 列;默认值按类型而定(联系人为email,firstname,lastname,createdate等),其他类型则必须指定。--sort PROP[:desc]用于对结果排序。--limit N限制获取的行数(默认值为 100,0= 获取全部 — 搜索最多返回 10,000 条结果);--page-size N(最大值为 200);--json会为每条记录输出一个 JSON 对象,而不是带表头的 TSV。匹配总数和行数会输出到 stderr。- 退出代码:
0表示成功,1表示请求失败或 API 错误(stderr 中会显示category和message),或参数错误。
如果脚本报错,请阅读脚本 — 它只有普通的 curl + jq — 并根据 references/api.md 进行调试。
脚本会输出一个执行 AND 操作的 filterGroup。如需 OR 分组,请通过 hsapi 发送原始请求体 — 限制为 5 个分组、每组 6 个筛选条件、总计 18 个筛选条件。搜索最终一致:几秒前创建或更新的记录可能尚未出现 — 如需写入后立即读取,请按 ID 直接执行 GET。
7. 批量读取 / 创建 / 更新 / 插入或更新
batch/* 端点只需一次往返即可处理最多 100 条记录(部分端点的上限较低 — 请参阅 references/api.md)。这五种操作都采用相同的 {"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 次请求(另有根据账户等级调整的每日上限)。搜索端点每个账户每秒最多可发起 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 条记录的批量调用只计为一次请求。
错误处理
错误采用 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— 唯一键冲突(例如,创建联系人的邮箱已存在)。改用 upsert,或更新现有记录。429RATE_LIMITS— 请求体中的policyName会说明触发了哪种限制:秒级/突发限制 → 按X-HubSpot-RateLimit-Interval-Milliseconds指定的时间休眠,然后重试;DAILY→ 停止请求,该限制会在账户本地时间午夜重置。5xx— 暂时性错误。使用退避策略重试。
深入了解
references/api.md 提供更完整的端点目录,包括各对象类型的完整默认属性列表、内置关联类型 ID 表、批量限制、所有者/管道/属性管理端点、自定义对象架构、列表以及互动对象类型(备注、通话、任务、会议、电子邮件)。需要上文未涵盖的端点或 ID 时,请阅读该文件。