Webhooks & APIOutbound

contact.merged

Emitted when two or more contacts are folded into one surviving contact

type: contact.merged

Fired after a merge commits. One or more contacts have been retired into a single survivor - the same person reached you on two channels, or two records turned out to be one.

Why this event exists

Without it, a merge would look like a deletion to your subscriber: the loser contacts simply stop existing, and their history appears to vanish. This event is the forwarding pointer that tells you where it went.

A merge does not emit contact.deleted for the retired contacts. If you only subscribe to contact.deleted you will never learn that a merge happened, and your copy of the data will drift out of sync silently.

When it fires

  • An operator merges contacts from the People page or the contact profile.
  • Wexio's merge reconciler folds duplicates together after resolving identities across channels.

It fires after the merge has committed, so a read issued when you receive it already reflects the new state.

data shape

type Data = {
  contact: {
    from: string[];  // the retired (loser) contact ids
    into: string;    // the surviving (winner) contact id
  };
  mergedAt: string;  // ISO-8601 UTC
};
  • from always has at least one entry.
  • into is never one of the from ids.

Example envelope

{
  "id": "evt_01JV4QEJX54A0E3KJ9W8R1Z4DP",
  "type": "contact.merged",
  "timestamp": "2026-04-24T12:14:22.000Z",
  "data": {
    "contact": {
      "from": ["6804f4d5a6f9f35f6e66f1a2", "6804f4d5a6f9f35f6e66f1b7"],
      "into": "6804f4d5a6f9f35f6e66f1c9"
    },
    "mergedAt": "2026-04-24T12:14:22.000Z"
  },
  "meta": {
    "eventId": "evt_01JV4QEJX54A0E3KJ9W8R1Z4DP",
    "event": "contact.merged",
    "occurredAt": "2026-04-24T12:14:22.000Z",
    "organisationId": "6640f3d5c8a0d7e8b7f20222",
    "connectionId": "6640f45ac8a0d7e8b7f2014a",
    "apiVersion": "2026-04-01",
    "attempt": 1
  }
}

How to handle it

  1. Look up your local records for every id in from.
  2. Re-point them at the record for into, or merge them into it.
  3. Keep the from ids as aliases - messages you already stored still reference them.

Notes

  • Key your own records on contactId (the merge-winner id, present on ContactPayload and ChatPayload) rather than on peopleId, and merges reconcile cleanly.
  • A winner's ContactPayload.merged.loosersIds carries the same information on subsequent contact reads.
  • Merging is plan-gated and role-gated inside Wexio, but the event shape is the same however it was triggered.

On this page