- Batch ingest clients into a pipeline —
POST /api/v2/public/salesflow/ingest/{input_node_uuid}/batch - List pipelines —
GET /api/v2/public/salesflow/pipelines - List API input nodes of a pipeline —
GET /api/v2/public/salesflow/pipelines/{pipeline_id}/input-nodes - List stages in a pipeline —
GET /api/v2/public/salesflow/pipelines/{pipeline_id}/stages
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
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
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:client_id: exacto. Envíalo en cuanto lo conozcas; sobrevive a un cambio de teléfono o de correo.- Teléfono: tolerante al código de país (ver abajo).
- Correo: sin distinguir mayúsculas.
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 (
5512345678conarea_code: "52", odefaults.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 coninvalid_format.
+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:
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,
nullo en blanco deja el valor guardado como está: no puedes vaciar un campo por este endpoint. phone_numberyarea_codenunca cambian. El teléfono es la identidad; cámbialo en el panel.timezonese escribe solo cuando la fila lo envía. Una zona inferida del teléfono o tomada dedefaults.timezoneaplica 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 valornullla elimina; las claves que no mencionas se conservan.defaults.datase 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 (
colorydescriptionaplican 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 comoadded 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_valuedel nodo se escribe en el valor del cliente si aún no tiene uno. - El
entry_sourcede la tarjeta esapiy su registro de entrada apunta al nodo.
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 (
422por 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 fueroncreatedvuelven comoupdated/already_active, nada se duplica. Si una solicitud agotó el tiempo y no sabes si llegó, envíala otra vez. - Define
defaults.area_codesiempre 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.updatepara una sincronización;skippara una importación puntual que no debe pisar datos editados a mano;failcuando un duplicado significa que tu fuente tiene un problema. - Prefiere
client_iden cuanto lo tengas. Guarda elclient_idde 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 Type → Header 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.