Documentation Index
Fetch the complete documentation index at: https://whiskeysockets-docs-jids-socket-config-ptbr.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
O Baileys comunica tudo que acontece na sua conexão WhatsApp por um event emitter tipado disponível em sock.ev. Cada nome de evento mapeia para um payload específico definido em BaileysEventMap.
Escutando eventos
Use sock.ev.on para se inscrever e sock.ev.off para sair.
sock.ev.on('messages.upsert', ({ messages, type }) => {
console.log(`Received ${messages.length} message(s) of type "${type}"`)
})
const handler = ({ messages }) => { /* ... */ }
sock.ev.on('messages.upsert', handler)
sock.ev.off('messages.upsert', handler)
A interface BaileysEventEmitter:
export interface BaileysEventEmitter {
on<T extends keyof BaileysEventMap>(event: T, listener: (arg: BaileysEventMap[T]) => void): void
off<T extends keyof BaileysEventMap>(event: T, listener: (arg: BaileysEventMap[T]) => void): void
removeAllListeners<T extends keyof BaileysEventMap>(event: T): void
emit<T extends keyof BaileysEventMap>(event: T, arg: BaileysEventMap[T]): boolean
}
O padrão ev.process()
Para a maioria das aplicações, use sock.ev.process em vez de chamadas individuais a sock.ev.on. O callback recebe um mapa de todos os eventos que dispararam num único tick.
sock.ev.process(async (events) => {
if (events['connection.update']) {
const { connection, lastDisconnect } = events['connection.update']
if (connection === 'close') {
const shouldReconnect =
(lastDisconnect?.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut
if (shouldReconnect) startSock()
}
}
if (events['creds.update']) {
await saveCreds()
}
if (events['messages.upsert']) {
const { messages, type } = events['messages.upsert']
if (type === 'notify') {
for (const msg of messages) {
// trata mensagem recebida
}
}
}
})
ev.process agrupa eventos disparados no mesmo tick. Se uma sincronização entrega 500 mensagens e 200 atualizações juntas, seu handler recebe tudo numa chamada só.
Referência de eventos
connection.update
Dispara sempre que o estado do WebSocket muda. Payload é Partial<ConnectionState>:
type ConnectionState = {
connection: 'open' | 'connecting' | 'close'
lastDisconnect?: { error: Boom | Error | undefined; date: Date }
isNewLogin?: boolean
qr?: string
receivedPendingNotifications?: boolean
isOnline?: boolean
}
sock.ev.on('connection.update', (update) => {
const { connection, lastDisconnect, qr } = update
if (qr) {
// renderize o QR aqui
}
if (connection === 'close') {
const code = (lastDisconnect?.error as Boom)?.output?.statusCode
if (code !== DisconnectReason.loggedOut) {
startSock()
}
}
})
creds.update
Dispara sempre que suas credenciais mudam. Você deve persistir imediatamente.
sock.ev.on('creds.update', saveCreds)
messages.upsert
Evento principal para mensagens recebidas e enviadas.
{
messages: WAMessage[]
type: 'notify' | 'append'
requestId?: string
}
type: 'notify' — mensagens em tempo real. Devem disparar notificações.
type: 'append' — mensagens de histórico/backfill. Não notifique.
sock.ev.on('messages.upsert', ({ messages, type }) => {
if (type !== 'notify') return
for (const msg of messages) {
const text =
msg.message?.conversation ??
msg.message?.extendedTextMessage?.text
if (text) {
console.log(`[${msg.key.remoteJid}] ${text}`)
}
}
})
Sempre itere com for...of. O array pode conter mais de uma mensagem por evento.
messages.update
Status de mensagens — recibos, reações, votos de enquete.
sock.ev.on('messages.update', async (updates) => {
for (const { key, update } of updates) {
if (update.status) {
// 1 = enviado, 2 = recebido, 3 = lido, 4 = reproduzido
console.log(`Message ${key.id} status: ${update.status}`)
}
if (update.pollUpdates) {
const pollCreation = await getMessage(key)
if (pollCreation) {
const result = getAggregateVotesInPollMessage({
message: pollCreation,
pollUpdates: update.pollUpdates,
})
console.log('Poll vote aggregation:', result)
}
}
}
})
messaging-history.set
Lote de sincronização de histórico do celular.
sock.ev.on('messaging-history.set', ({ chats, contacts, messages, isLatest, progress, syncType }) => {
console.log(
`History sync: ${chats.length} chats, ${contacts.length} contacts, ` +
`${messages.length} messages (progress: ${progress}%, latest: ${isLatest})`
)
})
O histórico é entregue em pedaços em ordem cronológica reversa. isLatest no último pedaço indica que terminou.
chats.upsert / chats.update / chats.delete
sock.ev.on('chats.upsert', (chats) => { /* novos chats */ })
sock.ev.on('chats.update', (updates) => { /* updates parciais */ })
sock.ev.on('chats.delete', (jids) => { /* chats deletados */ })
sock.ev.on('contacts.upsert', (contacts) => {
for (const contact of contacts) {
console.log(`Contact: ${contact.id} — ${contact.name ?? contact.notify}`)
}
})
sock.ev.on('contacts.update', async (updates) => {
for (const contact of updates) {
if (typeof contact.imgUrl !== 'undefined') {
const url = contact.imgUrl
? await sock.profilePictureUrl(contact.id!).catch(() => null)
: null
console.log(`${contact.id} has a new profile picture: ${url}`)
}
}
})
groups.upsert / groups.update / group-participants.update
sock.ev.on('groups.upsert', (groups) => { /* você foi adicionado */ })
sock.ev.on('groups.update', (updates) => { /* assunto/desc/settings */ })
sock.ev.on('group-participants.update', ({ id, author, participants, action }) => {
// action: 'add' | 'remove' | 'promote' | 'demote'
console.log(`Group ${id}: ${action} by ${author}`)
})
presence.update
sock.ev.on('presence.update', ({ id, presences }) => {
for (const [jid, data] of Object.entries(presences)) {
console.log(`${jid} in ${id}: ${data.lastKnownPresence}`)
}
})
await sock.presenceSubscribe(jid)
call
sock.ev.on('call', async (calls) => {
for (const call of calls) {
if (call.status === 'offer') {
await sock.rejectCall(call.id, call.from)
}
}
})
Sequência de eventos na primeira conexão
connection.update — connecting
O socket inicia o handshake. connection é 'connecting'.
connection.update — QR ou open
Se faltam credenciais, qr é populado. Após confirmação, connection vira 'open'.
messaging-history.set (lotes)
Se syncFullHistory for true, o celular envia mensagens passadas em pedaços.
connection.update — receivedPendingNotifications
Após o histórico, receivedPendingNotifications vira true.
Eventos em tempo real
Daqui pra frente, eventos disparam em tempo real.
import makeWASocket, {
DisconnectReason,
fetchLatestBaileysVersion,
getAggregateVotesInPollMessage,
makeCacheableSignalKeyStore,
useMultiFileAuthState,
} from '@whiskeysockets/baileys'
import { Boom } from '@hapi/boom'
import P from 'pino'
const logger = P({ level: 'silent' })
async function startSock() {
const { state, saveCreds } = await useMultiFileAuthState('baileys_auth_info')
const { version } = await fetchLatestBaileysVersion()
const sock = makeWASocket({
version,
logger,
auth: {
creds: state.creds,
keys: makeCacheableSignalKeyStore(state.keys, logger),
},
})
sock.ev.process(async (events) => {
if (events['connection.update']) {
const { connection, lastDisconnect, qr } = events['connection.update']
if (connection === 'close') {
const shouldReconnect =
(lastDisconnect?.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut
if (shouldReconnect) startSock()
}
}
if (events['creds.update']) {
await saveCreds()
}
if (events['messaging-history.set']) {
const { chats, contacts, messages, isLatest } = events['messaging-history.set']
console.log(`History: ${chats.length} chats, ${messages.length} messages, latest=${isLatest}`)
}
if (events['messages.upsert']) {
const { messages, type } = events['messages.upsert']
if (type === 'notify') {
for (const msg of messages) {
console.log('New message from', msg.key.remoteJid)
}
}
}
if (events['messages.update']) {
for (const { key, update } of events['messages.update']) {
if (update.pollUpdates) {
const pollCreation = await getMessage(key)
if (pollCreation) {
console.log(
'Poll results:',
getAggregateVotesInPollMessage({
message: pollCreation,
pollUpdates: update.pollUpdates,
})
)
}
}
}
}
if (events['group-participants.update']) {
const { id, participants, action } = events['group-participants.update']
console.log(`Group ${id}: ${action} — ${participants.map(p => p.id).join(', ')}`)
}
if (events['call']) {
for (const call of events['call']) {
if (call.status === 'offer') {
await sock.rejectCall(call.id, call.from)
}
}
}
})
return sock
}