> ## Documentation Index
> Fetch the complete documentation index at: https://developers.nuvia.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Envio de arquivo

> Envie imagem, vídeo, áudio e documento para uma conversa, em dois passos

Enviar um arquivo pela API são **duas chamadas**: primeiro você sobe o arquivo e recebe um
identificador, depois envia a mensagem referenciando esse identificador.

```
1. POST /v1/resource/upload-attachment   (multipart)  →  { "_id": "..." }
2. POST /v1/messages/send-document       (JSON, com o _id do passo 1)
```

Não existe uma chamada única que receba o arquivo e envie. Tentar mandar o arquivo direto no
endpoint de envio resulta em erro.

Tudo aqui usa o escopo `messages:create`, o mesmo do envio de texto. Se a sua chave já envia
mensagem, ela já envia arquivo.

## Passo 1: subir o arquivo

<Steps>
  <Step title="Envie o arquivo em multipart/form-data">
    Dois campos obrigatórios: `file` com o binário e `fileType` com a categoria.

    ```bash cURL theme={null}
    curl -X POST https://api.nuvia.ai/v1/resource/upload-attachment \
      -H "Authorization: Bearer $NUVIA_API_KEY" \
      -F "file=@orcamento.pdf" \
      -F "fileType=DOCUMENT"
    ```
  </Step>

  <Step title="Guarde o `_id` da resposta">
    A resposta traz o registro do anexo. O campo que importa para o passo 2 é o `_id`:

    ```json theme={null}
    {
      "_id": "65f1a2b3c4d5e6f7a8b9c0d1",
      "extension": "pdf",
      "external_url": "https://s3.amazonaws.com/bucket/orcamento.pdf",
      "file_type": "DOCUMENT",
      "meta": {
        "mimeType": "application/pdf",
        "size": 102400,
        "fileName": "orcamento.pdf"
      }
    }
    ```

    <Tip>
      O anexo fica salvo e pode ser reaproveitado. Para mandar o mesmo arquivo a vários contatos,
      suba uma vez e use o mesmo `_id` em cada envio.
    </Tip>
  </Step>
</Steps>

### Valores de `fileType`

| `fileType` | Formatos aceitos                    | Endpoint de envio                 |
| ---------- | ----------------------------------- | --------------------------------- |
| `DOCUMENT` | PDF, DOC, DOCX, XLS, XLSX, PPT, TXT | `POST /v1/messages/send-document` |
| `IMAGE`    | JPG, PNG, GIF, WEBP                 | `POST /v1/messages/send-image`    |
| `VIDEO`    | MP4, 3GP                            | `POST /v1/messages/send-video`    |
| `AUDIO`    | MP3, OGG, AAC, AMR                  | `POST /v1/messages/send-audio`    |
| `STICKER`  | WEBP                                | `POST /v1/messages/send-image`    |

O `fileType` do upload precisa combinar com o endpoint de envio. Subir como `DOCUMENT` e tentar
enviar por `send-image` não funciona.

## Passo 2: enviar para a conversa

O corpo é JSON, com a conversa de destino e o objeto `message`:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.nuvia.ai/v1/messages/send-document \
    -H "Authorization: Bearer $NUVIA_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "conversationId": "65f1a2b3c4d5e6f7a8b9c0d3",
      "message": {
        "content": "Segue o orçamento que combinamos.",
        "contentType": "DOCUMENT",
        "attachment": "65f1a2b3c4d5e6f7a8b9c0d1"
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  const upload = new FormData();
  upload.append("file", file);
  upload.append("fileType", "DOCUMENT");

  const { _id } = await fetch("https://api.nuvia.ai/v1/resource/upload-attachment", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.NUVIA_API_KEY}` },
    body: upload,
  }).then((r) => r.json());

  await fetch("https://api.nuvia.ai/v1/messages/send-document", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.NUVIA_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      conversationId,
      message: {
        content: "Segue o orçamento que combinamos.",
        contentType: "DOCUMENT",
        attachment: _id,
      },
    }),
  });
  ```

  ```python Python theme={null}
  import os
  import requests

  headers = {"Authorization": f"Bearer {os.environ['NUVIA_API_KEY']}"}

  with open("orcamento.pdf", "rb") as f:
      upload = requests.post(
          "https://api.nuvia.ai/v1/resource/upload-attachment",
          headers=headers,
          files={"file": f},
          data={"fileType": "DOCUMENT"},
      ).json()

  requests.post(
      "https://api.nuvia.ai/v1/messages/send-document",
      headers=headers,
      json={
          "conversationId": conversation_id,
          "message": {
              "content": "Segue o orçamento que combinamos.",
              "contentType": "DOCUMENT",
              "attachment": upload["_id"],
          },
      },
  )
  ```
</CodeGroup>

### Campos de `message`

| Campo           | Tipo   | Obrigatório | Descrição                                                     |
| --------------- | ------ | ----------- | ------------------------------------------------------------- |
| `attachment`    | string | Sim         | O `_id` devolvido pelo upload.                                |
| `contentType`   | string | Sim         | `DOCUMENT`, `IMAGE`, `VIDEO` ou `AUDIO`, conforme o endpoint. |
| `content`       | string | Não         | Texto que acompanha o arquivo, como legenda.                  |
| `quoteSourceId` | string | Não         | Id da mensagem que você quer citar (veja abaixo).             |

<Warning>
  O campo `contentAttributes.inReplyToExternalId` está **descontinuado e sem efeito**. Para
  responder citando uma mensagem, use `quoteSourceId`.
</Warning>

### Citar uma mensagem

`quoteSourceId` espera o id da mensagem **no canal**, não o `_id` da Nuvia. Mandar o `_id` não
cita nada e não devolve erro.

| Canal              | O que é o id |
| ------------------ | ------------ |
| WhatsApp (Meta)    | `wamid`      |
| Evolution          | `key.id`     |
| LinkedIn (Unipile) | `message_id` |

Esse valor chega no campo `source_id` de cada mensagem devolvida por
`GET /v1/messages/conversation/{id}`. Leia de lá e mande de volta em `quoteSourceId`. A mensagem
citada precisa ser da mesma conversa.

## Limites

* **Upload**: até 100 MB por arquivo.
* **WhatsApp**: imagem até 5 MB, áudio e vídeo até 16 MB, documento até 100 MB. O limite do canal
  vale mesmo que o upload tenha aceitado o arquivo, então um vídeo de 50 MB sobe mas não chega ao
  contato.
* **Formatos**: apenas os aceitos pelo WhatsApp, listados na tabela acima.

## Erros comuns

| Situação                                         | Resposta                   |
| ------------------------------------------------ | -------------------------- |
| Chave sem o escopo `messages:create`             | `403`                      |
| Arquivo acima de 100 MB                          | `413`, e nada é armazenado |
| `fileType` ausente ou fora da lista              | `400`                      |
| `attachment` que não existe, ou de outra empresa | `400`                      |
| Token ausente, inválido ou revogado              | `401`                      |

## Próximos passos

<CardGroup cols={2}>
  <Card title="Referência da API" icon="code" href="/api-reference/messages">
    Todos os endpoints de envio, com parâmetros e respostas.
  </Card>

  <Card title="Exemplos de integração" icon="puzzle-piece" href="/guias/exemplos-integracao">
    Casos completos de ponta a ponta.
  </Card>
</CardGroup>
