ZEVRACentro de Ayuda
IntegracionesAPI de captación

Atribución

Dile al CRM qué campaña, plataforma y anuncio produjeron cada lead, con los mismos parámetros UTM que ya usas.

Qué es

atribucion es un objeto opcional del cuerpo que describe el esfuerzo de marketing que trajo al prospecto: la campaña, la plataforma de tráfico, el tipo de tráfico, el anuncio o la variante, y la página donde convirtió. Sus campos corresponden uno a uno a los parámetros UTM, así que si tu landing ya recibe utm_campaign y compañía, solo tienes que reenviarlos.

{
  "nombre": "Ana Ruiz",
  "telefono": "+52 55 0000 0001",
  "propiedad": { "codigo": "ZVR-0123" },
  "atribucion": {
    "campana": "preventa-torre-b-sep",
    "fuente": "facebook",
    "medio": "cpc",
    "contenido": "video-recorrido-01",
    "pagina": "https://tusitio.com/torre-b"
  }
}

Una llave por sitio, atribución por campaña

La llave de API es el origen dentro de Captación: se enruta, se revoca y se reporta por separado. Por eso la regla es una llave por sitio web o por sistema (tu sitio principal, el chatbot de terceros, el call center), y atribucion para distinguir las campañas dentro de ese sitio. No crees una llave por campaña: multiplicarías orígenes y reglas de asignación para un dato que cabe en un campo.

Los campos

CampoUTMQué es
campanautm_campaignLa campaña o el esfuerzo: preventa-torre-b-sep, remarketing-octubre.
fuenteutm_sourceLa plataforma de tráfico: google, facebook, instagram, newsletter.
medioutm_mediumEl tipo de tráfico: cpc, organic, social, email, qr.
contenidoutm_contentEl anuncio, la variante o el botón: video-recorrido-01, boton-hero.
pagina(la URL)La página donde convirtió, sin query string: https://tusitio.com/torre-b o /torre-b.

Todos son opcionales y todos son texto. Manda los que tengas; un objeto con un solo campo es válido.

Cómo se normalizan

campana, fuente, medio y contenido se guardan recortados, con los espacios repetidos colapsados a uno, en minúsculas y cortados a 120 caracteres. Preventa Torre B y preventa torre b son la misma campaña. pagina se guarda tal como llega, cortada a 500 caracteres; tiene que ser una URL o una ruta que empiece por /.

Las llaves que no reconocemos se ignoran. Un campo con un tipo que no es texto (un número, un objeto) responde 400 validation_error con field apuntando al campo, por ejemplo atribucion.campana.

No cambia el origen ni la fuente

La atribución es información, no enrutamiento. El origen del lead sigue siendo la llave con la que llegó, y sus reglas de asignación se aplican igual. La Fuente del lead sigue siendo "API". fuente en atribucion es la plataforma de tráfico (de dónde vino el clic), no la fuente del lead en el CRM; son dos cosas distintas y se muestran en lugares distintos.

Solo la primera vez

La atribución se guarda cuando el teléfono entra al CRM por primera vez. Si el mismo teléfono vuelve a llegar (una respuesta 200 con "status": "enriched"), la atribución guardada no se toca: el lead sigue perteneciendo a la campaña que lo trajo. La campana nueva sí aparece en la Actividad del lead, así que el asesor ve que el prospecto volvió a convertir por otra campaña sin perder la original.

En modo de prueba, la respuesta incluye resolved.atribucion con los valores ya normalizados, o null si no la mandaste. Así se ve para el cuerpo de arriba (más un extras con el nombre del formulario):

{
  "status": "dry_run",
  "would": "create",
  "would_match": null,
  "resolved": {
    "organizacion": "Inmobiliaria Ejemplo",
    "origen": "Formulario del sitio",
    "development_id": "c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
    "unit_type_ids": [],
    "nombre": "Ana Ruiz",
    "telefono": "+525500000001",
    "email": null,
    "extras": { "origen_formulario": "landing-torre-b" },
    "atribucion": {
      "campana": "preventa-torre-b-sep",
      "fuente": "facebook",
      "medio": "cpc",
      "contenido": "video-recorrido-01",
      "pagina": "https://tusitio.com/torre-b"
    }
  },
  "request_id": "req_4f1c9a2b7d3e8c5a6b0f1e2d"
}

Dónde se ve en el dashboard

En el lead, la pastilla de Fuente abre un detalle con la atribución: Campaña, Plataforma, Medio, Contenido y Página. Es el mismo lugar donde el asesor ve de dónde llegó cualquier otro lead.

Ejemplo con curl

curl -X POST https://api.zevra.co/v1/leads \
  -H "Authorization: Bearer $ZEVRA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: formulario-web-8f3c2c" \
  -d '{
    "nombre": "Ana Ruiz",
    "telefono": "+52 55 0000 0001",
    "propiedad": { "codigo": "ZVR-0123" },
    "atribucion": {
      "campana": "preventa-torre-b-sep",
      "fuente": "facebook",
      "medio": "cpc",
      "contenido": "video-recorrido-01",
      "pagina": "https://tusitio.com/torre-b"
    }
  }'

Desde tu landing

Los parámetros UTM viven en la URL de la página, del lado del visitante. Tu formulario tiene que llevarlos hasta tu servidor, que es quien habla con ZEVRA. Lo más sencillo es copiarlos a campos ocultos del formulario al cargar la página:

<form method="post" action="/enviar-lead">
  <input type="hidden" name="utm_campaign" />
  <input type="hidden" name="utm_source" />
  <input type="hidden" name="utm_medium" />
  <input type="hidden" name="utm_content" />
  <input type="hidden" name="pagina" />
  <!-- nombre, teléfono, etc. -->
</form>

<script>
  const params = new URLSearchParams(window.location.search);
  for (const name of ["utm_campaign", "utm_source", "utm_medium", "utm_content"]) {
    document.querySelector(`input[name="${name}"]`).value = params.get(name) ?? "";
  }
  document.querySelector('input[name="pagina"]').value =
    window.location.origin + window.location.pathname;
</script>

En el servidor, los campos ocultos se convierten en atribucion. En PHP:

$atribucion = array_filter([
    'campana'   => $_POST['utm_campaign'] ?? null,
    'fuente'    => $_POST['utm_source'] ?? null,
    'medio'     => $_POST['utm_medium'] ?? null,
    'contenido' => $_POST['utm_content'] ?? null,
    'pagina'    => $_POST['pagina'] ?? null,
]);

Si la landing misma manda el lead desde el servidor (por ejemplo, la página se sirve con PHP y la URL todavía trae los parámetros), lee $_GET['utm_campaign'] en lugar de $_POST. En Node.js, con el cuerpo del formulario ya parseado en form:

const atribucion = { campana: form.utm_campaign, fuente: form.utm_source, medio: form.utm_medium, contenido: form.utm_content, pagina: form.pagina };

Manda solo los campos que traen valor: en PHP array_filter quita los vacíos, y en Node.js JSON.stringify omite los undefined. Si el visitante llegó sin parámetros UTM (tráfico directo), omite atribucion o mándala solo con pagina; el lead entra igual.

En esta página