Skip to content

Custom Messages

Sayrix edited this page Apr 29, 2026 · 3 revisions

Ticket-Bot message templates live in the messages/ directory. Config values reference them without the messages/ prefix or file extension.

Example:

message: "tickets/open-panel"

This resolves to:

messages/tickets/open-panel.ts

Template Types

Templates export a Discord message payload object or a function that returns one.

Simple object:

export default {
  content: "Hello from Ticket-Bot"
};

Function:

export default ({ LL }) => ({
  content: LL.tickets.templates.open_panel.description()
});

Templates can use:

  • content
  • embeds
  • components
  • flags
  • allowed_mentions
  • useComponentsV2

Classic Messages vs Components V2

Classic messages can use content and embeds.

Components V2 messages use component types such as containers and text displays. When Components V2 is enabled:

  • Do not use content.
  • Do not use embeds.
  • Put visible text inside components.

Ticket-Bot automatically adds the Components V2 flag when V2 components are detected or useComponentsV2 is true.

Use classic embeds when you want the old Discord embed layout instead of Components V2 containers:

  • Remove useComponentsV2: true.
  • Do not use Components V2 component types such as Container, TextDisplay, Section, Separator, Thumbnail, MediaGallery, or File.
  • Put the visible message body in content and/or embeds.
  • Keep interactive controls as regular action-row components. Ticket-Bot can still inject panel openers and ticket action buttons through slots.

Discord references:

Example: Classic Embed Panel

This creates a panel with a normal Discord embed. The select menu or buttons configured in panels are inserted into the panel-opener slot.

import { createPanelOpenerSlot } from "@/features/tickets/messages";
import type { LoadedMessageTemplate } from "@/features/tickets/types";

const openPanelMessage = (): LoadedMessageTemplate => ({
  content: "Choose the ticket type that fits your issue best.",
  embeds: [
    {
      title: "Support Tickets",
      description: "Open a ticket and the team will help you as soon as possible.",
      color: 0xf5c26b,
      footer: {
        text: "Powered by Ticket-Bot"
      }
    }
  ],
  components: [createPanelOpenerSlot()]
});

export default openPanelMessage;

Example: Classic Embed Ticket Welcome

This creates a ticket welcome message with a classic embed. Ticket-Bot inserts claim, unclaim, close, and delete buttons into the actions slot.

import { createMessageSlot } from "@/features/tickets/messages";
import type { LoadedMessageTemplate } from "@/features/tickets/types";

const ticketOpenedMessage = (): LoadedMessageTemplate => ({
  content: "{createdByMention}{staffMentions}",
  embeds: [
    {
      title: "{ticketTypeName} Ticket #{ticketNumber}",
      description: "Thanks for opening a ticket. A staff member will reply here.",
      color: 0xf5c26b,
      fields: [
        {
          name: "Reason",
          value: "{reason}"
        },
        {
          name: "Claim status",
          value: "{claimStatus}"
        }
      ],
      footer: {
        text: "Powered by Ticket-Bot"
      }
    }
  ],
  components: [createMessageSlot("actions")]
});

export default ticketOpenedMessage;

Example: Components V2 Container

Use Components V2 when you want container layouts, text display blocks, separators, thumbnails, media galleries, or other V2-only components. Do not include content or embeds in this format.

import { ComponentType } from "discord-api-types/v10";
import { createPanelOpenerSlot } from "@/features/tickets/messages";
import type { LoadedMessageTemplate } from "@/features/tickets/types";

const openPanelMessage = (): LoadedMessageTemplate => ({
  useComponentsV2: true,
  components: [
    {
      type: ComponentType.Container,
      accent_color: 0xf5c26b,
      components: [
        {
          type: ComponentType.TextDisplay,
          content: "## Support Tickets"
        },
        {
          type: ComponentType.TextDisplay,
          content: "Open a ticket and the team will help you as soon as possible."
        },
        {
          type: ComponentType.Separator
        },
        createPanelOpenerSlot()
      ]
    }
  ]
});

export default openPanelMessage;

Slots

Slots let Ticket-Bot inject runtime controls into your template.

Panel opener slot:

createPanelOpenerSlot()

Ticket runtime text slot:

createRuntimeTextSlot()

Generic action slot:

createMessageSlot("actions")

Common behavior:

  • Panel opener controls are inserted into the panel-opener slot.
  • Claim, unclaim, close, and delete buttons are inserted into the actions slot.
  • Runtime welcome content can be inserted into the runtime-text slot.

If a slot is missing, Ticket-Bot appends the controls in a safe fallback location.

Ticket Open Tokens

Ticket open and welcome templates can use:

  • {channelId}
  • {claimStatus}
  • {claimerId}
  • {claimerMention}
  • {createdByMention}
  • {reason}
  • {reason1}, {reason2}, etc.
  • {staffMentions}
  • {ticketNumber}
  • {ticketTypeKey}
  • {ticketTypeName}
  • {userId}
  • {username}
  • {closeButtonCustomId}

Close Tokens

Close channel and DM templates can use:

  • {channelId}
  • {claimStatus}
  • {claimerId}
  • {claimerMention}
  • {closerId}
  • {closerMention}
  • {closerName}
  • {reason}
  • {transcriptStatus}
  • {transcriptUrl}
  • {userId}
  • {deleteButtonCustomId}

Safe Customization Rules

  • Keep custom IDs provided by tokens when creating buttons used by the bot.
  • Do not hardcode private tokens or secrets in message templates.
  • Keep template references inside the messages/ directory.
  • Use TypeScript files when you want typed imports and helpers.
  • Restart the bot after changing templates so panels and future ticket messages use the new content.

Example: Custom Billing Welcome

Create:

messages/tickets/ticket-opened-billing-custom.ts

Then configure:

ticketTypes: {
  billing: {
    message: "tickets/ticket-opened-billing-custom"
  }
}

Restart the bot. Existing ticket welcome messages are not automatically rewritten unless a workflow such as claim sync edits them.

Clone this wiki locally