# wapp-api — envio de mídia Complementa `docs/api.md`. Autenticação, códigos de erro e consulta de status são os mesmos de lá. ## Como mandar Mesma rota do texto, `POST /api/mensagens`, mas em **`multipart/form-data`** em vez de JSON. O arquivo vai na parte **`arquivo`**; os demais campos vão como campos de formulário. Multipart e não base64 no JSON de propósito: o upload é derramado para arquivo temporário e a memória do servidor não acompanha o tamanho do anexo. O base64 acontece só no último salto, do worker para a Evolution — o arquivo **nunca** é exposto por URL. | Campo | Obrigatório | Observação | |---|---|---| | `arquivo` | sim | a parte com o arquivo em si | | `instancia` | sim | nome da instância | | `numero` | sim | mesma normalização do texto | | `tipo` | sim | `imagem`, `documento`, `video` ou `audio` | | `conteudo` | não | legenda (imagem/vídeo/documento) | | `nome_arquivo` | não | nome exibido; sem ele usa o nome do upload | | `nota_de_voz` | não | só para `tipo=audio`; padrão **`true`** | | `agendado_para` | não | ISO 8601 | O `tipo` precisa bater com o mimetype real do arquivo. Se mandar um PDF dizendo `tipo=imagem`, a resposta é **400** e nada é gravado. ## Tipos aceitos | mimetype | `tipo` | Extensão | |---|---|---| | `application/pdf` | `documento` | `.pdf` | | `image/jpeg` | `imagem` | `.jpg` | | `image/png` | `imagem` | `.png` | | `video/mp4` | `video` | `.mp4` | | `audio/ogg`, `audio/mpeg`, `audio/mp4` | `audio` | `.ogg`, `.mp3`, `.m4a` | Qualquer outro mimetype: **400**. ## Áudio: nota de voz ou anexo - `nota_de_voz=true` (padrão) → bolha de nota de voz, com onda sonora. A conversão para ogg/opus é feita pela Evolution. - `nota_de_voz=false` → anexo de áudio comum, com player de arquivo. ## Tamanho Teto de **16 MB por arquivo**, que é o limite do WhatsApp para mídia tocada dentro da conversa. Acima disso: **400**. O corpo inteiro da requisição é limitado a **20 MB** (a folga é o overhead do multipart). Passar disso devolve **413**, com `limite_bytes` na resposta. Vídeo acima de 16 MB no WhatsApp só existe enviado como *documento*, e aí perde o player — vira anexo para baixar. Se precisar disso, fale comigo antes: muda o desenho. ## Exemplo em Python ```python import os import requests API = 'http://wapp-api.local' CABECALHOS = {'X-API-Key': os.environ['WAPP_API_KEY']} with open('boleto.pdf', 'rb') as arquivo: resposta = requests.post( f'{API}/api/mensagens', headers=CABECALHOS, data={ 'instancia': 'principal', 'numero': '(11) 99999-8888', 'tipo': 'documento', 'conteudo': 'Segue seu boleto.', 'nome_arquivo': 'boleto-agosto.pdf', }, files={'arquivo': ('boleto.pdf', arquivo, 'application/pdf')}, timeout=60, ) resposta.raise_for_status() print(resposta.json()['id']) ``` Nota de voz é a mesma chamada com `'tipo': 'audio'` e o arquivo de áudio. ## Exemplo em curl ```bash curl -X POST http://wapp-api.local/api/mensagens \ -H "X-API-Key: $WAPP_API_KEY" \ -F 'instancia=principal' \ -F 'numero=(11) 99999-8888' \ -F 'tipo=documento' \ -F 'conteudo=Segue seu boleto.' \ -F 'arquivo=@boleto.pdf;type=application/pdf' ``` ## Onde o arquivo fica Em disco no servidor, sob `MIDIA_DIR/AAAA/MM/.`, modo `0640` e **nunca servido pelo Apache**. O banco guarda só os metadados (`arquivo_caminho`, `mimetype`, `tamanho_bytes`). Ainda **não existe rotina de expurgo**: os arquivos ficam até serem apagados à mão. A coluna `arquivo_expurgado_em` já está no schema para quando ela for escrita — é o que vai distinguir "a limpeza apagou" de "o arquivo se perdeu". Se o worker tentar enviar um anexo que sumiu, a mensagem vai para `falhou` com o motivo explícito.