Lo esencial
Un CRM suele ser un cementerio de datos que nadie captura. El vendedor llama, asiente, anota en un papelito y se le olvida. En el sistema quedan campos vacíos, estados viejos y negocios atorados en "negociación" desde 2022.
Claude convierte el CRM de cementerio en un organismo vivo: lee la correspondencia, actualiza los campos, escribe el seguimiento (follow-up) y detecta quién está listo para comprar ahora mismo.
Conceptos clave
- HubSpot MCP: Claude lee y escribe directamente en HubSpot con herramientas
- Llenado automático del CRM: llega un correo → Claude extrae los datos → los campos se actualizan solos
- AI Lead Scoring (calificación de prospectos con IA): una puntuación de 0 a 100; quién está listo para comprar y quién solo está viendo
- Automatización del seguimiento: el cliente lleva 3 días sin responder → Claude escribe por su cuenta
- Automatización del pipeline: un negocio se atoró → Claude lo ve y propone un plan para destrabarlo
- Pipedrive como alternativa: para quien prefiere otro CRM
Teoría
El problema: por qué los CRM no funcionan
Muchos CRM terminan siendo una libreta cara. Los vendedores capturan datos solo cuando les llaman la atención. El resultado:
- El jefe no sabe el estado real de los negocios
- Los prospectos se pierden: escribieron el viernes y el lunes ya nadie se acordó
- No hay análisis, porque no hay datos
- El cliente recibe el mismo correo tres veces ("hola, no nos hemos puesto en contacto")
La solución tradicional es obligar a los vendedores a llenar el CRM. Eso nunca funciona.
HubSpot MCP: Claude como operador del CRM
HubSpot tiene un servidor MCP con el que Claude trabaja en el CRM. Qué acciones están disponibles (solo lectura o también escritura) depende de la versión del servidor y de los permisos otorgados: revisa la documentación de HubSpot. Con permisos suficientes, Claude puede:
- Leer contactos: quién es esta persona, historial de interacciones
- Actualizar campos: puesto, presupuesto, etapa del negocio
- Crear tareas: "llamar en 2 días"
- Agregar notas: resumen de la conversación
- Mover negocios: pasarlos de una etapa del pipeline a otra
Lo clave: Claude hace la rutina solo, sin que intervenga el vendedor. Los pasos importantes (mover un negocio de etapa, escribirles a los clientes) conviene dejarlos con confirmación de una persona.
# HubSpot a través de Claude + API
import os
import time
import anthropic
import requests
HUBSPOT_TOKEN = os.environ["HUBSPOT_ACCESS_TOKEN"]
def update_crm_from_email(email_text: str, contact_id: str):
client = anthropic.Anthropic()
# Paso 1: Claude extrae datos estructurados del correo
extraction = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=500,
messages=[{
"role": "user",
"content": f"""Extrae del correo del cliente los siguientes datos en JSON:
- contact_name: nombre del cliente
- company: empresa
- interest: qué le interesa concretamente
- budget_hint: pista sobre el presupuesto (si la hay)
- next_step: qué hay que hacer después
- urgency: urgencia (low/medium/high)
Correo: {email_text}
Devuelve solo el JSON, sin explicaciones."""
}]
)
import json
data = json.loads("".join(b.text for b in extraction.content if b.type == "text"))
# Paso 2: actualizamos el contacto en HubSpot
headers = {
"Authorization": f"Bearer {HUBSPOT_TOKEN}",
"Content-Type": "application/json"
}
# Actualizamos las propiedades del contacto.
# HubSpot llena por su cuenta el campo notes_last_contacted (solo lectura), así que
# el resumen del correo lo guardamos como nota (ver la práctica abajo), no como propiedad.
update_payload = {
"properties": {
"hs_lead_status": "IN_PROGRESS"
}
}
response = requests.patch(
f"https://api.hubapi.com/crm/v3/objects/contacts/{contact_id}",
headers=headers,
json=update_payload
)
# Paso 3: creamos una tarea de seguimiento si la urgencia es alta
if data.get("urgency") == "high":
task_payload = {
"properties": {
"hs_task_subject": f"Seguimiento urgente: {data.get('contact_name')}",
"hs_timestamp": str(int(time.time() * 1000)), # fecha límite de la tarea, campo obligatorio
"hs_task_status": "NOT_STARTED",
"hs_task_priority": "HIGH",
"hubspot_owner_id": "owner_id_aqui"
}
}
requests.post(
"https://api.hubapi.com/crm/v3/objects/tasks",
headers=headers,
json=task_payload
)
return dataAI Lead Scoring: quién está listo para comprar ahora
No todos los prospectos son iguales. Uno está viendo por curiosidad; otro llama porque su director le dijo "compra antes de que termine el trimestre". Claude los distingue por las señales en la conversación.
Señales de alta disposición:
- Pregunta por plazos concretos ("¿cuándo podemos empezar?")
- Menciona a la competencia ("los estoy comparando con X")
- Hace preguntas sobre integración ("tenemos SAP, ¿cómo se conecta?")
- Dice su presupuesto o pregunta directamente por precios
Señales de baja disposición:
- "Solo estamos explorando el mercado"
- Nada concreto sobre plazos
- Lleva varias semanas sin contestar los correos
def score_lead(contact_history: str) -> dict:
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=300,
messages=[{
"role": "user",
"content": f"""Califica la disposición de compra del prospecto en una escala de 0 a 100.
Historial de interacciones:
{contact_history}
Devuelve JSON:
{{
"score": número de 0 a 100,
"reasoning": "explicación breve",
"recommended_action": "qué hacer ahora mismo",
"hot_signals": ["lista de señales de disposición"],
"risk_signals": ["lista de señales de alerta"]
}}"""
}]
)
import json
return json.loads("".join(b.text for b in response.content if b.type == "text"))
# Ejemplo de uso
history = """
- 15 de abril: primera llamada, preguntaron por las funciones
- 18 de abril: mandaron su lista de requisitos
- 22 de abril: pidieron una demo
- 25 de abril: después de la demo preguntaron "¿cuál es el plazo mínimo de implementación?"
- 28 de abril: escribieron "nuestro director quiere reunirse la próxima semana"
"""
result = score_lead(history)
# score: 87
# recommended_action: "Confirmar de inmediato la reunión con el director, preparar la propuesta comercial"Automatizar el seguimiento: el cliente no contestó
La forma más común de perder un negocio: el cliente dijo "lo pienso" y luego silencio. Al vendedor le da pena volver a escribir. O se le olvida.
Claude escribe el seguimiento por su cuenta, en el momento adecuado y con el tono adecuado:
def generate_followup(
contact_name: str,
last_interaction: str,
days_since_contact: int,
deal_stage: str
) -> str:
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=400,
messages=[{
"role": "user",
"content": f"""Escribe un correo de seguimiento para el cliente.
Contexto:
- Nombre: {contact_name}
- Último contacto: {last_interaction}
- Días sin respuesta: {days_since_contact}
- Etapa del negocio: {deal_stage}
Requisitos:
- Corto (3-4 oraciones)
- Sin presionar y sin suplicar
- Aporta valor (un artículo, una idea, un caso)
- Un solo llamado a la acción claro
- En español, tono profesional pero cercano"""
}]
)
return "".join(b.text for b in response.content if b.type == "text")Automatizar el pipeline: el negocio se atoró
Los negocios se atoran. Es normal. Lo que no es normal es que nadie lo note durante meses.
Cada semana, Claude revisa el pipeline y encuentra los "negocios zombi":
def audit_pipeline(deals: list) -> list:
client = anthropic.Anthropic()
deals_text = "\n".join([
f"- {d['name']}: etapa '{d['stage']}', "
f"última acción hace {d['days_stale']} días, "
f"monto {d['amount']}"
for d in deals
])
response = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=800,
messages=[{
"role": "user",
"content": f"""Analiza el pipeline de ventas y señala los negocios con problemas.
Negocios:
{deals_text}
Para cada negocio con problemas (atorado más de 14 días) da:
1. Diagnóstico: por qué se atoró
2. Plan para destrabarlo: 2-3 pasos concretos
3. Recomendación: seguir o cerrarlo como perdido
Formato: una lista con un encabezado por cada negocio."""
}]
)
return "".join(b.text for b in response.content if b.type == "text")Pipedrive como alternativa
Si HubSpot te parece caro o complicado, mira Pipedrive: es más sencillo y está hecho para ventas. Los planes y si hay plan gratis, revísalos en los sitios de ambos servicios.
| Aspecto | HubSpot | Pipedrive |
|---|---|---|
| Plan gratis | ✅ Sí (con límites) | Revisa en su sitio |
| Soporte de MCP | ✅ Tiene servidor MCP | ⚠️ Revisa la documentación; la API siempre está disponible |
| Precio | Revisa hubspot.com | Revisa pipedrive.com |
| Complejidad | Alta | Media |
| Mejor para | Marketing + ventas | Solo ventas |
La API de Pipedrive es muy sencilla: Claude trabaja con ella sin problema mediante solicitudes HTTP normales, incluso sin MCP.
Práctica
Tarea: que el CRM se actualice solo cuando llega un correo nuevo
Qué vamos a construir: llega un correo de un cliente → Claude lo lee → actualiza solo la ficha en HubSpot → crea una tarea si hace falta.
Paso 1: Obtén un token de la API de HubSpot
A octubre de 2026, HubSpot está desactivando la creación de apps del tipo anterior (Private Apps): para cuentas nuevas desde el 28.09.2026 y para las existentes desde el 26.10.2026. Para integraciones "servidor a servidor" ahora se recomienda una Service Key (a octubre de 2026 en beta pública; se crea desde la plataforma para desarrolladores de HubSpot). Los pasos exactos en la interfaz cambian, así que sigue la documentación vigente en developers.hubspot.com. Si ya tienes una app del tipo anterior, su token funciona igual: en el encabezado Authorization: Bearer ....
- Crea una Service Key (o usa el token de una app que ya tengas) con estos permisos (scopes):
crm.objects.contacts.read,crm.objects.contacts.write,crm.objects.deals.read,crm.objects.deals.write, y para notas y tareas, los permisos de esos objetos - Copia el token y guárdalo en el archivo
.env(nunca lo subas a Git)
# .env
HUBSPOT_ACCESS_TOKEN=<token de HubSpot>
ANTHROPIC_API_KEY=sk-ant-...Paso 2: Crea el script que procesa los correos entrantes
# email_processor.py
import os
import json
import time
import anthropic
import requests
from dotenv import load_dotenv
load_dotenv()
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
HUBSPOT_TOKEN = os.environ["HUBSPOT_ACCESS_TOKEN"]
def process_incoming_email(
email_from: str,
email_subject: str,
email_body: str
):
"""Procesa un correo entrante y actualiza el CRM"""
print(f"Procesando correo de: {email_from}")
# 1. Claude analiza el correo
analysis = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=600,
messages=[{
"role": "user",
"content": f"""Analiza el correo entrante del cliente.
Asunto: {email_subject}
De: {email_from}
Texto: {email_body}
Devuelve JSON sin texto adicional:
{{
"intent": "inquiry/complaint/purchase_ready/follow_up/other",
"summary": "resumen breve en 1-2 oraciones",
"key_points": ["lista de puntos importantes"],
"urgency": "low/medium/high",
"sentiment": "positive/neutral/negative",
"next_action": "siguiente acción concreta",
"follow_up_days": número de días tras los cuales escribir si no hay respuesta
}}"""
}]
)
data = json.loads("".join(b.text for b in analysis.content if b.type == "text"))
print(f"Análisis: {data['intent']}, urgencia: {data['urgency']}")
# 2. Buscamos el contacto en HubSpot por email
headers = {
"Authorization": f"Bearer {HUBSPOT_TOKEN}",
"Content-Type": "application/json"
}
search_response = requests.post(
"https://api.hubapi.com/crm/v3/objects/contacts/search",
headers=headers,
json={
"filterGroups": [{
"filters": [{
"propertyName": "email",
"operator": "EQ",
"value": email_from
}]
}],
"properties": ["email", "firstname", "lastname", "hs_lead_status"]
}
)
contacts = search_response.json().get("results", [])
if contacts:
contact_id = contacts[0]["id"]
contact_name = (
contacts[0]["properties"].get("firstname", "") + " " +
contacts[0]["properties"].get("lastname", "")
).strip() or email_from
# 3. Actualizamos el contacto
update_response = requests.patch(
f"https://api.hubapi.com/crm/v3/objects/contacts/{contact_id}",
headers=headers,
json={
"properties": {
"hs_lead_status": "IN_PROGRESS" if data["intent"] == "purchase_ready" else "OPEN"
}
}
)
# 4. Agregamos una nota
note_response = requests.post(
"https://api.hubapi.com/crm/v3/objects/notes",
headers=headers,
json={
"properties": {
"hs_note_body": f"Análisis del correo:\n{data['summary']}\n\nPuntos clave:\n" +
"\n".join(f"• {p}" for p in data["key_points"]),
"hs_timestamp": str(int(time.time() * 1000))
},
"associations": [{
"to": {"id": contact_id},
"types": [{"associationCategory": "HUBSPOT_DEFINED", "associationTypeId": 202}]
}]
}
)
# 5. Creamos una tarea si la urgencia es alta
if data["urgency"] == "high" or data["intent"] == "purchase_ready":
task_response = requests.post(
"https://api.hubapi.com/crm/v3/objects/tasks",
headers=headers,
json={
"properties": {
"hs_task_subject": f"[CALIENTE] Responder: {contact_name} — {email_subject}",
"hs_timestamp": str(int(time.time() * 1000)),
"hs_task_status": "NOT_STARTED",
"hs_task_priority": "HIGH",
"hs_task_body": data["next_action"]
}
}
)
print(f"Tarea urgente creada para {contact_name}")
print(f"CRM actualizado para {contact_name}")
return {"status": "updated", "contact": contact_name, "analysis": data}
else:
# No se encontró el contacto: creamos uno nuevo
print(f"Contacto nuevo: {email_from}")
create_response = requests.post(
"https://api.hubapi.com/crm/v3/objects/contacts",
headers=headers,
json={
"properties": {
"email": email_from,
"hs_lead_status": "NEW"
}
}
)
return {"status": "created", "contact": email_from, "analysis": data}
# Prueba
if __name__ == "__main__":
result = process_incoming_email(
email_from="[email protected]",
email_subject="Queremos implementar su sistema",
email_body="""
¡Buenas tardes!
Estamos evaluando varias soluciones para automatizar ventas.
Su producto nos interesó. Tenemos un equipo de 15 vendedores,
el presupuesto está por definirse y nos gustaría empezar este mismo trimestre.
¿Podríamos tener una demo la próxima semana?
Iván Pérez, Director de Ventas
"""
)
print(json.dumps(result, ensure_ascii=False, indent=2))Paso 3: Pruébalo
python email_processor.pyPaso 4: Conéctalo a correos reales
Opciones de integración:
- Gmail: Google Apps Script → llama a tu script cuando llega un correo nuevo
- Outlook: Power Automate → solicitud HTTP → tu endpoint
- Tu propio servidor de correo: un hook al recibir el correo
- Servicio de webhooks: Zapier / n8n → vigila el correo → llama al script
⚠️ Los correos de clientes contienen datos personales. Mándale a Claude solo lo que la tarea necesita, y revisa la lección Regulación de la IA y cumplimiento.
Herramientas y recursos
- HubSpot: hubspot.com (tiene un CRM gratis para empezar)
- Documentación de la API de HubSpot: developers.hubspot.com
- Pipedrive: pipedrive.com (más sencillo que HubSpot, de pago)
- python-dotenv: para guardar las claves de forma segura
- Modelos de Claude: los nombres en el código son a octubre de 2026; precios y versiones vigentes: Lo vigente
- n8n: para orquestar sin código (lección n8n + IA)
- Zapier: para integrarte con Gmail/Outlook sin programar
Ideas clave
Un CRM no muere por mal software, muere por la captura manual. Claude se encarga de la mayor parte de esa captura: lee los correos, propone actualizaciones de campos y crea tareas. El vendedor se enfoca en hablar con los clientes, no en llenar fichas, y conviene revisar por muestreo lo que hace la IA.
El lead scoring convierte la intuición en un sistema: en lugar de "me parece que este ya está listo", una calificación concreta de 87/100 con su justificación y una recomendación.
Lo más importante: esto no reemplaza a los vendedores, les da superpoderes. Cada vendedor tiene un asistente de IA que no se cansa ni se olvida de nada.
Siguiente lección
La marca se guarda solo en este navegador y no se envía a ningún sitio. Mi progreso