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.