Indicador de digitação
O indicador de digitação mostra ao destinatário que uma mensagem está sendo escrita.
Indicador automático
O Turbo Notify mostra o indicador de digitação sozinho antes de cada envio, por um breve período. Antes disso, a conversa é aberta como uma pessoa faria: o número aparece online e as mensagens não lidas dessa conversa são marcadas como lidas.
Use os endpoints abaixo apenas quando precisar de controle manual sobre o indicador de digitação.
Início da digitação
Para sinalizar que uma mensagem está sendo preparada, envie uma requisição com is_typing igual a true.
curl -X POST \ https://api.turbonotify.com/v1/typing-indicator \ -H "Authorization: Bearer SUA_CHAVE" \ -H "Content-Type: application/json" \ -d '{ "to": {"number": "+5511988887777"}, "is_typing": true }'const response = await fetch('https://api.turbonotify.com/v1/typing-indicator', { method: 'POST', headers: { 'Authorization': 'Bearer SUA_CHAVE', 'Content-Type': 'application/json' }, body: JSON.stringify({ to: { number: '+5511988887777' }, is_typing: true })});
console.log(response.status); // 202import requests
url = "https://api.turbonotify.com/v1/typing-indicator"headers = { "Authorization": "Bearer SUA_CHAVE", "Content-Type": "application/json"}data = { "to": {"number": "+5511988887777"}, "is_typing": True}
response = requests.post(url, json=data, headers=headers)print(response.status_code) # 202package main
import ( "fmt" "net/http" "strings")
func main() { payload := strings.NewReader(`{"to": {"number": "+5511988887777"}, "is_typing": true}`) req, _ := http.NewRequest("POST", "https://api.turbonotify.com/v1/typing-indicator", 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/typing-indicator';$data = [ 'to' => ['number' => '+5511988887777'], 'is_typing' => true];
$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 { to = new { number = "+5511988887777" }, is_typing = true};
var json = JsonSerializer.Serialize(data);var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://api.turbonotify.com/v1/typing-indicator", content);Console.WriteLine((int)response.StatusCode); // 202import java.net.http.*;import java.net.URI;
public class Typing { public static void main(String[] args) throws Exception { var client = HttpClient.newHttpClient();
var json = """ { "to": {"number": "+5511988887777"}, "is_typing": true } """;
var request = HttpRequest.newBuilder() .uri(URI.create("https://api.turbonotify.com/v1/typing-indicator")) .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:
{
"operation_id": "op_typing_9f3c2a1d47e8",
"status": {
"state": "pending",
"at": "2025-07-16T10:00:00Z"
}
} O que acontece ao começar a digitar
Começar a digitar também abre a conversa, como em um WhatsApp usado por uma pessoa, nesta ordem:
- O número aparece online, se ainda não estava.
- As mensagens que o número recebeu nessa conversa e ainda não leu são marcadas como lidas (o “check azul” para quem as enviou).
- Depois de uma pausa curta e aleatória, entre 0,3 e 1,5 segundo, aparece “digitando…”.
Assim, o “digitando…” nunca aparece por cima de mensagens não lidas. O número volta a ficar offline sozinho, alguns minutos depois da última interação com qualquer conversa (é a presença exibida no WhatsApp: a conexão e o status do número não mudam).
Tudo isso é automático. Não consome cota de mensagens nem de contatos e não gera evento de webhook. O plano exigido para o indicador de digitação continua o mesmo: a leitura que acompanha o início da digitação não depende do recurso de leitura do plano Empresarial ou superior, que vale só para a marcação manual como lida.
Fim da digitação
Para interromper o indicador de digitação manualmente, envie a mesma requisição com is_typing igual a false. Parar de digitar só remove o indicador: nenhuma mensagem é marcada como lida.
curl -X POST \ https://api.turbonotify.com/v1/typing-indicator \ -H "Authorization: Bearer SUA_CHAVE" \ -H "Content-Type: application/json" \ -d '{ "to": {"number": "+5511988887777"}, "is_typing": false }'const response = await fetch('https://api.turbonotify.com/v1/typing-indicator', { method: 'POST', headers: { 'Authorization': 'Bearer SUA_CHAVE', 'Content-Type': 'application/json' }, body: JSON.stringify({ to: { number: '+5511988887777' }, is_typing: false })});
console.log(response.status); // 202import requests
url = "https://api.turbonotify.com/v1/typing-indicator"headers = { "Authorization": "Bearer SUA_CHAVE", "Content-Type": "application/json"}data = { "to": {"number": "+5511988887777"}, "is_typing": False}
response = requests.post(url, json=data, headers=headers)print(response.status_code) # 202package main
import ( "fmt" "net/http" "strings")
func main() { payload := strings.NewReader(`{"to": {"number": "+5511988887777"}, "is_typing": false}`) req, _ := http.NewRequest("POST", "https://api.turbonotify.com/v1/typing-indicator", 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/typing-indicator';$data = [ 'to' => ['number' => '+5511988887777'], 'is_typing' => false];
$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 { to = new { number = "+5511988887777" }, is_typing = false};
var json = JsonSerializer.Serialize(data);var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://api.turbonotify.com/v1/typing-indicator", content);Console.WriteLine((int)response.StatusCode); // 202import java.net.http.*;import java.net.URI;
public class Typing { public static void main(String[] args) throws Exception { var client = HttpClient.newHttpClient();
var json = """ { "to": {"number": "+5511988887777"}, "is_typing": false } """;
var request = HttpRequest.newBuilder() .uri(URI.create("https://api.turbonotify.com/v1/typing-indicator")) .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:
{
"operation_id": "op_typing_5b8e0d6c21fa",
"status": {
"state": "pending",
"at": "2025-07-16T10:00:05Z"
}
} Destinatários disponíveis
O campo to aceita exatamente uma das três formas abaixo, assim como na rota de envio de mensagens:
| Forma | Exemplo | Quando usar |
|---|---|---|
number | {"number": "+5511988887777"} | Número E.164 conhecido |
group_id | {"group_id": "grp_…"} | Grupo do WhatsApp |
contact_id | {"contact_id": "ct_…"} | ID do contato no Turbo Notify (telefone resolvido internamente) |
Indicador de digitação em grupos
Para enviar o indicador de digitação em um grupo do WhatsApp, use to.group_id com o identificador do grupo no lugar de to.number.
curl -X POST \ https://api.turbonotify.com/v1/numbers/ALIAS_DO_NUMERO/typing-indicator \ -H "Authorization: Bearer SUA_CHAVE" \ -H "Content-Type: application/json" \ -d '{ "to": {"group_id": "grp_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4"}, "is_typing": true }'O group_id é o identificador do grupo no formato grp_{hex32}, retornado pelo endpoint de listagem de grupos.
Indicador de digitação por contact_id
Use to.contact_id para indicar digitação a um contato do catálogo do Turbo Notify sem informar o telefone diretamente. O telefone é resolvido internamente a partir do registro do contato.
curl -X POST \ https://api.turbonotify.com/v1/numbers/ALIAS_DO_NUMERO/typing-indicator \ -H "Authorization: Bearer SUA_CHAVE" \ -H "Content-Type: application/json" \ -d '{ "to": {"contact_id": "ct_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4"}, "is_typing": true }'Indicador de digitação com número extra
Na forma aninhada, o remetente do indicador de digitação é sempre o número informado no caminho. Para digitar
a partir de um número extra cadastrado e ativo, use essa forma com o alias desse
número no lugar de {ref}:
curl -X POST \ https://api.turbonotify.com/v1/numbers/vendas-sp/typing-indicator \ -H "Authorization: Bearer SUA_CHAVE" \ -H "Content-Type: application/json" \ -d '{ "to": {"number": "+5511988887777"}, "is_typing": true }'As duas formas tratam o remetente de maneira diferente:
- Aninhada (
POST /v1/numbers/{ref}/typing-indicator): o remetente é sempre o número informado no caminho. Um campofromno corpo é ignorado. - Plana (
POST /v1/typing-indicator): envia sempre a partir do número principal (main). Um campofromno corpo não gera erro de validação, mas é descartado silenciosamente: a requisição retorna202 Acceptede o indicador de digitação sai do número principal, não do número informado emfrom.
Para enviar um indicador de digitação a partir de um número extra, use obrigatoriamente a forma aninhada, com o alias do número extra no caminho da URL. A forma plana não tem como direcionar o remetente, e por não sinalizar erro, um from no corpo produz a falsa impressão de que funcionou.
Caso o alias informado no caminho não esteja cadastrado ou o número não esteja ativo, a operação será rejeitada.
Saiba mais sobre números extras.
Eventos de webhook
O indicador de digitação não tem confirmação de conclusão: o 202 Accepted confirma apenas o
aceite assíncrono e nenhum evento de webhook é entregue para essas operações.
Erros possíveis
| Status | Código de erro | Descrição |
|---|---|---|
400 | contact_not_found | O contact_id informado em to não pertence a esta organização. |
400 | contacts_not_enabled | O envio por contact_id está indisponível no momento. Tente de novo mais tarde; se persistir, fale com o suporte. |
400 | groups_not_enabled | O recurso de grupos está indisponível no momento. Tente de novo mais tarde; se persistir, fale com o suporte. |
400 | invalid_recipient | Não foi possível resolver o destinatário informado em to para um endereço de envio. Informar nenhum ou mais de um entre number, group_id e contact_id retorna 422 validation_error. |
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 | group_not_found | O group_id informado em to não foi encontrado. |
409 | number_not_connected | O número não está conectado ao WhatsApp. Reconecte o número e tente de novo. |
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. |