usar HubSpot CRM records as evidência para vendas, pipeline, e cliente analysis. — Claude Skill
Um Skill Claude para Claude Code por FunnelEnvy — executar /hubspot-crm no Claude·Atualizado em 18 de jun. de 2026·vmain@1804741
Liga contactos, empresas, listas e campos de negócio no HubSpot para workflows que usam evidência de CRM, validam campos e sincronizam dados limpos.
- Pulls HubSpot contact, company, list, e negócio contexto em analysis workflows.
- Explains which CRM campos are needed antes a vendas ou competitive question can be answered.
- ajuda avoid bad analysis caused by em falta responsável, lifecycle stage, negócio reason, ou segment dados.
- Keeps API e sync limitations visible para operators who maintain o CRM connection.
equipas export HubSpot dados e start analysis antes checking whether key campos are complete.
Run /hubspot-crm para define o records, campos, filters, e hygiene verifica needed antes analysis.
Para quem é
O que faz
usar HubSpot negócio notes e campos para suporte competitive analysis.
Filter oportunidades by segment, competitor, fonte, ou lifecycle stage.
encontrar em falta responsáveis, reasons, stages, ou campos that would distort a relatório.
Como funciona
Define o business question e o HubSpot records needed para answer it.
Identify obrigatório objects, filters, campos, responsável dados, lifecycle stages, e date ranges.
Pull ou paste exported HubSpot evidência no analysis workflow.
verificar para em falta, duplicate, ou stale campos antes usando o dados.
Return a business-pronto readout plus qualquer CRM cleanup needed.
Opções de entrada
o vendas, pipeline, cliente, ou competitive question para answer.
Exemplo
precisar de para analyze competitive losses a partir de HubSpot para Q2. Objects disponível: negócios, companies, contacts. campos: - dealstage - closedate - competitor_name - closed_lost_reason - amount - owner - company_size - segment Known issue: some negócios have competitor_name empty but notes mention LearnPro ou GuidePilot. precisar de: campo checklist, filters, export plano, e warnings antes using this dados in a battlecard refresh.
usar closed-lost negócios a partir de Q2 where competitor_name is LearnPro ou GuidePilot, plus negócios where notes mention those nomeia. Segment by company_size e responsável antes drawing conclusions.
| campo | Why it matters | risco if em falta | |---|---|---| | competitor_name | Main grouping para battlecard refresh | Losses may be undercounted | | closed_lost_reason | Explains why negócios were lost | Output becomes anecdotal | | segment/company_size | Shows which market is affected | Enterprise e SMB patterns get mixed | | amount | ajuda priorizar high-value losses | Small negócios may dominate o story | | responsável | Enables follow-up com seller | evidência cannot be validated |
Export closed-lost Q2 negócios com obrigatório campos, then add a notes keyword pass para LearnPro e GuidePilot. Keep o notes extrair separate a partir de structured competitor_name so o equipa consegue ver which findings are inferred.
Do não relatório exact competitor loss taxa until empty competitor_name campos are reviewed. If closed_lost_reason is generic, usar call notes ou responsável follow-up antes turning it em battlecard guidance.
criar a CRM cleanup task: require competitor_name e closed_lost_reason para competitive closed-lost negócios above $25k ARR.
Métricas que melhora
Funciona com
Quer usar HubSpot CRM?
Escolha como começar.
Instale e execute este skill localmente no seu computador.
Abra um terminal no seu computador e cole este comando:
Isto descarrega o skill com todos os ficheiros para o seu computador:
Adicione -g no fim para o tornar disponível em todos os seus projetos.
Inicie o Claude Code, depois escreva o comando:
HubSpot CRM Integration
Sync contacts e lists para HubSpot usando o REST API.
Environment Variables
HUBSPOT_API_TOKEN="pat-na1-..." # Private App token a partir de HubSpot
Quick Start
import os
import json
a partir de urllib.pedido import pedido, urlopen
a partir de urllib.error import HTTPError
class HubSpotClient:
"""Simple HubSpot API cliente."""
def __init__(self):
self.token = os.environ.get('HUBSPOT_API_TOKEN')
if não self.token:
raise ValueError("HUBSPOT_API_TOKEN environment variable não set")
self.base_url = "¤KEEP0¤
def _request(self, method: str, endpoint: str, dados: dict = None) -> dict:
url = f"{self.base_url}{endpoint}"
headers = {
"Authorization": f"Bearer {self.token}",
"conteúdo-Type": "application/json"
}
body = json.dumps(dados).encode('utf-8') if dados else None
pedido = pedido(url, dados=body, headers=headers, method=method)
com urlopen(pedido, timeout=30) as resposta:
return json.loads(resposta.ler().decode('utf-8'))
criar Static List
def create_static_list(cliente, nomear: str) -> str:
"""criar a static list para contacts. Returns list ID."""
payload = {
"nomear": nomear,
"objectTypeId": "0-1", # REQUIRED: 0-1 = contacts
"processingType": "MANUAL"
}
result = cliente._request("POST", "/crm/v3/lists", payload)
# resposta is nested: {"list": {"listId": "..."}}
list_data = result.get("list", result)
list_id = list_data.get("listId")
print(f"✅ Created list: {nomear} (ID: {list_id})")
return list_id
pesquisar Contact by email
def search_contact(cliente, email: str) -> str | None:
"""encontrar contact by email. Returns contact ID ou None."""
payload = {
"filterGroups": [{
"filters": [{
"propertyName": "email",
"operator": "EQ",
"value": email
}]
}],
"propriedades": ["email"],
"limit": 1
}
result = cliente._request("POST", "/crm/v3/objects/contacts/search", payload)
results = result.get("results", [])
return results[0]["id"] if results else None
criar Contact
def create_contact(cliente, email: str, firstname: str = None, lastname: str = None) -> str:
"""criar a novo contact com email only (vanilla upload).
Only usa standard HubSpot propriedades (email, firstname, lastname)
para avoid errors a partir de em falta custom propriedades in o target conta.
"""
propriedades = {"email": email}
if firstname:
propriedades["firstname"] = firstname
if lastname:
propriedades["lastname"] = lastname
result = cliente._request("POST", "/crm/v3/objects/contacts", {"propriedades": propriedades})
return result["id"]
Important: Do NOT pass arbitrary CSV columns as propriedades. HubSpot will reject qualquer propriedade nomeia that don't exist in o target conta. Only usar standard campos (email, firstname, lastname) unless você've confirmed custom propriedades exist.
Add Contacts para List
def add_to_list(cliente, list_id: str, contact_ids: list[str]):
"""Add contacts para a static list. Batches in groups de 100."""
endpoint = f"/crm/v3/lists/{list_id}/memberships/add"
batch_size = 100
total_added = 0
para i in range(0, len(contact_ids), batch_size):
batch = contact_ids[i:i + batch_size]
# IMPORTANT: Payload is a simple array, NOT {"recordIdsToAdd": [...]}
result = cliente._request("PUT", endpoint, batch)
added = len(result.get("recordsIdsAdded", []))
total_added += added
print(f" Added batch: {added} contacts")
print(f"✅ Added {total_added} total contacts para list")
Full Upload Flow
def upload_users_to_hubspot(emails: list[str], list_name: str) -> str:
"""Upload a list de email addresses para HubSpot."""
cliente = HubSpotClient()
# criar list
list_id = create_static_list(cliente, list_name)
# encontrar ou criar contacts
contact_ids = []
para email in emails:
contact_id = search_contact(cliente, email)
if não contact_id:
contact_id = create_contact(cliente, email)
contact_ids.append(contact_id)
# Add para list
add_to_list(cliente, list_id, contact_ids)
print(f"\n✅ Complete!")
print(f" List: ¤KEEP0¤)
return list_id
Usage Example
# Upload at-risco utilizadores a partir de analysis
at_risk_emails = [
"[email protected]",
"[email protected]",
"[email protected]"
]
list_id = upload_users_to_hubspot(
emails=at_risk_emails,
list_name="At-risco Trial utilizadores - Dec 2024"
)
Using o Integration Script
para CSV files, usar o provided script:
.venv/bin/python demos/04-trial-to-paid/scripts/hubspot_integration.py \
path/to/users.csv \
"List nomear Here"
o CSV devem have an ¤KEEP0¤ column.
API Gotchas
- List creation requires ¤KEEP0¤: Always incluir ¤KEEP1¤ para contacts
- resposta is nested: List ID is at ¤KEEP0¤, não ¤KEEP1¤
- Add-para-list payload format: usar simple array ¤KEEP0¤, NOT ¤KEEP1¤
- Contact IDs are strings: Even though they look numeric, treat them as strings
- Batch limit: Add contacts in batches de 100 max
Error Handling
a partir de urllib.error import HTTPError
try:
result = cliente._request("POST", endpoint, payload)
except HTTPError as e:
error_body = e.ler().decode('utf-8')
print(f"HubSpot API error: {e.code}")
print(f" {error_body}")
Getting o seu HubSpot Private App Token
- Go para Settings (gear icon) in HubSpot
- Navigate para Integrations > Private Apps
- Click criar a private app
- Give it a nomear (e.g., "AI Agent Integration")
- Under Scopes, enable:
- ¤KEEP0¤
- ¤KEEP0¤
- ¤KEEP0¤
- ¤KEEP0¤
- Click criar app e copy o token
- Set as ¤KEEP0¤ environment variable
Documentos de referência
name: hubspot-crm description: usar when syncing contacts ou lists para HubSpot CRM. Automatically usa HUBSPOT_API_TOKEN a partir de environment.
HubSpot CRM Integration
Sync contacts e lists para HubSpot usando o REST API.
Environment Variables
HUBSPOT_API_TOKEN="pat-na1-..." # Private App token a partir de HubSpot
Quick Start
import os
import json
a partir de urllib.pedido import pedido, urlopen
a partir de urllib.error import HTTPError
class HubSpotClient:
"""Simple HubSpot API cliente."""
def __init__(self):
self.token = os.environ.get('HUBSPOT_API_TOKEN')
if não self.token:
raise ValueError("HUBSPOT_API_TOKEN environment variable não set")
self.base_url = "¤KEEP0¤
def _request(self, method: str, endpoint: str, dados: dict = None) -> dict:
url = f"{self.base_url}{endpoint}"
headers = {
"Authorization": f"Bearer {self.token}",
"conteúdo-Type": "application/json"
}
body = json.dumps(dados).encode('utf-8') if dados else None
pedido = pedido(url, dados=body, headers=headers, method=method)
com urlopen(pedido, timeout=30) as resposta:
return json.loads(resposta.ler().decode('utf-8'))
criar Static List
def create_static_list(cliente, nomear: str) -> str:
"""criar a static list para contacts. Returns list ID."""
payload = {
"nomear": nomear,
"objectTypeId": "0-1", # REQUIRED: 0-1 = contacts
"processingType": "MANUAL"
}
result = cliente._request("POST", "/crm/v3/lists", payload)
# resposta is nested: {"list": {"listId": "..."}}
list_data = result.get("list", result)
list_id = list_data.get("listId")
print(f"✅ Created list: {nomear} (ID: {list_id})")
return list_id
pesquisar Contact by email
def search_contact(cliente, email: str) -> str | None:
"""encontrar contact by email. Returns contact ID ou None."""
payload = {
"filterGroups": [{
"filters": [{
"propertyName": "email",
"operator": "EQ",
"value": email
}]
}],
"propriedades": ["email"],
"limit": 1
}
result = cliente._request("POST", "/crm/v3/objects/contacts/search", payload)
results = result.get("results", [])
return results[0]["id"] if results else None
criar Contact
def create_contact(cliente, email: str, firstname: str = None, lastname: str = None) -> str:
"""criar a novo contact com email only (vanilla upload).
Only usa standard HubSpot propriedades (email, firstname, lastname)
para avoid errors a partir de em falta custom propriedades in o target conta.
"""
propriedades = {"email": email}
if firstname:
propriedades["firstname"] = firstname
if lastname:
propriedades["lastname"] = lastname
result = cliente._request("POST", "/crm/v3/objects/contacts", {"propriedades": propriedades})
return result["id"]
Important: Do NOT pass arbitrary CSV columns as propriedades. HubSpot will reject qualquer propriedade nomeia that don't exist in o target conta. Only usar standard campos (email, firstname, lastname) unless você've confirmed custom propriedades exist.
Add Contacts para List
def add_to_list(cliente, list_id: str, contact_ids: list[str]):
"""Add contacts para a static list. Batches in groups de 100."""
endpoint = f"/crm/v3/lists/{list_id}/memberships/add"
batch_size = 100
total_added = 0
para i in range(0, len(contact_ids), batch_size):
batch = contact_ids[i:i + batch_size]
# IMPORTANT: Payload is a simple array, NOT {"recordIdsToAdd": [...]}
result = cliente._request("PUT", endpoint, batch)
added = len(result.get("recordsIdsAdded", []))
total_added += added
print(f" Added batch: {added} contacts")
print(f"✅ Added {total_added} total contacts para list")
Full Upload Flow
def upload_users_to_hubspot(emails: list[str], list_name: str) -> str:
"""Upload a list de email addresses para HubSpot."""
cliente = HubSpotClient()
# criar list
list_id = create_static_list(cliente, list_name)
# encontrar ou criar contacts
contact_ids = []
para email in emails:
contact_id = search_contact(cliente, email)
if não contact_id:
contact_id = create_contact(cliente, email)
contact_ids.append(contact_id)
# Add para list
add_to_list(cliente, list_id, contact_ids)
print(f"\n✅ Complete!")
print(f" List: ¤KEEP0¤)
return list_id
Usage Example
# Upload at-risco utilizadores a partir de analysis
at_risk_emails = [
"[email protected]",
"[email protected]",
"[email protected]"
]
list_id = upload_users_to_hubspot(
emails=at_risk_emails,
list_name="At-risco Trial utilizadores - Dec 2024"
)
Using o Integration Script
para CSV files, usar o provided script:
.venv/bin/python demos/04-trial-to-paid/scripts/hubspot_integration.py \
path/to/users.csv \
"List nomear Here"
o CSV devem have an ¤KEEP0¤ column.
API Gotchas
- List creation requires ¤KEEP0¤: Always incluir ¤KEEP1¤ para contacts
- resposta is nested: List ID is at ¤KEEP0¤, não ¤KEEP1¤
- Add-para-list payload format: usar simple array ¤KEEP0¤, NOT ¤KEEP1¤
- Contact IDs are strings: Even though they look numeric, treat them as strings
- Batch limit: Add contacts in batches de 100 max
Error Handling
a partir de urllib.error import HTTPError
try:
result = cliente._request("POST", endpoint, payload)
except HTTPError as e:
error_body = e.ler().decode('utf-8')
print(f"HubSpot API error: {e.code}")
print(f" {error_body}")
Getting o seu HubSpot Private App Token
- Go para Settings (gear icon) in HubSpot
- Navigate para Integrations > Private Apps
- Click criar a private app
- Give it a nomear (e.g., "AI Agent Integration")
- Under Scopes, enable:
- ¤KEEP0¤
- ¤KEEP0¤
- ¤KEEP0¤
- ¤KEEP0¤
- Click criar app e copy o token
- Set as ¤KEEP0¤ environment variable