> ## Documentation Index
> Fetch the complete documentation index at: https://docs.1to1ai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Enviar mídia

> Envie um arquivo e obtenha um file_uuid para enviá-lo em uma ação.

Para enviar imagens, vídeo, áudio ou documentos, primeiro você envia o arquivo e
obtém um `file_uuid`, que depois passa a uma ação de envio.

<Steps>
  <Step title="Peça uma URL de upload">
    ```http theme={null}
    POST /files/request-upload
    ```

    Com `{ filename, mime_type }`. Responde `201` com `file_uuid`,
    `upload_url`, `upload_token`, `storage_path` e `expires_at`.
  </Step>

  <Step title="Envie o binário">
    ```http theme={null}
    PUT {upload_url}
    ```

    Envie o arquivo para a `upload_url` que você recebeu, antes que expire
    (`expires_at`).
  </Step>

  <Step title="Confirme">
    ```http theme={null}
    POST /files/confirm
    ```

    Com `{ file_uuid }`. Responde `200` com `file_uuid`, `mime_type`,
    `size_bytes`, `requires_transcription`, `download_url` e `expires_at`. A
    partir daqui o `file_uuid` é enviável.
  </Step>
</Steps>

<Note>
  Você não declara mais `size_bytes` ao pedir a URL: o server mede o tamanho real
  ao confirmar. Na resposta de confirm, `requires_transcription` sinaliza se este
  `file_uuid` exigirá uma transcrição ao usá-lo em um envio — porque o tipo de
  arquivo não é transcritível automaticamente ou passa de 20 MB. É uma dica para
  prepará-la com antecedência.

  Valide o tamanho do arquivo localmente antes de enviá-lo: o limite por tipo e a cota de armazenamento são aplicados ao confirmar, com o binário já transferido. Um negócio com o storage desabilitado (`quota_bytes = 0`) ou já acima do teto é rejeitado em `request-upload` com `413` antes da transferência.
</Note>

## Limites de tamanho

| Categoria    | Máximo                                     |
| ------------ | ------------------------------------------ |
| Imagem       | 5 MB                                       |
| Vídeo        | 16 MB                                      |
| Áudio        | 16 MB                                      |
| Documento    | 100 MB                                     |
| `text/plain` | 5 MB (limite próprio, menor que Documento) |

<Note>
  **Uploads pendentes concorrentes:** um negócio pode ter no máximo **100 uploads sem confirmar** por vez. Ao ultrapassar, `request-upload` responde `429 TOO_MANY_PENDING_UPLOADS` com `Retry-After` — confirme ou deixe expirar os pendentes antes de pedir mais. O fluxo normal (request → PUT → confirm) nunca o atinge; só afeta integrações que pedem muitos `request-upload` antecipadamente sem confirmar.
</Note>

## Enviar o arquivo

Uma vez confirmado, passe o `file_uuid` a uma ação de envio — como mídia
direta em `send_message`, ou como header de um template:

```jsonc theme={null}
{
  "conversation": { "phone": "+525512345678", "channel": "ch_7A9K2M4Q" },
  "actions": [
    {
      "type": "send_message",
      "template": {
        "name": "promo_verano",
        "language": "es_MX",
        "header": {
          "type": "document",
          "file_uuid": "7b8a1c2d-3e4f-5678-90ab-cdef12345678"
        },
        "body_variables": [{ "index": 1, "value": "Ana" }]
      }
    }
  ]
}
```

O `header.type` ∈ `image` | `video` | `document` leva `file_uuid` (`document`
aceita um `filename` opcional) e uma `transcription` **obrigatória** quando a visão
não pode transcrever o arquivo (o `requires_transcription` acima antecipa isso). Em
`send_message` no modo mídia, o `file_uuid` vai no nível da ação com `body` como
legenda opcional (o áudio não admite legenda) e a mesma regra de `transcription`.

<Tip>
  Se o preflight rejeitar o grupo, a resposta é um `4xx` síncrono e nenhuma
  ação é executada. Ver [Erros](/pt/errors).
</Tip>

<Warning>
  **A mídia enviada é efêmera.** Não é um armazenamento permanente: sob pressão da cota de
  armazenamento, o sistema pode excluir automaticamente os arquivos **por antiguidade do
  último uso** (os que estão há mais tempo sem serem enviados saem primeiro; reutilizar um
  `file_uuid` em qualquer conversa renova seu "último uso" e o mantém vivo para todas). Guarde
  sua própria cópia se precisar de um registro durável. A API não oferece um download estável
  por `file_uuid`; o único download é a `download_url` assinada que `/files/confirm` retorna,
  válida por tempo limitado. Reenviar um `file_uuid` já excluído responde `FILE_NOT_FOUND`.

  **Reutilização entre conversas.** O mesmo `file_uuid` pode ser enviado a várias
  conversas sem reenviar o arquivo, mas o arquivo é único: se a limpeza por cota o
  excluir, ele é perdido em **todas** as conversas que o referenciam. Se precisar de
  independência entre conversas, envie um arquivo por conversa.
</Warning>

## Exemplo executável

O fluxo completo em três chamadas. O `file_uuid` que o passo 3 confirma é o que
você depois passa a uma ação de envio.

**1 · Peça uma URL de upload**

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://app.1to1ai.com/api/v1/public/{slug}/files/request-upload" \
    -H "Authorization: Bearer sk_1to1_sua_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "filename": "comprovante.pdf",
      "mime_type": "application/pdf"
    }'
  ```

  ```json Resposta 201 theme={null}
  {
    "file_uuid": "7b8a1c2d-3e4f-5678-90ab-cdef12345678",
    "upload_url": "https://<project>.supabase.co/storage/v1/object/upload/sign/business-files/...",
    "upload_token": "eyJ...",
    "storage_path": "<business_uuid>/api/pending/1729383000_7b8a1c2d....pdf",
    "expires_at": "2026-07-22T15:30:00Z"
  }
  ```
</CodeGroup>

**2 · Envie o binário** para a `upload_url` antes que expire

```bash theme={null}
curl -X PUT "{upload_url}" \
  -H "Content-Type: application/pdf" \
  --data-binary @comprovante.pdf
```

**3 · Confirme**

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://app.1to1ai.com/api/v1/public/{slug}/files/confirm" \
    -H "Authorization: Bearer sk_1to1_sua_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "file_uuid": "7b8a1c2d-3e4f-5678-90ab-cdef12345678"
    }'
  ```

  ```json Resposta 200 theme={null}
  {
    "file_uuid": "7b8a1c2d-3e4f-5678-90ab-cdef12345678",
    "mime_type": "application/pdf",
    "size_bytes": 48213,
    "requires_transcription": false,
    "download_url": "https://<project>.supabase.co/storage/v1/object/sign/...",
    "expires_at": "2026-07-22T16:30:00Z"
  }
  ```
</CodeGroup>

## Com transcrição obrigatória

Se o arquivo não for auto-transcrevível pela visão (tipo não suportado como
`.docx`/`.xlsx`, ou maior que 20 MB), a resposta de `/confirm` antecipa
isso com `requires_transcription: true`:

```json Resposta 200 (requer transcrição) theme={null}
{
  "file_uuid": "9c1b2a3d-4e5f-6789-01ab-cdef23456789",
  "mime_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  "size_bytes": 91240,
  "requires_transcription": true,
  "download_url": "https://<project>.supabase.co/storage/v1/object/sign/...",
  "expires_at": "2026-07-22T16:30:00Z"
}
```

Nesse caso, ao enviá-lo você deve incluir `transcription` — como mídia primária em
`send_message` ou como `template.header.transcription` — ou a ação falha com
`TRANSCRIPTION_REQUIRED` / `TEMPLATE_HEADER_TRANSCRIPTION_MISSING`:

```bash Enviar com transcrição theme={null}
curl -X POST "https://app.1to1ai.com/api/v1/public/{slug}/conversation/actions" \
  -H "Authorization: Bearer sk_1to1_sua_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation": { "phone": "+525512345678", "channel": "ch_7A9K2M4Q" },
    "actions": [
      {
        "type": "send_message",
        "file_uuid": "9c1b2a3d-4e5f-6789-01ab-cdef23456789",
        "body": "Seu contrato 📄",
        "transcription": "Contrato de serviço (3 páginas): plano Pro mensal, renovação automática, cancelável com 30 dias de aviso."
      }
    ]
  }'
```
