# Enviar mídia (imagem · documento · áudio · vídeo)

`POST /v1/messages`

**O Connect não armazena arquivos.** Para mandar um arquivo seu, **hospede-o e mande o link dele** (`link`) — quem baixa é a **Meta**, não nós. Esse é o caminho principal, não a alternativa.

**Os identificadores (`id`) são os de arquivos que você RECEBEU**: chegam dentro do evento de uma mensagem recebida (`data.message.image.id`, `.document.id`, …). **Não há endpoint de upload** — `GET /v1/media/:mediaId` é só de download —, então **não existe forma de obter um `id` para um arquivo seu**.

⚠ E a parte incômoda, dita como é: a Meta **costuma** permitir reutilizar um identificador recebido para responder **do mesmo número**, mas **não garante** e nós **ainda não verificamos contra a Meta real**. Não afirmamos nem negamos. Se importa para você que saia sempre, use o link.

**Quer mandar SEMPRE o mesmo arquivo** — uma lista de preços, um manual, um catálogo? **Hospede-o e mande o link.** É a resposta completa: não há um `id` próprio para guardar e reutilizar. E não é uma limitação disfarçada — **não guardamos arquivos porque não guardamos conteúdo** (nem o texto das suas mensagens, salvo o histórico de Coexistence que você escolhe receber: criptografado e por 7 dias no máximo). É exatamente o que a nossa política de privacidade promete, aplicado aqui.

**Como se manda.** POST /v1/messages com `type` `image`/`document`/`audio`/`video` e, dentro do objeto desse tipo, **`link` ou `id` — exatamente um dos dois**. `caption` para image/document/video; `audio` **não** aceita caption; `document` pode levar `filename` (o nome que quem recebe vê).

**O que o link precisa para a Meta aceitá-lo:** ser **https** e **apontar direto para o arquivo** (que a resposta sejam os bytes, sem login nem página intermediária); trazer o **`Content-Type` correto** — se não coincidir com o arquivo, a Meta recusa; e respeitar os **limites da Meta**: imagem JPEG/PNG **5 MB**, áudio (aac · amr · mp3 · m4a · ogg _só OPUS_) **16 MB**, vídeo mp4/3gpp **16 MB**, documento (pdf · doc/docx · xls/xlsx · ppt/pptx · txt) **100 MB**.

⚠ **A armadilha mais comum: Google Drive, Dropbox e similares NÃO servem.** Um link de "compartilhar" devolve uma **página HTML** intermediária, não os bytes do arquivo: a Meta baixa essa página e recusa o envio. Sirva-o a partir de uma URL que responda com o arquivo direto.

## Exemplos

### cURL

```bash
curl -X POST https://api.waiaconnect.com/v1/messages \
  -H "Authorization: Bearer wc_live_YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"connectionId":"conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","to":"5493511234567","type":"image","image":{"link":"https://example.com/product.jpg","caption":"New product 📦"}}'
# document: {"type":"document","document":{"link":"https://…/invoice.pdf","filename":"invoice.pdf","caption":"Your invoice"}}
# audio (no caption): {"type":"audio","audio":{"link":"https://…/note.ogg"}}
# video: {"type":"video","video":{"link":"https://…/demo.mp4","caption":"Demo"}}
# by media id instead of a link: {"image":{"id":"1234567890"}}
# ...but the only ids that exist are the ones you RECEIVED (from a message.received
# event); there is no upload endpoint. To send a file of your own, host it and link it.
```

### Node.js

```javascript
// Media is sent by { link } (Meta fetches the URL) or { id }. The only media ids that
// exist are the ones you RECEIVED: there is no upload endpoint. Host your own files.
const res = await fetch("https://api.waiaconnect.com/v1/messages", {
  method: "POST",
  headers: {
    "Authorization": "Bearer wc_live_YOUR_API_KEY",
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "connectionId": "conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "to": "5493511234567",
  "type": "image",
  "image": {
    "link": "https://example.com/product.jpg",
    "caption": "New product 📦"
  }
})
});
console.log(await res.json()); // { id: "msg_…", status: "queued" }
```

### PHP

```php
<?php
// Media is sent by ["link" => …] (Meta fetches it) or ["id" => …]. The only media ids
// that exist are the ones you RECEIVED: there is no upload endpoint. Host your own files.
$ch = curl_init("https://api.waiaconnect.com/v1/messages");
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer wc_live_YOUR_API_KEY",
    "Idempotency-Key: " . bin2hex(random_bytes(16)),
    "Content-Type: application/json",
  ],
  CURLOPT_POSTFIELDS => json_encode(["connectionId" => "conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","to" => "5493511234567","type" => "image","image" => ["link" => "https://example.com/product.jpg","caption" => "New product 📦"]]),
]);
echo curl_exec($ch);
```

### Python

```python
import requests, uuid
# Media is sent by {"link": …} (Meta fetches it) or {"id": …}. The only media ids that
# exist are the ones you RECEIVED: there is no upload endpoint. Host your own files.
res = requests.post("https://api.waiaconnect.com/v1/messages",
  headers={
    "Authorization": "Bearer wc_live_YOUR_API_KEY",
    "Idempotency-Key": str(uuid.uuid4()),
  },
  json={"connectionId":"conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","to":"5493511234567","type":"image","image":{"link":"https://example.com/product.jpg","caption":"New product 📦"}})
print(res.json())  # {"id": "msg_…", "status": "queued"}
```

## Notas

- ⚠ Um identificador que chega num webhook **vence na Meta em poucos dias** (o prazo é definido pela Meta). Vencido, não serve nem para baixá-lo nem para reenviá-lo.
- A Meta **guarda o seu link em cache por 10 minutos**. Se você trocar o arquivo por trás da MESMA URL, acrescente uma query string aleatória (`?v=…`) ou vai mandar o antigo.
- **Se o link não servir, você fica sabendo em dois momentos.** (1) Ao aceitar, com um 400 e o seu `code`: `MEDIA_LINK_OR_ID_REQUIRED` (não mandou nenhum), `MEDIA_LINK_AND_ID` (mandou os dois), `MEDIA_LINK_INVALID` (não é uma URL https bem formada), `AUDIO_CAPTION_NOT_ALLOWED`.
- (2) Se passou pela validação mas **a Meta não conseguiu baixá-lo**, a recusa chega DEPOIS do 202: consulte `GET /v1/messages/:id` → `lastErrorCode` = `MEDIA_DOWNLOAD_FAILED` (link inacessível ou página intermediária), `MEDIA_FILE_REJECTED` (formato ou tamanho) ou `MEDIA_TYPE_UNSUPPORTED`. O que fazer: servir o arquivo direto, com o seu `Content-Type`, dentro dos limites acima.
- Para **baixar** um arquivo que mandaram para você, veja «Baixar mídia recebida».
