Pular para o conteúdo

Eventos de ciclo de vida de grupo

O Turbo Notify envia 10 webhooks próprios quando o seu número entra ou sai de grupos ou quando o estado de um grupo muda. Todos seguem o formato group.{ação}, com a ação no passado (como em contact.name_changed).

TipoQuando
group.joinedSeu número foi adicionado a um grupo (ou criou um)
group.leftSeu número foi removido, saiu, ou o grupo foi desfeito
group.name_changedO nome do grupo mudou
group.description_changedA descrição do grupo mudou
group.picture_changedA foto do grupo mudou
group.settings_changedUma configuração mudou (announce, locked, ephemeral, parent)
group.participants_addedOutros participantes foram adicionados ao grupo
group.participants_removedOutros participantes foram removidos
group.participants_promotedParticipantes foram promovidos a admin
group.participants_demotedAdmins foram rebaixados

O data de cada evento group.* segue o mesmo padrão do data de message.*: o id público do grupo vem no primeiro nível como id (grp_{hex32}), junto com name, mais os campos padrão de contexto direction: "inbound" (eventos de grupo chegam pelo WhatsApp), channel: "whatsapp" e origin: "tn".

Os campos que indicam quem fez a ação têm duas formas: verifique qual antes de usar. participants[] e alguns *_by são objetos de pessoa ({contact_id, name, number}, podem ser nulos); os demais *_by são o telefone em dígitos (string, ex.: "5511988887777").

  • Objeto de pessoa ({contact_id, name, number}): participants[], added_by, removed_by em group.participants_removed, promoted_by, demoted_by.
  • Telefone em dígitos (string): joined_by, removed_by em group.left, e changed_by nos eventos group.name_changed, group.description_changed e group.settings_changed. group.picture_changed não traz changed_by: a mudança de foto é percebida pela comparação do hash da imagem, sem um autor identificável.

Cuidado com removed_by: ele muda de forma entre os dois eventos que o trazem. É objeto de pessoa em group.participants_removed e string em group.left. Nos campos que são string, *_by.number é undefined: use o valor diretamente.

Campo at. Os eventos que refletem uma ação real no WhatsApp (group.name_changed, group.description_changed, group.settings_changed, group.participants_added, group.participants_removed, group.participants_promoted, group.participants_demoted e group.left) trazem data.at com o momento real da ação no WhatsApp (diferente do created_at do envelope). Já group.joined e group.picture_changed não trazem at: são situações percebidas pelo Turbo Notify, sem um momento único de ação no WhatsApp. Nesses casos, vale apenas o created_at do envelope.

Exemplos

O primeiro exemplo (group.joined) mostra o envelope completo. Para encurtar, os demais mostram apenas type e data; o envelope é idêntico: todo evento group.* traz number_alias (o identificador do número dono do evento) logo abaixo de organization_id, junto com id e created_at.

group.joined

{
"id": "evt_...",
"type": "group.joined",
"organization_id": "org_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"number_alias": "support",
"number_id": "num_5f60718293a4b5c6d7e8f90a1b2c3d4e",
"created_at": "2026-05-25T10:00:00Z",
"data": {
"id": "grp_9f6f0b37c98043e5835822eeae550e77",
"name": "Grupo A",
"joined_by": "5511988887777",
"creation": false,
"initial_participants_count": 7,
"direction": "inbound",
"channel": "whatsapp",
"origin": "tn"
}
}
  • id/name são o id público (grp_{hex32}) e o nome do grupo naquele momento (o grupo é o assunto do evento).
  • group.joined não traz data.at: é a entrada no grupo percebida pelo Turbo Notify, sem um momento de ação próprio no WhatsApp; use o created_at do envelope.
  • joined_by é o número (string de dígitos) do admin que adicionou o seu número. Omitido (chave ausente, nunca null) quando o evento vem da criação do grupo pelo seu próprio número (creation=true).

group.left

{
"type": "group.left",
"data": {
"id": "grp_...",
"name": "Grupo A",
"removed_by": "5511988887777",
"reason": "removed",
"direction": "inbound",
"channel": "whatsapp",
"origin": "tn",
"at": "2026-05-25T10:01:00Z"
}
}

reason é informativo: removed (removido por um admin), left (você saiu), deleted (grupo desfeito).

group.name_changed

{
"type": "group.name_changed",
"data": {
"id": "grp_...",
"name": "Grupo A 2.0",
"old_name": "Grupo A",
"changed_by": "5511988887777",
"direction": "inbound",
"channel": "whatsapp",
"origin": "tn",
"at": "2026-05-25T10:02:00Z"
}
}

name é o nome novo (atual) do grupo; old_name é o nome anterior. Não há campo new_name: name já traz o nome novo (mesma forma de contact.name_changed).

group.description_changed

{
"type": "group.description_changed",
"data": {
"id": "grp_...",
"name": "Grupo A 2.0",
"old_description": "...",
"new_description": "...",
"changed_by": "5511988887777",
"direction": "inbound",
"channel": "whatsapp",
"origin": "tn",
"at": "2026-05-25T10:03:00Z"
}
}

group.picture_changed

Enviado apenas quando uma foto de grupo real é armazenada com sucesso no seu BYO Storage. O bloco picture segue o mesmo ciclo de vida da mídia de mensagem: kind: "available" com uma URL pré-assinada e com validade limitada (url_expires_at, cerca de 15 min) do seu bucket, nunca uma URL do WhatsApp.

{
"type": "group.picture_changed",
"data": {
"id": "grp_...",
"name": "Grupo A 2.0",
"picture": {
"kind": "available",
"url": "https://<bucket>.r2.cloudflarestorage.com/groups/.../picture.jpg?...",
"url_expires_at": "2026-05-25T10:19:00Z",
"hash": "abc123..."
},
"direction": "inbound",
"channel": "whatsapp",
"origin": "tn"
}
}

Este evento não traz data.at (use o created_at do envelope para saber quando ele foi enviado), changed_by nem picture.fetched_at: a mudança é percebida pela comparação do hash da imagem, sem um autor identificável, e a validade da URL já aparece em picture.url_expires_at. O fetched_at aparece nas duas formas de leitura de grupo: GET /v1/numbers/{ref}/groups (listagem) e GET /v1/numbers/{ref}/groups/{group_id} (detalhe). Nunca neste webhook.

Guarde o picture.hash para detectar mudanças reais e baixe a foto de novo antes que a URL pré-assinada expire (url_expires_at). Para ler a foto quando quiser, use GET /v1/numbers/{ref}/groups/{group_id}/picture, onde {ref} é o number_id do envelope deste evento (o seu número que participa do grupo, não muda) ou o alias atual dele.

Pré-requisito: BYO Storage. Este evento só é enviado quando você tem uma integração de armazenamento de objetos habilitada: o Turbo Notify não entrega links do WhatsApp. Sem armazenamento, a foto fica unavailable e nenhum group.picture_changed é enviado. Veja como em Configurar o BYO Storage.

A foto fica disponível depois. Se um grupo foi visto enquanto você não tinha armazenamento configurado (ou o grupo ainda não tinha foto) e uma foto chega ao BYO Storage mais tarde, o Turbo Notify envia o group.picture_changed automaticamente assim que a foto é salva no seu bucket.

group.settings_changed

Um evento por configuração que mudou (o WhatsApp pode enviar várias mudanças ao mesmo tempo; cada uma vira um evento).

{
"type": "group.settings_changed",
"data": {
"id": "grp_...",
"name": "Grupo A 2.0",
"setting": "announce",
"old_value": false,
"new_value": true,
"changed_by": "5511988887777",
"direction": "inbound",
"channel": "whatsapp",
"origin": "tn",
"at": "2026-05-25T10:05:00Z"
}
}

setting: announce (apenas admins enviam mensagens), locked (apenas admins editam os dados do grupo), ephemeral (temporizador em segundos para mensagens temporárias) ou parent (o grupo está vinculado a uma comunidade).

group.participants_added

Um único webhook por operação: todos os participantes adicionados juntos vêm no mesmo evento.

{
"type": "group.participants_added",
"data": {
"id": "grp_...",
"name": "Grupo A 2.0",
"participants": [
{ "contact_id": "ct_...", "number": "5511555555555" },
{ "number": "5511444444444" }
],
"added_by": {
"contact_id": "ct_...",
"number": "5511988887777"
},
"direction": "inbound",
"channel": "whatsapp",
"origin": "tn",
"at": "2026-05-25T10:06:00Z"
}
}
  • participants[] lista quem foi adicionado.
  • added_by é o admin que fez a ação. Omitido (chave ausente, nunca null) quando não foi possível identificar quem fez a ação.
  • contact_id vem preenchido quando o participante já era seu contato. O Turbo Notify não cria contatos para participantes vistos apenas nestes eventos, para proteger a privacidade deles (LGPD) e não ocupar a sua cota.

group.participants_removed

Mesma forma de added, com removed_by no lugar de added_by.

group.participants_promoted

Mesma forma, com promoted_by no lugar de added_by. Não muda o participants_count do grupo.

group.participants_demoted

Mesma forma, com demoted_by. Não muda o participants_count.

Várias mudanças ao mesmo tempo

Quando o WhatsApp informa várias mudanças de uma vez (por exemplo, nome, descrição e 5 adições na mesma atualização), o Turbo Notify envia um webhook por mudança. Assim, você filtra pelo tipo que quiser sem precisar interpretar um evento com vários formatos.

Idempotência

Em situações excepcionais, o mesmo evento pode ser entregue mais de uma vez. Cada evento traz um id único (evt_…), o mesmo em todas as tentativas de entrega: use-o como chave para eliminar duplicatas do seu lado (guarde os id recebidos e ignore qualquer nova entrega do mesmo id).