Políticas, descadastro e saúde do número
Conexões por aparelho vinculado são bloqueadas pelo WhatsApp quando o número parece fazer disparo em massa. As políticas do Recadu seguram o ritmo antes que isso aconteça, e a nota de saúde mostra quando o número está perto do limite.
Políticas
Cada instância segue uma política em camadas: o padrão do tipo de negócio, ajustado pela conta e, por fim, pela própria instância. Veja a que vale agora:
curl https://api.recadu.com.br/v1/instances/ins_.../policy -H "Authorization: Bearer $GW_API_KEY"
| Regra | Padrão (varejo) | Padrão (saúde) | Efeito |
|---|---|---|---|
per_minute |
40 | 20 | Envios por minuto. Acima disso a mensagem espera na fila, não é recusada |
new_contacts_per_day |
300 | 80 | Contatos que nunca escreveram para o número, em 24 h. Acima: 429 policy-new-contacts-limit |
mass_block |
40 contatos em 10 min | 15 contatos em 10 min | O mesmo texto (ignorando maiúsculas, acentos e espaços) para muitos contatos novos: 422 policy-mass-send-blocked |
warmup |
14 dias, limites a 25% | igual | Número recém-conectado começa devagar |
typing |
ligado | ligado | "Digitando..." antes de cada texto, proporcional ao tamanho, com variação |
active_hours |
desligado | desligado | Janela de horário |
opt_out |
ligado | ligado | Descadastro |
menu_ttl_hours |
24 | 24 | Por quanto tempo a resposta "2" a um menu é reconhecida |
Contato novo é quem nunca mandou mensagem para aquele número. Responder a quem escreveu não conta no limite: o freio é para mensagens ativas.
Os limites padrão são conservadores e serão ajustados com o uso real. Se o seu caso precisa de outros, ajuste na instância:
curl -X PATCH https://api.recadu.com.br/v1/instances/ins_... \
-H "Authorization: Bearer $GW_API_KEY" -H "Content-Type: application/json" \
-d '{"policy": {"per_minute": 20, "active_hours": {"start": "08:00", "end": "20:00", "outside": "schedule"}}}'
Só os campos enviados mudam; null desliga uma regra; {"policy": {}} volta ao padrão da conta.
Janela de horário
Com active_hours, mensagens para quem não escreveu nas últimas 24 h só saem dentro da janela (start e end no timezone, padrão America/Sao_Paulo). Respostas a quem acabou de escrever saem a qualquer hora.
Fora da janela, outside decide:
outside |
O que acontece |
|---|---|
reject (padrão) |
422 policy-outside-hours; o seu sistema decide quando tentar de novo |
schedule |
A mensagem é aceita (202, status: queued) com scheduled_for na próxima abertura da janela |
Uma mensagem agendada:
- sai na hora se o contato escrever antes da abertura (ela deixa de ser ativa);
- é cancelada se o contato pedir para sair (
error.code: opted_out); - pode ser cancelada por você com
DELETE /v1/messages/{id}(error.code: canceled); - segura as mensagens seguintes da mesma conversa até sair, para manter a ordem.
Descadastro
Quando o contato manda uma mensagem só com SAIR, PARAR, STOP, DESCADASTRAR ou CANCELAR (maiúsculas, acentos e pontuação não importam), o Recadu:
- descadastra o contato na sua conta (vale para todas as instâncias);
- manda o evento
contact.opted_outpara o seu webhook; - passa a recusar envios para ele com
422 contact-opted-out, inclusive mensagens que já estavam na fila.
"Quero sair mais cedo hoje" não descadastra: só a mensagem inteira conta.
Quando o contato manda VOLTAR, RETOMAR ou START, ele é liberado e chega contact.opted_in.
O Recadu não responde ao contato automaticamente. Se quiser confirmar ("Pronto, você não vai mais receber mensagens"), responda a partir do contact.opted_out: uma resposta a quem acabou de escrever não é bloqueada.
Para gerenciar à mão:
curl https://api.recadu.com.br/v1/opt-outs -H "Authorization: Bearer $GW_API_KEY" # lista
curl -X POST https://api.recadu.com.br/v1/opt-outs \
-H "Authorization: Bearer $GW_API_KEY" -H "Content-Type: application/json" \
-d '{"phone": "5537999990000"}' # descadastra
curl -X DELETE https://api.recadu.com.br/v1/opt-outs/5537999990000 \
-H "Authorization: Bearer $GW_API_KEY" # libera
Só remova um descadastro com o consentimento do contato. As palavras podem ser trocadas na política (opt_out.keywords e opt_out.resume_keywords).
Saúde
GET /v1/instances/{id}/health dá uma nota de 0 a 100 para o risco de bloqueio do número, com os motivos e o que fazer:
{
"instance_id": "ins_...",
"score": 68,
"risk": "medium",
"warming_up": false,
"factors": [
{"key": "reply_rate", "label": "Taxa de resposta (7 dias)", "status": "attention", "penalty": 12, "value": 0.22,
"detail": "11 de 50 contatos responderam (22%)."}
],
"recommendations": ["Poucas respostas indicam mensagens que as pessoas não esperavam: mande só para quem pediu e comece com uma pergunta."],
"computed_at": "2026-10-13T14:00:00Z"
}
| Fator | Tira pontos quando |
|---|---|
| Contatos novos | Passa de 70% do limite do dia |
| Taxa de resposta | Menos de 30% dos contatos responderam em 7 dias (com pelo menos 20 contatos) |
| Descadastros | Mais de 2% dos contatos pediram para sair em 7 dias |
| Falhas de envio | Mais de 5% das mensagens falharam em 7 dias |
| Quedas | 3 ou mais desconexões em 7 dias |
| Aquecimento | Informativo: o número está nos primeiros 14 dias |
risk |
Nota |
|---|---|
low |
80 a 100 |
medium |
50 a 79 |
high |
abaixo de 50 (número bloqueado ou desconectado do celular: 0) |
A nota também aparece no painel, na lista de instâncias e na tela de cada uma.
Disponibilidade
GET /v1/instances/{id}/availability?month=2026-10 mostra quanto do mês a instância ficou conectada, dia a dia, e cada queda:
{
"instance_id": "ins_...",
"month": "2026-10",
"timezone": "America/Sao_Paulo",
"uptime": 99.82,
"days": [ ... ],
"incidents": [
{"start": "2026-10-07T03:12:00Z", "end": "2026-10-07T03:21:30Z", "duration_s": 570,
"state": "disconnected", "reason": "..."}
]
}
A conta começa na primeira conexão da instância. Qualquer estado diferente de conectada conta como queda, inclusive o celular sem internet ou o aparelho desconectado no celular. end vazio: a queda ainda está acontecendo. Aceita ?timezone= para os dias no seu fuso.