Skip to content
237 changes: 237 additions & 0 deletions descriptions/0/api.intercom.io.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8233,6 +8233,108 @@ paths:
from: 6762f0d51bb69f9f2193bb7f
into: 6762f0d51bb69f9f2193bb80
skip_duplicate_validation: true
"/contacts/merge/preview":
post:
summary: Preview a contact merge
parameters:
- name: Intercom-Version
in: header
schema:
"$ref": "#/components/schemas/intercom_version"
tags:
- Contacts
operationId: PreviewMergeContact
description: |
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](/docs/references/preview/rest-api/api.intercom.io/contacts/mergecontact).

- 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. |
responses:
'200':
description: successful
content:
application/json:
examples:
allowed:
summary: Merge allowed
value:
allowed: true
summary:
attribute_changes:
attributes:
- field: name
outcome: adopted
from_value: Jo
new_into_value: Jo
- field: companies
outcome: merged
from_value:
- Beta
into_value:
- Acme
new_into_value:
- Acme
- Beta
- field: phone
outcome: discarded
from_value: "+1555"
into_value: "+1999"
new_into_value: "+1999"
total_count: 3
reassignments:
conversations: 14
tags: 3
notes: 2
blocked:
summary: Merge not allowed
value:
allowed: false
reasons:
- code: no_shared_identifier
message: These contacts don't share a common identifier (email, phone, or external ID), so they aren't recognised as duplicates. Set skip_duplicate_validation to true to preview the merge anyway.
schema:
"$ref": "#/components/schemas/merge_preview_response"
'401':
description: Unauthorized
content:
application/json:
examples:
Unauthorized:
value:
type: error.list
request_id: ff328c7c-6140-48eb-84dd-bb8960b66cd0
errors:
- code: unauthorized
message: Access Token Invalid
schema:
"$ref": "#/components/schemas/error"
requestBody:
content:
application/json:
schema:
"$ref": "#/components/schemas/merge_preview_request"
examples:
allowed:
summary: successful
value:
from: 6762f0d51bb69f9f2193bb7f
into: 6762f0d51bb69f9f2193bb80
"/contacts/search":
post:
summary: Search contacts
Expand Down Expand Up @@ -34635,6 +34737,141 @@ components:
description: Set to `true` to merge two contacts that are not duplicates
(they share no matching email or phone).
example: true
merge_preview_request:
description: Preview a contact merge.
type: object
title: Merge preview request
required:
- from
- into
properties:
from:
type: string
description: The unique identifier for the contact to merge away from. Must be a lead.
example: 6762f0d51bb69f9f2193bb7f
into:
type: string
description: The unique identifier for the contact to merge into. Must be a user.
example: 6762f0d51bb69f9f2193bb80
skip_duplicate_validation:
type: boolean
default: false
description: When true, previews the merge even if the contacts don't share a common identifier. Defaults to false.
merge_preview_response:
title: Merge preview response
description: The result of a merge preview. Either the merge is allowed (with a summary of the changes) or it is not (with reasons).
oneOf:
- "$ref": "#/components/schemas/merge_preview_allowed"
- "$ref": "#/components/schemas/merge_preview_blocked"
merge_preview_allowed:
title: Merge preview allowed
type: object
description: Returned when the merge is allowed.
properties:
allowed:
type: boolean
enum:
- true
description: Always true. The merge is allowed.
summary:
"$ref": "#/components/schemas/merge_preview_summary"
merge_preview_blocked:
title: Merge preview not allowed
type: object
description: Returned when the merge is not allowed.
properties:
allowed:
type: boolean
enum:
- false
description: Always false. The merge is not allowed.
reasons:
type: array
description: One or more reasons the merge is not allowed.
items:
"$ref": "#/components/schemas/merge_preview_reason"
merge_preview_reason:
title: Merge preview reason
type: object
description: A reason a merge is not allowed.
properties:
code:
type: string
description: 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
message:
type: string
description: A human-readable explanation. Display this to people; do not match on it, as the wording may change.
merge_preview_summary:
title: Merge preview summary
type: object
description: A summary of the changes the merge would make to the surviving contact.
properties:
attribute_changes:
"$ref": "#/components/schemas/merge_preview_attribute_changes"
reassignments:
"$ref": "#/components/schemas/merge_preview_reassignments"
merge_preview_attribute_changes:
title: Merge preview attribute changes
type: object
description: The attribute changes the merge would make to the surviving contact.
properties:
attributes:
type: array
description: The individual attribute changes. Capped at 50 items; total_count reflects the full number of changes.
items:
"$ref": "#/components/schemas/merge_preview_attribute_change"
total_count:
type: integer
description: The total number of attribute changes detected, which may exceed the number of items in attributes.
example: 3
merge_preview_attribute_change:
title: Merge preview attribute change
type: object
description: A single attribute change on the surviving contact.
properties:
field:
type: string
description: The contact field that would change.
example: name
outcome:
type: string
description: 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
from_value:
nullable: true
description: The source contact's value. Omitted when null. May be a string, array, or object depending on the field.
into_value:
nullable: true
description: The target contact's value. Omitted when null. May be a string, array, or object depending on the field.
new_into_value:
nullable: true
description: The resulting value on the surviving contact. Always present; may be null. May be a string, array, or object depending on the field.
merge_preview_reassignments:
title: Merge preview reassignments
type: object
description: The number of records that would be reassigned to the surviving contact, by type. Only types with reassignments are included.
properties:
conversations:
type: integer
description: 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
tags:
type: integer
description: The number of tags that would be reassigned.
example: 3
notes:
type: integer
description: The number of notes that would be reassigned.
example: 2
merge_conversations_request:
title: Merge Conversations Request
type: object
Expand Down