{ kind: 'call' } event).
The handler receives a context with type === 'call', an empty body,
sender set to the caller (CallEvent.from, the same canonical id their
messages carry) and ctx.call holding the CallEvent. For a 1:1 call from
is the DM with the caller; for a group call (CallEvent.isGroup) from is the
group and isGroup is true, so scope: 'dm' | 'group' tells them apart.
ctx.reply() answers in that chat and a flow(CALL) keeps talking there (per
participant in a group, like any conversation).
- Fires once per call id (the first event seen for it). Transports emit
several updates per call (WhatsApp: offer → ringing/reject/timeout/terminate);
listen to
bot.on('call')to observe every update.ctx.call.offlineflags a notification delivered late (e.g. replayed after a reconnect). - Runs after the
before('call')/after('call')hooks and the'call'event; abefore('call')hook that callsabort()suppresses it (and the after-hooks and the'call'event). - Calls never reach text/function triggers, commands, active conversations,
the catch-all or the
'message'event, and are not persisted as messages. Message-bound helpers (react,quote,markRead,delete) are meaningless here. - A call never replaces a conversation in progress: while the caller has an
active conversation or a dormant (persisted) one, a
flow(CALL)/bot.conversation(…, { trigger: CALL })is skipped as if it did not match (the nextCALLhandler, if any, runs instead); plainbot.when(CALL, fn)handlers still run. - Group calls follow
groupMode: with'mentions'or'commands'they never reachCALLtriggers (a call can neither mention the bot nor be a command). - Ignored while the bot is not started.