Visão geral de grupos
Mensagens recebidas em um grupo do WhatsApp trazem o id do grupo e, quando o
nome é conhecido, o nome, e o envio para grupos usa o identificador público
grp_{hex32}.
Conceitos
Identificador público grp_
Toda referência pública a um grupo usa o formato grp_ seguido de 32 caracteres
hexadecimais, no mesmo padrão dos demais prefixos públicos
(msg_, ct_, req_, evt_).
O identificador do WhatsApp (
120363xxxxx@g.us) nunca é exposto em respostas, webhooks ou polling: apenas ogrp_{hex32}do Turbo Notify.
Campo to: três formas
O tipo de destinatário é definido pela chave presente em to, sem campo kind ou type:
- 1:1:
to: { "number": "+55..." }, o destinatário é uma pessoa. - Grupo:
to: { "group_id": "grp_..." }, o destinatário é um grupo. - Por contato:
to: { "contact_id": "ct_..." }, o telefone vem do contato registrado no Turbo Notify.
A mesma regra vale para os payloads de webhook e polling: quando
to.group_id está presente, o destinatário é o grupo.
Campo from é sempre uma pessoa
Quem escreve num grupo é sempre um participante, nunca o grupo. Portanto:
- Mensagem recebida:
fromé o participante que enviou a mensagem no grupo. - Mensagem enviada:
fromé o número do Turbo Notify que enviou a mensagem.
Em nenhum cenário from carrega um group_id.
Seu número na conversa (number_id e number_alias do envelope)
O número do Turbo Notify que participa da conversa (1:1 ou grupo, recebida ou
enviada) é identificado pelo campo number_alias do envelope do evento
("main" para o número principal ou o alias de um número extra). Para obter os
dados desse número, use GET /v1/numbers/{ref} com o number_id do envelope (o
alias é o que o número tinha na hora do evento).
// Inbound de grupo (envelope + data){ "number_alias": "main", "number_id": "num_0a1b2c3d4e5f60718293a4b5c6d7e8f9", "data": { "from": { "contact_id": "ct_...", "name": "Ana Souza", "number": "5511988887777" }, "to": { "group_id": "grp_e442553a56b14e2695f6acfd7d651b1a", "name": "TNT" } }}
// Outbound para grupo (envelope + data){ "number_alias": "main", "number_id": "num_0a1b2c3d4e5f60718293a4b5c6d7e8f9", "data": { "from": { "name": "Turbo Notify", "alias": "main", "number": "5511973117056" }, "to": { "group_id": "grp_e442553a56b14e2695f6acfd7d651b1a", "name": "TNT" } }}Para detectar mensagens de grupo, verifique a presença de to.group_id:
const isGroup = "group_id" in data.to;Recebendo mensagens de grupo
Cada mensagem recebida em um grupo é entregue como
message.received
no webhook e no polling. from é o participante que enviou; to traz o
group_id e o nome do grupo naquele momento; o seu número que participa
do grupo é identificado pelo number_alias do envelope.
Enviando para grupo
Para enviar a um grupo a partir do número principal, use POST /v1/messages. Para números extras, use POST /v1/numbers/{ref}/messages onde {ref} é o alias do número extra (ou o id dele, num_…). O campo to assume a forma { "group_id": "grp_..." }.
curl -X POST "https://api.turbonotify.com/v1/messages" \ -H "Authorization: Bearer SUA_CHAVE" \ -H "Content-Type: application/json" \ -d '{ "to": { "group_id": "grp_e442553a56b14e2695f6acfd7d651b1a" }, "content": { "text": "Bom dia, equipe" } }'await fetch('https://api.turbonotify.com/v1/messages', { method: 'POST', headers: { Authorization: 'Bearer SUA_CHAVE', 'Content-Type': 'application/json', }, body: JSON.stringify({ to: { group_id: 'grp_e442553a56b14e2695f6acfd7d651b1a' }, content: { text: 'Bom dia, equipe' }, }),});import httpx
httpx.post( "https://api.turbonotify.com/v1/messages", headers={"Authorization": "Bearer SUA_CHAVE"}, json={ "to": {"group_id": "grp_e442553a56b14e2695f6acfd7d651b1a"}, "content": {"text": "Bom dia, equipe"}, },)package main
import ( "fmt" "io" "net/http" "strings")
func main() { payload := strings.NewReader(`{"to": {"group_id": "grp_e442553a56b14e2695f6acfd7d651b1a"}, "content": {"text": "Bom dia, equipe"}}`) req, _ := http.NewRequest("POST", "https://api.turbonotify.com/v1/messages", payload) req.Header.Set("Authorization", "Bearer SUA_CHAVE") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))}<?php$url = 'https://api.turbonotify.com/v1/messages';$data = [ 'to' => ['group_id' => 'grp_e442553a56b14e2695f6acfd7d651b1a'], 'content' => ['text' => 'Bom dia, equipe'],];
$options = [ 'http' => [ 'header' => [ 'Authorization: Bearer SUA_CHAVE', 'Content-Type: application/json', ], 'method' => 'POST', 'content' => json_encode($data), ],];
$context = stream_context_create($options);$result = file_get_contents($url, false, $context);$response = json_decode($result, true);var_dump($response);?>using System.Text;using System.Text.Json;
var client = new HttpClient();client.DefaultRequestHeaders.Add("Authorization", "Bearer SUA_CHAVE");
var payload = new{ to = new { group_id = "grp_e442553a56b14e2695f6acfd7d651b1a" }, content = new { text = "Bom dia, equipe" },};var content = new StringContent( JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://api.turbonotify.com/v1/messages", content);var result = await response.Content.ReadAsStringAsync();Console.WriteLine(result);import java.net.http.*;import java.net.URI;
public class EnviarParaGrupo { public static void main(String[] args) throws Exception { var client = HttpClient.newHttpClient(); var body = """ {"to": {"group_id": "grp_e442553a56b14e2695f6acfd7d651b1a"}, "content": {"text": "Bom dia, equipe"}} """;
var request = HttpRequest.newBuilder() .uri(URI.create("https://api.turbonotify.com/v1/messages")) .header("Authorization", "Bearer SUA_CHAVE") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(body)) .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); }}O Turbo Notify localiza o grupo correspondente ao grp_{hex32} no WhatsApp e
envia a mensagem pelo número indicado em {ref}. Para 1:1, o campo to é um objeto { "number": "+5511988887777" }.
Consultando grupos
GET /v1/numbers/{ref}/groups lista os grupos observados por um número,
paginado por cursor. GET /v1/numbers/{ref}/groups/{group_id} retorna o
detalhe de um grupo específico. Os dois funcionam em qualquer plano e não
exigem o recurso groups:messages.
Escopo obrigatório: groups:read.
GET /v1/numbers/{ref}/groups?limit=20&cursor=<opaque>GET /v1/numbers/{ref}/groups/{group_id}| Parâmetro (listagem) | Tipo | Descrição |
|---|---|---|
cursor | string | Token opaco retornado em cursor pela página anterior |
limit | int | 1 a 200 (padrão 50) |
name | string | Filtro parcial pelo nome do grupo |
include_left | bool | Inclui grupos dos quais o número já saiu (padrão false) |
Cada item, tanto na listagem (data[]) quanto no detalhe, tem este formato:
{ "id": "grp_9f6f0b37c98043e5835822eeae550e77", "number_alias": "main", "name": "Grupo A", "description": "Equipe de suporte", "participants_count": 12, "is_announce_only": false, "is_locked": false, "ephemeral_seconds": null, "is_active": true, "picture": { "kind": "unavailable", "reason": "peer_has_none" }, "created_at": "2026-05-25T10:00:00Z", "updated_at": "2026-05-25T10:05:00Z"}A listagem envelopa os itens em { "data": [...], "cursor": "...", "has_more": true }.
is_active é false quando o número já saiu do grupo (só aparece na
listagem com include_left=true). picture tem o mesmo formato
usado pelo endpoint próprio da foto: veja Foto do grupo.
GET /v1/numbers/{ref}/groups/{group_id} retorna 400 invalid_group_id
quando o group_id não bate com ^grp_[0-9a-f]{32}$ (o formato é validado
antes da consulta). Um group_id bem-formado que não existe, ou que
pertence a outro número/organização, retorna 404 group_not_found.
Cota e limite de velocidade
Um envio para grupo conta como 1 destinatário no limite diário de
destinatários, não importa quantos participantes o grupo tenha. A cota de
contatos (contact.*) não é afetada por envios para grupos: grupos
nunca geram contatos.
Ciclo de vida de grupo
O Turbo Notify envia 10 webhooks próprios quando o estado do grupo muda. Consulte eventos de ciclo de vida de grupo para o catálogo completo.
Limitações
Consulte Limitações para ver o que não é oferecido pela API (criar grupos, administrar grupos e listar membros).