---
title: "Discord Botの作り方｜アプリ登録から24時間稼働までを手順どおりに"
url: "https://www.issoh.co.jp/tech/details/17623/"
published: 2026-09-15
updated: 2026-10-19
categories: ["プラットフォーム"]
publisher: "株式会社一創"
---

# Discord Botの作り方｜アプリ登録から24時間稼働までを手順どおりに

Discord Botの作り方を調べると、「どこでトークンを出すのか」「なぜコマンドが出てこないのか」「無料で24時間動かせるのか」で止まりがちです。この記事は、Developer Portalでのアプリ作成から、トークンの保管、招待URL、discord.js 14.27.0とdiscord.py 2.7.1で動くスラッシュコマンド、常時稼働の置き場所までを6工程で通しました。版番号と上限値は2026年10月19日時点の公式ドキュメントとレジストリから取り、エラー表示と署名検証は手元で実行して確かめています。

## まとめ｜Discord Botを作る6工程と最初に決める2つの分岐

作業は6つです。①Developer Portalでアプリを作る、②トークンを発行して環境変数へ置く、③インテントと権限を決めて招待URLでサーバーへ入れる、④コマンドを登録して応答を返す、⑤言語ごとの差分を埋める、⑥常時稼働の置き場所を決める。つまずきやすいのはコードを書く④より、①〜③の設定です。

着手前に決めるのは2つ。1つ目は自作が要るかどうかで、荒らし対策や一方向の通知だけなら既製BotかWebhookで足ります。2つ目は動かし方で、メッセージや入退室に反応するならGateway常駐、スラッシュコマンドに答えるだけならHTTP応答方式。後者なら常駐プロセスが要らず、Cloudflare Workersの無料枠で24時間応答させられます。

初回で止まる箇所は3つです。トークンは発行直後の一度しか表示されない。開発中のコマンドはギルド指定で登録すれば即時に反映される。メッセージ本文を読むにはMESSAGE\_CONTENTの有効化が要る。

## 実装前の判断｜自作の必要性とGateway・HTTPの受信経路

コードを書く前に、必要な機能が既製BotやIncoming Webhookで満たせるかと、Botがイベントを受け取る経路の2点を決めてください。

### 既製BotとWebhookで足りる要件と自作へ切り替える境目

荒らし対策、招待リンクの自動削除、メンションスパムの検知、ログ記録は既製Botの標準機能で、招待して権限を渡せば動きます。CIの結果や監視アラートを流すだけなら、Botすら要りません。[Incoming Webhookとは？Slack・Discord・Teams・Google Chatの使い方と違い【2026年版】](/tech/details/6596/)のとおり、Webhook URLへPOSTすれば送信でき、BotトークンもGatewayの常駐プロセスも要りません。ただしURL自体に認証用のトークンが含まれるので、URLは秘密情報として扱います。

自作へ移る境目は「Discord側の操作をきっかけに自分のシステムのデータを読み書きする」要件が入った時点。コマンドで在庫を照会する、ボタンで承認を記録するといった要件では、既製Botの連携機能・認証方式・データの保存先を確認し、満たせない部分を自作します。

| 観点           | 既製Bot     | Webhook  | 自作Bot    |
| ------------ | --------- | -------- | -------- |
| 導入までの時間      | 招待して即日    | URL発行で即日 | 実装と検証で数日 |
| Discordからの入力 | 提供元の機能の範囲 | 受け取れない   | 要件どおり    |
| 自社システムとの連携   | できないものが多い | 送信のみ     | 要件どおり    |
| 権限の絞り込み      | 提供元の要求に従う | チャンネル単位  | 必要最小限を指定 |
| 仕様変更への追随     | 提供元が対応    | ほぼ不要     | 自分で改修    |

既製Botの権限の絞り方は[Vortexの使い方｜Discord荒らし対策Botの導入・Automod設定とVortex Supportの窓口](/tech/details/10407/)に実例があります。

### Gateway常駐とInteractions Endpointの違いと排他になる条件

Botがイベントを受け取る経路は2つあります。Gatewayは、Bot側からDiscordへWebSocketで常時つなぐ方式。メッセージ投稿・入退室・リアクションなど、あらゆるイベントを受け取れる代わりに、プロセスを24時間動かし続ける必要があります。discord.jsとdiscord.pyの標準的な書き方はこちらです。

もう一方がInteractions Endpoint方式で、スラッシュコマンドやボタンが押されるたびにDiscordが自分のHTTPSのURLへPOSTしてきます。常時接続が要らないため、リクエスト課金のサーバーレス環境に載せられる。ただし受け取れるのはインタラクションだけで、通常のメッセージや入退室は届きません。

注意点は、インタラクション（コマンド・ボタン等）の受信経路が排他になること。[Receiving and Respondingのドキュメント](https://docs.discord.com/developers/interactions/receiving-and-responding)は、インタラクションの受信方法を「mutually exclusive」（どちらか一方のみ）と明記しています。Developer PortalでInteractions Endpoint URLを保存すると、Gatewayで待っているdiscord.jsの`InteractionCreate`にはコマンドが届かなくなる。通常のイベントをGatewayで、インタラクションをHTTPで受ける構成は組めますが、常駐プロセスは残ります。コマンドだけで完結するならHTTP方式、メッセージに反応する機能が1つでもあるならGateway方式、と最初に決めてください。

## 工程1と2｜Developer Portalでのアプリ作成とトークン取得の画面手順

最初はコードを書かず、Discord側で設定します。アプリを作成し、そこに紐づくBotユーザーの認証情報を取り出す作業です。

### Create AppからReset Tokenで認証情報をそろえるまでの画面操作

Discord Developer Portalの右上にあるCreate Appからアプリ名を入れて作成します。公式の[Getting Startedガイド](https://docs.discord.com/developers/quick-start/getting-started)のとおり、General InformationページにApplication IDとPublic Keyが並んでいるので、両方を控えます。Application IDは招待URLとコマンド登録に、Public KeyはHTTP方式の署名検証に使う値です。

次にBotページでReset Tokenを押します。表示される文字列がBotトークンで、画面を離れると二度と表示されません。稼働中のBotで押すと旧トークンがその場で失効して停止するため、本番後の再発行はデプロイ先の環境変数を差し替える段取りとセットにしてください。

Installationページでは、アプリをどこへ入れられるかを選びます。[Applicationのリファレンス](https://docs.discord.com/developers/resources/application)によると、インストール先はサーバー（Guild Install）とユーザー（User Install）の2種類。サーバーで動くBotを作るならGuild Installを有効にしておきます。最後にDiscordアプリ側で開発者モードを有効にし、対象サーバーを右クリックしてサーバーIDをコピーします。

### トークンを.envへ逃がす書き方と.gitignoreで漏洩を防ぐ設定

トークンはBotとして認証するための秘密情報です。漏洩すると、Botに付与された権限の範囲で他人に操作され、メッセージ管理やBANの権限を渡していればそれも悪用されます。作業ディレクトリを次の構成にして、値は`.env`に寄せてください。

```
my-discord-bot/
  .env          # トークンとID（Gitに入れない）
  .gitignore
  package.json
  register.js   # コマンド登録の実行用
  index.js      # 常駐して応答を返す
```

`.env`には次の3行を置きます。

```
DISCORD_TOKEN=Reset Tokenで表示された文字列
DISCORD_APP_ID=Application IDの数字
DISCORD_GUILD_ID=開発に使うサーバーのID
```

同じ階層の`.gitignore`に`.env`と`node_modules`を書いてから`git init`する順番にすれば、事故の大半は起きません。

## 工程3｜インテントと権限の指定と招待URLでサーバーへ入れる操作

どのイベントを受け取るか（インテント）と、サーバー内で何ができるか（権限）は別の仕組みです。混同すると「Botはいるのに反応しない」状態になります。

### 特権インテント3種と有効化が必要になる条件

インテントはBotが受け取るイベントの種類を宣言するビットフラグです。[Gatewayのリファレンス](https://docs.discord.com/developers/events/gateway)で特権インテントに指定されているのは、GUILD\_MEMBERS（1 << 1）、GUILD\_PRESENCES（1 << 8）、MESSAGE\_CONTENT（1 << 15）の3種。手元のdiscord.py 2.7.1で`discord.Intents.default()`を確かめると、この3つはいずれも`False`でした。

スラッシュコマンドだけで作るなら1つも要りません。要るのは、メンバーの参加検知、オンライン状態の取得、通常のメッセージ本文の読み取りのいずれかを実装するときです。同リファレンスによれば、Botへのメンションを含むメッセージとBotとのDMは、MESSAGE\_CONTENTが無くても本文を読めます。

[公式の変更履歴](https://docs.discord.com/developers/change-log)では、2026年6月10日に審査基準が「参加サーバー100以上」から「Botがアクセスできるユーザー10,000人」へ置き換わり、承認後も年1回の再申請が必須になりました。1万ユーザー未満ならPortalのトグルだけで使えますが、社内Botが全社へ広がって規模を超えた時点で審査対象に入ります。

### 招待URLのclient\_idとpermissionsを組み立てる手順

招待URLは手で組み立てられます。[OAuth2のドキュメント](https://docs.discord.com/developers/topics/oauth2)では、Botの招待に必要なのは`client_id`と`scope`で、`permissions`は権限ビットの合計値。`applications.commands`スコープは`bot`スコープに既定で含まれるため、`scope=bot`だけでもスラッシュコマンドは使えます。

```
https://discord.com/oauth2/authorize
  ?client_id=控えたApplication ID
  &scope=bot
  &permissions=3072
  &integration_type=0
```

3072は、View Channel（1024）とSend Messages（2048）の和です。必要になった権限だけを後から足し、チャンネル単位の権限設定を素通りする管理者権限（8）は渡さないでください。`integration_type=0`はサーバーへのインストールを指します。生成したURLを開いて対象サーバーを選べば、Botがメンバー一覧に現れます。追加先のサーバーが選択肢に出ない場合の確認は[Discord Botの入れ方｜招待リンクでのサーバー追加と権限の確認手順](/tech/details/18127/)で扱っています。

## 工程4｜discord.js 14.27.0でスラッシュコマンドを返す最小構成

JavaScriptで書く場合はdiscord.jsを使います。登録と応答を1ファイルに詰めると後で壊れやすいため、最初から2ファイルに分けます。

### npm initからdiscord.jsの導入までのコマンドとNode要件

[npmのパッケージページ](https://www.npmjs.com/package/discord.js)にある最新安定版は14.27.0（2026年7月15日公開）で、engines指定はNode 18以上。distタグには15.0.0のdev版も並びますが安定版ではないため、新規に作るなら14系を固定してください。

```
node -v                     # 18以上であることを確認
mkdir my-discord-bot && cd my-discord-bot
npm init -y
npm pkg set type=module
npm install discord.js@14.27.0 dotenv
```

`type=module`は後述のコードの`import`構文のためです。scriptsに2つ足しておくと、デプロイ先でも同じコマンドで動かせます。

```
"scripts": {
  "register": "node register.js",
  "start": "node index.js"
}
```

### コマンド登録スクリプトと応答ハンドラを別ファイルに分ける構成

コマンドの登録はBotの起動と別の操作で、REST APIへの1回の呼び出しで済みます。`register.js`を次の内容にして、コマンドを増やしたときだけ`npm run register`を実行する運用にします。

```
import { REST, Routes } from "discord.js";
import "dotenv/config";

const commands = [
  { name: "ping", description: "Botの応答を確認する" },
  { name: "help", description: "使えるコマンドを一覧で返す" },
];

const rest = new REST({ version: "10" }).setToken(process.env.DISCORD_TOKEN);

await rest.put(
  Routes.applicationGuildCommands(
    process.env.DISCORD_APP_ID,
    process.env.DISCORD_GUILD_ID
  ),
  { body: commands }
);

console.log("登録しました: " + commands.length + "件");
```

`applicationGuildCommands`はギルド単位の登録で、[アプリケーションコマンドの仕様](https://docs.discord.com/developers/interactions/application-commands)では即時に更新されます。全体公開に切り替えるときだけ`applicationCommands`へ差し替えます。同じ仕様で、チャット入力型はグローバルで最大100個、オプションは1コマンドに最大25個。新規コマンドの作成には1ギルドあたり1日200個の上限があり、コマンド名を変えながらCIで登録を繰り返すと新規作成として数えられて届きます。

常駐側の`index.js`は応答だけを担当します。インテントは`Guilds`だけです。

```
import { Client, GatewayIntentBits, Events } from "discord.js";
import "dotenv/config";

const client = new Client({ intents: [GatewayIntentBits.Guilds] });

client.once(Events.ClientReady, function (c) {
  console.log("起動しました: " + c.user.tag);
});

client.on(Events.InteractionCreate, async function (interaction) {
  if (!interaction.isChatInputCommand()) return;
  if (interaction.commandName === "ping") {
    await interaction.reply("pong");
    return;
  }
  if (interaction.commandName === "help") {
    await interaction.reply("使えるコマンド: ping と help");
  }
});

client.on(Events.Error, function (e) {
  console.error("gateway error", e);
});

client.login(process.env.DISCORD_TOKEN);
```

`npm run register`のあとに`npm start`で、サーバーのコマンド欄にpingが出ます。トークンを書き間違えたまま実行すると、`register.js`は`DiscordAPIError[0]: 401: Unauthorized`、`index.js`は`DiscordjsError [TokenInvalid]: An invalid token was provided.`で止まりました（14.27.0で確認）。この2つが出たら、コードではなく`.env`の値を見直します。

## 工程5｜discord.py 2.7.1で同じBotを書く場合の差分とコマンド同期

Pythonで書く場合の差は、コマンド同期の扱いに出ます。discord.pyは起動時の同期処理として書くのが通例です。

### 仮想環境の作成からdiscord.py 2.7.1の導入までのコマンド

[PyPIのパッケージページ](https://pypi.org/project/discord.py/)にある最新版は2.7.1（2026年3月3日公開）で、requires\_pythonは3.8以上。プロジェクト間の衝突を避けるため、仮想環境を切ってから入れます。

```
# Windows
python -m venv .venv
.venv\Scripts\activate

# macOS・Linux
python3 -m venv .venv
source .venv/bin/activate

pip install "discord.py==2.7.1" python-dotenv
```

`.gitignore`には`.venv`も足してください。JavaScript側の`.env`はそのまま使い回せます。

### app\_commandsでツリーを同期する書き方とJS版との差分

discord.pyのスラッシュコマンドは`app_commands`の`CommandTree`へ登録し、明示的に同期します。次のコードを`bot.py`へ保存し、仮想環境を有効にしたターミナルで`python bot.py`を実行します。

```
import os
import discord
from discord import app_commands
from dotenv import load_dotenv

load_dotenv()
GUILD = discord.Object(id=int(os.environ["DISCORD_GUILD_ID"]))

client = discord.Client(intents=discord.Intents.default())
tree = app_commands.CommandTree(client)

@tree.command(name="ping", description="Botの応答を確認する", guild=GUILD)
async def ping(interaction: discord.Interaction):
    await interaction.response.send_message("pong")

async def setup_hook():
    await tree.sync(guild=GUILD)

client.setup_hook = setup_hook

@client.event
async def on_ready():
    print("起動しました:", client.user)

client.run(os.environ["DISCORD_TOKEN"])
```

JS版との差は3つ。同期の呼び出しを書き忘れるとコマンドは出てきません。同期は再接続のたびに呼ばれる`on_ready`ではなく、ログイン後に1回だけ走る`setup_hook`に置いています。コマンドを頻繁に変えない段階になったら、同期を別スクリプトへ移して不要なAPI呼び出しを減らします。そして`discord.Intents.default()`は特権インテントを含まないため、本文を読むなら`message_content = True`を足す必要があります。トークンを誤ると`discord.errors.LoginFailure: Improper token has been passed.`で止まります（2.7.1で確認）。

## 工程6｜24時間稼働の置き場所と無料で動かせる範囲

ローカルで動いたBotは、ターミナルを閉じた瞬間に止まります。置き場所の選択肢は、最初に決めたGateway常駐かHTTP応答かで変わります。

### Gateway常駐のBotをRailwayに置く場合の料金の実額

自宅PCはOS更新の再起動や回線の瞬断で止まるため、業務で使うBotは最初からPaaSへ置いてください。

[Railwayの料金ページ](https://railway.com/pricing)では、Freeプランは月0ドルで、最初の30日は5ドル分のトライアルクレジット、その後は毎月1ドル分。1サービスあたり最大1 vCPU・RAM 0.5GBです。Hobbyは月5ドルの最低利用額に5ドル分のクレジットを含み、1サービスあたり最大48 vCPU・48GB。Proは月20ドルからです。デプロイの具体手順は[Railwayのデプロイ手順とrailway.ts移行｜料金の実額とリージョンの制約](/tech/details/17485/)にまとめました。

Railwayの[Config as Codeのドキュメント](https://docs.railway.com/config-as-code)には「Config as Code is deprecated.」とあり、既存の`railway.json`・`railway.toml`が機能するのは2026年12月1日まで、新規サービスはこの方式を選べません。後継は`.railway/railway.ts`で、`railway.toml`を置く前提の古い手順は写さないでください。

### スラッシュコマンドだけのBotをCloudflare Workersで無料稼働させる構成

「discord bot 24時間稼働 無料」の現実解はこちらです。HTTP方式ならプロセスを常駐させずに済み、Discordの公式チュートリアル[Hosting on Cloudflare Workers](https://docs.discord.com/developers/tutorials/hosting-on-cloudflare-workers)がサンプル一式を配っています。[Workersの制限値](https://developers.cloudflare.com/workers/platform/limits/)では、無料プランは1日10万リクエスト、1リクエストあたりCPU時間10ミリ秒。収まるかどうかはサーバーの人数ではなく、アカウント全体のリクエスト数と1回あたりのCPU時間で決まります。重い処理を挟むなら、ダッシュボードのCPU時間を見てから判断してください。

エンドポイントが守るべきことは2つで、[Interactions Overview](https://docs.discord.com/developers/interactions/overview)に書かれています。URLを保存するときに届く`type: 1`（PING）へ`type: 1`（PONG）を返すこと、そして毎回`X-Signature-Ed25519`と`X-Signature-Timestamp`を検証し、失敗したら401を返すこと。Discordは保存後も意図的に不正な署名を送って定期的に確かめ、検証に失敗するとURLを削除します。

中身を確かめるため、Discord公式の検証ライブラリdiscord-interactions 4.4.0を使い、Nodeの標準httpだけで書いた最小版を手元で動かしました。`npm install discord-interactions@4.4.0 dotenv`を実行し、`.env`に`DISCORD_PUBLIC_KEY=`（General InformationのPublic Key）を足してから、次のコードを`server.js`へ保存して`node server.js`で起動します。

```
import http from "node:http";
import {
  verifyKey,
  InteractionType,
  InteractionResponseType,
} from "discord-interactions";

import "dotenv/config";

const PUBLIC_KEY = process.env.DISCORD_PUBLIC_KEY;
if (!PUBLIC_KEY) {
  throw new Error("DISCORD_PUBLIC_KEYを設定してください");
}

http.createServer(async function (req, res) {
  const chunks = [];
  for await (const c of req) chunks.push(c);
  const raw = Buffer.concat(chunks);

  const ok = await verifyKey(
    raw,
    req.headers["x-signature-ed25519"],
    req.headers["x-signature-timestamp"],
    PUBLIC_KEY
  );
  if (!ok) {
    res.writeHead(401).end("invalid request signature");
    return;
  }

  const body = JSON.parse(raw.toString("utf8"));
  res.setHeader("Content-Type", "application/json");

  if (body.type === InteractionType.PING) {
    res.end(JSON.stringify({ type: InteractionResponseType.PONG }));
    return;
  }
  if (body.type === InteractionType.APPLICATION_COMMAND && body.data.name === "ping") {
    res.end(JSON.stringify({
      type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
      data: { content: "pong" },
    }));
    return;
  }
  res.writeHead(400).end();
}).listen(process.env.PORT || 8787);
```

Ed25519の鍵ペアを手元で作り、Discordと同じ形式で署名したリクエストを送った結果は次のとおりです。正しい署名のPINGには200で`{"type":1}`、署名の1文字を書き換えたPINGには401、`/ping`のコマンドには200で`{"type":4,"data":{"content":"pong"}}`が返りました。Workersへ載せる場合は、この判定部分をそのままWorkerのfetchハンドラへ移す形になり、公式サンプルの`src/server.js`も同じ構造です。

この方式を選ばないほうがよいのは、メッセージ本文への反応や入退室の検知が要るBotです。これらのイベントはInteractions Endpointでは届かず、Gatewayが要ります。一方、3秒を超える処理はどちらの方式でも遅延応答とフォローアップで対応するので、HTTP方式を避ける理由にはなりません。

### 再起動ループでセッション開始の1日1,000回を使い切る事故の防ぎ方

Gateway常駐のBotをPaaSへ載せた後に起きるのが、クラッシュと自動再起動の往復です。Gatewayのリファレンスでは、接続を始められる回数（session start limit）に1日あたりの上限があり、公式の応答例は`"total": 1000`。同ページによれば、IDENTIFYは24時間で1,000回まで（RESUMEは含まない）で、上限に達するとアプリの全セッションが切断され、Botトークンがリセットされてオーナーにメールが届きます。起動直後に落ちるループなら数時間で到達し、コードを直すだけでなく新しいトークンへの差し替えまで必要になります。

対策は、再起動の無制限リトライをやめること。連続失敗の回数に上限を設け、達したらプロセスを終了して通知を飛ばします。残り回数は`GET /gateway/bot`の`session_start_limit.remaining`で確認できます。

## 手順どおりに動かない場合の切り分け｜症状ごとに確認する設定の順番

まず設定と稼働状態を確かめ、問題がなければログとコードの応答処理を調べます。症状ごとに確認する順番を決めておくと、調査箇所を絞れます。

### メッセージの本文が空で返るときに疑うインテントの設定漏れ

イベント自体は届くのに`message.content`が空で返る。原因はMESSAGE\_CONTENT（1 << 15）が無効なことです。確認は2箇所で、Developer PortalのBotページでMessage Content Intentのトグルが入っているか、コード側で`GatewayIntentBits.MessageContent`（discord.pyなら`intents.message_content = True`）を足しているか。片方だけでは通りません。コードを直さずPortalだけ入れた場合は本文が空のまま動き続けますが、Portalで有効にしていない特権インテントをコードで要求すると、Gatewayは4014（Disallowed intent）で接続を閉じます。本文が空なのか、接続自体が切れているのかを、まずログで区別してください。

### スラッシュコマンドが出ない・応答しない場合の登録先と受信経路の確認

入力欄にコマンドが現れない場合は、登録の実行と登録先から確かめます。第一に登録スクリプトの実行忘れで、`index.js`を起動してもコマンドは登録されません。「登録しました」のログが出たかを見ます。第二に登録先の取り違えで、グローバル登録は開発中の確認に向かないため、`applicationGuildCommands`で対象サーバーへ直接登録します。それでも出ないなら、Botがそのサーバーにインストールされているか、サーバー設定の連携サービスでコマンドの利用権限が絞られていないかを見ます。

コマンドは出るのに押すと「アプリケーションは時間内に応答しませんでした」と表示される場合、Developer PortalにInteractions Endpoint URLが入っていないかを確かめてください。入っていると、Gatewayで待つ`index.js`には何も届きません。URLが空なのに同じ表示が出るなら、Botが停止していないか、接続に失敗していないか、ハンドラ内で例外が出ていないか、そのコマンド名の分岐を書き漏らしていないかをログで確かめます。いずれでもなければ応答が3秒を超えています。[Receiving and Responding](https://docs.discord.com/developers/interactions/receiving-and-responding)では最初の応答は3秒以内、トークンの有効期間は15分なので、重い処理の前に`interaction.deferReply()`（discord.pyは`interaction.response.defer()`）を返します。

### 401と403と429で切り分けるトークンと権限とレート制限

エラーが数字で返るなら意味が分かれています。401はトークンが不正か失効、403は権限不足、429はレート制限。トークンの生死は公式APIへ直接投げると早く分かります。次のcurlは`.env`を読まないので、実行するシェルで`DISCORD_TOKEN`を環境変数として設定してから使ってください。

```
curl -H "Authorization: Bot $DISCORD_TOKEN" \
  https://discord.com/api/v10/users/@me
```

Botの情報が返ればトークンは生きています。不正な値を渡すと401でした。403なら招待時の`permissions`かチャンネル個別の権限を見ます。[Rate Limitsのドキュメント](https://docs.discord.com/developers/topics/rate-limits)では、全体の上限が毎秒50リクエスト。401・403・429の無効リクエストが1つのIPで10分に10,000件を超えると一時的に遮断されます（`X-RateLimit-Scope: shared`の429は数えられません）。レスポンスの`X-RateLimit-Remaining`と`X-RateLimit-Reset-After`で残り回数と待ち時間が分かり、ルートごとの制限は`X-RateLimit-Bucket`で束ねられ、チャネルIDなどの主要リソースごとに別に数えられるので、Bucketと主要リソースの組で待ち時間を管理します。429を受けたら`Retry-After`ヘッダー（本文の`retry_after`）の秒数だけ待って再送すること。即座に再送するコードは、無効リクエストの件数を自分で積み上げます。

## 2026年の仕様変更で手順どおり作ったBotが止まる箇所

2026年の変更で、既存の解説記事のコードがそのままでは動かなくなる箇所が出ています。

### 11月16日に必須化するチャネル難読化へIDで備える書き換え方

公式の変更履歴によると、2026年8月12日にチャネル難読化が告知され、2026年11月16日に全Botで必須化されます。Botが閲覧できないチャネルは、Gateway経由では名前が`___hidden___`に置き換わり`CHANNEL_OBFUSCATED`フラグ（1 << 17）が付く。HTTP APIの`GET /guilds/{guild.id}/channels`からはチャネル自体が省かれます。

閲覧権限のあるチャネルだけを扱うBotは影響を受けません。壊れるのは、権限の無いチャネルまで名前で探す実装です。投稿先には閲覧・送信の権限を付けたうえで、チャネルIDを環境変数へ置いて指定してください。ID指定は名前の書き換えに強くなるだけで、権限不足を解消するものではありません。必須化の前に挙動を試すなら、Developer PortalのBotページにあるPrivate Channel Obfuscationのトグルで先行して有効にできます。

### 特権インテントの年1回の再申請に備える縮退運転の設計

1万ユーザーを超えて特権インテントの承認を受けたBotは、年1回の再申請が必須です。[Discordの告知記事](https://support-dev.discord.com/hc/en-us/articles/40281523410967-Changes-to-Privileged-Intent-Access-for-Discord-Apps)では、通知から90日以内に申請しないと特権インテントの利用権限が外されます。MESSAGE\_CONTENTに全機能が依存していると、権限を失った時点で全機能に響く。機能をインテントへの依存度で二層に分け、スラッシュコマンドと定期通知を土台に、本文解析やプレゼンス監視を上層に置いてください。権限を失ったときは、要求するインテントを設定値で外して上層を無効にした状態で接続し直します。未承認の特権インテントを要求したままでは4014で切断されるため、接続後に機能だけ止める作りでは復旧できません。

### 添付20MiBへの引き上げとサイズ検証の値

2026年9月3日に、ユーザー・Bot・Webhook・インタラクション応答の既定の添付上限が10MiBから20MiBへ引き上げられました。ファイルを返すBotは、サイズ検証の閾値を10MiBから20MiBへ置き直してください。

## 業務で使うBotの判断｜Slackへ寄せる条件と外注時の確認点

個人情報や与信情報をBotの応答に載せる要件で、監査ログの保持期間やデータの保管先に社内規程があるなら、Discord Botは作らず既存の業務チャットへ寄せるべきです。社外の開発コミュニティとのやり取りが主で、音声通話と画面共有を日常的に使う現場なら、Discordを軸にして構いません。ツール自体の比較は[Slack・Discord・LINEの違い｜料金・通話・セキュリティと用途別の選び方【2026年】](/tech/details/7427/)で扱っています。

自作Botを社内システムへ繋ぐ構成では、Discord側のコードに加えて、認証情報の管理、権限の対応付け、監査ログ、レート制限を吸収するキューも見積もりの対象になります。外注するなら、Botに要求する権限の内訳、レート制限とリトライの設計、特権インテントの審査が必要になる規模の見込み、の3点が見積もりに書かれているかを確かめてください。外部サービスと業務システムをつなぐ部分の設計は[API開発・システム連携](/service/system/api/)で承っています。

## よくある質問

### Discord Botの作り方は無料でどこまでできますか？

アプリの作成からコマンドの登録、ローカルでの動作確認まで無料で、Discord側にBot作成の料金はありません。24時間動かす段階でも、スラッシュコマンドだけのBotならCloudflare Workersの無料枠に載せられます。メッセージに反応するGateway常駐のBotは、Railwayなら月5ドルのHobbyが現実的な下限です。

### Discord Botはスマホだけで作れますか？

Developer Portalでのアプリ作成や招待はブラウザ操作ですが、Botのプログラムを動かす場所が別に要ります。スマホは常駐プロセスの置き場所に向かないため、コードの実行はPCかクラウドで行う前提で考えてください。例外がBot作成アプリで、Google Playの「Bot Designer For Discord」は、コードを書かずにスマホやタブレットからBotを作り、提供元のサーバーで動かす形を取っています。作れるのはアプリが用意した機能の範囲です。

### プログラミングなしで使えるDiscord Bot作成ツールはありますか？

あります。たとえばBot Designer For Discordは、コードを書かずにコマンドを組み立て、Botの稼働を提供元のサーバーに任せる形です。選ぶ際は、必要なコマンド・外部APIとの連携・稼働の条件が提供元の機能に収まるかを確かめてください。荒らし対策や定型の通知なら既製Botで足り、自分のシステムのデータを返す要件が出た時点で自作に切り替えます。

### スラッシュコマンドではなく普通のメッセージに反応させられますか？

できますが、MESSAGE\_CONTENTの有効化が要ります。Developer PortalのBotページでトグルを入れ、コード側のインテントにも足す、の両方が必要です。特定の合図に反応させたいだけなら、メンションかスラッシュコマンドにすればこのインテントなしで運用できます。

### トークンを誤ってGitHubへ公開した場合はどうすればよいですか？

最優先はDeveloper PortalでReset Tokenを押すことです。押した瞬間に旧トークンが失効するため、コミット履歴が残っていても使えなくなります。履歴の書き換えは失効させた後で足ります。続けて新しいトークンをデプロイ先の環境変数へ入れて再起動し、サーバーの監査ログでBAN・キック・ロール変更の履歴に身に覚えのない操作がないかを確かめてください。

## 関連記事

- [Discord Botの入れ方｜招待リンクでのサーバー追加と権限の確認手順](/tech/details/18127/)
- [Railwayのデプロイ手順とrailway.ts移行｜料金の実額とリージョンの制約](/tech/details/17485/)
- [Incoming Webhookとは？Slack・Discord・Teams・Google Chatの使い方と違い【2026年版】](/tech/details/6596/)
- [スラッシュコマンドとは？Slackでカスタムコマンドを自作する手順と3秒ルール](/tech/details/7935/)
- [Discord MCPの使い方｜Claude Code公式プラグインとMCPサーバーの選び方・設定手順【2026年10月】](/tech/details/8360/)

---

出典: [Discord Botの作り方｜アプリ登録から24時間稼働までを手順どおりに](<https://www.issoh.co.jp/tech/details/17623/>)（株式会社一創）
