Reactive CRM Recepción de Leads Multi-Contrato desde el Sitio Web ← Guía de integración

Recepción de Leads Multi-Contrato desde el Sitio Web

Este documento describe un único contrato API a través del cual el backend del sitio envía datos de lead, los detalles de contacto del visitante y las métricas UTM de marketing a ReactiveCRM en una sola solicitud.

1. Propósito

El integrador del sitio no necesita crear por separado el contacto, teléfono, correo electrónico, lead y evento de marketing. Una sola solicitud debe crear atómicamente:

  1. el contacto;
  2. el teléfono principal del contacto;
  3. el correo electrónico principal del contacto, si se proporciona;
  4. el lead;
  5. el vínculo entre el contacto y el lead;
  6. el evento de marketing y la atribución UTM.

Si falla algún paso, toda la solicitud se revierte y los datos parcialmente creados no se guardan.

2. Endpoint

http
POST /api/site/leads
Authorization: Bearer <CRM_ACCESS_TOKEN>
Content-Type: application/json

El token debe pasarse únicamente desde el backend del sitio o una función serverless. Nunca coloque el token de CRM en JavaScript del navegador.

El inquilino se determina a partir del token de autorización. Todos los UUID proporcionados se validan dentro de este inquilino.

3. Contrato JSON completo

json
{
  "externalId": "site-form-01J7K9A2M4Y5T6",
  "lead": {
    "leadSourceId": "7b33b18f-55bd-48a5-a8f0-e450a56dde47",
    "quality": "WARM",
    "message": "Me gustaría una asesoría sobre la implementación de CRM"
  },
  "contact": {
    "firstName": "Ivan",
    "lastName": "Ivanov",
    "phone": "+79991234567",
    "email": "ivan@example.com"
  },
  "marketing": {
    "occurredAt": "2026-09-06T18:00:00Z",
    "visitorId": "visitor-8b7f",
    "sessionId": "session-31ac",
    "source": "website",
    "channel": "paid",
    "utmSource": "google",
    "utmMedium": "cpc",
    "utmCampaign": "summer-consulting",
    "utmContent": "banner-a",
    "utmTerm": "crm consultation",
    "gclid": "EAIaIQobChMI-example",
    "fbclid": null,
    "landingUrl": "https://example.com/consultation",
    "referrer": "https://www.google.com/"
  }
}

4. Campos de la solicitud

4.1. Campos raíz

CampoTipoRequeridoDescripción
externalIdcadenarecomendadoID único estable del envío del formulario para idempotencia
leadobjetosíDatos del lead que se está creando
contactobjetosíDatos de la persona de contacto
marketingobjetonoMétricas UTM y datos técnicos de la visita de marketing

externalId se genera antes del primer intento de envío. Al repetir la solicitud después de un tiempo de espera o error de red, use el mismo valor.

4.2. El objeto lead

CampoTipoRequeridoDescripción
leadSourceIduuidsíID de la fuente de leads en el inquilino actual
qualitycadenanoCalificación inicial: HOT, WARM, COOL o COLD
messagecadenanoMensaje del visitante o comentario sobre el envío

Si el sitio no realiza una precalificación, es mejor no enviar el campo quality.

4.3. El objeto contact

CampoTipoRequeridoDescripción
firstNamecadenasíNombre de la persona de contacto
lastNamecadenanoApellido de la persona de contacto
phonecadenasíTeléfono principal; se recomienda el formato E.164
emailcadena(email)noCorreo electrónico principal de la persona de contacto

Los datos mínimos necesarios para procesar un envío son firstName y phone.

4.4. El objeto marketing

CampoTipoRequeridoDescripción
occurredAtfecha-horanoHora del envío del formulario; se usa la hora de CRM si está ausente
visitorIdcadenanoID de visitante anónimo
sessionIdcadenanoID de sesión del sitio
sourcecadenanoFuente del evento, por defecto website
channelcadenanoCanal: ej. paid, organic, social, email, direct
utmSourcecadenanoValor de utm_source
utmMediumcadenanoValor de utm_medium
utmCampaigncadenanoValor de utm_campaign
utmContentcadenanoValor de utm_content
utmTermcadenanoValor de utm_term
gclidcadenanoID de clic de Google
fbclidcadenanoID de clic de Meta/Facebook
landingUrlcadenanoURL de la página de destino
referrercadenanoURL de la página anterior

Los datos personales no deben duplicarse en el objeto marketing. El nombre, teléfono, correo electrónico y el texto del mensaje se pasan únicamente en contact y lead.

5. Solicitud mínima

json
{
  "externalId": "site-form-550e8400-e29b-41d4-a716-446655440000",
  "lead": {
    "leadSourceId": "7b33b18f-55bd-48a5-a8f0-e450a56dde47"
  },
  "contact": {
    "firstName": "Ivan",
    "phone": "+79991234567"
  }
}

6. Respuesta exitosa

Primera solicitud — 201 Created

json
{
  "leadId": "22222222-2222-2222-2222-222222222222",
  "contactId": "33333333-3333-3333-3333-333333333333",
  "phoneId": "44444444-4444-4444-4444-444444444444",
  "emailId": "55555555-5555-5555-5555-555555555555",
  "marketingEventId": "66666666-6666-6666-6666-666666666666",
  "duplicate": false,
  "createdAt": "2026-09-06T18:00:01Z"
}

Si no se proporcionan datos de correo electrónico o marketing, los ID correspondientes se devuelven como null.

Repetición con el mismo externalId — 200 OK

json
{
  "leadId": "22222222-2222-2222-2222-222222222222",
  "contactId": "33333333-3333-3333-3333-333333333333",
  "phoneId": "44444444-4444-4444-4444-444444444444",
  "emailId": "55555555-5555-5555-5555-555555555555",
  "marketingEventId": "66666666-6666-6666-6666-666666666666",
  "duplicate": true,
  "createdAt": "2026-09-06T18:00:01Z"
}

Una solicitud repetida no debe crear un segundo lead o contacto.

7. Ejemplo con cURL

bash
curl -X POST "$CRM_BASE_URL/api/site/leads" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "site-form-01J7K9A2M4Y5T6",
    "lead": {
      "leadSourceId": "7b33b18f-55bd-48a5-a8f0-e450a56dde47",
      "quality": "WARM",
      "message": "Llámeme de vuelta"
    },
    "contact": {
      "firstName": "Ivan",
      "lastName": "Ivanov",
      "phone": "+79991234567",
      "email": "ivan@example.com"
    },
    "marketing": {
      "utmSource": "google",
      "utmMedium": "cpc",
      "utmCampaign": "crm-demo",
      "landingUrl": "https://example.com/demo"
    }
  }'

8. Interfaces TypeScript

ts
type LeadQuality = 'HOT' | 'WARM' | 'COOL' | 'COLD';

interface SiteLeadRequest {
  externalId?: string;
  lead: {
    leadSourceId: string;
    quality?: LeadQuality;
    message?: string;
  };
  contact: {
    firstName: string;
    lastName?: string;
    phone: string;
    email?: string;
  };
  marketing?: {
    occurredAt?: string;
    visitorId?: string;
    sessionId?: string;
    source?: string;
    channel?: string;
    utmSource?: string;
    utmMedium?: string;
    utmCampaign?: string;
    utmContent?: string;
    utmTerm?: string;
    gclid?: string;
    fbclid?: string;
    landingUrl?: string;
    referrer?: string;
  };
}

interface SiteLeadResponse {
  leadId: string;
  contactId: string;
  phoneId: string;
  emailId: string | null;
  marketingEventId: string | null;
  duplicate: boolean;
  createdAt: string;
}

9. Ejemplo del lado del servidor

ts
export async function sendLeadToCrm(payload: SiteLeadRequest): Promise<SiteLeadResponse> {
  const response = await fetch(`${process.env.CRM_BASE_URL}/api/site/leads`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.CRM_ACCESS_TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(payload),
  });

  if (!response.ok) {
    const body = await response.text();
    throw new Error(`ReactiveCRM returned ${response.status}: ${body}`);
  }

  return response.json() as Promise<SiteLeadResponse>;
}

10. Errores

HTTPCausaAcción del integrador
400Error de formato, campo requerido faltante, correo/teléfono/quality inválidoCorrija los datos; no reintente automáticamente sin cambios
401Token faltante o inválidoActualice el token de integración
403Sin acceso al inquilino o a la operaciónVerifique el usuario de integración y el rol
404leadSourceId no encontrado en el inquilino actualActualice el ID de fuente en la configuración del sitio
409externalId ya está vinculado a una solicitud incompatibleVerifique la generación de ID y el registro de integración
5xxError transitorio de CRMReintente la misma solicitud con el mismo externalId

Ejemplo de error de validación:

json
{
  "status": 400,
  "error": "Bad Request",
  "message": "contact.phone must not be blank",
  "path": "/api/site/leads"
}

11. Idempotencia

12. Mini-guía para el desarrollador del sitio

  1. En la primera visita, almacene las etiquetas UTM, gclid, fbclid, la URL de destino y el referente.
  2. Cuando se envíe el formulario, genere un externalId estable.
  3. Envíe el formulario al backend del sitio.
  4. El backend añade el token de CRM y llama a POST /api/site/leads.
  5. En 201 o 200 con duplicate: true, considere el envío entregado.
  6. En caso de tiempo de espera o 5xx, reintente la solicitud con el mismo externalId.
  7. Nunca envíe el token de CRM directamente desde el navegador.

13. Lo que obtiene el gestor de CRM

Después de una solicitud exitosa, el CRM contiene un lead que:

Este conjunto es suficiente para que el gestor vea el envío, llame al contacto y califique el lead.