A ticket bot gives members a button. Pressing it opens a private channel only that member and your staff can see. This guide builds the core of one. You need a bot token first: How to create a Discord bot and get its token.
What you need
- The
Guildsintent only. No privileged intent is required. - Permissions for the bot: Manage Channels, View Channels, Send Messages.
- The ID of your staff role. Turn on Developer Mode in Discord, right-click the role and choose Copy Role ID.
The code
index.js
```js const { Client, GatewayIntentBits, ChannelType, PermissionFlagsBits, ActionRowBuilder, ButtonBuilder, ButtonStyle, SlashCommandBuilder, REST, Routes, } = require('discord.js');
const STAFF_ROLE_ID = process.env.STAFF_ROLE_ID; const client = new Client({ intents: [GatewayIntentBits.Guilds] });
client.once('ready', async () => { const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN); const cmd = new SlashCommandBuilder().setName('ticketpanel').setDescription('Post the ticket button') .setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild); await rest.put(Routes.applicationCommands(client.user.id), { body: [cmd.toJSON()] }); console.log(Logged in as ${client.user.tag}); });
client.on('interactionCreate', async (i) => { if (i.isChatInputCommand() && i.commandName === 'ticketpanel') { const row = new ActionRowBuilder().addComponents( new ButtonBuilder().setCustomId('open_ticket').setLabel('Open a ticket').setStyle(ButtonStyle.Primary)); await i.channel.send({ content: 'Need help? Press the button to open a private ticket.', components: [row] }); return i.reply({ content: 'Posted.', ephemeral: true }); }
if (i.isButton() && i.customId === 'open_ticket') { const channel = await i.guild.channels.create({ name: ticket-${i.user.username}, type: ChannelType.GuildText, permissionOverwrites: [ { id: i.guild.roles.everyone.id, deny: [PermissionFlagsBits.ViewChannel] }, { id: i.user.id, allow: [PermissionFlagsBits.ViewChannel, PermissionFlagsBits.SendMessages] }, { id: STAFF_ROLE_ID, allow: [PermissionFlagsBits.ViewChannel, PermissionFlagsBits.SendMessages] }, { id: client.user.id, allow: [PermissionFlagsBits.ViewChannel, PermissionFlagsBits.SendMessages, PermissionFlagsBits.ManageChannels] }, ], }); await channel.send(Hello ${i.user}, a member of staff will be with you soon.); return i.reply({ content: Your ticket: ${channel}, ephemeral: true }); } });
client.login(process.env.DISCORD_TOKEN); ```
Add "discord.js": "^14.16.0" to package.json. The staff role ID is read from STAFF_ROLE_ID: put it in a .env file and add the dotenv package, or type the ID into the code while you test.





