KasarKasar Docs
API Reference

Duplicates

Detect and merge duplicate records. Scan for matches by email, phone, LinkedIn, or name and consolidate them into a single master record.

The duplicates endpoint provides two operations: detecting potential duplicate records and merging confirmed duplicates. Both operations require admin privileges.

Both actions on this endpoint are restricted to admin users. Non-admin tokens receive a 403 error.

Detect Duplicates

POST /api/v1/duplicates

Scans records for potential duplicates based on matching criteria.

Request Body

{
  "action": "detect",
  "object_name": "contacts",
  "fields": ["email", "phone"],
  "limit": 100
}
FieldTypeRequiredDefaultDescription
actionstringYesMust be "detect"
object_namestringYesThe object to scan (e.g. contacts, companies)
fieldsstring[]Noall match fieldsRestrict matching to specific fields. Accepted values: email, phone, linkedin, name.
limitintegerNo50Maximum number of duplicate groups to return

Matching Rules

The detection engine scans up to 5000 records and matches on the following criteria (all comparisons are exact, case-insensitive):

Match FieldDescription
emailMatches on any email in the record's email fields
phoneMatches on normalized phone numbers
linkedinMatches on LinkedIn profile URL or vanity name
nameMatches on first name + last name (or company name)

Example Request

curl -X POST "https://kasar.app/api/v1/duplicates" \
  -H "Authorization: Bearer ksr_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{
    "action": "detect",
    "object_name": "contacts",
    "fields": ["email", "name"],
    "limit": 50
  }'

Response

{
  "duplicate_groups": [
    {
      "records": [
        {
          "id": "550e8400-...",
          "first_name": "Alice",
          "last_name": "Martin",
          "email": "alice@example.com",
          "created_at": "2025-01-15T10:30:00Z"
        },
        {
          "id": "660f9511-...",
          "first_name": "Alice",
          "last_name": "Martin",
          "email": "alice@example.com",
          "created_at": "2025-02-20T14:00:00Z"
        }
      ],
      "match_reason": "email"
    }
  ],
  "total_groups": 1,
  "records_scanned": 3420
}
FieldTypeDescription
duplicate_groupsobject[]Array of groups, each containing matching records
duplicate_groups[].recordsobject[]The records that match each other
duplicate_groups[].match_reasonstringThe field that triggered the match (e.g. email, phone, name)
total_groupsintegerTotal number of duplicate groups found
records_scannedintegerNumber of records that were scanned

Merge Duplicates

POST /api/v1/duplicates

Merges one or more duplicate records into a master record. All relations (BELONGS_TO_ONE foreign keys and MANY_TO_MANY junction entries) are re-linked to the master record before the duplicates are deleted.

Request Body

{
  "action": "merge",
  "object_name": "contacts",
  "master_id": "550e8400-...",
  "duplicate_ids": ["660f9511-..."],
  "merge_strategy": "fill_blanks"
}
FieldTypeRequiredDefaultDescription
actionstringYesMust be "merge"
object_namestringYesThe object containing the records
master_idUUIDYesThe record to keep as the canonical version
duplicate_idsUUID[]YesRecords to merge into the master and delete
merge_strategystringNokeep_masterHow to handle conflicting field values

Merge Strategies

StrategyDescription
keep_masterKeep all field values from the master record. Duplicate values are discarded. This is the default.
fill_blanksFor each field, if the master has a blank/null value, fill it with the value from the duplicate. Non-blank master fields are preserved.

Example Request

curl -X POST "https://kasar.app/api/v1/duplicates" \
  -H "Authorization: Bearer ksr_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{
    "action": "merge",
    "object_name": "contacts",
    "master_id": "550e8400-e29b-41d4-a716-446655440000",
    "duplicate_ids": ["660f9511-f3ac-52e5-b827-557766551111"],
    "merge_strategy": "fill_blanks"
  }'

Response

{
  "master_id": "550e8400-e29b-41d4-a716-446655440000",
  "duplicates_deleted": 1,
  "strategy": "fill_blanks"
}
FieldTypeDescription
master_idUUIDThe ID of the surviving master record
duplicates_deletedintegerNumber of duplicate records that were deleted
strategystringThe merge strategy that was applied

What Happens During a Merge

  1. Field values are resolved according to the chosen strategy.
  2. BELONGS_TO_ONE relations: Any records pointing to a duplicate via a foreign key are updated to point to the master instead.
  3. MANY_TO_MANY junctions: Junction table entries referencing duplicates are re-linked to the master. If a junction already exists for the master, the duplicate entry is removed to avoid conflicts.
  4. Duplicate records are permanently deleted.

The merge operation is atomic. If any step fails, the entire operation is rolled back and no data is modified.

Error Responses

StatusCodeDescription
400INVALID_OBJECTThe object name does not exist
400VALIDATION_ERRORInvalid action, missing required fields, or master_id appears in duplicate_ids
403PERMISSION_DENIEDToken does not belong to an admin user
404RECORD_NOT_FOUNDThe master record or one of the duplicate records was not found

On this page