WEVEN 봇 API 문서
봇으로 메시지를 보내고, 슬래시 명령어에 응답하고, 서버를 관리하는 방법을 정리했어요. 디스코드 봇을 만들어 봤다면 거의 같은 흐름이에요.
- REST
- http://localhost:3000/api
- Gateway
- ws://localhost:3000/ws
빠른 시작#
- 내 애플리케이션에서 새 애플리케이션을 만들어요. 봇 계정이 함께 만들어지고 토큰이 한 번 표시돼요.
- 토큰을 안전한 곳(예:
.env)에 저장해요. 토큰이 있으면 누구나 봇으로 행동할 수 있으니 절대 공개하지 마세요. - 애플리케이션의 초대 링크 탭에서 필요한 권한을 고르고 링크를 열어 봇을 서버에 추가해요. 서버 관리 권한(MANAGE_SERVER)이 있는 서버에만 추가할 수 있어요.
- 예제 봇을 실행해요. 저장소에 있는 완성 예제는
BOT_TOKEN=토큰 node examples/bot.mjs로 실행할 수 있어요. - 서버 채팅창에
/를 입력하면 봇의 명령어가 보여요./ping을 보내 보세요.
인증과 요청#
모든 REST 요청은 http://localhost:3000/api 아래로 보내고, 봇 토큰을 Authorization 헤더에 넣어요. 본문은 JSON이에요.
curl http://localhost:3000/api/bot/me \
-H "Authorization: Bot <토큰>"실패하면 HTTP 상태 코드와 함께 { "error": "코드" }를 돌려줘요. 코드 목록은 오류 코드에 있어요.
403 bot_forbidden이 돌아와요. 토큰이 틀리거나 재발급돼 무효가 되면 401 invalid_token이에요.방(room) 형식
메시지 API는 채널을 channel:<채널 ID> 형식의 room으로 가리켜요. 받은 메시지의 message.room을 그대로 쓰면 같은 채널에 답장할 수 있어요.
속도 제한
채널의 슬로우 모드는 봇에게도 적용돼요(MANAGE_MESSAGES나 MANAGE_CHANNELS 권한이 있으면 제외). 제한에 걸리면 429 slowmode와 retryAfter(초)가 돌아와요. 게이트웨이로 보내는 프레임도 너무 많으면 rate_limited 오류가 와요.
게이트웨이 (실시간)#
새 메시지나 명령어 사용 같은 이벤트는 웹소켓 게이트웨이로 받아요. 연결할 때 REST와 같은 Authorization 헤더를 보내요.
const socket = new WebSocket("ws://localhost:3000/ws", {
headers: { Authorization: "Bot <토큰>" },
});서버는 JSON 텍스트 프레임을 보내요. 모든 이벤트에는 type이 있어요. 봇은 참여 중인 서버의 채널 이벤트와 자기 자신에게 오는 이벤트를 받아요.
| type | 설명 |
|---|---|
hello | 연결 직후. 접속 상태(presence)와 음성 채널 참가자 스냅샷 |
ready | 봇 전용. { user, applicationId, serverIds } 이 이벤트를 받으면 명령어를 등록하기 좋아요. |
message_create | { message } 봇이 볼 수 있는 채널에 새 메시지 |
message_update | { message } 수정·반응·고정·투표 변경 |
message_delete | { room, messageId } |
typing | { room, userId } |
presence | { userId, status } ONLINE · IDLE · DND · OFFLINE |
user_update | { user } 프로필 변경 |
server_sync | { serverId } 서버·채널·역할이 바뀌었어요. GET /api/servers/{id}로 다시 읽으세요. |
members_sync | { serverId } 멤버 목록이 바뀌었어요. |
server_removed | { serverId } 서버에서 추방·차단됐거나 서버가 삭제됐어요. |
commands_sync | { serverId } 서버의 명령어 목록이 바뀌었어요. |
interaction_create | { interaction } 누군가 내 슬래시 명령어를 사용했어요. |
voice_state | { channelId, participants } 음성 채널 참가자 변경 |
error | { message } 보낸 프레임이 거부됐어요 (예: rate_limited, forbidden). |
봇이 보낼 수 있는 프레임
| 프레임 | 설명 |
|---|---|
{ "type": "typing", "room": "channel:…" } | 입력 중… 표시 (몇 초 동안) |
{ "type": "voice_moderate", "userId", "mute"?, "deafen"?, "disconnect"? } | 음성 채널 멤버 서버 음소거 / 헤드셋 끄기 / 연결 끊기 (MUTE_MEMBERS · DEAFEN_MEMBERS · MOVE_MEMBERS) |
연결 종료 코드
| 코드 | 의미 |
|---|---|
| 1008 | 토큰이 없거나 틀려요. 다시 연결하지 말고 토큰을 확인하세요. |
| 4004 | 토큰이 재발급됐거나 애플리케이션이 삭제됐어요. |
| 그 밖 | 서버 재시작 등 일시적인 끊김이에요. 잠시 뒤 다시 연결하세요. |
주요 객체#
User
{
id: string;
username: string; // 고유한 사용자 이름
displayName: string | null;
accentColor: string; // "#rrggbb"
avatarId: string | null; // 이미지: GET /api/uploads/{avatarId}
bio: string;
plan: "FREE" | "PLUS";
bot: boolean; // 봇·웹후크면 true
}Message
{
id: string;
room: "channel:<id>" | "dm:<id>";
content: string;
type: "DEFAULT" | "MEMBER_JOIN" | "PIN" | …;
authorId: string;
author: User;
createdAt: string; // ISO 8601
editedAt: string | null;
pinned: boolean;
attachments: { id, name, size, type }[]; // 파일: GET /api/uploads/{id}
reactions: { emoji, count, userIds }[];
replyTo: { id, authorId, content } | null;
poll: Poll | null;
embeds: Embed[];
interaction: { id, name, userId } | null; // 슬래시 명령어 응답이면 설정됨
}REST API#
봇이 쓸 수 있는 경로예요. 권한 열은 봇(정확히는 봇의 역할)이 그 서버나 채널에서 가져야 하는 권한이에요. 관리자(ADMINISTRATOR)는 모든 권한을 가진 것으로 취급돼요. 다른 멤버를 관리할 때는 대상보다 높은 역할이 필요해요(role_hierarchy).
봇 자신
| 메서드 | 경로 | 권한 | 설명 |
|---|---|---|---|
| GET | /api/bot/me | — | 봇 사용자, 애플리케이션, 참여 중인 서버(채널·역할 포함) 목록 |
| GET | /api/bot/commands | — | 등록한 슬래시 명령어 목록 |
| PUT | /api/bot/commands | — | 명령어 전체 덮어쓰기. 본문은 명령어 배열이에요. 슬래시 명령어 참고 |
| POST | /api/interactions/{id}/callback | — | 명령어 사용에 응답 { content?, embeds?, ephemeral? } |
| GET | /api/users/{id} | — | 사용자 공개 프로필 |
메시지
| 메서드 | 경로 | 권한 | 설명 |
|---|---|---|---|
| GET | /api/messages?room={room}&before={messageId} | READ_MESSAGE_HISTORY | 최근 메시지 50개(오래된 순)와 hasMore. before로 이전 페이지를 불러와요. |
| POST | /api/messages | SEND_MESSAGES | { room, content?, embeds?, replyToId?, attachmentIds?, poll?, nonce? } 임베드는 EMBED_LINKS, 첨부는 ATTACH_FILES, 투표는 SEND_POLLS가 필요해요. |
| PATCH | /api/messages/{id} | 작성자 | { content?, embeds? } 내가 보낸 메시지만 수정할 수 있어요. |
| DELETE | /api/messages/{id} | 작성자또는 MANAGE_MESSAGES | 메시지 삭제 |
| POST | /api/messages/{id}/reactions | ADD_REACTIONS | { emoji } 반응을 추가하거나, 이미 있으면 제거해요. |
| GET | /api/messages/pins?room={room} | READ_MESSAGE_HISTORY | 고정된 메시지 |
| PUT | /api/messages/{id}/pin | PIN_MESSAGES또는 MANAGE_MESSAGES | { pinned: boolean } |
| GET | /api/messages/search?room={room}&q={text} | READ_MESSAGE_HISTORY | 채널 안에서 검색 |
| POST | /api/uploads | ATTACH_FILES | multipart/form-data의 file 필드. 응답의 attachment.id를 attachmentIds에 넣어 보내요. |
서버와 멤버
| 메서드 | 경로 | 권한 | 설명 |
|---|---|---|---|
| GET | /api/servers/{id} | 멤버 | 서버 정보, 채널, 카테고리, 역할, 내 권한 |
| PATCH | /api/servers/{id} | MANAGE_SERVER | { name?, description?, systemChannelId?, defaultNotifications?, automodEnabled?, automodWords? } |
| GET | /api/servers/{id}/members | 멤버 | 멤버 목록 |
| PATCH | /api/servers/{id}/members/{userId} | MANAGE_ROLES또는 MANAGE_NICKNAMES또는 MODERATE_MEMBERS | 바꾸는 항목마다 해당 권한이 필요해요. { roleIds?, nickname?, timeoutMinutes?, timeoutReason? } timeoutMinutes는 1·5·10·60·1440·10080 또는 null(해제) |
| DELETE | /api/servers/{id}/members/{userId} | KICK_MEMBERS | 추방 |
| GET | /api/servers/{id}/bans | BAN_MEMBERS | 차단 목록 |
| PUT | /api/servers/{id}/bans/{userId} | BAN_MEMBERS | { reason?, deleteMessageHours?: 0|1|24|168 } |
| DELETE | /api/servers/{id}/bans/{userId} | BAN_MEMBERS | 차단 해제 |
| GET | /api/servers/{id}/audit-log | VIEW_AUDIT_LOG | 감사 로그 |
| POST | /api/servers/{id}/leave | — | 서버에서 나가기 (봇의 관리 역할도 함께 지워져요) |
역할
| 메서드 | 경로 | 권한 | 설명 |
|---|---|---|---|
| POST | /api/servers/{id}/roles | MANAGE_ROLES | { name? } |
| PATCH | /api/roles/{id} | MANAGE_ROLES | { name?, color?, hoist?, mentionable?, permissions?, move?: "up"|"down" } 내가 가진 권한 비트만 켜고 끌 수 있어요. |
| DELETE | /api/roles/{id} | MANAGE_ROLES | 봇이 관리하는 역할은 지울 수 없어요. |
채널과 카테고리
| 메서드 | 경로 | 권한 | 설명 |
|---|---|---|---|
| POST | /api/servers/{id}/channels | MANAGE_CHANNELS | { name, type?: "TEXT"|"VOICE", categoryId?, topic?, isPrivate? } |
| PUT | /api/servers/{id}/channels | MANAGE_CHANNELS | { channels: [{ id, categoryId, position }], categories? } 순서 바꾸기 |
| PATCH | /api/channels/{id} | MANAGE_CHANNELS | { name?, topic?, categoryId?, slowmode? } |
| DELETE | /api/channels/{id} | MANAGE_CHANNELS | 채널 삭제 |
| PUT | /api/channels/{id}/overwrites | MANAGE_ROLES | { targetType: "ROLE"|"MEMBER", targetId, allow, deny } 채널별 권한 덮어쓰기 |
| POST | /api/servers/{id}/categories | MANAGE_CHANNELS | { name } |
| PATCHDELETE | /api/categories/{id} | MANAGE_CHANNELS | 카테고리 이름 바꾸기 / 삭제 |
웹후크
| 메서드 | 경로 | 권한 | 설명 |
|---|---|---|---|
| GET | /api/servers/{id}/webhooks | MANAGE_WEBHOOKS | 웹후크 목록 (실행 주소 포함) |
| POST | /api/servers/{id}/webhooks | MANAGE_WEBHOOKS | { channelId, name } |
| PATCH | /api/webhooks/{id} | MANAGE_WEBHOOKS | { name?, channelId?, accentColor?, resetToken? } |
| DELETE | /api/webhooks/{id} | MANAGE_WEBHOOKS | 웹후크 삭제 (보낸 메시지는 남아요) |
| POST | /api/webhooks/{id}/{token} | 주소 = 비밀번호 | { content?, embeds? } 인증 헤더 없이 메시지를 보내요. |
임베드#
임베드는 색깔 띠가 있는 카드 형태의 메시지예요. 메시지 하나에 최대 10개까지 넣을 수 있어요. POST /api/messages, 메시지 수정, 명령어 응답, 웹후크에서 모두 같은 형식을 써요. 임베드 빌더로 미리 보면서 만들 수 있어요.
{
"title": "제목",
"description": "**마크다운**을 쓸 수 있어요",
"url": "https://example.com",
"color": "#5865F2",
"timestamp": "2026-10-14T12:00:00.000Z",
"author": { "name": "작성자", "url": "https://…", "iconUrl": "https://…" },
"footer": { "text": "푸터", "iconUrl": "https://…" },
"image": { "url": "https://…/big.png" },
"thumbnail": { "url": "https://…/small.png" },
"fields": [
{ "name": "시작", "value": "22:00", "inline": true },
{ "name": "길이", "value": "30분", "inline": true }
]
}color는"#rrggbb"문자열이나 디스코드처럼 숫자(0x5865F2=5793266)로 보낼 수 있어요.- URL은 모두 http(s)로 시작해야 해요. 이미지는 받는 사람의 브라우저가 직접 불러와요.
inline: true필드는 한 줄에 최대 3개까지 나란히 놓여요.- 제목·설명·필드·작성자·푸터·이미지 중 하나는 있어야 해요.
- 임베드를 보내려면 채널에서 EMBED_LINKS 권한이 필요해요.
| 항목 | 최대 |
|---|---|
| title | 256자 |
| description | 4096자 |
| fields | 25개 |
| field.name / field.value | 256자 / 1024자 |
| footer.text | 2048자 |
| author.name | 256자 |
| 메시지의 모든 임베드 글자 합 | 6000자 (넘으면 embed_too_large) |
슬래시 명령어#
슬래시 명령어는 PUT /api/bot/commands로 등록해요. 보낸 목록이 기존 목록을 통째로 대체하므로 봇이 켜질 때마다 전체 목록을 보내면 돼요. 봇이 들어가 있는 모든 서버에 바로 반영돼요.
[
{
"name": "날씨",
"description": "도시의 날씨를 알려 줘요",
"options": [
{ "name": "도시", "description": "도시 이름", "type": "string", "required": true },
{
"name": "단위", "description": "온도 단위", "type": "string",
"choices": [{ "name": "섭씨", "value": "c" }, { "name": "화씨", "value": "f" }]
}
]
}
]- 이름은 1–32자이고 소문자, 숫자, 한글,
-,_만 쓸 수 있어요. 설명은 1–100자예요. - 봇당 명령어 100개, 명령어당 옵션 25개, 옵션당 선택지 25개까지예요.
- 필수 옵션은 선택 옵션보다 앞에 와야 해요.
옵션 타입
| type | 봇이 받는 값 | 사용자가 입력하는 방법 |
|---|---|---|
string | 문자열 (choices가 있으면 선택한 value) | 아무 텍스트 |
integer | 정수 | 42 |
number | 숫자 | 3.14 |
boolean | true / false | true, yes, 예, 네 / false, no, 아니요 |
user | 사용자 ID (resolved.users에 프로필) | @사용자이름, 멘션, ID |
channel | 채널 ID (resolved.channels) | #채널이름, 멘션, ID |
role | 역할 ID (resolved.roles) | 역할 이름, 멘션, ID |
채팅창에서는 /날씨 서울처럼 쓰면 첫 번째 옵션에 전부 들어가고, /날씨 도시:서울 단위:섭씨처럼 이름:값으로 여러 옵션을 줄 수 있어요. 값이 맞지 않으면 사용자에게 바로 오류가 보이고 봇에게는 전달되지 않아요.
interaction_create
누군가 명령어를 쓰면 게이트웨이로 다음 이벤트가 와요.
{
"type": "interaction_create",
"interaction": {
"id": "cm…",
"applicationId": "cm…",
"command": { "id": "cm…", "name": "날씨" },
"options": { "도시": "서울", "단위": "c" },
"resolved": { "users": {}, "channels": {}, "roles": {} },
"room": "channel:cm…",
"channelId": "cm…",
"serverId": "cm…",
"user": { "id": "cm…", "username": "minji", … },
"member": { "nickname": null, "roleIds": ["cm…"] },
"createdAt": "2026-10-14T12:00:00.000Z"
}
}응답하기
await fetch(`http://localhost:3000/api/interactions/${interaction.id}/callback`, {
method: "POST",
headers: { Authorization: "Bot <토큰>", "Content-Type": "application/json" },
body: JSON.stringify({
content: "서울은 맑아요 ☀️",
embeds: [{ title: "서울 날씨", description: "18°C", color: "#FEE75C" }],
ephemeral: false,
}),
});- 응답은 한 번만, 명령어 사용 후 15분 안에 보낼 수 있어요. 두 번째 응답은
409 interaction_responded, 시간이 지나면interaction_expired예요. - 응답 메시지 위에는 “누가 /명령어를 사용함” 표시가 붙어요.
ephemeral: true면 명령어를 쓴 사람에게만 보이고 저장되지 않아요(새로고침하면 사라져요).- 사용자는 10초 안에 응답이 없으면 “응답이 없어요” 안내를 봐요. 오래 걸리는 작업이라면 먼저 짧게 응답하고, 이어서 일반 메시지를 보내세요.
- 명령어를 쓰려면 사용자에게 USE_APPLICATION_COMMANDS 권한이 필요해요.
웹후크#
웹후크는 봇을 띄우지 않고도 정해진 채널에 메시지를 보내는 주소예요. 서버 설정 → 연동에서 만들 수 있어요(MANAGE_WEBHOOKS 필요). 주소 자체가 비밀번호이므로 공개되면 주소 재설정을 누르세요.
curl -X POST "http://localhost:3000/api/webhooks/<id>/<token>" \
-H "Content-Type: application/json" \
-d '{"content":"배포 완료!","embeds":[{"title":"v1.2.0","color":"#57F287"}]}'웹후크 메시지는 웹후크의 이름과 아바타로 표시되고 APP 배지가 붙어요. 본문에는 content(최대 2000자)와 embeds를 넣을 수 있어요.
권한#
권한은 비트 필드(정수)예요. 여러 권한은 비트 OR로 합쳐요. 예를 들어 메시지 보내기 + 임베드는 8389632(= 1024 | 8388608)이에요. 봇을 초대할 때 고른 권한은 봇 전용 관리 역할로 만들어지고, 이 역할은 다른 멤버에게 줄 수 없고 봇이 나가면 함께 지워져요.
1137177792이에요. 채널별 권한 덮어쓰기는 @everyone → 역할 → 멤버 순서로 적용되고, 서버 주인과 관리자는 덮어쓰기를 무시해요.일반 서버 권한
| 이름 | 값 | 설명 |
|---|---|---|
ADMINISTRATOR관리자 | 1 (1 << 0) | 모든 권한을 가져요. 위험한 권한이니 신중하게 부여하세요. |
VIEW_CHANNEL채널 보기 | 262144 (1 << 18) | 기본적으로 채널을 볼 수 있어요. 비공개 채널은 따로 허용해야 해요. |
MANAGE_SERVER서버 관리하기 | 2 (1 << 1) | 서버 이름, 아이콘, 초대 코드 등을 바꿀 수 있어요. |
MANAGE_ROLES역할 관리하기 | 4 (1 << 2) | 자신보다 낮은 역할을 만들고 편집하고 부여할 수 있어요. |
MANAGE_CHANNELS채널 관리하기 | 8 (1 << 3) | 채널과 카테고리를 만들고 편집하고 삭제할 수 있어요. |
MANAGE_EXPRESSIONS표현 관리 | 536870912 (1 << 29) | 이 서버의 이모지, 스티커, 사운드를 올리고 지울 수 있어요. |
MANAGE_WEBHOOKS웹후크 관리 | 67108864 (1 << 26) | 웹후크를 만들고 고치고 지울 수 있어요. 웹후크는 외부 서비스가 채널에 메시지를 올리는 주소예요. |
VIEW_AUDIT_LOG감사 로그 보기 | 512 (1 << 9) | 서버의 관리 작업 기록을 볼 수 있어요. |
멤버십 권한
| 이름 | 값 | 설명 |
|---|---|---|
CREATE_INVITE초대 코드 만들기 | 64 (1 << 6) | 다른 사람을 서버에 초대할 수 있어요. |
CHANGE_NICKNAME별명 변경하기 | 128 (1 << 7) | 이 서버에서 자신의 별명을 바꿀 수 있어요. |
MANAGE_NICKNAMES별명 관리하기 | 256 (1 << 8) | 다른 멤버의 별명을 바꿀 수 있어요. |
KICK_MEMBERS멤버 추방하기 | 16 (1 << 4) | 자신보다 낮은 멤버를 서버에서 내보낼 수 있어요. |
BAN_MEMBERS멤버 차단하기 | 32 (1 << 5) | 멤버를 영구적으로 차단하고 차단 목록을 관리할 수 있어요. |
MODERATE_MEMBERS멤버 타임아웃 | 524288 (1 << 19) | 자신보다 낮은 멤버를 일정 시간 동안 채팅, 반응, 음성에서 제한할 수 있어요. |
채팅 채널 권한
| 이름 | 값 | 설명 |
|---|---|---|
SEND_MESSAGES메시지 보내기 | 1024 (1 << 10) | 채팅 채널에 메시지를 보낼 수 있어요. |
EMBED_LINKS임베드 보내기 | 8388608 (1 << 23) | 봇, 웹후크, API로 제목·색상·필드가 있는 임베드를 보낼 수 있어요. |
ATTACH_FILES파일 첨부하기 | 4096 (1 << 12) | 파일과 이미지를 업로드할 수 있어요. |
ADD_REACTIONS반응 추가하기 | 8192 (1 << 13) | 메시지에 새 이모지 반응을 추가할 수 있어요. |
MENTION_EVERYONE@everyone, @here, 모든 역할 멘션하기 | 16384 (1 << 14) | 모두에게 알림을 보낼 수 있어요. |
MANAGE_MESSAGES메시지 관리하기 | 2048 (1 << 11) | 다른 사람의 메시지를 삭제하고 고정할 수 있어요. 슬로우 모드도 적용되지 않아요. |
PIN_MESSAGES메시지 고정 | 134217728 (1 << 27) | 메시지를 고정하거나 고정을 해제할 수 있어요. |
READ_MESSAGE_HISTORY메시지 기록 보기 | 4194304 (1 << 22) | 채널에 예전에 올라온 메시지를 읽을 수 있어요. 없으면 들어와 있는 동안 온 메시지만 보여요. |
SEND_POLLS투표 만들기 | 16777216 (1 << 24) | 채널에 투표를 올릴 수 있어요. |
앱 권한
| 이름 | 값 | 설명 |
|---|---|---|
USE_APPLICATION_COMMANDS앱 명령어 사용 | 33554432 (1 << 25) | 서버에 있는 봇의 슬래시 명령어(/)를 쓸 수 있어요. |
음성 채널 권한
| 이름 | 값 | 설명 |
|---|---|---|
CONNECT연결 | 32768 (1 << 15) | 음성 채널에 참가할 수 있어요. |
SPEAK말하기 | 65536 (1 << 16) | 음성 채널에서 말할 수 있어요. |
VIDEO영상 | 131072 (1 << 17) | 카메라와 화면 공유를 사용할 수 있어요. |
USE_SOUNDBOARD사운드보드 사용 | 1073741824 (1 << 30) | 음성 채널에서 사운드보드를 재생할 수 있어요. |
MUTE_MEMBERS멤버 마이크 음소거 | 1048576 (1 << 20) | 음성 채널에서 다른 멤버의 마이크를 서버 전체에서 음소거할 수 있어요. |
DEAFEN_MEMBERS멤버 헤드셋 음소거 | 268435456 (1 << 28) | 음성 채널에서 다른 멤버가 아무것도 듣지 못하게 서버 전체에서 헤드셋을 음소거할 수 있어요. |
MOVE_MEMBERS멤버 연결 끊기 | 2097152 (1 << 21) | 음성 채널에 있는 다른 멤버의 연결을 끊을 수 있어요. |
오류 코드#
오류 응답은 { "error": "코드" } 형식이에요. 봇이 자주 만나는 코드예요.
| 코드 | 의미 |
|---|---|
unauthenticated | 다시 로그인해 주세요. |
invalid_token | 봇 토큰이 올바르지 않아요. |
bot_forbidden | 봇은 이 기능을 쓸 수 없어요. |
bot_only | 봇 토큰으로만 쓸 수 있는 기능이에요. |
forbidden | 권한이 없어요. |
invalid_input | 입력값을 확인해 주세요. |
rate_limited | 너무 빨라요! 잠시 후 다시 시도해 주세요. |
slowmode | 슬로우 모드가 켜져 있어요. 잠시 후에 다시 보내 주세요. |
not_found | 찾을 수 없어요. |
server_not_found | 서버를 찾을 수 없어요. |
channel_not_found | 채널을 찾을 수 없어요. |
message_not_found | 메시지를 찾을 수 없어요. |
member_not_found | 멤버를 찾을 수 없어요. |
role_not_found | 역할을 찾을 수 없어요. |
invalid_room | 잘못된 대화방이에요. |
message_empty | 빈 메시지는 보낼 수 없어요. |
message_too_long | 메시지가 너무 길어요. |
too_many_attachments | 첨부 파일은 최대 10개까지 보낼 수 있어요. |
embed_invalid | 임베드 형식이 올바르지 않아요. |
embed_too_large | 임베드 글자 수가 너무 많아요 (전체 6000자까지). |
poll_invalid | 투표 형식이 올바르지 않아요. |
automod_blocked | AutoMod가 이 서버에서 금지된 단어가 들어간 메시지를 막았어요. |
role_hierarchy | 내 역할보다 높거나 같은 대상은 관리할 수 없어요. |
role_managed | 봇 전용 역할은 지우거나 다른 멤버에게 줄 수 없어요. |
command_invalid | 명령어 정의가 올바르지 않아요. |
command_not_found | 명령어를 찾을 수 없어요. |
option_invalid | 명령어 옵션 값이 올바르지 않아요. |
option_required | 필수 옵션을 입력해 주세요. |
interaction_not_found | 명령어 요청을 찾을 수 없어요. |
interaction_responded | 이미 응답한 명령어예요. |
interaction_expired | 응답 시간이 지났어요 (15분). |
cannot_dm_bot | 봇에게는 DM을 보낼 수 없어요. |
cannot_friend_bot | 봇에게는 친구 요청을 보낼 수 없어요. |
application_not_found | 앱을 찾을 수 없어요. |
app_limit | 앱은 25개까지 만들 수 있어요. |
app_name_length | 앱 이름은 2~32자여야 해요. |
bot_already_added | 이미 이 서버에 있는 봇이에요. |
webhook_not_found | 웹후크를 찾을 수 없어요. |
webhook_limit | 채널 하나에 웹후크는 15개까지 만들 수 있어요. |
webhook_name_length | 웹후크 이름은 1~80자여야 해요. |
예제 봇#
Node.js 22+와 ws 패키지로 만든 최소 예제예요. 접속하면 명령어를 등록하고, /ping과 /안녕에 답하고, 채팅의 !ping에 답장해요.
import WebSocket from "ws"; // npm install ws
const TOKEN = process.env.BOT_TOKEN;
const API = "http://localhost:3000/api";
async function api(method, path, body) {
const res = await fetch(API + path, {
method,
headers: { Authorization: `Bot ${TOKEN}`, "Content-Type": "application/json" },
body: body ? JSON.stringify(body) : undefined,
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
return data;
}
const socket = new WebSocket("ws://localhost:3000/ws", { headers: { Authorization: `Bot ${TOKEN}` } });
socket.on("message", async (raw) => {
const event = JSON.parse(raw);
if (event.type === "ready") {
await api("PUT", "/bot/commands", [
{ name: "ping", description: "봇이 살아 있는지 확인해요" },
{ name: "안녕", description: "인사해요", options: [{ name: "이름", description: "누구에게", type: "string", required: true }] },
]);
console.log("준비 완료:", event.user.username);
}
if (event.type === "interaction_create") {
const i = event.interaction;
if (i.command.name === "ping") {
await api("POST", `/interactions/${i.id}/callback`, { content: "퐁! 🏓" });
}
if (i.command.name === "안녕") {
await api("POST", `/interactions/${i.id}/callback`, {
embeds: [{ title: `안녕하세요, ${i.options["이름"]}님!`, color: "#5865F2" }],
});
}
}
if (event.type === "message_create" && !event.message.author.bot && event.message.content === "!ping") {
await api("POST", "/messages", { room: event.message.room, content: "pong!", replyToId: event.message.id });
}
});주사위·정보·비밀(ephemeral)·투표 임베드 명령어와 재연결 처리가 포함된 완성 예제는 프로젝트의 examples/bot.mjs에 있어요.
BOT_TOKEN=<토큰> WEVEN_URL=http://localhost:3000 WEVEN_GATEWAY=ws://localhost:3000/ws node examples/bot.mjs