← Back to lessons
API COURSE

Lesson 2 — ER:LC Commands

Goal: Send commands to your ER:LC private server using the API pack.

Lesson Overview

This lesson introduces sending commands to your ER:LC server using the API pack. You will learn how commands are built and sent to the ERLC endpoint.

Video Lesson

Notes — Understanding the Code

COMMAND_MAP

This converts friendly command names into ERLC command prefixes like :h, :m, or :ban.

SlashCommandBuilder

Creates the slash command that users run in Discord.

interaction.options

Gets the options the user selected when running the command.

fetch()

Sends a request to the ERLC API to execute a command on the private server.

Server-Key

Your ERLC API key used to authenticate the request.

EmbedBuilder

Formats the response message sent back to Discord.

Step-by-Step

Create the command file

Create: commands/erlc.js

Add the API key

{
"TOKEN": "",
"APP_ID": "",
"MONGOURI": "",
"GUILD_ID": "",
"ERLC_API_KEY": ""
}

Add the ERLC Command

Show Code

const { SlashCommandBuilder } = require('@discordjs/builders');
const { EmbedBuilder } = require('discord.js');

const config = require("../config.json");

const COMMAND_MAP = {
    hint: ':h',
    message: ':m',
    ban: ':ban',
    unban: ':unban',
    h: ':h',
    m: ':m',
    pm: ':pm'
};

const USER_REQUIRED = ['ban', 'unban', 'privateMessage', 'pm'];

module.exports = {
    dev: true,
    guilds: [''],
    roles: [''],
    users: [''],
    cooldown: 0,
    userPerms: [''],
    clientPerms: [''],
    alias: '',
    aliases: [''],
    defer: false,
    cache: true,
    data: new SlashCommandBuilder()
        .setName('erlc')
        .setDescription('Run a command in your ER:LC server.')
        .addStringOption((option) =>
            option
                .setName('command')
                .setDescription('The command to run.')
                .setRequired(true)
                .addChoices(
                    { name: 'Hint (:h)', value: 'hint' },
                    { name: 'Message (:m)', value: 'message' },
                    { name: 'Private Message (:pm)', value: 'pm' },
                    { name: 'Ban (:ban)', value: 'ban' },
                    { name: 'Unban (:unban)', value: 'unban' }
                )
        )
        .addStringOption((option) =>
            option
                .setName('user')
                .setDescription('User to target in-game.')
                .setRequired(false)
        )
        .addStringOption((option) =>
            option
                .setName('content')
                .setDescription('The message content')
                .setRequired(false)
        ),
    async execute(interaction) {

        const commandKey = interaction.options.getString("command");
        const user = interaction.options.getString("user");
        const content = interaction.options.getString("content");

        const prefix = COMMAND_MAP[commandKey];

        if (USER_REQUIRED.includes(commandKey) && !user) {
            return interaction.editReply({
                embeds: [
                    new EmbedBuilder()
                        .setDescription(`The \`${commandKey}\` command requires a user to be specified.`)
                ]
            });
        }

        let fullCommand;

        if (commandKey === "pm") {

            if (!content) {
                return interaction.editReply({
                    embeds: [
                        new EmbedBuilder()
                            .setDescription(`The \`pm\` command requires both a **user** and **content**.`)
                    ]
                });
            }

            fullCommand = `${prefix} ${user} ${content}`;

        } else if (USER_REQUIRED.includes(commandKey)) {

            fullCommand = content
                ? `${prefix} ${user} ${content}`
                : `${prefix} ${user}`;

        } else {

            if (!content) {
                return interaction.editReply({
                    embeds: [
                        new EmbedBuilder()
                            .setDescription(`The \`${commandKey}\` command requires **content**.`)
                    ]
                });
            }

            fullCommand = `${prefix} ${content}`;

        }

        try {

            const response = await fetch(
                'https://api.policeroleplay.community/v1/server/command',
                {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                        "Server-Key": config.ERLC_API_KEY
                    },
                    body: JSON.stringify({
                        command: fullCommand
                    }),
                }
            );

            if (!response.ok) {

                const errorData = await response.json().catch(() => null);
                const errorMessage = errorData?.message ?? `HTTP ${response.status}`;

                return interaction.editReply({
                    embeds: [
                        new EmbedBuilder()
                            .setDescription(`Failed to execute command.\n\`\`\`${errorMessage}\`\`\``)
                    ]
                });

            }

            return interaction.editReply({
                embeds: [
                    new EmbedBuilder()
                        .setTitle('Command executed!')
                        .addFields({
                            name: 'Command',
                            value: `\`${fullCommand}\``,
                        })
                        .setFooter({
                            text: `Executed by ${interaction.user.tag}`,
                        })
                        .setTimestamp(),
                ],
            });

        } catch (err) {

            console.error('ERLC Command Error:', err);

            return interaction.editReply({
                embeds: [
                    new EmbedBuilder()
                        .setDescription('An unexpected error occurred while contacting the ERLC API.')
                ],
            });

        }

    },
};

Restart the bot


node index.js

Challenge

Completion Checklist

← Lesson 1 Next Lesson →