> ## Documentation Index
> Fetch the complete documentation index at: https://help.ciarem.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Catálogo de eventos

> Cada tipo de evento de webhook que a Ciarem envia, quando ele dispara e o corpo exato que ele carrega.

## O envelope

Todo evento tem o mesmo formato externo. Só `data` muda de um tipo para outro.

```json theme={null}
{
  "id": "evt_…",
  "type": "contact.created",
  "api_version": "v1",
  "created_at": "2026-10-09T15:04:05.123456Z",
  "data": { }
}
```

| Campo | Tipo | |
| - | - | - |
| `id` | string | Id único do evento. Ele continua o mesmo entre as novas tentativas e quando você envia uma entrega novamente, então é o valor a usar para remover duplicados. |
| `type` | string | O tipo do evento, um dos da lista abaixo. |
| `api_version` | string | Sempre `v1` hoje. |
| `created_at` | string | Quando o evento aconteceu na Ciarem. ISO 8601, UTC, terminando em `Z`. |
| `data` | object | Os detalhes do evento. |

## Todos os tipos de evento

| `type` | Dispara quando | `data` carrega |
| - | - | - |
| `contact.created` | Um contato é adicionado, por qualquer meio | O contato completo |
| `contact.updated` | Os campos ou as propriedades personalizadas de um contato mudam | O contato completo e o que mudou |
| `contact.deleted` | Um contato é excluído | O id do contato |
| `contact.merged` | Dois contatos são mesclados em um | O contato que permanece e o id que foi mesclado nele |
| `contact.funnel_stage.changed` | Um contato passa para outra etapa do funil | O contato completo e a etapa anterior |
| `contact.owner.changed` | O proprietário de um contato muda | O contato completo e o proprietário anterior |
| `conversation.created` | Uma nova conversa começa | Os ids da conversa, do contato e do canal |
| `conversation.assigned` | Uma conversa é atribuída a um colega | Os mesmos ids, mais a quem ela foi atribuída |
| `conversation.closed` | Uma conversa é resolvida | Os ids da conversa, do contato e do canal |
| `messages.inbound` | Um cliente envia uma mensagem | Os ids da conversa, do contato e do canal |
| `whatsapp_flow.completed` | Um cliente envia um [formulário do WhatsApp](https://help.ciarem.ai/pt/channels/whatsapp-forms.md) | O formulário, o contato, as respostas e o que a Ciarem salvou |

Os eventos de contato carregam o **contato inteiro**, então a maioria das integrações nunca precisa chamar a API de volta. Os eventos de conversa e de mensagem carregam **apenas ids**: leia a conversa ou as mensagens dela pela [API](https://help.ciarem.ai/pt/api-reference/overview) quando precisar do conteúdo.

> [!NOTE]
>
> Novos tipos de evento são adicionados com o tempo. Um endpoint inscrito em **todos os eventos** começa a recebê-los automaticamente. Responda `200` a qualquer `type` que você não trata.

## O objeto contato

Os eventos de contato incluem um objeto `contact` com os mesmos campos de `GET /v1/contacts/{id}`:

```json theme={null}
{
  "id": "cnt_…",
  "first_name": "Ana",
  "last_name": "García",
  "email": "ana@example.com",
  "phone": "+5215550100",
  "country": "MX",
  "city": "Ciudad de México",
  "instagram": null,
  "messenger": null,
  "whatsapp_username": null,
  "origin": "MANUAL",
  "sub_origin_id": null,
  "whatsapp_status": "verified",
  "marketing_opt_out": false,
  "funnel_stage_id": "stg_…",
  "owner_id": null,
  "properties": {
    "custom_budget": {
      "property_id": "prp_…",
      "kind": "NUMBER",
      "value_text": null,
      "value_number": 5000,
      "value_bool": null,
      "value_date": null,
      "value_json": null
    }
  },
  "last_contacted_at": null,
  "created_at": "2026-01-15T14:30:00Z",
  "updated_at": "2026-01-15T14:30:00Z"
}
```

Três coisas para saber:

* **`properties`** guarda suas propriedades personalizadas, indexadas pela chave da propriedade. Leia `kind` para saber qual campo `value_*` guarda o valor.
* **As propriedades de arquivo ficam de fora.** O link de download de um arquivo é temporário e expiraria antes de uma nova tentativa de entrega chegar. Leia o contato pela API para obter um link novo.
* **O contato é uma foto tirada quando a Ciarem prepara o evento**, um instante depois da mudança. Se o contato mudou duas vezes em sequência rápida, os dois eventos podem mostrar o estado mais recente. Uma nova tentativa envia a mesma foto de novo, não uma nova.

## Eventos de contato

### contact.created

Um contato foi adicionado: por um colega, por uma importação, pela API, por uma integração como o HubSpot, ou porque uma pessoa nova escreveu por um canal.

```json theme={null}
{
  "id": "evt_…",
  "type": "contact.created",
  "api_version": "v1",
  "created_at": "2026-10-09T15:04:05.123456Z",
  "data": {
    "contact": { "id": "cnt_…", "first_name": "Ana", "…": "…" }
  }
}
```

### contact.updated

Os campos próprios de um contato (nome, email, telefone, cidade e assim por diante) ou uma das suas propriedades personalizadas mudaram.

```json theme={null}
{
  "id": "evt_…",
  "type": "contact.updated",
  "api_version": "v1",
  "created_at": "2026-10-09T15:04:05.123456Z",
  "data": {
    "contact": { "id": "cnt_…", "first_name": "Ana María", "…": "…" },
    "changed_fields": ["first_name"]
  }
}
```

`changed_fields` lista o que mudou:

* Um campo simples aparece pelo nome: `"first_name"`, `"email"`.
* Uma propriedade personalizada aparece como `properties.<key>`: `"properties.custom_budget"`. Cada propriedade personalizada que muda envia **seu próprio** evento `contact.updated`.

As mudanças de etapa do funil e de proprietário **não** são informadas aqui. Elas têm seus próprios eventos, abaixo. Uma edição que muda um nome, a etapa e o proprietário de uma vez envia três eventos: `contact.updated`, `contact.funnel_stage.changed` e `contact.owner.changed`.

### contact.deleted

Um contato foi excluído. O contato não existe mais, então só o id dele é enviado.

```json theme={null}
{
  "id": "evt_…",
  "type": "contact.deleted",
  "api_version": "v1",
  "created_at": "2026-10-09T15:04:05.123456Z",
  "data": {
    "contact_id": "cnt_…"
  }
}
```

### contact.merged

Dois contatos foram mesclados. `contact` é o que permanece, com o resultado da mesclagem. `merged_contact_id` é o contato que foi incorporado a ele e não existe mais por conta própria: atualize os registros do seu lado que ainda apontam para ele.

```json theme={null}
{
  "id": "evt_…",
  "type": "contact.merged",
  "api_version": "v1",
  "created_at": "2026-10-09T15:04:05.123456Z",
  "data": {
    "contact": { "id": "cnt_…", "…": "…" },
    "merged_contact_id": "cnt_…"
  }
}
```

### contact.funnel\_stage.changed

Um contato passou para outra etapa do funil, seja porque um colega o moveu ou porque o agente de IA o moveu. A nova etapa é `contact.funnel_stage_id`; a que ele deixou é `previous_funnel_stage_id`. Converta os ids de etapa em nomes com `GET /v1/funnel-stages`.

```json theme={null}
{
  "id": "evt_…",
  "type": "contact.funnel_stage.changed",
  "api_version": "v1",
  "created_at": "2026-10-09T15:04:05.123456Z",
  "data": {
    "contact": { "id": "cnt_…", "funnel_stage_id": "stg_…", "…": "…" },
    "previous_funnel_stage_id": "stg_…"
  }
}
```

### contact.owner.changed

O proprietário de um contato mudou. O novo proprietário é `contact.owner_id`; o anterior é `previous_owner_id`. Qualquer um dos dois pode ser `null`, o que significa que o contato não tem, ou não tinha, proprietário.

```json theme={null}
{
  "id": "evt_…",
  "type": "contact.owner.changed",
  "api_version": "v1",
  "created_at": "2026-10-09T15:04:05.123456Z",
  "data": {
    "contact": { "id": "cnt_…", "owner_id": "mbr_…", "…": "…" },
    "previous_owner_id": null
  }
}
```

## Eventos de conversa e de mensagem

Estes quatro eventos compartilham o mesmo `data` base:

| Campo | Tipo | |
| - | - | - |
| `conversation_id` | string | A conversa. Leia-a com `GET /v1/conversations/{id}`. |
| `contact_id` | string ou null | O contato do outro lado. |
| `channel_kind` | string | `whatsapp`, `instagram`, `messenger` ou `webchat`. |
| `channel_id` | string | O canal conectado (por exemplo, qual número do WhatsApp). |

### conversation.created

Uma nova conversa começou.

```json theme={null}
{
  "id": "evt_…",
  "type": "conversation.created",
  "api_version": "v1",
  "created_at": "2026-10-09T15:04:05.123456Z",
  "data": {
    "conversation_id": "conv_…",
    "contact_id": "cnt_…",
    "channel_kind": "whatsapp",
    "channel_id": "chn_…"
  }
}
```

> [!NOTE]
>
> A Ciarem espera alguns segundos até o contato ser vinculado antes de enviar este evento, então `contact_id` está presente quase sempre. No caso raro em que ele ainda é `null`, leia a conversa pela API um pouco depois. Essa espera curta também significa que o primeiro `messages.inbound` de uma conversa pode chegar **antes** do `conversation.created` dela.

### conversation.assigned

Uma conversa foi atribuída, por um colega que a assumiu, por um administrador, pelas suas regras de atribuição automática ou pelo agente de IA ao transferi-la.

```json theme={null}
{
  "id": "evt_…",
  "type": "conversation.assigned",
  "api_version": "v1",
  "created_at": "2026-10-09T15:04:05.123456Z",
  "data": {
    "conversation_id": "conv_…",
    "contact_id": "cnt_…",
    "channel_kind": "whatsapp",
    "channel_id": "chn_…",
    "assignee_id": "mbr_…",
    "assignee": {
      "id": "mbr_…",
      "name": "Juan Lopez",
      "email": "juan@example.com"
    },
    "team_id": null,
    "strategy": "round_robin",
    "assigned_by": "system",
    "self_assigned": false,
    "url": "https://www.ciarem.ai/dashboard/inbox?c=conv_…"
  }
}
```

`assignee_id` é o colega e sempre vem preenchido. `team_id` é a equipe da conversa e pode ser `null`.

| Campo | Tipo | |
| - | - | - |
| `assignee` | objeto ou null | O `id`, `name` e `email` do colega, para que uma ferramenta sem código (um workflow do HubSpot, Zapier, Make) mostre quem recebeu o chat sem chamar a API. `name` e `email` podem ser `null`. |
| `strategy` | string | Como foi atribuída: `manual` (uma pessoa escolheu, ou a IA entregou ao colega indicado por uma regra de transferência), `round_robin` ou `random` (suas regras de atribuição), `owner` (foi para o proprietário do contato), `reassigned` (o atendente anterior não respondeu a tempo) ou `solo_admin` (nenhum atendente estava disponível, então foi para o único membro da organização, que é admin). |
| `assigned_by` | string | `system` para as regras e o agente de IA; caso contrário, o id `mbr_…` do colega que atribuiu. |
| `self_assigned` | boolean | `true` quando o colega assumiu a conversa por conta própria, por exemplo ao respondê-la. Filtre esses casos se quiser saber apenas dos chats entregues a alguém. |
| `url` | string | Abre a conversa no inbox da Ciarem. |

### conversation.closed

Uma conversa foi resolvida, seja por um colega que terminou o atendimento ou pelo agente de IA que a encerrou. O corpo é o `data` base acima.

```json theme={null}
{
  "id": "evt_…",
  "type": "conversation.closed",
  "api_version": "v1",
  "created_at": "2026-10-09T15:04:05.123456Z",
  "data": {
    "conversation_id": "conv_…",
    "contact_id": "cnt_…",
    "channel_kind": "whatsapp",
    "channel_id": "chn_…"
  }
}
```

### messages.inbound

Um cliente enviou uma mensagem. O evento diz **qual conversa** tem algo novo; ele não contém a mensagem em si.

```json theme={null}
{
  "id": "evt_…",
  "type": "messages.inbound",
  "api_version": "v1",
  "created_at": "2026-10-09T15:04:05.123456Z",
  "data": {
    "conversation_id": "conv_…",
    "contact_id": "cnt_…",
    "channel_kind": "whatsapp",
    "channel_id": "chn_…"
  }
}
```

Para ler o que foi dito, busque as mensagens da conversa:

```bash theme={null}
curl https://api.ciarem.ai/v1/conversations/conv_…/messages \
  -H "Authorization: Bearer oak_SEU_SEGREDO"
```

As mensagens que a sua equipe ou o agente de IA **enviam** não disparam um evento.

## Eventos de formulários do WhatsApp

### whatsapp\_flow\.completed

Um cliente enviou um [formulário do WhatsApp](https://help.ciarem.ai/pt/channels/whatsapp-forms.md). Dispara uma vez por envio, depois que a Ciarem salvou as respostas.

```json theme={null}
{
  "id": "evt_…",
  "type": "whatsapp_flow.completed",
  "api_version": "v1",
  "created_at": "2026-10-15T15:04:05.123456Z",
  "data": {
    "session_id": "wafs_…",
    "flow_id": "waflow_…",
    "contact_id": "cnt_…",
    "conversation_id": "conv_…",
    "answers": { "q1": "Ana", "q2": "ana@example.com" },
    "outcome": { "saved": ["contact:first_name", "contact:email"], "errors": [] }
  }
}
```

* `answers` usa os nomes internos dos campos do formulário, não o texto da pergunta. Para ler os valores por propriedade, use `outcome.saved` (os campos e propriedades do contato onde as respostas foram gravadas) e leia o contato.
* `outcome.errors` lista as respostas que não puderam ser salvas, por exemplo um email que pertence a outro contato.
* Um formulário de agendamento também traz `booking_id`, `start_at`, `end_at`, `meeting_url` e `attendee_email` em `outcome`.
* A resposta de uma pergunta de fotos ou documentos é uma lista de `{"file_name", "mime_type"}`, e `outcome.files` dá seu estado: `{"q3": {"status": "pending"}}`. O evento é enviado antes de os arquivos serem salvos. Quando a pergunta salva em uma propriedade de arquivo, os arquivos salvos chegam com o evento [`contact.updated`](#eventos-de-contato) que vem a seguir.
* `conversation_id` pode ser `null` quando o formulário foi enviado com um modelo fora de uma conversa.

## O evento de teste

Um teste enviado pelo painel ou com `POST /v1/webhook-endpoints/{id}/test` parece um evento real, com duas diferenças:

* O `id` dele começa com `evt_test_`, então você consegue distingui-lo e pular qualquer efeito real.
* Se você não escolher um tipo de evento, o `type` dele é `test` e o `data` é vazio:

```json theme={null}
{
  "id": "evt_test_…",
  "type": "test",
  "api_version": "v1",
  "created_at": "2026-10-09T15:04:05.123456Z",
  "data": {}
}
```

Quando você escolhe um tipo, o teste carrega dados de exemplo exatamente no formato de um evento real. `GET /v1/webhook-event-samples` retorna o corpo de exemplo de cada tipo, o que é útil para escrever testes do seu próprio handler.

## Compatibilidade

Os corpos dos webhooks seguem a mesma regra do restante da API: as mudanças são **aditivas**. Novos tipos de evento, novos campos dentro de `data` e novos valores em campos de texto podem aparecer a qualquer momento. Leia os campos de que você precisa, ignore o resto e confira o [changelog](https://help.ciarem.ai/pt/api-reference/changelog.md) quando algo parecer diferente.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.