TL;DR: pipeline real para cualificar leads sin intervención humana: formulario web → webhook → enriquecimiento (Clearbit/Apollo) → LLM clasificador (criterio BANT) → HubSpot con score y propietario asignado → notificación al comercial. Tiempo medio: 2-3 segundos por lead.
El problema que resuelves
En empresas B2B típicas, los comerciales dedican 30-50% de su tiempo a cualificar leads que no encajan. El resto se evapora en pedirles datos que ya están públicos (sector, tamaño, web). Un SDR cuesta 28-35k €/año en España.
Automatizando esta cualificación liberas a tu equipo comercial para que dedique su tiempo solo a oportunidades reales. ROI típico: el sistema se paga solo en 2-3 meses.
Arquitectura del pipeline
[Formulario web]
↓ POST datos básicos
[Tu API o middleware]
↓
[Enriquecimiento]
- Clearbit / Apollo (datos firmográficos)
- Hunter (verificación email)
↓
[Clasificador LLM]
- Aplica criterios BANT
- Devuelve {score: 0-100, tier: 'A'|'B'|'C'|'D', razones: []}
↓
[HubSpot]
- Crea/actualiza contact
- Asigna propietario según tier
- Crea tarea con prioridad
↓
[Notificación]
- Slack al comercial asignado
- Email con resumen del lead
Toda la cadena tarda 2-3 segundos. El lead entra a la cuenta del comercial cualificado.
1. Formulario web → webhook
Cualquier formulario funciona (Tally, HubSpot forms, formulario propio). Lo importante es que envíe un webhook con campos mínimos:
emailnombreyapellidosempresamensaje(qué necesita)presupuesto_orientativo(opcional pero muy útil)urgencia(opcional)
// app/api/leads/intake/route.ts (Cloudflare Workers / Vercel)
export async function POST(req: Request) {
const data = await req.json();
// Validación básica
if (!data.email || !data.empresa) {
return new Response("Faltan campos", { status: 400 });
}
// Procesar asíncronamente para responder rápido al form
ctx.waitUntil(processLead(data));
return new Response("OK", { status: 200 });
}
2. Enriquecimiento firmográfico
Antes de cualificar, enriquece con datos que el lead no te dio:
async function enrichLead(email: string, empresa: string) {
// Clearbit Reveal (gratuito hasta 1000/mes)
const clearbit = await fetch(
`https://person.clearbit.com/v2/people/find?email=${email}`,
{ headers: { Authorization: `Bearer ${process.env.CLEARBIT_KEY}` } },
).then((r) => (r.ok ? r.json() : null));
// Apollo (alternativa más barata, EU)
const apollo = await fetch("https://api.apollo.io/v1/people/match", {
method: "POST",
headers: { "X-Api-Key": process.env.APOLLO_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ email }),
}).then((r) => r.json());
// Verificación email (evita leads falsos)
const verification = await fetch(
`https://api.hunter.io/v2/email-verifier?email=${email}&api_key=${process.env.HUNTER_KEY}`,
).then((r) => r.json());
return {
person: clearbit ?? apollo,
company: clearbit?.employment ?? apollo?.organization,
email_valid: verification.data?.result === "deliverable",
};
}
3. Clasificador LLM (criterio BANT)
BANT = Budget, Authority, Need, Timing. Es el framework de cualificación más usado en B2B.
async function classifyLead(lead: any, enrichment: any) {
const prompt = `
Eres un SDR experto. Cualifica este lead según BANT y devuelve JSON estricto.
Datos del lead:
- Email: ${lead.email}
- Empresa: ${lead.empresa}
- Mensaje: "${lead.mensaje}"
- Presupuesto orientativo: ${lead.presupuesto_orientativo ?? "no indicado"}
- Urgencia: ${lead.urgencia ?? "no indicada"}
Datos enriquecidos:
- Cargo: ${enrichment.person?.title ?? "desconocido"}
- Sector empresa: ${enrichment.company?.industry ?? "desconocido"}
- Tamaño empresa: ${enrichment.company?.employees ?? "desconocido"}
- País: ${enrichment.company?.country ?? "desconocido"}
- Web: ${enrichment.company?.domain ?? "desconocido"}
Criterios mi empresa:
- Atendemos: pymes y empresas medianas en España (5-500 empleados)
- Ticket medio: 3.000-15.000 €
- Servicios: agentes IA, automatización, web, e-commerce, apps
- NO cobramos por horas
Evalúa cada dimensión BANT del 0 al 25, total 0-100:
- Budget: ¿el ticket cuadra con su presupuesto/tamaño?
- Authority: ¿tiene decisión o accede a ella?
- Need: ¿lo que pide encaja con lo que hacemos?
- Timing: ¿necesita ya o en meses?
Devuelve SOLO este JSON:
{
"score": 0-100,
"tier": "A" | "B" | "C" | "D",
"budget": 0-25,
"authority": 0-25,
"need": 0-25,
"timing": 0-25,
"razones": ["razón corta 1", "razón corta 2"],
"fit": "alto" | "medio" | "bajo",
"siguiente_accion": "qué debería hacer el comercial en su primera llamada"
}
Tiers: A=80-100, B=60-79, C=40-59, D=0-39.
`;
const response = await openai.chat.completions.create({
model: "gpt-4o-mini", // suficiente para clasificación, mucho más barato
messages: [{ role: "user", content: prompt }],
response_format: { type: "json_object" },
temperature: 0,
});
return JSON.parse(response.choices[0].message.content!);
}
Coste por lead clasificado: ~0,001-0,005 € con gpt-4o-mini. Para 1.000 leads/mes: ~5 € total.
4. Crear/actualizar en HubSpot
import hubspot from "@hubspot/api-client";
const client = new hubspot.Client({ accessToken: process.env.HUBSPOT_TOKEN });
async function upsertHubspotContact(lead: any, classification: any, enrichment: any) {
const ownerByTier = {
A: process.env.HS_OWNER_SENIOR!,
B: process.env.HS_OWNER_SENIOR!,
C: process.env.HS_OWNER_JUNIOR!,
D: process.env.HS_OWNER_NURTURE!,
};
const contact = await client.crm.contacts.basicApi.create({
properties: {
email: lead.email,
firstname: lead.nombre,
lastname: lead.apellidos,
company: lead.empresa,
jobtitle: enrichment.person?.title ?? "",
industry: enrichment.company?.industry ?? "",
numemployees: String(enrichment.company?.employees ?? ""),
lead_score: String(classification.score),
lead_tier: classification.tier,
lifecyclestage: classification.tier === "D" ? "subscriber" : "marketingqualifiedlead",
hs_lead_status: classification.tier === "A" ? "NEW" : "OPEN",
hubspot_owner_id: ownerByTier[classification.tier],
lead_qualification_notes: classification.razones.join(" | "),
lead_next_action: classification.siguiente_accion,
},
});
// Crear tarea con SLA según tier
const dueDateHours = { A: 2, B: 24, C: 72, D: 168 };
await client.crm.objects.tasks.basicApi.create({
properties: {
hs_task_subject: `Lead ${classification.tier} (${classification.score}): ${lead.empresa}`,
hs_task_body: classification.siguiente_accion,
hs_task_priority: classification.tier === "A" ? "HIGH" : "MEDIUM",
hs_timestamp: String(Date.now() + dueDateHours[classification.tier] * 3600 * 1000),
hubspot_owner_id: ownerByTier[classification.tier],
},
associations: [
{
to: { id: contact.id, type: "contact" },
types: [{ associationCategory: "HUBSPOT_DEFINED", associationTypeId: 204 }],
},
],
});
}
5. Notificación al comercial
Slack con resumen visual:
async function notifyOwner(lead: any, classification: any) {
const slackUserMap = {
A: "U01ABC123", B: "U01ABC123", C: "U02DEF456", D: "U03GHI789",
};
await fetch(process.env.SLACK_WEBHOOK_LEADS!, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: `Nuevo lead tier ${classification.tier} asignado a <@${slackUserMap[classification.tier]}>`,
blocks: [
{
type: "header",
text: { type: "plain_text", text: `🎯 Lead ${classification.tier} (${classification.score}/100) - ${lead.empresa}` },
},
{
type: "section",
fields: [
{ type: "mrkdwn", text: `*Contacto:* ${lead.nombre} ${lead.apellidos}` },
{ type: "mrkdwn", text: `*Email:* ${lead.email}` },
{ type: "mrkdwn", text: `*Fit:* ${classification.fit}` },
{ type: "mrkdwn", text: `*Siguiente acción:* ${classification.siguiente_accion}` },
],
},
{
type: "section",
text: { type: "mrkdwn", text: `*Mensaje original:*\n> ${lead.mensaje}` },
},
],
}),
});
}
6. Medición y mejora
Captura métricas desde el día 1:
| Métrica | Objetivo |
|---|---|
| Leads / día | depende de tu marketing |
| % Tier A | 10-25% típicamente |
| Conversión Tier A a SQL | >50% |
| Conversión Tier A a cliente | >20% |
| Falsos positivos (A pero no encaja) | <10% |
| Tiempo de respuesta comercial | <2h para Tier A |
Si los falsos positivos suben mucho, ajusta los criterios del prompt y prueba con leads históricos.
Variaciones según sector
- B2C alto ticket (inmobiliaria, lujo): añade verificación de capacidad financiera.
- SaaS: añade scoring de fit técnico (¿usan el stack que necesitan?).
- Servicios profesionales: añade scoring de “urgencia legal” o “criticidad”.
- E-commerce B2B: añade volumen estimado y frecuencia.
Costes reales mes a mes
Para una empresa con 500 leads/mes:
| Concepto | Coste |
|---|---|
| Clearbit Reveal (free tier hasta 1000) | 0 € |
| Hunter (verificación email) | 49 € |
| OpenAI gpt-4o-mini | ~3 € |
| HubSpot (sin cambios, ya lo tienes) | — |
| Slack (sin cambios) | — |
| Total | ~52 €/mes |
Ahorras 10-20h semanales de SDR. ROI inmediato.
Conclusión
Cualificar leads manualmente en 2026 es absurdo si tienes >50 leads/mes. El pipeline de este artículo:
- Tarda 2 semanas en implementarse bien
- Cuesta ~50-100 €/mes operativo
- Libera 10-20h semanales de tu equipo
- Mejora el tiempo de respuesta a leads top (factor de conversión crítico)
- Genera métricas accionables que antes no tenías
En La Bahía Digital implementamos pipelines como este de forma cerrada por 3.500-5.500 € según complejidad. Incluye integración, prompts optimizados con tus criterios reales y dashboard de métricas. Cuéntanos tu volumen y stack y te enviamos propuesta.
Lecturas relacionadas: