Documentation

How it works

Setup, the ticket lifecycle, every variable, every command, and what to do when Discord behaves in a way that looks like a bug.

Setup

  1. Sign in and add the bot

    Signing in reads who you are and which servers you hold Manage Server in. That is Discord's own permission, read live on every load, so the list is exactly what you can already administer — and someone demoted this morning loses access this afternoon rather than whenever a cache expires.

  2. Create a panel

    A panel is a ticket type. It owns the message people see, the button they press, the form they fill in, the category tickets land in, and who can handle them. A server can have as many as it likes, and one posted message can carry up to 25 of them.

  3. Post it

    Run /panel in the channel you want it in. Posting again updates the existing message in place rather than leaving a trail of dead panels.

  4. Name your support team

    Under Roles and access. Almost every other screen refers back to this list, so it is worth doing before anything else is tuned.

Ticket lifecycle

created → opened → closed → re-opened → deleted, with claimed and unclaimed running alongside as a separate axis.

Closed and deleted are deliberately different things. Closing denies the opener view of the channel, renames it and moves it to the closed category — the history is intact and it can be re-opened. Deleting removes the channel. The ticket record survives deletion on purpose: statistics, the audit trail and any transcript already taken all reference it, and removing the row along with the channel would silently rewrite last month's numbers.

Variables

Usable in any message, embed, channel name or custom command. Chain modifiers with a pipe: {owner.username|upper|max:12}.

An unknown variable renders as nothing, never as its own name. A typo that printed {owner.usrname} into a live support channel would look like the bot is broken; printing nothing looks like a field that was not filled in. Substitution is also single-pass, so a value that itself contains braces is not re-scanned — which is what stops someone typing a role ping into a ticket reason and having it expand.

Loading the reference…

Panel editor

Every tab below is per panel, so a billing ticket and a bug report can look and behave nothing alike.

Messages

Thirteen points where the bot says something, each with an embed builder. Leave one alone and it uses the built-in wording.

MessageWhen it is sent
Panel messageThe panel itself, in a public channel
Ticket messageFirst message inside a new ticket
Created DM / Closed DMDirect message to the opener, if DMs are on
Close questionThe are-you-sure confirmation
Opened embedPosted when a ticket is re-opened
Closed embedPosted when a ticket is closed
Moderator embedIn the staff thread, where the opener cannot see it
Claim / UnclaimWhen staff take or release a ticket
Transcript messageAlongside a delivered transcript
Delete messagePosted before deletion, so it lands in the transcript
Escalate messageWhen a ticket is handed to another panel

All accept the variables above. A mention only pings from the message text, never from inside an embed, which is why each editor has a box for both.

Channel permissions

Nine targets, each a grid of allow, inherit and deny across twenty-two permissions. Inherit keeps whatever the role has server-wide. This is what makes a ticket private, and why the bot never asks for Administrator, which would bypass every row.

TargetApplies
@everyoneSeparately while open and while closed
Ticket ownerSeparately while open and while closed
Support teamSeparately while open and while closed
Additional rolesSeparately while open and while closed
Claimed overrideLayered on top once somebody claims it

Untouched means the built-in private defaults. One rule cannot be switched off: unless you explicitly allow @everyone to view, it stays denied.

Automation and custom commands

Automation rules

A trigger and a list of actions, written as JSON. Seven of the ten triggers fire the moment they happen: created, closed, re-opened, claimed, unclaimed, close requested and claim requested.

{"window":3600,"source":"owner","fireOn":"absence","actions":[{"type":"close","delay":0}]}

Actions: close, delete, sendCommand, stopAutomations, startAutomations. The last two let a human take over a conversation a rule was about to close.

Custom commands

Run one with /custom. Three modes: strict matches the whole text, wildcard understands * and ?, regex puts named groups into the response. Strict beats wildcard beats regex.

{"trigger":"faq","match":"strict","response":"See {server.name} docs.","delivery":"channel"}

Delivery is channel, dm or ephemeral. Text after the trigger becomes {answer.1} onwards, up to five.

Permissions

Discord shows an invite's permissions as a list with no explanation, and never reviews what an app asks for. The only gate is an admin pressing Authorize. So here is the whole list with a reason for each.

Loading…

Commands

CommandDoesWho
/ticket [reason]Opens a ticketAnyone not blacklisted
/claimTakes ownership of the ticketSupport team
/close [reason]Closes it, keeping the historySupport team, or the opener
/panel [name]Posts a panel into this channelManage Server
/ask [question]Answers from this server's documentation, citing the page, or hands you to a humanAnyone
/custom [text]Runs one of this server's custom commandsAnyone
/unclaimReleases a claim so somebody else can take itThe claimer, or an admin
/escalateHands the ticket to the panel its type escalates toSupport team
/pingConfirms the bot is awakeAnyone
/add [user]Gives somebody access to this ticketSupport team
/remove [user]Takes an individual grant away againSupport team
/move [panel]Hands the ticket to another panel and re-files the channel: new category, new team's access, new nameSupport team
/bulk [action] [inactive_days]Closes or deletes many tickets at once. Reports what it would take and does nothing until you confirm that numberManage Server, or an admin role
/note [text]Writes a private note on this ticket. The person who opened it never sees itSupport team
/notesReads the private notes backSupport team
/rename [name]Renames the ticket's channelSupport team
/transfer [user]Hands the claim to another staff memberSupport team
/threadOpens a staff-only thread, kept out of the transcriptSupport team
/closerequest [reason]Asks the opener to confirm it can be closedSupport team
/openRe-opens a closed ticketSupport team
/deleteDeletes the channel for goodSupport team
/transcriptProduces a transcript nowSupport team
/priority [level]Sets urgency, which decides the ticket's place in the queueSupport team
/creditsShows your credit balance and lets you top it up. Credit belongs to you, not to a server, so it works anywhere and spends anywhereAnyone
/boostMoves this ticket up the queue, if the server offers itAnyone in the ticket
/link [provider]Proves you own a Steam, Roblox or Twitch accountAnyone
/unlink [provider]Disconnects a linked accountAnyone
/quicksetupCreates a working category and panel in one stepManage Server

Two more live on Discord's right-click menu rather than the slash list: Open a ticket about this on any message, and Open a ticket with this user on any member.

When it goes wrong

A slash command does not appear

Global commands take up to an hour to propagate, which looks exactly like a bug and has cost people entire afternoons. Register to a single server while testing and it appears instantly.

"I do not have permission to create channels here"

The bot's role is missing Manage Channels, or a category overwrite is denying it. A server admin can edit the bot's auto-created role, but only within their own role hierarchy — they cannot grant what they do not hold themselves.

The bot's banner keeps disappearing

Discord's developer portal never loads an existing banner back into its upload control, so every Save on that page submits the field empty and deletes it — including saves for something else entirely. Set the banner from the dashboard, which sends only the fields you actually named.

Sign-in returns "invalid_state"

The sign-in did not start on this page, or it sat unfinished for more than fifteen minutes. Start it again from the dashboard. On your own application, it also means the redirect URL registered in the portal does not match exactly — a trailing slash is a different URL to Discord.