OptionalpushOptionalquotedOptionalmediaOptionalsharedThe location the user shared (type === 'location'), normalized by the provider;
undefined otherwise. Named sharedLocation because ctx.location() SENDS one.
When the message was sent, in epoch milliseconds (new Date(ctx.timestamp) works).
A provider that still reports epoch seconds is converted.
OptionalinteractionPresent only when this context projects an interaction (Telegram/Discord).
acknowledge() is a safe no-op on transports without ack (WhatsApp). On a transport
with capabilities.interactionsRequireAck the core acks on its own; once that ack
went out (after the first send or near the deadline), acknowledge(text) sends
text as a regular reply instead.
OptionalcallPresent only on the context the CALL trigger receives (type === 'call'):
the provider's normalized call notification.
OptionalcapabilitiesCapabilities of the provider this message came from (set on contexts built by a Bot).
OptionaltextRich-text dialect of THIS chat: the provider's textFormatFor(chatId), else
capabilities.textFormat. Unset = unknown (send Markdown untouched). Use it,
not capabilities.textFormat, to format text for the chat (@botmesh/ai does).
Persistent profile of the sender (ctx.sender), shared across chats — see
UserData. ctx.user.ns('game') scopes it to a namespace.
Resolved language of this message (normalized locale code, e.g. 'es', 'en').
Order: ctx.user preference → provider-reported language → i18n.detect → default.
Optional ReadonlydefaultThe bot's default locale (lang / i18n.defaultLocale, 'en' unless configured), whatever
lang resolved to. Plugins that ship their own built-in texts for a few
languages use it as the fallback for a lang they do not cover.
OptionallangWhere lang came from ('user' | 'provider' | 'detector' | 'default');
undefined while i18n is off (then lang is just the default locale). Plugins
that want a real language signal (e.g. a speech-to-text hint) should ignore
'default'. A hook that assigns ctx.lang directly does not update it.
Optionaltext: stringSend text to this chat. Same as MessageContext.reply.
Optionalopts: ReplyOptionsUse MessageContext.reply (ctx.reply(text)). The flow DSL's .say() step is not affected.
Send text to this chat (ctx.from). The canonical text reply.
Optionalopts: ReplyOptionsOptionalopts: ReplyOptionsUse MessageContext.reply (ctx.reply(text)).
Optionalopts: ReplyOptionsUse MessageContext.reply (ctx.reply(text)).
Optionalcaption: stringOptionalcaption: stringOptionalopts: { gifPlayback?: boolean; ptv?: boolean }Optionalfilename: stringOptionalcaption: stringOptionalopts: { pack?: string; author?: string }Optionalname: stringOptionaldisplayName: stringOptionalmultiSelect: booleanReact to the inbound message (or target). On a provider without
capabilities.reactions it resolves a skipped result instead of rejecting.
An empty emoji removes the reaction where the transport supports it.
Optionaltarget: MessageRefOptionalopts: ReplyOptionsEdit this context's own last reply (ctx.edit(content), only when it has the same
content kind and no bot.send/bot.sendTo went to the chat since; replies of other
handler runs or other participants' flows are never targeted) or a given one
(ctx.edit(ref, content); a fallback send goes to ref.chatId). Native when the provider has capabilities.edit and
editMessage; otherwise (or when the kind is not editable there) it falls back
to sending a new message — { fallback: 'skip' } sends nothing instead. Edits run
the before/after('send') hooks (payload edit: ref); a hook abort resolves skipped.
Optionalopts: EditOptionsOptionalopts: EditOptionsHow the current provider supports a messaging feature (native / degraded / unsupported).
Show "typing…" for about msPerChar ms per character (40 by default, capped at 5 s),
then send text. Ignores BotConfig.typing.
OptionalmsPerChar: numberUse ctx.reply(text, { typing: true }) (or a TypingConfig object
such as { typing: { charsPerSecond: 25, maxMs: 5000 } }): it shares the bot-wide
typing policy, refreshes the indicator and is dropped on stop/handoff like every paced reply.
Escape hatch for transport-native content (templates, components).
Stream a reply that is still being generated (e.g. LLM tokens) to this chat,
using the best strategy the provider supports (capabilities.streaming):
native drafts, throttled edits, or sentence chunks with typing. Long text is
split so no message exceeds capabilities.maxTextLength. See StreamOptions.
Optionalopts: StreamOptionsOptionalformSend a native form (OutboundContent kind 'form'). Only meaningful when
capabilities.forms === 'native'; other providers reject it with
UnsupportedContentError. The submission arrives as an inbound message of
type 'form' (see parseFormReply()); flow().form() handles all of this.
Set on contexts built by a Bot.
Optionalopts: { token?: string; nativeId?: string }OptionalcanWhether the provider can render definition natively right now (see
IProvider.canRenderForm). Set on contexts built by a Bot whose provider
implements it; absent = assume yes when capabilities.forms === 'native'.
Optionalopts: { nativeId?: string }Show the typing indicator. Best-effort: never rejects (a provider failure is logged at debug).
Show the recording-audio indicator. Best-effort like typing.
Hand this chat (from) over to a human: the bot stops routing its messages until
bot.resume(chatId), and any conversation in the chat is cancelled silently.
Resolves true if the chat was not already handed off. Safe to call without
awaiting (the state flips synchronously). See bot.handoff().
Optionalopts: HandoffOptionsOptionalnextTranslate key (dot path) in lang, interpolating {param} placeholders;
params.count picks plural forms. Missing keys fall back to the default locale,
then to the key itself. See bot.locale().
Optionalparams: TranslateParamsSwitch the sender's language: persists the registered locale serving code
('en-GB' → 'en' when only en exists) to ctx.user (key 'lang' by default)
and updates lang for this message. Rejects with TypeError on an empty code
or one no registered locale serves (nothing is stored), with Error while i18n is
not enabled (no bot.locale() call and no BotConfig.i18n), and with
UserDataError when the profile cannot be written.
The ergonomic context handed to every handler. Generic over
TRaw. The reply helpers keep IDENTICAL signatures to v1 — internally each now builds anOutboundContentdescriptor and callsprovider.send, instead of hand-rolling Baileys JSON.from/sender/body/type/isGroupare read straight off the normalizedInboundMessage, so user code andkeyForare unchanged.