Vensy Developers
Webhooks de eventos

Formato do evento

O envelope, o versionamento e exemplos reais de message.received e conversation.closed.

Todo evento chega no mesmo envelope, independente do tipo:

{
  "id": "evt_01j8x3z9f9a2e8n4qf3r6h8g1p",
  "type": "deal.stage_changed",
  "version": 1,
  "occurredAt": "2026-10-01T18:22:07.123456Z",
  "workspace": { "id": "ws_9f2a...", "slug": "acme" },
  "actor": { "type": "api_key", "id": "key_7a1b...", "name": "n8n produção" },
  "data": {
    "object": { "...snapshot no formato público...": "" },
    "previous": { "stageId": "stg_old..." }
  },
  "test": false
}
CampoDescrição
idId do evento. Estável entre tentativas e endpoints — use para deduplicar.
typeTipo do evento (ver catálogo).
versionVersão do contrato do envelope. Sempre 1 hoje.
occurredAtQuando o evento aconteceu no domínio (não quando foi entregue). Use para ordenar/desempatar — a entrega não garante ordem.
workspaceId e slug do workspace dono do evento.
actorQuem causou o evento: { type: "user" | "contact" | "automation" | "campaign" | "api_key" | "system", id?, name? }. Com type: "user", o id é o da membership do usuário no workspace (o mesmo de assignee.membershipId); com "contact", o id do contato; com "api_key", o id da chave. Sem marcação específica no caminho que originou a mudança, type é "system".
data.objectO recurso no formato público da API (o mesmo formato de contato/empresa/negócio da API do CRM; mensagem, conversa, canal e campanha têm formato próprio, novo, feito para o webhook).
data.previousSó em eventos *.updated/*_changed: os campos que mudaram, com o valor anterior. Ausente quando não se aplica.
testtrue só no evento disparado manualmente pelo botão "Testar". Omitido (equivalente a false) em eventos reais.

campo omitido ≠ campo null: trate os dois como "sem valor" ao consumir o payload; não assuma que um campo estará sempre presente.

Política de versão

Mudanças no contrato só são aditivas: um campo novo pode aparecer a qualquer momento em data.object, data.previous ou no próprio envelope, sem aviso prévio — sua integração deve ignorar campos desconhecidos. Renomear ou remover um campo existente, ou mudar o tipo de um tipo de evento, é mudança incompatível: sai como version: 2 (ou um tipo de evento novo), com um período de convivência antes de desligar o formato anterior.

Exemplo: message.received

{
  "id": "evt_01j8x40htqb3nxrqz6tftg37z2",
  "type": "message.received",
  "version": 1,
  "occurredAt": "2026-10-01T18:22:07.123456Z",
  "workspace": { "id": "ws_9f2a...", "slug": "acme" },
  "actor": { "type": "contact", "id": "cta_4f21..." },
  "data": {
    "object": {
      "id": "msg_example",
      "conversationId": "conv_example",
      "contact": {
        "id": "cta_example",
        "name": "Maria Oliveira",
        "phone": "+5511999990000"
      },
      "channel": {
        "id": "ch_example",
        "provider": "WHATSAPP",
        "name": "Vendas"
      },
      "direction": "INBOUND",
      "contentType": "TEXT",
      "text": "Olá! Gostaria de saber mais sobre o produto.",
      "media": null,
      "sendStatus": null,
      "deliveryStatus": "sent",
      "sendError": null,
      "createdAt": "2026-10-01T18:22:07.123456Z"
    }
  }
}

Uma mensagem com mídia traz media preenchido, com uma URL assinada que expira em 7 dias (ver assinatura e segurança):

"media": {
  "kind": "image",
  "mimeType": "image/jpeg",
  "size": 48213,
  "fileName": "foto.jpg",
  "url": "https://vensy.com.br/api/v1/webhook-media/ast_7f3c...?t=ws_9f2a...&exp=1738598400&sig=..."
}

Exemplo: conversation.closed

{
  "id": "evt_01j8x42n7wf9b3xqk1v5t8m6c4",
  "type": "conversation.closed",
  "version": 1,
  "occurredAt": "2026-10-01T18:40:00.000000Z",
  "workspace": { "id": "ws_9f2a...", "slug": "acme" },
  "actor": { "type": "user", "id": "mem_8a21...", "name": "Ana Souza" },
  "data": {
    "object": {
      "id": "conv_example",
      "status": "CLOSED",
      "channel": { "id": "ch_example", "provider": "WHATSAPP", "name": "Vendas" },
      "contact": {
        "id": "cta_example",
        "name": "Maria Oliveira",
        "phone": "+5511999990000"
      },
      "assignee": { "membershipId": "mem_8a21...", "name": "Ana Souza" },
      "department": { "id": "dep_example", "name": "Vendas" },
      "closureReason": "RESOLVED",
      "createdAt": "2026-10-01T18:22:07.123456Z",
      "closedAt": "2026-10-01T18:40:00.000000Z"
    }
  }
}

Nesta página