Skip to main content
Usa el ingreso por lotes para sincronizar contactos desde un CRM, una exportación de hoja de cálculo, n8n o tu propio backend hacia un pipeline de Salesflow, muchos a la vez:
  • Batch ingest clients into a pipelinePOST /api/v2/public/salesflow/ingest/{input_node_uuid}/batch
  • List pipelinesGET /api/v2/public/salesflow/pipelines
  • List API input nodes of a pipelineGET /api/v2/public/salesflow/pipelines/{pipeline_id}/input-nodes
  • List stages in a pipelineGET /api/v2/public/salesflow/pipelines/{pipeline_id}/stages
Para un contacto a la vez — un formulario web, un webhook individual — usa Ingest a client into a pipeline. Ambos endpoints se dirigen a lo mismo: un nodo de entrada API.
El nodo de entrada es dueño del destino. Lo creas una vez en el editor de Salesflow (abre el pipeline → nodos de entrada → tipo API). Decide en qué etapa caen los contactos nuevos, cómo se asignan a tu equipo y el valor por defecto del lead. El endpoint por lotes añade lo que necesita una sincronización masiva: coincidencia de contactos, una política de duplicados, campos personalizados, etiquetas, un modo de prueba y un modo todo-o-nada.

Conceptos

De la clave de API al ingreso en tres llamadas

1

Encuentra el pipeline

2

Encuentra el nodo y copia su ruta de ingreso

Solo se listan los nodos de tipo API, los únicos a los que se pueden dirigir los endpoints de ingreso. Si la lista está vacía, crea uno en el editor de Salesflow.
3

(Opcional) elige otra etapa

List stages in a pipeline te da cada stage_id. Envía uno como stage_id en el lote para que los contactos caigan en una etapa distinta de la del nodo.

Un lote de principio a fin

Las filas tienen éxito o fallan de forma individual. Un 200 significa que la solicitud era válida y se procesó: lee summary para los totales y results[] para lo que pasó con cada fila, en el orden de la solicitud. external_id se devuelve tal cual, así que correlaciona por él y no por la posición en el arreglo. pipeline.status es added (tarjeta nueva), reactivated (el contacto había sido quitado del tablero y vuelve), already_active (ya estaba en el tablero: la tarjeta se queda donde está, sin duplicarse) o not_attempted (la fila falló, o fue una prueba).

Cómo se buscan los contactos

Cada fila se compara con tus contactos existentes por, en orden:
  1. client_id: exacto. Envíalo en cuanto lo conozcas; sobrevive a un cambio de teléfono o de correo.
  2. Teléfono: tolerante al código de país (ver abajo).
  3. Correo: sin distinguir mayúsculas.
Una fila que no coincide con nada se crea. Una fila cuyo teléfono coincide con un contacto y cuyo correo pertenece a otro se rechaza con conflict: escribirla pegaría datos a la persona equivocada.

Números de teléfono

Los teléfonos se normalizan a código de país + dígitos nacionales y se guardan así. Envíalos en la forma que tengas:
  • +E.164 (+525512345678) es la forma autoritativa: no se consulta nada más.
  • Dígitos nacionales + código de país (5512345678 con area_code: "52", o defaults.area_code: "52" para todo el lote): la forma recomendada para fuentes tipo CSV.
  • Dígitos internacionales sin + (525512345678) se aceptan solo cuando forman un número válido en algún país. Un número local de 9 dígitos sin código de país nunca se adivina como de otro país: falla con invalid_format.
La búsqueda tolera las formas que ya existen en tu cuenta: un +52 55 1234 5678 guardado se encuentra tanto si envías E.164, dígitos nacionales con código de país o los dígitos completos. Una regla a tener en cuenta: la unicidad del teléfono es sobre los dígitos nacionales, así que los mismos dígitos bajo dos códigos de país distintos no pueden coexistir; esa fila se reporta como conflict con conflicting_client_id apuntando al dueño.

Política de duplicados

on_duplicate decide qué hace una coincidencia:
Este valor por defecto es el contrario al del endpoint individual. El lote usa por defecto on_duplicate: "update"; Ingest a client into a pipeline usa por defecto update: false (colocar, pero no tocar). Indica la política explícitamente si mueves una integración de uno al otro.

Reglas de fusión

Una actualización es una fusión, nunca un reemplazo:
  • Solo se escriben los campos no vacíos de la fila. Un campo ausente, null o en blanco deja el valor guardado como está: no puedes vaciar un campo por este endpoint.
  • phone_number y area_code nunca cambian. El teléfono es la identidad; cámbialo en el panel.
  • timezone se escribe solo cuando la fila lo envía. Una zona inferida del teléfono o tomada de defaults.timezone aplica solo a contactos nuevos.
  • Los campos personalizados (data) se fusionan clave a clave, al estilo JSON Merge Patch. Una clave en la fila la establece; una clave con valor null la elimina; las claves que no mencionas se conservan. defaults.data se aplica primero y luego ganan las claves propias de la fila. Las claves son cadenas de hasta 100 caracteres; el objeto fusionado debe quedar por debajo de 16 KB.
  • Las etiquetas se añaden. Cada etiqueta se busca por nombre exacto y se crea si no existe (color y description aplican solo a etiquetas nuevas). Las etiquetas que alguien puso a mano nunca se quitan.

Prueba con dry_run

Envía "dry_run": true para recibir la misma respuesta — el estado, las coincidencias y los errores de cada fila — sin escribir nada. Las filas que coinciden traen además existing_client, una foto del contacto guardado antes de cualquier fusión, para mostrar una vista previa “actual → nuevo”. pipeline.status es not_attempted en todas las filas.

Todo o nada con all_or_none

Por defecto las filas buenas se guardan aunque otras fallen. Con "all_or_none": true, todas las filas se evalúan igualmente (para que veas todos los problemas de una vez) y luego, si al menos una falló, el lote completo se revierte:
details.summary y details.results tienen exactamente la forma de un cuerpo 200, así que un mismo parser sirve para ambos. Los estados describen lo que habría pasado; los ids que la reversión descartó (client_id de una fila created, client_state_id de una tarjeta added) se omiten. Corrige las filas que fallan y reenvía el lote completo.

Qué ocurre al colocar en el pipeline

Para cada fila colocada como added o reactivated:
  • Se disparan las automatizaciones de llegada de la etapa — secuencias, mensajes, lo que la etapa haga cuando llega un contacto — salvo que envíes "trigger_automations": false. Ese interruptor es para cargas históricas silenciosas; una sincronización en vivo debería dejarlo activado para que los leads importados se trabajen como cualquier otro.
  • Se aplican las reglas de asignación del nodo de entrada (estrategia y grupo), igual que para un lead que llegó por cualquier otra vía.
  • El default_lead_value del nodo se escribe en el valor del cliente si aún no tiene uno.
  • El entry_source de la tarjeta es api y su registro de entrada apunta al nodo.
Nada de lo anterior ocurre con las filas already_active: el contacto ya estaba en el tablero y su tarjeta, etapa y progreso se dejan tal cual. Volver a ingresar un contacto que está a mitad del pipeline es, por tanto, seguro: actualiza su registro (con update) y no lo mueve.

Límites y buenas prácticas

  • 500 filas por solicitud. Divide conjuntos mayores en lotes consecutivos (422 por encima del tope).
  • Síncrono. Un lote de 500 filas suele completarse en unos segundos. No lances lotes en paralelo contra el mismo nodo.
  • Reintentar es seguro, y no necesitas clave de idempotencia. Volver a enviar las mismas filas con on_duplicate: "update" converge: las filas que fueron created vuelven como updated / already_active, nada se duplica. Si una solicitud agotó el tiempo y no sabes si llegó, envíala otra vez.
  • Define defaults.area_code siempre que tu fuente tenga números nacionales. Sin código de país, un número local se rechaza en lugar de adivinarse.
  • Sé explícito con on_duplicate. update para una sincronización; skip para una importación puntual que no debe pisar datos editados a mano; fail cuando un duplicado significa que tu fuente tiene un problema.
  • Prefiere client_id en cuanto lo tengas. Guarda el client_id de cada resultado junto a tu propio registro; las filas siguientes podrán actualizar a esa persona aunque su teléfono o correo hayan cambiado de tu lado.

Conectarlo con n8n

1

Nodo HTTP Request

Método POST, URL https://api.dialtu.com + el ingest_path de List API input nodes of a pipeline.
2

Autenticación

Generic Credential TypeHeader Auth, nombre Authorization, valor Bearer pk_xxxxxxxx.
3

Cuerpo

Body Content Type JSON. Construye clients con tus nodos anteriores (un nodo Aggregate o Code convierte los ítems en un arreglo; mantente por debajo de 500 por ejecución y usa Split In Batches si hay más). Pon el id de tu propio registro en external_id.
4

Después de la llamada

Recorre results[]: guarda client_id de tu lado para las filas created / updated; enruta las filas failed por errors[0].code. Un 400 INGEST_ROLLED_BACK (solo con all_or_none) significa que nada se guardó: corrige y reenvía. Ver Errores.

No por este endpoint

Mover un contacto que ya está en el tablero no es tarea de un ingreso: usa Move a client between stages. Crear nodos de entrada API, y vaciar un campo guardado, se hace desde el panel.