Enviar reação
Sua aplicação pode enviar ou remover uma reação em uma mensagem específica.
O endpoint é roteado pelo message_id da mensagem-alvo na URL: não há campo to no corpo, pois o destinatário é inferido da mensagem original.
Esta página cobre o envio e a remoção de reações. Para listar as reações ativas de uma mensagem, veja Consultar reações.
Antes de enviar a reação, o Turbo Notify abre a conversa como uma pessoa faria: o número aparece online, o histórico de mensagens não lidas do chat de origem da mensagem-alvo é marcado como lido e só então a reação é enviada. Veja Marcar como lida.
Adicionar uma reação
POST /v1/messages/{message_id}/react: adiciona uma reação à mensagem identificada por {message_id} (formato msg_{hex32}). Esta rota opera sobre o número principal. Para enviar a reação a partir de um número extra, use a forma completa POST /v1/numbers/{ref}/messages/{message_id}/react com o alias do número no caminho da URL.
curl -X POST \ https://api.turbonotify.com/v1/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react \ -H "Authorization: Bearer SUA_CHAVE" \ -H "Content-Type: application/json" \ -d '{ "reaction": "🎉" }'const response = await fetch( 'https://api.turbonotify.com/v1/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react', { method: 'POST', headers: { 'Authorization': 'Bearer SUA_CHAVE', 'Content-Type': 'application/json' }, body: JSON.stringify({ reaction: '🎉' }) });
console.log(response.status); // 202import requests
url = "https://api.turbonotify.com/v1/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react"headers = { "Authorization": "Bearer SUA_CHAVE", "Content-Type": "application/json"}data = {"reaction": "🎉"}
response = requests.post(url, json=data, headers=headers)print(response.status_code) # 202package main
import ( "fmt" "net/http" "strings")
func main() { payload := strings.NewReader(`{"reaction": "🎉"}`) req, _ := http.NewRequest( "POST", "https://api.turbonotify.com/v1/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react", payload, ) req.Header.Set("Authorization", "Bearer SUA_CHAVE") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() fmt.Println(resp.StatusCode) // 202}<?php$url = 'https://api.turbonotify.com/v1/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react';$data = ['reaction' => '🎉'];
$options = [ 'http' => [ 'header' => [ 'Authorization: Bearer SUA_CHAVE', 'Content-Type: application/json' ], 'method' => 'POST', 'content' => json_encode($data) ]];
$context = stream_context_create($options);file_get_contents($url, false, $context);var_dump($http_response_header);?>using System.Text;using System.Text.Json;
var client = new HttpClient();client.DefaultRequestHeaders.Add("Authorization", "Bearer SUA_CHAVE");
var data = new { reaction = "🎉" };var json = JsonSerializer.Serialize(data);var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync( "https://api.turbonotify.com/v1/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react", content);Console.WriteLine((int)response.StatusCode); // 202import java.net.http.*;import java.net.URI;
public class Reaction { public static void main(String[] args) throws Exception { var client = HttpClient.newHttpClient();
var json = """ {"reaction": "🎉"} """;
var request = HttpRequest.newBuilder() .uri(URI.create( "https://api.turbonotify.com/v1/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react")) .header("Authorization", "Bearer SUA_CHAVE") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(json)) .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode()); // 202 }}Após enviar, o Turbo Notify retorna aceite assíncrono:
{
"message_id": "msg_01993c5a1b24d3e9f01a2b3c4d5e6f70",
"reaction_event_id": "op_reaction_a1b2c3d4e5f6",
"status": {
"state": "pending",
"at": "2025-07-16T10:00:00Z"
}
} Remover uma reação
Para remover uma reação previamente enviada, envie a propriedade reaction como null (ou string vazia) no mesmo endpoint.
curl -X POST \ https://api.turbonotify.com/v1/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react \ -H "Authorization: Bearer SUA_CHAVE" \ -H "Content-Type: application/json" \ -d '{ "reaction": null }'const response = await fetch( 'https://api.turbonotify.com/v1/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react', { method: 'POST', headers: { 'Authorization': 'Bearer SUA_CHAVE', 'Content-Type': 'application/json' }, body: JSON.stringify({ reaction: null }) });
console.log(response.status); // 202import requests
url = "https://api.turbonotify.com/v1/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react"headers = { "Authorization": "Bearer SUA_CHAVE", "Content-Type": "application/json"}data = {"reaction": None}
response = requests.post(url, json=data, headers=headers)print(response.status_code) # 202package main
import ( "fmt" "net/http" "strings")
func main() { payload := strings.NewReader(`{"reaction": null}`) req, _ := http.NewRequest( "POST", "https://api.turbonotify.com/v1/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react", payload, ) req.Header.Set("Authorization", "Bearer SUA_CHAVE") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() fmt.Println(resp.StatusCode) // 202}<?php$url = 'https://api.turbonotify.com/v1/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react';$data = ['reaction' => null];
$options = [ 'http' => [ 'header' => [ 'Authorization: Bearer SUA_CHAVE', 'Content-Type: application/json' ], 'method' => 'POST', 'content' => json_encode($data) ]];
$context = stream_context_create($options);file_get_contents($url, false, $context);var_dump($http_response_header);?>using System.Text;
var client = new HttpClient();client.DefaultRequestHeaders.Add("Authorization", "Bearer SUA_CHAVE");
var json = """{"reaction": null}""";var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync( "https://api.turbonotify.com/v1/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react", content);Console.WriteLine((int)response.StatusCode); // 202import java.net.http.*;import java.net.URI;
public class Reaction { public static void main(String[] args) throws Exception { var client = HttpClient.newHttpClient();
var json = """ {"reaction": null} """;
var request = HttpRequest.newBuilder() .uri(URI.create( "https://api.turbonotify.com/v1/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react")) .header("Authorization", "Bearer SUA_CHAVE") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(json)) .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode()); // 202 }}Após enviar, o Turbo Notify retorna aceite assíncrono:
{
"message_id": "msg_01993c5a1b24d3e9f01a2b3c4d5e6f70",
"reaction_event_id": "op_reaction_9f8e7d6c5b4a",
"status": {
"state": "pending",
"at": "2025-07-16T10:00:05Z"
}
} A conclusão da operação chega via webhook como message.reacted (sucesso) ou message.react.failed (falha). O payload de falha inclui o message_id da mensagem-alvo, dispensando o uso de request_id para correlação.
Reação com número extra
Para enviar a reação a partir de um número extra cadastrado e ativo, use o alias desse número no caminho da URL. O destinatário continua sendo inferido a partir do message_id.
curl -X POST \ https://api.turbonotify.com/v1/numbers/vendas-sp/messages/msg_01993c5a1b24d3e9f01a2b3c4d5e6f70/react \ -H "Authorization: Bearer SUA_CHAVE" \ -H "Content-Type: application/json" \ -d '{ "reaction": "🎉" }'Caso o alias informado na URL não esteja cadastrado como número extra ou não esteja ativo, a operação será rejeitada.
Saiba mais sobre números extras.
Erros possíveis
| Status | Código de erro | Descrição |
|---|---|---|
400 | invalid_message_id | O message_id na URL não está no formato msg_{hex32}. |
402 | feature_not_available | O recurso não está disponível no plano contratado. |
401 | not_authenticated | A chave de API está inválida ou ausente. |
403 | insufficient_scope | A chave de API não possui o escopo messages:send (resposta inclui required_scope). |
404 | number_not_found | O {ref} do caminho não corresponde a nenhum número da conta (na rota plana: a conta ainda não tem número principal). |
400 | invalid_number_id | O valor na URL começa com num_, mas não é um id de número válido. |
404 | not_found | A mensagem não foi encontrada, pertence a outra organização ou pertence a um número diferente do da URL (na rota atalho sem {ref}, o número principal): todos esses casos devolvem a mesma resposta, sem distinção. |
409 | number_not_connected | O número que envia não está conectado ao WhatsApp. Reconecte o número e tente de novo. |
422 | message_not_reactable | A mensagem alvo da reação ainda não foi enviada ao WhatsApp ou já foi apagada. |
422 | sender_not_found | O alias/número informado não corresponde a nenhum remetente da conta. |
422 | validation_error | O corpo da requisição está malformado ou não passou na validação. A resposta inclui details.errors com a lista de campos inválidos. |
500 | internal_error | Erro interno inesperado no servidor. |
Uma mensagem inexistente e uma mensagem de outro número devolvem o mesmo not_found, nas duas rotas (a atalho sem {ref} e a aninhada /numbers/{ref}/messages/...). Se você sabe que a mensagem existe mas recebeu not_found, confira se está usando o id (ou o alias atual) do número que a enviou ou recebeu.