Pular para o conteúdo principal

Mídia

Há duas formas de mandar um arquivo, e a escolha entre elas muda bastante o desempenho.

A Meta baixa o arquivo do seu servidor a cada envio.

curl -X POST https://api.joinotify.com/v1/106540352242922/messages \n -H 'Authorization: Bearer sk_live_xxx' \n -H 'Content-Type: application/json' \n -d '{
"messaging_product": "whatsapp",
"to": "5541987111527",
"type": "image",
"image": { "link": "https://exemplo.com/catalogo.png" }
}'

Bom para arquivo único, gerado sob demanda — um boleto, uma nota fiscal. A URL precisa ser pública, com Content-Type correto e sem redirecionamento para página de login.

Por id de mídia​

Você envia o arquivo uma vez e reutiliza o id.

1. Upload
curl -X POST https://api.joinotify.com/v1/106540352242922/media \
-H 'Authorization: Bearer sk_live_xxx' \
-F 'messaging_product=whatsapp' \
-F '[email protected];type=image/png'
{ "id": "1234567890" }
2. Envio, quantas vezes quiser
curl -X POST https://api.joinotify.com/v1/106540352242922/messages \n -H 'Authorization: Bearer sk_live_xxx' \n -H 'Content-Type: application/json' \n -d '{
"messaging_product": "whatsapp",
"to": "5541987111527",
"type": "image",
"image": { "id": "1234567890" }
}'

Para disparo em massa, sempre o id da mídia. Com link, mil envios são mil downloads no seu servidor. O arquivo fica disponível na Meta por 30 dias.

O upload tem limite próprio: 60 requisições por minuto.

Limites por tipo​

TipoFormatos aceitosTamanho
ImagemJPEG, PNG5 MB
VídeoMP4, 3GPP — H.264 + AAC16 MB
ÁudioAAC, AMR, MP3, MP4 Audio, OGG (só OPUS)16 MB
Documentoqualquer100 MB
FigurinhaWebP100 KB estática · 500 KB animada

Vídeo com outro codec é aceito no upload e falha na entrega, sem erro claro. Se um vídeo "some", confira o codec antes de qualquer outra coisa.

Recebendo mídia​

Quando o cliente manda um arquivo, o webhook traz apenas o id — não o conteúdo:

{
"messages": [
{
"from": "5541999999999",
"id": "wamid.HBgN...",
"type": "image",
"image": { "id": "9876543210", "mime_type": "image/jpeg", "sha256": "..." }
}
]
}

Para baixar, são dois passos.

1. Obter a URL temporária
curl https://api.joinotify.com/v1/9876543210 \
-H 'Authorization: Bearer sk_live_xxx'
{
"url": "https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=...",
"mime_type": "image/jpeg",
"file_size": 184320,
"id": "9876543210"
}
2. Baixar — o header Authorization é obrigatório
curl -L 'https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=...' \
-H 'Authorization: Bearer sk_live_xxx' \
-o recebido.jpg
Essa URL não é pública

Abrir o link no navegador devolve erro, e colocá-lo num <img src> não funciona. Ele só responde com o header Authorization.

Não guarde essa URL no seu banco como se fosse permanente: ela expira. Baixe o arquivo, salve no seu próprio storage e guarde a sua URL.

Fluxo recomendado ao receber​

async function baixarMidia(mediaId) {
const headers = { Authorization: `Bearer ${process.env.JOINOTIFY_TOKEN}` };

const meta = await fetch(`https://api.joinotify.com/v1/${mediaId}`, { headers });
const { url, mime_type } = await meta.json();

const arquivo = await fetch(url, { headers });
const buffer = Buffer.from(await arquivo.arrayBuffer());

// Guarde no seu storage e devolva a SUA URL.
return storage.salvar(buffer, { mimeType: mime_type });
}

Faça isso de forma assíncrona, fora do handler do webhook — o seu endpoint precisa responder 2xx em poucos segundos, ou a entrega é considerada falha e reenviada.

Apagando​

curl -X DELETE https://api.joinotify.com/v1/1234567890 \
-H 'Authorization: Bearer sk_live_xxx'

Mensagens já entregues com aquele arquivo continuam funcionando para o cliente. Apagar só libera o armazenamento e impede novos envios com aquele id.