Webhooks

Chat Events

chat.created, chat.updated, chat.deleted - the lifecycle of one channel thread

A chat is one channel thread with one contact. Subscribe with CHAT_CREATED, CHAT_UPDATED, CHAT_DELETED.

If you are mirroring conversations, message events alone are usually enough - a message.inbound.created carries the full chat payload with it. Subscribe to chat events when you need thread-level changes that no message accompanies: an assignment, an archive, a rename.

chat.created

type: chat.created

A new channel thread was opened - the contact messaged for the first time on this channel, or a first-touch send created the thread.

data

type Data = {
  chat: ChatPayload;
  contact?: ContactPayload;
};

See ChatPayload and ContactPayload.

Example

{
  "id": "evt_2b3c4d5e-6f70-8192-a3b4-c5d6e7f80912",
  "type": "chat.created",
  "timestamp": "2026-09-30T17:59:58.000Z",
  "data": {
    "chat": {
      "id": "6804f4c2a6f9f35f6e66f1a1",
      "integrationId": "67f95b0126a4d1c9e3f0aa12",
      "channel": "WHATSAPP",
      "whatsappId": "wa_99887766",
      "firstName": "Alex",
      "createdAt": "2026-09-30T17:59:58.000Z",
      "conversationId": "6804f4d5a6f9f35f6e66f1c4",
      "contactId": "6804f4d5a6f9f35f6e66f1a2"
    },
    "contact": {
      "peopleId": "6804f4d5a6f9f35f6e66f1a2",
      "phoneNumber": "+15551234567",
      "firstName": "Alex",
      "contactId": "6804f4d5a6f9f35f6e66f1a2"
    }
  },
  "meta": {
    "eventId": "evt_2b3c4d5e-6f70-8192-a3b4-c5d6e7f80912",
    "event": "chat.created",
    "occurredAt": "2026-09-30T17:59:58.000Z",
    "organisationId": "6716b2f0a1c34d0012ab89ef",
    "externalId": "crmco-client-5541",
    "partnerId": "6716b1001c34d0012ab89abc",
    "apiVersion": "2026-04-01",
    "attempt": 1
  }
}

chat.updated

type: chat.updated

Something about the thread changed: the contact's display name or photo, the thread title, or its archive state.

data

type Data = {
  chat: ChatPayload;
  contact?: ContactPayload;
  previous?: Partial<ChatPayload>; // prior values of the changed fields
};

previous is populated when the emitting code supplied it. Diff against it instead of re-reading the thread.

Example - the thread was archived

{
  "id": "evt_3c4d5e6f-7081-92a3-b4c5-d6e7f8091223",
  "type": "chat.updated",
  "timestamp": "2026-09-30T18:10:00.000Z",
  "data": {
    "chat": {
      "id": "6804f4c2a6f9f35f6e66f1a1",
      "channel": "WHATSAPP",
      "firstName": "Alex",
      "archivedAt": "2026-09-30T18:10:00.000Z",
      "updatedAt": "2026-09-30T18:10:00.000Z"
    },
    "previous": { "archivedAt": null }
  },
  "meta": {
    "eventId": "evt_3c4d5e6f-7081-92a3-b4c5-d6e7f8091223",
    "event": "chat.updated",
    "occurredAt": "2026-09-30T18:10:00.000Z",
    "organisationId": "6716b2f0a1c34d0012ab89ef",
    "externalId": "crmco-client-5541",
    "partnerId": "6716b1001c34d0012ab89abc",
    "apiVersion": "2026-04-01",
    "attempt": 1
  }
}

archivedAt is null while the thread is open and an ISO timestamp once archived.

chat.deleted

type: chat.deleted

The thread was deleted. Today this happens as part of removing a contact - deleting a contact removes their threads and emits one chat.deleted per thread, just before the rows are dropped. There is no standalone "delete this thread" action that emits it.

The payload is trimmed to three identifying fields plus the delete time.

data

type Data = {
  chat: {
    id: string;
    integrationId?: string;
    channel?: "WHATSAPP" | "TELEGRAM" | "VIBER" | "INSTAGRAM" | "WEB";
  };
  deletedAt: string; // ISO-8601 UTC
};

Example

{
  "id": "evt_4d5e6f70-8192-a3b4-c5d6-e7f809122334",
  "type": "chat.deleted",
  "timestamp": "2026-09-30T18:30:00.000Z",
  "data": {
    "chat": {
      "id": "6804f4c2a6f9f35f6e66f1a1",
      "integrationId": "67f95b0126a4d1c9e3f0aa12",
      "channel": "WHATSAPP"
    },
    "deletedAt": "2026-09-30T18:30:00.000Z"
  },
  "meta": {
    "eventId": "evt_4d5e6f70-8192-a3b4-c5d6-e7f809122334",
    "event": "chat.deleted",
    "occurredAt": "2026-09-30T18:30:00.000Z",
    "organisationId": "6716b2f0a1c34d0012ab89ef",
    "externalId": "crmco-client-5541",
    "partnerId": "6716b1001c34d0012ab89abc",
    "apiVersion": "2026-04-01",
    "attempt": 1
  }
}

No contact and no identity fields on a delete. The thread's messages go with it, and you do not get a message.*.deleted per message - cascade on your side from this one event.

Because the trigger is contact removal, expect contact.deleted for the same contact around the same time. Ordering between the two is not guaranteed.

On this page