> ## Documentation Index
> Fetch the complete documentation index at: https://docs.poplock.scyne.com/llms.txt
> Use this file to discover all available pages before exploring further.

# n8n + Discord integration

> Connect Discord slash commands to the PopLock API through n8n for role-gated server management.

This page describes the integration pattern for letting Discord users manage the PopLock server through slash commands — without ever exposing the API key or requiring direct server access.

<Note>
  This page covers the integration pattern and how it maps to the PopLock API. It does not walk through setting up a Discord bot or configuring n8n from scratch — see the n8n and Discord developer documentation for those steps.
</Note>

## How it works

The architecture places n8n between Discord and the PopLock API. The API key never leaves n8n.

```
Discord user
    │  slash command
    ▼
Discord bot → n8n webhook
                 │
                 ├─ check Discord role / permissions
                 │
                 ├─ (if authorized) HTTP request to PopLock API
                 │         with X-API-Key stored in n8n credentials
                 │
                 └─ send response back to Discord
```

1. **n8n stores the secret API key** — nobody else has it.
2. Discord users trigger slash commands, which hit n8n webhooks.
3. n8n validates the user's Discord role and permissions before forwarding anything.
4. n8n proxies the authorized request to the PopLock API, attaching the key.
5. End-users can manage the server via Discord, but nobody interacts with the server directly.

## Why this pattern

* The API key never appears in Discord messages or channel history.
* n8n owns all authorization logic — role checks, user allowlists, and rate limits all live in the workflow, not in the API.
* No one needs SSH access to the server to perform common management tasks.
* Read endpoints (status, players, backups) are public, so status-check workflows need no credentials at all.

<Tip>
  Store your API key as an n8n credential (a **Header Auth** credential with `X-API-Key` as the name) rather than hardcoding it in HTTP Request nodes. This way the key is managed in one place, masked in the n8n UI, and never visible in exported workflow JSON.
</Tip>

***

## Example flow: `/serverstatus`

A read-only flow that requires no API key.

<Steps>
  <Step title="Discord slash command fires">
    The user runs `/serverstatus` in Discord. Discord calls your n8n **Webhook** node.
  </Step>

  <Step title="n8n calls GET /api/status">
    An **HTTP Request** node makes a `GET` request to `http://your-server:6767/api/status`. No authentication header is needed.
  </Step>

  <Step title="n8n formats the response">
    A **Function** or **Set** node reads the `online`, `uptime`, `memory`, and `version` fields and assembles a Discord embed or plain message string.
  </Step>

  <Step title="n8n replies to Discord">
    n8n sends the formatted message back to Discord via the webhook response or a Discord bot node.
  </Step>
</Steps>

***

## Example flow: `/serverstart`

A write flow that requires role validation and an API key.

<Steps>
  <Step title="Discord slash command fires">
    The user runs `/serverstart` in Discord. Discord calls your n8n **Webhook** node, which receives the interaction payload including the user ID and guild roles.
  </Step>

  <Step title="n8n checks the user's role">
    An **IF** node checks whether the triggering user holds the required role (e.g. `Admin`). If not, n8n sends an error message back to Discord and the workflow stops.
  </Step>

  <Step title="n8n calls POST /api/server/start">
    An **HTTP Request** node makes a `POST` request to `http://your-server:6767/api/server/start` with the `X-API-Key` header pulled from n8n credentials.
  </Step>

  <Step title="n8n replies to Discord">
    On success, n8n sends a confirmation message. On failure (non-2xx from the API), n8n sends an error message.
  </Step>
</Steps>

***

## HTTP Request node configuration

Below is an example n8n HTTP Request node configuration for sending a console command. The API key is referenced from an n8n credential rather than hardcoded.

```json theme={null}
{
  "method": "POST",
  "url": "http://your-server:6767/api/command",
  "headers": {
    "X-API-Key": "={{ $credentials.poplockApi.apiKey }}",
    "Content-Type": "application/json"
  },
  "body": {
    "command": "say {{ $json.command }}"
  }
}
```

For read endpoints, omit the `X-API-Key` header entirely:

```json theme={null}
{
  "method": "GET",
  "url": "http://your-server:6767/api/status"
}
```

***

## Mapping Discord commands to API endpoints

| Discord command            | API endpoint                 | Auth required |
| -------------------------- | ---------------------------- | ------------- |
| `/serverstatus`            | `GET /api/status`            | No            |
| `/players`                 | `GET /api/players/online`    | No            |
| `/backups`                 | `GET /api/backups`           | No            |
| `/serverstart`             | `POST /api/server/start`     | Yes           |
| `/serverstop`              | `POST /api/server/stop`      | Yes           |
| `/serverrestart`           | `POST /api/server/restart`   | Yes           |
| `/command <cmd>`           | `POST /api/command`          | Yes           |
| `/whitelist add <name>`    | `POST /api/whitelist/add`    | Yes           |
| `/whitelist remove <name>` | `POST /api/whitelist/remove` | Yes           |
| `/backup`                  | `POST /api/backup`           | Yes           |

***

## Related pages

* [Read endpoints](/api/endpoints/read) — full reference for all public `GET` routes
* [Write endpoints](/api/endpoints/write) — full reference for all authenticated `POST` routes
* [Authentication](/api/authentication) — how the `X-API-Key` header works and how to generate a key
