DISCORD_SEND_FILE - Enviar Arquivos e Mídias no Discord
O que é este Node?
O DISCORD_SEND_FILE é o node responsável por enviar arquivos, imagens, PDFs e documentos para canais do Discord, permitindo compartilhar mídias ricas junto com mensagens.
Por que este Node existe?
Compartilhamento de arquivos é essencial para colaboração e documentação em equipes. O DISCORD_SEND_FILE existe para:
- Compartilhar Documentos: Enviar PDFs, relatórios, spreadsheets para equipe
- Enviar Imagens: Postar screenshots, gráficos, diagramas automaticamente
- Backup e Arquivamento: Salvar arquivos importantes em canais dedicados
- Notificações com Comprovantes: Anexar recibos, comprovantes, faturas em notificações
Como funciona internamente?
Quando o DISCORD_SEND_FILE é executado, o sistema:
- Valida Autenticação: Verifica webhook URL ou bot token + channel ID
- Valida Files Array: Garante que pelo menos um arquivo foi especificado
- Cria FormData: Prepara multipart/form-data para upload
- Baixa Arquivos: Faz download de cada arquivo das URLs especificadas
- Anexa Streams: Adiciona streams de arquivo ao FormData com nomes corretos
- Adiciona Payload JSON: Inclui content, username, avatar se especificados
- Envia Upload: POST com headers multipart/form-data
- Retorna Resposta: Devolve mensagem com array de attachments
Código interno (discord-executor.service.ts:330-377):
private async sendFile(data: DiscordNodeData): Promise<any> {
const form = new FormData();
// Add message content
if (data.content) {
form.append('payload_json', JSON.stringify({
content: data.content,
username: data.username,
avatar_url: data.avatarUrl
}));
}
// Download and attach files
for (let i = 0; i < data.files!.length; i++) {
const file = data.files![i];
try {
const fileResponse = await axios.get(file.url, { responseType: 'stream' });
form.append(`file${i}`, fileResponse.data, {
filename: file.name,
contentType: fileResponse.headers['content-type']
});
} catch (error) {
this.logger.error(`Failed to download file from ${file.url}:`, error.message);
throw new Error(`Failed to download file: ${file.name}`);
}
}
if (data.authType === 'webhook') {
const response: AxiosResponse = await axios.post(data.webhookUrl!, form, {
headers: {
...form.getHeaders()
}
});
return response.data;
} else {
const response: AxiosResponse = await axios.post(
`${this.DISCORD_API_BASE}/channels/${data.channelId}/messages`,
form,
{
headers: {
'Authorization': `Bot ${data.botToken}`,
...form.getHeaders()
}
}
);
return response.data;
}
}
Quando você DEVE usar este Node?
Use DISCORD_SEND_FILE sempre que precisar de envio de arquivos e mídias:
Casos de uso
- Relatórios Automáticos: "Gerar PDF de relatório mensal e enviar para canal de gestão"
- Screenshots de Erros: "Capturar screenshot de erro e postar em canal de bugs"
- Backups Diários: "Exportar dados como CSV e enviar para canal de backups"
- Comprovantes de Pagamento: "Enviar fatura PDF quando pagamento for confirmado"
- Gráficos e Visualizações: "Gerar gráfico de métricas e compartilhar com equipe"
Quando NÃO usar DISCORD_SEND_FILE
- Mensagens Simples: Use
DISCORD_SEND_MESSAGEpara texto sem arquivos - Embeds Formatados: Use
DISCORD_SEND_EMBEDpara conteúdo estruturado sem arquivos - Arquivos Muito Grandes: Discord limita a 8MB (Nitro: 100MB) - use serviço de storage
- Múltiplas Mensagens: Limite de 10 arquivos por mensagem - divida se necessário
Parâmetros Detalhados
operation (string, obrigatório)
O que é: Define a operação como envio de arquivo.
Valor: "send_file"
Flow completo para testar:
{
"name": "Teste Discord - Send File",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "discord_1",
"type": "discord",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Enviar Arquivo",
"parameters": {
"operation": "send_file",
"authType": "webhook",
"webhookUrl": "https://discord.com/api/webhooks/SEU_WEBHOOK",
"content": "Arquivo de teste enviado!",
"files": [
{
"name": "imagem.png",
"url": "https://i.imgur.com/exemplo.png"
}
]
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Confirmar",
"parameters": {
"message": "Arquivo enviado com sucesso!"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "discord_1" },
{ "source": "discord_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Execute o flow e verifique se a imagem foi enviada no Discord.
files (array, obrigatório)
O que é: Array de objetos com informações dos arquivos a serem enviados.
Estrutura:
{
"name": "nome-do-arquivo.ext",
"url": "https://url-publica-do-arquivo.com/arquivo.ext",
"description": "Descrição opcional do arquivo"
}
Limite: 10 arquivos por mensagem, 8MB por arquivo (100MB com Nitro)
Flow completo para testar:
{
"name": "Teste Discord - Files Array",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "discord_1",
"type": "discord",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Enviar Múltiplos Arquivos",
"parameters": {
"operation": "send_file",
"authType": "webhook",
"webhookUrl": "https://discord.com/api/webhooks/SEU_WEBHOOK",
"content": "📎 Relatório mensal com anexos:",
"files": [
{
"name": "relatorio-janeiro.pdf",
"url": "https://example.com/relatorio-janeiro.pdf",
"description": "Relatório completo de Janeiro"
},
{
"name": "grafico-vendas.png",
"url": "https://example.com/grafico.png",
"description": "Gráfico de vendas"
},
{
"name": "dados.csv",
"url": "https://example.com/dados.csv",
"description": "Dados brutos exportados"
}
]
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Confirmar",
"parameters": {
"message": "3 arquivos enviados com sucesso!"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "discord_1" },
{ "source": "discord_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Três arquivos serão enviados juntos na mesma mensagem.
content (string, opcional)
O que é: Mensagem de texto que acompanha os arquivos.
Limite: 2000 caracteres
Flow completo para testar:
{
"name": "Teste Discord - File Content",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "input_1",
"type": "input",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Descrição do Arquivo",
"parameters": {
"message": "Digite uma descrição para o arquivo:",
"variableName": "descricao"
}
}
},
{
"id": "discord_1",
"type": "discord",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Enviar com Descrição",
"parameters": {
"operation": "send_file",
"authType": "webhook",
"webhookUrl": "https://discord.com/api/webhooks/SEU_WEBHOOK",
"content": "📄 **Novo Documento**\n\n{{descricao}}\n\n*Enviado automaticamente pelo sistema*",
"files": [
{
"name": "documento.pdf",
"url": "https://example.com/documento.pdf"
}
]
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Confirmar",
"parameters": {
"message": "Arquivo enviado com descrição personalizada!"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 900, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "input_1" },
{ "source": "input_1", "target": "discord_1" },
{ "source": "discord_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Digite uma descrição e verifique se aparece junto com o arquivo no Discord.
username (string, opcional - apenas webhook)
O que é: Nome customizado que aparecerá como remetente. Só funciona com webhooks.
Flow completo para testar:
{
"name": "Teste Discord - File Username",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "discord_1",
"type": "discord",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Enviar como Bot Backup",
"parameters": {
"operation": "send_file",
"authType": "webhook",
"webhookUrl": "https://discord.com/api/webhooks/SEU_WEBHOOK",
"content": "💾 Backup diário gerado com sucesso",
"username": "Sistema de Backup",
"files": [
{
"name": "backup-2025-01-15.zip",
"url": "https://example.com/backup.zip"
}
]
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 500, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "discord_1" },
{ "source": "discord_1", "target": "end_1" }
]
}
Teste: Arquivo aparecerá como enviado por "Sistema de Backup".
avatarUrl (string, opcional - apenas webhook)
O que é: URL da imagem do avatar customizado. Só funciona com webhooks.
Flow completo para testar:
{
"name": "Teste Discord - File Avatar",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "discord_1",
"type": "discord",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Enviar com Avatar",
"parameters": {
"operation": "send_file",
"authType": "webhook",
"webhookUrl": "https://discord.com/api/webhooks/SEU_WEBHOOK",
"content": "📊 Relatório semanal anexado",
"username": "Bot Relatórios",
"avatarUrl": "https://i.imgur.com/report-bot-icon.png",
"files": [
{
"name": "relatorio-semanal.pdf",
"url": "https://example.com/relatorio.pdf"
}
]
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 500, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "discord_1" },
{ "source": "discord_1", "target": "end_1" }
]
}
Teste: Arquivo será enviado com avatar customizado no perfil.
Parâmetros
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| operation | string | Sim | Deve ser "send_file" |
| authType | string | Sim | "webhook" ou "bot" |
| webhookUrl | string | Sim (webhook) | URL do webhook Discord |
| botToken | string | Sim (bot) | Token do bot Discord |
| channelId | string | Sim (bot) | ID do canal Discord |
| files | array | Sim | Array de objetos |
| content | string | Não | Mensagem de texto com os arquivos |
| username | string | Não | Nome customizado (webhook only) |
| avatarUrl | string | Não | Avatar URL (webhook only) |
Exemplo 1: Envio Automático de Relatório PDF
Objetivo: Gerar e enviar relatório PDF diário para canal de gestão.
JSON para Importar
{
"name": "Discord - Relatório PDF Diário",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "variable_1",
"type": "variable",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Data",
"parameters": {
"name": "data",
"value": "15/01/2025"
}
}
},
{
"id": "variable_2",
"type": "variable",
"position": { "x": 300, "y": 200 },
"data": {
"label": "URL do Relatório",
"parameters": {
"name": "pdfUrl",
"value": "https://storage.lumina.app.br/relatorios/2025-01-15.pdf"
}
}
},
{
"id": "variable_3",
"type": "variable",
"position": { "x": 300, "y": 300 },
"data": {
"label": "Total Vendas",
"parameters": {
"name": "totalVendas",
"value": "R$ 45.890,00"
}
}
},
{
"id": "discord_1",
"type": "discord",
"position": { "x": 500, "y": 200 },
"data": {
"label": "Enviar Relatório",
"parameters": {
"operation": "send_file",
"authType": "webhook",
"webhookUrl": "https://discord.com/api/webhooks/SEU_WEBHOOK",
"content": "📊 **RELATÓRIO DIÁRIO - {{data}}**\n\n💰 Total em vendas: **{{totalVendas}}**\n📈 152 pedidos processados\n👥 23 novos clientes\n\n📎 Relatório completo em PDF anexado abaixo.",
"username": "Sistema de Relatórios",
"avatarUrl": "https://i.imgur.com/report-icon.png",
"files": [
{
"name": "relatorio-{{data}}.pdf",
"url": "{{pdfUrl}}",
"description": "Relatório completo de vendas e métricas"
}
]
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 700, "y": 200 },
"data": {
"label": "Confirmar",
"parameters": {
"message": "✅ Relatório de {{data}} enviado para equipe!"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 900, "y": 200 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "variable_1" },
{ "source": "variable_1", "target": "variable_2" },
{ "source": "variable_2", "target": "variable_3" },
{ "source": "variable_3", "target": "discord_1" },
{ "source": "discord_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Saída esperada no Discord:
[Avatar: ícone de relatório]
Sistema de Relatórios
📊 RELATÓRIO DIÁRIO - 15/01/2025
💰 Total em vendas: R$ 45.890,00
📈 152 pedidos processados
👥 23 novos clientes
📎 Relatório completo em PDF anexado abaixo.
[Anexo: relatorio-15/01/2025.pdf - 2.3 MB]
Exemplo 2: Screenshot de Erro Automático
Objetivo: Capturar e enviar screenshot de erro para canal de debugging.
JSON para Importar
{
"name": "Discord - Screenshot de Erro",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "variable_1",
"type": "variable",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Erro ID",
"parameters": {
"name": "errorId",
"value": "ERR-2025-001"
}
}
},
{
"id": "variable_2",
"type": "variable",
"position": { "x": 300, "y": 200 },
"data": {
"label": "Mensagem Erro",
"parameters": {
"name": "errorMsg",
"value": "Database connection timeout"
}
}
},
{
"id": "variable_3",
"type": "variable",
"position": { "x": 300, "y": 300 },
"data": {
"label": "Screenshot URL",
"parameters": {
"name": "screenshotUrl",
"value": "https://storage.lumina.app.br/errors/screenshot-001.png"
}
}
},
{
"id": "discord_1",
"type": "discord",
"position": { "x": 500, "y": 200 },
"data": {
"label": "Reportar Erro",
"parameters": {
"operation": "send_file",
"authType": "bot",
"botToken": "SEU_BOT_TOKEN",
"channelId": "ID_CANAL_BUGS",
"content": "🚨 **ERRO CRÍTICO DETECTADO**\n\n🆔 ID: `{{errorId}}`\n❌ Erro: `{{errorMsg}}`\n⏰ Timestamp: <t:1705329000:F>\n🖥️ Servidor: prod-server-01\n\n📸 Screenshot anexado para análise.\n\n@here",
"files": [
{
"name": "error-{{errorId}}.png",
"url": "{{screenshotUrl}}",
"description": "Screenshot do erro capturado"
}
]
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 700, "y": 200 },
"data": {
"label": "Confirmar",
"parameters": {
"message": "Erro {{errorId}} reportado para equipe de dev!"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 900, "y": 200 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "variable_1" },
{ "source": "variable_1", "target": "variable_2" },
{ "source": "variable_2", "target": "variable_3" },
{ "source": "variable_3", "target": "discord_1" },
{ "source": "discord_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Saída esperada no Discord:
🚨 ERRO CRÍTICO DETECTADO
🆔 ID: ERR-2025-001
❌ Erro: Database connection timeout
⏰ Timestamp: 15 de janeiro de 2025 às 14:30
🖥️ Servidor: prod-server-01
📸 Screenshot anexado para análise.
@here
[Anexo: error-ERR-2025-001.png - 456 KB]
[Preview da imagem renderizado inline]
Exemplo 3: Backup com Múltiplos Arquivos
Objetivo: Enviar múltiplos arquivos de backup para canal de arquivamento.
JSON para Importar
{
"name": "Discord - Backup Múltiplos Arquivos",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "variable_1",
"type": "variable",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Timestamp",
"parameters": {
"name": "timestamp",
"value": "2025-01-15-14h30"
}
}
},
{
"id": "discord_1",
"type": "discord",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Enviar Backup",
"parameters": {
"operation": "send_file",
"authType": "webhook",
"webhookUrl": "https://discord.com/api/webhooks/SEU_WEBHOOK",
"content": "💾 **BACKUP COMPLETO - {{timestamp}}**\n\n✅ Backup realizado com sucesso\n📦 3 arquivos anexados:\n\n• Database dump (PostgreSQL)\n• Uploads e mídias\n• Configurações do sistema\n\n🔐 Todos os arquivos estão criptografados",
"username": "Sistema de Backup",
"avatarUrl": "https://i.imgur.com/backup-icon.png",
"files": [
{
"name": "database-{{timestamp}}.sql.gz",
"url": "https://storage.lumina.app.br/backups/db.sql.gz",
"description": "Dump completo do banco de dados"
},
{
"name": "uploads-{{timestamp}}.zip",
"url": "https://storage.lumina.app.br/backups/uploads.zip",
"description": "Arquivos de upload dos usuários"
},
{
"name": "config-{{timestamp}}.tar.gz",
"url": "https://storage.lumina.app.br/backups/config.tar.gz",
"description": "Configurações e variáveis de ambiente"
}
]
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Confirmar",
"parameters": {
"message": "Backup {{timestamp}} arquivado com sucesso! 💾"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 900, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "variable_1" },
{ "source": "variable_1", "target": "discord_1" },
{ "source": "discord_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Saída esperada no Discord:
[Avatar: ícone de backup]
Sistema de Backup
💾 BACKUP COMPLETO - 2025-01-15-14h30
✅ Backup realizado com sucesso
📦 3 arquivos anexados:
• Database dump (PostgreSQL)
• Uploads e mídias
• Configurações do sistema
🔐 Todos os arquivos estão criptografados
[Anexo 1: database-2025-01-15-14h30.sql.gz - 45.2 MB]
[Anexo 2: uploads-2025-01-15-14h30.zip - 128.7 MB]
[Anexo 3: config-2025-01-15-14h30.tar.gz - 1.2 MB]
Resposta do Node
{
"id": "1234567890123456789",
"channel_id": "987654321098765432",
"author": {
"username": "Sistema de Backup",
"avatar": "abc123"
},
"content": "💾 BACKUP COMPLETO...",
"attachments": [
{
"id": "111111111111111111",
"filename": "database-2025-01-15-14h30.sql.gz",
"size": 47447040,
"url": "https://cdn.discordapp.com/.../database.sql.gz",
"proxy_url": "https://media.discordapp.net/.../database.sql.gz",
"content_type": "application/gzip"
},
{
"id": "222222222222222222",
"filename": "uploads-2025-01-15-14h30.zip",
"size": 134963200,
"url": "https://cdn.discordapp.com/.../uploads.zip",
"proxy_url": "https://media.discordapp.net/.../uploads.zip",
"content_type": "application/zip"
}
],
"timestamp": "2025-01-15T14:30:00.000Z"
}
Boas Práticas
✅ SIM:
- Valide que URLs de arquivos são públicas e acessíveis
- Use nomes descritivos com extensão correta (arquivo.pdf, not arquivo)
- Inclua contexto na mensagem (o que é o arquivo, por que foi enviado)
- Comprima arquivos grandes antes de enviar (ZIP, GZ)
- Verifique tamanho antes de enviar (limite 8MB sem Nitro)
- Use HTTPS para URLs de arquivos (nunca HTTP)
- Adicione descrições úteis em cada arquivo
- Organize backups em canais dedicados
- Use webhooks para automações simples de arquivos
- Combine com embed para contexto visual rico
❌ NÃO:
- Não tente enviar arquivos maiores que 8MB (100MB Nitro)
- Não envie mais de 10 arquivos por mensagem
- Não use URLs privadas/protegidas (download falhará)
- Não hardcode URLs de storage (use variáveis)
- Não esqueça extensões dos arquivos
- Não envie arquivos sem contexto (sempre adicione content)
- Não abuse do canal (respeite rate limits)
- Não envie arquivos sensíveis sem criptografia
- Não use URLs expiráveis sem validar antes
- Não ignore erros de download de arquivos
Dicas
💡 Dica 1: O sistema faz download do arquivo da URL e então upload para Discord. Certifique-se que a URL é pública e não expira rapidamente.
💡 Dica 2: Imagens (PNG, JPG, GIF) são renderizadas inline no Discord. Outros tipos (PDF, ZIP) aparecem como download.
💡 Dica 3: Use serviços de storage (AWS S3, Google Cloud Storage) para hospedar arquivos antes de enviar ao Discord.
💡 Dica 4: Content-Type é detectado automaticamente do header da URL. Garanta que seu servidor responde corretamente.
💡 Dica 5: Para múltiplos arquivos, considere criar ZIP único se ultrapassar limite de 10 arquivos.
💡 Dica 6: Webhooks não têm rate limit tão rigoroso quanto bots para file upload.
💡 Dica 7: Use FORMATTER node para preparar array de files dinamicamente antes de enviar.
Próximo Node
→ DISCORD_SEND_MESSAGE - Enviar mensagens de texto simples → DISCORD_SEND_EMBED - Enviar embeds formatados → DISCORD_EDIT_MESSAGE - Editar mensagens existentes → DISCORD_DELETE_MESSAGE - Deletar mensagens