GET
/mensagens/{id}/midiaBaixar mídia de uma mensagem
mensagens:ler
Arquivo binário, com Content-Type original e Content-Disposition. Aceita Range, sem redirecionar. Use item com o id de midia[] ou o índice a partir de zero. Mídia sob demanda retorna 202 midia_baixando com Retry-After; mídia indisponível retorna 409 midia_indisponivel.
GET /mensagens/{id}/midia
curl "https://chat.forsi.com.br/api/v1/mensagens/4e8cb5d0-2d89-4fc2-93bb-c8e5e17d4629/midia?item=0" \
-H "Authorization: Bearer $FORSI_CHAVE" \
--output arquivo-midiaconst resposta = await fetch('https://chat.forsi.com.br/api/v1/mensagens/4e8cb5d0-2d89-4fc2-93bb-c8e5e17d4629/midia?item=0', {
headers: {
Authorization: `Bearer ${process.env.FORSI_CHAVE}`,
},
});
if (resposta.status === 202) {
const { erro } = await resposta.json();
throw new Error(`${erro.codigo}: tente novamente em ${resposta.headers.get('Retry-After') ?? '3'} s`);
}
if (!resposta.ok) {
const { erro } = await resposta.json();
throw new Error(`${resposta.status} ${erro.codigo}: ${erro.mensagem}`);
}
const bytes = await resposta.arrayBuffer();
await (await import('node:fs/promises')).writeFile('arquivo-midia', Buffer.from(bytes));import os
import requests
resposta = requests.get(
"https://chat.forsi.com.br/api/v1/mensagens/4e8cb5d0-2d89-4fc2-93bb-c8e5e17d4629/midia",
headers={
"Authorization": f"Bearer {os.environ['FORSI_CHAVE']}",
},
params={
"item": "0",
},
timeout=30,
)
if resposta.status_code == 202:
erro = resposta.json()["erro"]
raise RuntimeError(f"{erro['codigo']}: tente novamente em {resposta.headers.get('Retry-After', '3')} s")
if not resposta.ok:
erro = resposta.json()["erro"]
raise RuntimeError(f"{resposta.status_code} {erro['codigo']}: {erro['mensagem']}")
with open("arquivo-midia", "wb") as arquivo:
for bloco in resposta.iter_content(chunk_size=64 * 1024):
if bloco:
arquivo.write(bloco)Resposta 200 · arquivo binário
HTTP/1.1 200 OK
Content-Type: audio/ogg
Content-Disposition: attachment; filename="voz.ogg"
Accept-Ranges: bytes
[bytes do arquivo]Parâmetros no caminho#
iduuidobrigatórioNo caminho da URL.
Parâmetros de consulta#
itemuuid ou stringopcionalId de midia[] ou índice a partir de zero. Sem item, baixa a primeira mídia.
Resposta#
O arquivo em si, com Content-Type e Content-Disposition. 206 para Range, 202 enquanto a mídia baixa.
Erros#
Todo erro vem como {"erro": {"codigo", "mensagem"}}. Trate pelo codigo: ele não muda.
| Status | Quando |
|---|---|
| 401 | Chave ausente ou inválida (resposta igual para qualquer motivo). |
| 403 | Plano sem API, escopo insuficiente ou https/origem recusados. |
| 404 | Não existe nesta organização ou não há mídia. |
| 409 | A mídia ainda não está disponível para download (midia_indisponivel). |
| 416 | Intervalo Range inválido ou fora do arquivo. |
| 422 | Dados inválidos ou regra de negócio (ex.: janela_fechada; conta_restrita = a Meta restringiu a conta por spam: erro traz os campos de RestricaoMeta, como ate, escopo, motivo e retry_after_s). |
| 429 | Limite de requisições. Veja Retry-After. |
Códigos de erro que esta área pode devolver22
tipo_invalidotipo deve ser texto, imagem, video, audio, documento ou modelo.texto_vazioMensagem de texto precisa de texto.texto_longoTexto longo demais (máximo de 4096 caracteres).midia_invalidaLink de mídia inválido: use https com um endereço público.midia_indisponivelO arquivo desta mídia está indisponível.midia_baixandoO download desta mídia está na fila. Tente novamente após Retry-After.janela_fechadaA janela de 24 horas desta conversa está fechada. Na API oficial do WhatsApp, só um modelo aprovado reabre a conversa.conta_restritaA Meta restringiu esta conta do WhatsApp por spam. Nada foi enviado: erro.ate diz até quando (erro.retry_after_s e o cabeçalho Retry-After, em segundos), erro.escopo o que está barrado e erro.motivo o código. Quem administra pode desligar a trava em Configurações > API.caixa_obrigatoriaA organização tem mais de um WhatsApp conectado: informe caixa_id (veja GET /me).caixa_sem_conexaoNenhum WhatsApp conectado nesta caixa.caixa_inexistenteCaixa não encontrada (veja GET /me).canal_sem_iniciarEste canal não permite começar conversa por telefone. Use uma caixa de WhatsApp.modelo_sem_api_oficialModelos só saem pela API oficial do WhatsApp. Conecte a API oficial nesta caixa.modelo_inexistenteModelo não encontrado nesta caixa (veja GET /modelos).telefone_invalidoTelefone inválido. Mande com DDI e DDD.conversa_inexistenteConversa não encontrada.mensagem_inexistenteMensagem não encontrada.canal_oficial_indisponivelcanal "oficial": a API oficial do WhatsApp não está conectada nesta caixa. Nada foi enviado pelo QR.canal_oficial_sem_grupocanal "oficial": a API oficial do WhatsApp não envia para grupo. Use "qr" ou omita o campo.canal_qr_indisponivelcanal "qr": o WhatsApp por QR não está conectado nesta caixa. Nada foi enviado pela API oficial.canal_qr_sem_modelocanal "qr": modelos só saem pela API oficial do WhatsApp. Use "oficial" ou omita o campo.canal_so_whatsappcanal "oficial"/"qr" só vale em caixa de WhatsApp. Omita o campo (ou use "auto").
Os erros que valem para qualquer rota (chave, limite, JSON) estão em Erros.