Documentation Index
Fetch the complete documentation index at: https://zapo.to/llms.txt
Use this file to discover all available pages before exploring further.
Padrões curtos e completos, construídos sobre a API real. Eles assumem que você já tem um client conectado — veja o Quickstart para o setup.
O texto recebido pode chegar como um conversation simples ou um extendedTextMessage (quando tem reply/preview). Normalize os dois:
function getText(message: { conversation?: string | null; extendedTextMessage?: { text?: string | null } | null } | null | undefined) {
return message?.conversation ?? message?.extendedTextMessage?.text ?? undefined
}
Roteador de comandos
Faça o parse de um /comando inicial e despache. Ignore suas próprias mensagens enviadas com event.isSender:
client.on('message', async (event) => {
if (event.isSender) return // ignora nossos próprios envios (echo multi-device)
const text = getText(event.message)?.trim()
const to = event.chatJid ?? event.senderJid
if (!text || !text.startsWith('/') || !to) return
const [command, ...args] = text.slice(1).split(/\s+/)
switch (command) {
case 'ping':
await client.message.send(to, 'pong')
break
case 'echo':
await client.message.send(to, args.join(' ') || '(nothing to echo)')
break
default:
await client.message.send(to, `Unknown command: ${command}`)
}
})
Responder com citação e menção
client.on('message', async (event) => {
const to = event.chatJid
if (!to || event.isSender) return
await client.message.send(
to,
{ type: 'text', text: 'got it 👍' },
{ quote: event, mentions: event.senderJid ? [event.senderJid] : [] }
)
})
Faça stream direto para o disco — nunca bufferize arquivos grandes na memória:
client.on('message', async (event) => {
if (!event.message?.imageMessage) return
const file = `./media/${Date.now()}.jpg`
await client.message.downloadToFile(event, file)
console.log('saved', file)
})
Veja Mídia › Baixando mídia recebida para vídeo/áudio/documentos e maxBytes.
Dar boas-vindas a novos membros do grupo
O evento group dispara em mudanças de participantes. Cumprimente todos que foram adicionados (action: 'add') e mencione-os:
client.on('group', async (event) => {
if (event.action !== 'add' || !event.groupJid || !event.participants?.length) return
const jids = event.participants.map((p) => p.jid).filter((j): j is string => Boolean(j))
const mentions = jids.map((j) => `@${j.split('@')[0]}`).join(' ')
await client.message.send(
event.groupJid,
{ type: 'text', text: `Welcome ${mentions}! 🎉` },
{ mentions: jids }
)
})
Enviar uma enquete
await client.message.send(chatJid, {
type: 'poll',
name: 'Lunch?',
options: ['Pizza', 'Sushi', 'Salad'],
selectableCount: 1
})
Reagir a uma mensagem
client.on('message', async (event) => {
if (event.isSender || !event.chatJid) return
await client.message.send(event.chatJid, {
type: 'reaction',
emoji: '❤️',
target: { stanzaId: event.stanzaId!, fromMe: false, participant: event.senderJid }
})
})
Manter o bot vivo entre quedas
O zapo não reconecta sozinho — ligue o evento connection a um loop de backoff. O padrão completo (incluindo quando não reconectar) está em Reconexão e Erros & desconexões.