Merge API
Merge duplicate records in DealCloud. The SDK exposes merge_entries() (POST .../data/merge/{entryTypeId}). HTTP is via intapp-rest-client.
Overview
The Merge API allows you to:
- Merge duplicate records into a single record
- Control which values are preserved
- Automatically update references
⚠️
Merging is permanent. The source record is deleted after merge. Test carefully before production use.
merge_entries()
Merge multiple records into one:
from dealcloud_sdk import DealCloud, DealCloudConfig
config = DealCloudConfig(
siteUrl="yoursite.dealcloud.com",
clientId=12345,
clientSecret="your-secret",
)
dc = DealCloud.from_config_object(config)
# Merge losers into winner (API max 10 loser IDs per request item)
result = dc.merge_entries(
object_id="Company",
winner_entry_id=12345,
loser_entry_ids=[12346, 12347],
)Parameters
| Parameter | Type | Description |
|---|---|---|
object_id | str | int | Object API name or ID |
winner_entry_id | int | Entry that survives |
loser_entry_ids | List[int] | Entries merged into the winner (max 10 per call) |
field_overrides | dict | None | Optional fieldOverrides payload (see your site’s API contract) |
delete_losers | bool | Sent as deleteLoserEntries in the request body |
transfer_relationships | bool | Sent as transferRelationships in the request body |
overwrite_empty_values | bool | None | Query flag overwriteEmptyValues when merging two entries (per API docs) |
How merge works (typical)
- Winner preserved — the surviving
entryIdstays canonical. - Losers — merged into the winner; API behavior for references/deletes follows DealCloud’s merge rules for your site.
- Batching — if you have more than 10 losers, split into multiple
merge_entries()calls.
Field overrides
Optional JSON fieldOverrides can be passed through when your API contract defines them:
result = dc.merge_entries(
object_id="Company",
winner_entry_id=12345,
loser_entry_ids=[12346],
field_overrides={"Revenue": 1500000},
)Find Duplicates
Before merging, identify duplicates:
def find_duplicates(dc, object_id: str, match_field: str):
"""Find records with duplicate values in a field."""
data = dc.read_data(object_id, output="pandas", fields=["EntryId", match_field])
# Group by match field
duplicates = data[data.duplicated(match_field, keep=False)]
duplicates = duplicates.sort_values(match_field)
# Group into sets
groups = duplicates.groupby(match_field)["EntryId"].apply(list).to_dict()
return {k: v for k, v in groups.items() if len(v) > 1}
# Find companies with same name
dupes = find_duplicates(dc, "Company", "CompanyName")
for name, entry_ids in dupes.items():
print(f"'{name}': {entry_ids}")Automated Merge Workflow
def merge_duplicates_by_field(
dc,
object_id: str,
match_field: str,
keep_strategy: str = "oldest" # "oldest", "newest", "highest_value"
):
"""
Automatically merge records with duplicate values.
Args:
dc: DealCloud client
object_id: Object to process
match_field: Field to identify duplicates
keep_strategy: Which record to keep as target
"""
# Find duplicates
data = dc.read_data(
object_id,
output="list",
fields=["EntryId", match_field, "CreatedDate", "Revenue"]
)
# Group by match field
groups = {}
for record in data:
key = record.get(match_field)
if key:
groups.setdefault(key, []).append(record)
merged_count = 0
for key, records in groups.items():
if len(records) < 2:
continue
# Select target based on strategy
if keep_strategy == "oldest":
records.sort(key=lambda r: r.get("CreatedDate", ""))
elif keep_strategy == "newest":
records.sort(key=lambda r: r.get("CreatedDate", ""), reverse=True)
elif keep_strategy == "highest_value":
records.sort(key=lambda r: r.get("Revenue", 0) or 0, reverse=True)
winner = records[0]["EntryId"]
losers = [r["EntryId"] for r in records[1:]]
# API allows up to 10 loser IDs per request
for i in range(0, len(losers), 10):
batch = losers[i : i + 10]
dc.merge_entries(
object_id=object_id,
winner_entry_id=winner,
loser_entry_ids=batch,
)
merged_count += len(losers)
print(f"Merged {len(losers)} duplicates of '{key}' into {winner}")
return merged_count
count = merge_duplicates_by_field(dc, "Company", "CompanyName", "oldest")
print(f"Total merged: {count}")Safe Merge with Preview
def merge_with_preview(dc, object_id, target_id, source_ids):
"""Preview merge before executing."""
# Load all records
all_ids = [target_id] + source_ids
ids_str = ",".join(map(str, all_ids))
records = dc.read_data(
object_id,
output="list",
query=f"{{EntryId: {{$in: [{ids_str}]}}}}"
)
# Identify target and sources
target = next(r for r in records if r["EntryId"] == target_id)
sources = [r for r in records if r["EntryId"] in source_ids]
print("=== MERGE PREVIEW ===")
print(f"\nTarget (keeping): Entry {target_id}")
for k, v in target.items():
if v is not None:
print(f" {k}: {v}")
print(f"\nSources (merging {len(sources)}):")
for s in sources:
print(f" Entry {s['EntryId']}")
confirm = input("\nProceed with merge? (yes/no): ")
if confirm.lower() == "yes":
dc.merge_entries(
object_id=object_id,
winner_entry_id=target_id,
loser_entry_ids=source_ids,
)
print("Merge completed!")
else:
print("Merge cancelled.")
merge_with_preview(dc, "Company", 12345, [12346, 12347])Error Handling
def safe_merge(dc, object_id, target_id, source_ids):
"""Merge with error handling."""
# Validate records exist
all_ids = [target_id] + source_ids
ids_str = ",".join(map(str, all_ids))
records = dc.read_data(
object_id,
output="list",
fields=["EntryId"],
query=f"{{EntryId: {{$in: [{ids_str}]}}}}"
)
found_ids = {r["EntryId"] for r in records}
missing = set(all_ids) - found_ids
if missing:
raise ValueError(f"Records not found: {missing}")
try:
dc.merge_entries(
object_id=object_id,
winner_entry_id=target_id,
loser_entry_ids=source_ids,
)
return {"success": True, "merged": len(source_ids)}
except Exception as e:
return {"success": False, "error": str(e)}
result = safe_merge(dc, "Company", 12345, [12346])Best Practices
- Preview before merge - Review what will be merged
- Backup first - Use Backups API before large merge operations
- Test with few records - Validate logic before bulk merges
- Log merge operations - Keep record of what was merged
- Handle references carefully - Understand relationship implications
Related
- Delete Data - Deleting records
- Backups API - Backup before merge