# Preview a contact merge

Preview the result of merging one contact into another without applying the merge. This is a read-only dry run: it reports whether the merge is allowed and, if so, exactly what would change, without modifying any data.

Send the same from (a lead) and into (a user) contact IDs you would pass to Merge a lead and a user.

- When allowed is true, the response contains a summary: every attribute change (with the resulting value on the surviving contact) and the number of conversations, notes, and tags that would be reassigned.
- When allowed is false, the response contains reasons. Each reason has a stable code you can branch on and a human-readable message you can display.

{% admonition type="warning" name="Previewing non-duplicate contacts" %}
By default a merge requires the two contacts to share an identifier (email, phone, or external ID). Set skip_duplicate_validation to true to preview a merge of contacts that don't — the same rule the merge endpoint enforces.
{% /admonition %}

When allowed is false, reasons[].code is one of:

| code | meaning |
| --- | --- |
| invalid_merge_role_pair | The from/into roles aren't mergeable. from must be a lead and into a user. |
| no_shared_identifier | The contacts share no email, phone, or external ID. Set skip_duplicate_validation to preview anyway. |
| facebook_user | Facebook contacts can't be merged. |
| external_lead_channel_not_allowed | The source is an external-channel lead that isn't eligible for merging. |
| mailing_list | Contacts created from a mailing list can't be merged. |

Endpoint: POST /contacts/merge/preview
Version: Preview
Security: bearerAuth

## Header parameters:

  - `Intercom-Version` (string)
    Intercom API version.By default, it's equal to the version set in the app package.
    Enum: "1.0", "1.1", "1.2", "1.3", "1.4", "2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13", "2.14", "2.15", "Preview"

## Request fields (application/json):

  - `from` (string, required)
    The unique identifier for the contact to merge away from. Must be a lead.
    Example: "6762f0d51bb69f9f2193bb7f"

  - `into` (string, required)
    The unique identifier for the contact to merge into. Must be a user.
    Example: "6762f0d51bb69f9f2193bb80"

  - `skip_duplicate_validation` (boolean)
    When true, previews the merge even if the contacts don't share a common identifier. Defaults to false.

## Response 200 fields (application/json):

  - `body` (Merge preview allowed (object) or Merge preview not allowed (object)) — one of:
    - Merge preview allowed:
      - `allowed` (boolean)
        Always true. The merge is allowed.
        Enum: true
      - `summary` (object)
        A summary of the changes the merge would make to the surviving contact.
      - `summary.attribute_changes` (object)
        The attribute changes the merge would make to the surviving contact.
      - `summary.attribute_changes.attributes` (array)
        The individual attribute changes. Capped at 50 items; total_count reflects the full number of changes.
      - `summary.attribute_changes.attributes.field` (string)
        The contact field that would change.
        Example: "name"
      - `summary.attribute_changes.attributes.outcome` (string)
        How the value is resolved. adopted = the source's value is taken; discarded = the source's value is dropped and the target's kept; merged = the two values are combined.
        Enum: "adopted", "discarded", "merged"
      - `summary.attribute_changes.attributes.from_value` (any,null)
        The source contact's value. Omitted when null. May be a string, array, or object depending on the field.
      - `summary.attribute_changes.attributes.into_value` (any,null)
        The target contact's value. Omitted when null. May be a string, array, or object depending on the field.
      - `summary.attribute_changes.attributes.new_into_value` (any,null)
        The resulting value on the surviving contact. Always present; may be null. May be a string, array, or object depending on the field.
      - `summary.attribute_changes.total_count` (integer)
        The total number of attribute changes detected, which may exceed the number of items in attributes.
        Example: 3
      - `summary.reassignments` (object)
        The number of records that would be reassigned to the surviving contact, by type. Only types with reassignments are included.
      - `summary.reassignments.conversations` (integer)
        The number of distinct conversations that would be reassigned to the surviving contact, counting both conversations the contact owns and conversations it participates in.
        Example: 14
      - `summary.reassignments.tags` (integer)
        The number of tags that would be reassigned.
        Example: 3
      - `summary.reassignments.notes` (integer)
        The number of notes that would be reassigned.
        Example: 2
    - Merge preview not allowed:
      - `allowed` (boolean)
        Always false. The merge is not allowed.
        Enum: false
      - `reasons` (array)
        One or more reasons the merge is not allowed.
      - `reasons.code` (string)
        A stable code identifying the reason. Branch on this value.
        Enum: "invalid_merge_role_pair", "no_shared_identifier", "facebook_user", "external_lead_channel_not_allowed", "mailing_list"
      - `reasons.message` (string)
        A human-readable explanation. Display this to people; do not match on it, as the wording may change.

## Response 401 fields (application/json):

  - `type` (string, required)
    The type is error.list
    Example: "error.list"

  - `request_id` (string,null)
    Example: "f93ecfa8-d08a-4325-8694-89aeb89c8f85"

  - `errors` (array, required)
    An array of one or more error objects

  - `errors.code` (string, required)
    A string indicating the kind of error, used to further qualify the HTTP response code
    Example: "unauthorized"

  - `errors.message` (string,null)
    Optional. Human readable description of the error.
    Example: "Access Token Invalid"

  - `errors.field` (string,null)
    Optional. Used to identify a particular field or query parameter that was in error.
    Example: "email"


