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

POST /send/media

Envia diferentes tipos de mídia para um contato, grupo ou canal/newsletter. Suporta URLs ou arquivos base64.

## Tipos de Mídia Suportados
- **`image`**: Imagens (JPG preferencialmente)
- **`video`**: Vídeos (apenas MP4)
- **`videoplay`**: Vídeo com comportamento visual de autoplay/loop no WhatsApp
- **`document`**: Documentos (PDF, DOCX, XLSX, etc)
- **`audio`**: Áudio comum (MP3 ou OGG)
- **`myaudio`**: Mensagem de voz (alternativa ao PTT)
- **`ptt`**: Mensagem de voz (Push-to-Talk)
- **`ptv`**: Mensagem de vídeo (Push-to-Video)
- **`sticker`**: Figurinha/Sticker

## Recursos Específicos
- **Upload por URL ou base64**
- **Caption/legenda** opcional com suporte a placeholders
- **Nome personalizado** para documentos (`docName`)
- **Geração automática de thumbnails para imagens e vídeos** quando `thumbnail` não é informado
- **Compressão otimizada** conforme o tipo
- **`viewOnce`** recomendado para mídia compatível

## Envio para Newsletter

Para enviar mídia para um canal, use o mesmo campo `number`, mas informe o JID completo do canal:
- Exemplo: `120363123456789012@newsletter`

```json
{
  "number": "120363123456789012@newsletter",
  "type": "image",
  "file": "https://exemplo.com/foto.jpg",
  "text": "Imagem publicada no canal"
}
```

## Campos Comuns

Este endpoint suporta todos os **campos opcionais comuns** documentados na tag **"Enviar Mensagem"**, incluindo:
`delay`, `readchat`, `readmessages`, `replyid`, `mentions`, `forward`, `track_source`, `track_id`, placeholders e envio para grupos.

## Exemplos Básicos

## Visualização Única (`viewOnce`)

O campo `viewOnce` é recomendado quando quiser mídia de visualização única e hoje produz efeito para os tipos:
`image`, `video`, `videoplay`, `ptv`, `audio`, `myaudio` e `ptt`.

Para `document`, `sticker` e demais endpoints de envio, o campo é ignorado silenciosamente.

## Thumbnail personalizado

Use `thumbnail` em `image`, `video`, `videoplay`, `ptv` ou
`document`. Aceita URL HTTP/HTTPS, Data URL ou base64 de imagem com até
1 MiB e 4096 px por dimensão. A API converte para JPEG e prioriza essa
imagem em relação à miniatura automática. Para documentos, envie uma
imagem de pelo menos 480 px para uma prévia mais nítida no WhatsApp Web.
Documentos sem `thumbnail` não recebem miniatura automática.

Ao reenviar o mesmo documento, reutilize a mesma miniatura: o WhatsApp
pode associar a prévia ao conteúdo do arquivo também em mensagens antigas.

### Imagem Simples
```json
{
  "number": "5511999999999",
  "type": "image",
  "file": "https://exemplo.com/foto.jpg"
}
```

### Documento com Nome
```json
{
  "number": "5511999999999",
  "type": "document",
  "file": "https://exemplo.com/contrato.pdf",
  "docName": "Contrato.pdf",
  "text": "Segue o documento solicitado"
}
```


## Autenticação

```json
[
  {
    "token": []
  }
]
```

```json
{
  "token": {
    "name": "token",
    "type": "apiKey",
    "in": "header"
  }
}
```

## Corpo da requisição

```json
{
  "required": true,
  "content": {
    "application/json": {
      "schema": {
        "type": "object",
        "properties": {
          "number": {
            "type": "string",
            "description": "ID do chat para o qual a mensagem será enviada. Pode ser um número de telefone em formato internacional, um ID de grupo (`@g.us`), um ID de usuário (com `@s.whatsapp.net` ou `@lid`) ou um ID de canal/newsletter (`@newsletter`).",
            "example": "5511999999999"
          },
          "type": {
            "type": "string",
            "description": "Tipo de mídia (image, video, videoplay, document, audio, myaudio, ptt, ptv, sticker)",
            "enum": [
              "image",
              "video",
              "videoplay",
              "document",
              "audio",
              "myaudio",
              "ptt",
              "ptv",
              "sticker"
            ],
            "example": "image"
          },
          "file": {
            "type": "string",
            "description": "URL ou base64 do arquivo",
            "example": "https://exemplo.com/imagem.jpg"
          },
          "text": {
            "type": "string",
            "description": "Texto descritivo (caption) - aceita placeholders",
            "example": "Veja esta foto!"
          },
          "docName": {
            "type": "string",
            "description": "Nome do arquivo (apenas para documents)",
            "example": "relatorio.pdf"
          },
          "thumbnail": {
            "type": "string",
            "description": "URL HTTP/HTTPS, Data URL ou base64 de imagem para image, video, videoplay, ptv e document. Até 1 MiB e 4096 px por dimensão. Tem prioridade sobre a miniatura automática; documentos sem este campo não recebem miniatura automática.",
            "example": "https://exemplo.com/thumb.jpg"
          },
          "mimetype": {
            "type": "string",
            "description": "MIME type do arquivo (opcional, detectado automaticamente)",
            "example": "application/pdf"
          },
          "replyid": {
            "type": "string",
            "description": "ID da mensagem para responder",
            "example": "3EB0538DA65A59F6D8A251"
          },
          "mentions": {
            "type": "string",
            "description": "Números para mencionar, separados por vírgula (só em grupos). Para mencionar todos, use all ou inclua @all ou @todos no texto da mensagem",
            "example": "5511999999999,5511888888888"
          },
          "readchat": {
            "type": "boolean",
            "description": "Marca conversa como lida após envio",
            "example": true
          },
          "readmessages": {
            "type": "boolean",
            "description": "Marca últimas mensagens recebidas como lidas",
            "example": true
          },
          "delay": {
            "type": "integer",
            "description": "Atraso em milissegundos antes do envio, durante o atraso aparecerá 'Digitando...' ou 'Gravando áudio...'",
            "example": 1000
          },
          "forward": {
            "type": "boolean",
            "description": "Marca a mensagem como encaminhada no WhatsApp",
            "example": true
          },
          "track_source": {
            "type": "string",
            "description": "Origem do rastreamento da mensagem",
            "example": "chatwoot"
          },
          "track_id": {
            "type": "string",
            "description": "ID para rastreamento da mensagem (aceita valores duplicados)",
            "example": "msg_123456789"
          },
          "async": {
            "type": "boolean",
            "description": "Se true, envia a mensagem de forma assíncrona via fila interna",
            "example": false
          },
          "viewOnce": {
            "type": "boolean",
            "description": "Recomendado para mídia com visualização única em tipos compatíveis (`image`, `video`, `videoplay`, `ptv`, `audio`, `myaudio`, `ptt`). Em tipos não compatíveis, o campo é ignorado silenciosamente.",
            "example": false
          }
        },
        "required": [
          "number",
          "type",
          "file"
        ]
      },
      "examples": {
        "image": {
          "summary": "Imagem",
          "description": "Envio de imagem simples",
          "value": {
            "number": "5511999999999",
            "type": "image",
            "file": "https://exemplo.com/foto.jpg"
          }
        },
        "imageWithCaption": {
          "summary": "Imagem com legenda",
          "description": "Imagem com texto descritivo",
          "value": {
            "number": "5511999999999",
            "type": "image",
            "file": "https://exemplo.com/foto.jpg",
            "text": "Veja esta foto!"
          }
        },
        "imageViewOnce": {
          "summary": "Imagem view once",
          "description": "Imagem enviada como visualização única",
          "value": {
            "number": "5511999999999",
            "type": "image",
            "file": "https://exemplo.com/foto.jpg",
            "text": "Abra uma vez",
            "viewOnce": true
          }
        },
        "document": {
          "summary": "Documento",
          "description": "Documento PDF com nome personalizado",
          "value": {
            "number": "5511999999999",
            "type": "document",
            "file": "https://exemplo.com/contrato.pdf",
            "docName": "Contrato.pdf",
            "text": "Segue o documento solicitado"
          }
        },
        "audio": {
          "summary": "Mensagem de voz",
          "description": "Arquivo de áudio como mensagem de voz",
          "value": {
            "number": "5511999999999",
            "type": "ptt",
            "file": "https://exemplo.com/audio.ogg"
          }
        },
        "video": {
          "summary": "Vídeo",
          "description": "Arquivo de vídeo com legenda",
          "value": {
            "number": "5511999999999",
            "type": "video",
            "file": "https://exemplo.com/video.mp4",
            "text": "Confira este vídeo!"
          }
        },
        "videoplay": {
          "summary": "Vídeo com autoplay",
          "description": "Vídeo MP4 enviado com comportamento visual de autoplay/loop no WhatsApp",
          "value": {
            "number": "5511999999999",
            "type": "videoplay",
            "file": "https://exemplo.com/video.mp4",
            "text": "Confira este vídeo"
          }
        },
        "ptv": {
          "summary": "Mensagem de vídeo",
          "description": "Arquivo de vídeo como mensagem de vídeo",
          "value": {
            "number": "5511999999999",
            "type": "ptv",
            "file": "https://exemplo.com/video.mp4"
          }
        },
        "sticker": {
          "summary": "Figurinha",
          "description": "Envio de figurinha/sticker",
          "value": {
            "number": "5511999999999",
            "type": "sticker",
            "file": "https://exemplo.com/sticker.webp"
          }
        },
        "newsletterImage": {
          "summary": "Imagem para newsletter",
          "description": "Publica uma imagem em um canal usando o JID completo `@newsletter`.",
          "value": {
            "number": "120363123456789012@newsletter",
            "type": "image",
            "file": "https://exemplo.com/foto.jpg",
            "text": "Imagem publicada no canal"
          }
        },
        "newsletterDocument": {
          "summary": "Documento para newsletter",
          "description": "Publica um documento em um canal usando o JID completo `@newsletter`.",
          "value": {
            "number": "120363123456789012@newsletter",
            "type": "document",
            "file": "https://exemplo.com/contrato.pdf",
            "docName": "Contrato.pdf",
            "text": "Documento publicado no canal"
          }
        }
      }
    }
  }
}
```

## Respostas

```json
{
  "200": {
    "description": "Mídia enviada com sucesso",
    "content": {
      "application/json": {
        "schema": {
          "allOf": [
            {
              "$ref": "#/components/schemas/Message"
            },
            {
              "type": "object",
              "properties": {
                "response": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "success"
                    },
                    "message": {
                      "type": "string",
                      "example": "Media sent successfully"
                    },
                    "fileUrl": {
                      "type": "string",
                      "example": "https://mmg.whatsapp.net/..."
                    }
                  }
                }
              }
            }
          ]
        }
      }
    }
  },
  "400": {
    "description": "Requisição inválida",
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "properties": {
            "error": {
              "type": "string",
              "example": "Invalid media type or file format"
            }
          }
        }
      }
    }
  },
  "401": {
    "description": "Não autorizado",
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "properties": {
            "error": {
              "type": "string",
              "example": "Invalid token"
            }
          }
        }
      }
    }
  },
  "413": {
    "description": "Arquivo muito grande",
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "properties": {
            "error": {
              "type": "string",
              "example": "File size exceeds limit"
            }
          }
        }
      }
    }
  },
  "415": {
    "description": "Formato de mídia não suportado",
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "properties": {
            "error": {
              "type": "string",
              "example": "Unsupported media format"
            }
          }
        }
      }
    }
  },
  "500": {
    "description": "Erro interno do servidor",
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "properties": {
            "error": {
              "type": "string",
              "example": "Failed to upload media"
            }
          }
        }
      }
    }
  }
}
```

## #/components/schemas/Message

```json
{
  "type": "object",
  "description": "Representa uma mensagem trocada no sistema",
  "properties": {
    "id": {
      "type": "string",
      "format": "uuid",
      "description": "ID único interno da mensagem (formato r + 7 caracteres hex aleatórios)"
    },
    "messageid": {
      "type": "string",
      "description": "ID original da mensagem no provedor"
    },
    "chatid": {
      "type": "string",
      "description": "ID da conversa relacionada"
    },
    "sender": {
      "type": "string",
      "description": "ID do remetente da mensagem"
    },
    "senderName": {
      "type": "string",
      "description": "Nome exibido do remetente"
    },
    "isGroup": {
      "type": "boolean",
      "description": "Indica se é uma mensagem de grupo",
      "default": false
    },
    "fromMe": {
      "type": "boolean",
      "description": "Indica se a mensagem foi enviada pelo usuário",
      "default": false
    },
    "messageType": {
      "type": "string",
      "description": "Tipo de conteúdo da mensagem"
    },
    "source": {
      "type": "string",
      "description": "Plataforma de origem da mensagem"
    },
    "messageTimestamp": {
      "type": "integer",
      "description": "Timestamp original da mensagem em milissegundos",
      "default": 0
    },
    "status": {
      "type": "string",
      "description": "Status do ciclo de vida da mensagem.\nExemplos comuns: `Queued`, `Canceled`, `Failed`, `Sent`, `Delivered`, `Read`.\nEm mensagem de grupo, segue o participante mais adiantado: `Delivered` quando pelo menos um recebeu, `Read` quando pelo menos um leu e `Played` quando pelo menos um ouviu.\n"
    },
    "text": {
      "type": "string",
      "description": "Texto original da mensagem",
      "default": ""
    },
    "quoted": {
      "type": "string",
      "description": "ID da mensagem citada/respondida",
      "default": ""
    },
    "edited": {
      "type": "string",
      "description": "Histórico de edições da mensagem",
      "default": ""
    },
    "reaction": {
      "type": "string",
      "description": "ID da mensagem reagida",
      "default": ""
    },
    "vote": {
      "type": "string",
      "description": "Dados de votação de enquete e listas",
      "default": ""
    },
    "convertOptions": {
      "type": "string",
      "description": "Conversão de opções da mensagem, lista, enquete e botões",
      "default": ""
    },
    "buttonOrListid": {
      "type": "string",
      "description": "ID do botão ou item de lista selecionado",
      "default": ""
    },
    "owner": {
      "type": "string",
      "description": "Dono da mensagem",
      "default": ""
    },
    "error": {
      "type": "string",
      "description": "Mensagem de erro caso o envio tenha falhado",
      "default": ""
    },
    "content": {
      "description": "Conteúdo bruto da mensagem (JSON serializado ou texto)",
      "oneOf": [
        {
          "type": "object",
          "additionalProperties": true
        },
        {
          "type": "string",
          "description": "Texto bruto quando não for JSON"
        }
      ]
    },
    "wasSentByApi": {
      "type": "boolean",
      "description": "Indica se a mensagem foi enviada via API"
    },
    "pinned": {
      "type": "boolean",
      "description": "Mensagem fixada na conversa (fixar e desafixar chegam também em `messages_update`, tipos `Pinned` e `Unpinned`)"
    },
    "sendFunction": {
      "type": "string",
      "description": "Função usada para enviar a mensagem (quando enviada via API)"
    },
    "sendPayload": {
      "description": "Payload usado no envio quando disponível. Dados de mídia em base64 são omitidos.",
      "oneOf": [
        {
          "type": "object",
          "additionalProperties": true
        },
        {
          "type": "string",
          "description": "Texto bruto quando não for JSON"
        }
      ]
    },
    "fileURL": {
      "type": "string",
      "description": "URL ou referência de arquivo da mensagem"
    },
    "callPeer": {
      "type": "object",
      "description": "Contato conhecido associado a uma ligação, quando disponível em `messageType: call`.",
      "properties": {
        "jid": {
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "imagePreviewUrl": {
          "type": "string"
        }
      }
    },
    "send_folder_id": {
      "type": "string",
      "description": "Pasta associada ao envio (quando aplicável)"
    },
    "track_source": {
      "type": "string",
      "description": "Origem de rastreamento"
    },
    "track_id": {
      "type": "string",
      "description": "ID de rastreamento (pode repetir)"
    },
    "ai_metadata": {
      "type": "object",
      "description": "Registro de uma rodada da IA. O completo (pedido ao modelo, resposta e `outcome`) fica uma vez, na última mensagem do contato que a rodada respondeu, também quando nada saiu (erro, resposta descartada). Cada mensagem enviada pela IA leva só `agent_id` e `turn` (o `id` dessa mensagem do contato).",
      "properties": {
        "agent_id": {
          "type": "string",
          "description": "ID do agente de IA responsável"
        },
        "turn": {
          "type": "string",
          "description": "Na mensagem enviada pela IA: o `id` da mensagem do contato onde está o registro completo da rodada."
        },
        "flow_id": {
          "type": "string",
          "description": "Mensagem enviada por um fluxo: o `id` do fluxo. A mensagem enviada pela IA traz o `agent_id`."
        },
        "request": {
          "type": "object",
          "description": "Dados da requisição à API de IA",
          "properties": {
            "messages": {
              "type": "array",
              "description": "Histórico de mensagens enviadas para a API"
            },
            "tools": {
              "type": "array",
              "description": "Ferramentas disponíveis para o agente"
            },
            "options": {
              "type": "object",
              "description": "Opções de configuração da API",
              "properties": {
                "model": {
                  "type": "string"
                },
                "temperature": {
                  "type": "number"
                },
                "maxTokens": {
                  "type": "integer"
                },
                "topP": {
                  "type": "number"
                },
                "frequencyPenalty": {
                  "type": "number"
                },
                "presencePenalty": {
                  "type": "number"
                }
              }
            }
          }
        },
        "response": {
          "type": "object",
          "description": "Resposta da API de IA",
          "properties": {
            "choices": {
              "type": "array",
              "description": "Resultados retornados pela API"
            },
            "toolResults": {
              "type": "array",
              "description": "Resultados da execução de ferramentas"
            },
            "error": {
              "type": "string",
              "description": "Mensagem de erro, se houver"
            }
          }
        },
        "outcome": {
          "type": "object",
          "description": "O que a rodada fez de fato (só no registro completo).",
          "properties": {
            "status": {
              "type": "string",
              "enum": [
                "sent",
                "cancelled",
                "error",
                "empty"
              ],
              "description": "`sent`: enviou algo; `cancelled`: descartada (a conversa pausou, um fluxo começou ou bateu o limite de respostas por hora); `error`: o provedor falhou; `empty`: nada a enviar."
            },
            "texts": {
              "type": "integer",
              "description": "Mensagens de texto enviadas."
            },
            "audio": {
              "type": "boolean",
              "description": "Respondeu em áudio."
            },
            "menus": {
              "type": "integer",
              "description": "Menus enviados."
            },
            "files": {
              "type": "integer",
              "description": "Arquivos (mensagens cadastradas) enviados."
            },
            "handoff": {
              "type": "string",
              "description": "`chamar_humano`: o resumo para quem atender."
            },
            "lead": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "`atualizar_lead`: o que foi gravado no CRM (`lead_email = ana@exemplo.com; column = Agendado`)."
            },
            "detail": {
              "type": "string",
              "description": "Por que foi descartada, ou o erro."
            }
          }
        }
      }
    },
    "sender_pn": {
      "description": "JID PN resolvido do remetente (quando disponível)",
      "oneOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ]
    },
    "sender_lid": {
      "description": "LID original do remetente (quando disponível)",
      "oneOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ]
    },
    "sender_image_preview_url": {
      "type": "string",
      "format": "uri",
      "description": "URL temporária de preview do remetente, quando conhecida. A hidratação desta versão preenche mensagens recebidas em grupos; o campo pode ser omitido. Não provoca consulta de foto ao WhatsApp na listagem."
    }
  }
}
```

## Guias relacionados

[Autenticação](/docs/authentication) · [Erros e retries](/docs/errors-and-retries) · [Server URL](/docs/server-url)
