Saltar al contenido

Sincronizar envíos de formularios de HubSpot a Salesforce en Jitterbit Studio

Introducción

Los envíos de formularios de HubSpot llegan como una lista paginada en la que cada envío contiene un arreglo de pares nombre/valor (un par por cada campo del formulario) en lugar de un registro plano con propiedades nombradas. Esta guía muestra cómo recuperar esos envíos usando la API de Envíos de Formularios de HubSpot a través del conector HTTP v2, enviarlos uno a la vez a través del patrón de bucle SelectNodes de Studio, extraer la dirección de correo electrónico, el nombre y el apellido de la matriz de valores, buscar en Salesforce un cliente potencial existente, y crear o actualizar un registro de Cliente potencial según el resultado.

Esta guía utiliza:

  • El conector HTTP v2 para llamar a la API de Envíos de Formularios de HubSpot.
  • Almacenamiento temporal de Studio para mantener el lote de envío completo entre el paso de obtención y el bucle de envío por registro.
  • SelectNodes y ReadFile para iterar a través de registros XML almacenados.
  • SfLookupAll para detectar clientes potenciales duplicados por dirección de correo electrónico.
  • Las actividades Crear y Actualizar del conector de Salesforce para escribir el registro de Cliente potencial.

Esta guía asume una cuenta de HubSpot con una aplicación privada y un token de acceso. Se necesita el GUID del formulario cuyos envíos se desean sincronizar. Cada formulario de HubSpot tiene un GUID único visible en la URL del editor de formularios o a través de la API de Formularios de HubSpot.

Patrón de diseño

La integración se ejecuta en dos etapas: una obtención por lotes que recupera todos los envíos de un formulario y los almacena como XML, y un bucle por registro que procesa cada envío individualmente.

flowchart LR A["Script
Initialize variables
Set form path"] --> B["HTTP v2 GET
HubSpot submissions
for [$hubspot.form.guid]"] B --> C["Transformation
Write to
temp storage (batch)"] C --> D["Script
ReadFile + SelectNodes
loop over submissions"] D --> E["Per-record operation
(transformation + scripts)"] E --> F{"Email found
in Salesforce?"} F -- Yes --> G["Salesforce
Update Lead"] F -- No --> H["Salesforce
Create Lead
+ optional ZoomInfo enrich"]

La obtención por lotes se ejecuta una vez por sincronización de formulario. El bucle por registro se ejecuta una vez por envío.

Parte 1: Configurar variables de proyecto y la conexión HTTP v2

Paso 1: Crear variables de proyecto

Almacena el token de acceso de HubSpot y el GUID del formulario como variables de proyecto para que se puedan actualizar sin editar scripts. Abre el menú de acciones del proyecto y selecciona Variables de proyecto. Luego agrega:

Nombre Valor predeterminado Descripción
hubspot.access.token (tu token de acceso de aplicación privada de HubSpot) Token de portador utilizado para autenticar todas las llamadas a la API
hubspot.form.guid (tu GUID de formulario de HubSpot) GUID del formulario cuyos envíos se desean sincronizar

Marca hubspot.access.token como oculta. Para obtener orientación sobre cómo almacenar credenciales de forma segura, consulta Administrar credenciales de punto de conexión.

Paso 2: Configurar la conexión HTTP v2

  1. En Studio, abre tu proyecto y haz clic en la pestaña Puntos de conexión y conectores del proyecto en la paleta de componentes de diseño.

  2. Haz clic en el conector HTTP v2 para abrir la pantalla de configuración de conexión.

  3. Nombre de conexión: Ingresa HubSpot API.

  4. URL base: Ingresa https://api.hubapi.com.

  5. Autorización: Selecciona Token de portador e ingresa [$hubspot.access.token] como valor del token.

  6. Haz clic en Probar para verificar la conexión y luego haz clic en Guardar cambios.

Paso 3: Crear la actividad GET Envíos de Formularios

  1. Desde la conexión HubSpot API, arrastra una actividad GET al lienzo de diseño.

  2. Nombre: Ingresa HubSpot - GET Form Submissions.

  3. Ruta: Ingresa /form-integrations/v1/submissions/forms/[$hubspot.form.guid].

    Studio sustituye [$hubspot.form.guid] con el valor de la variable de proyecto en tiempo de ejecución. Para sincronizar un formulario diferente, actualiza la variable de proyecto sin modificar la configuración de la actividad.

  4. En la pestaña Solicitud, agrega un encabezado:

    • Clave: Content-Type
    • Valor: application/json
  5. Haz clic en Finalizado.

Parte 2: Recuperar envíos y escribirlos en almacenamiento temporal

Paso 1: Crear la operación de obtención

Crea una operación llamada HubSpot - Fetch Form Submissions con estos pasos en orden:

  1. Script: Inicializa las variables utilizadas en el procesamiento por registro:

    // Reset per-run staging variables
    $hubspot.email = "";
    $hubspot.firstName = "";
    $hubspot.lastName = "";
    
    WriteToOperationLog("Starting HubSpot form submission sync for form: " + [$hubspot.form.guid]);
    
  2. Actividad GET: Coloca la actividad HubSpot - GET Form Submissions como paso de origen.

  3. Transformación: Agrega una transformación después de la actividad GET con una actividad Temporary Storage Write como destino. Asigna el esquema JSON de origen al esquema de destino en los niveles de bucle results/item y results/item/values/item para que todos los registros de envío se escriban en almacenamiento temporal en una sola pasada.

    Nombra la transformación HubSpot - Write Submissions to Temp Storage y nombra la actividad Temporary Storage Write como Write HubSpot Submissions.

La actividad Temporary Storage Write almacena los registros de envío como XML. Studio escribe cada elemento en el nivel de bucle más interno como un elemento DocInfo, que es el formato que el bucle de distribución lee en Parte 3.

Paso 2: Manejar el caso en el que no se encuentren envíos

Agrega un paso Script después de la transformación. Verifica el recuento de envíos antes de distribuir el bucle:

$count = Length(SelectNodes(
    ReadFile("<TAG>activity:tempstorage/HubSpot Temp Storage/tempstorage_read/Read HubSpot Submissions</TAG>"),
    "//DocInfo"
));

If($count == 0,
    WriteToOperationLog("No HubSpot submissions found. Exiting.");
    CancelOperation("<TAG>operation:HubSpot - Fetch Form Submissions</TAG>");
,
    WriteToOperationLog("Found " + $count + " submission(s) to process.");
);

CancelOperation cancela la operación actual de forma limpia sin generar un error cuando no hay envíos presentes.

Parte 3: Distribuir envíos uno a la vez

Paso 1: Agregar el script de distribución

Agrega un paso Script a la operación HubSpot - Fetch Form Submissions después de la verificación de recuento. Este script lee el lote almacenado, extrae registros de envío individuales usando SelectNodes y llama a una operación por registro una vez por envío:

data = ReadFile("<TAG>activity:tempstorage/HubSpot Temp Storage/tempstorage_read/Read HubSpot Submissions</TAG>");
nodes = SelectNodes(data, "//DocInfo");
counts = Length(nodes);

WriteToOperationLog("Dispatching " + counts + " submission(s).");
i = 0;
While(i < counts,
    node = nodes[i];

    // Wrap the single node so the per-record operation has a valid XML source
    xml = "<SubmissionBatch><Submissions>" + String(node) + "</Submissions></SubmissionBatch>";

    WriteFile(
        "<TAG>activity:tempstorage/HubSpot Temp Storage 2/tempstorage_write/Write Single HubSpot Submission</TAG>",
        xml
    );
    FlushFile(
        "<TAG>activity:tempstorage/HubSpot Temp Storage 2/tempstorage_write/Write Single HubSpot Submission</TAG>"
    );

    RunOperation("<TAG>operation:HubSpot - Process Single Submission</TAG>");
    i = i + 1;
);

El contenedor <SubmissionBatch><Submissions> es un contenedor externo fijo que proporciona a la transformación de origen de la operación por registro un elemento raíz predecible. El nodo DocInfo extraído se convierte en el elemento interno que la transformación asigna.

FlushFile fuerza la finalización de la escritura antes de que RunOperation llame a la operación por registro. Sin vaciar, la operación puede leer los datos del registro anterior.

Importante

RunOperation está sujeto a un límite a nivel de agente en las llamadas síncronas realizadas dentro de un único bucle While (50 de forma predeterminada). Si un lote tiene más de 50 envíos, este bucle de distribución alcanza ese límite a mitad de camino: RunOperation devuelve false para el envío 51 en adelante, y los envíos restantes en el lote no se procesan. Consulta la nota bajo RunOperation para saber cómo configurar o anular este límite para GUIDs de formulario que reciben regularmente más de 50 envíos por sincronización.

Paso 2: Configurar almacenamiento temporal para distribución por registro

Configura un segundo extremo de Temporary Storage (por ejemplo, HubSpot Temp Storage 2) con:

  • Una actividad Write llamada Write Single HubSpot Submission.
  • Una actividad Read llamada Read Single HubSpot Submission, utilizada como origen en la operación por registro.

Los dos extremos mantienen el lote completo y el búfer por registro separados para que el bucle de distribución no sobrescriba los datos de origen que está iterando.

Parte 4: Extraer valores de campo del envío

Los envíos de formularios de HubSpot almacenan valores de campo como una matriz values de objetos nombre/valor. El nombre del campo (email, firstname, lastname) está en el campo name, y el valor enviado está en el campo value. La transformación debe iterar ambos niveles (results/item para cada envío y el values/item anidado para cada campo) y leer el campo name para saber qué variable rellenar.

Paso 1: Crear la operación por registro

Crear una operación llamada HubSpot - Process Single Submission. Su origen es la actividad Read Single HubSpot Submission Temporary Storage Read.

Paso 2: Crear la transformación de extracción de campos

Agregar una transformación a la operación por registro llamada HubSpot - Extract Submission Fields. Definir dos niveles de bucle en la transformación:

  • Bucle externo: results/item en el origen, asignado a la ruta de destino correspondiente.
  • Bucle interno: results/item/values/item en el origen, anidado dentro del bucle externo.

En el bucle interno, agregar estos scripts de asignación:

Para el nodo de destino values/item/name:

$hubspot.fieldName = json$results$item.values$item.name$

Para el nodo de destino values/item/value:

If($hubspot.fieldName == "email",
    $hubspot.email = json$results$item.values$item.value$
);
If($hubspot.fieldName == "firstname",
    $hubspot.firstName = json$results$item.values$item.value$
);
If($hubspot.fieldName == "lastname",
    $hubspot.lastName = json$results$item.values$item.value$
);

Para el nodo de destino externo results/item/pageUrl (que se ejecuta después de que se completa el bucle interno para cada envío), llamar a la operación de verificación de Salesforce:

If(Length(Trim($hubspot.email)) > 0,
    $hubspot.email = ToLower(Trim($hubspot.email));
    RunOperation("<TAG>operation:HubSpot - Check Salesforce Lead</TAG>");
,
    WriteToOperationLog("Submission missing email field. Skipping.");
);

La asignación de pageUrl se ejecuta una vez por registro de envío, después de que se hayan procesado todos sus elementos secundarios values/item. Esto la convierte en el lugar correcto para activar la operación de Salesforce descendente. Normalizar el correo electrónico a minúsculas antes de la búsqueda evita discrepancias sensibles a mayúsculas y minúsculas con los registros de Salesforce.

Parte 5: Verificar Salesforce para un cliente potencial existente

Paso 1: Crear la operación de verificación de Salesforce

Crear una operación llamada HubSpot - Check Salesforce Lead. Agregar un paso de Script como único paso de operación:

$sf.existingLeadId = "";

$result = SfLookupAll(
    "<TAG>endpoint:salesforce/Salesforce</TAG>",
    "SELECT Id FROM Lead WHERE Email = '"
        + $hubspot.email
        + "' AND IsConverted = false LIMIT 1"
);

If(Length($result) > 0,
    $sf.existingLeadId = $result[0][0];
    WriteToOperationLog("Existing lead found: " + $sf.existingLeadId);
    RunOperation("<TAG>operation:HubSpot - Update Salesforce Lead</TAG>");
,
    WriteToOperationLog("No existing lead for: " + $hubspot.email);
    RunOperation("<TAG>operation:HubSpot - Create Salesforce Lead</TAG>");
);

SfLookupAll devuelve una matriz bidimensional: cada matriz interna es una fila de resultado, y cada elemento es un valor de campo en el orden indicado en la cláusula SELECT. $result[0][0] es el campo Id de la primera (y única) fila devuelta. LIMIT 1 evita que múltiples coincidencias causen un error de índice de matriz cuando el mismo correo electrónico aparece en más de un registro de cliente potencial.

IsConverted = false excluye los clientes potenciales que ya se han convertido en contactos, oportunidades o cuentas. Actualizar un cliente potencial convertido en Salesforce genera un error, por lo que es más seguro omitirlos y dejar que la ruta de creación maneje el caso extremo por separado si es necesario.

Para el patrón de consulta SOQL, consultar Consultar registros de Salesforce usando SOQL.

Parte 6: Crear o actualizar el cliente potencial de Salesforce

Paso 1: Crear el registro de cliente potencial

Crear una operación llamada HubSpot - Create Salesforce Lead. Agregar un paso de Transformación que asigne las variables de almacenamiento provisional a una actividad de Creación de Salesforce dirigida al objeto Lead:

Expresión de origen Campo de cliente potencial de Salesforce
$hubspot.firstName FirstName
$hubspot.lastName LastName
$hubspot.email Email
"HubSpot" (literal) LeadSource

Establecer un valor literal para LeadSource a fin de etiquetar todos los clientes potenciales creados por esta integración para fines de informes.

La actividad de Creación de Salesforce devuelve el ID del nuevo registro. Capturarlo para usarlo en el paso de enriquecimiento opcional:

$sf.newLeadId = TrimChars(
    GetJSONString($jitterbit.response, "/id"),
    "\""
);
WriteToOperationLog("Created Salesforce lead: " + $sf.newLeadId);

Después de capturar el ID, llamar a la operación de enriquecimiento de ZoomInfo para rellenar campos adicionales (consultar Parte 7):

If(Length($sf.newLeadId) > 0,
    RunOperation("<TAG>operation:ZoomInfo - Enrich Lead</TAG>")
);

Paso 2: Actualizar el registro de cliente potencial existente

Crear una operación llamada HubSpot - Update Salesforce Lead. Agregar un paso de Transformación que se asigne a una actividad de Actualización de Salesforce dirigida al objeto Lead. La actividad de Actualización requiere el campo Id para identificar el registro:

Expresión de origen Campo de cliente potencial de Salesforce
$sf.existingLeadId Id
$hubspot.firstName FirstName
$hubspot.lastName LastName
$hubspot.email Email

Mapea solo los campos que posee la integración. Si se omiten campos de la transformación, se preservan los valores existentes en el registro de Salesforce.

Parte 7: Enriquecer leads nuevos con ZoomInfo

Después de crear un lead nuevo en Salesforce, un paso de enriquecimiento opcional utiliza ZoomInfo para completar el puesto de trabajo actual del contacto, la empresa y el número de teléfono directo. La operación de enriquecimiento llama al endpoint de enriquecimiento de ZoomInfo usando el email del lead y el nombre de la empresa como claves de búsqueda, luego actualiza el lead de Salesforce con los datos devueltos.

Para la configuración de la conexión de la API de ZoomInfo y el patrón de enrutador de recursos utilizado por este paso, consulta Enriquecer datos de contacto usando ZoomInfo.

Verificar la integración

  1. En HubSpot, abre el formulario que estás sincronizando y envía una entrada de prueba con una dirección de email única que no exista en Salesforce. Ejecuta HubSpot - Fetch Form Submissions manualmente y revisa los registros de operación. Confirma que el registro muestre el recuento correcto de envíos y que HubSpot - Create Salesforce Lead se haya ejecutado para la entrada de prueba.

  2. En Salesforce, busca el registro de Lead por la dirección de email de prueba. Confirma que FirstName, LastName y Email estén completados y que LeadSource esté configurado en HubSpot.

  3. Envía una segunda entrada de prueba usando la misma dirección de email. Ejecuta la operación de obtención nuevamente y confirma que HubSpot - Update Salesforce Lead se haya ejecutado en lugar de la operación de creación, y que el lead de Salesforce existente se haya actualizado en lugar de duplicarse.

  4. Prueba el caso de envío vacío ejecutando la operación contra un formulario sin envíos. Confirma que los registros de operación muestren "No HubSpot submissions found" y que no se hayan llamado operaciones de Salesforce.

  5. Para probar un envío sin el campo de email, agrega temporalmente una entrada de prueba sin email. Confirma que el registro muestre "Submission missing email field. Skipping." y que no se hayan ejecutado operaciones de Salesforce para ese registro.

  6. Si la actividad GET devuelve un error 401, confirma que [$hubspot.access.token] esté configurado y que el token de acceso de la aplicación privada no haya expirado. Los tokens de aplicación privada de HubSpot no expiran por defecto, pero se pueden rotar. Verifica el token en la configuración de la aplicación privada de HubSpot.

  7. Si SelectNodes devuelve cero nodos a pesar de que la actividad GET devuelve datos, confirma que la transformación en Parte 2 esté iterando en el nivel results/item y que la actividad Temporary Storage Write se haya completado antes de que se ejecutara el script de envío.