All Docs
Navibot

Navibot - Messaging

Last modified

Sending Messages

Sends a plain-text message. Fire-and-forget (non-blocking).

navi.say(msg.channel_id, "Hello world!")

Like navi.say but blocks until the message is sent and returns the new message’s snowflake ID as a string, or nil on error.

local msg_id = navi.say_sync(channel_id, "This message was sent synchronously")

Sends a rich embed with optional buttons/selects. Fire-and-forget.

navi.send_message(channel_id, {
    title = "Welcome!",
    description = "Glad to have you here.",
    color = 0x2ECC71
})

Like navi.send_message but blocks until sent and returns the message ID as a string, or nil on error. Useful when you need to store the message ID for later editing.

local message_id = navi.send_message_sync(channel_id, build_embed())
if message_id then
    navi.db.set("stats:live_message_id", message_id)
end

Sends a plain-text direct message to a user. If the user has DMs disabled, the error is logged but does not crash the plugin.

navi.dm(ctx.user_id, "Hey, check this out!")

Adds a reaction to a message.

  • emoji: A Unicode emoji ("❤️", "⭐") or a custom emoji string in the format "name:id".
navi.react(tostring(msg.channel_id), tostring(msg.message_id), "⭐")

Edits the text content of a message the bot previously sent.

navi.edit_message(channel_id, message_id, "Updated content")

Replaces the embed on a message the bot previously sent. Useful for live-updating stat embeds.

navi.edit_embed(channel_id, message_id, build_embed())

Deletes a message.

navi.delete_message(tostring(msg.channel_id), tostring(msg.message_id))

Fetches a message from Discord by ID. Blocks until complete. Returns a table or nil if not found.

local fetched = navi.fetch_message(channel_id, message_id)
if fetched then
    navi.log.info("Message content: " .. fetched.content)
end
FieldTypeDescription
fetched.message_idstringThe message’s snowflake ID
fetched.channel_idstringThe channel’s snowflake ID
fetched.guild_idstring|nilThe guild’s snowflake ID
fetched.contentstringThe message text
fetched.author_idstringThe author’s snowflake ID
fetched.authorstringThe author’s username
fetched.attachmentsstring[]Array of attachment URLs

Embed Structure

An embed is a rich message card. You pass the same embed table structure to navi.send_message, ctx.reply_embed, and ctx.followup_embed.

{
    title       = "Optional title",
    description = "Main body text. Supports **markdown**.",
    color       = 0x3498DB,
    image       = "https://example.com/image.png",
    fields = {
        { name = "Field 1", value = "Some text",  inline = true  },
        { name = "Field 2", value = "More text",  inline = true  },
        { name = "Long one", value = "Full width", inline = false },
    },
    components = {
        -- Buttons and/or a select menu
    }
}
FieldTypeDescription
titlestringBold title at the top
descriptionstringMain body text (supports Discord markdown)
colornumberHex color as an integer, e.g. 0xFF0000 for red
imagestringURL of a large image to display at the bottom
fieldstableArray of {name, value, inline?} objects
componentstableArray of buttons and/or one select menu

When inline = true, up to 3 fields display side-by-side. Use inline = false (or omit it) for full-width fields.

Common Colors

0x2ECC71  -- Emerald green  (success)
0xE74C3C  -- Alizarin red   (error / danger)
0xF1C40F  -- Sunflower gold (warning / economy)
0x3498DB  -- Peter River blue (info)
0x5865F2  -- Discord blurple
0x99AAB5  -- Grey/neutral
0x000000  -- Black (removes the color bar)

Member & Role Management

Assigns a role to a member. All arguments are strings.

navi.add_role(ctx.guild_id, ctx.user_id, verified_role_id)

Removes a role from a member.

navi.remove_role(ctx.guild_id, ctx.user_id, unverified_role_id)

Fetches live member info from Discord. Blocks until complete. Returns a table or nil.

local member = navi.get_member(ctx.guild_id, ctx.user_id)
if member then
    navi.log.info("Display name: " .. member.display_name)
end
FieldTypeDescription
member.user_idstringThe member’s snowflake ID
member.usernamestringThe member’s username
member.display_namestringNickname if set, otherwise username
member.nicknamestring|nilServer-specific nickname, or nil
member.joined_atstring|nilISO 8601 timestamp of when they joined
member.rolesstring[]Array of role snowflake IDs

Kicks a member from the guild. The reason appears in the audit log.

navi.kick(ctx.guild_id, target_user_id, "Spam")

Bans a member. delete_message_days (0–7) controls how many days of their recent messages to delete.

navi.ban(ctx.guild_id, target_user_id, 1, "Harassment")

Removes a ban.

navi.unban(ctx.guild_id, target_user_id)

Times out a member (they cannot send messages or join voice). Pass 0 to remove an existing timeout.

navi.timeout(ctx.guild_id, target_user_id, 600)  -- 10 minutes
navi.timeout(ctx.guild_id, target_user_id, 0)    -- remove timeout

Channel Management

Creates a new text channel in the guild.

navi.create_channel(ctx.guild_id, "ticket-username", {
    category_id     = category_id,
    user_id         = ctx.user_id,
    role_id         = support_role_id,
    welcome_message = "Welcome! Staff will be with you shortly.",
    close_button    = true
})
OptionTypeDescription
category_idstring|nilSnowflake ID of the parent category
user_idstring|nilGrant this user private View + Send permissions
role_idstring|nilGrant this role private View + Send permissions
welcome_messagestring|nilText sent immediately after the channel is created
close_buttonboolean|nilIf true, attaches a red “Close Ticket” button to the welcome message

Permanently deletes a channel. This is instant and irreversible.

navi.delete_channel(ctx.channel_id)

Creates a thread and returns its channel ID as a string, or nil on failure. Blocks until complete.

local thread_id = navi.create_thread(ctx.channel_id, "Discussion", {
    message_id   = ctx.message_id,
    private      = true,
    auto_archive = 60
})

if thread_id then
    navi.say(thread_id, "Thread is open!")
end
OptionTypeDefaultDescription
message_idstring|nilnilIf set, creates the thread attached to this message
privatebooleanfalseCreate a private thread (invite-only)
auto_archivenumber1440Minutes until auto-archive: 60, 1440, 4320, 10080

Discord Cache

These functions return data from the bot’s cached guild state. Press u in the TUI to refresh the cache.

Returns an array of role objects for the guild.

local roles = navi.get_roles(ctx.guild_id)
for _, role in ipairs(roles) do
    navi.log.info(role.id .. " — " .. role.name)
end
FieldTypeDescription
role.idstringThe role’s snowflake ID
role.namestringThe role’s display name
role.colorinteger[]RGB tuple: {r, g, b}

Returns an array of text channel objects for the guild.

local channels = navi.get_channels(ctx.guild_id)
for _, ch in ipairs(channels) do
    navi.log.info(ch.id .. " — #" .. ch.name)
end
FieldTypeDescription
ch.idstringThe channel’s snowflake ID
ch.namestringThe channel’s display name

Bot Status

Changes the bot’s Discord presence (the “Playing X” message shown in the member list).

  • activity_type: "playing", "listening", "watching", "competing", "custom", or "none"
navi.set_status("watching", "over the server")
navi.set_status("none", "")  -- clears the status