npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dianabots/baileys

v0.1.20

Published

Uma biblioteca WebSockets para interagir com o WhatsApp Web — dianabots.

Readme

📋 Índice Geral

Para facilitar a navegação por esta extensa documentação, os tópicos estão organizados por categorias. Clique nas seções para expandi-las:


🔌 Conexão & Inicialização

Nesta seção, você aprenderá a instalar e inicializar a biblioteca @dianabots/baileys de diferentes maneiras.

📦 Instalação

Adicione a biblioteca ao seu projeto Node.js usando o gerenciador de pacotes de sua preferência:

npm install @dianabots/baileys
# ou usando yarn
yarn add @dianabots/baileys

📱 Conexão QR Code

Exemplo básico de inicialização com geração de QR Code no terminal e salvamento automático das credenciais:

// Importação no padrão CommonJS ou ESM
const {
  default: makeWASocket,
  useMultiFileAuthState,
  DisconnectReason,
  fetchLatestBaileysVersion
} = require('@dianabots/baileys')

async function start() {
  // Define a pasta onde os arquivos de autenticação serão salvos
  const { state, saveCreds } = await useMultiFileAuthState('auth_info')
  const { version } = await fetchLatestBaileysVersion()

  const sock = makeWASocket({
    version,
    auth: state,
    printQRInTerminal: true // Exibe o QR Code diretamente no terminal
  })

  // Escuta atualizações de credenciais para salvar o estado da sessão
  sock.ev.on('creds.update', saveCreds)

  // Monitora alterações na conexão (reconecta automaticamente caso caia)
  sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
    if (connection === 'close') {
      const code = lastDisconnect?.error?.output?.statusCode
      if (code !== DisconnectReason.loggedOut) {
        start() // Reconectar
      }
    } else if (connection === 'open') {
      console.log('Bot Conectado com sucesso!')
    }
  })
}

start()

🔑 Conexão Pairing Code

Ideal para servidores VPS ou ambientes onde não há visualização do terminal para leitura do QR Code. O código de 8 dígitos é retornado diretamente:

const sock = makeWASocket({ version, auth: state, printQRInTerminal: false })

sock.ev.on('creds.update', saveCreds)
sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
  if (connection === 'close') {
    if (lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut) start()
  }
})

// Solicitar código de pareamento passando o número de telefone (DDI + DDD + Número)
if (!sock.authState.creds.registered) {
  const code = await sock.requestPairingCode('5511999999999')
  console.log('Seu código de pareamento é:', code)
}

// Também é possível forçar um código específico de 8 caracteres
const customCode = await sock.requestPairingCode('5511999999999', 'BOTDIANA')

🌐 Identidade do Navegador

Você pode configurar como o seu bot é identificado nas sessões ativas do WhatsApp no celular (configuração browser):

const { Browsers } = require('@dianabots/baileys')

makeWASocket({
  // Opções pré-definidas da biblioteca:
  browser: Browsers.macOS('Chrome'),    // MacOS rodando Chrome
  browser: Browsers.windows('Chrome'),  // Windows rodando Chrome
  browser: Browsers.ubuntu('Chrome'),   // Ubuntu rodando Chrome
  browser: Browsers.baileys('Chrome'),  // Padrão Baileys
  
  // Ou defina uma identidade totalmente personalizada:
  browser: ['Minha Empresa', 'Safari', '2.0.0'] 
})

⚙️ Opções de Conexão

Lista das principais configurações disponíveis ao instanciar o socket do bot:

makeWASocket({
  version,
  auth: state,
  printQRInTerminal: true,
  browser: Browsers.macOS('Chrome'),
  connectTimeoutMs: 20000,              // Timeout de conexão
  keepAliveIntervalMs: 30000,           // Envio de PING para manter conexão ativa
  markOnlineOnConnect: true,            // Exibir bot como "Online"
  syncFullHistory: false,               // Desative para economizar consumo de RAM
  generateHighQualityLinkPreview: false,// Pré-visualizações de links em alta resolução
  emitOwnEvents: true,                  // Emitir eventos disparados pelo próprio bot
  getMessage: async key => {
    // Retorna mensagens salvas do banco de dados (ajuda em funções de quoted e decodificação)
    return store?.messages?.[key.remoteJid]?.get(key.id)?.message
  }
})

📨 Eventos & Gerenciamento de Chats

📬 Receber Mensagens

Acompanhe a chegada de novas mensagens por meio do monitoramento do evento messages.upsert:

sock.ev.on('messages.upsert', async ({ messages, type }) => {
  // Apenas processa mensagens recebidas em tempo real
  if (type !== 'notify') return

  for (const m of messages) {
    if (!m.message) continue
    if (m.key.fromMe) continue // Ignora mensagens enviadas pelo próprio bot

    const jid = m.key.remoteJid
    const isGroup = jid.endsWith('@g.us')
    const sender = isGroup ? m.key.participant : jid

    // Extrai o conteúdo textual independente do tipo de mensagem
    const text =
      m.message.conversation ||
      m.message.extendedTextMessage?.text ||
      m.message.imageMessage?.caption ||
      m.message.videoMessage?.caption || ''

    console.log(`Mensagem de ${sender}: ${text}`)

    // Marca a mensagem recebida como lida (visualizada)
    await sock.readMessages([m.key])
    
    // Envia o estado de "digitando..." para a conversa
    await sock.sendPresenceUpdate('composing', jid)
  }
})

👥 Manipulação de Grupos

Métodos para gerenciar membros, títulos, descrições e obter informações gerais sobre grupos:

// Escutar quando participantes entram, saem, são promovidos ou rebaixados
sock.ev.on('group-participants.update', ({ id, participants, action }) => {
  console.log(`Grupo: ${id} | Membros: ${participants} | Ação: ${action}`)
  // action pode ser: 'add' (entrou) | 'remove' (saiu) | 'promote' (adm) | 'demote' (rebaixado)
})

// Obter dados completos de um grupo (Nome, Descrição, Participantes, etc)
const meta = await sock.groupMetadata('[email protected]')
console.log(`Nome do Grupo: ${meta.subject}`)

// Listar todos os grupos em que o bot está inserido
const groups = await sock.groupFetchAllParticipating()

// Adicionar, remover, promover ou rebaixar membros
await sock.groupParticipantsUpdate(groupJid, ['[email protected]'], 'add')
await sock.groupParticipantsUpdate(groupJid, ['[email protected]'], 'remove')
await sock.groupParticipantsUpdate(groupJid, ['[email protected]'], 'promote')
await sock.groupParticipantsUpdate(groupJid, ['[email protected]'], 'demote')

// Alterar as propriedades do grupo
await sock.groupUpdateSubject(groupJid, 'Novo Nome do Grupo')
await sock.groupUpdateDescription(groupJid, 'Nova descrição detalhada do grupo')

// Bloquear ou liberar o envio de mensagens para apenas administradores
await sock.groupSettingUpdate(groupJid, 'announcement')     // Apenas ADMs enviam
await sock.groupSettingUpdate(groupJid, 'not_announcement') // Todos enviam

// Mencionar todos os membros do grupo de uma vez
const groupMeta = await sock.groupMetadata(groupJid)
const members = groupMeta.participants.map(p => p.id)
await sock.sendMessage(groupJid, {
  text: members.map(m => `@${m.split('@')[0]}`).join(' '),
  mentions: members
})

📤 Envio de Mensagens Básicas & Mídias

Exemplos de como enviar texto, fotos, vídeos, áudios, figurinhas, contatos e localizações.

💬 Texto

// Mensagem de texto simples
await sock.sendMessage(jid, { text: 'Olá, esta é uma mensagem!' })

// Mensagem marcando usuários específicos (menção) respondendo a outra mensagem (quoted)
await sock.sendMessage(jid, {
  text: 'Olá @5511999999999!',
  mentions: ['[email protected]']
}, { quoted: m })

🖼️ Imagem

// Envio informando uma URL externa
await sock.sendMessage(jid, {
  image: { url: 'https://example.com/foto.jpg' },
  caption: 'Esta é a legenda da imagem'
})

// Envio de imagem através de um arquivo Buffer ou arquivo local
await sock.sendMessage(jid, {
  image: fs.readFileSync('foto.jpg'),
  caption: 'Enviada através de buffer'
})

🎬 Vídeo

// Vídeo tradicional com legenda
await sock.sendMessage(jid, {
  video: { url: 'https://example.com/video.mp4' },
  caption: 'Legenda do vídeo',
  gifPlayback: false // Se true, o vídeo será enviado em loop infinito sem áudio
})

// Nota de Vídeo Circular (Mensagem de vídeo bubble / PTV)
await sock.sendMessage(jid, {
  video: fs.readFileSync('video.mp4'),
  ptv: true // Ativa o formato circular
})

🎙️ Áudio & Notas de Voz

// Enviar arquivo de áudio clássico (exibe player de duração)
await sock.sendMessage(jid, {
  audio: { url: 'https://example.com/musica.mp3' },
  mimetype: 'audio/mpeg'
})

// Enviar nota de voz (exibe gravação com microfone azul - PTT)
await sock.sendMessage(jid, {
  audio: fs.readFileSync('gravacao.ogg'),
  mimetype: 'audio/ogg; codecs=opus',
  ptt: true // Ativa a nota de voz
})

📄 Documento

await sock.sendMessage(jid, {
  document: fs.readFileSync('relatorio.pdf'),
  mimetype: 'application/pdf',
  fileName: 'Relatorio_Anual.pdf',
  caption: 'Legenda explicativa opcional'
})

🎴 Figurinha

// Envia arquivo WebP como figurinha estática
await sock.sendMessage(jid, { sticker: fs.readFileSync('figurinha.webp') })

📍 Localização

await sock.sendMessage(jid, {
  location: {
    degreesLatitude: -23.55052,
    degreesLongitude: -46.633308,
    name: 'Praça da Sé',
    address: 'São Paulo, Brasil'
  }
})

👤 Contato

await sock.sendMessage(jid, {
  contacts: {
    displayName: 'Diana Suporte',
    contacts: [{
      vcard: 'BEGIN:VCARD\nVERSION:3.0\nFN:Diana Suporte\nTEL;type=CELL;type=VOICE;waid=5511999999999:+55 11 99999-9999\nEND:VCARD'
    }]
  }
})

💬 Recursos de Interação & Enquetes

❤️ Reação

// Reagir com um emoji a uma mensagem específica utilizando a chave (key) dela
await sock.sendMessage(jid, { react: { text: '👍', key: m.key } })

// Para remover a reação, basta enviar o texto vazio
await sock.sendMessage(jid, { react: { text: '', key: m.key } })

📊 Enquete

// Enquete básica de escolha única
await sock.sendMessage(jid, {
  poll: {
    name: 'Qual seu tema preferido?',
    values: ['Modo Claro', 'Modo Escuro', 'Sistema'],
    selectableCount: 1 // 1 = escolha única. 0 = multipla escolha
  }
})

// Enquete avançada com parâmetros adicionais
await sock.sendMessage(jid, {
  poll: {
    name: 'Escolha de Cores',
    values: ['Vermelho', 'Azul'],
    selectableCount: 1,
    endDate: new Date('2025-12-31'),
    hideVoter: true,          // Oculta quem votou em qual opção
    canAddOption: false,
    toAnnouncementGroup: false
  }
})

// Quiz (Enquete estruturada contendo uma resposta certa)
await sock.sendMessage(jid, {
  poll: {
    name: 'Quem descobriu a gravidade?',
    values: ['Tesla', 'Newton', 'Einstein'],
    selectableCount: 1,
    pollType: 1, // 1 representa QUIZ
    correctAnswer: 'Newton'
  }
})

📈 Resultado da Enquete

Envio manual de um gráfico/card contendo o consolidado dos votos de uma enquete:

await sock.sendMessage(jid, {
  pollResult: {
    name: 'Resultado da Votação',
    votes: [
      { name: 'Opção A', voteCount: 15 },
      { name: 'Opção B', voteCount: 8 }
    ],
    pollType: 0 // 0 = ENQUETE, 1 = QUIZ
  }
})

🔄 Atualização da Enquete

Usado para sincronizar ou enviar um voto computado a uma enquete ativa:

await sock.sendMessage(jid, {
  pollUpdate: {
    key: pollMessage.key,       // Chave da mensagem da enquete original
    vote: encryptedVotePayload, // Payload do voto criptografado
    metadata: optionalMetadata
  }
})

↗️ Encaminhar

await sock.sendMessage(jid, {
  forward: messageToForward,
  force: true // Força a exibição do rótulo "Mensagem Encaminhada"
})

🗑️ Apagar Mensagem

Apaga mensagens para todos no chat:

await sock.sendMessage(jid, { delete: messageToDelete.key })

✏️ Editar Mensagem

Edita o conteúdo textual de uma mensagem enviada anteriormente:

await sock.sendMessage(jid, {
  text: 'Este texto foi corrigido via edição',
  edit: messageToEdit.key
})

📌 Fixar Mensagem

Fixa ou desafixa mensagens no topo da conversa:

// Fixar por 24 horas (tempo em segundos)
await sock.sendMessage(jid, {
  pin: m.key,
  type: 1,     // 1 = Fixar
  time: 86400  // 86400 = 1 dia | 604800 = 7 dias | 2592000 = 30 dias
})

// Desafixar mensagem
await sock.sendMessage(jid, { pin: m.key, type: 2 })

✨ Elementos Avançados & Wrappers

🗂️ Álbum

Permite o envio agrupado de mídias (fotos e vídeos) em uma única mensagem de grade:

await sock.sendMessage(jid, {
  album: [
    { image: { url: 'https://example.com/foto1.jpg' }, caption: 'Legenda do item 1' },
    { image: { url: 'https://example.com/foto2.jpg' }, caption: 'Legenda do item 2' },
    { video: { url: 'https://example.com/video.mp4' }, caption: 'Vídeo do álbum' }
  ]
})

📅 Evento

Cria convites de eventos integrados à agenda dos participantes:

await sock.sendMessage(jid, {
  event: {
    name: 'Lançamento Oficial Diana',
    description: 'Apresentação dos novos recursos do bot',
    startDate: new Date('2025-12-01T10:00:00'),
    endDate: new Date('2025-12-01T12:00:00'),
    location: {
      degreesLatitude: -23.55052,
      degreesLongitude: -46.633308,
      name: 'Auditório Principal'
    },
    extraGuestsAllowed: true // Permite acompanhantes
  }
})

// Evento acoplado a um agendamento de chamada nativa
await sock.sendMessage(jid, {
  event: {
    name: 'Chamada de Alinhamento',
    startDate: new Date('2025-12-01T10:00:00'),
    call: 'audio', // 'audio' ou 'video'
    isScheduleCall: true
  }
})

📖 Status / Story de Grupo

Publique um status ou story visível para todos os integrantes de um grupo específico:

// Enviar status textual
await sock.sendMessage(groupJid, {
  groupStatusMessage: { text: 'Aviso importante para o grupo!' }
})

// Enviar status de imagem
await sock.sendMessage(groupJid, {
  groupStatusMessage: {
    image: { url: 'https://example.com/status.jpg' },
    caption: 'Legenda explicativa'
  }
})

// Enviar status de áudio gravado (nota de voz)
await sock.sendMessage(groupJid, {
  groupStatusMessage: {
    audio: fs.readFileSync('status_voz.ogg'),
    mimetype: 'audio/ogg; codecs=opus',
    ptt: true
  }
})

🏷️ Menção no Status

Permite marcar usuários de forma oculta ao publicar um status (eles receberão notificações):

// Marcando múltiplos JIDs de contatos ou grupos
await sock.sendMessage(['[email protected]', '[email protected]'], {
  text: 'Status especial para vocês',
  backgroundColor: '#ff6b9d'
})

📡 Canal (Newsletter)

Melhoria v0.1.16: O envio de mídias para canais foi corrigido. Resolvidos os bugs de ausência do atributo mediatype e da falta de miniaturas.

Para postagens em canais onde o bot é administrador (JIDs terminados em @newsletter). Canais não possuem encriptação de ponta a ponta:

const channelJid = '120363425154682710@newsletter'

// Texto simples
await sock.sendMessage(channelJid, { text: 'Olá inscritos!' })

// Imagens (URL, arquivo local ou Buffer)
await sock.sendMessage(channelJid, {
  image: { url: 'https://example.com/post.jpg' },
  caption: 'Capa do dia'
})

// Vídeos e Áudios
await sock.sendMessage(channelJid, {
  video: { url: 'https://example.com/tutorial.mp4' },
  caption: 'Assista agora!'
})

// Enquete em Canal
await sock.sendMessage(channelJid, {
  poll: {
    name: 'O que prefere no bot?',
    values: ['Facilidade', 'Recursos', 'Suporte'],
    selectableCount: 1
  }
})

🔁 Resposta de Fluxo (Flow)

Permite enviar respostas estruturadas simulando interações nativas do tipo Flow:

await sock.sendMessage(jid, {
  flowReply: {
    name: 'quick_reply',
    paramsJson: '{"id":"botao_1"}',
    text: 'Ação executada',
    format: 1,
    version: 1
  }
})

🔘 Resposta de Botão

Simula e envia o evento de clique em um botão interativo:

// Simular clique em botão de template
await sock.sendMessage(jid, {
  buttonReply: { displayText: 'Confirmar Cadastro', id: 'confirm_btn', index: 0 },
  type: 'template'
})

// Simular clique em botão simples (Plain)
await sock.sendMessage(jid, {
  buttonReply: { displayText: 'Não, obrigado', id: 'cancel_btn' },
  type: 'plain'
})

📎 Manter no Chat (Keep)

Evita que uma mensagem de chat temporário seja apagada:

await sock.sendMessage(jid, {
  keep: m.key,
  keepType: 1  // 1 = Manter mensagem, 2 = Remover proteção (unkeep)
})

📞 Chamada Agendada

await sock.sendMessage(jid, {
  call: {
    time: Date.now() + 3600000, // Agendado para daqui a 1 hora
    type: 1,                    // 1 = Áudio, 2 = Vídeo
    title: 'Reunião de Escopo'
  }
})

🔗 Convite de Grupo

Cria e envia um card estruturado contendo o convite para um grupo:

await sock.sendMessage(jid, {
  groupInvite: {
    jid: '[email protected]',
    inviteCode: 'código_de_entrada',
    inviteExpiration: Date.now() + 86400000, // Expiração (24 horas)
    subject: 'Grupo de Clientes VIP',
    text: 'Junte-se à nossa comunidade exclusiva!'
  }
})

🛍️ Produto

await sock.sendMessage(jid, {
  product: {
    productImage: fs.readFileSync('celular.jpg'),
    productId: 'prod_99',
    title: 'Smartphone Diana S25',
    description: 'O celular mais moderno do mercado',
    currencyCode: 'BRL',
    priceAmount1000: 2999000, // R$ 2.999,00 (Valor em milésimos)
    retailerId: 'sku_diana_s25',
    url: 'https://loja.dianabots.com/s25'
  },
  businessOwnerJid: '[email protected]' // JID comercial obrigatório
})

👁️ Visualização Única

Envia imagens ou vídeos configurados para serem visualizados apenas uma vez:

await sock.sendMessage(jid, {
  image: { url: 'https://example.com/secreta.jpg' },
  viewOnce: true // Ativa visualização única
})

👁️ Visualização Única V2

// Utilizando a estrutura V2 do WhatsApp
await sock.sendMessage(jid, {
  image: { url: 'https://example.com/secreta.jpg' },
  viewOnceV2: true
})

// Com suporte estendido
await sock.sendMessage(jid, {
  image: { url: 'https://example.com/secreta.jpg' },
  viewOnceV2Extension: true
})

⏳ Efêmero

// Ativa o envio de uma mensagem temporária avulsa no chat
await sock.sendMessage(jid, {
  text: 'Esta mensagem desaparecerá no tempo configurado no chat',
  ephemeral: true
})

🙈 Spoiler

Envia imagens ocultando a legenda com filtro de spoiler:

await sock.sendMessage(jid, {
  image: { url: 'https://example.com/revelacao.jpg' },
  caption: 'Este é o grande final da temporada!',
  spoiler: true // Oculta legenda
})

🎭 Wrap de Status de Grupo

Wrapper automático para enviar mídias encapsuladas como status de grupo:

await sock.sendMessage(jid, {
  text: 'Status enviado via automação',
  groupStatus: true // Encapsula a mensagem automaticamente
})

🎞️ Figurinha Lottie

// Envia animação lottie como figurinha dinâmica
await sock.sendMessage(jid, {
  sticker: fs.readFileSync('animacao.webp'),
  isLottie: true
})

🤖 Ícone de IA

Exibe no cabeçalho ou nas informações da mensagem o selo oficial de "Mensagem Gerada por IA". Suportado apenas em chats privados:

await sock.sendMessage(jid, { text: 'Esta é uma resposta gerada por IA', ai: true })

🔒 Etiqueta Secure Meta Service

Envia mensagens de texto contendo a etiqueta azul de canal ou serviço oficial Meta verificado:

await sock.sendMessage(jid, {
  text: 'Serviço de Atendimento Autorizado',
  secureMetaServiceLabel: true
})

🎛️ Mensagens Interativas & Botões

📍 Botões com Cabeçalho de Localização

Permite criar botões estruturados contendo dados de localização no topo (Header do Tipo 6):

await sock.sendMessage(jid, {
  buttonsMessage: {
    locationMessage: {
      degreesLatitude: -23.55052,
      degreesLongitude: -46.633308,
      name: 'Minha Empresa',
      address: 'Endereço Comercial',
      jpegThumbnail: './img/fachada.jpg' // Aceita arquivo local, URL ou Buffer
    },
    contentText: 'Confirme sua visita no botão abaixo',
    footerText: 'Powered by @dianabots/baileys',
    buttons: [
      { buttonId: 'confirm_visit', buttonText: { displayText: 'Confirmar Agendamento' }, type: 1 }
    ],
    headerType: 6 // 6 indica cabeçalho de Localização
  }
})

Tipos suportados para headerType:

| ID | Formato do Cabeçalho | |:--:|----------------------| | 1 | Texto simples | | 2 | Imagem | | 3 | Vídeo | | 4 | Documento | | 6 | Localização geográfica |

🎛️ Botões

// Botões simples de resposta rápida (Quick Reply)
await sock.sendMessage(jid, {
  text: 'Selecione sua categoria de interesse',
  footer: 'Menu de Seleção',
  buttons: [
    { id: 'cat_tech', text: 'Tecnologia' },
    { id: 'cat_arts', text: 'Artes' }
  ]
})

// Shorthand prático: Criar menu de lista integrado a um único botão
await sock.sendMessage(jid, {
  text: 'Selecione abaixo',
  buttons: [{
    text: 'Ver Seções',
    sections: [{
      title: 'Principais Serviços',
      rows: [
        { id: 'serv_1', title: 'Consultoria', description: 'Atendimento especializado' },
        { id: 'serv_2', title: 'Suporte', description: 'Correção de erros' }
      ]
    }]
  }]
})

📋 Mensagem de Lista

await sock.sendMessage(jid, {
  text: 'Por favor, escolha uma opção abaixo', // Mapeado para description
  title: 'Central de Serviços',                // Mapeado para title
  buttonText: 'Ver Categorias',                // Rótulo do botão disparador da lista
  footer: 'Selecione apenas uma opção',
  sections: [
    {
      title: 'Desenvolvimento',
      rows: [
        { id: 'dev_web', title: 'Websites', description: 'Desenvolvimento frontend/backend' },
        { id: 'dev_app', title: 'Aplicativos', description: 'Mobile nativo iOS/Android' }
      ]
    },
    {
      title: 'Design',
      rows: [
        { id: 'design_logo', title: 'Logotipo & Branding' }
      ]
    }
  ]
})

🗃️ Botões de Modelo (Template Buttons)

Neste formato, você pode mesclar links web, chamadas telefônicas e respostas rápidas:

await sock.sendMessage(jid, {
  text: 'Central de Informações Diana',
  footer: 'Clique em uma das opções',
  templateButtons: [
    { id: 'quick_rep_1', text: 'Falar com Atendente' },
    { url: 'https://dianabots.com', text: 'Acessar Site Oficial' },
    { call: '+5511999999999', text: 'Ligar para a Central' }
  ]
})

🌊 Fluxo Nativo (Native Flow)

Permite construir interações nativas sofisticadas diretamente de acordo com as chaves inseridas:

// Botões automatizados via Native Flow
await sock.sendMessage(jid, {
  text: 'Painel Interativo',
  nativeFlow: [
    { id: 'op_1', text: 'Opção Rápida 1' },
    { url: 'https://example.com', text: 'Abrir Site' },
    { copy: 'CUPOMDIANA', text: 'Copiar Cupom' },
    { call: '+5511999999999', text: 'Iniciar Chamada' }
  ]
})

// Banner de Oferta por tempo limitado (offerText)
await sock.sendMessage(jid, {
  text: 'Super Desconto!',
  offerText: '50% de Desconto',
  offerUrl: 'https://example.com/desconto',
  offerCode: 'DIANA50',
  offerExpiration: 1800000000,
  nativeFlow: [{ id: 'claim_now', text: 'Garantir Cupom' }]
})

Detecção Automática de Tipos: A biblioteca converte automaticamente as chaves inseridas para as chamadas correspondentes do WhatsApp (id -> quick_reply, url -> cta_url, copy -> cta_copy, call -> cta_call, sections -> single_select).

🎠 Carrossel

Permite exibir múltiplos cartões com rolagem horizontal contendo mídias e botões independentes:

await sock.sendMessage(jid, {
  text: 'Portfólio de Produtos',
  footer: 'Navegue pelo carrossel',
  cards: [
    {
      image: { url: 'https://example.com/card1.jpg' },
      title: 'Plano Básico',
      caption: 'Ideal para iniciar sua jornada',
      footer: 'R$ 49/mês',
      nativeFlow: [{ name: 'quick_reply', paramsJson: '{"id":"choose_basic"}', text: 'Assinar Plano' }]
    },
    {
      image: { url: 'https://example.com/card2.jpg' },
      title: 'Plano Premium',
      caption: 'Acesso total aos nossos recursos',
      footer: 'R$ 99/mês',
      nativeFlow: [{ name: 'quick_reply', paramsJson: '{"id":"choose_premium"}', text: 'Assinar Plano' }]
    }
  ]
})

🔧 Recursos Especializados & Outros

📃 Resposta de Lista

Envia uma confirmação programática de resposta contendo o ID e os detalhes do item selecionado:

await sock.sendMessage(jid, {
  listReply: {
    title: 'Confirmação de Seleção',
    description: 'Você escolheu o Serviço A',
    id: 'serv_1' // ID correspondente ao item selecionado
  }
})

🎴 Pacote de Figurinhas

Carrega um arquivo contendo múltiplas figurinhas empacotadas de uma só vez. A biblioteca processa e ajusta os formatos necessários:

await sock.sendMessage(jid, {
  cover: fs.readFileSync('capa_pack.webp'), // Imagem de capa obrigatória
  name: 'Diana Pack',
  publisher: 'dianabots',
  description: 'Pacote oficial de figurinhas',
  stickers: [
    { data: fs.readFileSync('stk1.webp'), emojis: ['👍'], accessibilityLabel: 'Joinha' },
    { data: { url: 'https://example.com/stk2.webp' }, emojis: ['❤️'] }
  ]
})

📢 Resposta de Anúncio Externo

Cria balões enriquecidos exibindo banners, links externos e descrições detalhadas (Ad Cards):

await sock.sendMessage(jid, {
  text: 'Confira as novidades no blog',
  externalAdReply: {
    title: 'Artigo Especial Diana',
    body: 'Como utilizar bots para alavancar seu negócio',
    thumbnail: fs.readFileSync('capa_artigo.jpg'), // Buffer obrigatório
    url: 'https://dianabots.com/blog/bot-whatsapp',
    mediaType: 1,
    largeThumbnail: true // Exibe miniatura ampliada
  }
})

💳 Solicitar Pagamento

Gera um card solicitando transferência monetária através do WhatsApp Pay:

await sock.sendMessage(jid, {
  text: 'Pagamento referente à contratação',
  requestPaymentFrom: '[email protected]',
  amount1000: 50000000, // R$ 50.000,00 (Valor em milésimos)
  currencyCodeIso4217: 'BRL',
  expiryTimestamp: Date.now() + 86400000 // Expiração em 24h
})

🧾 Fatura (Invoice)

// Envio acoplado a um arquivo PDF
await sock.sendMessage(jid, {
  document: fs.readFileSync('fatura.pdf'),
  mimetype: 'application/pdf',
  fileName: 'Fatura_Servico.pdf',
  invoiceNote: 'Fatura digital detalhada para pagamento'
})

📦 Pedido (Order)

Cria e envia um card contendo os dados organizados de uma compra/pedido comercial:

await sock.sendMessage(jid, {
  order: {
    orderId: 'ped_29910',
    thumbnail: fs.readFileSync('produto.jpg'),
    itemCount: 3,
    status: 'PAYMENT_PENDING',
    surface: 'CATALOG',
    message: 'Seu pedido foi recebido com sucesso!',
    orderTitle: 'Pedido #29910',
    sellerJid: '[email protected]',
    token: 'token_de_seguranca_unico',
    totalAmount1000: 150000000, // R$ 150.000,00 (Em milésimos)
    totalCurrencyCode: 'BRL'
  }
})

💨 Mensagens Temporárias

Ative ou desative as mensagens temporárias em chats de grupos especificando o tempo de duração:

// Ativar (Duração padrão de 24 horas - 86400 segundos)
await sock.sendMessage(groupJid, { disappearingMessagesInChat: true })

// Desativar mensagens temporárias
await sock.sendMessage(groupJid, { disappearingMessagesInChat: false })

// Configurar tempo de expiração customizado (Exemplo: 7 dias)
await sock.sendMessage(groupJid, { disappearingMessagesInChat: 604800 })

Aviso: Suportado exclusivamente em chats de grupos (@g.us).

⚡ Mensagem Bruta (Raw)

Caso queira contornar as validações da biblioteca e enviar uma mensagem formatada diretamente nas especificações do WAProto:

await sock.sendMessage(jid, {
  raw: true, // Ignora o pré-processador da biblioteca
  extendedTextMessage: {
    text: 'Minha mensagem enviada no padrão proto cru do WhatsApp'
  }
})

🤖 Formatação Avançada de Respostas Ricas (IA)

As Mensagens Ricas (AIRichResponseMessage) são balões de formatação avançada criados para se assemelharem às interações estruturadas de Inteligência Artificial nativas do WhatsApp.

⚠️ Atenção: Os parâmetros contentText, headerText, footerText e disclaimerText não atuam como chaves de disparo. O envio isolado desses campos gerará uma falha do tipo Error: Invalid media type. Certifique-se de sempre inserir ao menos uma mídia rica disparadora (code, table, richImage, richResponse, etc).

✍️ addText

// ✅ Forma correta de enviar blocos textuais ricos usando o array richResponse
await sock.sendMessage(jid, {
  richResponse: [
    { text: 'Este é um bloco textual gerado via IA contendo formatações de *itálico* e **negrito**.' }
  ],
  headerText: 'Título Informativo',
  footerText: 'Informações Finais',
  disclaimerText: 'Mensagem gerada por Inteligência Artificial'
})

💻 addCode

Insere trechos de códigos com destaque e formatação estruturada na conversa:

await sock.sendMessage(jid, {
  code: 'const soma = (a, b) => a + b;\nconsole.log(soma(5, 10));',
  language: 'javascript', // Linguagem para formatação do código
  headerText: 'Exemplo prático de JavaScript:',
  footerText: 'Fim do trecho de código'
})

Lista de chaves de linguagens suportadas pela biblioteca:

| Linguagem | Chaves Suportadas | |---|---| | JavaScript | javascript, js | | TypeScript | typescript, ts | | Python | python, py | | Go | go, golang | | C++ | cpp, c++ | | Rust | rust, rs | | Java | java | | PHP | php | | Ruby | ruby, rb | | Kotlin | kotlin, kt | | Swift | swift | | C | c | | SQL / Banco de Dados | sql, mysql, postgresql, sqlite | | Bash / Shell | bash, sh, shell | | HTML / CSS | html, css | | JSON / YAML | json, yaml, yml |

📊 addTable

await sock.sendMessage(jid, {
  table: [
    ['Produto', 'Quantidade', 'Preço'], // Primeira linha define os cabeçalhos
    ['Celular', '10', 'R$ 2999'],
    ['Notebook', '5', 'R$ 4500']
  ],
  title: 'Inventário de Estoque',
  headerText: 'Confira as tabelas atualizadas',
  footerText: 'Dados de Dezembro de 2025'
})

// Tabela sem cabeçalho (utilizando a chave noHeading)
await sock.sendMessage(jid, {
  table: [
    ['Taxa de Entrega', 'R$ 15,00'],
    ['Desconto Aplicado', '-R$ 10,00']
  ],
  noHeading: true,
  title: 'Detalhamento Financeiro'
})

🖼️ addImage

// Envio de imagem rica unitária
await sock.sendMessage(jid, {
  richImage: 'https://example.com/banner.jpg',
  headerText: 'Capa da Campanha'
})

// Envio de múltiplas imagens em formato grade rica (Grid)
await sock.sendMessage(jid, {
  richImage: [
    'https://example.com/imagem1.jpg',
    'https://example.com/imagem2.jpg',
    'https://example.com/imagem3.jpg'
  ],
  headerText: 'Grade de fotos do evento'
})

🎬 addVideo

// Envio de vídeo rico com definição opcional de duração (sintaxe: 'url|segundos')
await sock.sendMessage(jid, {
  richVideo: 'https://example.com/video.mp4|60', // 60 segundos
  headerText: 'Apresentação Institucional'
})

// Lista contendo múltiplos vídeos ricos em sequência
await sock.sendMessage(jid, {
  richVideo: [
    'https://example.com/video1.mp4|30',
    'https://example.com/video2.mp4|45'
  ],
  headerText: 'Lista de reprodução de tutoriais'
})

🔗 addSource

Permite indexar fontes de referências externas contendo ícones e links:

await sock.sendMessage(jid, {
  source: [
    {
      url: 'https://wikipedia.org',
      title: 'Artigo Principal Wikipedia',
      display_name: 'Wikipedia',
      subtitle: 'Enciclopédia Livre',
      favicon: 'https://wikipedia.org/favicon.ico'
    }
  ],
  headerText: 'Fontes consultadas'
})

🎥 addReels

Cria uma listagem com rolagem horizontal contendo vídeos curtos (Reels):

await sock.sendMessage(jid, {
  reels: [
    {
      username: 'criador_tech',
      videoUrl: 'https://example.com/video.mp4',
      thumbnailUrl: 'https://example.com/capa.jpg',
      profileIconUrl: 'https://example.com/avatar.jpg',
      reels_title: 'Como automatizar chats',
      likes_count: 5200,
      view_count: 90000,
      reel_source: 'IG',
      is_verified: true
    }
  ],
  headerText: 'Destaques em vídeos curtos'
})

🛍️ addProduct

// Produto único rico (Layout Single)
await sock.sendMessage(jid, {
  richProduct: {
    title: 'Camiseta Premium',
    brand: 'Diana Vestuário',
    price: 'R$ 79,90',
    product_url: 'https://loja.dianabots.com/camiseta',
    image_url: 'https://example.com/camiseta.jpg'
  },
  headerText: 'Sugestão de Compra'
})

// Múltiplos produtos ricos (Layout HScroll com rolagem)
await sock.sendMessage(jid, {
  richProduct: [
    { title: 'Item A', price: 'R$ 29', product_url: 'https://loja.com/a', image_url: 'https://loja.com/a.jpg' },
    { title: 'Item B', price: 'R$ 39', product_url: 'https://loja.com/b', image_url: 'https://loja.com/b.jpg' }
  ],
  headerText: 'Confira as promoções do dia'
})

📝 addPost

Publicações ricas simulando redes sociais:

await sock.sendMessage(jid, {
  richPost: {
    username: 'dianabots_oficial',
    profile_picture_url: 'https://example.com/avatar.jpg',
    is_verified: true,
    thumbnail_url: 'https://example.com/post_capa.jpg',
    post_caption: 'Acabamos de lançar as respostas ricas para o bot!',
    likes_count: 4500,
    post_url: 'https://instagram.com/p/post_id',
    source_app: 'INSTAGRAM',
    orientation: 'LANDSCAPE'
  },
  headerText: 'Publicação Recente'
})

💡 addTip

Adiciona blocos explicativos de dicas no rodapé ou cabeçalho das respostas ricas:

await sock.sendMessage(jid, {
  tip: 'Dica: Você pode encadear múltiplas tabelas e blocos utilizando o array richResponse.',
  headerText: 'Dica de Uso'
})

🔮 addSuggest

Exibe pílulas horizontais contendo botões de sugestões rápidas para facilitar a resposta dos usuários:

await sock.sendMessage(jid, {
  contentText: 'O que você deseja fazer agora?',
  suggest: [
    'Ver exemplo de código',
    'Acessar tabelas',
    'Falar com suporte'
  ]
})

🗺️ Mapa Rico, LaTeX, Grades & Animações

// LaTeX (Expressões matemáticas formatações ricas)
await sock.sendMessage(jid, {
  latex: {
    text: 'Equação de Einstein:',
    expressions: [
      { expression: 'E = mc^2', width: 120, height: 40 }
    ]
  },
  headerText: 'Física Teórica'
})

// Mapa Rico integrado com marcadores
await sock.sendMessage(jid, {
  map: {
    centerLatitude: -23.55052,
    centerLongitude: -46.633308,
    latitudeDelta: 0.05,
    longitudeDelta: 0.05,
    showInfoList: true,
    annotations: [
      { number: 1, latitude: -23.55052, longitude: -46.633308, title: 'São Paulo', body: 'Cidade Central' }
    ]
  },
  headerText: 'Coordenadas Geográficas'
})

📥 Receber & Decodificar Mensagem Rica

Para capturar e decodificar mensagens ricas recebidas pelo bot, utilize a seguinte estrutura no escutador messages.upsert:

const { normalizeMessageContent, parseRichMessage } = require('@dianabots/baileys')

sock.ev.on('messages.upsert', async ({ messages }) => {
  for (const msg of messages) {
    const inner = normalizeMessageContent(msg.message)
    const parsed = parseRichMessage(inner?.richResponseMessage)

    if (!parsed) continue

    for (const sub of parsed.submessages) {
      switch (sub.type) {
        case 'text':         console.log('Teks:', sub.text); break
        case 'code':         console.log('Código:', sub.language, sub.raw); break
        case 'table':        console.log('Tabela:', sub.title, sub.rows); break
        case 'gridImage':    console.log('Grid Image:', sub.gridImageUrl); break
        case 'inlineImage':  console.log('Inline Image:', sub.imageUrl); break
        case 'dynamic':      console.log('Dynamic:', sub.url); break
        case 'map':          console.log('Map:', sub.centerLatitude, sub.centerLongitude); break
        case 'latex':        console.log('LaTeX:', sub.expressions); break
        case 'contentItems': console.log('Content Items:', sub.items); break
      }
    }
  }
})

🏛️ Licença

Este projeto é distribuído sob os termos da licença MIT. Veja o arquivo LICENSE para mais informações.