wapp-api — referência dos endpoints
Base: https://wapp-api.renatopavan.com.br
Todo acesso é por HTTPS. Chamadas em http:// são redirecionadas.
Autenticação
Toda rota /api/* exige o header X-API-Key. Cada projeto tem a sua chave,
gerada no servidor com python gerar_chave.py criar <nome>. Sem header
válido: 401.
O <nome> do cliente vira a origem das mensagens. Não dá para
sobrescrever pelo body — se você mandar origem no JSON, ele é ignorado.
Cada cliente só enxerga nas consultas as mensagens que ele mesmo enfileirou.
/health é a única rota sem autenticação.
Mensagens
POST /api/mensagens — enfileira
{"instancia":"principal","numero":"(11) 99999-8888","tipo":"texto",
"conteudo":"Seu boleto venceu.","agendado_para":null}
| Campo | Obrigatório | Observação |
|---|---|---|
instancia |
não | nome de uma instância sua, ou "gateway"; omitido, vale a sua conectada — e o gateway, se você não tiver nenhuma |
numero |
sim | aceita (11) 99999-8888, 11999998888, 5511999998888; ou JID de grupo autorizado (docs/api-grupos.md) |
tipo |
não | texto (padrão); anexos em docs/api-midia.md |
conteudo |
sim | texto da mensagem |
agendado_para |
não | ISO 8601; nulo = assim que for a vez |
201
{"id":123,"status":"na_fila","numero_destino":"5511999998888",
"origem":"erp-financeiro","instancia":"principal","agendado_para":null}
A resposta é o enfileiramento, não o envio. Quem envia é o worker, com
intervalo aleatório entre mensagens. Acompanhe pelo GET /api/mensagens/<id>.
Sem aparelho próprio: envio pelo gateway
Projeto que só manda link de senha e aviso técnico (svn-monitor, bkp-app) não precisa de celular pareado: recebe chave e manda pelo número do gateway.
| Cliente com aparelho | Cliente sem aparelho | |
|---|---|---|
instancia no body |
nome da sua | omitir, ou "gateway" |
| Número que aparece para o destinatário | o seu | o do gateway |
| Janela de horário | a sua (GET /api/janela) |
a do gateway, 7h–22h |
| Teto diário do número | o do seu aparelho | o do aparelho do gateway, dividido com os demais |
origem, teto por minuto, quota, opt-out, log, callback |
seus | seus também — muda só o número que sai |
"instancia": "gateway" vale mesmo para quem tem aparelho: é o jeito de
mandar um aviso técnico pelo número do sistema. Se você tiver uma instância
sua chamada gateway, ela ganha — a palavra reservada não toma o seu
aparelho.
Quando a mensagem sai pelo gateway, a resposta 201 traz pelo_gateway
e um aviso:
{"id":123,"status":"na_fila","instancia":"gateway","pelo_gateway":true,
"aviso":"sai pelo número do gateway: ... A janela de horário é a do gateway, 7h–22h."}
409 quando não há por onde mandar — você sem instância conectada e o
gateway sem aparelho pareado. Não é falha do serviço: é aparelho faltando, e
o corpo diz onde resolver (Painel › Instâncias). Detalhes em
docs/instancias.md.
GET /api/mensagens/<id>
200 com os campos da mensagem, incluindo status, tentativas, erro,
id_mensagem_wa, enviado_em. 404 se o id não for seu.
GET /api/mensagens — lista
Filtros: status, numero, data_inicio, data_fim (ISO 8601),
limite (padrão 100, teto 500).
200 → {"total":2,"limite":100,"mensagens":[...]}
Mensagens recebidas
GET /api/mensagens/entrada lista o que chegou e
GET /api/mensagens/entrada/<id>/arquivo baixa o anexo. Formato, cursor e
o callback mensagem_recebida em docs/api-entrada.md.
Ciclo do status
na_fila → enviando → enviado → entregue → lido, ou falhou.
Instâncias
| Método | Path | Devolve |
|---|---|---|
POST |
/api/instancias |
201 {id, nome, status} — body: {"nome":"principal","descricao":"..."} |
GET |
/api/instancias |
200 lista com status |
GET |
/api/instancias/<nome>/qrcode |
200 {qrcode_base64, pairing_code} |
GET |
/api/instancias/<nome>/status |
200 {status, estado_evolution} |
DELETE |
/api/instancias/<nome> |
200; 409 se houver mensagem na fila |
Passo a passo de conexão (QR, código de pareamento, erros) em
docs/instancias.md.
GET /health
Sem autenticação. 200 {"status":"ok","banco":true,"evolution":true}
ou 503 com "status":"degradado".
Códigos de erro
| Código | Quando |
|---|---|
| 400 | body inválido, número que não normaliza, data fora do ISO 8601, instancia que não é sua nem gateway (a resposta traz instancias_validas) |
| 401 | X-API-Key ausente, inválida ou revogada |
| 403 | número está no opt-out |
| 404 | mensagem inexistente (ou de outro cliente) |
| 405 | método errado para a rota |
| 409 | nome de instância repetido, remoção com fila pendente, ou nenhum aparelho conectado para enviar (nem seu, nem do gateway) |
| 413 | corpo acima do limite de 20 MB (ver docs/api-midia.md) |
| 429 | limite de requisições por minuto excedido; respeite o Retry-After |
| 507 | sua quota de disco para anexos acabou |
| 500 | erro interno — já registrado em log_eventos |
| 502 | a Evolution recusou ou não respondeu |
Todo erro vem como {"erro":"...","detalhe":"..."} — detalhe é opcional.
Opt-out
Quem responde SAIR, PARAR ou DESCADASTRAR entra na tabela optout
automaticamente. A partir daí, enfileirar para esse número devolve 403,
e o worker também confere de novo antes de cada envio.
Anexos
Imagem, documento, vídeo e áudio vão por multipart/form-data na mesma
rota. Ver docs/api-midia.md.
Exemplos de código
curl, Python, PHP e Delphi: ver docs/api-exemplos.md.
Limites
| Limite | Padrão | Estouro |
|---|---|---|
| Requisições por minuto | 60 | 429 com Retry-After |
| Espaço em disco para anexos | 1 GB | 507 |
| Tamanho de um anexo | 16 MB | 400 |
| Corpo da requisição | 20 MB | 413 |
Os dois primeiros são por cliente e podem ser ajustados — fale comigo se o seu volume pedir mais.
Janela de horário
Disparo sai só dentro da sua janela. Resposta não: se o destino escreveu para a instância nos últimos 60 min, a mensagem sai a qualquer hora. Quem confere isso é o gateway, olhando as mensagens recebidas — não há campo para declarar "isto é resposta".
| Rota | O que faz |
|---|---|
GET /api/janela |
Devolve inicio, fim, o teto e resposta_minutos |
PUT /api/janela |
Grava {"inicio": 8, "fim": 20} |
A janela é sua; o teto é do gateway e só o administrador muda (padrão 07–22h). Janela fora do teto → 400 dizendo qual é o teto. Motivo: quem a Meta bane é o número, e o número é nosso.
Pelo mesmo motivo, a janela que vale é sempre a do dono do número que sai: mensagem sua que sai pelo gateway obedece à janela do gateway (7h–22h), não à sua.
Callback
Em vez de consultar, você pode receber um POST a cada mudança de status e a
cada mensagem recebida. Ver docs/api-callbacks.md.