Recipes
Complete patterns, not fragments. Every recipe assumes the Getting Started socket (with the store wired and saveCreds hooked) already exists.
1 โ Prefix command bot
const PREFIX = '/'
const commands = {
ping: async (sock, m) => sock.aunuHandler.reply(m.key.remoteJid, { text: 'Pong ๐ค' }, m),
menu: async (sock, m) =>
sock.aunuHandler.send(m.key.remoteJid, {
text: ['*AunuCore Bot*', '/ping โ check the bot', '/menu โ this menu'].join('
')
})
}
sock.ev.on('messages.upsert', async ({ messages, type }) => {
if (type !== 'notify') return
for (const m of messages) {
if (m.key.fromMe || !m.message) continue
const text = m.message.conversation || m.message.extendedTextMessage?.text || ''
if (!text.startsWith(PREFIX)) continue
const name = text.slice(PREFIX.length).split(' ')[0].toLowerCase()
const cmd = commands[name]
if (cmd) {
await sock.readMessages([m.key])
await cmd(sock, m).catch(err => console.error(name, err))
}
}
})
2 โ Group welcome & goodbye
sock.ev.on('group-participants.update', async ({ id, participants, action }) => {
const meta = await sock.groupMetadata(id).catch(() => null)
for (const p of participants) {
const num = '@' + p.split('@')[0]
if (action === 'add') {
await sock.sendMessage(id, {
text: `Welcome ${num} to *${meta?.subject || 'the group'}* โ ${meta?.participants.length || ''} members strong. Read the description, say hi!`,
mentions: [p]
})
}
if (action === 'remove') {
await sock.sendMessage(id, { text: `${num} left the group.`, mentions: [p] })
}
}
})
Mentions only notify when the JID is in the mentions array and written as @number in the text โ both halves above matter.
3 โ Sticker maker (reply to an image)
import { downloadMediaMessage } from 'aunubaileys'
// inside your command handler, for the command /sticker:
const quoted = m.message.extendedTextMessage?.contextInfo?.quotedMessage
const imgMsg = quoted?.imageMessage ? { message: quoted, key: m.key } : null
if (!imgMsg) return sock.aunuHandler.reply(jid, { text: 'Reply to an image with /sticker.' }, m)
const buffer = await downloadMediaMessage(imgMsg, 'buffer', {})
// Convert to 512x512 WebP first (sharp/jimp โ optional peers), then:
await sock.sendMessage(jid, { sticker: buffer }, { quoted: m })
For a whole pack instead of one sticker, collect the converted WebPs and send them with the stickerPack content form from Sending Messages.
4 โ Tally poll results
import { getAggregateVotesInPollMessage } from 'aunubaileys'
sock.ev.on('messages.update', (updates) => {
for (const { key, update } of updates) {
if (!update.pollUpdates?.length) continue
store.loadMessage(key.remoteJid, key.id).then(pollMsg => {
if (!pollMsg) return
const results = getAggregateVotesInPollMessage({ message: pollMsg.message, pollUpdates: update.pollUpdates })
console.log(results.map(r => r.name + ': ' + r.voters.length + ' votes').join('
'))
})
}
})
This is why the store matters: votes arrive as bare updates โ the original poll message (with its options and encryption key) comes from your store.
5 โ Scheduled channel announcements, safely
import { wrapAntiBan } from 'aunubaileys'
sock = wrapAntiBan(sock) // announcements inherit rate limits + typing
const CHANNEL = '120363xxxxxxxxx@newsletter'
async function announce(text) {
await sock.sendMessage(CHANNEL, { text, ai: false })
}
// e.g. from cron / setInterval in your own scheduler:
setInterval(() => announce('Daily build is out โ see the changelog.'), 24 * 60 * 60 * 1000)
6 โ Save every document you're sent
import { downloadMediaMessage } from 'aunubaileys'
import { createWriteStream } from 'node:fs'
import { pipeline } from 'node:stream/promises'
sock.ev.on('messages.upsert', async ({ messages, type }) => {
if (type !== 'notify') return
for (const m of messages) {
const doc = m.message?.documentMessage
if (!doc) continue
const stream = await downloadMediaMessage(m, 'stream', {})
await pipeline(stream, createWriteStream('./inbox/' + (doc.fileName || m.key.id)))
await sock.aunuHandler.react(m.key.remoteJid, '๐ค', m.key)
}
})