MergeLeadsAPI makes two lead identities one lead: the absorbed identity points
curl --request POST \
--url https://api.erdo.ai/v1/datasets/{datasetSlug}/leads/{leadRef}/merge \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"absorb_lead_id": "<string>",
"overwrite_columns": [
"<string>"
]
}
'import requests
url = "https://api.erdo.ai/v1/datasets/{datasetSlug}/leads/{leadRef}/merge"
payload = {
"absorb_lead_id": "<string>",
"overwrite_columns": ["<string>"]
}
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({absorb_lead_id: '<string>', overwrite_columns: ['<string>']})
};
fetch('https://api.erdo.ai/v1/datasets/{datasetSlug}/leads/{leadRef}/merge', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.erdo.ai/v1/datasets/{datasetSlug}/leads/{leadRef}/merge",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'absorb_lead_id' => '<string>',
'overwrite_columns' => [
'<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.erdo.ai/v1/datasets/{datasetSlug}/leads/{leadRef}/merge"
payload := strings.NewReader("{\n \"absorb_lead_id\": \"<string>\",\n \"overwrite_columns\": [\n \"<string>\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.erdo.ai/v1/datasets/{datasetSlug}/leads/{leadRef}/merge")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"absorb_lead_id\": \"<string>\",\n \"overwrite_columns\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.erdo.ai/v1/datasets/{datasetSlug}/leads/{leadRef}/merge")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"absorb_lead_id\": \"<string>\",\n \"overwrite_columns\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"absorbed_lead_id": "<string>",
"aliases_moved": 123,
"lead": {
"absorbed_lead_ids": [
"<string>"
],
"aliases": [
{
"created_at": "2023-11-07T05:31:56Z",
"provenance": "<string>",
"type": "<string>",
"value": "<string>"
}
],
"canonical_lead_id": "<string>",
"captures": [
{
"candidate_lead_ids": [
"<string>"
],
"conversion_id": "<string>",
"conversion_status": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"id": "<string>",
"operation_key": "<string>",
"producer": "<string>",
"resolution": "<string>",
"rows_affected": 123
}
],
"created_at": "2023-11-07T05:31:56Z",
"dataset_id": "<string>",
"dataset_slug": "<string>",
"merged_at": "2023-11-07T05:31:56Z",
"merged_by": "<string>",
"merged_into": "<string>",
"merged_into_reference": "<string>",
"reference": "<string>",
"requested_lead_id": "<string>",
"row": {}
},
"rows_combined": 123,
"state": "<string>"
}{
"code": "not_found",
"details": {},
"message": "<string>"
}API Reference
MergeLeadsAPI makes two lead identities one lead: the absorbed identity points
at the survivor, its contact evidence moves across, and the two dataset rows become one row.
There is deliberately no MCP tool for this. It is not reversible in practice, and the captures it settles are the ones where the evidence contradicts itself — a person decides, holding both leads’ evidence side by side.
A scoped API key is refused: those are per-end-user credentials, and one lead’s holder must never be able to fold another lead into it.
POST
/
v1
/
datasets
/
{datasetSlug}
/
leads
/
{leadRef}
/
merge
MergeLeadsAPI makes two lead identities one lead: the absorbed identity points
curl --request POST \
--url https://api.erdo.ai/v1/datasets/{datasetSlug}/leads/{leadRef}/merge \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"absorb_lead_id": "<string>",
"overwrite_columns": [
"<string>"
]
}
'import requests
url = "https://api.erdo.ai/v1/datasets/{datasetSlug}/leads/{leadRef}/merge"
payload = {
"absorb_lead_id": "<string>",
"overwrite_columns": ["<string>"]
}
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({absorb_lead_id: '<string>', overwrite_columns: ['<string>']})
};
fetch('https://api.erdo.ai/v1/datasets/{datasetSlug}/leads/{leadRef}/merge', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.erdo.ai/v1/datasets/{datasetSlug}/leads/{leadRef}/merge",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'absorb_lead_id' => '<string>',
'overwrite_columns' => [
'<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.erdo.ai/v1/datasets/{datasetSlug}/leads/{leadRef}/merge"
payload := strings.NewReader("{\n \"absorb_lead_id\": \"<string>\",\n \"overwrite_columns\": [\n \"<string>\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.erdo.ai/v1/datasets/{datasetSlug}/leads/{leadRef}/merge")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"absorb_lead_id\": \"<string>\",\n \"overwrite_columns\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.erdo.ai/v1/datasets/{datasetSlug}/leads/{leadRef}/merge")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"absorb_lead_id\": \"<string>\",\n \"overwrite_columns\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"absorbed_lead_id": "<string>",
"aliases_moved": 123,
"lead": {
"absorbed_lead_ids": [
"<string>"
],
"aliases": [
{
"created_at": "2023-11-07T05:31:56Z",
"provenance": "<string>",
"type": "<string>",
"value": "<string>"
}
],
"canonical_lead_id": "<string>",
"captures": [
{
"candidate_lead_ids": [
"<string>"
],
"conversion_id": "<string>",
"conversion_status": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"id": "<string>",
"operation_key": "<string>",
"producer": "<string>",
"resolution": "<string>",
"rows_affected": 123
}
],
"created_at": "2023-11-07T05:31:56Z",
"dataset_id": "<string>",
"dataset_slug": "<string>",
"merged_at": "2023-11-07T05:31:56Z",
"merged_by": "<string>",
"merged_into": "<string>",
"merged_into_reference": "<string>",
"reference": "<string>",
"requested_lead_id": "<string>",
"row": {}
},
"rows_combined": 123,
"state": "<string>"
}{
"code": "not_found",
"details": {},
"message": "<string>"
}Authorizations
An Erdo API key (erdo_api_...) or scoped token (erdo_token_...).
Response
Success response
existing so the capture receipts referencing it stay accurate.
Show child attributes
Show child attributes
the two were already one lead — which is also what a retry of an uncertain merge answers.

