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:

  • email
  • nombre y apellidos
  • empresa
  • mensaje (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étricaObjetivo
Leads / díadepende de tu marketing
% Tier A10-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:

ConceptoCoste
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: