# Thanks for Purchasing!

We’re really glad you decided to pick up our multi-purpose Discord bot. It means a lot to us, and we can’t wait for you to see what it can do for your server.

In the pages ahead, you’ll find everything you need to set things up and get rolling. We’ll keep it simple, clear, and straight to the point so you can spend less time reading and more time using the bot.\
\
Have fun, and thanks again for being here with us!\
\~ *<mark style="color:$success;background-color:$success;">The Team at Iynx</mark>*\
\ <br>

<figure><img src="/files/oBEN6rdFY9BzeGntx7TX" alt="" width="188"><figcaption></figcaption></figure>

## <mark style="color:blue;">The Team</mark>

### <mark style="color:yellow;">Owner</mark>

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><mark style="color:red;"><strong>Zeroknights</strong></mark></td><td><strong>Discord:</strong> zeroknightss</td><td><strong>GitHub:</strong> <a href="https://github.com/Zeroknights16">Zeroknights16</a></td><td><a href="/files/ovJvEPMXm48BPYRrcaAL">/files/ovJvEPMXm48BPYRrcaAL</a></td></tr><tr><td><mark style="color:red;"><strong>Hiase</strong></mark></td><td><strong>Discord:</strong> hlase</td><td></td><td><a href="/files/G3OH75iRGlZsGT8wcDfk">/files/G3OH75iRGlZsGT8wcDfk</a></td></tr></tbody></table>

### <mark style="color:yellow;">Developers</mark>

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><mark style="color:red;"><strong>CrazyGamer</strong></mark></td><td><strong>Discord:</strong> crazygameer</td><td></td><td><a href="/files/9rCZvnLPBNXkAwFw0vBl">/files/9rCZvnLPBNXkAwFw0vBl</a></td></tr><tr><td><mark style="color:red;"><strong>Dilva</strong></mark></td><td><strong>Discord:</strong> dilva</td><td></td><td><a href="/files/MUxeT0SeasmKBjXDMnsx">/files/MUxeT0SeasmKBjXDMnsx</a></td></tr></tbody></table>

### <mark style="color:yellow;">Staff</mark>

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><mark style="color:red;"><strong>EinfachMaiki</strong></mark></td><td><strong>Discord:</strong> einfachmaiki</td><td></td><td><a href="/files/6loQdooBoW4LA2kysGUm">/files/6loQdooBoW4LA2kysGUm</a></td></tr></tbody></table>

### <mark style="color:yellow;">Special Credits</mark>

#### <mark style="color:orange;">Athena Beta Testers</mark>

* <mark style="color:red;">**BeeFour**</mark> (dracopulse)
* <mark style="color:red;">**EinfachEmer**</mark> (einfachemer)
* <mark style="color:red;">**gOOvER|AT**</mark> (goover)
* <mark style="color:red;">**TheFlyingL**</mark> (theflyingl)
* <mark style="color:red;">**Sewdohe**</mark> (sewdohe)
* <mark style="color:red;">**Konrad**</mark> (neokonrad9833)
* <mark style="color:red;">**Noct**</mark> (noc.t)

#### <mark style="color:orange;">Special Thanks</mark>

* <mark style="color:red;">**AppDatty**</mark> (appdatty) - For supporting development over the years
* <mark style="color:red;">**gOOvER|AT**</mark> (goover) - For making the Pterodactyl Egg that Athena runs on!
* <mark style="color:red;">**Noct**</mark> (noct) - For designing our documentation
* <mark style="color:red;">**CMRiddles**</mark> (cmriddles) - For inspiring Noct to make the docs a lot better

#### <mark style="color:orange;">Community Addon Creators</mark>

* <mark style="color:red;">**Dilva**</mark> (dilva)
* <mark style="color:red;">**Muffiny**</mark> (yapalmuffiny)
* <mark style="color:red;">**TheRedStone**</mark> (theredstonee\_live)
* <mark style="color:red;">**SgtGreyWolf**</mark> (sgtgreywolf)
* <mark style="color:red;">**Cam**</mark> (cammyzed)

#### <mark style="color:orange;">Ex. Staff Members</mark>

* <mark style="color:red;">**Noct**</mark> (noct) - Support
* <mark style="color:red;">**Sewdohe**</mark> (sewdohe) - Support/Developer


# Basic Setup Guide

Ready to get started? Let's go!

## <mark style="color:blue;">Hosting Options</mark>

{% hint style="info" %}
**There is no such thing as absolutely free hosting!**

Either your information is the payment, or your feature set is extremely limited! Be careful for scams, obscure hosting plans, or sneaky payment systems and plans!
{% endhint %}

#### <mark style="color:orange;">Self Hosting</mark>

If you're looking to host a tiny instance, or something that's not critical to keep online all the time, you're more than welcome to run it on your local machine!

#### <mark style="color:orange;">VPS/KVM/VDS Systems</mark>

There's many services that host systems that you could use for this! Hostinger, DigitalOcean, Contabo, etc.! These are much more in depth due to you needing knowledge of how to manage the system.

#### <mark style="color:orange;">Pterodactyl Panel</mark>

The most "plug and play" out of them all! This is the most popular option since this panel lets you do anything from Console Management, File Management, and more! Something like SparkedHost comes to mind!<br>

## <mark style="color:blue;">Configuration</mark>

{% hint style="info" %}
This configuration happens in the <mark style="color:green;">**`common.json`**</mark> file stored at the root of the bot directory.
{% endhint %}

{% hint style="warning" %}
**You need to enable&#x20;*****Developer Mode*** **if you haven't already for this process!**

To **enable** it, go to: *Discord Settings* > *Advanced* > *Developer Mode*
{% endhint %}

#### <mark style="color:orange;">**1. Get your License!**</mark>

All customers need to have a <mark style="color:purple;">license</mark>! This is to allow your bot to communicate with our API and support neat features like global bans, Lavalink services, and some other things! Plus, it helps us protect our product.

If you need a license, open a ticket in our [Support Server](https://discord.iynxdev.com/)!<br>

#### <mark style="color:orange;">**2. FOR PTERODACTYL ONLY: Change your .json file format!**</mark>

<mark style="color:purple;">Pterodactyl</mark> does not support colored `.json5` files within your editor. Due to this make sure to set <mark style="color:purple;">json5</mark> to `false` if your host is running pterodactyl.<br>

{% hint style="info" %}
**Pterdactyl Panel**\
\
The screenshot below shows what a typical **Pterodactyl** file editor looks like. If your panel looks slightly different, don't worry, many hosting providers use custom themes or branding, so the appearance may vary.\
\
![](/files/8SFH3obeDpE2ko8eBl40)
{% endhint %}

#### <mark style="color:orange;">**3. Set your Bot Token!**</mark>

For this, you'll have to look in the Discord Developer Portal!

<mark style="color:purple;">For new bots</mark>, first create a new application, then navigate to Bot and click Reset Token to generate your bot token. While you are at the dev portal, don't forget to invite the bot to your server if you haven't already, preferably with Administrator permissions. Finally, enable the required privileged intents under *Bot* > *Privileged Gateway Intents* (Presence, Server Members, and Message Content).

<mark style="color:purple;">For those with an older version of Athena</mark>, you can just copy over your current token into the new configuration file.

If you need help finding how to make one, [I'll link that video here](https://www.youtube.com/watch?v=dHuWTYRrhDc)!<br>

#### <mark style="color:orange;">**4. Set your MongoDB URI!**</mark>

This is what lets your bot save data! [The process for that is shown in this video](https://www.youtube.com/watch?v=XARrj4hJSD0)!<br>

#### <mark style="color:orange;">**5. Set your Discord Bot ID!**</mark>

Without this, your bot doesn't know which account to interface with.

You need to have Discord's Developer Mode enabled if you haven't yet! It's pretty simple to get it, just right click your bot user in your server and 'Copy ID'.<br>

#### <mark style="color:orange;">**6. Set your Discord Server (Guild) ID!**</mark>

You need to have Discord's Developer Mode enabled if you haven't yet! This is the Server/Guild your bot is in! (Right-click your server icon to get it)<br>

#### <mark style="color:orange;">7. Set your server name!</mark>

This is for your bot's reference in regards to your server name in it's messages.<br>

#### <mark style="color:orange;">8. Set your server color!</mark>

This just makes your embeds correlate to the color you wanted to see the most, so choose whatever you want here.<br>

#### <mark style="color:orange;">9. Set your language!</mark>

This is the language the bot responds in on Discord.

* English: <mark style="color:green;">**`en`**</mark>
* German: <mark style="color:green;">**`de`**</mark>
* Spanish: <mark style="color:green;">**`es`**</mark>
* French: <mark style="color:green;">**`fr`**</mark>
* Portugese: <mark style="color:green;">**`pt`**</mark>
* Dutch: <mark style="color:green;">**`nl`**</mark>
* Turkish: <mark style="color:green;">**`tr`**</mark>
* Russian: <mark style="color:green;">**`ru`**</mark>
* Polish: <mark style="color:green;">**`pl`**</mark>

#### <mark style="color:orange;">10. Set your timezone!</mark>

This is the timezone the bot will use for time-based operations and logging. Use [standard timezone identifiers](https://docs.oracle.com/cd/E72987_01/wcs/tag-ref/MISC/TimeZones.html) (e.g., "Europe/Berlin", "America/New\_York").<br>

***

After everything is done, it should look something similar to below!

<pre class="language-json"><code class="lang-json"><strong>{
</strong>    "general": {
        "license": "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX",
        "json5": false,
        "lang": "en",
        "timezone": "Europe/Berlin"
    },
    "bot": {
        "mongodb_uri": "URI KEY HERE",
        "discord_bot_token": "BOT TOKEN HERE",
        "discord_bot_id": "BOT ID HERE",
        "discord_guild_id": "SERVER ID HERE",
        "server_name": "SERVER NAME HERE",
        "server_color": "YOUR FAVORITE COLOR IN HEX HERE"
    },
    "dashboard": {
        "enabled": false,
        "port": 3222,
        "discord_client_oauth_secret": "",
        "dashboard_base_url": "",
        "web_api_base_url": "",
        "whitelisted_user_ids": [],
        "disable_dashboard_configuration": true,
        "sync_dashboard_configs_to_file": false,
        "low_ram_mode": false
    },
    "console": {
        "logs_include_date": true,
        "logs_to_file": true,
        "logs_include_dashboard_output": true,
        "maximum_log_file_count": 20
    },
    "util": {
        "register_commands": true,
        "prevent_duplicated_message": false,
        "backup_configs_on_startup": false,
        "maximum_config_backup_count": 10,
        "auto_restart": true,
        "auto_restart_every": "7d",
        "debug": false,
        "developer_mode": false
    },
    "updater": {
        "auto_update": true,
        "create_system_backup_before_update": true,
        "maximum_backup_count": 10,
        "plugin_bypass": [],
        "delay_restart_in_seconds": 60,
        "dev_builds": false
    }
}
</code></pre>

{% hint style="success" %}
**Congrats! You're all set on this part!**

But we're not done yet!
{% endhint %}

***

## <mark style="color:blue;">Installing Dependencies</mark>

### <mark style="color:yellow;">Pterodactyl Setup</mark>

{% hint style="info" %}
If you're hosting your **own** Pterodactyl panel, you can use [**the official AthenaBot egg**](https://github.com/gsrvtech/gameserver-templates/tree/main/bots/athenabot). Any standard Node.js egg that supports `Node.js v22+` is also compatible. In addition, the AthenaBot download includes a *pterodactyl-eggs* folder containing two ready to use egg files.

\
**ATTENTION:** Based on user reports, **gsrvtech**'s egg may not be compatible with all pterodactyl setups. If you experience any issues, we recommend using the standard Node.js eggs included with the AthenaBot download instead.
{% endhint %}

{% hint style="warning" %}
Make sure to select [Node v22 (LTS)](https://nodejs.org/en/download/package-manager) or above in your panel!
{% endhint %}

### <mark style="color:yellow;">Self-Host/Non-Pterodactyl Setup</mark>

{% hint style="info" %}
AthenaBot is developed in **JavaScript** and requires [Node v22 / v24 LTS](https://nodejs.org/en/download/package-manager) to run. You can download it from the official `Node.js` website.
{% endhint %}

#### <mark style="color:orange;">Linux (Ubuntu/Debian) Manual Installation</mark>

* [ ] <mark style="color:purple;">**Open a terminal**</mark> in your Athena bot folder.
* [ ] <mark style="color:purple;">**Run**</mark> <mark style="color:green;">**`sudo apt-get update`**</mark>
* [ ] <mark style="color:purple;">**Run**</mark> <mark style="color:green;">**`sudo apt-get install -y build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev`**</mark> to install Canvas/native build requirements.
* [ ] <mark style="color:purple;">**Run**</mark> <mark style="color:green;">**`npm install`**</mark> to install Node packages.
* [ ] <mark style="color:purple;">**Start the bot**</mark> using <mark style="color:green;">**`node index.js`**</mark>

#### <mark style="color:orange;">Windows Manual Installation</mark>

* [ ] <mark style="color:purple;">**Open CMD or PowerShell**</mark> in your Athena bot folder.
* [ ] <mark style="color:purple;">**Run**</mark> <mark style="color:green;">**`npm install`**</mark> to install Node packages.
* [ ] <mark style="color:purple;">**If Canvas fails to install**</mark>, install <mark style="color:green;">**Visual Studio Build Tools (Desktop development with C++)**</mark> and <mark style="color:green;">**Python 3**</mark>, then run <mark style="color:green;">**`npm install`**</mark> again.
* [ ] <mark style="color:purple;">**Start the bot**</mark> using <mark style="color:green;">**`node index.js`**</mark>

{% hint style="info" %}
**For Bot Persistence even after closing the CMD Prompt window:**

<mark style="color:purple;">**Linux:**</mark>

Install PM2 once with <mark style="color:green;">**`npm install pm2 -g`**</mark>, then use <mark style="color:green;">**`pm2 start index.js --name Athena`**</mark> to keep your bot alive.

And use <mark style="color:green;">**`pm2 stop Athena`**</mark> to turn it back off!\
\ <mark style="color:purple;">**Windows:**</mark>

PM2 is primarily documented here for Linux hosts. For Windows, use the startup batch script *windows start.bat* provided in the download (or Windows Task Scheduler) for persistence.

This script allows you to keep AthenaBot online even after restarts. The batch script was made by <mark style="color:red;">**@.dodgeman**</mark> (334154279029833728)
{% endhint %}

## <mark style="color:blue;">Finalizing Setup</mark>

{% hint style="info" %}
If you edit Athena files **locally** in `Visual Studio Code`, install the <mark style="color:green;">**JSON5 Syntax**</mark> extension so your <mark style="color:green;">**`.json5`**</mark> config files are color highlighted and easier to read.

<img src="/files/HXNV2ZAgTgZTpcKTcYd6" alt="" data-size="original">
{% endhint %}

* [ ] <mark style="color:purple;">**Start the Bot!**</mark> This will create all necessary configuration files for you to edit!
* [ ] <mark style="color:purple;">**Configure everything!**</mark> All configuration files can be found in your ./*configuration* folder!
* [ ] <mark style="color:purple;">**Restart the Bot!**</mark>
* [ ] <mark style="color:purple;">**Enjoy!**</mark>

{% hint style="danger" %}
**Configuration Files**\
\
**After completing this guide, your configuration files will be generated in the `/configuration` folder.** These are the files you should edit. The files inside the `/plugins` folder are templates and <mark style="color:$danger;">**should not be**</mark> modified.
{% endhint %}

{% hint style="success" %}
If you'd also like to set up the **dashboard**, follow the [**Dashboard Setup Guide**](/getting-started/dashboard-setup).
{% endhint %}


# Dashboard Setup

Ready to launch your dashboard? Let's set it up.

{% hint style="warning" %}
**This setup guide assumes that the** [**Basic Setup Guide**](/getting-started/basic-setup-guide) **has already been completed!**
{% endhint %}

{% hint style="info" %}
We've recorded a **video** that walks you through this part of the documentation. [Check it out here](https://www.youtube.com/watch?v=31lCDLs6b3s)!
{% endhint %}

## <mark style="color:blue;">AthenaBot Web API Setup</mark>

The Web API is the bridge between AthenaBot and the Dashboard. If this is wrong, the dashboard cannot load data.<br>

Open <mark style="color:green;">**`/configuration/web_api.json(5)`**</mark> and complete these steps:

#### <mark style="color:orange;">1. Set your API port</mark>

Pick a free port (example uses `3111`):

```json5
port: "3111"
```

#### <mark style="color:orange;">2. Set a secure authentication key</mark>

Replace the default value of `authentication_key` with a randomly generated string:

```json5
authentication_key: ["your-super-secure-key"]
```

{% hint style="danger" %}
Leaving the **default API key** unchanged will prevent the plugin from loading for security reasons.
{% endhint %}

#### <mark style="color:orange;">3. Set base IP / domain</mark>

Configure `base_ip` using **one** of the following options:

* IP Address: `"<host_ip>:<web_api_port>"`\
  Example: `123.123.123.123:3111`
* Domain: `"<web_api_subdomain>"`\
  Example: `api.iynxdev.com`

{% hint style="info" %}
If you are using a domain, point it to your server using an **A record** (or **CNAME**) and configure either a **reverse proxy** (recommended) or **Cloudflare Tunnel** to forward requests to your dashboard. DNS and web server configuration are outside the scope of this guide.
{% endhint %}

#### <mark style="color:orange;">4. Optional hardening options</mark>

* `secure_mode`: Restrict most API routes to trusted IP addresses listed in `whitelisted_ips`
* `whitelisted_ips`: Keep the default entries and add any additional trusted IP addresses that should be allowed to access protected API routes
* `rate_limit.enabled`: Keep enabled to protect the API against excessive requests
* `rate_limit.proxied`: Enable if the dashboard is behind a reverse proxy (e.g. Nginx, Apache, Caddy, or Cloudflare Tunnel)

***

## <mark style="color:blue;">Dashboard Configuration</mark>

Now open <mark style="color:green;">**`/common.json`**</mark> and edit the `dashboard` section.

#### <mark style="color:orange;">1. Enable dashboard</mark>

```json
"enabled": true
```

#### <mark style="color:orange;">2. Set dashboard port</mark>

Pick a free port (example uses `3222`):

```json
"port": 3222
```

{% hint style="warning" %}
The dashboard must use a **different** port than the one configured for the Web API
{% endhint %}

#### <mark style="color:orange;">3. Configure the Dashboard & Web API URLs</mark>

Update both URLs to match your deployment.

**Dashboard URL (`dashboard_base_url`):**

* IP setup: `http://<server_ip>:<dashboard_port>`\
  Example: `http://123.123.123.123:3222`
* Domain setup: `https://<dashboard_subdomain>`\
  Example: `https://dashboard.iynxdev.com`

\
**Web API URL (`web_api_base_url`):**

* IP setup: `http://<server_ip>:<web_api_port>`\
  Example: `http://123.123.123.123:3111`
* Domain: *equals IP setup*

{% hint style="danger" %}
**Please leave the `web_api_local_url` setting empty unless instructed otherwise by our Support team.**
{% endhint %}

#### <mark style="color:orange;">4. Whitelist your Discord account</mark>

Add your Discord user ID to:

```json
"whitelisted_user_ids": ["YOUR_DISCORD_USER_ID", "YOUR_FRIENDS_DISCORD_USER_ID"]
```

#### <mark style="color:orange;">5. Optional Dashboard Configuration</mark>

When the dashboard is enabled for the first time, Athena imports the configuration files from the `/configuration` directory into the database.

From that point onward, **the dashboard configuration becomes the source of truth**. Changes made to the configuration files are ignored while the dashboard is enabled.

Optional settings:

* **`disable_dashboard_configuration`:** Prevent configuration changes from the dashboard and use the configuration files in `/configuration` instead.
* **`sync_dashboard_configs_to_file`:** Automatically write configuration changes made in the dashboard back to the files in `/configuration`.

{% hint style="warning" %}
Enabling `sync_dashboard_configs_to_file` **may overwrite** your existing configuration files.<br>

Synchronization only occurs from the dashboard to the configuration files, **not the other way around**.
{% endhint %}

{% hint style="info" %}
If you want to **discard** the dashboard configuration and **reimport** your configuration files, run in console while the bot is running:

```
script clear-dashboard
```

{% endhint %}

***

## <mark style="color:blue;">Discord OAuth Setup</mark>

The dashboard login uses Discord OAuth.

#### <mark style="color:orange;">1. Add redirect URL</mark>

Open your application in the [**Discord Developer Portal**](https://discord.com/developers/applications) and navigate to **OAuth2 → Redirects**.

Add **one** of the following redirect URLs:

* **IP setup:** `http://<host_ip>:<dashboard_port>/api/auth/callback`\
  Example: `http://123.123.123.123:3222/api/auth/callback`
* **Domain setup**: `https://<dashboard_subdomain>/api/auth/callback`\
  Example: `https://dashboard.iynxdev.com/api/auth/callback`

#### <mark style="color:orange;">2. Configure the Client Secret</mark>

In the **Discord Developer Portal**, navigate to **OAuth2**, generate or copy your **Client Secret**, and set it in `common.json`:

```json
"discord_client_oauth_secret": "YOUR_DISCORD_CLIENT_SECRET"
```

***

{% hint style="success" %}
**Setup Complete!**

Restart the bot and access your dashboard using the URL you configured:

* **IP setup:** `http://<server_ip>:<dashboard_port>`\
  Example: `http://123.123.123.123:3222`
* **Domain setup:** `https://<dashboard_subdomain>`\
  Example: `https://dashboard.iynxdev.com`
  {% endhint %}


# Nginx Configuration

{% hint style="info" %}
This page assumes your AthenaBot Dashboard and Web API are already configured and working on local ports.

If you have not finished that yet, complete the Dashboard Setup guide first.
{% endhint %}

## <mark style="color:blue;">Before You Start</mark>

Make sure you know these values before editing Nginx:

* Dashboard domain (example: `panel.example.com`)
* Web API domain (example: `api.example.com`)
* Dashboard local URL (example: `http://127.0.0.1:3222`)
* Web API local URL (example: `http://127.0.0.1:3111`)

Using two subdomains is recommended when transcripts and API routes are served together.

{% hint style="warning" %}
Use different ports for Dashboard and Web API. Do not expose those internal ports directly to the public internet when using Nginx as a reverse proxy.
{% endhint %}

***

## <mark style="color:blue;">HTTP-Only Configuration (Testing)</mark>

Use this only for local testing or private networks.

Create a site file in Nginx (for example `/etc/nginx/sites-available/athena-dashboard`) and add:

```nginx
server {
	listen 80;
	server_name panel.example.com;

	# Dashboard frontend + dashboard API
	location / {
		proxy_pass http://127.0.0.1:3222;
		proxy_http_version 1.1;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_set_header Upgrade $http_upgrade;
		proxy_set_header Connection "upgrade";
	}
}

server {
	listen 80;
	server_name api.example.com;

	# AthenaBot Web API + transcripts
	location / {
		proxy_pass http://127.0.0.1:3111;
		proxy_http_version 1.1;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
	}
}
```

{% hint style="warning" %}
This is a testing-only setup. For production, use HTTPS on both subdomains.
{% endhint %}

***

## <mark style="color:blue;">HTTPS Configuration (Recommended)</mark>

For production, use HTTPS with a valid certificate.

```nginx
server {
	listen 80;
	server_name panel.example.com;
	return 301 https://$host$request_uri;
}

server {
	listen 80;
	server_name api.example.com;
	return 301 https://$host$request_uri;
}

server {
	listen 443 ssl http2;
	server_name panel.example.com;

	ssl_certificate /etc/letsencrypt/live/panel.example.com/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/panel.example.com/privkey.pem;

	# Dashboard frontend + dashboard API
	location / {
		proxy_pass http://127.0.0.1:3222;
		proxy_http_version 1.1;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_set_header Upgrade $http_upgrade;
		proxy_set_header Connection "upgrade";
	}
}

server {
	listen 443 ssl http2;
	server_name api.example.com;

	ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;

	# AthenaBot Web API + transcripts
	location / {
		proxy_pass http://127.0.0.1:3111;
		proxy_http_version 1.1;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
	}
}
```

***

## <mark style="color:blue;">AthenaBot Config Values When Using Nginx</mark>

Set your Dashboard and Web API URLs in `common.json` to public-facing values:

```json
"dashboard_base_url": "https://panel.example.com",
"web_api_base_url": "https://api.example.com"
```

In your Web API config (`web_api.json(5)`), set `base_ip` to your API domain (example: `api.example.com`).

In Discord Developer Portal OAuth2 redirects, use:

```
https://panel.example.com/api/auth/callback
```

{% hint style="danger" %}
The redirect URL must match exactly, including protocol (`http` or `https`), domain, and path.
{% endhint %}

***

## <mark style="color:blue;">Enable and Test</mark>

After saving your Nginx file:

1. Test syntax:

```bash
sudo nginx -t
```

2. Reload Nginx:

```bash
sudo systemctl reload nginx
```

3. Start AthenaBot and test:

* Open `https://panel.example.com`
* Confirm dashboard login works
* Confirm data loads without `fetch failed`

***

## <mark style="color:blue;">Common Problems</mark>

If the dashboard does not load correctly:

1. `502 Bad Gateway`
   * Dashboard or Web API is not running on the target local port.
   * `proxy_pass` points to the wrong host/port.
2. `fetch failed` or API errors
   * `web_api_base_url` does not match your API subdomain.
   * Web API `authentication_key` is invalid/default.
3. OAuth redirect loop or login failure
   * Redirect URL in Discord Developer Portal does not exactly match the active dashboard URL.
4. Cloudflare / reverse proxy rate-limit issues
   * Set Web API `rate_limit.proxied` to `true`.
   * Keep only trusted proxy paths publicly exposed.


# Common Issues

A list of issues people might commonly have!

{% hint style="info" %}
**Problem not solved after checking here? Let us know in** [**our Support Server**](https://discord.iynxdev.com/)**!**
{% endhint %}

## <mark style="color:blue;">Bot Related</mark>

### <mark style="color:yellow;">My Bot Crashes Immediately</mark>

#### <mark style="color:orange;">Your Configuration is not complete</mark>

You may have forgotten to fill some information in the `common.json` file. <mark style="color:red;">**It's mandatory to fill in every space in that file!**</mark>

#### <mark style="color:orange;">Guild Not Whitelisted</mark>

You may have forgotten to <mark style="color:purple;">add your Guild to the whitelist</mark> required with your license!

Make sure to run <mark style="color:green;">**`/guild whitelist`**</mark> in [our Support Server!](https://discord.iynxdev.com/)

#### <mark style="color:orange;">IP Not Whitelisted</mark>

You may have forgotten to <mark style="color:purple;">add your IP to the whitelist</mark> required with your license!

Make sure to run <mark style="color:green;">**`/ip whitelist`**</mark> in [our Support Server!](https://discord.iynxdev.com/)

***

## <mark style="color:blue;">Antivirus Related</mark>

### <mark style="color:yellow;">My Antivirus Quarantined Files</mark>

*Microsoft Defender* and *potentially* some other Anti-Malware services are flagging the obfuscated code with emojis in them! These are not malicious files but they're being quarantined/removed by accident. You can restore the files through whatever software solution you're using to get the files back in place, they **do not** contain malicious code!

***

## <mark style="color:blue;">Command Related</mark>

### <mark style="color:yellow;">My Commands aren't working</mark>

#### <mark style="color:orange;">Forgot to configure Permissions</mark>

You need to <mark style="color:purple;">make sure all permissions are assigned</mark> in the <mark style="color:green;">**`permissions.json`**</mark> file, *both* the roles and IDs, as *well* as the permission levels each of them get!

#### <mark style="color:orange;">Developer Mode is Enabled</mark>

This can cause commands to not show up! Make sure that <mark style="color:green;">**`developer-mode`**</mark> is <mark style="color:purple;">disabled</mark> in the <mark style="color:green;">**`common.json`**</mark> file.

#### <mark style="color:orange;">A Plugin might have crashed</mark>

<mark style="color:purple;">Check to see if you don't have errors coming up in your console for plugins</mark>! If plugins disable, they'll disable any associated commands too.

#### <mark style="color:orange;">Server or Bot ID may be incorrect</mark>

<mark style="color:purple;">Check to see if your Server/Bot ID are wrong</mark> by accident. Your bot needs the right value. If either of them are wrong, your bot will not know what it's trying to connect to.

***

## <mark style="color:blue;">MongoDB Related</mark>

### <mark style="color:yellow;">My Bot Crashes During Startup</mark>

#### <mark style="color:orange;">MongoDB Firewall</mark>

```javascript
MongooseError: Operation users.findOne() buffering timed out after 10000ms
    at Timeout. (C:\Users\khyek\crossfit-wod-api\node_modules\mongoose\lib\drivers\node-mongodb-native\collection.js:187:23)
    at listOnTimeout (node:internal/timers:594:17)
    at process.processTimers (node:internal/timers:529:7)
```

If you encounter this error, make sure to <mark style="color:purple;">add</mark> your host's IP address to your database's IP allowlist (whitelist). Alternatively, you can allow <mark style="color:purple;">connections from any IP</mark> by adding <mark style="color:green;">**`0.0.0.0/0`**</mark> to the allowlist. [A guide to that is here](https://www.mongodb.com/docs/atlas/security/add-ip-address-to-list/)!

{% hint style="warning" %}
**If and only if that did not resolve the issue**, make sure your MongoDB connection string contains a **database name**.\
\
Some MongoDB setups require a database name to be specified. If it is missing, Mongoose may fail to connect and you'll receive the same error.\
\
**✅ Correct**

```berry
mongodb+srv://<credentials>@cluster.mongodb.net/athenabot?retryWrites=true&w=majority&appName=YourCluster
```

\
**❌ Incorrect**

```berry
mongodb+srv://username:<PASSWORD>@cluster.mongodb.net?retryWrites=true&w=majority&appName=YourCluster
```

\
Notice the `/athenabot` after `.mongodb.net/`. If you don't have a database yet, you can use any name. MongoDB Atlas will automatically create it the first time AthenaBot stores data.
{% endhint %}

#### <mark style="color:orange;">MongoDB Connection</mark>

<pre class="language-javascript"><code class="lang-javascript"><strong>[ERR] | ERROR REPORT
</strong>[ERR] | * Error: querySrv ECONNREFUSED _mongodb._tcp.cluster0.gpitjxx.mongodb.net
[ERR] | * Type: Javascript
[ERR] | * ID: as7mf0
[ERR] | * Impact: critical
[ERR] |
[ERR] | Error Information
[ERR] | * Registered error: ✅
[ERR] | * Description: These are very specific errors that require further investigation. Please create a ticket
[ERR] | * Documentation: none
[ERR] |
[ERR] | (!) Please checkout our documentation page to address your issue.
</code></pre>

There is currently an issue in **Node.js on Windows** that can cause this error. If you're interested, you can read more about it here: <https://github.com/nodejs/node/pull/61453>.

The issue has already been fixed in **Node.js v26**, and the Node.js team is working on backporting the fix to earlier versions.

For the time being, the recommended workaround is to **downgrade to Node.js `v24.11.1`** or run Athena on a **non Windows host** (such as Linux), where this issue does not occur.

***

## <mark style="color:blue;">Dashboard Related</mark>

### <mark style="color:yellow;">My Dashboard Fails To Build During Startup</mark>

#### <mark style="color:orange;">Dependency Issues</mark>

```javascript
[ERR] | ERROR REPORT
[ERR] | * Error: npm run build exited with code 135
[ERR] | * Type: Javascript
[ERR] | * ID: 15e5sl
[ERR] | * Impact: critical
[ERR] | 
[ERR] | Error Information
[ERR] | * Registered error: ✅
[ERR] | * Description: These are very specific errors that require further investigation. Please create a ticket
[ERR] | * Documentation: none
[ERR] | 
[ERR] | (!) Please checkout our documentation page to address your issue.
```

This issue can have two different causes:

* **Insufficient memory:** The bot does not have enough RAM available to build the dashboard.
* **Node.js version change:** Updating or changing your Node.js version can leave behind incompatible build artifacts.

To resolve the issue, navigate to your `/dashboard` folder, delete the `.next` and `node_modules` directories, and then restart the bot. This will force the dashboard to rebuild using your current Node.js version.


# Applications

Complete guide to configuring your application system

## <mark style="color:blue;">Introduction</mark>

The Applications system allows your server members to apply for staff positions, roles, or other opportunities directly through Discord. Applications are managed through private channels with customizable questions, review permissions, and automated workflows.

This guide covers every aspect of the application configuration file (`applications.json`) to help you create a professional application system for your server.

***

## <mark style="color:blue;">Part 1: Basic Configuration</mark>

### <mark style="color:yellow;">Understanding Basic Settings</mark>

The basic configuration section controls global application behavior, including staff management integration, channel naming, and cooldown periods.

```json
config: {
    staff_management_hook: true,
    application_channel_name: "app-%random%",
    default_cooldown: "7d",
    // ... applications and questions below
}
```

***

### <mark style="color:yellow;">Configuration Options</mark>

#### <mark style="color:orange;">staff\_management\_hook</mark>

**Type:** Boolean (`true` or `false`)

Controls automatic integration with the Staff Management plugin when applications are accepted.

**When enabled (`true`):**

* Accepted applicants automatically receive their designated roles
* Staff roster panel is automatically updated
* Promotion message is generated based on staff\_management configuration

**When disabled (`false`):**

* Manual role assignment required
* No automatic roster updates

**Recommended:** `true` if you have the Staff Management plugin configured

{% hint style="info" %}
**Note:** For this feature to work properly, ensure your staff\_management plugin is configured with the appropriate role assignments and promotion messages.
{% endhint %}

***

#### <mark style="color:orange;">application\_channel\_name</mark>

**Type:** String

Defines the naming pattern for application channels that are created when a user starts an application.

**Available Placeholders:**

| Placeholder       | Description                          | Example    |
| ----------------- | ------------------------------------ | ---------- |
| `%random%`        | Random 4-digit number                | `1234`     |
| `%creator%`       | Username of the applicant            | `john_doe` |
| `%created_total%` | Total number of applications created | `42`       |
| `%category%`      | Application category name            | `staff`    |

**Examples:**

```json
// Using random number (recommended for privacy)
application_channel_name: "app-%random%"
// Result: app-7382

// Using creator name
application_channel_name: "application-%creator%"
// Result: application-john_doe

// Using category and number
application_channel_name: "%category%-app-%created_total%"
// Result: staff-app-42

// Combining multiple placeholders
application_channel_name: "%category%-%creator%-%random%"
// Result: staff-john_doe-5821
```

{% hint style="success" %}
**Best Practice:** Use `%random%` to maintain applicant privacy and prevent channel name conflicts.
{% endhint %}

{% hint style="warning" %}
**Privacy Warning:** Using `%creator%` exposes the applicant's username to anyone who can see the channel category. Consider privacy implications before using this placeholder.
{% endhint %}

***

#### <mark style="color:orange;">default\_cooldown</mark>

**Type:** String (Time Duration)

Sets how long users must wait before submitting a new application after being denied.

**Time Format:**

* `s` = seconds (e.g., `30s`)
* `m` = minutes (e.g., `15m`)
* `h` = hours (e.g., `12h`)
* `d` = days (e.g., `7d`)
* `w` = weeks (e.g., `2w`)

**Recommended Values:**

| Server Type       | Recommended Cooldown | Reasoning                                    |
| ----------------- | -------------------- | -------------------------------------------- |
| Small/Casual      | `3d` to `5d`         | Allows quick reapplication with improvements |
| Medium            | `7d` to `14d`        | Balances feedback time with persistence      |
| Large/Competitive | `14d` to `30d`       | Ensures applicants take time to improve      |

**Examples:**

```json
// 7-day cooldown (most common)
default_cooldown: "7d"

// 2-week cooldown for serious positions
default_cooldown: "14d"

// 12-hour cooldown for testing/casual applications
default_cooldown: "12h"

// 30-day cooldown for highly competitive roles
default_cooldown: "30d"
```

{% hint style="info" %}
**Tip:** Longer cooldowns encourage applicants to put more effort into their applications rather than spam submissions.
{% endhint %}

***

## <mark style="color:blue;">Part 2: Application Categories</mark>

### <mark style="color:yellow;">Understanding Application Categories</mark>

Application categories define different types of applications (Staff, Helper, Builder, etc.) with their own questions, permissions, and settings. Users select which category to apply for, and a private channel is created for their application.

```json
applications: [
    {
        application: "Staff",
        description: "Select to start a Staff Application",
        emoji: "👮",
        category_id: "1160209305593716776",
        questions: "first_question_set",
        permission_list: ["804354019455139900"],
        mention_roles: ["804354019455139900"]
    },
]
```

***

### <mark style="color:yellow;">Category Configuration Options</mark>

#### <mark style="color:orange;">application</mark>

**Type:** String

The display name of the application type.

**Examples:**

* `"Staff"` - General staff position
* `"Helper"` - Support team member
* `"Moderator"` - Moderation role
* `"Builder"` - Minecraft/Creative role
* `"Developer"` - Development team
* `"Content Creator"` - Media/Content team

**Best Practices:**

* Keep names short and clear (1-2 words)
* Use title case for professionalism
* Match the role name for clarity

***

#### <mark style="color:orange;">description</mark>

**Type:** String

Brief explanation shown to users when selecting an application type.

**Examples:**

```json
// Clear and action-oriented
description: "Apply to join our staff team"

// Informative with requirements hint
description: "Apply for Moderator (Must be active member)"

// Welcoming and encouraging
description: "Join our build team! Show us your creativity"

// Professional with expectations
description: "Content Creator application - Provide portfolio"
```

**Best Practices:**

* Be clear about what the role entails
* Mention any key requirements
* Keep it under 50 characters
* Use encouraging language

***

#### <mark style="color:orange;">emoji</mark>

**Type:** String

Icon displayed next to the application option in the selection menu.

**Emoji Options:**

**Default Discord Emojis:**

```json
emoji: "👮"  // Police officer (Staff/Security)
emoji: "🛡️"  // Shield (Moderator)
emoji: "🔨"  // Hammer (Builder)
emoji: "💻"  // Computer (Developer)
emoji: "🎨"  // Art palette (Designer)
emoji: "🎥"  // Camera (Content Creator)
emoji: "❓"  // Question (Helper/Support)
emoji: "🌟"  // Star (Premium/VIP)
```

**Custom Server Emojis:**

To use custom emojis, you need the emoji ID:

1. Enable Developer Mode in Discord (User Settings → Advanced → Developer Mode)
2. Right-click your custom emoji and select "Copy Link"
3. Extract the ID from the URL: `https://cdn.discordapp.com/emojis/123456789.png`
4. Format: `<:emoji_name:emoji_id>`

```json
// Custom emoji example
emoji: "<:staff:123456789>"
```

**Animated Emojis:**

```json
emoji: "<a:sparkle:123456789>"
```

***

#### <mark style="color:orange;">category\_id</mark>

**Type:** String

The Discord category ID where application channels will be created.

**How to Get Category ID:**

1. Enable Developer Mode in Discord
2. Right-click the category in your server
3. Click "Copy ID"
4. Paste the ID as a string

```json
category_id: "1160209305593716776"
```

***

#### <mark style="color:orange;">questions</mark>

**Type:** String

The ID of the question set to use for this application category (references `application_questions` configuration).

```json
questions: "first_question_set"
```

This links to your question configuration:

```json
application_questions: {
    "first_question_set": [
        // questions here
    ],
    "moderator_questions": [
        // different questions
    ]
}
```

**Examples:**

```json
// Staff applications
questions: "staff_questions"

// Moderator applications
questions: "moderator_questions"

// Builder applications  
questions: "builder_questions"
```

{% hint style="info" %}
**Tip:** Create different question sets for different roles. Moderators need different questions than builders or developers.
{% endhint %}

***

#### <mark style="color:orange;">permission\_list</mark>

**Type:** Array of Strings (Role IDs)

List of role IDs that can view and review applications in this category.

```json
permission_list: [
    "804354019455139900",  // Head Staff
    "805123456789012345",  // Moderators
]
```

**How to Get Role IDs:**

1. Enable Developer Mode
2. Go to Server Settings → Roles
3. Right-click a role and select "Copy ID"

**Best Practices:**

{% hint style="success" %}
**Recommended Structure:**

* Include management/admin roles
* Include the specific team leads (e.g., Head Moderator for mod applications)
* Don't give access to roles that shouldn't review (prevents bias)
* Consider creating a dedicated "Application Reviewer" role
  {% endhint %}

**Examples:**

```json
// Only senior staff
permission_list: [
    "123456789012345678"  // Admin
]

// Multiple review tiers
permission_list: [
    "123456789012345678",  // Admin
    "234567890123456789",  // Head Moderator
    "345678901234567890"   // Senior Moderator
]

// Team-specific reviewers
permission_list: [
    "123456789012345678",  // Admin
    "456789012345678901"   // Build Team Lead
]
```

***

#### <mark style="color:orange;">mention\_roles</mark>

**Type:** Array of Strings (Role IDs)

List of role IDs to mention (@ping) when a new application is submitted.

```json
mention_roles: [
    "804354019455139900"
]
```

**Best Practices:**

{% hint style="warning" %}
**Mention Carefully:**

* Don't mention large roles (can cause spam)
* Only mention roles that actively review applications
* Consider using a dedicated "Application Notifications" role
* Ensure mentioned users have notifications enabled
  {% endhint %}

**Examples:**

```json
// No mentions (silent applications)
mention_roles: []

// Mention application reviewers only
mention_roles: [
    "123456789012345678"  // Application Reviewers
]

// Mention multiple roles
mention_roles: [
    "123456789012345678",  // Head Staff
    "234567890123456789"   // Moderators
]
```

***

### <mark style="color:yellow;">Complete Category Examples</mark>

#### <mark style="color:orange;">Example 1: Staff Application</mark>

General staff position for your server:

```json
{
    application: "Staff",
    description: "Apply to join our staff team",
    emoji: "👮",
    category_id: "1160209305593716776",
    questions: "staff_questions",
    permission_list: [
        "804354019455139900",  // Admin
        "805123456789012345"   // Head Staff
    ],
    mention_roles: [
        "805123456789012345"   // Head Staff only
    ]
}
```

***

#### <mark style="color:orange;">Example 2: Multiple Application Categories</mark>

Server with multiple different application types:

```json
applications: [
    {
        application: "Staff",
        description: "General staff application",
        emoji: "👮",
        category_id: "1160209305593716776",
        questions: "staff_questions",
        permission_list: ["804354019455139900"],
        mention_roles: ["804354019455139900"]
    },
    {
        application: "Moderator",
        description: "Apply for Moderator role",
        emoji: "🛡️",
        category_id: "1160209305593716776",
        questions: "moderator_questions",
        permission_list: ["804354019455139900", "805123456789012345"],
        mention_roles: ["805123456789012345"]
    },
    {
        application: "Developer",
        description: "Join our development team",
        emoji: "💻",
        category_id: "1160209305593716776",
        questions: "developer_questions",
        permission_list: ["804354019455139900", "806234567890123456"],
        mention_roles: ["806234567890123456"]
    },
    {
        application: "Content Creator",
        description: "Apply to be a content creator",
        emoji: "🎥",
        category_id: "1160209305593716776",
        questions: "creator_questions",
        permission_list: ["804354019455139900"],
        mention_roles: ["804354019455139900"]
    }
]
```

***

## <mark style="color:blue;">Part 3: Application Questions</mark>

### <mark style="color:yellow;">Understanding Question Structure</mark>

Application questions are what applicants must answer to submit their application. Questions can be text inputs or selection menus with predefined options.

```json
application_questions: {
    "first_question_set": [
        {
            question: "What is your IGN?",
            max_length: 20,
            min_length: 2,
            placeholder: "Enter a value...",
            select_options: [],
            required: true,
        },
    ],
}
```

***

### <mark style="color:yellow;">Question Configuration Options</mark>

#### <mark style="color:orange;">question</mark>

**Type:** String

The actual question text displayed to the applicant. Max length is set to 45 characters by Discord!

**Best Practices:**

{% hint style="success" %}
**Writing Good Questions:**

* Be specific and clear
* Ask one thing per question
* Use proper grammar and punctuation
* Avoid yes/no questions (unless using select options)
* Ask questions that reveal character, skills, and fit
  {% endhint %}

**Examples:**

```json
// Good questions
question: "What is your in-game name?"
question: "Describe your previous moderation experience"
question: "Why do you want to join our team?"
question: "How would you handle a conflict between members?"
question: "What timezone are you in?"

// Avoid these
question: "Tell me about yourself"  // Too vague
question: "Are you active?"  // Yes/no without context
question: "Why should we pick you?"  // Too generic
```

***

#### <mark style="color:orange;">max\_length & min\_length</mark>

**Type:** Number

For text inputs, these define character limits. For select menus, they define how many options can be selected.

**Text Input Behavior:**

```json
// Short answer (username, IGN, etc.)
max_length: 20
min_length: 2

// Medium answer (timezone, age range)
max_length: 50
min_length: 3

// Long answer (experience, scenarios)
max_length: 800
min_length: 50

// Essay-style answer
max_length: 2000
min_length: 100
```

**Select Menu Behavior:**

```json
// Single selection only
max_length: 1
min_length: 1

// Multiple selections allowed (1-3 options)
max_length: 3
min_length: 1

// Multiple selections required (at least 2)
max_length: 5
min_length: 2
```

{% hint style="warning" %}
**Important:** Discord has a maximum of 4000 characters for text inputs. Keep `max_length` reasonable to prevent hitting Discord's limits.
{% endhint %}

***

#### <mark style="color:orange;">placeholder</mark>

**Type:** String

Hint text shown in the input field before the user types.

**Examples:**

```json
// Generic placeholder
placeholder: "Enter a value..."

// Helpful hints
placeholder: "e.g., Steve123"
placeholder: "EST, PST, GMT+1, etc."
placeholder: "Describe in detail..."
placeholder: "Select one or more options"

// Format examples
placeholder: "Format: DD/MM/YYYY"
placeholder: "Example: 2-3 hours daily"
```

**Best Practices:**

* Provide examples when format matters
* Keep it short (under 50 characters)
* Use "e.g.," or "Example:" for clarity
* Don't repeat the question text

***

#### <mark style="color:orange;">select\_options</mark>

**Type:** Array of Strings

When this array has items, the question becomes a dropdown/select menu instead of a text input.

**Empty Array = Text Input:**

```json
select_options: []  // User types free-form text
```

**With Options = Select Menu:**

```json
select_options: ['Option 1', 'Option 2', 'Option 3']
```

**Examples:**

```json
// Yes/No questions
select_options: ['✅ Yes', '❌ No']
select_options: ['Yes', 'No']

// Age ranges
select_options: ['Under 13', '13-17', '18-24', '25-34', '35+']

// Experience levels
select_options: ['No experience', 'Beginner', 'Intermediate', 'Advanced', 'Expert']

// Time commitment
select_options: ['Less than 5h/week', '5-10h/week', '10-20h/week', '20+h/week']

// Platforms
select_options: ['PC', 'Console', 'Mobile', 'Multiple']

// Hobbies/Interests (multi-select)
select_options: ['Gaming', 'Coding', 'Art', 'Music', 'Sports', 'Reading', 'Other']

// Time zones
select_options: ['EST', 'CST', 'MST', 'PST', 'GMT', 'CET', 'Other']

// Minecraft versions
select_options: ['Java', 'Bedrock', 'Both']
```

{% hint style="info" %}
**Tip:** Use emojis in select options to make them more visually appealing and easier to scan (e.g., `'✅ Yes'`, `'❌ No'`).
{% endhint %}

***

#### <mark style="color:orange;">required</mark>

**Type:** Boolean

Whether the question must be answered to submit the application.

```json
// Must answer this question
required: true

// Optional question
required: false
```

**When to Use Optional Questions:**

* Supplementary information (e.g., "Anything else you'd like to add?")
* Portfolio links (nice to have, not required)
* Social media handles
* Referrals ("Who referred you?")

**Best Practices:**

{% hint style="success" %}

* Keep most questions required for complete applications
* Use 1-2 optional questions at the end for additional context
* Don't make critical questions optional
  {% endhint %}

***

### <mark style="color:yellow;">Question Examples</mark>

```json
// In-game name (text input)
{
    question: "What is your in-game name (IGN)?",
    max_length: 20,
    min_length: 2,
    placeholder: "e.g., Steve123",
    select_options: [],
    required: true
}

// Age range (select menu)
{
    question: "What is your age range?",
    max_length: 1,
    min_length: 1,
    placeholder: "Select your age range",
    select_options: ['13-17', '18-24', '25-34', '35+'],
    required: true
}

// Timezone (select menu)
{
    question: "What is your timezone?",
    max_length: 1,
    min_length: 1,
    placeholder: "Select your timezone",
    select_options: ['EST', 'CST', 'MST', 'PST', 'GMT', 'CET', 'Other'],
    required: true
}

// Timezone (text input for more flexibility)
{
    question: "What is your timezone?",
    max_length: 20,
    min_length: 1,
    placeholder: "e.g., EST, GMT+1, PST",
    select_options: [],
    required: true
}
```

***

### <mark style="color:yellow;">Question Set Example</mark>

#### <mark style="color:orange;">Basic Staff Questions</mark>

Simple question set for general staff positions:

```json
application_questions: {
    "staff_questions": [
        {
            question: "What is your in-game name?",
            max_length: 20,
            min_length: 2,
            placeholder: "Enter your IGN",
            select_options: [],
            required: true
        },
        {
            question: "What is your age range?",
            max_length: 1,
            min_length: 1,
            placeholder: "Select one",
            select_options: ['13-17', '18-24', '25-34', '35+'],
            required: true
        },
        {
            question: "What is your timezone?",
            max_length: 20,
            min_length: 1,
            placeholder: "e.g., EST, PST, GMT+1",
            select_options: [],
            required: true
        },
        {
            question: "How many hours per week can you dedicate?",
            max_length: 1,
            min_length: 1,
            placeholder: "Select one",
            select_options: ['Less than 5h', '5-10h', '10-20h', '20+h'],
            required: true
        },
        {
            question: "Why do you want to join our staff team?",
            max_length: 1000,
            min_length: 100,
            placeholder: "Explain your motivation...",
            select_options: [],
            required: true
        },
        {
            question: "Have you been punished on our server before?",
            max_length: 500,
            min_length: 2,
            placeholder: "Be honest - we can check logs",
            select_options: [],
            required: true
        }
    ]
}
```

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a complete, production-ready application configuration for a server with multiple application types:

```json
{
    config: {
        staff_management_hook: true,
        application_channel_name: "app-%random%",
        default_cooldown: "7d",

        applications: [
            {
                application: "Staff",
                description: "Apply to join our general staff team",
                emoji: "👮",
                category_id: "1160209305593716776",
                questions: "staff_questions",
                permission_list: [
                    "804354019455139900",  // Admin
                ],
                mention_roles: [
                    "804354019455139900",  // Admin
                ]
            },
            {
                application: "Moderator",
                description: "Apply for Moderator position (Experienced)",
                emoji: "🛡️",
                category_id: "1160209305593716776",
                questions: "moderator_questions",
                permission_list: [
                    "804354019455139900",  // Admin
                    "805123456789012345",  // Head Moderator
                ],
                mention_roles: [
                    "805123456789012345",  // Head Moderator
                ]
            },
            {
                application: "Builder",
                description: "Join our creative build team",
                emoji: "🔨",
                category_id: "1160209305593716776",
                questions: "builder_questions",
                permission_list: [
                    "804354019455139900",  // Admin
                    "806234567890123456",  // Build Team Lead
                ],
                mention_roles: [
                    "806234567890123456",  // Build Team Lead
                ]
            },
        ],

        application_questions: {
            "staff_questions": [
                {
                    question: "What is your in-game name?",
                    max_length: 20,
                    min_length: 2,
                    placeholder: "Enter your IGN",
                    select_options: [],
                    required: true,
                },
                {
                    question: "What is your timezone?",
                    max_length: 20,
                    min_length: 1,
                    placeholder: "e.g., EST, PST, GMT+1",
                    select_options: [],
                    required: true
                },
                {
                    question: "How old are you?",
                    max_length: 1,
                    min_length: 1,
                    placeholder: "Select age range",
                    select_options: ['14-18', '18-24', '25-34', '35+'],
                    required: true
                },
                {
                    question: "Do you have a working microphone?",
                    max_length: 1,
                    min_length: 1,
                    placeholder: "Select one",
                    select_options: ['✅ Yes', '❌ No'],
                    required: true
                },
                {
                    question: "Are you able to record videos?",
                    max_length: 1,
                    min_length: 1,
                    placeholder: "Select one",
                    select_options: ['✅ Yes', '❌ No'],
                    required: true
                },
                {
                    question: "What are your favorite hobbies?",
                    max_length: 5,
                    min_length: 1,
                    placeholder: "Select your interests",
                    select_options: ['Gaming', 'Coding', 'Art', 'Music', 'Sports', 'Reading', 'Traveling', 'Cooking', 'Other'],
                    required: true
                },
                {
                    question: "Have you been punished before?",
                    max_length: 800,
                    min_length: 2,
                    placeholder: "Be honest - we can check logs",
                    select_options: [],
                    required: true
                },
            ],

            "moderator_questions": [
                {
                    question: "What is your Discord username?",
                    max_length: 32,
                    min_length: 2,
                    placeholder: "e.g., Username#1234",
                    select_options: [],
                    required: true
                },
                {
                    question: "What is your age range?",
                    max_length: 1,
                    min_length: 1,
                    placeholder: "Select one",
                    select_options: ['16-17', '18-21', '22-25', '26+'],
                    required: true
                },
                {
                    question: "What is your timezone?",
                    max_length: 1,
                    min_length: 1,
                    placeholder: "Select your timezone",
                    select_options: ['EST', 'CST', 'MST', 'PST', 'GMT', 'CET', 'Other'],
                    required: true
                },
                {
                    question: "Do you have a working microphone?",
                    max_length: 1,
                    min_length: 1,
                    placeholder: "Required for voice moderation",
                    select_options: ['✅ Yes', '❌ No'],
                    required: true
                },
                {
                    question: "How would you rate your moderation experience?",
                    max_length: 1,
                    min_length: 1,
                    placeholder: "Be honest",
                    select_options: ['No experience', 'Beginner', 'Intermediate', 'Advanced'],
                    required: true
                },
                {
                    question: "Describe your previous moderation experience",
                    max_length: 1000,
                    min_length: 50,
                    placeholder: "Server names, roles, duration, responsibilities...",
                    select_options: [],
                    required: true
                },
                {
                    question: "How many hours per week can you moderate?",
                    max_length: 1,
                    min_length: 1,
                    placeholder: "Select one",
                    select_options: ['5-10 hours', '10-15 hours', '15-20 hours', '20+ hours'],
                    required: true
                },
                {
                    question: "Why do you want to become a moderator?",
                    max_length: 1500,
                    min_length: 150,
                    placeholder: "Explain your motivation...",
                    select_options: [],
                    required: true
                },
                {
                    question: "How would you handle two members arguing in chat?",
                    max_length: 1000,
                    min_length: 100,
                    placeholder: "Describe your approach step-by-step...",
                    select_options: [],
                    required: true
                },
                {
                    question: "Have you been punished on our server before?",
                    max_length: 800,
                    min_length: 2,
                    placeholder: "Be honest - we can check. Explain if yes.",
                    select_options: [],
                    required: true
                },
            ],

            "builder_questions": [
                {
                    question: "What is your in-game name?",
                    max_length: 20,
                    min_length: 2,
                    placeholder: "Minecraft username",
                    select_options: [],
                    required: true
                },
                {
                    question: "What Minecraft version do you build in?",
                    max_length: 1,
                    min_length: 1,
                    placeholder: "Select one",
                    select_options: ['Java Edition', 'Bedrock Edition', 'Both'],
                    required: true
                },
                {
                    question: "What is your building specialty?",
                    max_length: 3,
                    min_length: 1,
                    placeholder: "Select your strengths",
                    select_options: ['Medieval', 'Modern', 'Fantasy', 'Redstone', 'Terraforming', 'Interiors'],
                    required: true
                },
                {
                    question: "How long have you been building?",
                    max_length: 1,
                    min_length: 1,
                    placeholder: "Select one",
                    select_options: ['Less than 1 year', '1-2 years', '2-5 years', '5+ years'],
                    required: true
                },
                {
                    question: "Describe your building experience",
                    max_length: 1500,
                    min_length: 100,
                    placeholder: "Projects, servers, achievements...",
                    select_options: [],
                    required: true
                },
                {
                    question: "Portfolio links (at least 3 images required)",
                    max_length: 500,
                    min_length: 10,
                    placeholder: "Imgur, Planet Minecraft, etc.",
                    select_options: [],
                    required: true
                },
                {
                    question: "How many hours per week can you build?",
                    max_length: 1,
                    min_length: 1,
                    placeholder: "Select one",
                    select_options: ['5-10 hours', '10-20 hours', '20+ hours'],
                    required: true
                },
                {
                    question: "Why do you want to join our build team?",
                    max_length: 1000,
                    min_length: 100,
                    placeholder: "What excites you?",
                    select_options: [],
                    required: true
                },
            ],
        },
    }
}
```


# Commands

Configure which commands are enabled or disabled across all plugins

## <mark style="color:blue;">Introduction</mark>

The Commands configuration file (`commands.json`) allows you to enable or disable any command across all Athena Bot plugins. This gives you complete control over which features are available in your server.

***

## <mark style="color:blue;">How to Disable Commands</mark>

Each command has a boolean value that determines whether it loads when the bot starts:

```json
config: {
    core: {
        ping: true,      // ✅ Command is enabled
        debug: false,    // ❌ Command is disabled
    }
}
```

**To disable a command:**

1. Set the command to `false` in the configuration file
2. Save the file
3. **Restart the bot** - changes only apply after a full restart

**When a command is disabled (`false`):**

* The command will not load on bot restart
* It will not be available to anyone, including admins
* It will not appear in the `/help` command
* It behaves as if it doesn't exist

{% hint style="warning" %}
**Important:** Changes require a bot restart to take effect. Simply saving the configuration file is not enough.
{% endhint %}

***

## <mark style="color:blue;">Protected Commands</mark>

Two commands cannot be disabled by default and require the **Watermark Addon** to disable:

### <mark style="color:yellow;">botinfo</mark>

The `botinfo` command displays information about Athena Bot (version, credits, uptime, etc.).

**To disable this command:**

1. Purchase the **Watermark Addon**
2. Use the `/claim` command in the Athena Support Discord
3. Set `botinfo: false` in this configuration
4. Restart the bot

Without the Watermark Addon, this command will remain active regardless of the configuration setting.

***

### <mark style="color:yellow;">devstatus</mark>

The `devstatus` command displays the current system status of Iynx Development's services.

**To disable this command:**

1. Purchase the **Watermark Addon**
2. Use the `/claim` command in the Athena Support Discord
3. Set `devstatus: false` in this configuration
4. Restart the bot

Without the Watermark Addon, this command will remain active regardless of the configuration setting.

***


# Core

Core bot configuration including status, cooldowns, and global settings

## <mark style="color:blue;">Introduction</mark>

The Core configuration file (`core.json`) contains essential bot settings that affect the overall behavior of Athena Bot, including bot status, command cooldowns, global placeholders, and various system-wide features.

***

## <mark style="color:blue;">Bot Activity</mark>

### <mark style="color:yellow;">status</mark>

**Type:** String

Sets the bot's online status indicator.

**Available Options:**

* `"online"` - Green status (online)
* `"dnd"` - Red status (Do Not Disturb)
* `"idle"` - Yellow status (idle/away)
* `"offline"` - Gray status (invisible)

```json
status: "online"
```

***

### <mark style="color:yellow;">activity\_type</mark>

**Type:** String

Defines the type of activity displayed in the bot's status.

**Available Options:**

* `"playing"` - Displays as "Playing ..."
* `"watching"` - Displays as "Watching ..."
* `"listening"` - Displays as "Listening to ..."
* `"competing"` - Displays as "Competing in ..."
* `"streaming"` - Displays as "Streaming ..."

```json
activity_type: "playing"
```

***

### <mark style="color:yellow;">activity</mark>

**Type:** Array of Strings

The text displayed in the bot's status. If multiple activities are provided, the bot will randomly cycle through them every 30 seconds.

**Available Placeholders:**

* `%members%` - Total server member count
* `%tickets_open%` - Number of currently open tickets
* `%tickets_closed%` - Number of closed tickets
* `%mc_online%` - Online players on Minecraft server (requires Minecraft addon)
* `%mc_max%` - Maximum players on Minecraft server (requires Minecraft addon)

**Examples:**

```json
// Single activity
activity: ["/help"]

// Multiple activities (rotates every 30 seconds)
activity: ["with %members% members", "/help", "Watching %tickets_open% tickets"]

// Minecraft server status
activity: ["MC: %mc_online%/%mc_max% players"]
```

***

## <mark style="color:blue;">Command Cooldowns</mark>

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables the command cooldown system globally.

```json
cooldown: {
    enabled: true,  // Cooldowns are active
}
```

**When `true`:** Users must wait between command uses\
**When `false`:** All cooldowns are disabled (not recommended)

***

### <mark style="color:yellow;">cooldown\_length</mark>

**Type:** Number (seconds)

The default cooldown duration in seconds that applies to all commands unless a custom cooldown is set.

```json
cooldown_length: 4
```

This means users must wait 4 seconds between using commands (by default).

***

### <mark style="color:yellow;">role\_bypass</mark>

**Type:** Object

Allows specific roles to bypass all command cooldowns.

```json
role_bypass: {
    enabled: true,
    role_id: "804354015638716443",
}
```

**enabled** - Whether role bypass is active\
**role\_id** - Discord role ID that can bypass cooldowns

**How it works:**

* Users with this role (or any role higher in the Discord role hierarchy) can use commands without waiting
* Useful for staff/moderator roles

{% hint style="info" %}
**Tip:** To get a role ID, enable Developer Mode in Discord, right-click the role in Server Settings → Roles, and click "Copy ID".
{% endhint %}

***

### <mark style="color:yellow;">custom\_command\_cooldowns</mark>

**Type:** Object

Allows you to set specific cooldown durations for individual commands, overriding the default cooldown.

```json
custom_command_cooldowns: {
    enabled: true,
    commands: {
        "restart": 60,
        "backup": 300,
        "giveaway": 30,
    },
}
```

**enabled** - Whether custom cooldowns are active\
**commands** - Object mapping command names to cooldown lengths (in seconds)

**Example:**

* `"restart": 60` means the restart command has a 60-second cooldown
* Commands not listed use the default `cooldown_length`

***

## <mark style="color:blue;">Global Placeholders</mark>

**Type:** Array of Objects

Create custom placeholders that can be used throughout all message configurations in any plugin.

```json
global_placeholders: [
    {
        placeholder: '%website%',
        value: 'https://example.com',
    },
    {
        placeholder: '%discord%',
        value: 'https://discord.gg/your-invite',
    },
]
```

**How it works:**

* Define a placeholder name (e.g., `%website%`)
* Set its value (what it should be replaced with)
* Use the placeholder anywhere in embed messages, descriptions, etc.

**Usage Example:**

If you define `%website%` as shown above, you can use it in any message configuration:

```json
description: "Visit our website at %website%"
// Will display as: "Visit our website at https://example.com"
```

{% hint style="success" %}
**Use Case:** Global placeholders are perfect for server-specific information like website URLs, Discord invites, social media links, or server rules that you reference frequently across different messages.
{% endhint %}

***

## <mark style="color:blue;">Permission-Based Help Page</mark>

**Type:** Boolean

When enabled, the `/help` command shows only commands that the user has permission to execute.

```json
permission_based_help_page: false
```

**When `true`:**

* Users see only commands they can use
* Cleaner help menu for regular members
* Staff see all commands they have access to

**When `false`:**

* All users see all commands
* Users may see commands they cannot execute
* More comprehensive overview

{% hint style="info" %}
**Recommendation:** Set to `true` if you want to avoid confusing users with commands they can't access. Set to `false` if you want all users to see the full command list for transparency.
{% endhint %}

***

## <mark style="color:blue;">Commands Blacklisted Channels</mark>

**Type:** Array of Strings

List of channel IDs where **no commands** can be executed

```json
commands_blacklisted_channels: [
    "123456789012345678",
    "234567890123456789",
]
```

**How it works:**

* Commands used in these channels will be ignored
* Useful for keeping certain channels clean

***

## <mark style="color:blue;">Calltime Requirements</mark>

**Type:** Object

Configures requirements for voice channel time to count toward calltime statistics (used in leveling, economy, etc.).

```json
calltime_requirement_users: {
    enabled: true,
    minimum_users: 2,
    bots_included: false,
}
```

### <mark style="color:yellow;">enabled</mark>

Whether calltime requirements are enforced.

**When `true`:** Calltime only counts if requirements are met\
**When `false`:** Calltime always counts regardless of who's in the channel

***

### <mark style="color:yellow;">minimum\_users</mark>

**Type:** Number

Minimum number of users required in a voice channel for calltime to count.

```json
minimum_users: 2
```

**Example:** With `minimum_users: 2`, a user sitting alone in a voice channel won't earn calltime rewards. Once a second person joins, both start earning calltime.

**Purpose:** Prevents users from AFK farming calltime rewards in empty voice channels.

***

### <mark style="color:yellow;">bots\_included</mark>

**Type:** Boolean

Whether bots count toward the minimum user requirement.

```json
bots_included: false
```

**When `false`:** Bots don't count - only real users\
**When `true`:** Bots count toward the minimum

**Example:** If `minimum_users: 2` and `bots_included: false`:

* 1 user + 1 bot = calltime does NOT count
* 2 users + 0 bots = calltime counts
* 2 users + 1 bot = calltime counts

{% hint style="warning" %}
**Recommended:** Keep `bots_included: false` to prevent users from sitting in voice channels with music bots to farm rewards.
{% endhint %}

***

## <mark style="color:blue;">Pastebin API Key</mark>

**Type:** String

API key for Pastebin integration, used by the `/pastebin` command to upload text content.

```json
pastebin_api_key: ""
```

**How to get an API key:**

1. Go to <https://pastebin.com/doc\\_api>
2. Create a Pastebin account (if you don't have one)
3. Generate your API key
4. Paste the key in this configuration

**When configured:**

* The `/pastebin` command can upload content to Pastebin
* Useful for sharing logs, error messages, or large text content

**When left empty:**

* The `/pastebin` command may not function or will have limited functionality

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a complete, production-ready core configuration:

```json
{
    config: {
        activity: {
            status: "online",
            activity_type: "playing",
            activity: ["with %members% members", "/help", "%tickets_open% tickets open"]
        },

        cooldown: {
            enabled: true,
            cooldown_length: 4,

            role_bypass: {
                enabled: true,
                role_id: "804354015638716443",
            },

            custom_command_cooldowns: {
                enabled: true,
                commands: {
                    "restart": 60,
                    "backup": 300,
                    "giveaway": 30,
                },
            },
        },

        global_placeholders: [
            {
                placeholder: '%website%',
                value: 'https://yourserver.com',
            },
            {
                placeholder: '%discord%',
                value: 'https://discord.gg/yourinvite',
            },
            {
                placeholder: '%rules%',
                value: 'https://yourserver.com/rules',
            },
        ],

        permission_based_help_page: true,

        commands_blacklisted_channels: [
            "123456789012345678",  // #announcements
            "234567890123456789",  // #rules
        ],

        calltime_requirement_users: {
            enabled: true,
            minimum_users: 2,
            bots_included: false,
        },

        pastebin_api_key: "your_api_key_here",
    },
}
```


# Fun

Configure fun features including leveling, counting game, starboard, and daily content

## <mark style="color:blue;">Introduction</mark>

The Fun configuration file (`fun.json`) controls entertainment and engagement features including the leveling system, counting game, starboard, birthdays, and daily question/quote systems.

***

## <mark style="color:blue;">Counting Game</mark>

The counting game is a channel activity where users count sequentially (1, 2, 3, etc.). You can configure rules and penalties for mistakes.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables the counting game feature.

```json
enabled: true
```

***

### <mark style="color:yellow;">alternating\_users</mark>

**Type:** Boolean

When enabled, consecutive numbers must be sent by different users.

```json
alternating_users: false
```

**When `true`:**

* User A sends "1"
* User A cannot send "2" (must be a different user)
* User B must send "2"

**When `false`:**

* Any user can send any number in sequence

***

### <mark style="color:yellow;">reset\_on\_failure</mark>

**Type:** Boolean

Whether the counter resets to 0 when someone sends the wrong number.

```json
reset_on_failure: true
```

**When `true`:** Counter resets on mistakes\
**When `false`:** Counter stays at current number

***

### <mark style="color:yellow;">timeout\_user\_on\_failure</mark>

**Type:** Boolean

Whether to timeout users who send the wrong number.

```json
timeout_user_on_failure: true
```

**When `true`:** User is timed out for the duration specified in `timeout_length`\
**When `false`:** No timeout penalty applied

***

### <mark style="color:yellow;">timeout\_length</mark>

**Type:** String

Duration of timeout when a user fails. Only applies if `timeout_user_on_failure` is `true`.

```json
timeout_length: "15m"
```

**Format:** `"15m"`, `"1h"`, `"30s"`, etc.

***

## <mark style="color:blue;">Level System</mark>

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables the entire leveling system.

```json
level_system: {
    enabled: true,
}
```

***

### <mark style="color:yellow;">level\_up</mark>

**Type:** String (Formula)

Formula to calculate XP required to reach the next level.

```json
level_up: "%level% * 5 + 20"
```

**Placeholder:** `%level%` = Current level

**Example Calculations:**

* Level 0 → 1: `0 * 5 + 20 = 20 XP`
* Level 1 → 2: `1 * 5 + 20 = 25 XP`
* Level 5 → 6: `5 * 5 + 20 = 45 XP`

You can use basic math operators: `+`, `-`, `*`, `/`, `()`

***

### <mark style="color:yellow;">XP Gain Settings</mark>

Controls how much XP users earn per action.

#### <mark style="color:orange;">min & max</mark>

**Type:** String (Number)

Random XP range awarded per message or voice activity.

```json
xp_gain: {
    min: "1",
    max: "3",
}
```

Users gain between 1-3 XP randomly with each eligible action.

***

#### <mark style="color:orange;">cooldown\_in\_seconds</mark>

**Type:** Number

Cooldown period between XP gains from messages.

```json
cooldown_in_seconds: 5
```

Users can only gain XP from messages once every 5 seconds (prevents spam).

***

#### <mark style="color:orange;">voice\_support</mark>

**Type:** Boolean

Whether users can gain XP from being in voice channels.

```json
voice_support: false
```

**When `true`:** Users gain XP while in voice channels\
**When `false`:** Only message XP is awarded

{% hint style="info" %}
**Note:** Voice channel requirements (minimum users, etc.) are configured in the Core configuration file under `calltime_requirement_users`.
{% endhint %}

***

#### <mark style="color:orange;">voice\_time\_in\_seconds</mark>

**Type:** Number

How many seconds a user must spend in voice to gain XP.

```json
voice_time_in_seconds: 20
```

Users gain XP (random between min/max) every 20 seconds in voice.

***

### <mark style="color:yellow;">Blacklists</mark>

**Type:** Object

Exclude specific users, channels, or categories from gaining XP.

```json
blacklists: {
    users: ["123456789012345678"],
    channels: ["234567890123456789"],
    categories: ["345678901234567890"],
}
```

**users** - Array of user IDs who cannot gain XP\
**channels** - Array of channel IDs where XP gain is disabled\
**categories** - Array of category IDs where XP gain is disabled

***

### <mark style="color:yellow;">Notification</mark>

**Type:** Object

Configure how level-up notifications are sent.

```json
notification: {
    reply: true,
    channel: false,
}
```

**reply** - When `true`, bot replies to the user's message with level-up notification\
**channel** - When `true`, sends notification to a specific channel (configured elsewhere)

{% hint style="info" %}
**Tip:** Enable `reply: true` for immediate feedback. Use `channel: true` if you want all level-ups posted to a dedicated channel.
{% endhint %}

***

### <mark style="color:yellow;">Role Rewards</mark>

**Type:** Object

Automatically assign roles when users reach specific levels.

#### <mark style="color:orange;">enabled</mark>

**Type:** Boolean

Whether role rewards are active.

```json
role_rewards: {
    enabled: false,
}
```

***

#### <mark style="color:orange;">keep\_all\_roles</mark>

**Type:** Boolean

Determines if users keep all earned roles or only the highest.

```json
keep_all_roles: true
```

**When `true`:** User has all roles they've earned (Level 5 role + Level 10 role)\
**When `false`:** User only has their highest level role (Level 10 role only, Level 5 role removed)

***

#### <mark style="color:orange;">roles</mark>

**Type:** Array of Objects

Define which roles are awarded at which levels.

```json
roles: [
    {
        level: 5,
        role_id: "804354034135597066",
    },
    {
        level: 10,
        role_id: "804354033338286130",
    },
    {
        level: 25,
        role_id: "123456789012345678",
    },
]
```

**level** - Level required to earn the role\
**role\_id** - Discord role ID to assign

***

## <mark style="color:blue;">Starboard</mark>

The starboard feature reposts popular messages to a dedicated channel when they receive enough reactions.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables the starboard feature.

```json
starboard: {
    enabled: false,
}
```

***

### <mark style="color:yellow;">emoji</mark>

**Type:** String

The emoji users must react with to add messages to the starboard.

```json
emoji: "⭐"
```

Can be any Unicode emoji or custom emoji ID.

***

### <mark style="color:yellow;">reactions</mark>

**Type:** Number

Number of reactions required before a message is added to the starboard.

```json
reactions: 10
```

Once a message receives 10 ⭐ reactions, it's posted to the starboard channel.

***

### <mark style="color:yellow;">whitelisted\_channels</mark>

**Type:** Array of Strings

List of channel IDs where starboard is active. Leave empty to allow all channels.

```json
whitelisted_channels: []
```

***

### <mark style="color:yellow;">whitelisted\_categories</mark>

**Type:** Array of Strings

List of category IDs where starboard is active.

```json
whitelisted_categories: ["804354056575254558"]
```

Only messages in channels within these categories can be starred.

{% hint style="info" %}
**Note:** If both `whitelisted_channels` and `whitelisted_categories` are empty, starboard works in all channels. Use these to limit starboard to specific areas of your server.
{% endhint %}

***

## <mark style="color:blue;">Birthday</mark>

### <mark style="color:yellow;">birthday\_set\_cooldown</mark>

**Type:** String

Cooldown period for setting or changing a birthday.

```json
birthday_set_cooldown: "1y"
```

**Format:** `"1y"` (1 year), `"6m"` (6 months), etc.

{% hint style="warning" %}
**Recommendation:** Keep this at `"1y"` to prevent abuse. Users should only be able to set their birthday once per year.
{% endhint %}

***

### <mark style="color:yellow;">channel\_notification</mark>

**Type:** Boolean

Whether to send birthday notifications to a specific channel.

```json
channel_notification: true
```

**When `true`:** Bot posts birthday messages to the configured birthday channel\
**When `false`:** No automatic birthday messages

***

### <mark style="color:yellow;">special\_role</mark>

**Type:** Object

Assign a special role to users on their birthday.

```json
special_role: {
    enabled: false,
    role_id: "804354034135597066",
}
```

**enabled** - Whether birthday role is active\
**role\_id** - Role to assign on user's birthday

The role is automatically removed at the end of their birthday (24 hours).

***

## <mark style="color:blue;">Quote of the Day</mark>

Automatically post inspirational quotes at scheduled times.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables the quote of the day feature.

```json
quote_of_the_day: {
    enabled: true,
}
```

***

### <mark style="color:yellow;">weekly</mark>

**Type:** Object

Schedule when quotes are posted for each day of the week.

```json
weekly: {
    monday: ["12:00", "18:00"],
    tuesday: ["14:22"],
    wednesday: ["14:00"],
    thursday: ["10:00"],
    friday: ["12:00"],
    saturday: ["20:00"],
    sunday: [],
}
```

**Format:** 24-hour time (`"HH:MM"`)\
**Timezone:** UTC\
**Multiple times:** Add multiple times per day as array elements\
**No quotes:** Use empty array `[]` for days without quotes

{% hint style="warning" %}
**Important:** Use `"0:00"` for midnight, not `"24:00"`. Time is based on your set timezone.
{% endhint %}

***

### <mark style="color:yellow;">mention\_roles</mark>

**Type:** Array of Strings

List of role IDs to mention when a quote is posted.

```json
mention_roles: []
```

Leave empty for no mentions, or add role IDs to ping specific roles.

***

### <mark style="color:yellow;">create\_thread</mark>

**Type:** Boolean

Whether to create a discussion thread for each quote.

```json
create_thread: true
```

**When `true`:** A thread is created where users can discuss the quote\
**When `false`:** Quote is posted without a thread

***

## <mark style="color:blue;">Question of the Day</mark>

Post daily questions to engage your community.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables the question of the day feature.

```json
question_of_the_day: {
    enabled: false,
}
```

***

### <mark style="color:yellow;">weekly</mark>

**Type:** Object

Schedule when questions are posted for each day of the week.

```json
weekly: {
    monday: ["12:00", "18:00"],
    tuesday: ["16:00"],
    wednesday: ["14:00"],
    thursday: ["10:00"],
    friday: ["12:00"],
    saturday: ["20:00"],
    sunday: [],
}
```

Same format as quote of the day. Time is based on your set timezone.

***

### <mark style="color:yellow;">mention\_roles</mark>

**Type:** Array of Strings

List of role IDs to mention when a question is posted.

```json
mention_roles: ['804354037662220289']
```

***

### <mark style="color:yellow;">create\_thread</mark>

**Type:** Boolean

Whether to create a discussion thread for each question.

```json
create_thread: true
```

***

### <mark style="color:yellow;">dataset</mark>

**Type:** Array of Strings

List of questions to randomly choose from when posting.

```json
dataset: [
    "What is your favorite color?",
    "What is your favorite food?",
    "What is your dream vacation destination?",
    "If you could have any superpower, what would it be?",
]
```

The bot randomly selects one question from this list for each scheduled post. Add as many questions as you like.

***

## <mark style="color:blue;">Activity Check</mark>

### <mark style="color:yellow;">activity\_check\_disable\_mention</mark>

**Type:** Boolean

When the activity check command is used, this controls whether the targeted user is mentioned.

```json
activity_check_disable_mention: false
```

**When `true`:** User is not mentioned in the activity check message\
**When `false`:** User is mentioned (@username) in the activity check

***

## <mark style="color:blue;">Customized Dick Size</mark>

The `/dicksize` command generates random sizes, but you can set custom values for specific users.

### <mark style="color:yellow;">customized\_dicksize</mark>

**Type:** Array of Objects

List of users with custom dick sizes.

```json
customized_dicksize: [
    {
        user_id: "707336356786864211",
        size: 7.2,
    },
    {
        user_id: "123456789012345678",
        size: 12.5,
    },
]
```

**user\_id** - Discord user ID\
**size** - Custom size value (number)

When these users use the `/dicksize` command, they'll always get their configured value instead of a random one.

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a complete, production-ready fun configuration:

```json
{
    config: {
        counting_game: {
            enabled: true,
            alternating_users: true,
            reset_on_failure: true,
            timeout_user_on_failure: true,
            timeout_length: "15m",
        },

        level_system: {
            enabled: true,
            level_up: "%level% * 5 + 20",
            xp_gain: {
                min: "1",
                max: "3",
                cooldown_in_seconds: 5,
                voice_support: true,
                voice_time_in_seconds: 20,
            },
            blacklists: {
                users: [],
                channels: [],
                categories: [],
            },
            notification: {
                reply: true,
                channel: false,
            },
            role_rewards: {
                enabled: true,
                keep_all_roles: true,
                roles: [
                    {
                        level: 5,
                        role_id: "804354034135597066",
                    },
                    {
                        level: 10,
                        role_id: "804354033338286130",
                    },
                ]
            }
        },

        starboard: {
            enabled: true,
            emoji: "⭐",
            reactions: 10,
            whitelisted_channels: [],
            whitelisted_categories: ["804354056575254558"],
        },

        birthday: {
            birthday_set_cooldown: "1y",
            channel_notification: true,
            special_role: {
                enabled: true,
                role_id: "804354034135597066",
            },
        },

        quote_of_the_day: {
            enabled: true,
            weekly: {
                monday: ["12:00"],
                tuesday: ["12:00"],
                wednesday: ["12:00"],
                thursday: ["12:00"],
                friday: ["12:00"],
                saturday: [],
                sunday: [],
            },
            mention_roles: [],
            create_thread: true,
        },

        question_of_the_day: {
            enabled: true,
            weekly: {
                monday: ["18:00"],
                tuesday: ["18:00"],
                wednesday: ["18:00"],
                thursday: ["18:00"],
                friday: ["18:00"],
                saturday: [],
                sunday: [],
            },
            mention_roles: [],
            create_thread: true,
            dataset: [
                "What is your favorite color?",
                "What is your favorite food?",
                "What is your favorite movie?",
                "What is your dream vacation destination?",
                "If you could have any superpower, what would it be?",
            ],
        },

        activity_check_disable_mention: false,

        customized_dicksize: []
    },
}
```


# Invites

Configure invite tracking and role rewards for inviting members

## <mark style="color:blue;">Introduction</mark>

The Invites configuration file (`invites.json`) controls the invite tracking system and role rewards for users who invite members to your server.

***

## <mark style="color:blue;">Role Rewards</mark>

Automatically assign roles to users based on how many members they've successfully invited to the server.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables invite role rewards.

```json
role_rewards: {
    enabled: false,
}
```

**When `true`:** Users receive roles when they reach invite milestones\
**When `false`:** Invite tracking still works, but no roles are automatically assigned

***

### <mark style="color:yellow;">keep\_all\_roles</mark>

**Type:** Boolean

Determines whether users keep all earned invite roles or only the highest one.

```json
keep_all_roles: true
```

**When `true`:**

* User with 5 invites gets the 5-invite role
* When they reach 10 invites, they keep the 5-invite role AND get the 10-invite role
* Users accumulate all milestone roles

**When `false`:**

* User with 5 invites gets the 5-invite role
* When they reach 10 invites, the 5-invite role is removed and replaced with the 10-invite role
* Users only have their highest milestone role

***

### <mark style="color:yellow;">roles</mark>

**Type:** Array of Objects

Define which roles are awarded at which invite counts.

```json
roles: [
    {
        invites: 5,
        role_id: "804354034135597066",
    },
    {
        invites: 10,
        role_id: "804354033338286130",
    },
    {
        invites: 25,
        role_id: "123456789012345678",
    },
    {
        invites: 50,
        role_id: "234567890123456789",
    },
]
```

**invites** - Number of successful invites required to earn the role\
**role\_id** - Discord role ID to assign

{% hint style="info" %}
**Note:** Only successful invites count - if an invited member leaves the server, the invite count may be adjusted based on your server's invite tracking settings.
{% endhint %}

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a complete invite rewards configuration:

```json
{
    config: {
        role_rewards: {
            enabled: true,
            keep_all_roles: true,
            roles: [
                {
                    invites: 5,
                    role_id: "804354034135597066",
                },
                {
                    invites: 10,
                    role_id: "804354033338286130",
                },
                {
                    invites: 25,
                    role_id: "123456789012345678",
                },
                {
                    invites: 50,
                    role_id: "234567890123456789",
                },
                {
                    invites: 100,
                    role_id: "345678901234567890",
                },
            ]
        }
    },
}
```


# Join to Create

Configure temporary voice channels that users can create on demand

## <mark style="color:blue;">Introduction</mark>

The Join to Create configuration file (`join_to_create.json`) allows you to set up voice channels that automatically create temporary, user-owned voice channels when joined. These temporary channels are deleted when empty.

***

## <mark style="color:blue;">Temporary Channels</mark>

**Type:** Array of Objects

Define which voice channels act as "join to create" triggers and where the temporary channels are created.

```json
temporary_channels: [
    {
        voice_channel_id: "804354081711849492",
        category_id: "1196838574943907850",
        settings_id: "settings_1",
    },
]
```

### <mark style="color:yellow;">voice\_channel\_id</mark>

**Type:** String

The ID of the voice channel that users join to create their temporary channel.

```json
voice_channel_id: "804354081711849492"
```

When a user joins this channel, they are immediately moved to a new temporary channel created specifically for them.

***

### <mark style="color:yellow;">category\_id</mark>

**Type:** String

The Discord category ID where temporary voice channels will be created.

```json
category_id: "1196838574943907850"
```

All temporary channels created from this join-to-create channel will appear in this category.

***

### <mark style="color:yellow;">settings\_id</mark>

**Type:** String

The ID of the settings configuration to apply to temporary channels. This references a settings object defined in the `settings` section below.

```json
settings_id: "settings_1"
```

This allows you to have different configurations for different join-to-create channels.

***

## <mark style="color:blue;">Settings</mark>

**Type:** Object

Define different configuration sets for temporary voice channels. You can create multiple setting sets and reference them by ID.

```json
settings: {
    "settings_1": {
        channel_name: "%user%'s call",
        user_limit: 4,
        locked: false,
        hidden: false,
        base_permission_role: "804354037662220289",
        blacklisted_roles: [],
    },
    "settings_2": {
        // Different configuration...
    },
}
```

***

### <mark style="color:yellow;">channel\_name</mark>

**Type:** String

The name format for created temporary voice channels.

```json
channel_name: "%user%'s call"
```

**Available Placeholder:**

* `%user%` - Username of the channel creator

**Examples:**

* `"%user%'s call"` → `"JohnDoe's call"`
* `"%user%'s Channel"` → `"JohnDoe's Channel"`
* `"Temp VC - %user%"` → `"Temp VC - JohnDoe"`

***

### <mark style="color:yellow;">user\_limit</mark>

**Type:** Number (0-99)

Maximum number of users allowed in the temporary voice channel.

```json
user_limit: 4
```

**Values:**

* `0` - No limit (unlimited users)
* `1-99` - Specific user limit

The channel creator can change this limit later using the `/tempvoice` command.

***

### <mark style="color:yellow;">locked</mark>

**Type:** Boolean

Whether the temporary channel is locked by default (only the owner can join).

```json
locked: false
```

**When `true`:**

* Only the channel owner can join initially
* Owner must manually allow others to join
* Useful for private channels

**When `false`:**

* Anyone with permissions can join
* More open for public use

The channel creator can toggle this later using the `/tempvoice` command.

***

### <mark style="color:yellow;">hidden</mark>

**Type:** Boolean

Whether the temporary channel is hidden by default (only the owner can see it).

```json
hidden: false
```

**When `true`:**

* Only the channel owner can see the channel
* Completely private until owner makes it visible
* Useful for private discussions

**When `false`:**

* Channel is visible to users with the base permission role
* More discoverable

The channel creator can toggle this later using the `/tempvoice` command.

***

### <mark style="color:yellow;">base\_permission\_role</mark>

**Type:** String

The role ID that determines who can see and join temporary channels by default.

```json
base_permission_role: "804354037662220289"
```

**How it works:**

* Users with this role (or higher in the role hierarchy) can see and join the channel
* Commonly set to a "Member" or "Verified" role to prevent unverified users from accessing

{% hint style="info" %}
**Tip:** If your server has a verification system, set this to your verified member role to prevent unverified users from using temporary channels.
{% endhint %}

***

### <mark style="color:yellow;">blacklisted\_roles</mark>

**Type:** Array of Strings

List of role IDs that are not allowed to join temporary voice channels by default.

```json
blacklisted_roles: [
    "123456789012345678",
    "234567890123456789",
]
```

Users with these roles cannot join temporary channels unless explicitly granted access by the channel owner.

**Common use cases:**

* Muted roles
* Banned from voice roles
* Restricted roles

***

## <mark style="color:blue;">Multiple Configurations Example</mark>

You can create different join-to-create channels with different settings:

```json
{
    config: {
        temporary_channels: [
            {
                // Public temporary channels
                voice_channel_id: "804354081711849492",
                category_id: "1196838574943907850",
                settings_id: "public_settings",
            },
            {
                // Private temporary channels
                voice_channel_id: "123456789012345678",
                category_id: "234567890123456789",
                settings_id: "private_settings",
            },
            {
                // Gaming temporary channels
                voice_channel_id: "345678901234567890",
                category_id: "456789012345678901",
                settings_id: "gaming_settings",
            },
        ],

        settings: {
            "public_settings": {
                channel_name: "%user%'s Channel",
                user_limit: 0,
                locked: false,
                hidden: false,
                base_permission_role: "804354037662220289",
                blacklisted_roles: [],
            },
            "private_settings": {
                channel_name: "%user%'s Private Room",
                user_limit: 5,
                locked: true,
                hidden: true,
                base_permission_role: "804354037662220289",
                blacklisted_roles: [],
            },
            "gaming_settings": {
                channel_name: "%user%'s Gaming Session",
                user_limit: 10,
                locked: false,
                hidden: false,
                base_permission_role: "804354037662220289",
                blacklisted_roles: ["123456789012345678"],
            },
        }
    }
}
```

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a simple, production-ready configuration:

```json
{
    config: {
        temporary_channels: [
            {
                voice_channel_id: "804354081711849492",
                category_id: "1196838574943907850",
                settings_id: "settings_1",
            },
        ],

        settings: {
            "settings_1": {
                channel_name: "%user%'s call",
                user_limit: 4,
                locked: false,
                hidden: false,
                base_permission_role: "804354037662220289",
                blacklisted_roles: [],
            },
        }
    }
}
```

{% hint style="success" %}
**How it works:**

1. User joins the voice channel specified in `voice_channel_id`
2. Bot creates a new temporary channel in the specified `category_id`
3. User is moved to their new temporary channel
4. User becomes the owner and can manage the channel with `/tempvoice`
5. When all users leave, the channel is automatically deleted
   {% endhint %}


# Lang

Customize bot messages, embeds, and language strings

## <mark style="color:blue;">Introduction</mark>

The Language configuration file (`lang.json`) contains all messages, embeds, and text strings used by Athena Bot. This file allows you to customize every message the bot sends, translate the bot to other languages, or adjust wording to match your server's style.

***

## <mark style="color:blue;">File Structure</mark>

The language file is organized into several main sections:

```json
{
    lang: {
        // Simple text strings
        unexpected_command_error: "...",
        no_reason_provided: "...",
    },
    embeds: {
        // Embed configurations
        help_default: { ... },
        ping: { ... },
    },
    warnings: {
        // Warning/error messages
        no_permission: "...",
    },
    interaction_names: {
        // Command and option names
    }
}
```

***

## <mark style="color:blue;">Available Placeholders</mark>

### <mark style="color:yellow;">Finding Placeholders</mark>

Each embed and message configuration lists its available placeholders in a comment above it:

```json
// Placeholder: %bot_latency%, %ws_latency%, %api_latency%, %request%
ping: {
    description: "Bot latency: %bot_latency%ms",
}
```

The comment shows which placeholders you can use for that specific message.

***

### <mark style="color:yellow;">Global Placeholders</mark>

These placeholders work in **all** embed configurations throughout the file:

```
%custom_emoji_<number>%     - Custom emojis (e.g., %custom_emoji_28%)
%user%                      - Username
%user_display%              - Display name
%user_id%                   - User ID
%user_mention%              - User mention (@user)
%user_icon%                 - User avatar URL
%user_created%              - Account creation date
%user_created_formatted%    - Formatted creation date
%user_joined%               - Server join date
%user_joined_formatted%     - Formatted join date
%guild%                     - Server name
%guild_id%                  - Server ID
%guild_icon%                - Server icon URL
%random_int_<max_number>%   - Random integer (e.g., %random_int_100%)
%random_string_<length>%    - Random string (e.g., %random_string_8%)
%current_date%              - Current date (YYYY-MM-DD)
%current_time%              - Current time (HH:mm)
%current_time_seconds%      - Current time (HH:mm:ss)
%current_datetime%          - Date and time (YYYY-MM-DD HH:mm)
%current_iso%               - ISO format date (2025-06-02T00:00:00Z)
%bot_user%                  - Bot username
%bot_user_id%               - Bot user ID
%bot_user_mention%          - Bot mention
%bot_user_icon%             - Bot avatar URL
```

{% hint style="info" %}
**Note:** Global placeholders can be used in any message or embed. Specific placeholders (listed above each configuration) only work in their designated messages.
{% endhint %}

***

## <mark style="color:blue;">Configuring Embeds</mark>

### <mark style="color:yellow;">Basic Embed Structure</mark>

Embeds under the `embeds` section support the full Discord embed JSON format. Here's how to configure an embed:

```json
// Placeholder: %bot_latency%, %ws_latency%, %api_latency%, %request%
ping: {
    title: "🏓 Pong!",
    description: "Bot Latency: **%bot_latency%ms**\nWebSocket: **%ws_latency%ms**\nAPI: **%api_latency%ms**",
    color: "#00FF00",
    thumbnail: {
        url: "%bot_user_icon%"
    },
    footer: {
        text: "%guild% - Requested by %user%",
        iconURL: "%guild_icon%"
    },
    defaultTimestamp: true,
}
```

***

### <mark style="color:yellow;">Available Embed Properties</mark>

You can use any Discord embed property in JSON format:

**Basic Properties:**

* `title` - Embed title
* `description` - Main embed text
* `color` - Hex color code (e.g., `"#FF0000"`) or decimal number
* `url` - URL when clicking the title

**Image & Thumbnail:**

* `thumbnail: { url: "..." }` - Small image in top-right
* `image: { url: "..." }` - Large image at bottom

**Author:**

```json
author: {
    name: "Author Name",
    iconURL: "https://...",
    url: "https://..."
}
```

**Footer:**

```json
footer: {
    text: "Footer text",
    iconURL: "https://..."
}
```

**Fields:**

```json
fields: [
    {
        name: "Field Title",
        value: "Field content",
        inline: true
    },
    {
        name: "Another Field",
        value: "More content",
        inline: false
    }
]
```

**Special Properties:**

* `defaultTimestamp: true` - Adds current timestamp to embed
* `guildIcon: true` - Uses server icon in footer

***

### <mark style="color:yellow;">Example: Customizing the Help Embed</mark>

Here's an example of customizing the help command embed:

```json
help_default: {
    title: "📚 %guild% - Command Help",
    description: "Welcome to the help menu, %user%!\n\nUse the buttons below to navigate through different command categories.\n\n**Your Highest Role:** %highest_role%",
    color: "#5865F2",
    thumbnail: {
        url: "%guild_icon%"
    },
    footer: {
        text: "Requested by %user%",
        iconURL: "%user_icon%"
    },
    defaultTimestamp: true,
}
```

***

## <mark style="color:blue;">Simple Text Strings</mark>

Not all messages use embeds. Simple text strings are configured under the `lang` section:

```json
lang: {
    unexpected_command_error: "An **error** occurred while executing __command__ ``%command%``",
    no_reason_provided: "No reason provided",
    modal_placeholder: "Enter a value...",
    left_guild: "User left guild",
}
```

These are plain text strings (with optional Discord markdown formatting) that can include placeholders where specified.

***

## <mark style="color:blue;">Warning Messages</mark>

The `warnings` section contains error and warning messages:

```json
warnings: {
    no_permission: "%user%, you **don't have** __permission__ to use this ``command``",
    cooldown: "%user%, please **wait** ``%time%`` before using this ``command`` again",
}
```

These follow the same format as simple text strings but are used for errors and warnings.

***

## <mark style="color:blue;">Best Practices</mark>

{% hint style="success" %}
**Customization Tips:**

1. **Test changes** - Edit one message at a time and test before making more changes
2. **Keep placeholders** - Don't remove placeholders unless you're sure they're not needed
3. **Maintain formatting** - Keep Discord markdown (`**bold**`, `__underline__`, `` `code` ``) for consistency
4. **Use global placeholders** - Add server branding with `%guild%`, `%guild_icon%`, etc.
5. **Check syntax** - Invalid JSON will cause the bot to fail loading the config
6. **Backup first** - Save a copy of the original file before making changes
   {% endhint %}

{% hint style="warning" %}
**Common Mistakes:**

* Removing required placeholders (e.g., removing `%user%` from a user-specific message)
* Invalid JSON syntax (missing commas, quotes, brackets)
* Using placeholders that don't exist for that message
* Breaking Discord's embed character limits (title: 256, description: 4096, field value: 1024)
  {% endhint %}

***

## <mark style="color:blue;">Example: Complete Custom Embed</mark>

Here's a fully customized embed using multiple properties:

```json
server: {
    title: "📊 Server Information",
    description: "**%guild%** Statistics",
    color: "#5865F2",
    thumbnail: {
        url: "%guild_icon%"
    },
    fields: [
        {
            name: "👥 Members",
            value: "Total: **%members%**\nOnline: **%online%**\nBots: **%bots%**",
            inline: true
        },
        {
            name: "📝 Channels",
            value: "Text: **%text_channels%**\nVoice: **%voice_channels%**\nCategories: **%categories%**",
            inline: true
        },
        {
            name: "🎭 Roles",
            value: "Total: **%roles%**",
            inline: true
        },
        {
            name: "👑 Owner",
            value: "%owner%",
            inline: true
        },
        {
            name: "📅 Created",
            value: "%created%",
            inline: true
        },
        {
            name: "🚀 Boosts",
            value: "Level **%boosts%**",
            inline: true
        }
    ],
    footer: {
        text: "Server ID: %guild_id%",
        iconURL: "%guild_icon%"
    },
    defaultTimestamp: true,
}
```

This creates a rich, informative embed with organized fields, custom colors, and relevant server information.


# Management

Configure server management features including logs, welcome messages, and automation

## <mark style="color:blue;">Introduction</mark>

The Management configuration file (`management.json`) controls various server management features including logging, welcome/goodbye messages, auto-roles, auto-responses, suggestions, and other automation features.

***

## <mark style="color:blue;">Logs</mark>

The logging system records various server events to designated channels.

### <mark style="color:yellow;">types</mark>

**Type:** Object

Enable or disable specific log types. Each log type can be toggled individually.

```json
logs: {
    types: {
        channel_create: true,
        channel_delete: true,
        channel_update: true,
        emoji_create: true,
        emoji_delete: true,
        emoji_update: true,
        member_join: true,
        member_leave: true,
        member_update: true,
        member_roles_update: true,
        invite_create: true,
        invite_delete: true,
        invite_update: true,
        message_delete: true,
        message_update: true,
        role_create: true,
        role_delete: true,
        role_update: true,
        sticker_create: true,
        sticker_delete: true,
        sticker_update: true,
        thread_create: true,
        thread_delete: true,
        voice_state: true,
        command_execute: true,
        direct_message: true,
    },
}
```

Set any log type to `false` to disable that specific log.

***

### <mark style="color:yellow;">exclude\_message\_logs</mark>

**Type:** Array of Strings

List of channel IDs to exclude from message edit/delete logging.

```json
exclude_message_logs: [
    "123456789012345678",
    "234567890123456789",
]
```

Messages edited or deleted in these channels won't create log entries.

***

### <mark style="color:yellow;">exclude\_channel\_edit\_logs</mark>

**Type:** Array of Strings

List of channel IDs to exclude from channel edit logging.

```json
exclude_channel_edit_logs: []
```

***

## <mark style="color:blue;">Welcome Message</mark>

Configure automated welcome messages for new members.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables the welcome message feature.

```json
welcome_message: {
    enabled: true,
}
```

***

### <mark style="color:yellow;">display\_type</mark>

**Type:** String

Type of welcome message to send.

**Available Options:**

* `"IMAGE"` - Welcome card/image
* `"EMBED"` - Text embed (configured in lang.json)
* `"BOTH"` - Both image and embed

```json
display_type: "IMAGE"
```

***

### <mark style="color:yellow;">image</mark>

**Type:** Object

Configuration for the welcome image. Only applies when `display_type` is `"IMAGE"` or `"BOTH"`.

```json
image: {
    title: "Welcome %user%",
    description_text: "Member #%member_size%",
}
```

**Available Placeholders:**

* `%user%` - Username
* `%member_size%` - Total member count
* `%user_created%` - Account creation date
* `%user_joined%` - Server join date
* `%invited_by%` - Who invited them
* `%invites_by_invitor%` - Inviter's invite count

{% hint style="info" %}
**Custom Images:** To change the welcome background image, upload new images to `./logs/images/welcome/` directory.
{% endhint %}

***

### <mark style="color:yellow;">mention\_user</mark>

**Type:** Boolean

Whether to mention the user in their welcome message.

```json
mention_user: true
```

***

### <mark style="color:yellow;">emoji</mark>

**Type:** Object

Auto-react to welcome messages with an emoji.

```json
emoji: {
    enabled: false,
    emoji: "👋",
}
```

**enabled** - Whether emoji reactions are active\
**emoji** - Emoji to react with (Unicode or custom emoji ID)

***

### <mark style="color:yellow;">send\_after\_verification</mark>

**Type:** Boolean

Whether to wait until the user verifies before sending the welcome message.

```json
send_after_verification: false
```

**When `true`:** Welcome message only sent after verification\
**When `false`:** Welcome message sent immediately on join

***

### <mark style="color:yellow;">dm\_message</mark>

**Type:** Boolean

Whether to send an additional welcome message to the user's DMs.

```json
dm_message: false
```

DM message content is configured in the lang.json file.

***

## <mark style="color:blue;">Goodbye Message</mark>

Configure automated goodbye messages when members leave.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables the goodbye message feature.

```json
goodbye_message: {
    enabled: false,
}
```

***

### <mark style="color:yellow;">display\_type</mark>

**Type:** String

Type of goodbye message to send.

**Available Options:**

* `"IMAGE"` - Goodbye card/image
* `"EMBED"` - Text embed (configured in lang.json)
* `"BOTH"` - Both image and embed

```json
display_type: "IMAGE"
```

***

### <mark style="color:yellow;">image</mark>

**Type:** Object

Configuration for the goodbye image.

```json
image: {
    title: "Goodbye %user%",
    description_text: "Member #%member_size%",
}
```

**Available Placeholders:**

* `%user%` - Username
* `%member_size%` - Total member count

{% hint style="info" %}
**Custom Images:** To change the goodbye background image, upload new images to `./logs/images/goodbye/` directory.
{% endhint %}

***

### <mark style="color:yellow;">emoji</mark>

**Type:** Object

Auto-react to goodbye messages with an emoji.

```json
emoji: {
    enabled: false,
    emoji: "👋",
}
```

***

## <mark style="color:blue;">Auto Role</mark>

Automatically assign roles to new members when they join.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables auto-role assignment.

```json
auto_role: {
    enabled: false,
}
```

***

### <mark style="color:yellow;">roles\_to\_add</mark>

**Type:** Array of Strings

List of role IDs to automatically assign to new members.

```json
roles_to_add: ['804354038987882588', '123456789012345678']
```

Common use cases:

* Member role (if verification is disabled)
* Unverified role (if verification is enabled)
* Notification roles

***

## <mark style="color:blue;">Auto Thread Reaction</mark>

Automatically react to new threads in forum channels.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables auto thread reactions.

```json
auto_thread_reaction: {
    enabled: false,
}
```

***

### <mark style="color:yellow;">parent\_id</mark>

**Type:** String

Forum channel ID where this feature applies.

```json
parent_id: "1155463362377961615"
```

***

### <mark style="color:yellow;">emojis</mark>

**Type:** Array of Strings

List of emojis to react with on new threads.

```json
emojis: ["✅", "❌"]
```

Supports both Unicode emojis and custom emoji IDs.

***

## <mark style="color:blue;">Auto Message Response</mark>

Automatically respond to messages containing specific keywords/patterns.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables auto-response system.

```json
auto_message_response: {
    enabled: false,
}
```

***

### <mark style="color:yellow;">keywords</mark>

**Type:** Array of Objects

List of keyword patterns and their responses.

```json
keywords: [
    {
        regex: "ip|server address",
        predefined_message_id: "server_ip",
        auto_delete_after_seconds: 20,
        permission_role: "everyone",
        ticket_only: false,
    },
]
```

**regex** - Regular expression pattern to match (e.g., `"store"`, `"ip|server"`)\
**predefined\_message\_id** - ID of message created with `/sendmsg` command\
**auto\_delete\_after\_seconds** - Auto-delete response after X seconds, or `false` to keep permanently\
**permission\_role** - Permission level required (from permission config)\
**ticket\_only** - Whether response only triggers in ticket channels

{% hint style="info" %}
**Creating Responses:**

1. Use `/sendmsg` to create a custom message
2. Save it with a predefined message ID
3. Reference that ID in `predefined_message_id`
   {% endhint %}

***

## <mark style="color:blue;">Auto Crosspost</mark>

Automatically publish messages in announcement channels.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables auto-crossposting.

```json
auto_crosspost: {
    enabled: false,
}
```

***

### <mark style="color:yellow;">channel\_ids</mark>

**Type:** Array of Strings

List of announcement channel IDs to auto-publish.

```json
channel_ids: ["123456789012345678"]
```

**When empty:** All announcement channels are affected\
**When populated:** Only specified channels are affected

***

## <mark style="color:blue;">Scheduled Messages</mark>

Send predefined messages at scheduled times.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables scheduled messages.

```json
scheduled_messages: {
    enabled: false,
}
```

***

### <mark style="color:yellow;">messages</mark>

**Type:** Array of Objects

List of scheduled messages to send.

```json
messages: [
    {
        channel_id: "1266773588619427840",
        predefined_message_id: "daily_announcement",
        weekly: {
            monday: ["12:00", "18:00"],
            tuesday: ["14:22"],
            wednesday: ["14:00"],
            thursday: ["10:00"],
            friday: ["12:00"],
            saturday: ["20:00"],
            sunday: [],
        },
    },
]
```

**channel\_id** - Channel where message is sent\
**predefined\_message\_id** - ID of message created with `/sendmsg`\
**weekly** - Schedule with 24-hour time format in UTC timezone

{% hint style="warning" %}
**Important:** Use `"0:00"` for midnight, not `"24:00"`. Times are in your set timezone.
{% endhint %}

***

## <mark style="color:blue;">Suggestions</mark>

Configure the suggestion system behavior.

### <mark style="color:yellow;">disable\_suggestion\_threads</mark>

**Type:** Boolean

Whether to disable automatic thread creation for suggestions.

```json
suggestions: {
    disable_suggestion_threads: false,
}
```

***

### <mark style="color:yellow;">seperate\_suggestion\_channels</mark>

**Type:** Boolean

Move approved/denied suggestions to separate channels.

```json
seperate_suggestion_channels: false
```

**When `true`:** Approved/denied suggestions move to dedicated channels\
**When `false`:** All suggestions stay in the pending channel

***

### <mark style="color:yellow;">allow\_message\_suggestions</mark>

**Type:** Boolean

Allow users to submit suggestions by simply typing in the suggestion channel.

```json
allow_message_suggestions: false
```

**When `true`:** Messages in suggestion channel create suggestions\
**When `false`:** Must use `/suggest` command

***

### <mark style="color:yellow;">category\_based\_colors</mark>

**Type:** Boolean

Use different colors for suggestion embeds based on category.

```json
category_based_colors: false
```

Requires `suggestion_categories` to be configured.

***

### <mark style="color:yellow;">suggestion\_categories</mark>

**Type:** Array of Objects

Define suggestion categories with custom colors.

```json
suggestion_categories: [
    {
        name: "General",
        color: "#3498DB",
    },
    {
        name: "Discord",
        color: "#E74C3C",
    },
]
```

**name** - Category name\
**color** - Hex color code (leave empty for default)

***

## <mark style="color:blue;">Role Saving</mark>

Save and restore user roles when they leave and rejoin.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables role saving.

```json
role_saving: {
    enabled: false,
}
```

***

### <mark style="color:yellow;">bypass\_auto\_roles</mark>

**Type:** Boolean

Whether to skip auto-roles if saved roles exist.

```json
bypass_auto_roles: false
```

**When `true`:** Auto-roles won't apply if user has saved roles\
**When `false`:** Both saved roles and auto-roles are applied

***

### <mark style="color:yellow;">blacklisted\_roles</mark>

**Type:** Array of Strings

Roles that should not be saved or restored.

```json
blacklisted_roles: ["123456789012345678"]
```

Common use cases:

* Temporary roles (muted, etc.)
* Event-specific roles
* Roles that should be earned again

***

## <mark style="color:blue;">Custom Boost Message</mark>

### <mark style="color:yellow;">enable\_custom\_boost\_message</mark>

**Type:** Boolean

Send a custom message when someone boosts the server.

```json
enable_custom_boost_message: true
```

Message content is configured in the lang.json file.

***

## <mark style="color:blue;">Support Voice Call Notification</mark>

Ping staff when someone joins a support voice channel.

### <mark style="color:yellow;">support\_voice\_channels</mark>

**Type:** Array of Strings

List of support voice channel IDs.

```json
support_voice_call_notification: {
    support_voice_channels: ["123456789012345678"],
}
```

**When empty:** Feature is disabled

***

### <mark style="color:yellow;">mention\_roles</mark>

**Type:** Array of Strings

Roles to mention when someone joins a support voice channel.

```json
mention_roles: ["804354037662220289"]
```

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a production-ready management configuration:

```json
{
    config: {
        logs: {
            types: {
                channel_create: true,
                channel_delete: true,
                member_join: true,
                member_leave: true,
                message_delete: true,
                message_update: true,
                // Enable only the logs you need
            },
            exclude_message_logs: [],
            exclude_channel_edit_logs: [],
        },

        welcome_message: {
            enabled: true,
            display_type: "IMAGE",
            image: {
                title: "Welcome %user%",
                description_text: "Member #%member_size%",
            },
            mention_user: true,
            emoji: {
                enabled: true,
                emoji: "👋",
            },
            send_after_verification: false,
            dm_message: false,
        },

        goodbye_message: {
            enabled: true,
            display_type: "IMAGE",
            image: {
                title: "Goodbye %user%",
                description_text: "We'll miss you!",
            },
            emoji: {
                enabled: false,
                emoji: "👋",
            },
        },

        auto_role: {
            enabled: true,
            roles_to_add: ['804354038987882588'],
        },

        auto_thread_reaction: {
            enabled: false,
            parent_id: "",
            emojis: [],
        },

        auto_message_response: {
            enabled: false,
            keywords: [],
        },

        auto_crosspost: {
            enabled: false,
            channel_ids: [],
        },

        scheduled_messages: {
            enabled: false,
            messages: [],
        },

        suggestions: {
            disable_suggestion_threads: false,
            seperate_suggestion_channels: false,
            allow_message_suggestions: false,
            category_based_colors: false,
            suggestion_categories: [],
        },

        role_saving: {
            enabled: false,
            bypass_auto_roles: false,
            blacklisted_roles: [],
        },

        enable_custom_boost_message: true,

        support_voice_call_notification: {
            support_voice_channels: [],
            mention_roles: [],
        }
    }
}
```


# Moderation

Configure moderation features including automod, punishments, and warnings

## <mark style="color:blue;">Introduction</mark>

The Moderation configuration file (`moderation.json`) controls punishment systems, automatic moderation rules, warning thresholds, and other safety features for your server.

***

## <mark style="color:blue;">Punishment Whitelist</mark>

**Type:** String

Role ID that cannot be punished by moderation commands.

```json
punishment_whitelist: '804354024048427009'
```

Users with this role (or any role higher in the Discord role hierarchy) are protected from all moderation commands.

{% hint style="info" %}
**Recommendation:** Set this to your lowest staff role so all staff members are protected from accidental punishment.
{% endhint %}

***

## <mark style="color:blue;">Lock Roles</mark>

**Type:** Array of Strings

List of role IDs that lose write access when `/lock` is used.

```json
lock_roles: [
    "884573835205148692",
    "804354028419022888",
]
```

When you use `/lock` on a channel, these roles will have their send message permission removed.

***

## <mark style="color:blue;">Global Punishment</mark>

Share and receive ban information across all Athena Bot instances.

### <mark style="color:yellow;">send\_data</mark>

**Type:** Boolean

Submit your bans to the global punishment database.

```json
global_punishment: {
    send_data: true,
}
```

**When `true`:** Bans with valid proof images are shared with other Athena Bot servers\
**When `false`:** Your bans are not shared

Only bans with proof images are submitted.

***

### <mark style="color:yellow;">receive</mark>

**Type:** Boolean

Receive global ban requests in a configured channel.

```json
receive: true
```

**When `true`:** Global ban notifications are sent to your moderation channel\
**When `false`:** You don't receive global ban requests

Moderators can review the information and decide whether to ban the user on your server.

***

## <mark style="color:blue;">Role-Based Mute</mark>

Use a mute role instead of Discord's timeout feature.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables role-based mutes instead of timeouts.

```json
role_based_mute: {
    enabled: false,
}
```

**Why use this:** Discord timeouts prevent users from using buttons/dropdowns, which means they can't open tickets to appeal. Role-based mutes don't have this limitation.

***

### <mark style="color:yellow;">role\_id</mark>

**Type:** String

The mute role ID to apply when muting users.

```json
role_id: "804354031388196894"
```

{% hint style="warning" %}
**Important:** You must manually configure the mute role's permissions in Discord channel settings. The bot only applies the role - it doesn't modify channel permissions.
{% endhint %}

***

## <mark style="color:blue;">Warning Punishments</mark>

Automatically punish users when they reach certain warning thresholds.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables automatic punishments based on warning count.

```json
warn_punishments: {
    enabled: true,
}
```

***

### <mark style="color:yellow;">punishments</mark>

**Type:** Array of Objects

Define punishments for specific warning thresholds.

```json
punishments: [
    {
        violations: 1,
        type: "MUTE",
        duration: "3h",
        reset: false,
    },
    {
        violations: 3,
        type: "MUTE",
        duration: "1d",
        reset: false,
    },
    {
        violations: 5,
        type: "BAN",
        duration: 0,
        reset: true,
    },
]
```

**violations** - Number of warnings required\
**type** - Punishment type: `"MUTE"`, `"KICK"`, or `"BAN"`\
**duration** - Punishment length (e.g., `"3h"`, `"1d"`), or `0` for permanent\
**reset** - Whether to reset warning count to 0 after applying this punishment

{% hint style="success" %}
**Example Logic:**

* 1 warning = 3-hour mute
* 3 warnings = 1-day mute
* 5 warnings = permanent ban and reset counter to 0
  {% endhint %}

***

## <mark style="color:blue;">Punishment Presets</mark>

Use punishment presets to make manual moderation commands faster and more consistent.

### <mark style="color:yellow;">punishment\_presets</mark>

**Type:** Object

Enable preset-based punishments and define a list of standard punishments for use in the moderation commands.

```json
punishment_presets: {
    enabled: false,
    presets: [
        {
            name: "Spamming",
            type: "MUTE",
            reason: "Spamming in chat",
            duration: "1h",
        },
        {
            name: "Harassment",
            type: "BAN",
            reason: "Harassing other members",
            duration: "1d",
        },
    ],
}
```

* `enabled` — Whether presets are enabled. When `true`, moderators can choose a preset in the `/warn`, `/mute`, `/kick`, and `/ban` preset subcommands.
* `presets` — List of preset punishments.
* `name` — The preset name shown in the command dropdown.
* `type` — The punishment type (`"WARN"`, `"MUTE"`, `"KICK"`, or `"BAN"`).
* `reason` — The reason that is logged when the punishment is applied.
* `duration` — How long the punishment lasts. Use `""` for a permanent punishment.

***

## <mark style="color:blue;">Punishment Notification</mark>

**Type:** Boolean

Send DM notifications to punished users.

```json
punishment_notification: true
```

**When `true`:** Users receive a DM with punishment details, duration, and reason\
**When `false`:** No DM is sent

***

## <mark style="color:blue;">Automod</mark>

Automatic message filtering and moderation system.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enables or disables the entire automod system.

```json
automod: {
    enabled: true,
}
```

***

### <mark style="color:yellow;">role\_whitelist</mark>

**Type:** String

Role ID that bypasses all automod rules.

```json
role_whitelist: "884573835205148692"
```

Users with this role (or higher in the role hierarchy) are exempt from automod filtering.

***

### <mark style="color:yellow;">whitelist\_ticket\_channels</mark>

**Type:** Boolean

Whether to exempt ticket channels from automod.

```json
whitelist_ticket_channels: true
```

**When `true`:** Messages in ticket channels bypass automod\
**When `false`:** Ticket channels are subject to automod rules

***

### <mark style="color:yellow;">whitelisted\_channels</mark>

**Type:** Array of Strings

Specific channel IDs exempt from automod.

```json
whitelisted_channels: ["804354119523500082", "947577986939514881"]
```

***

### <mark style="color:yellow;">whitelisted\_categories</mark>

**Type:** Array of Strings

Category IDs where all channels are exempt from automod.

```json
whitelisted_categories: ["804354054829506590"]
```

***

### <mark style="color:yellow;">rules</mark>

**Type:** Array of Objects

Regex-based automod filters.

```json
rules: [
    {
        name: "Invite Filter",
        regex: "(https?:\/\/)?(www\\.)?(discord\\.(gg|io|me|li)|discordapp\\.com\/invite)\/+[a-zA-Z0-9]{4,16}",
        whitelisted_text: [],
        warn: true,
    },
    {
        name: "IP Filter",
        regex: "(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d{1})\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d{1})",
        whitelisted_text: [],
        warn: true,
    },
]
```

**name** - Rule name (used in warn reasons and logs)\
**regex** - Regular expression pattern to match\
**whitelisted\_text** - Array of strings/regex that bypass this specific rule\
**warn** - Whether to issue a warning when this rule is triggered

{% hint style="info" %}
**Regex Resources:**

* Test patterns: <https://regexr.com/>
* The config includes pre-configured filters for invites, IPs, Steam URLs, URL shorteners, Cyrillic spoofing, and Zalgo text
  {% endhint %}

***

## <mark style="color:blue;">Custom Automod Rules</mark>

Special automod rules that require different detection methods than regex.

### <mark style="color:yellow;">Mentions Filter</mark>

Delete messages with too many mentions.

```json
custom_rules: {
    mentions: {
        enabled: true,
        rule_name: "Mention Filter",
        max_mentions: 3,
        warn: true,
    },
}
```

**enabled** - Whether this rule is active\
**rule\_name** - Name used in logs/warnings\
**max\_mentions** - Maximum mentions allowed per message\
**warn** - Issue a warning when triggered

***

### <mark style="color:yellow;">Repeating Message Filter</mark>

Delete duplicate consecutive messages.

```json
repeating_message: {
    enabled: true,
    rule_name: "Repeating Message Filter",
    max_message_repeat: 4,
    warn: true,
}
```

**max\_message\_repeat** - How many times the same message can be sent before deletion

***

### <mark style="color:yellow;">Blacklisted Words</mark>

Delete messages containing specific words.

```json
blacklisted_words: {
    enabled: true,
    rule_name: "Restricted Words Filter",
    blacklisted_words: ["word1", "word2", "word3"],
    warn: true,
}
```

**blacklisted\_words** - Array of words/phrases to filter

The default configuration includes a comprehensive list of inappropriate words.

***

### <mark style="color:yellow;">Blacklisted Mentions</mark>

Prevent mentioning specific users.

```json
blacklisted_mentions: {
    enabled: false,
    rule_name: "Blacklisted mentions",
    protected_users: ["123456789012345678"],
    warn: true,
}
```

**protected\_users** - Array of user IDs that cannot be mentioned

Useful for protecting specific users from harassment.

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a production-ready moderation configuration:

```json
{
    config: {
        punishment_whitelist: '804354024048427009',

        lock_roles: [
            "884573835205148692",
            "804354028419022888",
        ],

        global_punishment: {
            send_data: true,
            receive: true,
        },

        role_based_mute: {
            enabled: false,
            role_id: "804354031388196894",
        },

        warn_punishments: {
            enabled: true,
            punishments: [
                {
                    violations: 1,
                    type: "MUTE",
                    duration: "3h",
                    reset: false,
                },
                {
                    violations: 3,
                    type: "MUTE",
                    duration: "1d",
                    reset: false,
                },
                {
                    violations: 5,
                    type: "BAN",
                    duration: 0,
                    reset: true,
                },
            ]
        },

        punishment_presets: {
            enabled: false,
            presets: [
                {
                    name: "Spamming",
                    type: "MUTE",
                    reason: "Spamming in chat",
                    duration: "1h",
                },
                {
                    name: "Harassment",
                    type: "BAN",
                    reason: "Harassing other members",
                    duration: "1d",
                },
            ],
        },

        punishment_notification: true,

        automod: {
            enabled: true,
            role_whitelist: "884573835205148692",
            whitelist_ticket_channels: true,
            whitelisted_channels: [],
            whitelisted_categories: [],

            rules: [
                {
                    name: "Invite Filter",
                    regex: "(https?:\/\/)?(www\\.)?(discord\\.(gg|io|me|li)|discordapp\\.com\/invite)\/+[a-zA-Z0-9]{4,16}",
                    whitelisted_text: [],
                    warn: true,
                },
                {
                    name: "IP Filter",
                    regex: "(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d{1})\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d{1})",
                    whitelisted_text: [],
                    warn: true,
                },
            ],

            custom_rules: {
                mentions: {
                    enabled: true,
                    rule_name: "Mention Filter",
                    max_mentions: 3,
                    warn: true,
                },
                repeating_message: {
                    enabled: true,
                    rule_name: "Repeating Message Filter",
                    max_message_repeat: 4,
                    warn: true,
                },
                blacklisted_words: {
                    enabled: true,
                    rule_name: "Restricted Words Filter",
                    blacklisted_words: [],
                    warn: true,
                },
                blacklisted_mentions: {
                    enabled: false,
                    rule_name: "Blacklisted mentions",
                    protected_users: [],
                    warn: true,
                },
            }
        },
    },
}
```


# Music

Configure music playback settings, Lavalink nodes, and audio features

## <mark style="color:blue;">Introduction</mark>

The Music configuration file (`music.json`) controls Lavalink node connections, default playback settings, channel restrictions, and autoplay features.

***

## <mark style="color:blue;">Lavalink Nodes</mark>

**Type:** Array of Objects

Configure Lavalink servers for music playback.

```json
lavalink_nodes: [
    {
        name: 'Iynx',
        url: '127.0.0.1:2333',
        auth: 'youshallnotpass',
        secure: false,
    },
]
```

**name** - Descriptive name for the node\
**url** - Server address in format `ip:port`\
**auth** - Lavalink server password\
**secure** - Whether to use secure connection (true/false)

You can add multiple nodes and the bot will automatically select the one with the lowest traffic for optimal performance.

{% hint style="warning" %}
**Lavalink Addon Users:** If you have the Lavalink premium addon, this configuration is automatically overridden by the addon's servers.
{% endhint %}

***

## <mark style="color:blue;">Default Volume</mark>

**Type:** Number

Starting volume level for new music sessions.

```json
default_volume: 60
```

**Valid range:** 1 to 1000

This is the volume level used when the bot first starts playing music. Users can adjust it afterward using music commands.

***

## <mark style="color:blue;">Whitelist Channels</mark>

Restrict music commands to specific channels.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Whether to enable channel restrictions.

```json
whitelist_channels: {
    enabled: false,
}
```

**When `true`:** Music commands only work in configured channels\
**When `false`:** Music commands work everywhere

***

### <mark style="color:yellow;">channels</mark>

**Type:** Array of Strings

List of channel IDs where music commands are allowed.

```json
channels: ["804354119523500082", "947577986939514881"]
```

Only applies when `enabled` is set to `true`.

***

## <mark style="color:blue;">Use Own Lavalink</mark>

**Type:** Boolean

Override addon Lavalink servers with your own configuration.

```json
use_own_lavalink: false
```

**When `true`:** Uses your configured Lavalink nodes even if you own the addon\
**When `false`:** Uses premium addon Lavalink servers (if you have the addon)

This option only matters if you have purchased the Lavalink addon.

***

## <mark style="color:blue;">Autoplay Enabled by Default</mark>

**Type:** Boolean

Automatically add similar songs to the queue.

```json
autoplay_enabled_by_default: false
```

**When `true`:** After the first song plays, the bot automatically adds similar tracks based on metadata\
**When `false`:** Bot only plays queued songs

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a production-ready music configuration:

```json
{
    config: {
        lavalink_nodes: [
            {
                name: 'Primary Node',
                url: '127.0.0.1:2333',
                auth: 'yourpassword',
                secure: false,
            },
            {
                name: 'Backup Node',
                url: '192.168.1.100:2333',
                auth: 'yourpassword',
                secure: false,
            },
        ],

        default_volume: 60,

        whitelist_channels: {
            enabled: true,
            channels: ["804354119523500082", "947577986939514881"],
        },

        use_own_lavalink: false,

        autoplay_enabled_by_default: false,
    }
}
```


# Permission

Configure permission levels and command access control

## <mark style="color:blue;">Introduction</mark>

The Permission configuration file (`permission.json`) controls access to bot commands using a role-based hierarchy system or Discord's built-in permission system.

***

## <mark style="color:blue;">Enabled</mark>

**Type:** Boolean

Whether to use the custom permission system.

```json
enabled: true
```

**When `true`:** Uses the custom role-based permission levels defined in this config\
**When `false`:** Uses Discord's native command permission system

{% hint style="danger" %}
**Warning:** If disabled, everyone can use every command unless you manually configure permissions in Discord Server Settings > Integrations > Athena Bot.
{% endhint %}

Learn more about Discord's built-in command permissions: [Discord Support Article](https://support.discord.com/hc/en-us/articles/4644915651095-Command-Permissions)

***

## <mark style="color:blue;">Permission Levels</mark>

**Type:** Object

Define role-based permission levels with Discord role IDs.

```json
permission_levels: {
    management: "804354019455139900",
    admin: "804354024048427009",
    staff: "804354029076348959",
    support: "884573835205148692",
    member: "804354037662220289",
    everyone: "804352424777220186",
}
```

**How it works:**

* Each permission level is assigned to a Discord role ID
* Permission level names can be customized (they don't have to match role names)
* When a command requires a specific permission level, users with that role **or any role higher in the Discord role hierarchy** can use it
* The `everyone` level should be set to your server ID (same as @everyone role)

**Example:** If a command requires `support` level, users with the support role, staff role, admin role, or management role can all use it.

***

## <mark style="color:blue;">Admins</mark>

**Type:** Array of Strings

User IDs that bypass all permission checks.

```json
admins: ["707336356786864211", "123456789012345678"]
```

These users can execute any command regardless of their roles or the command's required permission level.

***

## <mark style="color:blue;">Command Permissions</mark>

Commands are organized by plugin category, with each command assigned a permission level.

**Format:**

```json
plugin_name: {
    command_name: "permission_level",
}
```

**Examples:**

```json
core: {
    botinfo: "member",
    setup: "management",
    restart: "management",
}

moderation: {
    warn: "staff",
    ban: "admin",
    report: "member",
}

tickets: {
    tclose: "support",
    tpanel: "management",
}
```

The permission level must match one of the levels defined in `permission_levels`.

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a production-ready permission configuration:

```json
{
    config: {
        enabled: true,

        permission_levels: {
            management: "804354019455139900",
            admin: "804354024048427009",
            staff: "804354029076348959",
            support: "884573835205148692",
            member: "804354037662220289",
            everyone: "804352424777220186", // Your server ID
        },

        admins: ["707336356786864211"],

        core: {
            botinfo: "member",
            setup: "management",
            restart: "management",
        },

        moderation: {
            warn: "staff",
            ban: "admin",
            kick: "admin",
            mute: "staff",
        },

        tickets: {
            tclose: "support",
            tpanel: "management",
            topen: "support",
        },

        // Add all other plugin commands following the same format
    },
}
```

{% hint style="info" %}
**Tip:** The default configuration file includes all available commands. Simply adjust the permission levels to match your server's role structure.
{% endhint %}


# Security

Configure verification, anti-bot, anti-spam, and anti-nuke protection

## <mark style="color:blue;">Introduction</mark>

The Security configuration file (`security.json`) manages server protection features including member verification, bot protection, spam prevention, and anti-nuke systems.

***

## <mark style="color:blue;">Verification</mark>

Member verification system to ensure users are human before accessing your server.

### <mark style="color:yellow;">roles\_to\_remove</mark>

**Type:** Array of Strings

Roles removed after successful verification.

```json
verification: {
    roles_to_remove: ["123456789012345678"],
}
```

Typically used to remove an "unverified" role.

***

### <mark style="color:yellow;">roles\_to\_add</mark>

**Type:** Array of Strings

Roles granted after successful verification.

```json
roles_to_add: ['804354037662220289']
```

Typically used to grant a "member" role that unlocks server access.

***

### <mark style="color:yellow;">automatic\_verification</mark>

**Type:** Boolean

Auto-verify returning members.

```json
automatic_verification: false
```

**When `true`:** Users who previously verified are automatically verified on rejoin\
**When `false`:** Users must verify again after rejoining

***

### <mark style="color:yellow;">minimum\_account\_age</mark>

Prevent new/alt accounts from verifying.

**enabled** - Whether to enforce minimum account age (Boolean)\
**age** - Required account age in format `"<months>mo <days>d"` (String)

```json
minimum_account_age: {
    enabled: true,
    age: "30d",
}
```

**Examples:**

* `"28d"` - 28 days
* `"1mo"` - 30 days
* `"1mo 12d"` - 42 days
* `"1y 11mo 2d"` - 692 days

***

### <mark style="color:yellow;">user\_join\_activity</mark>

Temporarily disable verification during bot raids.

**enabled** - Whether to monitor join activity (Boolean)\
**max\_joins\_per\_minute** - Maximum joins allowed before triggering (Number)\
**disabled\_for** - How long to disable verification when triggered (String)

```json
user_join_activity: {
    enabled: true,
    max_joins_per_minute: 30,
    disabled_for: "15m",
}
```

If more than 30 users join per minute, verification is paused for 15 minutes to prevent bot floods.

***

### <mark style="color:yellow;">unverified\_kick</mark>

Automatically kick users who don't verify.

**enabled** - Whether to kick unverified users (Boolean)\
**kick\_after** - How long to wait before kicking (String)

```json
unverified_kick: {
    enabled: false,
    kick_after: "30m",
}
```

Keeps your member list clean by removing users who don't complete verification.

***

### <mark style="color:yellow;">must\_be\_synced</mark>

**Type:** Boolean

Require Minecraft account sync before verification.

```json
must_be_synced: false
```

**Requires:** Minecraft addon

***

## <mark style="color:blue;">Anti-Bots</mark>

**Type:** Boolean

Automatically kick bots added to your server.

```json
anti_bots: false
```

**When `true`:** All bots (except those added by server owner) are kicked immediately\
**When `false`:** Bots can be added normally

{% hint style="warning" %}
**Requirement:** Moderation plugin must be loaded for this feature to work.
{% endhint %}

Protects against malicious bots used for server nuking.

***

## <mark style="color:blue;">Message Spam</mark>

Auto-enable slowmode during spam attacks.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Whether to enable spam protection.

```json
message_spam: {
    enabled: true,
}
```

***

### <mark style="color:yellow;">max\_messages\_per\_minute</mark>

**Type:** Number

Message threshold before triggering slowmode.

```json
max_messages_per_minute: 30
```

If more than this many messages are sent in a channel within one minute, slowmode is applied.

***

### <mark style="color:yellow;">slowmode</mark>

**Type:** String

Slowmode interval to apply.

```json
slowmode: "10s"
```

Users can only send one message per 10 seconds when triggered.

***

### <mark style="color:yellow;">duration</mark>

**Type:** String

How long slowmode stays active.

```json
duration: "15m"
```

***

### <mark style="color:yellow;">whitelisted\_channels</mark>

**Type:** Array of Strings

Channels exempt from spam detection.

```json
whitelisted_channels: ["804354119523500082"]
```

***

## <mark style="color:blue;">Anti-Nuke</mark>

Prevent server destruction by monitoring destructive actions.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Whether to enable anti-nuke protection.

```json
anti_nuke: {
    enabled: false,
}
```

***

### <mark style="color:yellow;">violations</mark>

**Type:** Object

Point values for different actions.

```json
violations: {
    member_ban: 5,
    member_unban: 3,
    member_kick: 3,
    member_prune: 14,
    channel_delete: 2,
    channel_create: 1,
    role_delete: 2,
    role_create: 1,
    message_delete: 1,
    message_bulk_delete: 5,
    emoji_delete: 2,
    webhook_create: 5,
    webhook_delete: 3,
}
```

Each action adds points to a user's violation score. The score resets every 15 minutes.

***

### <mark style="color:yellow;">max\_vls</mark>

**Type:** Number

Maximum violation points before action is taken.

```json
max_vls: 15
```

When a user reaches this score within 15 minutes, their roles are removed.

***

### <mark style="color:yellow;">whitelisted\_users</mark>

**Type:** Array of Strings

User IDs exempt from anti-nuke.

```json
whitelisted_users: ['707336356786864211']
```

***

### <mark style="color:yellow;">whitelist\_bots</mark>

**Type:** Boolean

Exempt bots from anti-nuke monitoring.

```json
whitelist_bots: true
```

**When `true`:** Bot actions don't count toward violations\
**When `false`:** Bots are monitored

***

### <mark style="color:yellow;">notification</mark>

Warn users before taking action.

**enabled** - Whether to send warnings (Boolean)\
**vls** - Violation threshold for sending warning (Number)

```json
notification: {
    enabled: true,
    vls: 10,
}
```

When a user reaches 10 violations, they receive a notification warning them to stop.

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a production-ready security configuration:

```json
{
    config: {
        verification: {
            roles_to_remove: [],
            roles_to_add: ['804354037662220289'],
            automatic_verification: false,
            minimum_account_age: {
                enabled: true,
                age: "30d",
            },
            user_join_activity: {
                enabled: true,
                max_joins_per_minute: 30,
                disabled_for: "15m",
            },
            unverified_kick: {
                enabled: false,
                kick_after: "30m",
            },
            must_be_synced: false,
        },

        anti_bots: false,

        message_spam: {
            enabled: true,
            max_messages_per_minute: 30,
            slowmode: "10s",
            duration: "15m",
            whitelisted_channels: [],
        },

        anti_nuke: {
            enabled: true,
            violations: {
                member_ban: 5,
                member_kick: 3,
                channel_delete: 2,
                role_delete: 2,
                message_bulk_delete: 5,
                webhook_create: 5,
            },
            max_vls: 15,
            whitelisted_users: ['707336356786864211'],
            whitelist_bots: true,
            notification: {
                enabled: true,
                vls: 10,
            },
        },
    }
}
```


# Social

Configure YouTube, Twitch, and RSS feed notifications

## <mark style="color:blue;">Introduction</mark>

The Social configuration file (`social.json`) manages notifications for YouTube uploads, Twitch streams, and RSS feeds.

***

## <mark style="color:blue;">YouTube Notification</mark>

Notify your server when YouTube channels upload new videos.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Whether to enable YouTube notifications.

```json
youtube_notification: {
    enabled: false,
}
```

***

### <mark style="color:yellow;">youtube\_api\_key</mark>

**Type:** String

Google API key for YouTube API V3.

```json
youtube_api_key: "YOUR_API_KEY_HERE"
```

**How to get an API key:** <https://elfsight.com/blog/how-to-get-youtube-api-key-tutorial/>

***

### <mark style="color:yellow;">subscribed\_channels</mark>

**Type:** Array of Objects

YouTube channels to monitor for new uploads.

```json
subscribed_channels: [
    {
        youtube_channel_username: "Iynx",
        discord_channel_id: "804354119523500082",
        mention_roles: ["884573835205148692"],
    },
]
```

**youtube\_channel\_username** - Exact YouTube username (case-sensitive)\
**discord\_channel\_id** - Where to send upload notifications\
**mention\_roles** - Array of role IDs to ping on new uploads

{% hint style="warning" %}
**Important:** The YouTube username must match exactly (case-sensitive) or the channel will fail to load.
{% endhint %}

***

## <mark style="color:blue;">Twitch Notification</mark>

Notify your server when Twitch streamers go live.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Whether to enable Twitch notifications.

```json
twitch_notification: {
    enabled: false,
}
```

***

### <mark style="color:yellow;">twitch\_client\_id</mark>

**Type:** String

Your Twitch application client ID.

```json
twitch_client_id: "YOUR_CLIENT_ID"
```

**How to get credentials:**

1. Visit <https://dev.twitch.tv/console/apps>
2. Create a new application
3. Set OAuth Redirect URLs to `http://localhost`
4. Select category "ChatBot"
5. Copy the Client ID from the management page

***

### <mark style="color:yellow;">twitch\_client\_secret</mark>

**Type:** String

Your Twitch application client secret.

```json
twitch_client_secret: "YOUR_CLIENT_SECRET"
```

Found on the same management page as the Client ID.

***

### <mark style="color:yellow;">pingable\_role\_id</mark>

**Type:** String

Role ID to mention when streamers go live.

```json
pingable_role_id: "884573835205148692"
```

Leave empty to disable role pings.

***

### <mark style="color:yellow;">enable\_raid\_notifications</mark>

**Type:** Boolean

Whether to send notifications when raids occur.

```json
enable_raid_notifications: true
```

***

### <mark style="color:yellow;">delete\_embeds\_on\_offline</mark>

**Type:** Boolean

Automatically delete live notifications when stream ends.

```json
delete_embeds_on_offline: true
```

**When `true`:** Live embeds are deleted when streamer goes offline\
**When `false`:** Embeds remain in the channel

***

## <mark style="color:blue;">RSS Feeds</mark>

Monitor RSS feeds and post updates to Discord.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Whether to enable RSS feed monitoring.

```json
rss_feeds: {
    enabled: false,
}
```

***

### <mark style="color:yellow;">feeds</mark>

**Type:** Array of Objects

RSS feeds to monitor.

```json
feeds: [
    {
        name: 'Feed One',
        url: "https://rss.nytimes.com/services/xml/rss/nyt/US.xml",
        channel_id: "1274005906610454619",
        mention_roles: ["884573835205148692"],
    },
]
```

**name** - Feed name used in embed title\
**url** - RSS feed URL\
**channel\_id** - Discord channel for feed posts\
**mention\_roles** - Array of role IDs to ping (leave empty to disable)

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a production-ready social configuration:

```json
{
    config: {
        youtube_notification: {
            enabled: true,
            youtube_api_key: "AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            subscribed_channels: [
                {
                    youtube_channel_username: "Iynx",
                    discord_channel_id: "804354119523500082",
                    mention_roles: ["884573835205148692"],
                },
            ]
        },

        twitch_notification: {
            enabled: true,
            twitch_client_id: "your_client_id_here",
            twitch_client_secret: "your_client_secret_here",
            pingable_role_id: "884573835205148692",
            enable_raid_notifications: true,
            delete_embeds_on_offline: true,
        },

        rss_feeds: {
            enabled: true,
            feeds: [
                {
                    name: 'Server News',
                    url: "https://example.com/rss",
                    channel_id: "1274005906610454619",
                    mention_roles: [],
                },
            ],
        }
    }
}
```


# Staff Management

Configure staff roles, promotions, demotions, and strike system

## <mark style="color:blue;">Introduction</mark>

The Staff Management configuration file (`staff_management.json`) manages staff hierarchy, role assignments, nickname formatting, and the strike system.

***

## <mark style="color:blue;">Staff Roles</mark>

**Type:** Array of Objects

Define your staff role hierarchy.

```json
staff_roles: [
    {
        'name': 'Admin',
        'id': '804354024048427009',
        'additional_roles': ['123456789012345678'],
        'sorting_role': false,
    },
    {
        'name': 'Moderator',
        'id': '804354026568155137',
        'additional_roles': [],
        'sorting_role': false,
    },
    {
        'name': 'Staff',
        'id': '804354029076348959',
        'additional_roles': [],
        'sorting_role': true,
    },
]
```

**name** - Role name used in nicknames and roster\
**id** - Discord role ID\
**additional\_roles** - Extra roles applied when promoted/demoted to this position (e.g., "Training Needed")\
**sorting\_role** - Whether this is an organizational role for grouping staff (e.g., "Management" for all admins/managers)

{% hint style="info" %}
**Sorting Roles:** Used to group staff members in activity lists. For example, "Management" might be a sorting role applied to both Managers and Admins for organization purposes.
{% endhint %}

{% hint style="warning" %}
**Important:** Include your member role at the end of the list so staff can be demoted back to regular members.
{% endhint %}

***

## <mark style="color:blue;">Manage Roles</mark>

Control how roles are applied during promotions/demotions.

### <mark style="color:yellow;">apply\_sorting\_roles</mark>

**Type:** Boolean

Whether to apply sorting roles in addition to the primary staff role.

```json
manage_roles: {
    apply_sorting_roles: true,
}
```

**When `true`:** Sorting roles are added along with the staff position role\
**When `false`:** Only the primary staff role is applied

***

### <mark style="color:yellow;">apply\_all\_possible\_sorting\_roles</mark>

**Type:** Boolean

Whether to apply all applicable sorting roles or just the highest one.

```json
apply_all_possible_sorting_roles: false
```

**When `true`:** All sorting roles the user qualifies for are applied\
**When `false`:** Only the highest applicable sorting role is applied

***

### <mark style="color:yellow;">remove\_roles\_if\_demoted</mark>

**Type:** Boolean

Whether to remove staff roles when demoting users.

```json
remove_roles_if_demoted: true
```

**When `true`:** Old staff roles are removed during demotion\
**When `false`:** Roles are kept (not recommended)

Only roles listed in `staff_roles` are removed.

***

## <mark style="color:blue;">Manage Nicknames</mark>

Automatically format staff member nicknames.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Whether to auto-update nicknames.

```json
manage_nicknames: {
    enabled: true,
}
```

***

### <mark style="color:yellow;">format</mark>

**Type:** String

Nickname format template.

```json
format: "%role_name% » %user%"
```

**Placeholders:**

* `%role_name%` - Staff role name
* `%user%` - Original username

**Example Result:** `Admin » JohnDoe`

***

## <mark style="color:blue;">Sync Roster Panel</mark>

**Type:** Boolean

Auto-update roster panel when staff changes.

```json
sync_roster_panel: true
```

**When `true`:** Roster is automatically updated after promotions/demotions/resignations\
**When `false`:** Roster must be manually updated

***

## <mark style="color:blue;">DM Notification</mark>

**Type:** Boolean

Send DM notifications for staff changes.

```json
dm_notification: false
```

**When `true`:** Users receive DMs when promoted, demoted, or force-resigned\
**When `false`:** No DM notifications are sent

***

## <mark style="color:blue;">Staff Strikes</mark>

Automatic demotion system based on strikes.

### <mark style="color:yellow;">max\_strikes</mark>

**Type:** Number

Maximum strikes before automatic demotion.

```json
staff_strikes: {
    max_strikes: 3,
}
```

When a staff member reaches this number of active strikes, they are automatically demoted.

***

### <mark style="color:yellow;">demote\_to\_next\_lower\_role</mark>

**Type:** Boolean

Demotion behavior when max strikes is reached.

```json
demote_to_next_lower_role: true
```

**When `true`:** User is demoted to the next lower staff role\
**When `false`:** User is demoted directly to member role

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a production-ready staff management configuration:

```json
{
    config: {
        staff_roles: [
            {
                'name': 'Owner',
                'id': '804354016888750150',
                'additional_roles': [],
                'sorting_role': false,
            },
            {
                'name': 'Manager',
                'id': '804354021481381909',
                'additional_roles': [],
                'sorting_role': false,
            },
            {
                'name': 'Management',
                'id': '804354019455139900',
                'additional_roles': [],
                'sorting_role': true,
            },
            {
                'name': 'Admin',
                'id': '804354024048427009',
                'additional_roles': [],
                'sorting_role': false,
            },
            {
                'name': 'Moderator',
                'id': '804354026568155137',
                'additional_roles': [],
                'sorting_role': false,
            },
            {
                'name': 'Helper',
                'id': '804354028419022888',
                'additional_roles': ['999999999999999999'], // Training Needed role
                'sorting_role': false,
            },
            {
                'name': 'Staff',
                'id': '804354029076348959',
                'additional_roles': [],
                'sorting_role': true,
            },
            {
                'name': 'Member',
                'id': '804354037662220289',
                'additional_roles': [],
                'sorting_role': false,
            }
        ],

        manage_roles: {
            apply_sorting_roles: true,
            apply_all_possible_sorting_roles: false,
            remove_roles_if_demoted: true,
        },

        manage_nicknames: {
            enabled: true,
            format: "%role_name% » %user%",
        },

        sync_roster_panel: true,

        dm_notification: false,

        staff_strikes: {
            max_strikes: 3,
            demote_to_next_lower_role: true,
        },
    },
}
```


# Tebex

Configure Tebex store integration, webhooks, and purchase notifications

## <mark style="color:blue;">Introduction</mark>

The Tebex configuration file (`tebex.json`) integrates your Tebex store with Discord for purchase notifications, coupon management, and payment event logging.

***

## <mark style="color:blue;">Tebex Secret Key</mark>

**Type:** String

Your Tebex API secret key.

```json
tebex_secret_key: "your_secret_key_here"
```

**Required for:**

* Creating/modifying/deleting gift cards
* Creating/modifying/deleting coupons
* Banning users from your store

**How to find it:** <https://docs.tebex.io/store/faq#how-can-i-find-my-secret-key>

{% hint style="danger" %}
**Security Warning:** Never share this key with untrusted individuals. This key grants full access to your Tebex store management.
{% endhint %}

***

## <mark style="color:blue;">Tebex Webhook Secret</mark>

**Type:** String

Webhook secret for verifying Tebex requests.

```json
tebex_webhook_secret: "your_webhook_secret_here"
```

**Setup Instructions:**

1. Visit <https://creator.tebex.io/webhooks/endpoints>
2. Create a new webhook endpoint
3. Set URL to: `http://<web_api_baseip>:<web_api_port>/api/tebex`
4. Select webhook type: "All events" (enable all checkboxes)
5. Copy the webhook secret to this config

**Required for:**

* Purchase notifications
* Admin and player logs
* All store event tracking

***

## <mark style="color:blue;">Tebex Logs</mark>

**Type:** Object

Configure which store events should be logged to Discord.

```json
tebex_logs: {
    purchase_public: true,
    purchase_private: true,
    payment_declined: true,
    payment_refunded: true,
    payment_dispute_opened: true,
    payment_dispute_closed: true,
    payment_dispute_won: true,
    payment_dispute_lost: true,
}
```

### <mark style="color:yellow;">purchase\_public</mark>

**Type:** Boolean

Public purchase announcement for your community.

**When `true`:** Sends a community-friendly purchase notification (no sensitive info like price)\
**When `false`:** No public announcement

***

### <mark style="color:yellow;">purchase\_private</mark>

**Type:** Boolean

Detailed purchase log for admins.

**When `true`:** Sends detailed purchase information to admin channel\
**When `false`:** No private admin log

Contains more detailed information than public announcements.

***

### <mark style="color:yellow;">payment\_declined</mark>

**Type:** Boolean

Log when payments are declined.

```json
payment_declined: true
```

***

### <mark style="color:yellow;">payment\_refunded</mark>

**Type:** Boolean

Log when payments are refunded.

```json
payment_refunded: true
```

***

### <mark style="color:yellow;">payment\_dispute\_opened</mark>

**Type:** Boolean

Log when payment disputes/chargebacks are opened.

```json
payment_dispute_opened: true
```

***

### <mark style="color:yellow;">payment\_dispute\_closed</mark>

**Type:** Boolean

Log when payment disputes are closed.

```json
payment_dispute_closed: true
```

***

### <mark style="color:yellow;">payment\_dispute\_won</mark>

**Type:** Boolean

Log when payment disputes are won in your favor.

```json
payment_dispute_won: true
```

***

### <mark style="color:yellow;">payment\_dispute\_lost</mark>

**Type:** Boolean

Log when payment disputes are lost.

```json
payment_dispute_lost: true
```

***

## <mark style="color:blue;">Store Link</mark>

**Type:** String

Your Tebex store URL.

```json
store_link: "https://yourstore.tebex.io"
```

**When configured:** A "Visit Store" button is added to public purchase announcements\
**When empty:** No button is displayed

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a production-ready Tebex configuration:

```json
{
    config: {
        tebex_secret_key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",

        tebex_webhook_secret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",

        tebex_logs: {
            purchase_public: true,
            purchase_private: true,
            payment_declined: true,
            payment_refunded: true,
            payment_dispute_opened: true,
            payment_dispute_closed: true,
            payment_dispute_won: true,
            payment_dispute_lost: true,
        },

        store_link: "https://yourstore.tebex.io",
    },
}
```


# Tickets

Configure ticket system, categories, permissions, and automation

## <mark style="color:blue;">Introduction</mark>

The Tickets configuration file (`tickets.json`) manages your support ticket system including categories, permissions, questions, transcripts, and automation.

***

## <mark style="color:blue;">General Settings</mark>

### <mark style="color:yellow;">send\_transcript\_to\_ticket\_creator</mark>

**Type:** Boolean

Send transcript copy to ticket creator.

```json
send_transcript_to_ticket_creator: true
```

**When `true`:** User receives transcript when ticket closes\
**When `false`:** No transcript is sent to user

***

### <mark style="color:yellow;">save\_ticket\_transcript\_on\_disk</mark>

**Type:** Boolean

Save transcripts to disk locally.

```json
save_ticket_transcript_on_disk: true
```

**When `true`:** Transcripts saved to `\logs\transcripts\`\
**When `false`:** No local save

***

### <mark style="color:yellow;">update\_permissions\_on\_move</mark>

**Type:** Boolean

Sync permissions when moving tickets.

```json
update_permissions_on_move: true
```

**When `true`:** Permissions update to match new category when using `/tmove`\
**When `false`:** Permissions stay the same

***

### <mark style="color:yellow;">ticket\_channel\_name</mark>

**Type:** String

Channel name format for tickets.

```json
ticket_channel_name: "ticket-%random%"
```

**Placeholders:**

* `%random%` - Random number
* `%creator%` - Username
* `%created_total%` - Total tickets created
* `%category%` - Category name

Categories can override this with custom names.

***

### <mark style="color:yellow;">ticket\_transcript\_message\_limit</mark>

**Type:** Number

Maximum messages included in transcripts.

```json
ticket_transcript_message_limit: 200
```

***

### <mark style="color:yellow;">close\_ticket\_after\_creator\_left</mark>

**Type:** Boolean

Auto-close tickets when creator leaves server.

```json
close_ticket_after_creator_left: true
```

***

### <mark style="color:yellow;">ping\_role\_at\_permission\_update</mark>

**Type:** Boolean

Ping role when ticket is elevated/lowered.

```json
ping_role_at_permission_update: false
```

**When `true`:** New permission level role is mentioned\
**When `false`:** No ping

***

### <mark style="color:yellow;">ticket\_creation\_limit</mark>

**Type:** String

How many tickets users can create.

```json
ticket_creation_limit: "CATEGORY"
```

**Options:**

* `"CATEGORY"` - One ticket per category
* `"GLOBAL"` - One ticket total across all categories
* `"NONE"` - Unlimited tickets

Does not apply to applications.

***

### <mark style="color:yellow;">enable\_web\_server</mark>

**Type:** Boolean

Upload transcripts to web server.

```json
enable_web_server: true
```

**When `true`:** Transcripts uploaded and replaced with link\
**When `false`:** Transcripts sent as files

***

### <mark style="color:yellow;">send\_transcript\_to\_claimed\_user</mark>

**Type:** Boolean

Send transcript to staff who claimed ticket.

```json
send_transcript_to_claimed_user: false
```

***

### <mark style="color:yellow;">send\_plain\_ticket\_create\_message</mark>

**Type:** Boolean

Use plain text instead of embed for ticket creation message.

```json
send_plain_ticket_create_message: false
```

***

### <mark style="color:yellow;">use\_discord\_category\_permissions</mark>

**Type:** Boolean

Inherit Discord category permissions.

```json
use_discord_category_permissions: false
```

**When `true`:** Uses Discord category permissions, ignores `permission_level` settings\
**When `false`:** Uses configured permission levels

***

### <mark style="color:yellow;">generate\_new\_category\_if\_full</mark>

**Type:** Boolean

Auto-create new categories when full (50 channel limit).

```json
generate_new_category_if_full: false
```

***

### <mark style="color:yellow;">maximum\_generated\_categories</mark>

**Type:** Number

Maximum auto-generated categories.

```json
maximum_generated_categories: 10
```

Only applies when `generate_new_category_if_full` is enabled.

***

### <mark style="color:yellow;">all\_roles\_required\_to\_open</mark>

**Type:** Boolean

Whether all roles in `required_role_to_open` are needed.

```json
all_roles_required_to_open: false
```

**When `true`:** User needs ALL configured roles\
**When `false`:** User needs only ONE of the configured roles

***

### <mark style="color:yellow;">enable\_ticket\_rating\_system</mark>

**Type:** Boolean

Enable rating system after ticket closure.

```json
enable_ticket_rating_system: true
```

***

## <mark style="color:blue;">Ticket Categories</mark>

**Type:** Array of Objects

Define ticket types and their settings. Each category represents a different ticket type (e.g., General Support, Bug Reports, Appeals, etc.).

```json
ticket_categories: [
    {
        category: "General Support",
        description: "Select to create a General ticket.",
        emoji: "❓",
        category_id: "833732233021751306",
        permission_level: 0,
        ticket_create_questions: "first_question_set",
        required_role_to_open: [],
        mention_roles: ["804354029076348959"],
        ticket_create_msg: "default",
    },
    {
        category: "Bug Report",
        description: "Report bugs or issues with the server.",
        emoji: "🐛",
        category_id: "833732304366338128",
        permission_level: 1,
        ticket_create_questions: "bug_questions",
        required_role_to_open: [],
        mention_roles: ["804354022612926515"],
        ticket_create_msg: "bug_template",
    },
    {
        category: "VIP Support",
        description: "Priority support for VIP members.",
        emoji: "⭐",
        category_id: "833732400000000000",
        permission_level: 0,
        ticket_create_questions: null,
        required_role_to_open: ["123456789012345678"], // VIP Role ID
        mention_roles: ["804354019455139900"],
        ticket_create_msg: "vip_template",
    },
]
```

**category** - Category name displayed in the ticket panel and channel\
**description** - Category description shown in panel dropdown/buttons\
**emoji** - Emoji for category button (use Discord emoji picker or custom emoji ID)\
**category\_id** - Discord category ID where ticket channels will be created\
**permission\_level** - Starting permission level (0 = lowest, higher numbers = more restricted)\
**ticket\_create\_questions** - Question set ID from `question_list` or `null` to skip questions\
**required\_role\_to\_open** - Array of role IDs required to open this ticket type (empty array = anyone can open)\
**mention\_roles** - Array of role IDs to ping when ticket is created (e.g., support team roles)\
**ticket\_create\_msg** - Message template ID from `ticket_create_message` section

{% hint style="success" %}
**Example Use Cases:**

* **General Support**: Open to everyone, low permission level, asks basic questions
* **Bug Report**: Open to everyone, higher permission for developers, asks detailed bug info
* **VIP Support**: Restricted to VIP role, pings senior staff, no questions needed
* **Appeals**: Open to everyone, highest permission for admins, asks for appeal details
  {% endhint %}

***

## <mark style="color:blue;">Permission Levels</mark>

**Type:** Array of Strings

Define ticket access hierarchy using Discord role IDs. This creates a tiered support system where higher-level staff can access lower-level tickets.

```json
permission_levels: [
    "804354029076348959", // Level 0 - Helper/Support (lowest)
    "804354022612926515", // Level 1 - Moderator
    "804354019455139900", // Level 2 - Senior Moderator
    "804354017580810260", // Level 3 - Admin (highest)
]
```

**How Permission Levels Work:**

1. **Position in Array**: Index 0 is the lowest level, higher indexes = higher permission levels
2. **Ticket Access**: Staff with a role can see tickets at their level AND all levels below them
3. **Starting Level**: Tickets start at the `permission_level` set in their category
4. **Escalation**: Use `/televate` to increase level, `/tlower` to decrease level

**Detailed Example:**

Let's say you have these permission levels:

* Level 0: Helper role (ID: `111111111111111111`)
* Level 1: Moderator role (ID: `222222222222222222`)
* Level 2: Admin role (ID: `333333333333333333`)

**Scenario 1 - General Support Ticket (permission\_level: 0)**

* ✅ Helpers can see it (they are level 0)
* ✅ Moderators can see it (level 1 can access level 0)
* ✅ Admins can see it (level 2 can access levels 0 and 1)

**Scenario 2 - Bug Report Ticket (permission\_level: 1)**

* ❌ Helpers CANNOT see it (level 0 cannot access level 1)
* ✅ Moderators can see it (they are level 1)
* ✅ Admins can see it (level 2 can access level 1)

**Scenario 3 - Ticket Elevated to Level 2**

* ❌ Helpers CANNOT see it
* ❌ Moderators CANNOT see it
* ✅ Only Admins can see it (level 2)

{% hint style="info" %}
**Common Setup:**

* Level 0: Junior Support / Helpers
* Level 1: Moderators / Regular Support
* Level 2: Senior Moderators / Team Leads
* Level 3: Administrators / Management

This allows tickets to start with helpers, then be escalated to mods, then admins if needed.
{% endhint %}

***

## <mark style="color:blue;">Ticket Create Questions</mark>

Pre-ticket questions to gather information before the ticket is created. This helps support staff have context immediately.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Whether to enable question system.

```json
ticket_create_questions: {
    enabled: true,
}
```

***

### <mark style="color:yellow;">question\_list</mark>

**Type:** Object

Question sets for different categories. Each set has a unique ID that you reference in `ticket_categories`.

```json
question_list: {
    "first_question_set": [
        {
            question: "What is your ingame name?",
            max_length: 20,
            min_length: 2,
            placeholder: "Enter your username...",
            select_options: [],
            required: true,
        },
        {
            question: "On which realm are you playing?",
            max_length: 1,
            min_length: 1,
            placeholder: "Select your realm...",
            select_options: ['Orbit', 'Skyblock', 'Survival', 'Creative'],
            required: true,
        },
        {
            question: "What's your issue?",
            max_length: 500,
            min_length: 30,
            placeholder: "Describe your issue in detail...",
            select_options: [],
            required: true,
        },
    ],
    "bug_questions": [
        {
            question: "What type of bug is this?",
            max_length: 2,
            min_length: 1,
            placeholder: "Select bug type(s)...",
            select_options: ['Gameplay Bug', 'Visual Bug', 'Crash', 'Performance Issue', 'Other'],
            required: true,
        },
        {
            question: "Describe the bug in detail",
            max_length: 1000,
            min_length: 50,
            placeholder: "What happened? What did you expect to happen?",
            select_options: [],
            required: true,
        },
        {
            question: "Steps to reproduce",
            max_length: 500,
            min_length: 20,
            placeholder: "1. First I did...\n2. Then I...\n3. Bug occurred when...",
            select_options: [],
            required: true,
        },
    ],
    "appeal_questions": [
        {
            question: "What were you punished for?",
            max_length: 1,
            min_length: 1,
            placeholder: "Select punishment type...",
            select_options: ['Ban', 'Mute', 'Kick', 'Warning'],
            required: true,
        },
        {
            question: "When were you punished?",
            max_length: 100,
            min_length: 5,
            placeholder: "e.g., Yesterday, Last week, 3 days ago...",
            select_options: [],
            required: true,
        },
        {
            question: "Why should we remove your punishment?",
            max_length: 1000,
            min_length: 50,
            placeholder: "Explain why you believe the punishment should be removed...",
            select_options: [],
            required: false,
        },
    ],
}
```

**question** - Question text displayed to the user\
**max\_length** - For text: max characters allowed. For dropdowns: max number of options user can select\
**min\_length** - For text: min characters required. For dropdowns: min number of options user must select\
**placeholder** - Placeholder text shown in the input field\
**select\_options** - Empty array `[]` = text input. Array with values = dropdown menu\
**required** - `true` = must be answered, `false` = optional

{% hint style="warning" %}
**Important:** For select menus (dropdowns), `max_length` and `min_length` control how many options can be selected, NOT the character length of each option.

**Example:**

* `max_length: 1, min_length: 1` = User must select exactly 1 option
* `max_length: 3, min_length: 1` = User can select 1 to 3 options
* `max_length: 5, min_length: 2` = User must select between 2 and 5 options
  {% endhint %}

**Question Type Examples:**

**Text Input (Short Answer):**

```json
{
    question: "What is your Minecraft username?",
    max_length: 16,
    min_length: 3,
    placeholder: "Enter your username...",
    select_options: [],
    required: true,
}
```

**Text Input (Long Answer):**

```json
{
    question: "Describe what happened",
    max_length: 1000,
    min_length: 30,
    placeholder: "Provide as much detail as possible...",
    select_options: [],
    required: true,
}
```

**Single Selection Dropdown:**

```json
{
    question: "Which server are you on?",
    max_length: 1,
    min_length: 1,
    placeholder: "Select a server...",
    select_options: ['Survival', 'Creative', 'Skyblock', 'Prison'],
    required: true,
}
```

**Multiple Selection Dropdown:**

```json
{
    question: "What features are affected? (Select all that apply)",
    max_length: 5,
    min_length: 1,
    placeholder: "Select affected features...",
    select_options: ['Chat', 'Commands', 'Economy', 'PvP', 'Building'],
    required: true,
}
```

**Optional Question:**

```json
{
    question: "Additional information (optional)",
    max_length: 500,
    min_length: 0,
    placeholder: "Any other details...",
    select_options: [],
    required: false,
}
```

***

## <mark style="color:blue;">Ticket Create Message</mark>

**Type:** Object

First message sent in new tickets. Each template has a unique ID that you reference in ticket categories.

```json
ticket_create_message: {
    "default": {
        author: {
            name: '%guild%',
            icon_url: '%guild_icon%',
        },
        title: "``🎫 Ticket Created``",
        description: "Hey %creator%,\nThank you for creating %ticket_channel%. A staff member will assist you shortly.\n\nWhile you wait, please provide:\n• Your in-game name\n• What you need help with\n• Any relevant screenshots",
        color: "#3498db",
        defaultFooter: true,
        defaultTimestamp: true,
        userIcon: true,
    },
    "bug_template": {
        author: {
            name: 'Bug Report',
            icon_url: '%guild_icon%',
        },
        title: "``🐛 Bug Report Ticket``",
        description: "Thanks for reporting a bug, %creator%!\n\nA developer will review your report soon. Please make sure you've provided:\n✅ Detailed description\n✅ Steps to reproduce\n✅ Screenshots/videos if possible",
        color: "#e74c3c",
        defaultFooter: true,
        defaultTimestamp: true,
    },
    "vip_template": {
        author: {
            name: 'VIP Support',
            icon_url: '%guild_icon%',
        },
        title: "``⭐ VIP Priority Support``",
        description: "Welcome %creator%!\n\nThank you for being a VIP member. A senior staff member has been notified and will assist you as soon as possible.\n\nPriority response time: **Under 15 minutes**",
        color: "#f1c40f",
        thumbnail: {
            url: '%guild_icon%',
        },
        defaultFooter: true,
        defaultTimestamp: true,
    },
    "appeal_template": {
        title: "``⚖️ Punishment Appeal``",
        description: "%creator%, your appeal has been submitted.\n\nAn administrator will review your case within 24-48 hours.\n\n**Important:**\n• Be honest and respectful\n• Additional rule violations will result in appeal denial\n• Spamming messages will delay your appeal",
        color: "#95a5a6",
        defaultFooter: true,
        defaultTimestamp: true,
    },
}
```

Uses same embed format as `lang.json` configuration file.

**Available Placeholders:**

* `%creator%` - Mentions the ticket creator
* `%ticket_channel%` - Mentions the ticket channel
* `%guild%` - Server name
* `%guild_icon%` - Server icon URL

**Embed Properties:**

* `author` - Author section with name and icon
* `title` - Embed title
* `description` - Main embed content (supports newlines with `\n`)
* `color` - Hex color code (e.g., `"#3498db"`)
* `thumbnail` - Small image in top-right corner
* `image` - Large image at bottom
* `fields` - Array of field objects with `name` and `value`
* `footer` - Footer text and icon
* `defaultFooter` - Use default footer (true/false)
* `defaultTimestamp` - Add timestamp (true/false)
* `userIcon` - Use ticket creator's avatar (true/false)

{% hint style="success" %}
**Pro Tip:** Create different templates for different ticket types to set the right expectations:

* **General Support**: Welcoming message with basic instructions
* **Bug Reports**: Technical format asking for reproduction steps
* **VIP Support**: Priority messaging with faster response times
* **Appeals**: Formal tone with appeal process information
  {% endhint %}

***

## <mark style="color:blue;">Ticket Priority</mark>

The Tickets plugin now includes a full priority system for tickets.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enable the ticket priority system.

```json
priority_settings: {
    enabled: true,
}
```

***

### <mark style="color:yellow;">default\_level</mark>

**Type:** String

The default priority level assigned to tickets when no role-based priority applies.

```json
default_level: "Default"
```

***

### <mark style="color:yellow;">levels</mark>

**Type:** Array of Objects

Defines the available priority levels and how they behave.

Each level can include:

* `priority_name` - The displayed priority name.
* `mention_roles` - Roles to ping when a ticket is created at this priority.
* `move_to_top` - Whether the ticket channel is moved to the top of the category.
* `priority_placeholder` - Text added before the ticket channel name.

```json
levels: [
    {
        priority_name: "High",
        mention_roles: ["884573835205148692"],
        move_to_top: true,
        priority_placeholder: "🔴-",
    },
    {
        priority_name: "Medium",
        mention_roles: ["878410148874448928"],
        move_to_top: false,
        priority_placeholder: "🟡-",
    },
    {
        priority_name: "Low",
        mention_roles: ["804354030662713344"],
        move_to_top: false,
        priority_placeholder: "🟢-",
    },
    {
        priority_name: "Default",
        mention_roles: [],
        move_to_top: false,
        priority_placeholder: "",
    }
]
```

***

### <mark style="color:yellow;">role\_priority</mark>

**Type:** Object

Automatically assign priority levels based on user roles.

```json
role_priority: {
    enabled: false,
    roles: [
        {
            role_id: "804354030662713344",
            priority_level: "High",
        },
        {
            role_id: "804354036001407037",
            priority_level: "Low",
        },
    ],
}
```

If a user has one of the listed roles, their ticket will receive the mapped priority level. If not, the default priority level is used.

***

## <mark style="color:blue;">Out of Service</mark>

Notify users during off-hours.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enable out-of-service notifications.

```json
out_of_service: {
    enabled: false,
}
```

***

### <mark style="color:yellow;">time</mark>

**Type:** Object

Off-hours time range in UTC.

```json
time: {
    start: "23:00",
    finished: "07:00",
}
```

Format: `"hh:mm"` in 24-hour UTC time.

***

## <mark style="color:blue;">Inactivity Closure</mark>

Auto-close inactive tickets.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enable inactivity closure.

```json
inactivity_closure: {
    enabled: true,
}
```

***

### <mark style="color:yellow;">send\_warning</mark>

**Type:** Boolean

Send warning before closing.

```json
send_warning: true
```

***

### <mark style="color:yellow;">send\_warning\_before</mark>

**Type:** Number

Hours before closure to send warning.

```json
send_warning_before: 24
```

***

### <mark style="color:yellow;">inactive\_for</mark>

**Type:** Number

Hours of inactivity before closing.

```json
inactive_for: 72
```

***

## <mark style="color:blue;">Ticket Buttons</mark>

**Type:** Object

Control which buttons appear on ticket creation message.

```json
ticket_buttons: {
    close: false,
    close_request: true,
    elevate: true,
    lower: true,
    claim: true,
    unclaim: true,
}
```

**close** - Direct close button\
**close\_request** - Request closure button\
**elevate** - Increase permission level\
**lower** - Decrease permission level\
**claim** - Claim ticket\
**unclaim** - Unclaim ticket

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a production-ready tickets configuration:

```json
{
    config: {
        send_transcript_to_ticket_creator: true,
        save_ticket_transcript_on_disk: true,
        update_permissions_on_move: true,
        ticket_channel_name: "ticket-%random%",
        ticket_transcript_message_limit: 200,
        close_ticket_after_creator_left: true,
        ping_role_at_permission_update: false,
        ticket_creation_limit: "CATEGORY",
        enable_web_server: true,
        send_transcript_to_claimed_user: false,
        send_plain_ticket_create_message: false,
        use_discord_category_permissions: false,
        generate_new_category_if_full: false,
        maximum_generated_categories: 10,
        all_roles_required_to_open: false,
        enable_ticket_rating_system: true,

        ticket_categories: [
            {
                category: "General Support",
                description: "Select to create a General ticket.",
                emoji: "❓",
                category_id: "833732233021751306",
                permission_level: 0,
                ticket_create_questions: "first_question_set",
                required_role_to_open: [],
                mention_roles: ["804354029076348959"],
                ticket_create_msg: "default",
            },
        ],

        permission_levels: [
            "804354029076348959", // Level 0
            "804354022612926515", // Level 1
            "804354019455139900", // Level 2
        ],

        ticket_create_questions: {
            enabled: true,
            question_list: {
                "first_question_set": [
                    {
                        question: "What is your issue?",
                        max_length: 200,
                        min_length: 30,
                        placeholder: "Describe your issue...",
                        select_options: [],
                        required: true,
                    },
                ],
            }
        },

        ticket_create_message: {
            "default": {
                title: "``🎫 Ticket Created``",
                description: "Thank you for creating %ticket_channel%!",
                defaultFooter: true,
            },
        },

        priority_settings: {
            enabled: true,
            default_level: "Default",
            levels: [
                {
                    priority_name: "High",
                    mention_roles: ["884573835205148692"],
                    move_to_top: true,
                    priority_placeholder: "🔴-",
                },
                {
                    priority_name: "Medium",
                    mention_roles: ["878410148874448928"],
                    move_to_top: false,
                    priority_placeholder: "🟡-",
                },
                {
                    priority_name: "Low",
                    mention_roles: ["804354030662713344"],
                    move_to_top: false,
                    priority_placeholder: "🟢-",
                },
                {
                    priority_name: "Default",
                    mention_roles: [],
                    move_to_top: false,
                    priority_placeholder: "",
                },
            ],
            role_priority: {
                enabled: false,
                roles: [
                    {
                        role_id: "804354030662713344",
                        priority_level: "High",
                    },
                ],
            },
        },

        out_of_service: {
            enabled: false,
            time: {
                start: "23:00",
                finished: "07:00",
            }
        },

        inactivity_closure: {
            enabled: true,
            send_warning: true,
            send_warning_before: 24,
            inactive_for: 72,
        },

        ticket_buttons: {
            close: false,
            close_request: true,
            elevate: true,
            lower: true,
            claim: true,
            priority: true,
            unclaim: true,
        },
    },
}
```


# Web API

Configure Web API server, authentication, IP whitelisting, and rate limiting

## <mark style="color:blue;">Introduction</mark>

The Web API configuration file (`web_api.json`) manages the built-in web server for API endpoints, webhooks, and external integrations.

***

## <mark style="color:blue;">Port</mark>

**Type:** String

Server port for the Web API.

```json
port: "3111"
```

The bot will listen for HTTP requests on this port.

***

## <mark style="color:blue;">Authentication Key</mark>

**Type:** Array of Strings

API keys required to access endpoints.

```json
authentication_key: ['09563-34763-36235-36235', 'second-key-here']
```

{% hint style="danger" %}
**Security Warning:** Change the default authentication key immediately! Never share these keys publicly.
{% endhint %}

Requests must include one of these keys in the authentication header.

***

## <mark style="color:blue;">Whitelisted IPs</mark>

**Type:** Array of Strings

IP addresses allowed to access the API.

```json
whitelisted_ips: ['18.209.80.3', '54.87.231.232', '203.0.113.0']
```

**Default IPs included:**

* `18.209.80.3` - Tebex server
* `54.87.231.232` - Tebex server

{% hint style="warning" %}
**Important:** Do not remove the Tebex IPs if you use the Tebex integration, or webhooks will fail.
{% endhint %}

***

## <mark style="color:blue;">Secure Mode</mark>

**Type:** Boolean

Restrict API to whitelisted IPs only.

```json
secure_mode: false
```

**When `true`:** Only whitelisted IPs can access the API (still requires authentication)\
**When `false`:** All IPs can access with valid authentication key

***

## <mark style="color:blue;">Base IP</mark>

**Type:** String

Base URL for API hooks and webhooks.

```json
base_ip: "bot.example.com"
```

**Format options:**

* With domain: `"bot.example.com"` or `"api.example.com"`
* Without domain: `"192.168.1.100:3111"` (IP:port format)

Used to construct full URLs for external services like Tebex webhooks.

***

## <mark style="color:blue;">Rate Limit</mark>

Prevent API abuse with request limiting.

### <mark style="color:yellow;">enabled</mark>

**Type:** Boolean

Enable rate limiting.

```json
rate_limit: {
    enabled: true,
}
```

***

### <mark style="color:yellow;">window\_ms</mark>

**Type:** Number

Time window for rate limit in milliseconds.

```json
window_ms: 300000
```

**Example:** `300000` = 5 minutes (300,000 milliseconds)

After this window elapses, the request count resets for that client.

***

### <mark style="color:yellow;">max</mark>

**Type:** Number

Maximum requests per window.

```json
max: 150
```

Clients exceeding this limit during the time window will be rate limited.

***

### <mark style="color:yellow;">proxied</mark>

**Type:** Boolean

Whether API is behind a reverse proxy.

```json
proxied: false
```

**When `true`:** Bot uses proxy headers to identify real client IP (required for Nginx/Apache)\
**When `false`:** Direct connection IP is used

{% hint style="info" %}
**Reverse Proxy Users:** If you use Nginx, Apache, or Cloudflare in front of the bot, set this to `true` to ensure correct IP detection for rate limiting and security.
{% endhint %}

***

### <mark style="color:yellow;">proxies\_between\_user\_and\_server</mark>

**Type:** Number

Number of proxy layers between client and bot.

```json
proxies_between_user_and_server: 1
```

Only relevant when `proxied` is `true`.

**Examples:**

* Direct proxy: `1`
* Cloudflare + Nginx: `2`

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a production-ready Web API configuration:

```json
{
    config: {
        port: "3111",

        authentication_key: ['your-secure-key-here-change-this'],

        whitelisted_ips: [
            '18.209.80.3',      // Tebex
            '54.87.231.232',    // Tebex
            '203.0.113.10',     // Your server IP
        ],

        secure_mode: true,

        base_ip: "api.yourserver.com",

        rate_limit: {
            enabled: true,
            window_ms: 300000,
            max: 150,
            proxied: true,
            proxies_between_user_and_server: 1,
        },
    },
}
```


# Source Code

## <mark style="color:blue;">Table of Contents</mark>

1. **Features**
2. **Installation**
3. **Responsibilities**
4. **License Limitations**

### <mark style="color:yellow;">1 - Features</mark>

<mark style="color:purple;">The</mark> <mark style="color:purple;">**Source Code**</mark> <mark style="color:purple;">addon is a necessity for those looking to really get into the gritty details of the bot and make it truly their own.</mark> Don't worry, the bot is customizable enough! But sometimes, people need a bit more than just to change a *few* things about their installation.

* <mark style="color:red;">**True Control**</mark><mark style="color:red;">:</mark> Control everything, down to the byte!
* <mark style="color:red;">**Expandability**</mark><mark style="color:red;">:</mark> Maybe if Athena does something a way you don't want it to, this allows you to change it as you see fit and change it your way!
* <mark style="color:red;">**Remove License Limitations**</mark><mark style="color:red;">:</mark> Need to run a copy of Athena for multiple servers? Maybe run it in multiple instances at one time? This removes that limitation!\*

{% hint style="success" %}
**Additional perks:**

* Permanent access to old and future updates
* Github Repo Access
* Includes <mark style="color:red;">Watermark Addon</mark>
* Includes <mark style="color:red;">Minecraft Addon</mark>
* Includes <mark style="color:red;">Hytale Addon</mark>
* Includes <mark style="color:red;">Invoice Addon</mark>
* Includes <mark style="color:red;">Command Maker Addon</mark>
* Includes <mark style="color:red;">Economy Addon</mark>
  {% endhint %}

***

### <mark style="color:yellow;">2 - Installation</mark>

<mark style="color:purple;">**This is a purchased addon!**</mark> Other than simply dragging and dropping the source where you want it and following the setup guide, there isn't much else to do in terms of installation.

***

### <mark style="color:yellow;">3 - Responsibilities</mark>

{% hint style="danger" %}
**Please take a good look at this section if you're purchasing the Source Addon!**
{% endhint %}

The Source Addon is an amazing feature, but it does have the responsibilities attached to it, of you not distributing the source code to anyone else, sharing your licenses, etc.

Anyone found distributing source code to third parties will be removed from the licensing system, disabling even your legitimate copies, and losing any possibility of a refund if possible.

So please, do *not* share your license or source code with other people.

***

### <mark style="color:yellow;">4 - License Limitations</mark>

{% hint style="warning" %}
**All Limits have been put in place for Good-Faith Installations**
{% endhint %}

#### <mark style="color:orange;">**Regular User Limits (not source):**</mark>

* 2 IPs per user
* 3 Guilds per user

What does this mean? A **Normal User** will only be able to install their bot on three separate instances and on up to three servers at a time.

Here's where the magic of <mark style="color:purple;">**Source**</mark> comes in!

<mark style="color:purple;">**Source Users**</mark> have an unlimited\* number of instances and guilds they can run the bot in with a single license, this means if you have multiple servers and multiple hosting systems, you can run the bot in all of them just fine!

\*Keep in mind, this is for **reasonable** installations. If there's a pattern of abuse (aka 1 license being installed in machines all over the place or in an inconceivably large number of servers) then action will have to be taken against you/your license.

***


# Setup & Install

Not sure where to start? Here's a good place!

## <mark style="color:blue;">Table of Contents</mark>

1. **Features**
2. **Installation**
3. **Disclaimer**

### <mark style="color:yellow;">Features</mark>

<mark style="color:purple;">The</mark> <mark style="color:purple;">**Setup & Install**</mark> <mark style="color:purple;">addon is a necessity for those looking to get started with their bot with guidance involved!</mark> Iynx Development staff will help you get your bot set up without all the hassle of figuring it out yourself!

* <mark style="color:red;">**Quick Service**</mark><mark style="color:red;">:</mark> We strive to take care of your needs within one up to two days at most to get you going quickly!
* <mark style="color:red;">**Low-Cost**</mark><mark style="color:red;">:</mark> Don't pay someone else to do it for you for more, even if things take a bit longer than usual, you'll pay our low cost setup and be done with it!

***

### <mark style="color:yellow;">Installation</mark>

<mark style="color:purple;">**This is a purchased addon!**</mark> You need to submit a ticket to us so we can help you promptly!

***

### <mark style="color:yellow;">Disclaimer</mark>

<mark style="color:purple;">**This service is only offered once!**</mark> We don't provide a second reinstall! So please keep that in mind before opening a ticket!


# Watermark

Don't want credits in your bot? Check this out!

## <mark style="color:blue;">Table of Contents</mark>

1. **Features**
2. **Installation**
3. **Responsibilities**

### <mark style="color:yellow;">1 - Features</mark>

<mark style="color:purple;">The</mark> <mark style="color:purple;">**Watermark**</mark> <mark style="color:purple;">addon allows you to remove/disable the /botinfo command, Athena's 'watermark' so to speak.</mark> This basically hides the page that has Iynx's information.

***

### <mark style="color:yellow;">2 - Installation</mark>

<mark style="color:purple;">**This is a purchased addon!**</mark> No installation required, /claim the addon in our support server, then just disable the <mark style="color:green;">**`/botinfo`**</mark> command in the configs!

***


# Fastlink

Reliable Music Streaming Made Easy!

## <mark style="color:blue;">Table of Contents</mark>

1. **Features**
2. **Installation**

### <mark style="color:yellow;">Features</mark>

<mark style="color:purple;">The</mark> <mark style="color:purple;">**Fastlink**</mark> <mark style="color:purple;">addon is a necessity for those looking to get reliable music streaming for no effort.</mark> Iynx Development would be handling a Lavalink Server that's accessible to those purchasing the plugin and maintaining it for you at no extra cost.

* <mark style="color:red;">**High Quality Streaming**</mark><mark style="color:red;">:</mark> The setup we have enables higher-than-most quality being sent directly to your bot!
* <mark style="color:red;">**Low-Cost**</mark><mark style="color:red;">:</mark> Other than paying us what would be the setup/access fee, you don't have to pay for a monthly sub to keep the instance running, nor worry about hosting a dedicated server for Lavalink yourself, cutting costs!
* <mark style="color:red;">**No Trouble**</mark><mark style="color:red;">:</mark> You don't have to worry about your lavalink server being blocked by Youtube or other streaming services!

***

### <mark style="color:yellow;">Installation</mark>

<mark style="color:purple;">**This is a purchased addon!**</mark> No installation required, /claim the addon in our support server, then just restart the bot.

***


# Economy

Build an engaging economy system to keep your community active and rewarded!

## <mark style="color:blue;">Overview</mark>

Tired of a quiet server? The **Economy** addon is the perfect solution to get your members interacting, competing, and sticking around for the long haul. This comprehensive virtual currency system rewards members for the activities they already do - and encourages them to do more.

***

## <mark style="color:blue;">Table of Contents</mark>

1. **Features**
2. **Installation**
3. **How It Works**
4. **Commands**

***

## <mark style="color:blue;">Features</mark>

### <mark style="color:yellow;">Earning Coins</mark>

Members can earn coins through **20+ unique activities**:

**Social Activities:**

* <mark style="color:red;">**Message Sending**</mark> - Earn coins for staying active in chat
* <mark style="color:red;">**Voice Calls**</mark> - Get rewarded for every minute in voice channels
* <mark style="color:red;">**Server Invites**</mark> - Bonus coins for bringing new members
* <mark style="color:red;">**Suggestions & Polls**</mark> - Earn for voting and having suggestions approved
* <mark style="color:red;">**Birthdays**</mark> - Special birthday coin rewards

**Progression Activities:**

* <mark style="color:red;">**Level Ups**</mark> - Bonus coins when ranking up
* <mark style="color:red;">**Starboard Messages**</mark> - Rewards for popular messages
* <mark style="color:red;">**Daily & Weekly Claims**</mark> - Regular income with streak bonuses
* <mark style="color:red;">**Quests**</mark> - Complete daily and weekly challenges

**Interactive Activities:**

* <mark style="color:red;">**Games**</mark> - Play guess-the-number, hangman, RPS, trivia, and more
* <mark style="color:red;">**Game Wagers**</mark> - Bet coins on games for multiplied rewards
* <mark style="color:red;">**Jobs**</mark> - Take on roles like Fisher to earn passive income
* <mark style="color:red;">**Counting Game**</mark> - Participate in the counting channel

**Economy Activities:**

* <mark style="color:red;">**Begging**</mark> - Try your luck begging for coins
* <mark style="color:red;">**Robbing**</mark> - Steal from other members (with risks!)
* <mark style="color:red;">**Spying**</mark> - Check other users' wealth

***

### <mark style="color:yellow;">Spending Coins</mark>

**Built-in Shop System:**

* <mark style="color:red;">**Roles**</mark> - Purchase exclusive or VIP roles
* <mark style="color:red;">**Boosters**</mark> - Buy coin multipliers for increased earnings
* <mark style="color:red;">**Lootboxes**</mark> - Try your luck with random rewards
* <mark style="color:red;">**Custom Messages**</mark> - Send messages to specific channels
* <mark style="color:red;">**Tebex Coupons**</mark> - Redeem real store discounts
* <mark style="color:red;">**Configurable Items**</mark> - Create unlimited custom shop items

**Advanced Features:**

* Rank-locked items (require specific levels to purchase)
* One-time purchase restrictions
* Multiple reward types per item
* Custom emojis and descriptions

***

### <mark style="color:yellow;">Engagement Features</mark>

* <mark style="color:red;">**Streak Bonuses**</mark> - Daily and weekly claim streaks with increasing rewards
* <mark style="color:red;">**Game Wagers**</mark> - Configurable betting system with multipliers
* <mark style="color:red;">**Banking System**</mark> - Deposit, withdraw, and protect your coins
* <mark style="color:red;">**Cooldown Management**</mark> - Prevent spam and balance the economy
* <mark style="color:red;">**Punishment System**</mark> - Automatic coin deduction for rule violations

***

## <mark style="color:blue;">Installation</mark>

{% hint style="warning" %}
**This is a premium addon!** You must purchase this addon separately and have a valid license.
{% endhint %}

1. Download the Economy addon files from your purchase
2. Extract all files into the `plugins/` folder of your Athena Bot installation
3. Restart your bot to load the addon
4. Configure the addon using the `economy.json` file in your `configuration/` folder

***

## <mark style="color:blue;">How It Works</mark>

### <mark style="color:yellow;">1. Members Earn Coins</mark>

Your members automatically earn coins by participating in server activities. You control exactly how many coins each activity grants through the configuration file.

### <mark style="color:yellow;">2. Coins Are Stored Safely</mark>

Members can use the banking system to:

* **Deposit** coins for safekeeping (protected from robbery)
* **Withdraw** coins when needed
* **Spy** on other members to see their wealth
* View their total **balance** and **rank**

### <mark style="color:yellow;">3. Members Spend in the Shop</mark>

Use the `/shop` command to browse and purchase items. The shop supports:

* Multiple items with custom emojis and descriptions
* Rank requirements to unlock premium items
* One-time or unlimited purchase items
* Automatic reward delivery (roles, boosters, etc.)

### <mark style="color:yellow;">4. Engage with Activities</mark>

Members can increase their earnings through:

* **Daily/Weekly Claims** with streak bonuses
* **Game Wagers** for multiplied rewards
* **Jobs** for alternative income sources
* **Quests** for bonus challenges
* **Boosters** for temporary coin multipliers

***

## <mark style="color:blue;">Commands</mark>

### <mark style="color:yellow;">User Commands</mark>

**Banking & Balance:**

* `/bank info` - View your bank account details
* `/bank deposit <amount>` - Store coins in your bank
* `/bank withdraw <amount>` - Take coins from your bank
* `/bank spy <user>` - Check another user's wallet (cooldown applies)
* `/coins` - View your current coin balance
* `/rank` - Check your economy rank and leaderboard position

**Earning Coins:**

* `/claim daily` - Claim your daily reward (24h cooldown)
* `/claim weekly` - Claim your weekly reward (7d cooldown)
* `/beg` - Beg for coins (cooldown applies)
* `/rob <user>` - Attempt to steal coins from another user (cooldown applies)
* `/job fisher` - Start fishing to earn coins
* `/quests daily` - View and track daily quests
* `/quests weekly` - View and track weekly quests

**Shop & Items:**

* `/shop` - Browse and purchase items from the shop
* `/lootbox` - Open your lootboxes for random rewards
* `/booster list` - View available and active boosters
* `/booster activate <booster>` - Activate a coin multiplier booster

***

### <mark style="color:yellow;">Admin Commands</mark>

**Economy Management:**

* `/economyadmin coins <user> <amount>` - Add or remove coins from a user
* `/economyadmin karma <user> <amount>` - Adjust a user's karma points
* `/economyadmin lootbox <user> <amount>` - Give lootboxes to a user
* `/economyadmin booster <user> <booster>` - Grant boosters to users
* `/economyadmin reset <user>` - Reset a user's economy data

***

## <mark style="color:blue;">Getting Started</mark>

{% hint style="success" %}
**Quick Start Guide:**

1. Install the addon and restart your bot
2. Configure coin rewards for activities in `economy.json`
3. Set up shop items with roles and rewards
4. Adjust cooldowns and wager limits to your preference
5. Monitor the economy and adjust values as needed
   {% endhint %}

{% hint style="info" %}
**Balancing Tips:**

* Start with lower coin values and increase if needed
* Monitor the richest members to prevent inflation
* Use cooldowns to prevent grinding/exploitation
* Make premium items expensive to maintain value
* Consider one-time purchases for exclusive rewards
* Test the economy in a private channel first
  {% endhint %}


# Configuration

Complete guide to configuring your economy system

## <mark style="color:blue;">Introduction</mark>

The Economy addon configuration file (`economy.json`) controls every aspect of your server's virtual currency system. This guide will walk you through each section to help you create a balanced and engaging economy.

***

## <mark style="color:blue;">Part 1: Coin Rewards</mark>

### <mark style="color:yellow;">Understanding Coin Rewards</mark>

The `coins` section defines how many coins users earn for different activities. Setting a value to `0` disables coin rewards for that activity.

```json
coins: {
    message_sent: 1,
    invite: 150,
    game_played: 5,
    game_won: 15,
    counting_game: 3,
    level_up: 100,
    daily: 125,
    weekly: 1000,
    calltime_minute: 15,
    approved_suggestion: 200,
    suggestion_vote: 25,
    poll_vote: 25,
    birthday: 5000,
    starboard_message: 200,
    punishment: -5000,
}
```

***

### <mark style="color:yellow;">Activity Breakdown</mark>

#### <mark style="color:orange;">Social Activities</mark>

**message\_sent**

* Coins earned per message sent in chat
* Recommended: `1-5` coins
* Too high = spam encouragement | Too low = no incentive

**invite**

* Coins earned when a user's invite brings a new member
* Recommended: `100-500` coins
* High value encourages organic growth

**calltime\_minute**

* Coins earned per minute in voice channels
* Recommended: `10-30` coins
* Encourages voice activity and community engagement

**suggestion\_vote** & **poll\_vote**

* Coins earned for voting on suggestions or polls
* Recommended: `10-50` coins each
* Encourages community participation in decisions

**approved\_suggestion**

* Bonus coins when your suggestion is approved
* Recommended: `100-500` coins
* Rewards quality suggestions

**starboard\_message**

* Coins earned when your message gets starred
* Recommended: `100-300` coins
* Rewards popular/quality content

***

#### <mark style="color:orange;">Game Activities</mark>

**game\_played**

* Coins earned just for playing a game
* Recommended: `1-10` coins
* Participation reward

**game\_won**

* Coins earned for winning a game
* Recommended: `10-50` coins
* Should be higher than `game_played`

**counting\_game**

* Coins earned per successful count in counting channel
* Recommended: `1-5` coins
* Small but consistent reward

***

#### <mark style="color:orange;">Progression Activities</mark>

**level\_up**

* Bonus coins when reaching a new level
* Recommended: `50-200` coins
* Scales with your leveling system difficulty

**daily**

* Base reward for daily claims
* Recommended: `100-500` coins
* Influenced by streak bonuses (see Streaks section)

**weekly**

* Base reward for weekly claims
* Recommended: `500-2000` coins
* Should be significantly higher than daily

**birthday**

* Special reward on user's birthday
* Recommended: `1000-10000` coins
* Once-per-year celebration bonus

***

#### <mark style="color:orange;">Punishment</mark>

**punishment**

* Coins deducted when a user is punished (warned, muted, etc.)
* Recommended: `-1000` to `-10000` coins
* Use negative values to deduct coins
* Serves as an economic deterrent for rule-breaking

***

## <mark style="color:blue;">Part 2: Shop Items</mark>

### <mark style="color:yellow;">Understanding Shop Structure</mark>

Shop items appear in the `/shop` command and can be purchased with earned coins. Each item has rewards that are automatically delivered upon purchase.

```json
shop_items: [
    {
        id: 0,
        emoji: '👑',
        name: 'VIP',
        description: 'Enter to purchase the VIP role',
        cost: 50000,
        requirement: {
            rankId: 5,
            oneTimePurchase: true,
        },
        reward: [
            {
                type: "ROLE",
                target: "804354029076348959",
            }
        ],
    }
]
```

***

### <mark style="color:yellow;">Item Configuration Options</mark>

#### <mark style="color:orange;">Basic Properties</mark>

**id** (Number)

* Unique identifier for the item
* **CRITICAL:** Never reuse IDs, even after deleting items
* Used to track who purchased what
* Start at 0 and increment for each new item

**emoji** (String)

* Emoji displayed next to the item in the shop
* Use any Discord emoji or Unicode emoji
* Example: `'👑'`, `'🎁'`, `'💎'`

**name** (String)

* Display name of the item
* Keep it short and descriptive
* Shown in shop list and purchase confirmations

**description** (String)

* Longer explanation of what the item does
* Tell users exactly what they're buying
* Example: "Permanent VIP role with exclusive perks"

**cost** (Number)

* Price in coins
* Must be greater than 0
* Consider your coin earning rates when pricing

***

#### <mark style="color:orange;">Requirements</mark>

**rankId** (Number)

* Minimum economy rank required to purchase
* Set to `0` for no requirement
* Higher ranks = more exclusive items
* Use for progression-locked rewards

**oneTimePurchase** (Boolean)

* `true` = Can only buy once per user
* `false` = Can buy unlimited times
* Use `true` for roles and permanent items
* Use `false` for consumables (boosters, lootboxes)

***

### <mark style="color:yellow;">Reward Types</mark>

Each item can have multiple rewards. When purchased, all rewards are given simultaneously.

#### <mark style="color:orange;">ROLE Reward</mark>

Grants a Discord role to the purchaser:

```json
reward: [
    {
        type: "ROLE",
        target: "804354029076348959",
    }
]
```

* `target` = Role ID (right-click role with Developer Mode enabled)
* Bot must have permission to assign roles
* Bot's role must be higher than the target role

***

#### <mark style="color:orange;">BOOSTER Reward</mark>

Gives a coin multiplier booster:

```json
reward: [
    {
        type: "BOOSTER",
        target: "booster_coin_1h_2",
    }
]
```

* `target` = Booster ID from your booster configuration
* Format usually: `booster_coin_<duration>_<multiplier>`
* Examples: `booster_coin_1h_2` = 2x coins for 1 hour
* Users activate boosters with `/booster activate`

***

#### <mark style="color:orange;">LOOTBOX Reward</mark>

Adds lootboxes to the user's inventory:

```json
reward: [
    {
        type: "LOOTBOX",
        target: null,
        amount: 1,
    }
]
```

* `target` = Always `null` for lootboxes
* `amount` = Number of lootboxes to give
* Lootboxes contain random rewards when opened

***

#### <mark style="color:orange;">CHANNEL\_MESSAGE Reward</mark>

Sends a predefined message to a specific channel:

```json
reward: [
    {
        type: "CHANNEL_MESSAGE",
        target: "1274005906610454619",
        predefined_id: "vip_announcement",
    }
]
```

* `target` = Channel ID where the message will be sent
* `predefined_id` = ID of your saved message template
* Create templates using `/sendmsg` and `/editmsg` commands
* Useful for announcing purchases or sending instructions

***

#### <mark style="color:orange;">COUPON Reward</mark>

Generates a Tebex store coupon code:

```json
reward: [
    {
        type: "COUPON",
        target: "10",
    }
]
```

* `target` = Coupon value (percentage or fixed amount)
* Requires Tebex plugin integration
* Automatically generates and DMs the code to the user
* Perfect for bridging virtual and real economy

{% hint style="danger" %}
**Warning:** Coupon rewards can be exploited if coin earning rates are too high or if jobs generate too much passive income. Use with caution and balance your economy carefully!
{% endhint %}

***

### <mark style="color:yellow;">Shop Item Examples</mark>

#### <mark style="color:orange;">Example 1: VIP Role</mark>

Permanent role requiring rank 5:

```json
{
    id: 0,
    emoji: '👑',
    name: 'VIP',
    description: 'Permanent VIP role with exclusive perks and channels',
    cost: 50000,
    requirement: {
        rankId: 5,
        oneTimePurchase: true,
    },
    reward: [
        {
            type: "ROLE",
            target: "804354029076348959",
        }
    ],
}
```

***

#### <mark style="color:orange;">Example 2: Coin Booster</mark>

Consumable 2x booster for 1 hour:

```json
{
    id: 1,
    emoji: '🪄',
    name: 'Gilded Elixir',
    description: 'Double your coin earnings for 1 hour',
    cost: 750,
    requirement: {
        rankId: 0,
        oneTimePurchase: false,
    },
    reward: [
        {
            type: "BOOSTER",
            target: "booster_coin_1h_2",
        },
    ],
}
```

***

#### <mark style="color:orange;">Example 3: Lootbox</mark>

Random reward box:

```json
{
    id: 2,
    emoji: '🎁',
    name: 'Mystery Lootbox',
    description: 'Open for random coins, boosters, or rare items!',
    cost: 500,
    requirement: {
        rankId: 0,
        oneTimePurchase: false,
    },
    reward: [
        {
            type: "LOOTBOX",
            target: null,
            amount: 1,
        }
    ],
}
```

***

#### <mark style="color:orange;">Example 4: Announcement Purchase</mark>

Send a message to a public channel:

```json
{
    id: 3,
    emoji: '💬',
    name: 'Server Announcement',
    description: 'Post your custom message in the announcements channel',
    cost: 2000,
    requirement: {
        rankId: 3,
        oneTimePurchase: false,
    },
    reward: [
        {
            type: "CHANNEL_MESSAGE",
            target: "1274005906610454619",
            predefined_id: "user_announcement",
        }
    ],
}
```

***

#### <mark style="color:orange;">Example 5: Store Coupon</mark>

Real-money store discount:

```json
{
    id: 4,
    emoji: '🎟️',
    name: 'Store Coupon',
    description: '10% discount code for our Tebex store',
    cost: 100000,
    requirement: {
        rankId: 10,
        oneTimePurchase: false,
    },
    reward: [
        {
            type: "COUPON",
            target: "10",
        }
    ],
}
```

***

#### <mark style="color:orange;">Example 6: Multiple Rewards</mark>

Item granting multiple rewards at once:

```json
{
    id: 5,
    emoji: '🎉',
    name: 'Ultimate Package',
    description: 'VIP role + 3 lootboxes + announcement',
    cost: 75000,
    requirement: {
        rankId: 8,
        oneTimePurchase: true,
    },
    reward: [
        {
            type: "ROLE",
            target: "804354029076348959",
        },
        {
            type: "LOOTBOX",
            target: null,
            amount: 3,
        },
        {
            type: "CHANNEL_MESSAGE",
            target: "1274005906610454619",
            predefined_id: "vip_welcome",
        }
    ],
}
```

***

## <mark style="color:blue;">Part 3: Streak Bonuses</mark>

### <mark style="color:yellow;">Understanding Streaks</mark>

Streaks encourage users to claim their daily/weekly rewards consistently. Each consecutive claim increases their streak counter, which adds bonus coins on top of the base reward.

```json
streaks: {
    daily: {
        enabled: true,
        bonus: "%streak% * 25 + 25",
    },
    weekly: {
        enabled: true,
        bonus: "%streak% * 250 + 250",
    }
}
```

***

### <mark style="color:yellow;">Streak Configuration</mark>

**enabled** (Boolean)

* `true` = Streak bonuses are active
* `false` = Only base reward is given (no streak tracking)

**bonus** (String - Formula)

* Mathematical formula to calculate bonus coins
* `%streak%` placeholder = Current streak count (0, 1, 2, 3...)
* Can use operators: `+`, `-`, `*`, `/`, `( )`

***

### <mark style="color:yellow;">Streak Formula Examples</mark>

#### <mark style="color:orange;">Linear Growth</mark>

```json
bonus: "%streak% * 25 + 25"
```

* Streak 0: 0 \* 25 + 25 = **25 coins**
* Streak 1: 1 \* 25 + 25 = **50 coins**
* Streak 5: 5 \* 25 + 25 = **150 coins**
* Streak 10: 10 \* 25 + 25 = **275 coins**

***

#### <mark style="color:orange;">Exponential Growth</mark>

```json
bonus: "%streak% * %streak% * 10"
```

* Streak 0: 0 \* 0 \* 10 = **0 coins**
* Streak 1: 1 \* 1 \* 10 = **10 coins**
* Streak 5: 5 \* 5 \* 10 = **250 coins**
* Streak 10: 10 \* 10 \* 10 = **1000 coins**

***

#### <mark style="color:orange;">Capped Growth</mark>

For formulas, you'll need to handle caps in your economy system logic, but you can design slower growth:

```json
bonus: "%streak% * 10"
```

* Streak 0: 0 \* 10 = **0 coins**
* Streak 10: 10 \* 10 = **100 coins**
* Streak 30: 30 \* 10 = **300 coins**

***

### <mark style="color:yellow;">How Streaks Work</mark>

1. User claims their daily/weekly reward
2. Base reward is given (from `coins` section)
3. Streak counter increases by 1
4. Bonus is calculated using the formula
5. Bonus is added to the base reward
6. If user misses the claim window, streak resets to 0

**Example with Daily:**

* Base daily reward: `125` coins
* User on 5-day streak
* Bonus formula: `%streak% * 25 + 25` = 5 \* 25 + 25 = `150` coins
* **Total reward: 125 + 150 = 275 coins**

***

## <mark style="color:blue;">Part 4: Game Wagers</mark>

### <mark style="color:yellow;">Understanding Wagers</mark>

The wager system lets users bet coins on games. If they win, they get their wager back plus additional coins based on the multiplier.

```json
game_wagers: {
    enabled: true,
    max: 1000,
    cooldown: "5m",
    multipliers: {
        gtn: 1.5,
        hangman: 1.5,
        rps: 2,
        trivia: 2.5,
    }
}
```

***

### <mark style="color:yellow;">Wager Configuration</mark>

**enabled** (Boolean)

* `true` = Wager system is active for games
* `false` = Wagers are disabled (only base game rewards apply)

**max** (Number)

* Maximum coins that can be wagered on a single game
* Prevents large losses/gains that imbalance economy
* Recommended: `500-2000` coins

**cooldown** (String)

* Time users must wait between placing wagers
* Prevents rapid betting/grinding
* Format: `"5m"`, `"1h"`, `"30s"`
* Recommended: `"5m"` to `"30m"`

**multipliers** (Object)

* Defines payout multiplier for each game type
* Higher multiplier = Higher difficulty/risk
* Format: `game_name: multiplier`

***

### <mark style="color:yellow;">Game Multipliers</mark>

**gtn** (Guess The Number)

* Recommended: `1.5` - `2.0`
* Easy game, lower multiplier

**hangman**

* Recommended: `1.5` - `2.0`
* Medium difficulty

**rps** (Rock Paper Scissors)

* Recommended: `1.5` - `2.5`
* Pure luck, moderate multiplier

**trivia**

* Recommended: `2.0` - `3.0`
* Knowledge-based, higher multiplier

***

### <mark style="color:yellow;">Wager Calculation Example</mark>

User wagers `500` coins on Trivia (2.5x multiplier):

**If they win:**

* Wager returned: `500` coins
* Winnings: `500 * 2.5 = 1,250` coins
* **Total gained: 1,750 coins** (net +1,250)

**If they lose:**

* **Total lost: 500 coins** (wager is taken)

***

## <mark style="color:blue;">Part 5: Cooldowns</mark>

### <mark style="color:yellow;">Understanding Cooldowns</mark>

Cooldowns prevent spam and balance the economy by limiting how often certain actions can be performed.

```json
cooldowns: {
    spy: "30m",
    rob: "3h",
    beg: "2h",
}
```

***

### <mark style="color:yellow;">Cooldown Configuration</mark>

**spy** (String)

* Cooldown for `/bank spy` command
* Prevents constant wealth checking
* Recommended: `"15m"` to `"1h"`

**rob** (String)

* Cooldown for `/rob` command
* Prevents repeated robbery attempts
* Recommended: `"1h"` to `"6h"`
* Should be longer due to potential for large gains/losses

**beg** (String)

* Cooldown for `/beg` command
* Limits passive income from begging
* Recommended: `"30m"` to `"3h"`

***

### <mark style="color:yellow;">Time Format</mark>

Use these formats for cooldown values:

* `"30s"` = 30 seconds
* `"5m"` = 5 minutes
* `"2h"` = 2 hours
* `"1d"` = 1 day
* `"1w"` = 1 week

***

## <mark style="color:blue;">Complete Configuration Example</mark>

Here's a balanced economy configuration for a medium-sized server:

```json
config: {
    coins: {
        message_sent: 2,
        invite: 200,
        game_played: 5,
        game_won: 20,
        counting_game: 3,
        level_up: 150,
        daily: 200,
        weekly: 1500,
        calltime_minute: 20,
        approved_suggestion: 300,
        suggestion_vote: 30,
        poll_vote: 30,
        birthday: 5000,
        starboard_message: 250,
        punishment: -3000,
    },

    shop_items: [
        {
            id: 0,
            emoji: '👑',
            name: 'VIP',
            description: 'Permanent VIP role',
            cost: 50000,
            requirement: {
                rankId: 5,
                oneTimePurchase: true,
            },
            reward: [
                { type: "ROLE", target: "YOUR_ROLE_ID" }
            ],
        },
        {
            id: 1,
            emoji: '🪄',
            name: '2x Coin Booster',
            description: 'Double coins for 1 hour',
            cost: 1000,
            requirement: {
                rankId: 0,
                oneTimePurchase: false,
            },
            reward: [
                { type: "BOOSTER", target: "booster_coin_1h_2" }
            ],
        },
        {
            id: 2,
            emoji: '🎁',
            name: 'Lootbox',
            description: 'Random reward box',
            cost: 750,
            requirement: {
                rankId: 0,
                oneTimePurchase: false,
            },
            reward: [
                { type: "LOOTBOX", target: null, amount: 1 }
            ],
        },
    ],

    streaks: {
        daily: {
            enabled: true,
            bonus: "%streak% * 30 + 30",
        },
        weekly: {
            enabled: true,
            bonus: "%streak% * 300 + 300",
        }
    },

    game_wagers: {
        enabled: true,
        max: 1500,
        cooldown: "10m",
        multipliers: {
            gtn: 1.5,
            hangman: 1.75,
            rps: 2,
            trivia: 2.5,
        }
    },

    cooldowns: {
        spy: "30m",
        rob: "4h",
        beg: "2h",
    }
}
```


# Command Maker

Create powerful custom commands and interactive buttons for your Discord server!

## <mark style="color:blue;">Overview</mark>

The **Command Maker** addon empowers you to create custom slash commands and interactive buttons without writing any code. Build automated workflows, create interactive menus, send predefined messages, assign roles, and much more - all through simple configuration.

***

## <mark style="color:blue;">Table of Contents</mark>

1. **Features**
2. **Installation**
3. **Key Concepts**

***

## <mark style="color:blue;">Features</mark>

### <mark style="color:yellow;">Custom Commands</mark>

* <mark style="color:red;">**Up to 5 Custom Commands:**</mark> Create multiple unique slash commands for your server
* <mark style="color:red;">**Command Parameters:**</mark> Add arguments to your commands (user mentions, text input with predefined options)
* <mark style="color:red;">**Flexible Responses:**</mark> Send rich embed messages using predefined message templates
* <mark style="color:red;">**Permission Control:**</mark> Restrict command usage based on your server's permission levels
* <mark style="color:red;">**Advanced Actions:**</mark> Execute multiple actions like role assignment, channel messaging, and DM sending

### <mark style="color:yellow;">Custom Buttons</mark>

* <mark style="color:red;">**Unlimited Custom Buttons:**</mark> Create interactive buttons to attach to any bot message
* <mark style="color:red;">**Multiple Styles:**</mark> Choose from Primary (Blue), Secondary (Gray), Success (Green), Danger (Red), or Link buttons
* <mark style="color:red;">**Custom Emojis:**</mark> Add visual flair with custom or standard Discord emojis
* <mark style="color:red;">**Smart Responses:**</mark> Update existing messages or send new ephemeral/public responses
* <mark style="color:red;">**Automated Workflows:**</mark> Chain actions together for complex automation

***

## <mark style="color:blue;">Installation</mark>

{% hint style="warning" %}
**This is a premium addon!** You must purchase this addon separately and have a valid license.
{% endhint %}

1. Download the Command Maker addon files from your purchase
2. Extract all files into the `plugins/` folder of your Athena Bot installation
3. Restart your bot to load the addon
4. Configure the addon using the `command_maker.json` file in your `configuration/` folder

***

## <mark style="color:blue;">Key Concepts</mark>

### <mark style="color:yellow;">Predefined Messages</mark>

Predefined messages are reusable message templates that you create using the `/sendmsg` and `/editmsg` commands. These templates can include:

* Custom embeds with titles, descriptions, colors, and fields
* Images, thumbnails, and attachments
* Formatted text with markdown support

Once created, you save them with a unique ID and reference that ID in your command or button configuration.

### <mark style="color:yellow;">Actions</mark>

Actions are automated tasks that execute when a command is run or a button is clicked. Available actions include:

* **CHANNEL\_SEND:** Send a message to a specific channel
* **USER\_SEND:** Send a direct message to a user
* **ROLE\_APPLY:** Add a role to the user who executed the command/button
* **ROLE\_REMOVE:** Remove a role from the user who executed the command/button

### <mark style="color:yellow;">Placeholders</mark>

Use dynamic placeholders in your action targets:

* `%user_id%` - The ID of the user who executed the command/clicked the button
* `%string_args_1%` - The value of the first STRING parameter (for commands with parameters)

### <mark style="color:yellow;">Components</mark>

Components (currently buttons) can be attached to any message sent by your bot. Use the `/buttons` command to add your custom buttons to existing bot messages, or reference them in your custom command responses.

***


# Configuration

Complete guide to configuring custom commands and buttons

## <mark style="color:blue;">Getting Started</mark>

The Command Maker addon is configured through the `command_maker.json` file located in your bot's `configuration/` folder. This guide will walk you through creating custom commands and buttons step-by-step.

***

## <mark style="color:blue;">Part 1: Creating Custom Commands</mark>

### <mark style="color:yellow;">Step 1: Understanding Command Structure</mark>

Each custom command is defined within the `commands` object. You can create up to **5 custom commands**. Here's the basic structure:

```json
{
    config: {
        commands: {
            "command_id": {
                enabled: true,
                command_name: "commandname",
                command_description: "Description shown in Discord",
                command_permission: "everyone",
                command_parameters: [],
                command_message_response: { ... },
                actions: []
            }
        }
    }
}
```

***

### <mark style="color:yellow;">Step 2: Basic Command Configuration</mark>

Let's create a simple command that displays your Minecraft server IP:

#### <mark style="color:orange;">1. Set the Command ID</mark>

The command ID is the unique identifier for your command in the config file. This is **not** visible to users.

```json
"minecraft_ip": {
    enabled: true,
```

#### <mark style="color:orange;">2. Set Command Name & Description</mark>

The command name is what users will type in Discord (e.g., `/ip`). The description appears when users view the command.

```json
    command_name: "ip",
    command_description: "Displays the IP address of our Minecraft server",
```

#### <mark style="color:orange;">3. Set Permissions</mark>

Control who can use this command. This must match a permission level from your Core plugin's permission configuration.

```json
    command_permission: "everyone",
```

Common permission levels:

* `everyone` - All server members
* `staff` - Staff members and above
* `admin` - Administrators only
* `management` - Server management only

***

### <mark style="color:yellow;">Step 3: Creating Predefined Messages</mark>

Before configuring the command response, you need to create a predefined message template.

{% hint style="info" %}
**Creating Predefined Messages:**

1. Use the `/sendmsg` command in Discord to create a new message template
2. Design your message with embeds, text, colors, images, etc.
3. Press the **Save** button and assign it a unique **predefined message ID**
4. Use this ID in your command configuration
   {% endhint %}

For our Minecraft IP command, create a predefined message with ID `minecraft_server_ip` that contains your server information.

***

### <mark style="color:yellow;">Step 4: Configure Command Response</mark>

Now configure what happens when the command is executed:

```json
    command_message_response: {
        predefined_message_id: "minecraft_server_ip",
        files: [],
        components: [],
        ephemeral: false
    },
```

**Options explained:**

* `predefined_message_id` - The ID of your saved message template
* `files` - Array of file paths to attach (e.g., `["./images/banner.png"]`)
* `components` - Array of button IDs to add to the message (e.g., `["info_button"]`)
* `ephemeral` - If `true`, only the user who ran the command sees the response

***

### <mark style="color:yellow;">Step 5: Adding Command Parameters</mark>

Parameters allow users to provide input when using your command. You can add parameters for user mentions or text with predefined options.

#### <mark style="color:orange;">Example: Command with User Parameter</mark>

Let's create a `/tutorial` command that sends a tutorial message to a specific user:

```json
"send_tutorial": {
    enabled: true,
    command_name: "tutorial",
    command_description: "Send a tutorial to a user",
    command_permission: "moderator",
    command_parameters: [
        {
            name: "user",
            description: "The user to send the tutorial to",
            required: true,
            type: "USER"
        }
    ],
```

#### <mark style="color:orange;">Example: Command with String Options</mark>

Create a command where users select from predefined options:

```json
    command_parameters: [
        {
            name: "topic",
            description: "Select a tutorial topic",
            options: ["getting-started", "commands", "permissions"],
            required: true,
            type: "STRING"
        }
    ],
```

**Parameter Types:**

* `USER` - User mention/selection
* `STRING` - Text input with optional predefined options

***

### <mark style="color:yellow;">Step 6: Adding Actions</mark>

Actions execute automatically when the command is run. You can chain multiple actions together.

#### <mark style="color:orange;">Available Action Types</mark>

**ROLE\_APPLY** - Give the user a role:

```json
    actions: [
        {
            type: "ROLE_APPLY",
            target: "1234567890123456789"
        }
    ]
```

**ROLE\_REMOVE** - Remove a role from the user:

```json
    actions: [
        {
            type: "ROLE_REMOVE",
            target: "1234567890123456789"
        }
    ]
```

**CHANNEL\_SEND** - Send a message to a specific channel:

```json
    actions: [
        {
            type: "CHANNEL_SEND",
            target: "1234567890123456789",
            predefinedId: "welcome_message"
        }
    ]
```

**USER\_SEND** - Send a DM to a user:

```json
    actions: [
        {
            type: "USER_SEND",
            target: "%user_id%",
            predefinedId: "tutorial_message"
        }
    ]
```

{% hint style="warning" %}
For `CHANNEL_SEND` and `USER_SEND` actions:

* If `predefinedId` is specified, that message template will be sent
* If `predefinedId` is `null` or omitted, the command's main response message will be sent
  {% endhint %}

***

### <mark style="color:yellow;">Step 7: Using Placeholders</mark>

Placeholders allow dynamic values in your actions:

* `%user_id%` - The user who executed the command
* `%string_args_1%` - The value of the first STRING parameter
* `%string_args_2%` - The value of the second STRING parameter (if exists)

**Example:** Send different tutorials based on user selection:

```json
"tutorial_sender": {
    enabled: true,
    command_name: "sendtutorial",
    command_description: "Send a tutorial to a user",
    command_permission: "moderator",
    command_parameters: [
        {
            name: "user",
            description: "The user to send the tutorial to",
            required: true,
            type: "USER"
        },
        {
            name: "tutorial",
            description: "Which tutorial to send",
            options: ["beginner", "advanced", "expert"],
            required: true,
            type: "STRING"
        }
    ],
    command_message_response: {
        predefined_message_id: "tutorial_sent_confirmation",
        files: [],
        components: [],
        ephemeral: true
    },
    actions: [
        {
            type: "USER_SEND",
            target: "%user_id%",
            predefinedId: "%string_args_1%"
        }
    ]
}
```

In this example:

* `%user_id%` will be replaced with the selected user's ID
* `%string_args_1%` will be replaced with the tutorial name ("beginner", "advanced", or "expert")

***

### <mark style="color:yellow;">Complete Command Example</mark>

Here's a fully configured custom command:

```json
"server_ip": {
    enabled: true,
    command_name: "ip",
    command_description: "Get our Minecraft server IP",
    command_permission: "everyone",
    command_parameters: [],
    command_message_response: {
        predefined_message_id: "minecraft_ip_embed",
        files: [],
        components: ["join_button", "rules_button"],
        ephemeral: false
    },
    actions: [
        {
            type: "ROLE_APPLY",
            target: "1234567890123456789"
        },
        {
            type: "CHANNEL_SEND",
            target: "9876543210987654321",
            predefinedId: "new_player_alert"
        }
    ]
}
```

This command:

1. Shows the server IP using the `minecraft_ip_embed` message
2. Adds two buttons to the message
3. Gives the user a "Player" role
4. Sends an alert to a staff channel

***

## <mark style="color:blue;">Part 2: Creating Custom Buttons</mark>

### <mark style="color:yellow;">Step 1: Understanding Button Structure</mark>

Buttons are defined in the `components` object. You can create up to **5 custom buttons**:

```json
{
    config: {
        components: {
            "button_id": {
                enabled: true,
                type: "BUTTON",
                button_name: "Click Me",
                button_emoji: "👆",
                button_type: "Primary",
                button_url: "",
                button_permission: "everyone",
                button_message_response: { ... },
                actions: []
            }
        }
    }
}
```

***

### <mark style="color:yellow;">Step 2: Basic Button Configuration</mark>

#### <mark style="color:orange;">1. Set Button ID & Type</mark>

```json
"info_button": {
    enabled: true,
    type: "BUTTON",
```

#### <mark style="color:orange;">2. Set Button Text & Emoji</mark>

```json
    button_name: "Server Info",
    button_emoji: "📊",
```

Set `button_emoji: false` if you don't want an emoji.

#### <mark style="color:orange;">3. Choose Button Style</mark>

```json
    button_type: "Primary",
```

**Available Styles:**

* `Primary` - Blue button
* `Secondary` - Gray button
* `Success` - Green button
* `Danger` - Red button
* `Link` - URL button (requires `button_url`)

#### <mark style="color:orange;">4. Configure Link Buttons (Optional)</mark>

For `Link` type buttons:

```json
    button_type: "Link",
    button_url: "https://yourserver.com",
```

***

### <mark style="color:yellow;">Step 3: Button Response & Actions</mark>

Button responses work the same as command responses:

```json
    button_permission: "everyone",
    button_message_response: {
        predefined_message_id: "server_stats",
        files: [],
        components: [],
        ephemeral: true,
        message_update: false
    },
    actions: [
        {
            type: "ROLE_APPLY",
            target: "1234567890123456789"
        }
    ]
```

**Special Option:**

* `message_update` - If `true`, updates the message containing the button instead of sending a new message

***

### <mark style="color:yellow;">Complete Button Example</mark>

```json
"verify_button": {
    enabled: true,
    type: "BUTTON",
    button_name: "Verify",
    button_emoji: "✅",
    button_type: "Success",
    button_url: "",
    button_permission: "everyone",
    button_message_response: {
        predefined_message_id: "verification_success",
        files: [],
        components: [],
        ephemeral: true,
        message_update: false
    },
    actions: [
        {
            type: "ROLE_APPLY",
            target: "1234567890123456789"
        },
        {
            type: "ROLE_REMOVE",
            target: "9876543210987654321"
        }
    ]
}
```

This button:

1. Shows a green button with a checkmark
2. Sends an ephemeral success message
3. Gives the user a "Verified" role
4. Removes an "Unverified" role

***

## <mark style="color:blue;">Part 3: Practical Examples</mark>

### <mark style="color:yellow;">Example 1: Server Rules Command</mark>

```json
"rules": {
    enabled: true,
    command_name: "rules",
    command_description: "Display server rules",
    command_permission: "everyone",
    command_parameters: [],
    command_message_response: {
        predefined_message_id: "server_rules",
        files: [],
        components: ["accept_rules"],
        ephemeral: false
    },
    actions: []
}
```

***

### <mark style="color:yellow;">Example 2: Support Ticket Button</mark>

```json
"create_ticket": {
    enabled: true,
    type: "BUTTON",
    button_name: "Create Ticket",
    button_emoji: "🎫",
    button_type: "Primary",
    button_url: "",
    button_permission: "everyone",
    button_message_response: {
        predefined_message_id: "ticket_created",
        files: [],
        components: [],
        ephemeral: true,
        message_update: false
    },
    actions: [
        {
            type: "CHANNEL_SEND",
            target: "1234567890123456789",
            predefinedId: "new_ticket_staff_alert"
        }
    ]
}
```

***

### <mark style="color:yellow;">Example 3: Role Selection Menu</mark>

```json
"get_gamer_role": {
    enabled: true,
    type: "BUTTON",
    button_name: "Gamer",
    button_emoji: "🎮",
    button_type: "Primary",
    button_url: "",
    button_permission: "everyone",
    button_message_response: {
        predefined_message_id: "role_added",
        files: [],
        components: [],
        ephemeral: true,
        message_update: false
    },
    actions: [
        {
            type: "ROLE_APPLY",
            target: "1234567890123456789"
        }
    ]
},
"get_artist_role": {
    enabled: true,
    type: "BUTTON",
    button_name: "Artist",
    button_emoji: "🎨",
    button_type: "Success",
    button_url: "",
    button_permission: "everyone",
    button_message_response: {
        predefined_message_id: "role_added",
        files: [],
        components: [],
        ephemeral: true,
        message_update: false
    },
    actions: [
        {
            type: "ROLE_APPLY",
            target: "9876543210987654321"
        }
    ]
}
```

***

## <mark style="color:blue;">Tips & Best Practices</mark>

{% hint style="success" %}
**Best Practices:**

* Set appropriate permissions to prevent abuse
* Test your commands in a test channel before deploying
* Use ephemeral messages for personal information
* Create predefined messages before configuring commands
  {% endhint %}

{% hint style="warning" %}
**Important Notes:**

* Command names must be unique and cannot override built-in commands
* You can have maximum 5 custom commands
* Button type must be "BUTTON" (more types coming soon)
* Predefined message IDs are case-sensitive
* File paths are relative to your bot's `index.js` file
* Discord limits messages to 25 components (buttons) maximum
  {% endhint %}

***

## <mark style="color:blue;">Troubleshooting</mark>

### <mark style="color:yellow;">Command not appearing in Discord</mark>

* Ensure `enabled: true` is set
* Check that `command_name` is unique and doesn't conflict with existing commands
* Verify the bot has permission to register slash commands
* Restart the bot after making configuration changes

### <mark style="color:yellow;">Predefined message not found</mark>

* Double-check the `predefined_message_id` spelling
* Ensure you've saved the message using `/sendmsg` or `/editmsg`
* Predefined message IDs are case-sensitive

### <mark style="color:yellow;">Actions not executing</mark>

* Verify role/channel IDs are correct (right-click with Developer Mode enabled)
* Check that the bot has permission to assign roles or send messages to channels
* Ensure role hierarchy - bot's role must be higher than the role being assigned

### <mark style="color:yellow;">Buttons not working</mark>

* Verify button ID matches the ID referenced in `components` array
* Check `enabled: true` is set for the button
* Ensure the button type is valid
* For Link buttons, make sure `button_url` is a valid URL


# Hytale

Bridge your Discord server with your Hytale server for seamless cross-platform integration!

## <mark style="color:blue;">Overview</mark>

The **Hytale** addon creates a powerful bridge between your Discord server and your Hytale game server. Enable two-way chat relay, account linking with rewards, real-time server status monitoring, automated ban synchronization, and remote console access - all seamlessly integrated with Athena Bot.

***

## <mark style="color:blue;">Table of Contents</mark>

1. **Features**
2. **Installation**
3. **Server Requirements**
4. **Commands**

***

## <mark style="color:blue;">Features</mark>

### <mark style="color:yellow;">Account Linking System</mark>

* <mark style="color:red;">**Link Discord to Hytale:**</mark> Players can link their Discord account to their in-game Hytale account
* <mark style="color:red;">**Automatic Role Assignment:**</mark> Assign verified roles to linked players
* <mark style="color:red;">**Nickname Synchronization:**</mark> Automatically sync Discord nicknames with Hytale usernames
* <mark style="color:red;">**Discord Rewards:**</mark> Give coins or other Discord rewards when players link their accounts
* <mark style="color:red;">**In-Game Rewards:**</mark> Execute commands to give in-game items or bonuses upon linking
* <mark style="color:red;">**Recurring Rewards:**</mark> Configure rewards to be claimable once, daily, weekly, or monthly
* <mark style="color:red;">**Admin Controls:**</mark> Force link/unlink accounts and manage reward claims

***

### <mark style="color:yellow;">Two-Way Chat Relay</mark>

* <mark style="color:red;">**Discord to Hytale:**</mark> Messages sent in Discord appear in-game
* <mark style="color:red;">**Hytale to Discord:**</mark> In-game chat messages appear in Discord
* <mark style="color:red;">**Reply Support:**</mark> Discord users can reply to Hytale messages and vice versa
* <mark style="color:red;">**Attachment Detection:**</mark> Automatically indicates when Discord messages contain attachments
* <mark style="color:red;">**World Context:**</mark> Optionally show which world/zone the player is in

***

### <mark style="color:yellow;">Real-Time Server Status Panel</mark>

* <mark style="color:red;">**Live Server Information:**</mark> Display current server status in a dedicated Discord embed
* <mark style="color:red;">**Player Count:**</mark> Show online players and max capacity
* <mark style="color:red;">**Performance Metrics:**</mark> Display TPS (ticks per second), memory usage, and uptime
* <mark style="color:red;">**Player List:**</mark> Show all currently online players
* <mark style="color:red;">**Custom Branding:**</mark> Add server name, description, and thumbnail
* <mark style="color:red;">**Refresh Button:**</mark> Manual refresh option for instant updates
* <mark style="color:red;">**Custom Buttons:**</mark> Add links to your website, wiki, or store
* <mark style="color:red;">**Auto-Updates:**</mark> Configurable update intervals (30s, 1m, 5m, etc.)

***

### <mark style="color:yellow;">Event Notifications</mark>

* <mark style="color:red;">**Player Join/Leave:**</mark> Notify your Discord when players connect or disconnect
* <mark style="color:red;">**Death Messages:**</mark> Broadcast player deaths and their causes
* <mark style="color:red;">**World Events:**</mark> Announce boss spawns, invasions, and special events
* <mark style="color:red;">**Zone Discovery:**</mark> Celebrate when players discover new zones or biomes
* <mark style="color:red;">**Server Status:**</mark> Alert when the server goes online or offline

***

### <mark style="color:yellow;">Ban Synchronization</mark>

* <mark style="color:red;">**Discord to Hytale:**</mark> Automatically ban linked Hytale accounts when a user is banned on Discord
* <mark style="color:red;">**Hytale to Discord:**</mark> Automatically ban Discord users when their Hytale account is banned
* <mark style="color:red;">**Custom Ban Commands:**</mark> Configure the exact command used to ban players in-game
* <mark style="color:red;">**Bidirectional Sync:**</mark> Keep both platforms moderated consistently

***

### <mark style="color:yellow;">Remote Console Access</mark>

* <mark style="color:red;">**Execute Commands:**</mark> Run server commands directly from Discord
* <mark style="color:red;">**Console Channel:**</mark> Dedicated channel for sending commands via chat
* <mark style="color:red;">**Console Logging:**</mark> Real-time relay of server console logs to Discord
* <mark style="color:red;">**Filtered Logs:**</mark> Choose which log categories to display (info, warnings, errors, etc.)
* <mark style="color:red;">**Permission-Based:**</mark> Restrict console access to authorized staff only

***

## <mark style="color:blue;">Installation</mark>

{% hint style="warning" %}
**This is a premium addon!** You must purchase this addon separately and have a valid license.
{% endhint %}

### <mark style="color:yellow;">Step 1: Install Discord Bot Addon</mark>

1. Download the Hytale addon files from your purchase
2. Extract all files into the `plugins/` folder of your Athena Bot installation
3. Restart your bot to load the addon
4. Configure the addon using the `hytale.json5` file in your `configuration/` folder

### <mark style="color:yellow;">Step 2: Install Hytale Server Plugin</mark>

{% hint style="info" %}
The Hytale addon includes a **server-side plugin** that must be installed on your Hytale server.
{% endhint %}

1. Locate the Hytale server plugin files included with your download
2. Install the plugin in your Hytale server's mod/plugin directory
3. Configure the `config.json` file in your Hytale server's plugin directory

***

## <mark style="color:blue;">Server Requirements</mark>

### <mark style="color:yellow;">Hytale Server Plugin Configuration</mark>

The Hytale server-side plugin requires a `config.json` file with the following structure:

```json
{
    "athena_license_key": "YOUR-LICENSE-KEY-HERE",
    "hytale_server_api": {
        "hytale_server_api_port": 3333,
        "hytale_server_api_ip_whitelist": false,
        "hytale_server_api_ip_list": ["localhost"]
    },
    "athena_web_api": {
        "authentication_key": "YOUR-API-KEY-HERE",
        "athena_web_api_ip": "localhost",
        "athena_web_api_port": 3111
    },
    "features": {
        "chat_relay": true,
        "player_join": true,
        "player_leave": true,
        "console_relay": true
    }
}
```

{% hint style="danger" %}
**IMPORTANT:** The `athena_web_api.authentication_key` must match the **first API key** configured in your Athena Bot's Web API settings.
{% endhint %}

### <mark style="color:yellow;">Configuration Parameters</mark>

**athena\_license\_key**

* Your Athena Bot license key

**hytale\_server\_api\_port**

* The port the Hytale plugin's API will listen on (default: 3333)
* This is **NOT** your Hytale game server port

**hytale\_server\_api\_ip\_whitelist**

* Enable IP whitelisting for security (recommended: `true` for production)

**hytale\_server\_api\_ip\_list**

* List of allowed IPs that can connect to the Hytale plugin API
* Include your Athena Bot server's IP address

**athena\_web\_api.authentication\_key**

* API key for authenticating with Athena Bot
* **Must match the first API key in your Web API configuration**

**athena\_web\_api\_ip** and **athena\_web\_api\_port**

* IP address and port where your Athena Bot's Web API is accessible

***

## <mark style="color:blue;">Commands</mark>

### <mark style="color:yellow;">User Commands</mark>

**/link**

* Link your Discord account to your Hytale account
* **Usage:** `/link code:<6-digit-code>`
* **Example:** `/link code:A1B2C3`
* Get your link code by typing `/link` in-game on the Hytale server

**/unlink**

* Unlink your Discord account from your Hytale account
* **Usage:** `/unlink`
* Removes linked role and resets nickname if configured

***

### <mark style="color:yellow;">Admin Commands</mark>

**/hytaleconsole execute**

* Execute a command on the Hytale server console
* **Usage:** `/hytaleconsole execute command:<command>`
* **Example:** `/hytaleconsole execute command:give PlayerName Weapon_Sword_Iron`
* **Permission:** Requires management-level access

**/linkadmin force-link**

* Manually link a Discord user to a Hytale account
* **Usage:** `/linkadmin force-link user:<@user> hytale_username:<username>`
* Bypasses the normal linking process

**/linkadmin force-unlink**

* Manually unlink a Discord user's Hytale account
* **Usage:** `/linkadmin force-unlink user:<@user>`
* Useful for fixing incorrect links

**/linkadmin reset-user**

* Reset a user's link reward claims
* **Usage:** `/linkadmin reset-user user:<@user>`
* Allows them to claim rewards again

**/linkadmin reset-all**

* Reset all users' link reward claims
* **Usage:** `/linkadmin reset-all`
* Use when changing reward configurations

***

## <mark style="color:blue;">Getting Help</mark>

Need assistance with the Hytale addon?

* Join the Athena Bot support Discord server
* Check the configuration guide for detailed setup instructions
* Contact support for technical issues or questions

***


# Configuration

Complete guide to configuring the Hytale addon

## <mark style="color:blue;">Getting Started</mark>

The Hytale addon is configured through the `hytale.json(5)` file located in your bot's `configuration/` folder. This guide will walk you through each section to help you set up seamless Discord-Hytale integration.

{% hint style="info" %}
**Remember:** You must also configure the server-side plugin on your Hytale server. See the main Hytale documentation for server setup requirements.
{% endhint %}

***

## <mark style="color:blue;">Part 1: API Connection</mark>

### <mark style="color:yellow;">Connecting to Your Hytale Server</mark>

The first step is configuring how Athena Bot communicates with your Hytale server.

```json5
hytale_server_api: {
    hytale_server_ip: "localhost",
    hytale_server_api_port: 3333
}
```

***

### <mark style="color:yellow;">Configuration Parameters</mark>

**hytale\_server\_ip** (String)

* The IP address of your Hytale server
* Use `"localhost"` if the bot and server are on the same machine
* Use the server's public IP if they're on different machines
* **Examples:**
  * Same machine: `"localhost"`
  * Different machine: `"192.168.1.100"` or `"play.example.com"`

**hytale\_server\_api\_port** (Number)

* The port the Hytale server plugin's API listens on
* **Must match** the port in your Hytale server's `config.json`
* **Default:** `3333`
* This is **NOT** your Hytale game server port!

{% hint style="warning" %}
**Firewall Configuration:** If your bot and Hytale server are on different machines, ensure the API port is open in your firewall and accessible to the bot.
{% endhint %}

***

## <mark style="color:blue;">Part 2: Account Linking</mark>

### <mark style="color:yellow;">Linked Role Assignment</mark>

Automatically assign a Discord role to players who link their accounts.

```json5
account_linking: {
    linked_role: {
        enabled: false,
        role_id: "1457834856447873355"
    }
}
```

**enabled** (Boolean)

* Set to `true` to enable automatic role assignment
* Set to `false` to disable this feature

**role\_id** (String)

* The Discord role ID to assign to linked players
* Right-click a role in Discord → Copy ID (requires Developer Mode)
* Use this to give linked players special permissions or access

***

### <mark style="color:yellow;">Nickname Synchronization</mark>

Automatically update Discord nicknames to include Hytale usernames.

```json5
nickname_sync: {
    enabled: true,
    format: "[%hytale_name%] %discord_name%"
}
```

**enabled** (Boolean)

* Set to `true` to automatically sync nicknames when players link accounts
* Set to `false` to leave nicknames unchanged

**format** (String)

* The template for the synchronized nickname
* **Available Placeholders:**
  * `%hytale_name%` - The player's Hytale username
  * `%discord_name%` - The user's Discord username
  * `%discord_display_name%` - The user's Discord display name
* **Examples:**
  * `"[%hytale_name%] %discord_name%"` → `[Steve123] JohnDoe`
  * `"%hytale_name%"` → `Steve123`
  * `"%hytale_name% | %discord_display_name%"` → `Steve123 | John`
* Maximum length: 32 characters (Discord limit)

***

### <mark style="color:yellow;">Discord Rewards</mark>

Give coins or other Discord-based rewards when players link their accounts.

```json5
discord_rewards: {
    enabled: true,
    recurrence: "once",
    rewards: {
        coins: 1000
    }
}
```

**enabled** (Boolean)

* Set to `true` to give Discord rewards upon linking
* Set to `false` to disable Discord rewards

**recurrence** (String)

* How often players can claim Discord linking rewards
* **Options:**
  * `"once"` - One-time reward, never claimable again
  * `"24h"` - Claimable once every 24 hours
  * `"7d"` - Claimable once every 7 days
  * `"30d"` - Claimable once every 30 days

**rewards.coins** (Number)

* Amount of economy coins to give
* Set to `0` to disable coin rewards
* Requires the Economy addon to be installed
* **Recommended values:**
  * One-time: `500-2000` coins
  * Daily: `100-500` coins
  * Weekly: `1000-3000` coins

{% hint style="info" %}
**Adding More Discord Rewards:** Future updates may include additional reward types like XP, badges, or items. Currently, only coins are supported.
{% endhint %}

***

### <mark style="color:yellow;">In-Game Rewards</mark>

Execute commands on the Hytale server to give items, currency, or other bonuses when players link.

```json5
ingame_rewards: {
    enabled: true,
    recurrence: "once",
    commands: [
        "give %player% Weapon_Axe_Iron_Rusty"
    ]
}
```

**enabled** (Boolean)

* Set to `true` to execute in-game reward commands
* Set to `false` to disable in-game rewards

**recurrence** (String)

* How often players can claim in-game linking rewards
* Same options as Discord rewards: `"once"`, `"24h"`, `"7d"`, `"30d"`

**commands** (Array)

* List of commands to execute on the Hytale server
* Commands run with administrator privileges
* **Available Placeholders:**
  * `%player%` - The player's Hytale username
* **Examples:**
  * `"give %player% Weapon_Sword_Iron"` - Give an iron sword
  * `"give %player% Item_Currency_Gold 100"` - Give 100 gold
  * `"teleport %player% SpawnPoint"` - Teleport to spawn
  * `"addpermission %player% vip"` - Grant VIP permission

You can add multiple commands:

```json5
commands: [
    "give %player% Weapon_Axe_Iron_Rusty",
    "give %player% Item_Currency_Gold 500",
    "give %player% Armor_Chest_Leather"
]
```

***

## <mark style="color:blue;">Part 3: Ban Synchronization</mark>

### <mark style="color:yellow;">Keeping Bans Synchronized</mark>

Automatically synchronize bans between Discord and your Hytale server.

```json5
ban_sync: {
    discord_to_hytale: false,
    hytale_to_discord: false,
    ban_command: "ban %player% %reason%"
}
```

***

### <mark style="color:yellow;">Configuration Parameters</mark>

**discord\_to\_hytale** (Boolean)

* Set to `true` to automatically ban linked Hytale accounts when their Discord account is banned
* Set to `false` to disable this sync direction
* When a user with a linked account is banned on Discord, their Hytale account will be banned automatically

**hytale\_to\_discord** (Boolean)

* Set to `true` to automatically ban Discord accounts when their linked Hytale account is banned
* Set to `false` to disable this sync direction
* When a linked player is banned on Hytale, their Discord account will be banned from the server

**ban\_command** (String)

* The command used to ban players on your Hytale server
* **Available Placeholders:**
  * `%player%` - The player's Hytale username
  * `%reason%` - The ban reason from Discord
* **Examples:**
  * `"ban %player% %reason%"`
  * `"blacklist add %player% %reason%"`
  * `"punishment ban %player% permanent %reason%"`

{% hint style="danger" %}
**Use Ban Sync Carefully:** Enabling bidirectional ban sync can be powerful but may lead to unintended consequences. Consider enabling only one direction, or carefully test with a non-linked account first.
{% endhint %}

***

## <mark style="color:blue;">Part 4: Server Status Panel</mark>

### <mark style="color:yellow;">Real-Time Server Information</mark>

Display a live-updating embed in Discord showing your Hytale server's current status.

```json5
server_status_panel: {
    enabled: false,
    update_interval: "1m",
    server_name: "My Hytale Server",
    server_description: "An awesome Hytale server!",
    thumbnail: "",
    show_ip: false,
    ip_address: "play.example.com",
    port: 5520,
    max_players: 100,
    show_tps: true,
    show_memory: true,
    show_uptime: true,
    show_player_list: true,
    show_refresh_button: true,
    buttons: []
}
```

***

### <mark style="color:yellow;">Basic Configuration</mark>

**enabled** (Boolean)

* Set to `true` to enable the server status panel
* Set to `false` to disable it
* When enabled, a dedicated embed will be posted in your configured channel

**update\_interval** (String)

* How often to automatically refresh the status panel
* **Examples:**
  * `"30s"` - Every 30 seconds (high frequency)
  * `"1m"` - Every 1 minute (recommended)
  * `"5m"` - Every 5 minutes (low frequency)
* Shorter intervals provide more real-time data but use more API calls

**server\_name** (String)

* The display name for your server in the status panel
* Appears as the embed title

**server\_description** (String)

* A brief description of your server
* Appears below the server name

**thumbnail** (String)

* URL to an image to display in the status panel
* Leave empty (`""`) to disable
* Recommended size: 128x128 pixels or larger
* **Example:** `"https://i.imgur.com/yourimage.png"`

***

### <mark style="color:yellow;">Connection Information</mark>

**show\_ip** (Boolean)

* Set to `true` to display the server IP and port
* Set to `false` to hide connection information

**ip\_address** (String)

* The IP address or domain players use to connect
* Only displayed if `show_ip` is `true`
* **Examples:** `"play.example.com"`, `"192.168.1.100"`

**port** (Number)

* The game port players use to connect
* Only displayed if `show_ip` is `true`
* **Default Hytale Port:** `5520`

**max\_players** (Number)

* The maximum number of players your server supports
* Used to display "X/Y players online"

***

### <mark style="color:yellow;">Performance Metrics</mark>

**show\_tps** (Boolean)

* Set to `true` to display TPS (ticks per second)
* TPS indicates server performance (20 TPS = optimal)

**show\_memory** (Boolean)

* Set to `true` to display server memory usage
* Shows used memory and total available memory

**show\_uptime** (Boolean)

* Set to `true` to display how long the server has been running
* Shows days, hours, and minutes since last restart

***

### <mark style="color:yellow;">Player Information</mark>

**show\_player\_list** (Boolean)

* Set to `true` to show a list of all online players
* Set to `false` to only show player count

**show\_refresh\_button** (Boolean)

* Set to `true` to add a refresh button to the status panel
* Players can click the button to manually update the information
* Useful when auto-updates are infrequent

***

### <mark style="color:yellow;">Custom Buttons</mark>

Add custom buttons with links to external resources.

```json5
buttons: [
    { Label: "Website", Emoji: "🌐", URL: "https://example.com" },
    { Label: "Discord", Emoji: "💬", URL: "https://discord.gg/yourinvite" },
    { Label: "Vote", Emoji: "⭐", URL: "https://vote.example.com" }
]
```

Each button requires:

* **Label** (String) - The button text
* **Emoji** (String) - An emoji to display (optional, use `""` to omit)
* **URL** (String) - The link the button opens

You can add up to 5 buttons per status panel.

***

## <mark style="color:blue;">Part 5: Features & Event Notifications</mark>

### <mark style="color:yellow;">Chat Relay</mark>

```json5
features: {
    chat_relay: true
}
```

**chat\_relay** (Boolean)

* Set to `true` to enable two-way chat relay between Discord and Hytale
* Discord messages appear in-game, and in-game messages appear in Discord
* Requires a dedicated chat channel to be configured

***

### <mark style="color:yellow;">Player Events</mark>

```json5
player_join_leave: true
```

**player\_join\_leave** (Boolean)

* Set to `true` to send notifications when players join or leave the server
* Displays player names and connection status
* Set to `false` to disable join/leave messages

***

### <mark style="color:yellow;">Server Status Updates</mark>

```json5
server_status_updates: true
```

**server\_status\_updates** (Boolean)

* Set to `true` to send alerts when the server goes online or offline
* Useful for monitoring server crashes or restarts
* Set to `false` to disable status alerts

***

### <mark style="color:yellow;">Game Event Notifications</mark>

```json5
death_messages: true,
world_events: true,
zone_discovery: true
```

**death\_messages** (Boolean)

* Set to `true` to broadcast player deaths and their causes to Discord
* Examples: "Steve123 was slain by a Trork" or "Jane456 fell to their death"

**world\_events** (Boolean)

* Set to `true` to announce major world events
* Examples: Boss spawns, invasions, special encounters
* Helps coordinate community participation

**zone\_discovery** (Boolean)

* Set to `true` to celebrate when players discover new zones or biomes
* Encourages exploration and creates excitement

***

### <mark style="color:yellow;">Chat Enhancements</mark>

```json5
show_world_in_chat: true
```

**show\_world\_in\_chat** (Boolean)

* Set to `true` to include the player's current world/zone in chat messages
* Format: `[Hytale] [Orbis] Steve123: Hello!`
* Set to `false` to only show player names

***

### <mark style="color:yellow;">Console Access</mark>

```json5
console_channel: true,
console_logging: true
```

**console\_channel** (Boolean)

* Set to `true` to enable a dedicated channel for executing server commands
* Staff can type commands directly in Discord, and they execute on the server
* Requires a console channel to be configured

**console\_logging** (Boolean)

* Set to `true` to relay server console logs to Discord
* Displays real-time server output, warnings, and errors
* Requires a console logging channel to be configured

***

### <mark style="color:yellow;">Console Log Filtering</mark>

Control which types of console messages are relayed to Discord.

```json5
console_relay: {
    server_info: true,
    server_warning: true,
    server_error: true,
    command_log: true,
    player_event: true
}
```

**server\_info** (Boolean)

* General server information messages
* Examples: "Server started", "World loaded"

**server\_warning** (Boolean)

* Warning messages that don't stop the server
* Examples: "Plugin took 5s to load", "High memory usage"

**server\_error** (Boolean)

* Critical error messages
* Examples: "Failed to connect to database", "Plugin crash"

**command\_log** (Boolean)

* Logs of commands executed by players or the console
* Examples: "Steve123 executed: /give @self Item\_Gold"

**player\_event** (Boolean)

* Player-related events beyond join/leave
* Examples: Achievements, level-ups, purchases

{% hint style="info" %}
**Performance Tip:** If console logging is overwhelming your Discord channel, disable less important categories like `server_info` and `player_event`.
{% endhint %}

***

## <mark style="color:blue;">Part 6: Channel Configuration</mark>

### <mark style="color:yellow;">Setting Up Channels</mark>

The Hytale addon requires specific Discord channels to be configured for different features.

Use the `/setup` commands in Discord to assign channels:

* **Hytale Chat & Events** - Where chat relay and event notifications are sent
* **Hytale Console** - Where staff can execute server commands (if enabled)
* **Hytale Console Logs** - Where console output is relayed (if enabled)
* **Hytale Server Status** - Where the live status panel is displayed (if enabled)

{% hint style="warning" %}
**Channel Permissions:** Ensure the bot has permissions to send messages, embeds, and manage messages in all configured channels.
{% endhint %}

***

## <mark style="color:blue;">Example Configurations</mark>

### <mark style="color:yellow;">Minimal Setup (Chat Relay Only)</mark>

```json5
{
    config: {
        hytale_server_api: {
            hytale_server_ip: "localhost",
            hytale_server_api_port: 3333
        },
        account_linking: {
            linked_role: { enabled: false },
            nickname_sync: { enabled: false },
            discord_rewards: { enabled: false },
            ingame_rewards: { enabled: false }
        },
        ban_sync: {
            discord_to_hytale: false,
            hytale_to_discord: false
        },
        server_status_panel: {
            enabled: false
        },
        features: {
            chat_relay: true,
            player_join_leave: true,
            server_status_updates: true,
            death_messages: false,
            world_events: false,
            zone_discovery: false,
            show_world_in_chat: false,
            console_channel: false,
            console_logging: false
        }
    }
}
```

***

### <mark style="color:yellow;">Full-Featured Setup</mark>

```json5
{
    config: {
        hytale_server_api: {
            hytale_server_ip: "play.example.com",
            hytale_server_api_port: 3333
        },
        account_linking: {
            linked_role: {
                enabled: true,
                role_id: "1457834856447873355"
            },
            nickname_sync: {
                enabled: true,
                format: "[%hytale_name%] %discord_name%"
            },
            discord_rewards: {
                enabled: true,
                recurrence: "7d",
                rewards: { coins: 1500 }
            },
            ingame_rewards: {
                enabled: true,
                recurrence: "once",
                commands: [
                    "give %player% Weapon_Sword_Iron",
                    "give %player% Item_Currency_Gold 1000"
                ]
            }
        },
        ban_sync: {
            discord_to_hytale: true,
            hytale_to_discord: false,
            ban_command: "ban %player% %reason%"
        },
        server_status_panel: {
            enabled: true,
            update_interval: "1m",
            server_name: "Orbis Legends",
            server_description: "The premier Hytale survival experience!",
            thumbnail: "https://i.imgur.com/serverlogo.png",
            show_ip: true,
            ip_address: "play.example.com",
            port: 5520,
            max_players: 100,
            show_tps: true,
            show_memory: true,
            show_uptime: true,
            show_player_list: true,
            show_refresh_button: true,
            buttons: [
                { Label: "Website", Emoji: "🌐", URL: "https://example.com" },
                { Label: "Vote", Emoji: "⭐", URL: "https://vote.example.com" }
            ]
        },
        features: {
            chat_relay: true,
            player_join_leave: true,
            server_status_updates: true,
            death_messages: true,
            world_events: true,
            zone_discovery: true,
            show_world_in_chat: true,
            console_channel: true,
            console_logging: true,
            console_relay: {
                server_info: true,
                server_warning: true,
                server_error: true,
                command_log: false,
                player_event: false
            }
        }
    }
}
```

***

## <mark style="color:blue;">Troubleshooting</mark>

### <mark style="color:yellow;">Bot Can't Connect to Hytale Server</mark>

* Verify the IP address and port are correct
* Ensure the Hytale server plugin is installed and running
* Check firewall rules allow connections on the API port
* Confirm the API key matches in both config files

### <mark style="color:yellow;">Chat Relay Not Working</mark>

* Ensure `chat_relay` is set to `true`
* Verify the chat channel is configured in Discord
* Check that the Hytale server plugin is receiving messages
* Confirm both `features.chat_relay` is enabled in the server plugin config

### <mark style="color:yellow;">Link Rewards Not Given</mark>

* Verify rewards are `enabled: true`
* For Discord rewards, ensure the Economy addon is installed
* Check that `recurrence` settings aren't blocking repeated claims
* Use `/linkadmin reset-user` to reset a specific user's claims

### <mark style="color:yellow;">Status Panel Not Updating</mark>

* Confirm `enabled: true` in `server_status_panel`
* Verify the status channel is configured
* Check that the Hytale server is online and responding
* Ensure `update_interval` is a valid time format

***

## <mark style="color:blue;">Need More Help?</mark>

If you encounter issues not covered here:

* Review the main Hytale addon documentation
* Join the Athena Bot support Discord server
* Check that both the bot addon and server plugin are up to date
* Contact support with your configuration file and error logs

***


# Invoice

Create and manage PayPal invoices directly from Discord.

## <mark style="color:blue;">Overview</mark>

The **Invoice** addon lets your staff create PayPal invoices directly from Discord, share payment links or QR codes, and track payment status without leaving the server. It supports optional partial payments, fee handling, and webhook-driven status updates.

***

## <mark style="color:blue;">Table of Contents</mark>

1. **Features**
2. **Installation**
3. **How It Works**
4. **Commands**
5. **Webhooks and Logs**

***

## <mark style="color:blue;">Features</mark>

### <mark style="color:yellow;">Invoice Creation</mark>

* <mark style="color:red;">**Create PayPal invoices from Discord:**</mark> Use a slash command to generate invoices with item, price, and customer details
* <mark style="color:red;">**Pay link and QR code:**</mark> Share a direct PayPal pay link and optional QR code
* <mark style="color:red;">**Fee handling:**</mark> Automatically add a percentage fee to invoice totals
* <mark style="color:red;">**Optional partial payments:**</mark> Allow partial payments with an enforced minimum

***

### <mark style="color:yellow;">Status Tracking</mark>

* <mark style="color:red;">**Live status sync:**</mark> Refresh invoice status from PayPal on demand
* <mark style="color:red;">**Paid/partial/ cancelled states:**</mark> Track payment progress and close out invoices automatically
* <mark style="color:red;">**Webhook updates:**</mark> Auto-update invoice status when PayPal sends events

***

### <mark style="color:yellow;">Logging and Visibility</mark>

* <mark style="color:red;">**Dedicated logs channel:**</mark> Log invoice events in a configured Discord channel
* <mark style="color:red;">**Audit-friendly embeds:**</mark> Consistent log entries for created, paid, cancelled, and refunded invoices

***

## <mark style="color:blue;">Installation</mark>

{% hint style="warning" %}
**This is a premium addon!** You must purchase this addon separately and have a valid license.
{% endhint %}

1. Download the Invoice addon files from your purchase
2. Extract all files into the `plugins/` folder of your Athena Bot installation
3. Restart your bot to load the addon
4. Configure the addon using the `invoice.json5` file in your `configuration/` folder

***

## <mark style="color:blue;">How It Works</mark>

### <mark style="color:yellow;">1. Configure PayPal</mark>

Add your PayPal REST API client ID and secret, then choose sandbox or live mode. A PayPal **Business** account is required to create live API credentials. Optional: enable webhooks for automatic status updates.

### <mark style="color:yellow;">2. Create an Invoice</mark>

Use `/invoice create` to generate a PayPal invoice. The bot posts an embed with buttons for:

* Pay link (opens PayPal)
* QR code (for mobile payments)
* Resync (manual status refresh)
* Cancel (close the invoice)

### <mark style="color:yellow;">3. Track Status</mark>

Invoices are stored and can be viewed with `/invoice view`. Status changes are synced via PayPal API or webhooks.

***

## <mark style="color:blue;">Commands</mark>

### <mark style="color:yellow;">Staff Commands</mark>

**/invoice create**

* Create a new invoice
* **Options:** `customer` (user), `price` (1-5000), `item` (text), `email` (optional)

**/invoice view**

* View a previously created invoice
* **Options:** `id` (invoice ID)

**/invoice cancel**

* Cancel an existing invoice
* **Options:** `id` (invoice ID)

***

## <mark style="color:blue;">Webhooks and Logs</mark>

### <mark style="color:yellow;">PayPal Webhooks</mark>

If you enable webhooks, configure PayPal to send events to:

```
http://<host_ip>:<web_api_port>/api/paypal
```

Recommended events:

* `INVOICING.INVOICE.CREATED`
* `INVOICING.INVOICE.PAID`
* `INVOICING.INVOICE.PARTIALLY_PAID`
* `INVOICING.INVOICE.CANCELLED`
* `INVOICING.INVOICE.REFUNDED`

### <mark style="color:yellow;">Discord Logs</mark>

When enabled, the addon logs invoice activity in the `paypal_invoice_logs` channel.


# Configuration

## <mark style="color:blue;">Introduction</mark>

The Invoice addon is configured through `invoice.json5` in your `configuration/` folder. This file controls your PayPal credentials, invoice defaults, partial payment rules, and logging behavior.

***

## <mark style="color:blue;">Quick Start</mark>

1. Add your PayPal REST API `client_id` and `client_secret`
2. Set `is_live` to `false` for sandbox or `true` for live
3. Configure your merchant and invoice defaults
4. (Optional) Enable webhooks and add your PayPal webhook ID

***

## <mark style="color:blue;">Full Example</mark>

```json5
{
	config: {
		paypal: {
			paypal_client: {
				client_id: "",
				client_secret: "",
				is_live: false,
				webhooks: {
					enabled: false,
					webhook_id: "",
				},
			},

			merchant: {
				business_name: "Test Business",
				email_address: "",
				website_url: "https://example.com",
				logo_url: "",
				additional_notes: "",
			},

			invoice: {
				fee_in_percent: 5,
				currency_code: "USD",
				note: "",
				terms_and_conditions: "Your terms and conditions",
			},

			minimum_payment: {
				enabled: true,
				minimum_in_percent: 50,
			},

			settings: {
				allow_partial_payments: false,
			},

			logs: {
				invoice_created: true,
				invoice_paid: true,
				invoice_cancelled: true,
				invoice_refunded: true,
			},
		},
	}
}
```

***

## <mark style="color:blue;">PayPal Client</mark>

### <mark style="color:yellow;">Creating a PayPal Application</mark>

You must have a **PayPal Business** account to generate API credentials for live payments.

1. Open the PayPal Developer Portal: [Developer Portal](https://developer.paypal.com/developer/applications/)
2. Create an app for **Sandbox** (testing) or **Live** (production)
3. Copy the **Client ID** and **Secret** into `paypal.paypal_client.client_id` and `paypal.paypal_client.client_secret`
4. Set `is_live` to `true` for live credentials, or `false` for sandbox

***

### <mark style="color:yellow;">paypal.paypal\_client</mark>

**client\_id**

* PayPal REST API client ID

**client\_secret**

* PayPal REST API client secret

**is\_live**

* `false` = sandbox environment
* `true` = live production environment

### <mark style="color:yellow;">paypal.paypal\_client.webhooks</mark>

**enabled**

* Enable PayPal webhook verification and automatic status updates

**webhook\_id**

* PayPal webhook ID used to validate incoming webhook signatures

***

## <mark style="color:blue;">Merchant Details</mark>

### <mark style="color:yellow;">paypal.merchant</mark>

**business\_name**

* Store or business name shown on invoices

**email\_address**

* Primary PayPal email used for receiving payments

**website\_url**

* Website shown on invoices

**logo\_url**

* Optional logo image URL shown on the PayPal invoice page

**additional\_notes**

* Extra notes shown to the customer on invoices

***

## <mark style="color:blue;">Invoice Defaults</mark>

### <mark style="color:yellow;">paypal.invoice</mark>

**fee\_in\_percent**

* Percentage fee added to the invoice total

**currency\_code**

* Default invoice currency (e.g. `USD`, `EUR`, `GBP`)

**note**

* Optional note attached to each invoice

**terms\_and\_conditions**

* Terms shown at the bottom of each invoice

***

## <mark style="color:blue;">Partial Payments</mark>

### <mark style="color:yellow;">paypal.settings</mark>

**allow\_partial\_payments**

* Allow customers to pay in multiple transactions

### <mark style="color:yellow;">paypal.minimum\_payment</mark>

**enabled**

* Enforce a minimum payment amount

**minimum\_in\_percent**

* Minimum payment as a percentage of the invoice total

***

## <mark style="color:blue;">Logging</mark>

### <mark style="color:yellow;">paypal.logs</mark>

Enable or disable logging per event. Logs are posted to the `paypal_invoice_logs` channel.

* **invoice\_created**
* **invoice\_paid**
* **invoice\_cancelled**
* **invoice\_refunded**

***

## <mark style="color:blue;">Webhook Notes</mark>

If you enable webhooks, configure PayPal to send invoice events to:

```
http://<host_ip>:<web_api_port>/api/paypal
```

Make sure your Athena Web API is reachable from PayPal and that the webhook ID matches `paypal.paypal_client.webhooks.webhook_id`. **Important:** Ensure you select *only* the invoice events to be sent when configuring the webhook in PayPal.


# Home

Learn how to build AthenaBot addons.

#### 👋 Welcome!

Welcome to the Addon API guide for AthenaBot. This section walks you through creating plugins, the recommended project structure, and links to useful resources.

For the most up to date version of the developer docs, please visit our GitHub wiki: [AthenaBot Plugin Template Wiki](https://github.com/Zeroknights16/AthenaBot-PluginTemplate/wiki).

If you have questions or suggestions to improve the plugin template or documentation, please open a ticket in our [Support Discord](https://discord.iynxdev.com/).

***

Happy building!

\~ Zeroknights, Developer & Executive @ Iynx Development


# Getting Started

This page explains how to create your own plugin for AthenaBot using the [Plugin Template](https://github.com/Zeroknights16/AthenaBot-PluginTemplate). The internal Developer API makes it easy to extend AthenaBot’s functionality without touching the core code.

{% hint style="warning" %}
Familiarity with Node.js and discord.js is required to follow this documentation.
{% endhint %}

***

## 1. Setting up your editor

If you are using Visual Studio Code, you can enable typings for AthenaBot by creating a configuration file in the root directory. This will help you see available functions directly in your editor.

```json
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "Node",
    "target": "ES2020",
    "jsx": "react",
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "baseUrl": "./",
    "paths": {
      "*": ["types/*"]
    }
  },
  "exclude": [
    "node_modules",
    "**/node_modules/*"
  ]
}
```

We also use [ESLint](https://www.npmjs.com/package/eslint) to keep the codebase clean and consistent. If you want to follow the same style rules, create a file called `.eslintrc.json` in the root directory and paste the following:

```json
{
  "extends": ["eslint:recommended"],
  "env": {
    "node": true,
    "es6": true
  },
  "parserOptions": {
    "ecmaVersion": 2020
  },
  "rules": {
    "brace-style": ["error", "stroustrup", { "allowSingleLine": true }],
    "comma-dangle": ["error", "always-multiline"],
    "comma-spacing": "error",
    "comma-style": "error",
    "curly": ["error", "multi-line", "consistent"],
    "dot-location": ["error", "property"],
    "handle-callback-err": "off",
    "indent": ["error", "tab"],
    "max-nested-callbacks": ["error", { "max": 4 }],
    "max-statements-per-line": ["error", { "max": 2 }],
    "no-console": "off",
    "no-empty-function": "error",
    "no-floating-decimal": "error",
    "no-inline-comments": "off",
    "no-lonely-if": "error",
    "no-multi-spaces": "error",
    "no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF": 0 }],
    "no-shadow": ["error", { "allow": ["err", "resolve", "reject"] }],
    "no-trailing-spaces": ["error"],
    "no-var": "off",
    "object-curly-spacing": ["error", "always"],
    "prefer-const": "error",
    "quotes": ["error", "single"],
    "semi": ["error", "always"],
    "space-before-blocks": "error",
    "space-before-function-paren": ["error", {
      "anonymous": "never",
      "named": "never",
      "asyncArrow": "always"
    }],
    "space-in-parens": "error",
    "space-infix-ops": "error",
    "space-unary-ops": "error",
    "spaced-comment": "error",
    "yoda": "error"
  }
}
```

***

## 2. Downloading the plugin template

1. Go to the [Plugin Template repository](https://github.com/Zeroknights16/AthenaBot-PluginTemplate).
2. Download the template files with Code → Download ZIP or clone it with Git.
3. Place the entire folder into your AthenaBot installation under `/plugins/`.

Your directory structure should look like this:

```
AthenaBot/
├── backup/
├── configuration/
├── logs/
├── main/
├── node_modules/
├── plugins/
│   └── MyFirstPlugin/
│       ├── main.js
│       ├── data/
│       │   ├── configs/
│       │   └── dashboard/
│       └── src/
│           └── dashboard/
```

***

## 3. Understanding the plugin template

### Main file

Below is the entry point of your plugin. This example was taken from the template itself. We will go through the whole `main.js` file step by step.

```js
const plugin = require('../../main/discord/core/plugins/plugin.js');
const testHandler = require('./src/handler/test.js');

module.exports = class test extends plugin {
  constructor(heart) {
    super(heart, { name: 'test', author: 'Zeroknights', version: '1.0.0', requiredAthenaVersion: '2.2.0', priority: 0, dependencies: ['core'], softDependencies: [], nodeDependencies: [], channels: [], dashboard: { cannotDisable: false } });
  }

  async preLoad() {
    this.heart.core.console.log(this.heart.core.console.type.startup, 'The plugin is pre-loading now...');
    const helloConfig = new this.heart.core.discord.core.config.interface(
      this.heart,
      { name: 'hello', plugin: this.getName(), dashboardConfigurable: true },
      {
        config: {
          bot_name: undefined,
          bot_id: undefined,
          bot: undefined,
          permissions: {
            test_command: undefined,
            info_command: undefined,
            ticket_inactivity_event: undefined,
          },
          dashboard_panels: undefined,
          alert_rules: undefined,
        }
      },
    );
    const loadHelloConfig = await this.heart.core.discord.core.config.manager.load(helloConfig);
    if (!loadHelloConfig) {
      this.setDisabled();
      this.heart.core.console.log(this.heart.core.console.type.error, `Disabling plugin ${this.getName()}...`);
      return;
    }
  }

  async load() {
    this.heart.core.console.log(this.heart.core.console.type.startup, 'The plugin is loading now...');
    this.heart.core.discord.core.handler.manager.register(new testHandler(this.heart));
  }
};
```

> The `heart` object is your access point to the Developer API, including logging, configs, and utilities.

### Class constructor

```js
super(heart, { name: 'test', author: 'Zeroknights', version: '1.0.0', requiredAthenaVersion: '2.2.0', priority: 0, dependencies: ['core'], softDependencies: [], nodeDependencies: [], channels: [], dashboard: { cannotDisable: false } });
```

* **Name:** Your plugin name. Make sure this is unique.
* **Author:** Your username.
* **Version:** Your plugin version.
* **RequiredAthenaVersion:** Specifies the minimum AthenaBot version needed for the plugin.
* **Priority:** The higher the number, the earlier your plugin will be loaded.
* **Dependencies:** List of plugin dependencies required for this plugin to run. All plugins depend on the core plugin.
* **softDependencies:** Optional plugin dependencies.
* **nodeDependencies:** Node.js dependencies that are installed before loading.
* **channels:** Registered channels that can be configured through Athena’s `/setup` command.
* **dashboard.cannotDisable:** If set to `true`, the plugin cannot be disabled in the dashboard.

### Config constructor

If your plugin does not offer a config, you can remove the following code snippet from your plugin template.

```js
const helloConfig = new this.heart.core.discord.core.config.interface(
  this.heart,
  { name: 'hello', plugin: this.getName() },
  {
    config: {
      bot_name: undefined,
      bot_id: undefined,
      bot: undefined,
      permissions: {
        test_command: undefined,
        info_command: undefined,
        ticket_inactivity_event: undefined,
      },
      dashboard_panels: undefined,
      alert_rules: undefined,
    }
  },
);
const loadHelloConfig = await this.heart.core.discord.core.config.manager.load(helloConfig);
if (!loadHelloConfig) {
  this.setDisabled();
  this.heart.core.console.log(this.heart.core.console.type.error, `Disabling plugin ${this.getName()}...`);
  return;
}
```

* **Line 1:** Always keep the `heart` object for the config manager.
* **Line 2:** `name` is the config name. In this example, your config is called `hello`.
* **Line 3-17:** This defines the structure of your plugin configuration file.

> Important: Your configuration file must start with a top-level `config` object.

```js
{
  config: {
    bot_name: 'Athena',
    bot_id: '22354373457231251362',
    bot: true,
    permissions: {
      test_command: 'everyone',
      info_command: 'member',
      ticket_inactivity_event: 'everyone',
    },
  }
}
```


# Commands

This page explains how to create your own commands for your AthenaBot plugin.

***

## 1. Setting up the command file

1. Copy the command template.

```js
const { SlashCommandBuilder, MessageFlags } = require('discord.js');
const command = require('../../../../main/discord/core/commands/command.js');

module.exports = class test extends command {
  constructor(heart) {
    const helloConfig = heart.core.discord.core.config.manager.get('hello').get();

    super(heart, {
      name: 'test',
      data: new SlashCommandBuilder()
        .setName('test')
        .setDescription('Test command')
        .addStringOption(option => option.setName('name').setDescription('Name').setAutocomplete(true).setRequired(true)),
      contextMenu: false,
      global: true,
      category: 'general',
      bypass: true,
      permissionLevel: helloConfig.config.permissions.test_command,
    });
  }

  async execute(interaction, langConfig) {
    try {
      const name = interaction.options.getString('name');
      interaction.reply({ content: `Hello World, ${name}!`, flags: MessageFlags.Ephemeral });
    }
    catch (err) {
      this.heart.core.console.log(this.heart.core.console.type.error, `An issue occurred while executing command ${this.getName()}`);
      new this.heart.core.error.interface(this.heart, err);
      interaction.reply({ embeds: [this.heart.core.util.discord.generateErrorEmbed(langConfig.lang.unexpected_command_error.replace(/%command%/g, `/${interaction.commandName}`))], flags: MessageFlags.Ephemeral });
    }
  }

  async autocomplete(interaction) {
    try {
      await interaction.respond([{ name: 'Test', value: 'test' }]);
    }
    catch (err) {
      this.heart.core.console.log(this.heart.core.console.type.error, `An issue occurred while executing autocomplete event ${this.getName()}`);
      new this.heart.core.error.interface(this.heart, err);
    }
  }
};
```

2. Create a new command file inside your `/plugins/<plugin_name>/src/commands/` directory.
3. The name of the file must follow the format `<command_name>.js`.

### Parameters

* **name:** The name of the command.
* **data:** A [Discord slash command builder](https://discordjs.guide/slash-commands/parsing-options.html#parsing-options) object.
* **contextMenu:** Set to `true` for a context menu command; otherwise, `false`.
* **global:** Keep this as `true`.
* **category:** Help category for the command. Keep this as `general`.
* **bypass:** Must remain `true`.
* **permissionLevel:** The required permission level to execute the command. Set to `null` to allow everyone to execute it.

***

## 2. Command response

There are two main interaction types you may need to handle in your command file:

* **Autocomplete interaction** — only if you enabled an autocomplete parameter.
* **Default command interaction**.

### Command interaction

This is the standard interaction from discord.js. You can respond and handle the interaction however you like.

### Autocomplete interaction

This is also the standard discord.js interaction. You can respond and handle it however you like.

If your command has multiple autocomplete parameters enabled, check out [this guide](https://discordjs.guide/slash-commands/autocomplete.html#handling-multiple-autocomplete-options) for handling multiple options in a single command file.

***

## 3. Additional information

{% hint style="warning" %}
Athena provides a custom error logging system that is deeply integrated into the framework. Do not throw errors directly. Instead, catch them and handle them with Athena’s error interface.
{% endhint %}

```js
try {
  // Your code here
}
catch (err) {
  this.heart.core.console.log(this.heart.core.console.type.error, `An issue occurred while executing command ${this.getName()}`);
  new this.heart.core.error.interface(this.heart, err);

  interaction.reply({ embeds: [this.heart.core.util.discord.generateErrorEmbed(langConfig.lang.unexpected_command_error.replace(/%command%/g, `/${interaction.commandName}`))], flags: MessageFlags.Ephemeral });
}
```

{% hint style="info" %}
Athena also provides custom embed builders for warnings, errors, and success messages. It is recommended to use these builders to maintain consistency across your plugin. See the internal API documentation for more details.
{% endhint %}


# Events

This page explains how to create your own event listeners for your AthenaBot plugin.

***

## 1. Setting up the event file

1. Copy the event template.

```js
const event = require('../../../../main/discord/core/events/event.js');
const { Events } = require('discord.js');

module.exports = class startUp extends event {
  constructor(heart) {
    super(heart, { name: 'startUp', event: { discord: Events.ClientReady, bypassManager: false, dm: false, bypassRestrictions: true, permissionLevel: null } });
  }

  execute(client) {
    this.heart.core.console.log(this.heart.core.console.type.log, 'The bot is ready now :)');
  }
};
```

2. Create a new event file inside your `/plugins/<plugin_name>/src/events/` directory.
3. The name of the file must follow the format `<event_name>.js`. Please note that in this case the event name does not match the Discord event. Try to use a unique event name.

### Parameters

* **name:** A unique identifier for the event.
* **discord:** The corresponding `discord.js` event name.
* **bypassManager:** Avoid setting this to `true` unless you are certain of the consequences.
* **dm:** Applicable only for `Discord.interactionCreate` events. Determines whether the interaction should also fire in DMs.
* **bypassRestrictions:** Must remain `true`.
* **permissionLevel:** Applicable only for `Discord.interactionCreate` events. This works like the permission configuration. Set to `null` to allow everyone.

> For custom events, the important value is `event.discord`. It must exactly match the emitted event name.

***

## 2. Event response

It is important to note that each event comes with its own parameters, which you receive in the method header. A full list of available events and their return values can be found in the Discord.js documentation.

### Interaction events

To begin, let’s look at a code snippet that creates a button.

```js
const button = new ActionRowBuilder().addComponents(
  new ButtonBuilder()
    .setCustomId(`iynx:athenabot:testButton:${interaction.user.id}:${Date.now()}`)
    .setLabel('Send')
    .setEmoji(this.heart.core.discord.core.emoji.manager.getEmoji(22))
    .setStyle(ButtonStyle.Primary));
interaction.reply({ content: 'Hello World!', components: [button] });
```

The corresponding event file:

```js
const event = require('../../../../main/discord/core/events/event.js');
const { Events, MessageFlags } = require('discord.js');

module.exports = class testButton extends event {
  constructor(heart) {
    super(heart, { name: 'testButton', event: { discord: Events.InteractionCreate, bypassManager: false, dm: false, bypassRestrictions: true, permissionLevel: null } });
  }

  async execute(interaction, interactionId, langConfig) {
    try {
      interaction.reply({ content: 'You just pressed a button.' });
    }
    catch (err) {
      this.heart.core.console.log(this.heart.core.console.type.error, `An issue occurred while executing event ${this.getName()}`);
      new this.heart.core.error.interface(this.heart, err);
      interaction.reply({ embeds: [this.heart.core.util.discord.generateErrorEmbed(langConfig.lang.unexpected_function_error.replace(/%function%/g, `${this.getName()}`))], flags: MessageFlags.Ephemeral });
    }
  }
};
```

Component interaction IDs are the unique identifiers for component interactions. They allow Athena to determine which event file should be executed and which configuration options should be applied. It is important that labels follow this format: `iynx:athenabot:<interaction_name>:<additional_data>`.

> The `<interaction_name>` must match the event name you defined, not the `discord.js` event name.

As you may have noticed, the `Discord.interactionCreate` event includes an additional parameter that `discord.js` does not provide: `interactionId`. This parameter represents the interaction label, returned as an array. For example: `['iynx', 'athenabot', 'testButton', '<executor_id>', '<data>']`.

If you want to restrict button access so only the user who ran the command can use it, add a simple check:

```js
if (interaction.user.id !== interactionId[3]) return interaction.reply({ content: 'No Access' });
```

***

## 3. Additional information

{% hint style="warning" %}
Athena provides a custom error logging system that is deeply integrated into the framework. Do not throw errors directly. Instead, catch them and handle them with Athena’s error interface.
{% endhint %}

```js
try {
  // Your code here
}
catch (err) {
  this.heart.core.console.log(this.heart.core.console.type.error, `An issue occurred while executing command ${this.getName()}`);
  new this.heart.core.error.interface(this.heart, err);

  interaction.reply({ embeds: [this.heart.core.util.discord.generateErrorEmbed(langConfig.lang.unexpected_function_error.replace(/%function%/g, `/${interaction.commandName}`))], flags: MessageFlags.Ephemeral });
}
```

{% hint style="info" %}
Athena also provides custom embed builders for warnings, errors, and success messages. See the internal API documentation for more details.
{% endhint %}


# Handlers

This page explains how to create your own handlers for your AthenaBot plugin.

***

## 1. Setting up the handler file

1. Copy the handler template.

```js
const handler = require('../../../../main/discord/core/handler/handler.js');

module.exports = class testHandler extends handler {
  constructor(heart) {
    super(heart, 'test');
    this.api = '';
  }

  setAPI(url) {
    if (!url) return false;

    this.api = url;
    return true;
  }

  getAPI() {
    if (!url) return null;
    return this.api;
  }
};
```

2. Create a new handler file inside your `/plugins/<plugin_name>/src/handler/` directory.
3. The name of the file must follow the format `<handler_name>.js`.
4. At the `load()` function of your plugin’s `main.js` file, register the handler.

```js
load() {
  const testHandler = require('./src/handler/<handler_name>.js');
  this.heart.core.discord.core.handler.manager.register(new testHandler(this.heart));
}
```

### Parameters

* **`'test'`**: A unique identifier for the handler.

***

## 2. Working with handlers

Handlers are not mandatory, but they are very useful if multiple files require the same functions or access to the same temporary database. They can be imported throughout the bot, and you can access handlers provided by different plugins.

To do so, add the following snippet to your file:

```js
const handler = this.heart.core.discord.core.handler.manager.get('<handler_name>');
```

In our case:

```js
const testHandler = this.heart.core.discord.core.handler.manager.get('test');
testHandler.setAPI('https://google.com/');

const testAPI = testHandler.getAPI();
console.log(testAPI); // Returns https://google.com/
```

Athena provides over 20 custom handlers, ranging from cooldown, permission, and invite handlers to moderation, ticket, and Minecraft access. This allows you to integrate Athena’s features into your plugin easily. For example, you can hook into the moderation plugin to automatically warn a user on Discord for certain actions.

```js
const mod = this.heart.core.discord.core.handler.manager.get('mod');
await mod.warn(interaction.guild, user, interaction.user, null, reason);
```

> It is recommended to make use of the handlers Athena offers to keep your plugin consistent with the rest of the bot infrastructure.


# MongoDB Models

This page explains how to create your own MongoDB models for your AthenaBot plugin.

***

## 1. Setting up the MongoDB model file

1. Copy the model template.

```js
const modelBuilder = require('../../../../main/core/database/modelBuilder.js');

module.exports = class testModel extends modelBuilder {
  constructor() {
    super('test', {
      version: Number,
      guildId: String,
      id: String,
    });
  }
};
```

2. Create a new model file inside your `/plugins/<plugin_name>/src/models/` directory.
3. The name of the file must follow the format `<model_name>.js`.

### Parameters

* **`'test'`:** A unique identifier for the model.
* **`'object'`:** This follows the same model definition approach you may already know from Mongoose.

***

## 2. Importing models

Add the following snippet to your code to import any MongoDB model:

```js
const model = this.heart.core.database.getModel('<model_name>').getModel();
```

This returns a Mongoose model instance. With this instance, you can search, delete, insert, or modify datasets.

```js
const testModel = this.heart.core.database.getModel('test').getModel();
const docs = await testModel.find();
for (let i = 0; i < docs.length; i++) {
  const testDoc = docs[i];
  if (i % 2 === 0) continue;

  await testDoc.deleteOne();
}
```


# Schedules

This page explains how to create your own schedules for your AthenaBot plugin.

***

## 1. Setting up the schedule file

1. Copy the schedule template.

```js
const scheduledTask = require('../../../../main/discord/core/schedule/schedule.js');

module.exports = class loop extends scheduledTask {
  constructor(heart) {
    super(heart, 'loop', { repeat: true, interval: 60000 });
  }

  execute() {
    this.heart.core.console.log(this.heart.core.console.type.log, '60 seconds have passed since the last time :-:');
  }
};
```

2. Create a new schedule file inside your `/plugins/<plugin_name>/src/schedules/` directory.
3. The name of the file must follow the format `<schedule_name>.js`.

### Parameters

* **`'loop'`:** A unique identifier for the schedule.
* **repeat:** Defines whether the file should be executed repeatedly every `<interval>` milliseconds, or only once after `<interval>` milliseconds.
* **interval:** The time in milliseconds between each execution.

***

## 2. Schedule response

Schedules are used to handle tasks that occur repeatedly. A common example is unmutes.

When a user is muted, the mute duration and punishment date are stored in the user database. The bot then loads all documents of currently muted users and, at each interval check, determines whether the mute has expired. If so, it automatically executes the `unmute` function.

For an example, see the unmute schedule from Athena’s source code:

```js
module.exports = class tempUnmute extends scheduledTask {
  constructor(heart) {
    super(heart, 'tempUnmute', { repeat: true, interval: 223000 });
  }

  async execute() {
    try {
      const commonConfig = this.heart.core.config.common.get();
      const guild = this.heart.core.discord.guilds.cache.get(commonConfig.bot.discord_guild_id);
      if (!guild) return;

      const mod = this.heart.core.discord.core.handler.manager.get('mod');
      const model = this.heart.core.database.getModel('user').getModel();
      const data = await model.find({
        guildId: guild.id,
        muted: true,
      });

      for (let i = 0, length = data.length; i < length; i++) {
        const punishment = await mod.load(data[i].mutes[data[i].mutes.length - 1]);
        const validTil = punishment.validTil();

        if (punishment.isActive() && !validTil.permanent && !validTil.active) {
          const user = await this.heart.core.discord.users.fetch(data[i].userId, { force: true, cache: true });
          if (!user) {
            await data[i].deleteOne();
            continue;
          }

          const unmute = await mod.unmute(guild, user, this.heart.core.discord.user, false, punishment);
          if (!unmute) {
            this.heart.core.console.log(this.heart.core.console.type.log, `User with the ID ${punishment.getUserId()} has been unmuted due to`);
            this.heart.core.console.log(this.heart.core.console.type.log, `his temporary mute running out. Punishment ID: ${punishment.getPunishmentId()}`);
          }
          await this.heart.core.util.util.sleep(2000);
        }
      }
    }
    catch (err) {
      this.heart.core.console.log(this.heart.core.console.type.error, `An issue occurred while executing schedule event ${this.getName()}`);
      new this.heart.core.error.interface(this.heart, err);
    }
  }
};
```

***

## 3. Additional information

{% hint style="warning" %}
Intervals are not executed immediately. Once the time until the next execution has passed, the schedule is pushed to Athena’s schedule queue, so it may take up to 20 additional seconds for your schedule to run.
{% endhint %}

{% hint style="warning" %}
Athena provides a custom error logging system that is deeply integrated into the framework. Do not throw errors directly. Instead, catch them and handle them with Athena’s error interface.
{% endhint %}

```js
try {
  // Your code here
}
catch (err) {
  this.heart.core.console.log(this.heart.core.console.type.error, `An issue occurred while executing schedule event ${this.getName()}`);
  new this.heart.core.error.interface(this.heart, err);
}
```


# Rest API

This page explains how to create and use custom HTTP API routes for your AthenaBot plugin.

***

## Running API calls

```js
const result = await axios.get('https://<web_api_base_ip>/api/status', {
  headers: { Authorization: '<web_api_auth_key>' }
});
```

Depending on the restrictions configured for each API route, the IP address of the incoming request may need to be whitelisted in your Web API configuration.

***

## Adding custom API routes

### 1. Setting up the route file

* Create a new route file inside your plugin directory: `/plugins/<plugin_name>/src/routes/`
* The file name can be anything, but it is recommended to match the route name, such as `hello.js`.

> The Web API plugin must be enabled and running for routes to work. If the Web API plugin fails to load, is disabled, or if the plugin that owns the route is disabled, the route becomes unavailable.

### 2. Configuration options

* **name:** A unique identifier for the route.
* **path:** The endpoint path where the route will be accessible. Do not include `http://` or the domain name.
* **type:** The HTTP method the route should respond to. Available types: `get`, `post`, `put`, `delete`.
* **ip:** If enabled, all incoming requests must originate from a whitelisted IP address.
* **key:** If enabled, all incoming requests must include a valid authentication key in the request headers.

### 3. Handling requests

Each route must implement an asynchronous `execute(req, res)` method. This method is called whenever a request hits the registered endpoint. You can access:

* Request data via `req`
* Response helpers via `res`

Athena provides helper methods such as `this.generateSuccessResponse()` or `this.generateErrorResponse()` to keep API responses consistent across plugins.

### 4. Example route

The following example registers a `GET` endpoint at `/api/hello` and returns a simple JSON response.

```js
const routeManager = require('../../../web_api/src/route.js');

module.exports = class hello extends routeManager {
  constructor(heart) {
    super(heart, { name: 'hello', path: 'api/hello', type: 'get' }, { ip: false, key: false });
  }

  async execute(req, res) {
    res.status(200).send(this.generateSuccessResponse({ message: 'Hello world!' }));
  }
};
```


# Dashboard Config Editor

This page explains how to make your plugin config editable in Athena’s dashboard with a dashboard schema file.

***

## 1. Required files

For a config named `hello`, you need both files:

* `/plugins/<plugin_name>/data/configs/en-hello.json5`
* `/plugins/<plugin_name>/data/dashboard/en-hello.json`

If the dashboard schema file is missing, your config is still loaded, but it is not editable in the dashboard config editor.

***

## 2. Enabling dashboard editing

To make your config editable in the dashboard, add the `dashboardConfigurable: true` flag to your config interface constructor:

```js
const helloConfig = new this.heart.core.discord.core.config.interface(
  this.heart,
  { name: 'hello', plugin: this.getName(), dashboardConfigurable: true },
  {
    config: {
      // your config structure
    }
  },
);
```

> Without this flag, even if you provide a dashboard schema file, your config will not appear in the dashboard config editor. This flag is required to enable dashboard integration for your config.

***

## 3. Schema basics

Your dashboard schema file maps config keys to UI field definitions.

```json
{
  "bot_name": {
    "type": 0,
    "name": "Bot Name",
    "description": "Display name used by your plugin",
    "autocomplete": []
  },
  "bot": {
    "type": 2,
    "name": "Bot Enabled",
    "description": "Enable or disable plugin features globally",
    "autocomplete": [true, false]
  }
}
```

### Common field settings

* `name`: UI label shown in the editor.
* `description`: Help text shown under the field.
* `extra`: Optional markdown details shown in the info popover.
* `autocomplete`: Suggested values for supported field types.

***

## 4. Useful config types

The dashboard supports many built-in types. For custom plugin schemas, the most common are:

* `type 0`: string input
* `type 1`: number input
* `type 2`: boolean toggle or choice
* `type 3`: array of strings
* `type 4`: array of numbers
* `type 5`: array of booleans
* `type 10`: group of related settings
* `type 1000`: array of objects (schema-driven)
* `type 1001`: dynamic object where each key maps to an array of schema-driven objects
* `type 1002`: dynamic object where each key maps to a single object (schema-driven)

***

## 5. Schema-driven types

### Type 1000: Array of objects

Use this when users should add multiple objects with one fixed structure.

```json
{
  "dashboard_panels": {
    "type": 1000,
    "name": "Dashboard Panels",
    "value_schema": {
      "name": { "type": 0, "label": "Panel Name", "autocomplete": ["Welcome", "Rules"] },
      "channel_id": { "type": 0, "label": "Channel ID" },
      "enabled": { "type": 2, "label": "Enabled", "autocomplete": [true, false] },
      "tags": { "type": 3, "label": "Tags", "autocomplete": ["staff", "public"] }
    },
    "autocomplete": []
  }
}
```

Example data structure:

```json5
dashboard_panels: [
  {
    name: "Welcome",
    channel_id: "000000000000000001",
    enabled: true,
    tags: ["public", "rules"]
  },
  {
    name: "Staff",
    channel_id: "000000000000000002",
    enabled: false,
    tags: ["staff"]
  }
]
```

### Type 1001: Dynamic object of arrays

Use this when users should create named groups and each group contains an array of objects.

```json
{
  "alert_rules": {
    "type": 1001,
    "name": "Alert Rules",
    "value_schema": {
      "role_id": { "type": 0, "label": "Role ID" },
      "threshold": { "type": 1, "label": "Threshold", "autocomplete": [1, 3, 5, 10] },
      "enabled": { "type": 2, "label": "Enabled", "autocomplete": [true, false] },
      "notes": { "type": 3, "label": "Notes", "autocomplete": ["Escalate", "Soft warning"] }
    },
    "autocomplete": []
  }
}
```

Example data structure:

```json5
alert_rules: {
  "moderation": [
    {
      role_id: "111111111111111111",
      threshold: 3,
      enabled: true,
      notes: ["Escalate"]
    },
    {
      role_id: "222222222222222222",
      threshold: 5,
      enabled: false,
      notes: ["Soft warning"]
    }
  ],
  "security": [
    {
      role_id: "333333333333333333",
      threshold: 10,
      enabled: true,
      notes: ["Escalate", "Notify admin"]
    }
  ]
}
```

### Type 1002: Dynamic object of single objects

Use this when users should create named groups and each group contains a single configured object.

```json
{
  "service_configs": {
    "type": 1002,
    "name": "Service Configurations",
    "value_schema": {
      "api_key": { "type": 0, "label": "API Key" },
      "endpoint": { "type": 0, "label": "Endpoint URL" },
      "timeout": { "type": 1, "label": "Timeout (ms)", "autocomplete": [1000, 3000, 5000] },
      "enabled": { "type": 2, "label": "Enabled", "autocomplete": [true, false] }
    }
  }
}
```

Example data structure:

```json5
service_configs: {
  "service_a": {
    api_key: "key123",
    endpoint: "https://api.example.com",
    timeout: 5000,
    enabled: true
  },
  "service_b": {
    api_key: "key456",
    endpoint: "https://api2.example.com",
    timeout: 3000,
    enabled: false
  }
}
```

***

## 6. Keep config and schema in sync

Your `data/configs/en-hello.json5` defaults and `data/dashboard/en-hello.json` schema should describe the same keys.

For example:

* schema key `dashboard_panels` should exist in the default config as `config.dashboard_panels`
* schema key `alert_rules` should exist in the default config as `config.alert_rules`

If key names diverge, the editor can show empty values or reject edits.


# Custom Dashboard Pages

This page explains how plugins can ship custom dashboard pages.

***

## 1. How loading works

When Athena starts and the dashboard is enabled, it checks every loaded plugin for:

* `/plugins/<plugin_name>/src/dashboard/addon.json`

If present, Athena copies your plugin dashboard files into the main dashboard app and adds your addon to the sidebar automatically.

***

## 2. Required manifest

Create:

* `/plugins/<plugin_name>/src/dashboard/addon.json`

Example:

```json
{
  "name": "Template Addon",
  "slug": "template-addon",
  "icon": "TbPlug",
  "description": "Sample custom dashboard page bundled with the plugin template."
}
```

### Required fields

* **name:** Sidebar or page title.
* **slug:** URL path key. It must be unique.

### Optional fields

* **icon:** Tabler icon key. Defaults to `TbPlug`.
* **description:** Subtitle shown in the addon layout header.

> The `slug` should be lowercase kebab-case and should not change after release, otherwise old links and bookmarks may break.

***

## 3. Folder structure

Use this structure inside your plugin:

```
src/dashboard/
  addon.json
  pages/
    page.jsx
  components/
    HelloCard.jsx
  api/
    ping/
      route.js
```

How each folder is used:

* `pages/`: Copied to the dashboard app route `/addons/<slug>/...`
* `components/`: Copied to `dashboard/components/addons/<slug>/...`
* `api/`: Copied to `dashboard/app/api/addons/<slug>/...`

***

## 4. Route and imports

For addon slug `template-addon`:

* `src/dashboard/pages/page.jsx` becomes `/addons/template-addon`
* Import shared components from `dashboard/components/addons/template-addon`

Example import in your `page.jsx`:

```js
import HelloCard from '../../../../components/addons/template-addon/HelloCard';
```

If you rename the `slug`, update any imports that include the old slug path.

The dashboard currently maps addon icons using a fixed icon map. If you use a custom icon key that is not available there, the UI falls back to `TbPlug`.

***

## 5. Fetching plugin data

The most common pattern is reading your plugin config through Web API dashboard routes:

```js
const API_BASE = process.env.NEXT_PUBLIC_ATHENA_WEB_API_URL;
const API_KEY = process.env.NEXT_PUBLIC_ATHENA_WEB_API_KEY;

const response = await fetch(`${API_BASE}/api/dashboard/config/hello/data`, {
  headers: { authorization: API_KEY }
});
```

Save updates with:

```js
await fetch(`${API_BASE}/api/dashboard/config/hello/save`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', authorization: API_KEY },
  body: JSON.stringify({ data: updatedConfig })
});
```


# Internal API

You have made it this far, congratulations! You have completed the plugin setup process and gained an understanding of what plugins have to offer.

This is only one part of Athena’s full framework. The following pages take a deeper look into Athena’s internal API and the features it provides.

***

## Available topics

* [Cache](/addon-api/getting-started/internal-api/cache)
* [Configs](/addon-api/getting-started/internal-api/configs)
* [Custom Emojis](/addon-api/getting-started/internal-api/custom-emojis)
* [Custom Events](/addon-api/getting-started/internal-api/custom-events)
* [Embeds](/addon-api/getting-started/internal-api/embeds)
* [Plugins](/addon-api/getting-started/internal-api/plugins)
* [User Data](/addon-api/getting-started/internal-api/user-data)
* [Utils](/addon-api/getting-started/internal-api/utils)


# Plugins

This page explains how to work with the internal Plugin API.

## Plugin API

### Dependencies

When integrating with other plugins and their handlers, you should first verify that the plugin is loaded. If the plugin is not loaded, attempting to fetch its handler returns `null`. You can check whether a plugin is loaded with:

```js
const isLoaded = this.core.discord.core.plugin.manager.isLoaded('<plugin_name>');
```

This returns:

* `true` if the plugin is loaded and available.
* `false` if the plugin is not loaded.

### Plugins

Let’s take a quick look at a plugin’s instance functions. In most cases, you will not need these directly, but here is how you can fetch a plugin:

```js
const plugin = this.heart.core.discord.core.plugin.manager.get('<plugin_name>');
```

> If the plugin is not found, this function returns `null`.

The following code snippets and explanations work similarly for plugins, commands, events, and schedules. The relevant imports are:

```js
const command = this.heart.core.discord.core.command.manager.get('<command_name>');
const event = this.heart.core.discord.core.event.manager.get('<event_name>');
const schedule = this.heart.core.discord.core.schedule.manager.get('<schedule_name>');
```

### Functions

* `plugin.getName()`: Returns the name of the plugin.
* `plugin.getAuthor()`: Returns the author of the plugin.
* `plugin.getVersion()`: Returns the version of the plugin.
* `plugin.getPriority()`: Returns the plugin’s load priority.
* `plugin.getDependencies()`: Returns a list of required plugin dependencies.
* `plugin.getSoftDependencies()`: Returns a list of optional soft dependencies.
* `plugin.getNodeDependencies()`: Returns a list of required Node.js dependencies.
* `plugin.getChannelNames()`: Returns the names of the plugin’s registered channels.
* `plugin.setDisabled()`: Disables the plugin.
* `plugin.setEnabled()`: Enables the plugin.
* `plugin.isEnabled()`: Returns `true` if the plugin is enabled.


# Configs

This page explains how to work with the internal Config API.

## Config API

This is one of the simplest parts of the documentation. There is not much you need to do with configs directly, but here is how to import one:

```js
// Plugin configs
const config = this.heart.core.discord.core.config.manager.get('<config_name>').get();

// Common config
const commonConfig = this.heart.core.config.common.get();
```

This returns:

* `null` if the config could not be found.
* `config_json` if the config was found.


# Custom Events

This page explains how to run Athena custom events for your AthenaBot plugin.

***

## 1. Setting up the event file

1. Create a new event file in `/plugins/<plugin_name>/src/events/`.
2. Name the file with a unique event listener name, such as `myLevelUpListener.js`.
3. Set `event.discord` to the Athena custom event name you want to listen to, such as `athena:levelUp`.

```js
const event = require('../../../../main/discord/core/events/event.js');

module.exports = class myLevelUpListener extends event {
  constructor(heart) {
    super(heart, { name: 'myLevelUpListener', event: { discord: 'athena:levelUp', bypassManager: false, dm: false, bypassRestrictions: true, permissionLevel: null } });
  }

  async execute(userId, newLevel) {
    try {
      this.heart.core.console.log(this.heart.core.console.type.log, `${userId} reached level ${newLevel}`);
    }
    catch (err) {
      this.heart.core.console.log(this.heart.core.console.type.error, `An issue occurred while executing event ${this.getName()}`);
      new this.heart.core.error.interface(this.heart, err);
    }
  }
};
```

### Parameters

* **name:** Unique identifier for your listener file.
* **discord:** The Athena custom event name.
* **bypassManager:** Keep `false` unless you fully understand the side effects.
* **dm:** Keep `false` for Athena custom events.
* **bypassRestrictions:** Keep `true`.
* **permissionLevel:** Keep `null` for Athena custom events.

> The important value is `event.discord`. It must exactly match the emitted event name.

***

## 2. Running the event

Athena events are not fired by Discord.js. You run them by calling Athena’s `eventManager.emitSafe` from your feature logic.

```js
const didEmit = await this.heart.manager.discord.eventManager.emitSafe('athena:levelUp', userId, newLevel);
if (!didEmit) {
  this.heart.core.console.log(this.heart.core.console.type.warn, 'Event levelUp emitted but no listener was registered');
}
```

If you emit:

```js
emitSafe('athena:levelUp', userId, newLevel)
```

Your listener should be:

```js
async execute(userId, newLevel) {
  // ...
}
```

***

## 3. Additional information

* Event names are case-sensitive.
* Do not rename `athena:*` events unless all emitters and listeners are updated together.
* IDs are Discord snowflakes unless the event signature states otherwise.
* Object payloads should be treated as internal APIs that may evolve.

***

## 4. Athena custom event catalog

> Signatures are shown as `EventName(arg1, arg2, ...)`.

### Core

* `athena:error(errorInterface)`

### Economy

* `athena:bankUpgrade(userId, bankLevel)`
* `athena:shopPurchase(userId, itemId, cost)`
* `athena:jobUpgrade(userId, jobKey, jobLevel)`
* `athena:lootboxRollPurchase(userId, purchasedRolls)`
* `athena:lootboxOpen(userId, rewardType, rewardAmount)`
* `athena:questClaim(userId, period, finishedQuestCount, rewards)`
* `athena:rankUpgrade(userId, newRank)`

### Fun

* `athena:levelUp(userId, level)`
* `athena:countingGameSuccess(userId, counterValue)`
* `athena:countingGameFail(userId, evaluatedInput, expectedCounter)`
* `athena:hangmanEnd(userId, won, streak, winStreakCurrent)`
* `athena:higherLowerEnd(userId, streak, highscore)`
* `athena:starboardSend(userId, messageId, reactionCount)`
* `athena:starboardReaction(userId, messageId, reactionCount)`

### Giveaway

* `athena:giveawayEnter(userId, giveawayMessageId, entryCount)`
* `athena:giveawayLeave(userId, giveawayMessageId, entryCount)`

### Join to create

* `athena:tempVoiceCreate(voiceChannelId, ownerUserId, sourceChannelId)`
* `athena:tempVoiceDelete(voiceChannelId, ownerUserId)`
* `athena:tempVoiceOwnerChange(voiceChannelId, previousOwnerUserId, newOwnerUserId)`
* `athena:tempVoiceOwnerSet(voiceChannelId, executorUserId, newOwnerUserId)`
* `athena:tempVoiceName(voiceChannelId, executorUserId, newName)`
* `athena:tempVoiceLimit(voiceChannelId, executorUserId, newLimit)`
* `athena:tempVoiceVisibility(voiceChannelId, executorUserId, visibility)`
* `athena:tempVoiceKick(voiceChannelId, executorUserId, targetUserId)`
* `athena:tempVoiceBlacklist(voiceChannelId, executorUserId, targetUserId)`
* `athena:tempVoiceUnblacklist(voiceChannelId, executorUserId, targetUserId)`

### Management

* `athena:applySavedRoles(userId, roleCount)`
* `athena:autoRole(userId, roleCount)`
* `athena:saveRoles(userId, roleCount)`
* `athena:pollVote(userId, pollId, optionId)`
* `athena:pollVoteRevoke(userId, pollId, optionId)`
* `athena:suggestionCreate(userId, suggestionNumber)`
* `athena:suggestionStatus(staffUserId, suggestionId, status)`
* `athena:suggestionReview(staffUserId, suggestionId, approved)`

### Moderation

* `athena:blacklist(type, targetUserId, executorUserId, punishmentId)`
* `athena:unblacklist(type, targetUserId, executorUserId, punishmentId)`
* `athena:ban(targetUserId, executorUserId, punishmentId, manual)`
* `athena:unban(targetUserId, executorUserId, punishmentId, manual)`
* `athena:kick(targetUserId, executorUserId, punishmentId, manual)`
* `athena:mute(targetUserId, executorUserId, punishmentId, manual)`
* `athena:unmute(targetUserId, executorUserId, punishmentId, manual)`
* `athena:warn(targetUserId, executorUserId, punishmentId)`
* `athena:unwarn(targetUserId, executorUserId, punishmentId)`
* `athena:strike(targetUserId, executorUserId, punishmentId, strikeAmount)`
* `athena:automodAction(userId, ruleName, warning)`

### Music

* `athena:nodeConnect(nodeName)`
* `athena:nodeDisconnect(nodeName, disconnectCount)`
* `athena:nodeError(nodeName, errorMessageOrNull)`
* `athena:playerCreate(guildIdOrNull, defaultVolume)`
* `athena:trackStart(guildId, requesterUserId, title)`
* `athena:trackEnd(guildId, titleOrNull, remainingQueueLength)`
* `athena:queueEnd(guildId, textChannelId)`

### Security

* `athena:autoVerify(userId)`
* `athena:verifyFail(userId, remainingAttempts)`
* `athena:verifySuccess(userId)`

### Social

* `athena:twitchLive(username, messageId, viewerCount)`
* `athena:twitchOffline(username)`
* `athena:youtubeNotification(authorName, videoId, discordChannelId)`

### Staff management

* `athena:verifyStaffRoles()`
* `athena:verifyStaffRolesFail(invalidRoleIds)`
* `athena:strikelistView(viewerUserId, targetMemberId, punishmentId, page)`
* `athena:taskClaim(userId, taskId)`
* `athena:taskEditOpen(userId, taskId, type)`
* `athena:taskEdit(userId, taskId, type)`

### Tickets

* `athena:ticketCreate(ticket)`
* `athena:ticketAdd(ticket, addedUserId)`
* `athena:ticketRemove(ticket, removedUserId)`
* `athena:ticketRename(ticket, newName)`
* `athena:ticketClaim(ticket, claimerUserId)`
* `athena:ticketUnclaim(ticket, unclaimerUserId)`
* `athena:ticketClose(ticket)`
* `athena:ticketLower(ticket, level)`
* `athena:ticketElevate(ticket, level)`
* `athena:applicationStart(userId, applicationIndex)`
* `athena:applicationSubmit(userId, applicationIndex, answersCount, submitted)`
* `athena:applicationCancel(userId, applicationIndex)`
* `athena:applicationChannelCreate(application)`
* `athena:applicationChatAllow(applicantUserId, staffUserId, appChannelId)`
* `athena:applicationChatDeny(applicantUserId, staffUserId, appChannelId)`
* `athena:applicationHistoryView(staffUserId, applicantUserId, appChannelId)`
* `athena:applicationAccept(application, roleName, staffUserId)`
* `athena:applicationDeny(application, staffUserId, reason, timeoutMs)`
* `athena:applicationAutoClose(application)`


# Embeds

This page explains how to work with the internal Embed API.

## Embed API

Embeds are a beautiful way to enhance your plugin with clean, professional-looking message designs. Athena’s API provides three custom pre-built embed types.

***

### Error embeds

Error embeds are primarily used inside `try-catch` blocks. To generate an error embed, use the following snippet:

```js
const errorEmbed = this.heart.core.util.discord.generateErrorEmbed(`${userMention(interaction.user.id)}, something went wrong!`);
interaction.reply({ embeds: [errorEmbed] });
```

The `.generateErrorEmbed()` function returns an [EmbedBuilder](https://discord.js.org/docs/packages/builders/main/EmbedBuilder:Class) instance. The text you pass in becomes the description of the error embed preset.

***

### Warning embeds

Warning embeds are the correct way to inform the command or interaction executor that they cannot proceed. Typical use cases include:

* The user does not have permission to use a panel.
* The command can only be executed in ticket channels.
* Any other situation where the command cannot be executed.

```js
const warnEmbed = this.heart.core.util.discord.generateWarnEmbed(`${userMention(interaction.user.id)}, this command can only be run in tickets!`);
interaction.reply({ embeds: [warnEmbed] });
```

The `.generateWarnEmbed()` function returns an [EmbedBuilder](https://discord.js.org/docs/packages/builders/main/EmbedBuilder:Class) instance. The text you pass in becomes the description of the warning embed preset.

***

### Other embeds

Not every message should be an error or warning. This embed type is used for general information, notifications, and other messages that do not fall under those categories.

```js
const embedConfiguration = {
  title: 'Test',
  description: 'Hello World, I\'m testing my first placeholder here %test%. The command was executed by %userId%',
  color: 'red',
  defaultFooter: true,
  defaultTimestamp: true,
  guildIcon: true,
  userIcon: true,
};

const placeholders = {
  test: 'Placeholder 1',
  userId: interaction.user.id,
};

const embed = this.heart.core.util.discord.resolveEmbed(embedConfiguration, placeholders, interaction.guild, interaction.user);
interaction.reply({ embeds: [embed] });
```

The embed configuration follows the official Embed JSON representation. Athena provides four additional custom fields to extend the embed functionality:

* `defaultFooter`: If set to `true`, the time when the embed is generated is used as the timestamp.
* `defaultFooter`: If set to `true`, the default footer text from your `common.json` config is used.
* `guildIcon`: If set to `true` and a guild instance is provided, the guild icon is displayed in the embed thumbnail.
* `userIcon`: If set to `true` and a user instance is provided, the user avatar is displayed in the embed thumbnail.

Placeholders can be used by writing `%placeholder_name%` in any field such as the title or description. This is extremely useful if you want to make your messages configurable through your configuration file.

Athena also provides additional default placeholders that work in every embed rendered by `.resolveEmbed()`:

* `%custom_emoji_<number>%`
* `%user%`
* `%user_display%`
* `%user_id%`
* `%user_mention%`
* `%user_icon%`
* `%user_created%`
* `%user_created_formatted%`
* `%user_joined%`
* `%user_joined_formatted%`
* `%guild%`
* `%guild_id%`
* `%guild_icon%`
* `%random_int_<max_number>%`
* `%random_string_<length>%`
* `%current_date%`
* `%current_time%`
* `%current_time_seconds%`
* `%current_datetime%`
* `%current_iso%`

> All `%user_...%` placeholders only work if a user instance is provided to `.resolveEmbed()`. The same applies to `%guild_...%` placeholders and a guild instance.


# Custom Emojis

This page explains how to work with the internal Emoji API.

## Emoji API

Athena provides a large set of custom emojis that you can use in your plugins. A complete list of these emojis can be found in the [Discord Developer Portal](https://discord.com/developers/applications).

All custom emojis are available in embeds rendered with `.resolveEmbed()`. You can use them with the following placeholder format: `%custom_emoji_<number>%`. The `<number>` corresponds to the emoji ID shown in the Discord Developer Portal.

If you want to use an emoji outside of embeds, such as in buttons or messages, you can retrieve the full emoji and use it directly:

```js
const emoji = this.heart.core.discord.core.emoji.manager.getEmoji('<emoji_number>');

// Example
const testEmoji = this.heart.core.discord.core.emoji.manager.getEmoji(10);
interaction.reply({ content: `${testEmoji}, Hey there!` });
```


# Cache

This page explains how to work with the internal Cache API.

## Cache API

Caches are an extended version of Discord’s [Collections](https://discord.js.org/docs/packages/discord.js/14.22.1/Collection:Class). They can be generated with the following snippet:

```js
this.heart.core.discord.core.cache.manager.register(new this.heart.core.discord.core.cache.interface(this.heart, '<cache_name>'));
```

Like any other component of the API, you can fetch and access caches used by Athena.

```js
const cache = this.heart.core.discord.core.cache.manager.get('<cache_name>');
```

### Functions

* `cache.getName()`: Returns the name of the cache.
* `cache.setPluginName(name)`: Sets the name of the plugin associated with this cache.
* `cache.getPluginName()`: Returns the name of the plugin associated with this cache.
* `cache.getPlugin()`: Returns the plugin instance associated with this cache.
* `cache.set(key, value)`: Stores a new entry in the cache under the given key.
* `cache.get(key)`: Retrieves the value stored under the given key. Returns `null` if the key does not exist.
* `cache.has(key)`: Returns `true` if the given key exists in the cache.
* `cache.delete(key)`: Removes the entry with the given key.
* `cache.deleteAfter(key)`: Marks the given key for deletion after a short delay.

> To access the raw Discord Collection instance used by the cache, use `cache.cache`.


# User Data

This page explains how to work with Athena’s user data system.

## User data

User data is commonly stored in the database and can be accessed from your plugin. For example, if you want to fetch a user’s data object, you can use the built-in model accessors and work with the returned document.

```js
const model = this.heart.core.database.getModel('user').getModel();
const userData = await model.findOne({ userId: interaction.user.id });
```

You can then update it or create a new record if it does not exist.

```js
if (!userData) {
  await model.create({ userId: interaction.user.id, balance: 0 });
}
```

> Always make sure your data structure matches the schema used by the relevant model.


# Utils

This page explains how to work with the internal Utils API. It covers the most important utility functions.

## Utils API

To fetch the utility manager, add the following snippet:

```js
const utils = this.heart.core.util.util;
```

### Functions

#### `secureEval(string)`

Securely evaluate a string by removing non-numeric characters.

```js
const equation = parseInt(eval(this.heart.core.util.util.secureEval('1 * 2 + 5')));
```

#### `ms(string)`

Convert a time string to milliseconds. The format is `12h 2m 15s 262ms`.

```js
const time = this.heart.core.util.util.ms('2m 6s');
```

#### `ms(number)`

Convert milliseconds to a time string.

```js
const time = this.heart.core.util.util.ms(60000);
```

#### `resolveTime(string)`

Resolve a time string to milliseconds. This supports a wide range of formats.

```js
const time = this.heart.core.util.util.resolveTime('1,5h');
```

#### `sleep(number)`

Sleep for a specified amount of time in milliseconds.

```js
await this.heart.core.util.util.sleep(4000);
```

#### `getRandomElement(array)`

Get a random element from an array.

```js
const random = this.heart.core.util.util.getRandomElement([1, 2, 3, 4]);
```

#### `upperCase(string)`

Convert the first letter of a string to uppercase.

```js
const value = this.heart.core.util.util.upperCase('hello');
```

#### `generateRandom(number, number, array)`

Generate a random string.

```js
const id = this.heart.core.util.util.generateRandom(7, 10, ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']);
```

#### `isNumber(string)`

Check whether a string is a number.

```js
const isNumber = this.heart.core.util.util.isNumber('2165236727247347835835845845');
```

#### `isEquation(string)`

Check whether a string is an equation.

```js
const isEquation = this.heart.core.util.util.isNumber('2 * 326 * 23623 + d + 326 - 23');
```

#### `validateHex(string)`

Validate a hex color code.

```js
const isHex = this.heart.core.util.util.validateHex('#783224');
```

#### `isPicture(string)`

Check whether a file is a picture based on its extension.

```js
const isPicture = this.heart.core.util.util.isPicture(attachment.name);
```

#### `validateURL(string)`

Validate a URL.

```js
const isURL = this.heart.core.util.util.validateURL('https://discord.gg/');
```


# AthenaBot

## AthenaBot — Software License Agreement

**Version 1.0 — Effective Date: September 4, 2024**

***

### 1. Introduction

This Software License Agreement ("Agreement") is a legal contract between you ("Licensee") and Iynx ("Licensor") concerning your use of the software product **AthenaBot**, including any related documentation, updates, and support services (collectively referred to as "Software").

By installing, accessing, or otherwise using the Software, you agree to be bound by the terms of this Agreement. If you do not agree to these terms, do not install or use the Software.

***

### 2. License Grant

Subject to the terms and conditions of this Agreement, Licensor grants you a **non-exclusive, non-transferable, non-sublicensable, limited license** to install and use one copy of the Software on a single device, solely for your personal or internal business use.

***

### 3. Restrictions

You agree to the following restrictions:

* **No Sharing or Distribution** — You may not share, distribute, sell, lease, or transfer the Software or any portion thereof to any third party, whether in whole or in part, and whether for commercial or non-commercial purposes.
* **No Modification** — You may not modify, adapt, translate, reverse engineer, decompile, disassemble, or create derivative works based on the Software, except to the extent expressly permitted by applicable law.
* **No Copying** — You may not copy the Software except as expressly permitted by this Agreement. Any authorized copies remain subject to the terms of this Agreement.
* **No Transfer of Rights** — You may not transfer, assign, or sublicense your rights under this Agreement to any third party.
* **No Unauthorized Environments** — You may not use the Software in any environment not explicitly authorized by Licensor, including but not limited to cloud computing environments or on multiple devices simultaneously.
* **Administrative Access Reservation** — Licensor accounts shall retain administrator permissions on every AthenaBot instance at all times. Even where operational access is restricted to debugging and setup commands, such restrictions do not revoke or limit Licensor's administrator-level permissions. Access for all other parties remains subject to Licensor's role-based restrictions unless explicitly authorized otherwise in writing.

***

### 4. Ownership

The Software is **licensed, not sold**. Licensor retains all right, title, and interest — including all intellectual property rights — in and to the Software. This Agreement does not grant you any ownership rights in the Software. All rights not expressly granted are reserved by Licensor.

***

### 5. Confidentiality

The Software contains proprietary and confidential information belonging to Licensor. You agree to maintain the confidentiality of the Software and not to disclose, provide, or otherwise make available such information to any third party without the prior written consent of Licensor.

***

### 6. Updates and Support

Licensor may, at its sole discretion, provide updates or support services related to the Software. Any updates provided shall be subject to the terms of this Agreement. Licensor is under **no obligation** to provide support, updates, or maintenance for the Software.

***

### 7. Term and Termination

This Agreement is effective upon your acceptance and will remain in effect until terminated. Licensor may terminate this Agreement **immediately upon notice** if you fail to comply with any term herein.

Upon termination, you must immediately:

* Cease all use of the Software.
* Destroy all copies of the Software in your possession.

***

### 8. Disclaimer of Warranties

The Software is provided **"as is"** without warranty of any kind, express or implied, including but not limited to the implied warranties of merchantability, fitness for a particular purpose, and non-infringement. Licensor does not warrant that the Software will meet your requirements or that its operation will be uninterrupted or error-free.

***

### 9. Limitation of Liability

To the maximum extent permitted by applicable law, in no event shall Licensor be liable for any special, incidental, indirect, or consequential damages whatsoever — including but not limited to damages for loss of business profits, business interruption, loss of business information, or any other pecuniary loss — arising out of the use of or inability to use the Software, even if Licensor has been advised of the possibility of such damages.

***

### 10. Governing Law and Jurisdiction

This Agreement shall be governed by and construed in accordance with the laws of **Germany**, without regard to its conflict of law principles. Any legal action or proceeding arising under this Agreement will be brought exclusively before the competent courts of Germany, and the parties hereby consent to the personal jurisdiction and venue therein.

***

### 11. Entire Agreement

This Agreement constitutes the entire agreement between you and Licensor concerning the subject matter hereof and supersedes all prior or contemporaneous communications, agreements, and understandings — whether oral or written — relating to the Software.

***

### 12. Severability

If any provision of this Agreement is held to be invalid or unenforceable, the remaining provisions shall remain in full force and effect.

***

### 13. Amendments

Licensor reserves the right to modify or amend the terms of this Agreement at any time. Changes will be effective upon notice, which may be given by any reasonable means, including by posting the revised terms on Licensor's website or documentation. Your continued use of the Software after such notice constitutes your acceptance of the modified terms.

***

By installing or using the Software, you acknowledge that you have read, understood, and agree to be bound by the terms and conditions of this Software License Agreement.

**Copyright © Iynx. All rights reserved.**

***

## AthenaBot — Source License Agreement

**Version 1.1 — Effective Date: September 16, 2024**

{% hint style="info" %}
This agreement applies exclusively to licensees who have purchased access to the AthenaBot source code. It supersedes Version 1.0 for source-tier users.
{% endhint %}

***

### 1. Introduction

This Software License Agreement ("Agreement") is a legal contract between you ("Licensee") and Iynx ("Licensor") concerning your use of the software product **AthenaBot**, including its source code, any related documentation, updates, and support services (collectively referred to as "Software").

By installing, accessing, or otherwise using the Software, you agree to be bound by the terms of this Agreement. If you do not agree to these terms, do not install, access, or use the Software.

***

### 2. License Grant

Subject to the terms and conditions of this Agreement, Licensor grants you a **non-exclusive, non-transferable, non-sublicensable, limited license** to install, use, and modify the Software on multiple devices that you own, solely for your personal or internal business use.

Access to and modification of the source code is permitted under this Agreement, provided such modifications remain subject to the restrictions set out below.

***

### 3. Restrictions

You agree to the following restrictions:

* **No Sharing or Distribution** — You may not share, distribute, sell, lease, or transfer the Software, its source code, or any portion thereof to any third party — whether in whole or in part, and whether for commercial or non-commercial purposes — without explicit written permission from Licensor.
* **No Unauthorized Publication** — You may not publish, post, or otherwise make the Software's source code publicly available, including but not limited to open-source platforms or public repositories.
* **No Reselling** — You may not sell, sublicense, or exploit the Software, including its source code, for any commercial gain without prior written consent from Licensor.
* **Limited Modification Rights** — You may modify the source code solely for personal or internal business use. Any modified versions of the Software remain subject to the terms of this Agreement and may not be distributed without Licensor's explicit written permission.
* **No Unauthorized Environments** — You may not use the Software in any environment not explicitly authorized by Licensor, including but not limited to cloud computing environments or on devices not owned by you.
* **Administrative Access Reservation** — Licensor accounts shall retain administrator permissions on every AthenaBot instance at all times. Even where operational access is restricted to debugging and setup commands, such restrictions do not revoke or limit Licensor's administrator-level permissions. Access for all other parties remains subject to Licensor's role-based restrictions unless explicitly authorized otherwise in writing.

***

### 4. Ownership

The Software is **licensed, not sold**. Licensor retains all rights, title, and interest — including all intellectual property rights — in and to the Software, including any modifications made by you. This Agreement does not grant you any ownership rights in the Software. All rights not expressly granted are reserved by Licensor.

***

### 5. Confidentiality

The Software, including its source code, contains proprietary and confidential information belonging to Licensor. You agree to maintain the confidentiality of the Software and not to disclose, provide, or otherwise make available such information to any third party without the prior written consent of Licensor.

***

### 6. Updates and Support

Licensor may, at its sole discretion, provide updates or support services related to the Software. Any updates provided shall be subject to the terms of this Agreement. Licensor is under **no obligation** to provide support, updates, or maintenance for the Software.

***

### 7. Term and Termination

This Agreement is effective upon your acceptance and will remain in effect until terminated. Licensor may terminate this Agreement **immediately upon notice** if you fail to comply with any term herein.

Upon termination, you must immediately:

* Cease all use of the Software.
* Destroy all copies of the Software in your possession, including any modified versions.
* Provide written confirmation of such destruction upon request by Licensor.

***

### 8. Disclaimer of Warranties

The Software is provided **"as is"** without warranty of any kind, express or implied, including but not limited to the implied warranties of merchantability, fitness for a particular purpose, and non-infringement. Licensor does not warrant that the Software will meet your requirements or that its operation will be uninterrupted or error-free.

***

### 9. Limitation of Liability

To the maximum extent permitted by applicable law, in no event shall Licensor be liable for any special, incidental, indirect, or consequential damages whatsoever — including but not limited to damages for loss of business profits, business interruption, loss of business information, or any other pecuniary loss — arising out of the use of or inability to use the Software, even if Licensor has been advised of the possibility of such damages.

***

### 10. Governing Law and Jurisdiction

This Agreement shall be governed by and construed in accordance with the laws of **Germany**, without regard to its conflict of law principles. Any legal action or proceeding arising under this Agreement will be brought exclusively before the competent courts of Germany, and the parties hereby consent to the personal jurisdiction and venue therein.

***

### 11. Entire Agreement

This Agreement constitutes the entire agreement between you and Licensor concerning the subject matter hereof and supersedes all prior or contemporaneous communications, agreements, and understandings — whether oral or written — relating to the Software.

***

### 12. Severability

If any provision of this Agreement is held to be invalid or unenforceable, the remaining provisions shall remain in full force and effect.

***

### 13. Amendments

Licensor reserves the right to modify or amend the terms of this Agreement at any time. Changes will be effective upon notice, which may be given by any reasonable means, including by posting the revised terms on Licensor's website or documentation. Your continued use of the Software after such notice constitutes your acceptance of the modified terms.

***

By installing, accessing, or using the Software, you acknowledge that you have read, understood, and agree to be bound by the terms and conditions of this Software License Agreement.

**Copyright © Iynx. All rights reserved.**


# Iynx API

**Last updated: March 3, 2026**

By accessing or using the Iynx API ("the API"), you agree to be bound by these Terms of Service ("Terms"). If you do not agree to these Terms, you are not permitted to access or use the API in any way.

***

## 1. Restricted Access

Access to the Iynx API is **strictly restricted**. Use of the API requires explicit, prior written authorization from Iynx Development. Unauthorized access attempts are prohibited and may result in legal action.

* Access is granted solely on a case-by-case basis at the sole discretion of Iynx Development.
* Any granted access may be revoked at any time, with or without notice, for any reason.
* Credentials, API keys, and tokens issued to you are personal and non-transferable. You may not share, sell, lease, or sublicense your access to any third party.

***

## 2. Permitted Use

The Iynx API is used internally by Athena and other Iynx products to power their built-in features. This intended, program-native usage is explicitly permitted and requires no additional authorization.

However, any use **beyond** this built-in, intended scope — including but not limited to sending custom API requests, integrating the API into external tools, or accessing API endpoints directly outside of the program — is **not permitted** without explicit, prior written authorization from Iynx Development.

In short: if the program does it as part of its normal operation, it is allowed. Anything you initiate yourself on top of or outside of that is not.

***

## 3. Prohibited Use

The following activities are strictly prohibited when using the Iynx API:

* **Unintended Use** — You may only use the API for the specific, explicitly approved purpose for which access was granted. Any use beyond the approved scope is forbidden.
* **Reverse Engineering** — You may not decompile, disassemble, reverse-engineer, or otherwise attempt to derive the source code, underlying logic, or structure of the API.
* **Automated Abuse** — You may not use the API to send excessive requests, conduct stress tests, perform denial-of-service attacks, or otherwise disrupt the availability or performance of the API.
* **Data Harvesting** — You may not scrape, collect, store, or redistribute data obtained through the API beyond what is strictly necessary for the approved use case.
* **Malicious Activity** — You may not use the API to distribute malware, conduct phishing, facilitate fraud, or engage in any illegal or harmful activity.
* **Circumvention** — You may not attempt to bypass rate limits, authentication mechanisms, IP restrictions, or any other security measures implemented by Iynx Development.
* **Reselling or Redistribution** — You may not resell, redistribute, republish, or otherwise make the API or its data available to third parties without express written consent.

***

## 4. No Warranty & Limitation of Liability

The API is provided **"as is"** and **"as available"** without any warranties of any kind, express or implied, including but not limited to warranties of merchantability, fitness for a particular purpose, or non-infringement.

Iynx Development shall not be liable for any direct, indirect, incidental, special, consequential, or exemplary damages resulting from your use of or inability to use the API, even if advised of the possibility of such damages.

***

## 5. Rate Limits & Fair Use

Iynx Development reserves the right to impose rate limits, quotas, and usage restrictions at any time. Exceeding imposed limits will result in temporary or permanent suspension of API access without prior notice.

***

## 6. Monitoring & Enforcement

Iynx Development reserves the right to monitor all API usage to ensure compliance with these Terms. Any violation may result in:

* Immediate and permanent revocation of API access.
* Removal from any affiliated services or platforms.
* Reporting to relevant authorities where applicable.

***

## 7. Changes to These Terms

Iynx Development reserves the right to modify these Terms at any time. Continued use of the API following any such changes constitutes your acceptance of the revised Terms. It is your responsibility to review these Terms regularly.

***

## 8. Contact

If you have questions regarding these Terms or wish to request API access, please contact Iynx Development through official channels.


# Community Addons

Iynx Development offers the opportunity to create, share, and request community-built plugins for AthenaBot. These community-driven plugins are **completely independent from Iynx Development** and are not officially supported, maintained, or endorsed by us.

{% hint style="warning" %}
Access to requesting, sharing, or downloading community plugins requires a valid purchase of [AthenaBot](https://builtbybit.com/resources/athenabot-discord-server-bot.28547/).
{% endhint %}

***

## Sharing Plugins

When sharing a plugin in the community plugins channel, the following rules apply:

* You are **not allowed** to recreate any addon already officially offered by Iynx Development.
* If your plugin is **free**, it must be **open source**.
* If your plugin is **monetized**, you must open a ticket and provide Iynx Development with the full source code for verification **before** offering it for sale. You may sell either the source code or an obfuscated version of your plugin.
* Your community post must comply with our Discord server rules. Discord invite links are **not permitted**, but you may include your BuiltByBit product link.
* Use the correct tag when creating a post (`paid` / `free`).
* Provide a short and clear description of what your plugin does.
* If your plugin depends on third-party libraries, list them clearly in your post.
* Do **not** include any malicious, harmful, or deceptive content in your plugins.

***

## Requesting Plugins

When submitting a plugin request, the following rules apply:

* Be as **specific as possible** when describing your request.
* Check whether a similar plugin already exists before submitting a new request.
* If you are offering payment for a development request, use the appropriate tag.

***

## Downloading & Using Plugins

* Iynx Development is **not responsible** for any issues, damages, or data loss caused by community-made plugins.
* All community plugins are provided for **personal use only**, unless explicitly stated otherwise by the original developer.
* You may **not** redistribute, resell, or claim ownership of a plugin unless you are the original author or have been given explicit written permission by the author.

***

## Enforcement

We take the security of our members and the effort developers invest in their plugins very seriously.

The following actions will **not be tolerated** and may result in disciplinary measures, including Discord bans and termination of your Athena license:

* Stealing or copying plugin code without permission
* Redistributing plugins without the author's explicit consent
* Including malware, obfuscated harmful code, or any other malicious components in shared plugins
* Misrepresenting the origin, authorship, or licensing of a plugin

***

## Plugin Development

The official plugin template for AthenaBot is available on [GitHub](https://github.com/Zeroknights16/AthenaBot-PluginTemplate). It includes the source code of one command and one event used in Athena as a reference.

The plugin development documentation can be found in the [template wiki](https://github.com/Zeroknights16/AthenaBot-PluginTemplate/wiki).

If you have any questions, please open a ticket in our Discord server.


# Privacy

**Version 1.0 — Effective Date: March 3, 2026**

***

## 1. Introduction

This Privacy Policy ("Policy") describes how **Iynx** ("we", "us", or "our") collects, uses, stores, and protects personal and technical data in connection with your use of **AthenaBot** and associated services, including our licensing system, dashboard, and API (collectively, the "Services").

By purchasing, activating, or using the Services, you acknowledge that you have read and understood this Policy. If you do not agree with the practices described herein, please discontinue use of the Services.

***

## 2. Data We Collect

When you register and use the Services, we collect and store the following categories of data:

### 2.1 Account & License Information

We collect identifying information necessary to manage your license, including your username, Discord account details, marketplace account information (e.g. BuiltByBit), and your unique license key. We also store metadata such as when your license was created, your last login timestamp, and any sub-users associated with your account.

### 2.2 Network & Device Data

To enforce license boundaries and prevent unauthorized use, we collect IP addresses and hardware identifiers (HWIDs) of devices used to activate the Services. Each entry is stored alongside a timestamp of first registration. The number of permitted IPs is also tracked per license.

### 2.3 Discord Server Data

We store the Discord server IDs of servers where AthenaBot is installed and operated under your license. This is used solely to validate and scope your license to its authorized environments.

### 2.4 Feature Entitlements

We store a record of which premium features and add-ons are active on your license. This is used to control access to functionality within the Services.

### 2.5 API Access Data

If you use our API, we collect your API keys, generation timestamps, request counts, rate-limiting status, and IP whitelist settings. This data is used exclusively to authenticate requests, enforce usage limits, and maintain the security of our API.

### 2.6 Usage Metrics

We record aggregate usage counters, such as the total number of license validation requests made. This data is used for monitoring, abuse detection, and service stability.

***

## 3. How We Use Your Data

We use the collected data for the following purposes:

* **License validation and enforcement** — to verify that your license is active and being used within its permitted scope (IP limits, HWID limits, guild assignments).
* **Fraud prevention and abuse detection** — to identify unauthorized sharing, reverse engineering, or misuse of the Software.
* **Account management** — to manage your account, sub-users, and feature entitlements.
* **API access control** — to authenticate requests, enforce rate limits, and maintain the security and stability of our API.
* **Support and troubleshooting** — to diagnose technical issues and assist you when requested.
* **Service improvement** — aggregated, anonymized usage metrics may be used to improve and develop the Services.

***

## 4. Data Retention

We retain your data for the full duration of your active license and for a reasonable period thereafter in order to comply with legal obligations, resolve disputes, and enforce our agreements. Data associated with terminated or expired licenses may be retained in anonymized or aggregated form.

You may request deletion of your personal data by contacting us at the details provided in Section 9. Requests are subject to our ability to fulfill them while remaining compliant with applicable law and our legitimate business interests.

***

## 5. Data Sharing and Disclosure

We do not sell, trade, or rent your personal data to third parties. We may disclose your data only in the following circumstances:

* **Service providers** — trusted third-party services that operate infrastructure on our behalf (e.g., database hosting), subject to confidentiality obligations.
* **Legal requirements** — when required to do so by law, court order, or governmental authority.
* **Protection of rights** — when we believe disclosure is necessary to protect the rights, property, or safety of Iynx, our users, or others.
* **Business transfers** — in the event of a merger, acquisition, or transfer of all or part of our assets, your data may be transferred as part of that transaction.

***

## 6. Data Security

We implement reasonable technical and organizational security measures to protect your data against unauthorized access, alteration, disclosure, or destruction. These include access controls, encrypted storage, and monitoring of our systems.

However, no method of transmission over the internet or electronic storage is entirely secure. We cannot guarantee absolute security and are not liable for unauthorized access beyond what is reasonably preventable.

***

## 7. IP Address and Hardware ID Data

IP addresses and hardware identifiers are collected solely for the purpose of license validation and enforcement. This data is used to verify that the Software is being operated within the authorized limits of your license plan. We do not use this data for advertising, behavioral tracking, or any purpose unrelated to service operation.

Each IP address entry and HWID entry is stored alongside a timestamp indicating when it was first recorded.

***

## 8. Your Rights

Depending on your jurisdiction, you may have the following rights regarding your personal data:

* **Access** — the right to request a copy of the data we hold about you.
* **Rectification** — the right to request correction of inaccurate or incomplete data.
* **Erasure** — the right to request deletion of your data, subject to legal retention requirements.
* **Restriction** — the right to request that we limit the processing of your data.
* **Objection** — the right to object to certain processing activities.

To exercise any of these rights, please contact us through our official support channels.

***

## 9. Contact

If you have any questions, concerns, or requests regarding this Privacy Policy or our data practices, please contact us through our official Discord server or support portal.

***

## 10. Changes to This Policy

We reserve the right to update or modify this Privacy Policy at any time. Changes will be posted with an updated effective date. Continued use of the Services after any such changes constitutes your acceptance of the revised Policy. We encourage you to review this Policy periodically.

***

## 11. Governing Law

This Policy is governed by and construed in accordance with the laws of **Germany**, without regard to its conflict of laws principles.


