# Connect a Discord server

> Link your community's Discord server to your organization for staff links, role menus, commands and support channels.

Source: https://docs.coritan.com/organizations/integrations/discord/

In the dashboard:

- /dashboard/organizations/…/integrations/discord: https://www.coritan.com/dashboard/organizations

Connect a Discord bot of your own to your organization, and your community's Discord server becomes part of your support desk. New tickets appear in a staff channel, customers use slash commands to see their servers and open tickets, members pick roles from menus, and your storefront's community page can show the server's public channels.

## Before you begin

- You need the `owner` or `admin` role in the organization.
- Create an application with a bot in the [Discord developer portal](https://discord.com/developers/applications), and note its application ID, public key and bot token.
- Invite the bot to your Discord server. To copy the server and channel IDs, turn on Developer Mode in Discord's settings.

## Connect the bot

1. Go to [Organizations](https://www.coritan.com/dashboard/organizations), open your organization, choose **Integrations**, then **Discord**.
2. Enter the **Application ID**, the **Public key** and the **Bot token**. We store the token encrypted and never show it again.
3. Enter the **Server (guild) ID** and the **Staff channel ID**, the channel where we post new tickets. Under **Staff channel kind**, choose **Text channel** or **Forum channel**.
4. Leave **Integration enabled** ticked. With it off, we keep the settings and the bot stops answering.
5. To give each ticket its own private channel that staff and the customer both see, tick **One private channel per ticket** under **Ticket channels**. Enter the **Staff role ID** of the role that answers tickets, a **Category prefix** for the channel category, and **Max open channels**, from 1 to 450.
6. To show your server's public channels on your storefront's community page, tick **Mirror public channels on the storefront** under **Community chat**. Add the server's **Invite link**, and list any public channels to keep off the website in **Hidden channels**, separated by commas.
7. Choose **Save Discord settings**.
8. Copy the **Interactions endpoint URL** from the card, and paste it into the Discord developer portal under the application's General Information.

## Result

The **Discord bot** card shows **Enabled**, with the state of the bot's connection to Discord. Saving queues the registration of the bot's slash commands, and customers can then use them in your server, in a direct message to the bot, or anywhere else they have the bot:

| Command | What it does |
| --- | --- |
| `/link` | Connects the customer's Discord account to their account on your storefront. |
| `/servers` | Lists their servers, with start, stop and restart buttons. |
| `/status` | Shows how their servers are doing right now. |
| `/support` | Opens a support ticket. |
| `/tickets` | Lists their open tickets, with a reply button on each. |
| `/help` | Says what the bot can do. |

## Check the connection

The **Diagnostics** card tests the bot's token, its place in your server, the staff channel, the community channels and our queue of Discord work. Each check shows a detail line when it fails. The card's badge reads **All checks pass** or **Needs attention**; choose **Run checks again** after you fix something.

The buttons under the settings do the rest:

- **Sync community channels** rebuilds the list of public channels from your server's own permissions. It needs a server ID.
- **Register slash commands** registers the commands again, for example after you change the application.
- **Edit settings** opens the form again. Leave **Bot token** empty to keep the stored one.
- **Disconnect…** turns the bot off and forgets its token. Type `disconnect` to confirm. We keep the IDs, so reconnecting only needs a new token.

## Add a role menu

A role menu is a message in Discord with one button per role. Members click a button to take the role or drop it.

1. In **Role menus**, choose **New role menu…**.
2. Enter a **Title** for the message and, if you like, a **Description**.
3. Enter the **Channel ID** to post in. To map buttons you posted by hand instead, leave it empty and give the menu a **Key**.
4. Tick the **Roles** members can choose. The list only offers roles the bot can hand out: roles below its own, and not roles that belong to another integration.
5. Choose **Create menu**, then **Publish** on the menu's row to post it. After an edit, **Repost** updates the message already posted.

To delete a menu, choose **Delete role menu** on its row and type the menu's key, or its ID when it has no key. The buttons stop working, but the message stays in Discord until you delete it there.

## Troubleshooting

`No Discord server configured`
: Syncing channels and listing roles need a server. Enter the **Server (guild) ID** and save.

`No bot token configured`
: The integration has no token, for example after a disconnect. Choose **Edit settings** and enter a bot token.

No assignable roles found on the server
: The bot can only hand out roles below its own. In your Discord server's settings, move the bot's role above the roles it should offer.

A check fails with "Discord rejected the token"
: The token was reset in the developer portal. Copy the new one into **Bot token** and save.

The card shows **Last error**
: The bot hit an error talking to Discord. Read the message, fix the cause, then choose **Run checks again**.

## Related

- [Organization integrations](/organizations/integrations/)
- [Answer customer conversations](/organizations/staff-console/support-inbox/)
- [Run a community with a server list, forum and guides](/organizations/storefront/community/)
- [Read the organization audit log](/organizations/audit-log/)

## With the API

Every route needs an owner's or admin's access token, sent as `Authorization: Bearer $CORITAN_TOKEN`, and every change goes on the audit log.

| Route | What it does |
| --- | --- |
| `GET /api/v1/orgs/{org_slug}/discord` | Reads the settings. `configured` is `false` until the first save, and `has_bot_token` says whether a token is stored. |
| `PUT /api/v1/orgs/{org_slug}/discord` | Saves the settings and queues the command registration. |
| `DELETE /api/v1/orgs/{org_slug}/discord` | Turns the bot off and forgets its token. |
| `GET .../discord/diagnostics` | Runs the checks. Each item in `checks` has `check`, `ok` and `detail`. |
| `POST .../discord/community/sync-channels` | Rebuilds the list of public channels. |
| `POST .../discord/register-commands` | Queues the command registration again. |
| `GET .../discord/roles` | Lists your server's roles, with `assignable` on each. |
| `GET` and `POST .../discord/role-menus` | Lists or creates role menus. |
| `PUT` and `DELETE .../discord/role-menus/{menu_id}` | Replaces or deletes a menu. |
| `POST .../discord/role-menus/{menu_id}/publish` | Posts the menu, or edits the message already posted. |
| `GET`, `PUT` and `DELETE .../discord/staff/{discord_user_id}` | Lists, sets and removes staff links. |

`PUT /discord` takes `application_id` and `public_key`, which are required, and optionally `bot_token`, `guild_id`, `staff_channel_id`, `staff_channel_kind` (`text` or `forum`), `is_enabled`, `ticket_channels_enabled`, `ticket_category_prefix`, `staff_role_id`, `max_ticket_channels` (1–450), `community_chat_enabled`, `community_invite_url` and `community_hidden_channels`. A field you leave out keeps its value; send an empty string to clear an ID, or `[]` to clear the hidden channels.

```bash
curl -X PUT "https://api.coritan.com/api/v1/orgs/acme/discord" \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"application_id": "123456789012345678", "public_key": "'"$DISCORD_PUBLIC_KEY"'", "bot_token": "'"$DISCORD_BOT_TOKEN"'", "guild_id": "234567890123456789", "staff_channel_id": "345678901234567890"}'
```

A role menu takes `title`, and optionally `description`, `channel_id` (digits), `menu_key`, `is_enabled` and up to 25 `options`. Each option has `role_id` and `label`, and optionally `emoji`, `description` and `key`. Removing a role from a menu stops members taking it at once, even from a message already posted.

### Staff links

A *staff link* names the member behind a Discord account, so a ticket reply they type in Discord is recorded as theirs. Anyone who holds the role you entered as **Staff role ID** can also answer tickets, and their replies carry their Discord name. No dashboard page manages staff links, so use the API.

```bash
curl -X PUT "https://api.coritan.com/api/v1/orgs/acme/discord/staff" \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"discord_user_id": "456789012345678901", "user_id": 1234}'
```

`user_id` must belong to a member of the organization, or the API answers `404 That user is not a member of this organization`. The link takes the member's role in the organization.

## API

- `GET /api/v1/orgs/{org_slug}/discord`: Get discord config (https://docs.coritan.com/api/reference/organizations/discord/#op-get-api-v1-orgs-org-slug-discord)
- `PUT /api/v1/orgs/{org_slug}/discord`: Put discord config (https://docs.coritan.com/api/reference/organizations/discord/#op-put-api-v1-orgs-org-slug-discord)
- `DELETE /api/v1/orgs/{org_slug}/discord`: Switch the bot off and forget the token (https://docs.coritan.com/api/reference/organizations/discord/#op-delete-api-v1-orgs-org-slug-discord)
- `POST /api/v1/orgs/{org_slug}/discord/community/sync-channels`: Rebuild the public-channel allowlist from Discord's own permissions (https://docs.coritan.com/api/reference/organizations/discord/#op-post-api-v1-orgs-org-slug-discord-community-sync-channels)
- `GET /api/v1/orgs/{org_slug}/discord/diagnostics`: Probe the bot, the guild, the staff channel and the job queue (https://docs.coritan.com/api/reference/organizations/discord/#op-get-api-v1-orgs-org-slug-discord-diagnostics)
- `POST /api/v1/orgs/{org_slug}/discord/register-commands`: Register commands (https://docs.coritan.com/api/reference/organizations/discord/#op-post-api-v1-orgs-org-slug-discord-register-commands)
- `GET /api/v1/orgs/{org_slug}/discord/role-menus`: List role menus (https://docs.coritan.com/api/reference/organizations/discord/#op-get-api-v1-orgs-org-slug-discord-role-menus)
- `POST /api/v1/orgs/{org_slug}/discord/role-menus`: Create role menu (https://docs.coritan.com/api/reference/organizations/discord/#op-post-api-v1-orgs-org-slug-discord-role-menus)
- `PUT /api/v1/orgs/{org_slug}/discord/role-menus/{menu_id}`: Update role menu (https://docs.coritan.com/api/reference/organizations/discord/#op-put-api-v1-orgs-org-slug-discord-role-menus-menu-id)
- `DELETE /api/v1/orgs/{org_slug}/discord/role-menus/{menu_id}`: Delete role menu (https://docs.coritan.com/api/reference/organizations/discord/#op-delete-api-v1-orgs-org-slug-discord-role-menus-menu-id)
- `POST /api/v1/orgs/{org_slug}/discord/role-menus/{menu_id}/publish`: Post the menu to its channel, or edit the message already posted for it (https://docs.coritan.com/api/reference/organizations/discord/#op-post-api-v1-orgs-org-slug-discord-role-menus-menu-id-publish)
- `GET /api/v1/orgs/{org_slug}/discord/roles`: The roles in the org's guild, so a menu can be built by picking not typing (https://docs.coritan.com/api/reference/organizations/discord/#op-get-api-v1-orgs-org-slug-discord-roles)
- `GET /api/v1/orgs/{org_slug}/discord/staff`: List staff links (https://docs.coritan.com/api/reference/organizations/discord/#op-get-api-v1-orgs-org-slug-discord-staff)
- `PUT /api/v1/orgs/{org_slug}/discord/staff`: Put staff link (https://docs.coritan.com/api/reference/organizations/discord/#op-put-api-v1-orgs-org-slug-discord-staff)
- `DELETE /api/v1/orgs/{org_slug}/discord/staff/{discord_user_id}`: Delete staff link (https://docs.coritan.com/api/reference/organizations/discord/#op-delete-api-v1-orgs-org-slug-discord-staff-discord-user-id)
