티켓 디스코드 봇 만들기

2026. 4. 25. 16:52·봇 개발 팁/Discord.py

문의가 늘기 시작했는데도 아직 일반 채팅에서 처리하고 있다면, 답변 품질보다 문의 채널 구조가 먼저 무너집니다.

티켓 봇의 핵심은 고급 분류가 아니라 "유저 한 명당 개인 문의 공간을 바로 열어 준다"는 데 있습니다.

이 글은 복잡한 지원 센터가 아니라, 버튼 하나로 개인 문의 채널을 생성하는 가장 작은 티켓 자동화 글입니다.

1. 티켓의 본질은 개인 문의 공간을 분리하는 것이다

코드부터 쓰기 전에 아래 세 가지를 먼저 정합니다.

  • 티켓을 어느 카테고리 아래에 만들 것인가
  • 누가 볼 수 있어야 하는가
  • 닫을 때 채널을 삭제할지 보관할지

운영 공지 흐름은 디스코드 공지 채널 운영법과도 연결됩니다.

2. 필요한 역할과 채널

아래 정도를 먼저 준비합니다.

역할
- 운영진
- 문의담당

채널
- 문의-안내
카테고리
- 티켓


`문의-안내` 채널에는 버튼 메시지만 두고, 실제 대화는 티켓 카테고리 아래 새 채널에서 진행하는 방식이 깔끔합니다.

3. 카테고리와 담당 역할 값 정리

DISCORD_TOKEN=여기에_봇_토큰
TICKET_CATEGORY_ID=티켓_카테고리_ID
SUPPORT_ROLE_ID=문의담당_역할_ID


채널 이름을 문자열로 합칠 때는 유저 ID를 같이 붙여 두면 중복 충돌을 줄이기 쉽습니다.

4. 문의 채널을 여닫는 기본 코드

import os

import discord
from dotenv import load_dotenv

load_dotenv()

TOKEN = os.getenv("DISCORD_TOKEN")
TICKET_CATEGORY_ID = int(os.getenv("TICKET_CATEGORY_ID"))
SUPPORT_ROLE_ID = int(os.getenv("SUPPORT_ROLE_ID"))

intents = discord.Intents.default()
intents.guilds = True
client = discord.Client(intents=intents)


class TicketView(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=None)

    @discord.ui.button(label="문의 열기", style=discord.ButtonStyle.primary, custom_id="ticket:create")
    async def create_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
        if interaction.guild is None:
            await interaction.response.send_message("서버 안에서만 사용할 수 있습니다.", ephemeral=True)
            return

        category = interaction.guild.get_channel(TICKET_CATEGORY_ID)
        support_role = interaction.guild.get_role(SUPPORT_ROLE_ID)

        if not isinstance(category, discord.CategoryChannel) or support_role is None:
            await interaction.response.send_message("카테고리 또는 담당 역할을 찾지 못했습니다.", ephemeral=True)
            return

        channel_name = f"ticket-{interaction.user.name}-{interaction.user.id}"
        existing_channel = discord.utils.get(interaction.guild.text_channels, name=channel_name)
        if existing_channel is not None:
            await interaction.response.send_message(f"이미 열린 티켓이 있습니다: {existing_channel.mention}", ephemeral=True)
            return

        overwrites = {
            interaction.guild.default_role: discord.PermissionOverwrite(view_channel=False),
            interaction.user: discord.PermissionOverwrite(view_channel=True, send_messages=True, read_message_history=True),
            support_role: discord.PermissionOverwrite(view_channel=True, send_messages=True, read_message_history=True),
            interaction.guild.me: discord.PermissionOverwrite(view_channel=True, send_messages=True, manage_channels=True),
        }

        ticket_channel = await interaction.guild.create_text_channel(
            name=channel_name,
            category=category,
            overwrites=overwrites,
            reason="티켓 문의 채널 생성",
        )

        await ticket_channel.send(
            f"{interaction.user.mention} 님 문의가 접수되었습니다.\n"
            f"{support_role.mention} 확인 후 이 채널에서 답변해 주세요.",
            view=CloseTicketView(),
        )
        await interaction.response.send_message(f"티켓이 생성되었습니다: {ticket_channel.mention}", ephemeral=True)


class CloseTicketView(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=None)

    @discord.ui.button(label="티켓 닫기", style=discord.ButtonStyle.danger, custom_id="ticket:close")
    async def close_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
        await interaction.response.send_message("이 채널을 닫습니다.", ephemeral=True)
        await interaction.channel.delete(reason="티켓 종료")


@client.event
async def on_ready():
    client.add_view(TicketView())
    client.add_view(CloseTicketView())
    print(f"로그인 성공: {client.user}")


if not TOKEN:
    raise ValueError("DISCORD_TOKEN 값이 없습니다.")

client.run(TOKEN)


핵심은 안내 채널에서 버튼을 누르면 새 개인 문의 채널이 열리고, 닫기 버튼으로 바로 정리하는 흐름입니다.
재시작 뒤에도 버튼이 살아 있게 하려면 `custom_id`와 `add_view()`를 같이 둬야 합니다.

5. 안내 메시지 올리기

문의-안내 채널에는 아래 같은 문구를 먼저 올립니다.

문의가 필요하면 아래 버튼을 눌러 주세요.
새 채널이 열리면 그 안에서 내용을 남기면 됩니다.


이 메시지를 보낼 때 `view=TicketView()`를 같이 붙이면 됩니다.
초반에는 한 채널에 문의 버튼 하나만 두면 덜 헷갈립니다.

6. 채널 생성과 persistent view에서 막히는 부분

  • 버튼은 눌리는데 채널 생성이 안 되는 경우 봇에 Manage Channels 권한이 없거나 카테고리 ID가 틀린 경우가 많습니다.
  • 티켓이 여러 개 중복 생성되는 경우 기존 채널 존재 여부 체크가 없을 때 자주 나옵니다.
  • 닫기 버튼이 안 먹는 경우 재시작 뒤 persistent view 등록이 빠졌을 수 있습니다.

7. 티켓은 채널 생성보다 분류가 더 중요하다

티켓 기능 자체는 금방 만들 수 있습니다.

문제는 문의 유형이 섞이기 시작했을 때입니다.

결제 문의, 서버 문의, 신고 문의가 같은 카테고리에 몰리면 운영 효율이 떨어집니다.

그래서 실제 운영 단계에서는 카테고리 설계와 문의 동선을 같이 봐야 합니다.

8. 로그를 남길지 미리 정한다

채널을 바로 삭제하면 깔끔하지만 기록이 남지 않습니다.

반대로 전부 보관하면 카테고리가 금방 무거워집니다.

초반에는 닫기 -> 로그 채널에 요약 남기기 -> 채널 삭제 정도 기준을 잡아 두면 무난합니다.

9. 상시 운영 기능이라 배포가 사실상 필수다

티켓 봇은 운영 시간 밖에도 문의가 들어옵니다.

노트북을 끄면 문의 버튼이 바로 죽습니다.

실제 서버에 붙여 둘 생각이라면 24시간 디스코드 봇 무료 호스팅, 디스호스트처럼 계속 켜져 있는 환경이 필요합니다.

10. 티켓 생성 다음에는 분류와 입구 문구가 따라와야 한다

티켓 생성 자체가 됐다면 다음 단계는 채널을 더 많이 여는 게 아니라, 안내 문구와 권한 구조를 더 선명하게 세우는 일입니다.

입구 문구를 다시 다듬을 때는 디스코드 공지 채널 운영법과 디스코드 채널 권한 설정법, 공지 채널과 관리자 채널이 꼬이지 않게 만드는 법을 먼저 확인하면 됩니다.

'봇 개발 팁 > Discord.py' 카테고리의 다른 글

온보딩 체크리스트 디스코드 봇 만들기  (0) 2026.04.24
인증 디스코드 봇 만들기  (0) 2026.04.23
규칙 동의 인증 디스코드 봇 만들기  (0) 2026.04.22
반응 역할 디스코드 봇 만들기  (0) 2026.04.21
자동 역할 부여 디스코드 봇 만들기  (0) 2026.04.20
'봇 개발 팁/Discord.py' 카테고리의 다른 글
  • 온보딩 체크리스트 디스코드 봇 만들기
  • 인증 디스코드 봇 만들기
  • 규칙 동의 인증 디스코드 봇 만들기
  • 반응 역할 디스코드 봇 만들기
디스호스트
디스호스트
쉽고 안정적인 디스코드 봇 호스팅 서비스, 디스호스트의 기술 블로그입니다. 디스호스트는 24시간 구동되는 서버를 통해 디스코드 봇을 대신 구동시켜 드리는 서비스를 제공하고 있습니다.
  • 디스호스트
    디스호스트 기술 블로그
    디스호스트
  • 블로그 메뉴

    • 홈
    • 디스호스트 사용 가이드
    • 디스코드 봇 호스팅, 24시간 서버 구동
    • 분류 전체보기 (87) N
      • 디스코드 (9)
      • 디스호스트 가이드 (12)
      • 봇 개발 팁 (28) N
        • Discord.js (11)
        • Discord.py (16) N
      • DiscordJS 개발 튜토리얼 (15)
      • 디스코드 서버 운영 (15)
      • 디스코드 봇 오류 해결 (7)
  • 링크

    • 디스호스트
  • hELLO· Designed By정상우.v4.10.3
디스호스트
티켓 디스코드 봇 만들기
상단으로

티스토리툴바