Skip to main content
These are the data types you receive in event payloads and pass to Client methods. The SDK ships full TypeScript declarations, so your editor knows all of this already.

Message

The payload of a messageCreate event, and each element of a fetchMessages() result.

Fields

string
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.
string
The sender’s normalized id. Compare with client.user?.id to detect your bot’s own messages.
string
The sender’s display name. This is empty for messages returned by fetchMessages(), which does not carry usernames.
string
The unique id of this message. Cloak message ids are random UUIDs and are not time-sortable.
string | null
The server the message came from, or null when isDM is true. A direct message has no server at all.
Guard before using it. if (msg.isDM || !msg.serverId) return; is the standard first line of a messageCreate handler that does server-scoped work. Passing a null value into client.can(), client.guild(), or client.send() is the most common bug in Cloak bots.
string
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.
boolean
True when this message arrived as a direct message rather than from a channel. See Direct messages.
string | null
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.
Date | null
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.
object | null
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.
MessageMentions
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.
boolean
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.
FileAttachment[]
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.
MessagePoll | null
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.
string | null
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.
string | null
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.
string | null
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.
string | null
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.
boolean
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.
MessageCard | null
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.
boolean
Whether the message is pinned, when known. Present on messages from fetchMessages() and after a pinUpdate.
CommandInvocation | undefined
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

(text: string, opts?: SendOptions) => Promise<void>
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.
(text: string, opts?: SendOptions) => Promise<void>
A plain send into the same channel or DM, with no quote header and no reply notification. This is what a ping bot wants.
(reactionId: string) => Promise<void>
Adds a reaction. reactionId is opaque: a unicode emoji, or a custom emoji id from fetchEmojis(). Requires reaction_add. See Reactions.
(reactionId: string) => Promise<void>
Removes your bot’s own reaction.
(newContent: string) => Promise<void>
Edits the message. Author only, server-side. Re-encrypts with the channel’s current epoch key, exactly like send(). See Editing, deleting, and pinning.
() => Promise<void>
Deletes the message. Author, or a member with message_manage for others’ messages.
() => Promise<void>
Pins the message. Author, or a member with the channel’s pin permission.
() => Promise<void>
Unpins the message.
(card: CardEdit) => Promise<void>
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.
pin() and unpin() reject unconditionally on a DM message, with a plain Error, before anything reaches the wire. The other five work on a DM message that carries createdAt, which needs a backend that honors wire version 3; without a timestamp they reject with a plain Error saying so. reply() and channel.send() work everywhere. See Direct messages.
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().
string
The channel’s group, for the rare case where the SDK has not already cached it from an inbound frame.
MentionTarget[]
Who to notify.
Mention targets are sent in plaintext. The server routes notification fanout without decrypting the message body, so who your bot pinged is visible server-side even though what it said is not. This is Cloak’s design. See Encryption lanes.
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.
ReplyTarget
Makes this send a true reply: it renders the quote header and fires the “replied to you” notification.
PollCreate
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.
string
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.
string
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.
boolean
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.
number
default:"15000"
How long an ack: true send waits for its echo.
This object replaced a positional groupId fourth argument in 0.2.0, and the positional form is gone. send(s, c, text, groupId) becomes send(s, c, text, { groupId }).

BotCapabilities

What capabilities() 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

What sendFile() and sendFiles() take: every send option plus the caption and a signal that cancels the upload and grant legs.

FileInput

One file to attach. contentType defaults to application/octet-stream; the SDK never sniffs. The bytes are encrypted before they leave the host.

TypingTarget

The optional fourth argument of sendTyping(): the channel’s group, or one container to type in.

ReplyTarget

The message a send is replying to. A received Message satisfies it structurally, so { replyTo: msg } just works.
All three fields ride the wire together, and the server re-reads the original row using all three as a compound key. 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 in SendOptions.mentions. Ids may be dashed or undashed.
Role, @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 as Message.mentions.
string[]
Normalized ids from <@id> user-mention entities in the body.
string[]
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.
boolean
True when the body carries @everyone. Matched case-insensitively, like the real clients.
boolean
True when the body carries @here.

SystemMessageEvent

The payload of a systemMessage event.
'member_join' | 'bot_add' | 'thread_created' | 'unknown'
Which system event this is.
string
The id of the member the event is about, such as the person who joined.
string
The display name of that member.
string
The server the event happened in. Not nullable: system messages are always server events.
string
The channel the event is associated with.
string
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.
string
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 of forumPostUpdate, the result of createForumPost(), and each element of a fetchForumPosts() page.
string
The parent forum channel the post lives in.
string
Decrypted best-effort with the server key for the ciphertext’s own epoch. '' (never ciphertext) when the key is missing.
number[]
The applied tag ids. Resolve names through fetchForumMeta().
boolean
The computed archive verdict: the manual flag folded with the forum’s lazy auto-archive.
boolean
A locked post rejects replies with -18 on sendRejected.
object | null
The accepted answer, when the post is marked solved. Set with setForumPostState(..., 'answered', msg).
string | null
The post’s first message. null only on the row createForumPost() synthesizes when the server’s own create event has not arrived in time.
string | null
The starter’s decrypted body when the row carried it (a fetchForumPosts() page, or the create event). null otherwise, including on activity bumps.
boolean
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 on ForumMeta. 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 by fetchForumMeta().
guidelines is decrypted best-effort and '' when absent or the key is missing. requireTag: true means createForumPost() without a tag denies -4.

ForumPostStateFieldName

The field argument of setForumPostState().

Interaction

The payload of the interaction 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

string
The server-minted interaction id. Valid for 15 minutes after the click.
'button' | 'select' | 'modal'
What produced it.
string
The button’s, select’s, or modal’s customId, verbatim.
string[]
A select’s chosen option values. Empty for a button or a modal.
Record<string, string>
A modal’s input values keyed by input customId. Empty otherwise.
string | null
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.
string
Who clicked, normalized.
string
The addressed bot. Always this one: the SDK drops clicks addressed to another bot.
string
The message the control lives on. A click inside an ephemeral reply carries the original message id.
string | null
The server, or null for a click inside a DM.
string
The id the message lives in: a thread or post id when inside one, the dm id in a DM.
string | null
Set when channelId is a thread the SDK’s thread index knows.
string | null
Set when channelId is a forum post the SDK’s post index knows.
Date | null
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 a CloakClientError whose source is 'interaction', before any frame goes out, and the server refuses it too. A server-side refusal rejects with CloakActionError.
() => Promise<void>
Clear the clicker’s pending state and show nothing.
(def: ModalDefinition) => Promise<void>
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.
(reply: EphemeralMessage) => Promise<void>
Show the clicker, and nobody else, a reply under the message. Never stored. Rows inside it are clickable. See EphemeralMessage.

Member

One server member.
The only producer of Member[] is fetchMembers(), which hangs against every current Cloak backend. The shape below survives the eventual fix, so code written against it stays valid, but you cannot obtain one today.

MemberSearchResult

One searchMembers() 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.
string
The member’s normalized id.
string
The member’s display name.
number
Online status code, where 0 means offline.
Date | null
Account creation time, not the time the member joined the server, when known.
string | null
The member’s avatar reference, or null.
number | null
The member’s subscription tier, or null.
boolean
Whether the member is a bot.
MemberRole | null
The member’s assigned role, or null.

MemberRole

A member’s assigned role, carried on Member.
string
The role’s normalized id.
string
The role’s name.
string | null
The role’s primary color, or null.
string | null
The role’s secondary color, or null.
boolean
Whether the role confers admin standing.

Role

One server role, returned by fetchRoles().
string
The role’s normalized id.
string
The role’s name.
string | null
The role’s primary color, or null.
string | null
The role’s secondary color, or null.
number | null
The role’s position in the ordering, or null. Lower numbers sort higher.
number
How many members hold the role.

BanInfo

One entry in a server’s ban list, returned by fetchBans().
string
The banned member’s normalized id.
string | null
The resolved display name, or null when the account no longer resolves.
Date | null
When the ban was recorded, when known.
string
The stored ban reason, or an empty string.

MessageLocation

The remembered location of a message the bot has seen, returned by messageLocation().
string | null
The server the message is in, or null for a DM. When it is null, channelId holds the dm id.
string
The channel the message is in.
string
The channel’s group, where known.
string
The message author’s normalized id.
number | null
The message’s send time in milliseconds, or null.

ChannelInfo

One channel of a server, returned by fetchChannels() and getChannel().
string
The channel’s normalized id, in the same shape as every other id the SDK hands you.
string
The channel’s name.
string
The channel’s group, which the Cloak clients call a category. This is the value SendOptions.groupId and deleteChannel() want.
number
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.
number
The channel’s sort position within its group.
Date | null
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 against ChannelInfo.type and for passing to createChannel().
Text and voice are the two your bot is most likely to care about: text channels are where 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.
A channel created before Cloak had channel types carries no type on the wire. The SDK reports those as ChannelType.TEXT, which is what they are and what every Cloak client treats them as. You will never see a null here.

VoiceConnection

Your bot’s own voice membership, returned by joinVoice() and voiceConnection().
string
The LiveKit credential the backend minted, opaque to the SDK.
This is a live credential. Never log it. A bot session’s grant is microphone-only, so a bot cannot publish video with it whatever permissions it holds.
string
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.
boolean
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, from voiceRoster() and the voiceJoin event. Eventually consistent.
boolean
True while the member’s voice session is inside the backend’s 60 second reconnect grace window.
p2pWebcam and p2pStream are deprecated and permanently false. Peer-to-peer video is deleted from the Cloak platform, and the wire columns those fields read no longer exist. Do not treat them as capability flags.
serverMuted and serverDeafened come from a separate server-side query and are best-effort. The other flags are reliable.

BotStatus

The named presence values setStatus() 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 a voiceStateUpdate event.
The last two are dead values that can no longer arrive, for the same reason as the VoiceParticipant fields above.

Guild

The payload of guildCreate and guildDelete. A server is called a guild here, matching the discord.js naming.

BotUser

Your bot’s identity, available as client.user after login.
string
Your bot’s normalized id. Compare it against msg.authorId to ignore your bot’s own messages.
string
Your bot’s username.

PermissionSet

The resolved capability set for one server: 43 named booleans plus a numeric rank. Returned by permissions() and spread into the permissionsUpdate payload.
Documented in full, with every permission name, on Permissions.

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.