Cómo Funciona

Esta guía explica en detalle cómo funciona el procesamiento de leads en MasLeads API.

Visión General

MasLeads API es asíncrona. Esto significa que:

  1. Envías los leads a procesar
  2. Recibes un job_id inmediatamente
  3. El procesamiento ocurre en segundo plano
  4. Consultas o recibes los resultados cuando estén listos
┌──────────────┐       ┌──────────────┐       ┌──────────────┐
│   TU APP     │       │  MASLEADS    │       │   TU APP     │
│              │       │     API      │       │              │
│  Crear Job   │──────▶│  Procesa...  │       │              │
│              │       │              │       │              │
│  Consultar   │──────▶│  "pending"   │       │              │
│   estado     │◀──────│              │       │              │
│              │       │              │       │              │
│  Consultar   │──────▶│ "completed"  │       │              │
│   estado     │◀──────│              │       │              │
│              │       │              │       │              │
│  Obtener     │──────▶│              │──────▶│  Resultados  │
│  resultados  │       │              │       │              │
└──────────────┘       └──────────────┘       └──────────────┘

Paso 1: Crear un Job

Endpoint

POST /api/v1/enrich/leads

Request Body

{
  "leads": [
    {
      "first_name": "Carlos",
      "last_name": "García",
      "company": "Telefonica",
      "linkedin_url": "https://linkedin.com/in/carlosgarcia",
      "title": "Director Comercial"
    }
  ],
  "enrichment_type": ["email", "phone"],
  "webhook_url": "https://tu-servidor.com/webhook"
}

Campos de Lead

Campo Requerido Descripción
first_name ✅ Sí Nombre del contacto
last_name ✅ Sí Apellido del contacto
company ✅ Sí Nombre de la empresa
linkedin_url ❌ No URL de perfil LinkedIn (mejora precisión)
title ❌ No Cargo en la empresa
domain ❌ No Dominio de la empresa (alternativa a company)

Tipos de Datos Solicitados

Tipo Créditos Descripción
email 1 Email corporativo verificado
phone 1 Teléfono directo
["email", "phone"] 2 Ambos datos

Límites por Defecto

Restricción Valor por defecto Configuración
Máximo leads por job 100 Según plan
Mínimo leads por job 1 Fijo
Jobs concurrentes máximo 10 Según plan

Nota: Los límites pueden variar según tu plan contratado.

Response

{
  "job_id": "job_abc123xyz",
  "status": "pending",
  "total_leads": 1,
  "credits_reserved": 2,
  "created_at": "2025-01-08T10:30:00Z"
}

Paso 2: Monitorear el Estado

Opción A: Polling

Consulta periódicamente el estado del job:

GET /api/v1/jobs/{job_id}

Estados del Job

Estado Descripción Acción
pending En cola Esperar y reintentar
processing Procesando Esperar y reintentar
completed Finalizado Obtener resultados
failed Error Ver mensaje de error

Estrategia de Polling Recomendada

import time

def poll_job(job_id, max_attempts=60, interval=2):
    """
    Polling con backoff exponencial suave.
    Timeout total: ~2 minutos
    """
    for attempt in range(max_attempts):
        response = get_job_status(job_id)
        status = response["status"]

        if status == "completed":
            return response
        elif status == "failed":
            raise Exception(f"Job failed: {response.get('error')}")

        # Aumentar intervalo gradualmente
        wait_time = min(interval * (1.2 ** (attempt // 10)), 10)
        time.sleep(wait_time)

    raise TimeoutError("Job did not complete in time")

Opción B: Webhooks (Recomendado)

En lugar de hacer polling, configura un webhook para recibir notificaciones automáticas.

Ver Guía de Webhooks para configuración completa.

Paso 3: Obtener Resultados

Cuando status sea completed:

GET /api/v1/jobs/{job_id}/results

Response

{
  "job_id": "job_abc123xyz",
  "results": [
    {
      "input": {
        "first_name": "Carlos",
        "last_name": "García",
        "company": "Telefonica"
      },
      "status": "found",
      "data": {
        "email": "carlos.garcia@telefonica.com",
        "email_confidence": 0.95,
        "phone": "+34612345678",
        "phone_confidence": 0.87
      }
    }
  ],
  "summary": {
    "total": 1,
    "found": 1,
    "not_found": 0,
    "error": 0
  }
}

Estados de Resultado por Lead

Status Descripción Créditos
found Datos encontrados Consumidos
not_found No se encontró información Reembolsados
error Error de procesamiento Reembolsados

Niveles de Confianza

Rango Interpretación
0.90 - 1.00 Alta confianza, verificado
0.70 - 0.89 Confianza media, probable
0.50 - 0.69 Baja confianza, requiere verificación
< 0.50 No incluido en resultados

Listar Jobs

Para ver el historial de jobs:

GET /api/v1/jobs?status=completed&limit=10

Query Parameters

Parámetro Tipo Descripción
status string Filtrar por estado
limit int Máximo resultados (default: 20, max: 100)
offset int Para paginación
created_after ISO date Jobs creados después de fecha
created_before ISO date Jobs creados antes de fecha

Response

{
  "jobs": [
    {
      "job_id": "job_abc123xyz",
      "status": "completed",
      "total_leads": 50,
      "leads_found": 42,
      "created_at": "2025-01-08T10:30:00Z",
      "completed_at": "2025-01-08T10:32:15Z"
    }
  ],
  "pagination": {
    "total": 156,
    "limit": 10,
    "offset": 0,
    "has_more": true
  }
}

Errores Comunes

400 Bad Request - Leads inválidos

{
  "error": "validation_error",
  "message": "Invalid leads data",
  "details": [
    {"index": 2, "field": "first_name", "error": "required"}
  ]
}

402 Payment Required - Sin créditos

{
  "error": "insufficient_credits",
  "message": "Not enough credits. Required: 200, Available: 50"
}

429 Too Many Requests - Límite de jobs

{
  "error": "max_concurrent_jobs_exceeded",
  "message": "Maximum concurrent jobs reached. Wait for existing jobs to complete."
}

Mejores Prácticas

Optimizar la tasa de éxito

  1. Incluye LinkedIn URL cuando esté disponible (aumenta precisión ~30%)
  2. Usa el nombre de empresa exacto (no abreviaciones)
  3. Incluye el cargo para desambiguar contactos

Batch eficiente

# ✅ Bueno: Un job con 100 leads
create_job(leads=leads_batch)

# ❌ Malo: 100 jobs de 1 lead cada uno
for lead in leads:
    create_job(leads=[lead])

Manejo de errores

try:
    job = create_job(leads)
except InsufficientCreditsError:
    notify_admin("Need to purchase more credits")
except ConcurrentJobsLimitError:
    queue_for_later(leads)
except RateLimitError as e:
    time.sleep(e.retry_after)
    retry()

Anterior: ← Autenticación | Siguiente: Webhooks →