Mensagens
Tudo o que você faz com mensagens pela API aparece no chat do painel como se a equipe tivesse feito: o envio, a edição, a reação e a mensagem apagada.
| Ação | Endpoint |
|---|---|
| Enviar texto e/ou mídia (para contatos e grupos) | POST /messages |
| Consultar uma mensagem e o status de entrega | GET /messages/{message_id} |
| Editar o texto de uma mensagem enviada (até 15 min) | PATCH /messages/{message_id} |
| Apagar para todos (até 48 h) ou só no painel | DELETE /messages/{message_id} |
| Reagir com um emoji | POST /messages/{message_id}/reaction |
| Ler o histórico de uma conversa | GET /contacts/{contact_id}/messages |
O objeto mensagem
Seção intitulada “O objeto mensagem”{ "id": "8d66a526-230c-481a-86e5-be09b6bbb952", "object": "message", "contact_id": "3f1c2b9a-7d4e-4c55-8a0e-1b2c3d4e5f60", "channel_id": "d781e759-4047-4c35-bfcd-eae8c666369a", "direction": "outbound", "type": "document", "text": "Segue o boleto.", "media": { "url": "https://exemplo.com/boleto-1234.pdf", "mime_type": "application/pdf", "filename": "boleto-1234.pdf" }, "status": "delivered", "error": null, "reply_to_id": null, "reaction": null, "sender_name": null, "transcript": null, "created_at": "2026-11-11T14:40:31Z", "edited_at": null}| Campo | Tipo | Descrição |
|---|---|---|
id |
UUID | ID da mensagem. |
object |
string | Sempre message. |
contact_id |
UUID ou null |
Contato (conversa) da mensagem. Em grupos, é o id do grupo. |
channel_id |
UUID ou null |
Canal por onde a mensagem passou. |
direction |
string | inbound (o contato mandou) ou outbound (a empresa mandou: equipe, IA, campanha, Agenda ou API). |
type |
string | Valores comuns: text, image, video, audio, document e sticker. Trate valores desconhecidos como mídia genérica. |
text |
string ou null |
Texto ou legenda. Mídia sem legenda pode trazer um rótulo como “📷 Foto”. Mensagem apagada para todos vira “Mensagem apagada”. |
media |
objeto ou null |
Arquivo anexado: url, mime_type e filename. |
status |
string | queued, sent, delivered, read ou failed. |
error |
string ou null |
Motivo da falha quando status é failed. |
reply_to_id |
UUID ou null |
Mensagem citada (quando é uma resposta). |
reaction |
string ou null |
Reação enviada por nós a esta mensagem (ex.: 👍). Veja Reagir a uma mensagem. |
sender_name |
string ou null |
Em grupos, quem mandou. |
transcript |
string ou null |
Transcrição de áudio, quando houver. |
created_at |
data | Quando a mensagem foi criada. |
edited_at |
data ou null |
Quando foi editada, se foi. |
Status de entrega
Seção intitulada “Status de entrega”As mensagens enviadas (outbound) passam por:
queued → sent → delivered → read ↘ failed| Status | Significado |
|---|---|
queued |
Na fila para sair. |
sent |
Saiu da TopTalking para o WhatsApp. |
delivered |
Chegou no celular do contato. |
read |
O contato leu (se ele não desativou a confirmação de leitura). |
failed |
Não foi possível entregar; veja error. |
Para acompanhar sem ficar consultando, use o webhook message.status_updated.
Enviar mensagem
Seção intitulada “Enviar mensagem”POST/v1/messages
Envia texto e/ou mídia pelo WhatsApp (ou responde no Chat do site, se a conversa for de lá). A mensagem aparece no chat do painel como qualquer outra. É o endpoint para avisos transacionais (pedido, boleto, lembrete) e para responder conversas.
Destino: informe to (telefone) ou contact_id. Se o telefone ainda não for contato, o contato é criado e a conversa aparece na caixa de entrada do painel. Para grupos, use o id do grupo em contact_id (veja Grupos).
Canal usado, nesta ordem:
- o
channel_idenviado, se houver; - o canal da conversa, se estiver conectado;
- o WhatsApp principal conectado.
| Parâmetro | Onde | Tipo | Obrigatório | Descrição |
|---|---|---|---|---|
to |
corpo | string | to ou contact_id |
Telefone com DDI e DDD. Formatação é ignorada; números brasileiros sem 55 recebem o 55. |
contact_id |
corpo | UUID | to ou contact_id |
Conversa de destino. Também aceita o id de um grupo (veja GET /groups). |
text |
corpo | string | text e/ou media |
Até 4096 caracteres. Aceita a formatação do WhatsApp: *negrito*, _itálico_, ~tachado~. Com media, vira a legenda. |
media |
corpo | objeto | text e/ou media |
Arquivo a enviar (veja abaixo). |
channel_id |
corpo | UUID | não | Força o envio por este canal. |
reply_to_id |
corpo | UUID | não | Responde (cita) esta mensagem da conversa. |
contact_name |
corpo | string | não | Nome usado se o contato ainda não existir. |
Idempotency-Key |
cabeçalho | string | não (recomendado) | Impede que uma retentativa mande a mensagem duas vezes. Veja Idempotência. |
Objeto media:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
url |
string | sim | URL pública HTTPS do arquivo (acessível sem login). |
type |
string | sim | image, video, audio ou document. |
filename |
string | não | Nome exibido (documentos). Padrão: o nome na URL. |
mime_type |
string | não | Tipo do arquivo (ex.: application/pdf). Padrão: deduzido pela extensão. |
voice_note |
booleano | não | Com type: "audio", envia como nota de voz (sem legenda). Padrão: false. |
# Texto para um telefonecurl https://platform.toptalking.com.br/v1/messages \ -H "Authorization: Bearer $TOPTALKING_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: pedido-1234-saiu" \ -d '{ "to": "5511999998888", "text": "Olá, Maria! Seu pedido *#1234* saiu para entrega." }'
# Documento com legenda para um contato existentecurl https://platform.toptalking.com.br/v1/messages \ -H "Authorization: Bearer $TOPTALKING_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: boleto-1234" \ -d '{ "contact_id": "3f1c2b9a-7d4e-4c55-8a0e-1b2c3d4e5f60", "text": "Segue o boleto.", "media": { "url": "https://exemplo.com/boleto-1234.pdf", "type": "document", "filename": "boleto-1234.pdf" } }'async function enviarMensagem(corpo, idempotencyKey) { const res = await fetch('https://platform.toptalking.com.br/v1/messages', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOPTALKING_API_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': idempotencyKey, }, body: JSON.stringify(corpo), }); const body = await res.json(); if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`); return body;}
// Textoawait enviarMensagem( { to: '5511999998888', text: 'Olá, Maria! Seu pedido *#1234* saiu para entrega.' }, 'pedido-1234-saiu',);
// Imagem com legendaawait enviarMensagem( { to: '5511999998888', text: 'Olha como ficou o seu pedido 😍', media: { url: 'https://exemplo.com/fotos/pedido-1234.jpg', type: 'image' }, }, 'pedido-1234-foto',);
// Nota de vozawait enviarMensagem( { contact_id: '3f1c2b9a-7d4e-4c55-8a0e-1b2c3d4e5f60', media: { url: 'https://exemplo.com/audios/boas-vindas.ogg', type: 'audio', voice_note: true }, }, 'boas-vindas-audio-3f1c2b9a',);
// Responder citando uma mensagem recebidaawait enviarMensagem( { contact_id: '3f1c2b9a-7d4e-4c55-8a0e-1b2c3d4e5f60', reply_to_id: 'b7fa4c19-3e25-4ce9-9794-4e7f60efa4ba', text: 'Entregamos sim! Sábado das 8h às 14h.', }, 'resposta-b7fa4c19',);import osimport requests
def enviar_mensagem(corpo: dict, idempotency_key: str) -> dict: res = requests.post( "https://platform.toptalking.com.br/v1/messages", headers={ "Authorization": f"Bearer {os.environ['TOPTALKING_API_KEY']}", "Idempotency-Key": idempotency_key, }, json=corpo, timeout=30, ) body = res.json() if not res.ok: raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}") return body
# Textoenviar_mensagem( {"to": "5511999998888", "text": "Olá, Maria! Seu pedido *#1234* saiu para entrega."}, "pedido-1234-saiu",)
# Documento com legendaenviar_mensagem( { "contact_id": "3f1c2b9a-7d4e-4c55-8a0e-1b2c3d4e5f60", "text": "Segue o boleto.", "media": { "url": "https://exemplo.com/boleto-1234.pdf", "type": "document", "filename": "boleto-1234.pdf", }, }, "boleto-1234",)Resposta 201
Seção intitulada “Resposta 201”A mensagem criada:
{ "id": "03ab9a84-86b0-4a1c-a9b2-bbfa205cc52e", "object": "message", "contact_id": "3f1c2b9a-7d4e-4c55-8a0e-1b2c3d4e5f60", "channel_id": "d781e759-4047-4c35-bfcd-eae8c666369a", "direction": "outbound", "type": "text", "text": "Olá, Maria! Seu pedido *#1234* saiu para entrega.", "media": null, "status": "sent", "error": null, "reply_to_id": null, "reaction": null, "sender_name": null, "transcript": null, "created_at": "2026-11-11T14:30:12Z", "edited_at": null}| HTTP | code |
Quando acontece |
|---|---|---|
| 400 | missing_field |
Faltou to/contact_id ou text/media. |
| 400 | invalid_phone |
Telefone em to inválido. |
| 400 | invalid_field |
Campo inválido: texto acima de 4096 caracteres, media.url sem HTTPS, media.type desconhecido… |
| 403 | read_only_key |
Chave somente leitura. |
| 404 | resource_not_found |
contact_id, channel_id ou reply_to_id não encontrado. |
| 409 | idempotency_conflict |
Idempotency-Key reutilizada com outro corpo. |
| 422 | channel_unavailable |
Nenhum WhatsApp conectado (ou o canal escolhido está desconectado). Reconecte o canal. |
| 502 | provider_error |
O WhatsApp recusou o envio. A mensagem fica registrada com status failed. |
{ "error": { "type": "channel_error", "code": "channel_unavailable", "message": "WhatsApp desconectado. Reconecte no painel.", "request_id": "req_6f1d2c3b4a5e" }}Buscar mensagem
Seção intitulada “Buscar mensagem”GET/v1/messages/{message_id}
Busca uma mensagem pelo ID. Use para conferir o status de entrega (sent → delivered → read) de um envio importante.
| Parâmetro | Onde | Tipo | Obrigatório | Descrição |
|---|---|---|---|---|
message_id |
caminho | UUID | sim | ID da mensagem. |
curl https://platform.toptalking.com.br/v1/messages/03ab9a84-86b0-4a1c-a9b2-bbfa205cc52e \ -H "Authorization: Bearer $TOPTALKING_API_KEY"const messageId = '03ab9a84-86b0-4a1c-a9b2-bbfa205cc52e';const res = await fetch(`https://platform.toptalking.com.br/v1/messages/${messageId}`, { headers: { Authorization: `Bearer ${process.env.TOPTALKING_API_KEY}` },});const mensagem = await res.json();console.log(mensagem.status); // "read"import osimport requests
message_id = "03ab9a84-86b0-4a1c-a9b2-bbfa205cc52e"res = requests.get( f"https://platform.toptalking.com.br/v1/messages/{message_id}", headers={"Authorization": f"Bearer {os.environ['TOPTALKING_API_KEY']}"}, timeout=30,)res.raise_for_status()print(res.json()["status"])Resposta 200
Seção intitulada “Resposta 200”{ "id": "03ab9a84-86b0-4a1c-a9b2-bbfa205cc52e", "object": "message", "contact_id": "3f1c2b9a-7d4e-4c55-8a0e-1b2c3d4e5f60", "channel_id": "d781e759-4047-4c35-bfcd-eae8c666369a", "direction": "outbound", "type": "text", "text": "Olá, Maria! Seu pedido *#1234* saiu para entrega.", "media": null, "status": "read", "error": null, "reply_to_id": null, "reaction": null, "sender_name": null, "transcript": null, "created_at": "2026-11-11T14:30:12Z", "edited_at": null}| HTTP | code |
Quando acontece |
|---|---|---|
| 404 | resource_not_found |
A mensagem não existe ou é de outra organização. |
Editar mensagem
Seção intitulada “Editar mensagem”PATCH/v1/messages/{message_id}
Corrige o texto de uma mensagem de texto enviada pela empresa (outbound) em até 15 minutos depois do envio — o mesmo limite do WhatsApp. O contato vê a mensagem marcada como editada, e o texto novo aparece no painel.
Só mensagens de texto: mídias (inclusive legendas) não podem ser editadas. Mensagens recebidas (inbound) também não.
| Parâmetro | Onde | Tipo | Obrigatório | Descrição |
|---|---|---|---|---|
message_id |
caminho | UUID | sim | ID da mensagem enviada. |
text |
corpo | string | sim | Novo texto (até 4096 caracteres). |
curl -X PATCH https://platform.toptalking.com.br/v1/messages/03ab9a84-86b0-4a1c-a9b2-bbfa205cc52e \ -H "Authorization: Bearer $TOPTALKING_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "text": "Olá, Maria! Seu pedido *#1234* sai amanhã cedo." }'const messageId = '03ab9a84-86b0-4a1c-a9b2-bbfa205cc52e';const res = await fetch(`https://platform.toptalking.com.br/v1/messages/${messageId}`, { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.TOPTALKING_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ text: 'Olá, Maria! Seu pedido *#1234* sai amanhã cedo.' }),});const body = await res.json();if (res.status === 409) console.log('Não dá mais para editar:', body.error.message);import osimport requests
message_id = "03ab9a84-86b0-4a1c-a9b2-bbfa205cc52e"res = requests.patch( f"https://platform.toptalking.com.br/v1/messages/{message_id}", headers={"Authorization": f"Bearer {os.environ['TOPTALKING_API_KEY']}"}, json={"text": "Olá, Maria! Seu pedido *#1234* sai amanhã cedo."}, timeout=30,)mensagem = res.json()Resposta 200
Seção intitulada “Resposta 200”A mensagem com o texto novo e edited_at preenchido:
{ "id": "03ab9a84-86b0-4a1c-a9b2-bbfa205cc52e", "object": "message", "contact_id": "3f1c2b9a-7d4e-4c55-8a0e-1b2c3d4e5f60", "channel_id": "d781e759-4047-4c35-bfcd-eae8c666369a", "direction": "outbound", "type": "text", "text": "Olá, Maria! Seu pedido *#1234* sai amanhã cedo.", "media": null, "status": "delivered", "error": null, "reply_to_id": null, "reaction": null, "sender_name": null, "transcript": null, "created_at": "2026-11-11T14:30:12Z", "edited_at": "2026-11-11T14:38:05Z"}| HTTP | code |
Quando acontece |
|---|---|---|
| 400 | missing_field |
Faltou text. |
| 400 | invalid_field |
A mensagem é de mídia (não pode ser editada) ou o texto passou de 4096 caracteres. |
| 403 | read_only_key |
Chave somente leitura. |
| 404 | resource_not_found |
A mensagem não existe. |
| 409 | invalid_state |
A mensagem foi recebida (inbound) ou já passaram 15 minutos do envio. |
| 422 | channel_unavailable |
O WhatsApp da conversa está desconectado. |
| 502 | provider_error |
O WhatsApp recusou a edição. |
{ "error": { "type": "conflict_error", "code": "invalid_state", "message": "Só é possível editar mensagens enviadas há no máximo 15 minutos.", "request_id": "req_6f1d2c3b4a5e" }}Apagar mensagem
Seção intitulada “Apagar mensagem”DELETE/v1/messages/{message_id}
Apaga uma mensagem de um destes dois jeitos:
scope |
O que acontece | Quando dá |
|---|---|---|
everyone (padrão) |
Apaga para todos no WhatsApp. No painel e na API, o texto vira “Mensagem apagada”. | Só mensagens enviadas (outbound), em até 48 horas. |
me |
Só esconde a mensagem: ela some do painel e de GET /contacts/{contact_id}/messages. O contato continua vendo. |
Qualquer mensagem, a qualquer momento. |
Mesmo escondida com scope=me, a mensagem continua acessível por GET /messages/{message_id}.
| Parâmetro | Onde | Tipo | Obrigatório | Descrição |
|---|---|---|---|---|
message_id |
caminho | UUID | sim | ID da mensagem. |
scope |
query | string | não | everyone (padrão) ou me. |
# Apagar para todoscurl -X DELETE https://platform.toptalking.com.br/v1/messages/0dd803ad-1be8-4d87-8cf8-3b3d0e94de93 \ -H "Authorization: Bearer $TOPTALKING_API_KEY"
# Só esconder do painelcurl -X DELETE "https://platform.toptalking.com.br/v1/messages/0dd803ad-1be8-4d87-8cf8-3b3d0e94de93?scope=me" \ -H "Authorization: Bearer $TOPTALKING_API_KEY"async function apagarMensagem(messageId, scope = 'everyone') { const res = await fetch( `https://platform.toptalking.com.br/v1/messages/${messageId}?scope=${scope}`, { method: 'DELETE', headers: { Authorization: `Bearer ${process.env.TOPTALKING_API_KEY}` } }, ); const body = await res.json(); if (res.status === 409 && scope === 'everyone') { return apagarMensagem(messageId, 'me'); // passou de 48 h ou é recebida: só esconde } if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`); return body;}
await apagarMensagem('0dd803ad-1be8-4d87-8cf8-3b3d0e94de93');import osimport requests
message_id = "0dd803ad-1be8-4d87-8cf8-3b3d0e94de93"res = requests.delete( f"https://platform.toptalking.com.br/v1/messages/{message_id}", headers={"Authorization": f"Bearer {os.environ['TOPTALKING_API_KEY']}"}, params={"scope": "everyone"}, # ou "me" timeout=30,)mensagem = res.json()Resposta 200
Seção intitulada “Resposta 200”A mensagem apagada (com scope=everyone):
{ "id": "0dd803ad-1be8-4d87-8cf8-3b3d0e94de93", "object": "message", "contact_id": "3f1c2b9a-7d4e-4c55-8a0e-1b2c3d4e5f60", "channel_id": "d781e759-4047-4c35-bfcd-eae8c666369a", "direction": "outbound", "type": "text", "text": "Mensagem apagada", "media": null, "status": "delivered", "error": null, "reply_to_id": null, "reaction": null, "sender_name": null, "transcript": null, "created_at": "2026-11-11T14:41:00Z", "edited_at": null}Com scope=me, a resposta é a mensagem como estava (o texto não muda): ela só deixa de aparecer no painel e no histórico.
| HTTP | code |
Quando acontece |
|---|---|---|
| 403 | read_only_key |
Chave somente leitura. |
| 404 | resource_not_found |
A mensagem não existe. |
| 409 | invalid_state |
Com scope=everyone: a mensagem foi recebida (inbound) ou já passaram 48 horas. Use scope=me. |
| 422 | channel_unavailable |
Com scope=everyone: o WhatsApp da conversa está desconectado. |
| 502 | provider_error |
O WhatsApp recusou apagar a mensagem. |
{ "error": { "type": "conflict_error", "code": "invalid_state", "message": "Só é possível apagar para todos mensagens enviadas há no máximo 48 horas. Para esconder do painel, use scope=me.", "request_id": "req_6f1d2c3b4a5e" }}Reagir a uma mensagem
Seção intitulada “Reagir a uma mensagem”POST/v1/messages/{message_id}/reaction
Envia uma reação com emoji a uma mensagem da conversa — recebida ou enviada —, como o “segurar e reagir” do WhatsApp. Útil para confirmar que viu um pedido sem mandar uma mensagem nova. Enviar emoji vazio ("") remove a reação.
Não disponível para conversas do Chat do site (webchat).
| Parâmetro | Onde | Tipo | Obrigatório | Descrição |
|---|---|---|---|---|
message_id |
caminho | UUID | sim | ID da mensagem que vai receber a reação. |
emoji |
corpo | string | sim | Um emoji (ex.: "👍"). "" remove a reação. |
curl https://platform.toptalking.com.br/v1/messages/b7fa4c19-3e25-4ce9-9794-4e7f60efa4ba/reaction \ -H "Authorization: Bearer $TOPTALKING_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "emoji": "👍" }'async function reagir(messageId, emoji) { const res = await fetch(`https://platform.toptalking.com.br/v1/messages/${messageId}/reaction`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOPTALKING_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ emoji }), // '' remove }); const body = await res.json(); if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`); return body;}
await reagir('b7fa4c19-3e25-4ce9-9794-4e7f60efa4ba', '👍');import osimport requests
message_id = "b7fa4c19-3e25-4ce9-9794-4e7f60efa4ba"res = requests.post( f"https://platform.toptalking.com.br/v1/messages/{message_id}/reaction", headers={"Authorization": f"Bearer {os.environ['TOPTALKING_API_KEY']}"}, json={"emoji": "👍"}, # "" remove a reação timeout=30,)res.raise_for_status()mensagem = res.json()Resposta 200
Seção intitulada “Resposta 200”A mensagem com a reação em reaction:
{ "id": "b7fa4c19-3e25-4ce9-9794-4e7f60efa4ba", "object": "message", "contact_id": "3f1c2b9a-7d4e-4c55-8a0e-1b2c3d4e5f60", "channel_id": "d781e759-4047-4c35-bfcd-eae8c666369a", "direction": "inbound", "type": "text", "text": "Vocês entregam no sábado?", "media": null, "status": "delivered", "error": null, "reply_to_id": null, "reaction": "👍", "sender_name": null, "transcript": null, "created_at": "2026-11-11T14:12:40Z", "edited_at": null}| HTTP | code |
Quando acontece |
|---|---|---|
| 400 | missing_field |
Faltou emoji. |
| 400 | invalid_field |
Mais de um emoji, ou a conversa é do Chat do site. |
| 403 | read_only_key |
Chave somente leitura. |
| 404 | resource_not_found |
A mensagem não existe. |
| 409 | invalid_state |
A mensagem ainda não tem identificador no WhatsApp (ex.: ainda está queued). Tente de novo em instantes. |
| 422 | channel_unavailable |
O WhatsApp da conversa está desconectado. |
| 502 | provider_error |
O WhatsApp recusou a reação. |
{ "error": { "type": "invalid_request_error", "code": "invalid_field", "message": "Reações não estão disponíveis no Chat do site.", "request_id": "req_6f1d2c3b4a5e" }}