curl --request POST \
--url https://api.dialtu.com/api/v2/public/salesflow/ingest/{input_node_uuid}/batch \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"clients": [
{
"company": "ACME",
"data": {
"plan": "gold",
"source": "landing-page"
},
"email": "ana@example.com",
"external_id": "crm-1001",
"first_name": "Ana",
"last_name": "García",
"phone_number": "+525512345678",
"tags": [
{
"name": "spring-campaign"
}
]
},
{
"client_id": 8874,
"data": {
"plan": "silver"
},
"external_id": "crm-1002"
}
]
}
'import requests
url = "https://api.dialtu.com/api/v2/public/salesflow/ingest/{input_node_uuid}/batch"
payload = { "clients": [
{
"company": "ACME",
"data": {
"plan": "gold",
"source": "landing-page"
},
"email": "ana@example.com",
"external_id": "crm-1001",
"first_name": "Ana",
"last_name": "García",
"phone_number": "+525512345678",
"tags": [{ "name": "spring-campaign" }]
},
{
"client_id": 8874,
"data": { "plan": "silver" },
"external_id": "crm-1002"
}
] }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
clients: [
{
company: 'ACME',
data: {plan: 'gold', source: 'landing-page'},
email: 'ana@example.com',
external_id: 'crm-1001',
first_name: 'Ana',
last_name: 'García',
phone_number: '+525512345678',
tags: [{name: 'spring-campaign'}]
},
{client_id: 8874, data: {plan: 'silver'}, external_id: 'crm-1002'}
]
})
};
fetch('https://api.dialtu.com/api/v2/public/salesflow/ingest/{input_node_uuid}/batch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));Batch ingest clients into a pipeline
Create or update up to 500 clients in one request and place them on the
input node’s target stage (or on stage_id, if given, within the same
pipeline). The batch form of Ingest a client into a pipeline.
Each row is matched by client_id, then phone number (country-code
tolerant), then email. What happens on a match is set by on_duplicate:
update (the default) merges the row into the existing client — blank
fields never clear stored values, and the phone number is never changed;
skip leaves the client untouched but still places it; fail reports the
row. Note that the single-row endpoint defaults to not updating.
Rows succeed or fail individually — read results[] — unless
all_or_none is set, in which case any failure returns
400 INGEST_ROLLED_BACK with the same per-row detail and nothing is
written. dry_run returns the same shape without writing anything.
curl --request POST \
--url https://api.dialtu.com/api/v2/public/salesflow/ingest/{input_node_uuid}/batch \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"clients": [
{
"company": "ACME",
"data": {
"plan": "gold",
"source": "landing-page"
},
"email": "ana@example.com",
"external_id": "crm-1001",
"first_name": "Ana",
"last_name": "García",
"phone_number": "+525512345678",
"tags": [
{
"name": "spring-campaign"
}
]
},
{
"client_id": 8874,
"data": {
"plan": "silver"
},
"external_id": "crm-1002"
}
]
}
'import requests
url = "https://api.dialtu.com/api/v2/public/salesflow/ingest/{input_node_uuid}/batch"
payload = { "clients": [
{
"company": "ACME",
"data": {
"plan": "gold",
"source": "landing-page"
},
"email": "ana@example.com",
"external_id": "crm-1001",
"first_name": "Ana",
"last_name": "García",
"phone_number": "+525512345678",
"tags": [{ "name": "spring-campaign" }]
},
{
"client_id": 8874,
"data": { "plan": "silver" },
"external_id": "crm-1002"
}
] }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
clients: [
{
company: 'ACME',
data: {plan: 'gold', source: 'landing-page'},
email: 'ana@example.com',
external_id: 'crm-1001',
first_name: 'Ana',
last_name: 'García',
phone_number: '+525512345678',
tags: [{name: 'spring-campaign'}]
},
{client_id: 8874, data: {plan: 'silver'}, external_id: 'crm-1002'}
]
})
};
fetch('https://api.dialtu.com/api/v2/public/salesflow/ingest/{input_node_uuid}/batch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));Authorizations
API key created in the dashboard under Settings → API Keys. Send it as Authorization: Bearer pk_....
Path Parameters
UUID of the pipeline's API input node. Copy it from the input node's settings in the Salesflow editor, or read it from List API input nodes of a pipeline.
Body
Request body for the batch ingest.
1 to 500 client rows
1 - 500 elementsShow child attributes
Show child attributes
What to do when a row matches an existing client: update = merge the row into it (default; blank fields never clear values), skip = leave it untouched but still place it on the pipeline, fail = report the row as failed
update, skip, fail If true, any failed row rolls back the whole batch (400 INGEST_ROLLED_BACK)
Validate and match without writing anything
Fire the target stage's on-arrival automations for each placed client
Override the input node's target stage; must belong to the same pipeline
Batch-wide values applied wherever a row is silent.
Show child attributes
Show child attributes
Response
OK
Success response for the batch ingest (rows may still have failed individually unless all_or_none was set).
True when nothing was written
The input node the batch was ingested through
Pipeline the clients were placed on
Stage the clients were placed on
Counts over all rows
Show child attributes
Show child attributes
One result per request row, in request order
Show child attributes
Show child attributes
Response status
"success"