Client methods. The SDK ships full TypeScript declarations, so your editor knows all of this already.
Message
The payload of amessageCreate event, and each element of a fetchMessages() result.
Fields
The decrypted message text. Empty string if the key was missing or decryption failed, so check for content before acting on it. Never raw ciphertext.
The sender’s display name. This is empty for messages returned by
fetchMessages(), which does not carry usernames.The server the message came from, or
null when isDM is true. A direct message has no server at all.The channel the message came from. For a DM this is the dm id, the same value as
dmId. One convention, so msg.reply() and msg.channel.send() keep working on a DM without your branching.True when this message arrived as a direct message rather than from a channel. See Direct messages.
The dm id for a DM,
null otherwise. Always equal to channelId when set. It exists so isDM is not the only way to read the intent.The server-generated send time, or
null when the payload omitted it. edit, editCard, delete, pin, unpin, react, and unreact all need this value, so they reject when it is null. Live server messages and fetched messages carry it. A DM message carries it on a backend that honors wire version 3, and not on an older one, where the legacy notify signal has no timestamp.The context of the message this one replies to, or
null for a normal message. Its content is the decrypted quote, decrypted against the key for the quote’s own epoch, and is '' when it cannot be decrypted. Compare repliedTo.authorId with client.user?.id to detect a reply to your bot.On a DM message, set only on a backend that honors wire version 3. null on an older backend, whose notify frame carries no reply array.The mentions carried by this message’s body. See MessageMentions.Derived from the decrypted body, not from a wire field. A sender’s mention array is routing metadata the server consumes for notification fanout and never echoes back, so the body is the only inbound source. The real Cloak clients decide “was I mentioned” the same way.
True when the body carries a
<@id> entity naming your bot. Direct user mentions only.@everyone and @here are mentions.everyone and mentions.here. A role mention cannot be resolved here, because the SDK does not know which roles your bot holds. Role names surface in mentions.names for you to check yourself.The
[file:id:name] attachment references carried by this message’s decrypted body, in order. Parse-only: an entry proves the sender named a file, not that your bot may read it. Download with downloadAttachment(). See File attachments.The native poll this message carries, or
null for a plain message. poll.state is the server’s plaintext structure; poll.data is the decrypted question and labels, best-effort, and null (never ciphertext) when the key is missing. Watch pollUpdate for tallies. See Polls.The thread this message was sent into, or
null for a channel or DM message. When set, channelId is the same id: a thread’s replies are ordinary messages whose channel is the thread, and reply() and channel.send() route back into it. See Threads.The thread’s parent text channel, when the SDK knows it, resolved from its thread index. In practice
null only when event ordering breaks; reply() on a thread message needs it and rejects without it.The forum post this message was sent into, or
null. When set, channelId is the same id and threadId is null. reply() and channel.send() route back into the post. See Forums.The parent forum channel of
postId, or null. Unlike a thread’s parent, this is always known when postId is set, because a post frame carries it on the wire.True for a forum post’s first message. The starter never rides the ordinary message stream: the SDK emits it from the post’s create event, once, with
messageId equal to ForumPost.starterMessageId, right before the matching forumPostUpdate.The encrypted card this message carries, decrypted with the key for its own epoch: every embed that survived the read-side validator, plus the component rows.
null for a plain message, and null (never a partial card) when the payload fails a cap or the media rule. Present on live messages and on fetchMessages() rows. On a DM message it is populated only on a backend that honors wire version 3, including the echo of your own sendCardDM(). See MessageCard.Whether the message is pinned, when known. Present on messages from
fetchMessages() and after a pinUpdate.The slash-command invocation this message carries, when it is one your registry recognizes. Plain data with no back-reference to the message.Filter with
if (msg.command) return; in a messageCreate handler that also does its own text handling, so you do not process an invocation twice. Never set on fetched history (server or DM) or on your bot’s own messages. Set on a DM message when the invocation came from the DM’s / picker on a wire version 3 backend. See CommandInvocation and CommandContext for the serverId, dmId, channelId, and userId a handler receives.Methods
Sends a true reply into the same channel or DM: it renders a quote header and fires a “replied to you” notification that pierces mutes.Use it when your bot is genuinely answering a specific message. For a plain response, use
channel.send().It degrades to a plain send, and never throws, when the message has no createdAt, because the reply pointer cannot be built without the server’s own send time.A plain send into the same channel or DM, with no quote header and no reply notification. This is what a ping bot wants.
Adds a reaction.
reactionId is opaque: a unicode emoji, or a custom emoji id from fetchEmojis(). Requires reaction_add. See Reactions.Edits the message. Author only, server-side. Re-encrypts with the channel’s current epoch key, exactly like
send(). See Editing, deleting, and pinning.Deletes the message. Author, or a member with
message_manage for others’ messages.Replaces this message’s card (embed and component rows) and re-encrypts its text in one edit. Author only, server-side. Fills in the location and
createdAt that client.editCard() needs, including the null server id of a DM. Pass components: [] to retire a card’s buttons. See Buttons and selects.react, unreact, edit, delete, pin, unpin, and editCard reject with CloakActionError on a server deny.
reply() and channel.send() are fire-and-forget for delivery and do not reject on a deny. A denial arrives on sendRejected. See Handling errors.
SendOptions
The options object every send-shaped call takes:send(), msg.reply(), msg.channel.send(), guild().send(), and sendDM().
The channel’s group, for the rare case where the SDK has not already cached it from an inbound frame.
Who to notify.A mention is two independent halves and you supply both. This array is the ping. The pill is literal text in the body, produced by
userMention(), roleMention(), EVERYONE, or HERE. The SDK never scans your outgoing text to synthesize the array. See Mentions.Makes this send a true reply: it renders the quote header and fires the “replied to you” notification.
Attach a native poll to this message. The question and option labels are end-to-end encrypted; the structure (option count, window, flags) is plaintext, because the server validates and tallies votes. Server sends need the create-polls capability, DM polls are ungated, and bots never vote: the backend refuses a bot vote by design. See Polls.
Target this send at a thread of the channel. Pass the parent text channel as
channelId and the thread’s id here. Requires send_in_thread; a locked, deleted, or inaccessible private thread denies on sendRejected. Not valid on DM sends. Mutually exclusive with postId. See Threads.Target this send at a forum post. Pass the parent forum channel as
channelId and the post’s id here. The SDK enters the post, which moves the session cursor, and sends the ordinary frame. A locked post denies -18 on sendRejected; a send into the forum channel with no postId denies -17. Not valid on DM sends. Mutually exclusive with threadId. See Forums.Resolve with the persisted
Message instead of void. The SDK matches the bot’s own firehose echo back to the send by its ciphertext and resolves when it lands, so a resolved promise means the server persisted the row. A denial pinned to this send rejects with CloakActionError; no echo and no deny inside ackTimeoutMs, a socket drop while waiting, or a deny that could belong to several outstanding sends rejects with CloakSendTimeoutError, whose outcome is indeterminate. The wait does not hold the send chain. A DM echo needs a backend that honors wire version 3. See Sending is fire-and-forget unless you ask for a receipt.BotCapabilities
Whatcapabilities() returns: the backend’s own declaration, at login, of which optional behaviors this deployment has. Every flag is a behavior the SDK would otherwise have to probe or assume.
null from capabilities() means the backend sent no map; treat every flag as false.
SendFileOptions
sendFile() and sendFiles() take: every send option plus the caption and a signal that cancels the upload and grant legs.
FileInput
contentType defaults to application/octet-stream; the SDK never sniffs. The bytes are encrypted before they leave the host.
TypingTarget
sendTyping(): the channel’s group, or one container to type in.
ReplyTarget
The message a send is replying to. A receivedMessage satisfies it structurally, so { replyTo: msg } just works.
createdAt must therefore be the server’s own send time, which is exactly what the SDK puts there. The target must live in the channel you are sending to. A target with no createdAt cannot be used, so building a reply slot from one throws.
MentionTarget
One entry inSendOptions.mentions. Ids may be dashed or undashed.
@everyone, and @here targets are dropped server-side inside a DM. Only direct user mentions produce a notification there. See Mentions.
MessageMentions
What the SDK recovers from a decrypted message body, exposed asMessage.mentions.
Literal
@name tokens that are not @everyone or @here and not an id entity. A name may be a role, an older-style user mention, or just text. The SDK cannot tell them apart without the server’s roster, so compare against fetchRoles() if you need to.A multi-word role name yields only its first word here, because the SDK has no role list at decode time.SystemMessageEvent
The payload of asystemMessage event.
The group of the source channel, where known. Pass it to
send() so the message lands in the right channel. It can be undefined if the channel’s group has not been seen yet.For
type: 'thread_created': the new thread’s id. channelId is the parent text channel the system row lives in; the thread’s title arrives on its own threadUpdate. See Threads.ForumPost
One post of a forum channel. The payload offorumPostUpdate, the result of createForumPost(), and each element of a fetchForumPosts() page.
Decrypted best-effort with the server key for the ciphertext’s own epoch.
'' (never ciphertext) when the key is missing.The applied tag ids. Resolve names through
fetchForumMeta().The accepted answer, when the post is marked solved. Set with
setForumPostState(..., 'answered', msg).The post’s first message.
null only on the row createForumPost() synthesizes when the server’s own create event has not arrived in time.The starter’s decrypted body when the row carried it (a
fetchForumPosts() page, or the create event). null otherwise, including on activity bumps.Whether this bot follows the post. Known from the rows that carry it;
false when the row did not say.ForumTag
One tag of a forum channel, carried onForumMeta. The name is end-to-end encrypted like a post title and decrypted best-effort.
moderated: true means only a member who may manage posts can apply it.
ForumMeta
A forum channel’s settings, returned byfetchForumMeta().
guidelines is decrypted best-effort and '' when absent or the key is missing. requireTag: true means createForumPost() without a tag denies -4.
ForumPostStateFieldName
Thefield argument of setForumPostState().
Interaction
The payload of theinteraction event: one click, select, or modal submit on a card your bot posted. It was encrypted by the clicker with the conversation key and pushed to your bot alone.
Fields
For a modal submit, the id of the click that opened it. For a click on a row inside an ephemeral reply, the interaction that produced that reply.
null otherwise.The message the control lives on. A click inside an ephemeral reply carries the original message id.
When the click happened. This is not the message’s send time, so it cannot be passed to
editCard().Methods
Answer with exactly one of these. A second call rejects locally with aCloakClientError whose source is 'interaction', before any frame goes out, and the server refuses it too. A server-side refusal rejects with CloakActionError.
Open a modal on the clicker’s screen. Its submit arrives as a fresh
interaction with kind: 'modal' and parentId equal to this id. Validated locally before anything is encrypted. See Modals.Show the clicker, and nobody else, a reply under the message. Never stored. Rows inside it are clickable. See EphemeralMessage.
Member
One server member.MemberSearchResult
OnesearchMembers() hit. Richer than Member: the search lane carries the display name and nickname.
nickname is '' when none is set. role is the member’s primary role, or null when they have none or the server hides role buckets for offline members.
MemberRole
A member’s assigned role, carried onMember.
Role
One server role, returned byfetchRoles().
BanInfo
One entry in a server’s ban list, returned byfetchBans().
MessageLocation
The remembered location of a message the bot has seen, returned bymessageLocation().
The server the message is in, or
null for a DM. When it is null, channelId holds the dm id.ChannelInfo
One channel of a server, returned byfetchChannels() and getChannel().
The channel’s group, which the Cloak clients call a category. This is the value
SendOptions.groupId and deleteChannel() want.What kind of channel this is. Compare against
ChannelType.Deliberately a plain number rather than a narrowed union, so a channel kind newer than your installed SDK still appears in the list with its wire code intact instead of being dropped or mislabelled.When the channel last received a message, or
null if it never has. Always null on channel kinds that do not carry messages.The channel list is filtered server-side to what your bot may view, so an absent channel is one the bot cannot see rather than one that does not exist. The SDK does no permission math of its own.
ChannelType
The named channel-type codes, for comparing againstChannelInfo.type and for passing to createChannel().
send() works, and voice channels are what joinVoice() accepts.
This list is what Cloak ships today, and it grows. Treat an unrecognized
type as a channel kind your SDK predates rather than as bad data. channelTypeName(code) returns the name for a known code and undefined for anything else, which is the cheapest way to tell the two apart.VoiceConnection
Your bot’s own voice membership, returned byjoinVoice() and voiceConnection().
The LiveKit signalling url:
ClientOptions.livekitUrl, or the value derived from your transport url. The SDK makes no connection to it. Hand it, with the token, to a media layer. See Voice audio.The broadcast deafen flag, not an answer to “can I hear”. Whether the bot receives audio is decided by
voice_listen and the scope of its voice key.VoiceParticipant
One member of a voice channel’s roster, fromvoiceRoster() and the voiceJoin event. Eventually consistent.
True while the member’s voice session is inside the backend’s 60 second reconnect grace window.
serverMuted and serverDeafened come from a separate server-side query and are best-effort. The other flags are reliable.
BotStatus
The named presence valuessetStatus() accepts.
dnd also suppresses push notifications on every device. busy does not. online defers to session liveness rather than pinning a green dot.
VoiceStateFlag
Which flag changed on avoiceStateUpdate event.
VoiceParticipant fields above.
Guild
The payload ofguildCreate and guildDelete. A server is called a guild here, matching the discord.js naming.
BotUser
Your bot’s identity, available asclient.user after login.
PermissionSet
The resolved capability set for one server: 43 named booleans plus a numeric rank. Returned bypermissions() and spread into the permissionsUpdate payload.
Next
Errors
Every error class an action can reject with.
Permissions
All 43 permission names.
Events
Where these types come from.
Client
The methods that return them.