TopDiscordServers
Home Servers Bots
Server Categories Bot Categories
List Your Server List Your Bot
Blog About
Log in
  1. Home
  2. Discord Bot Vote Command Docs
Developer Docs

Discord Bot Vote Command Guide

Add a vote command to your Discord bot with examples you can adapt to your project. Any language that can send an HTTP POST request will work.

Endpoint: https://topdiscordservers.com/api/external/discord-servers/{discordServerId}/vote Python, JS/TS, Java, C#, PHP, Go

Test your request and inspect the JSON response before you deploy.

Open API Tester

Sections

  • Quick Start
  • API Contract
  • Variables and Errors
  • Command Examples (Tabs)
  • Safety Checklist

01 Quick Start

  1. Generate an External API key in your admin panel.
  2. Copy your Discord Server ID from Discord.
  3. Add required environment variables: TDS_API_KEY and TDS_DISCORD_SERVER_ID.
  4. In your bot command, call POST /api/external/discord-servers/{discordServerId}/vote.
  5. Send user Discord ID and direction in JSON.
  6. Send the success or cooldown response back to Discord.
Keep your API key private. Don’t put it in browser code or a public repository.

Environment variables (required):

TDS_API_KEY=your_external_api_key
TDS_DISCORD_SERVER_ID=your-discord-server-id

Examples by runtime:

# Node.js / Python / PHP (dotenv)
TDS_API_KEY=your_external_api_key
TDS_DISCORD_SERVER_ID=your-discord-server-id

# Java (JVM args)
-DTDS_API_KEY=your_external_api_key
-DTDS_DISCORD_SERVER_ID=your-discord-server-id

# C# / Windows PowerShell
$env:TDS_API_KEY="your_external_api_key"
$env:TDS_DISCORD_SERVER_ID="your-discord-server-id"

# Linux/macOS shell
export TDS_API_KEY="your_external_api_key"
export TDS_DISCORD_SERVER_ID="your-discord-server-id"

02 API Contract

Use any of these auth methods:

Authorization: Bearer YOUR_API_KEY X-API-Key: YOUR_API_KEY api_key in request JSON

Payload fields:

{
  "discord_user_id": "123456789012345678",
  "direction": "up"
}

Also accepted:

{
  "user_id": "123456789012345678",
  "direction": "upvote"
}

Success response:

{
  "message": "Vote recorded.",
  "data": {
    "discordServerId": "123456789012345678",
    "votes": 101,
    "appliedDelta": 1,
    "direction": "up",
    "voterDiscordId": "123456789012345678"
  }
}

03 Variables and Errors

What each variable means:

Variable Example of the output
TDS_API_KEY tds_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
External API key generated in admin.
TDS_DISCORD_SERVER_ID 123456789012345678
Discord server ID (guild ID) for the target server.
discord_user_id 123456789012345678
Discord ID of the user who ran the command.
direction up
Vote direction. Normally use up for positive votes.
user_id / voter_id 123456789012345678
Accepted aliases for discord_user_id.

Allowed direction values:

Input value How the API treats it
up Up vote
down Down vote
upvote Normalized to up
downvote Normalized to down
1 Normalized to up
-1 Normalized to down

Possible error responses:

Status Example of the output
401 Unauthorized Missing API key.
{
  "message": "API key required."
}
401 Unauthorized Invalid or revoked API key.
{
  "message": "Invalid or revoked API key."
}
404 Not Found Discord server ID not found.
{
  "message": "Server not found."
}
403 Forbidden Discord user is not registered on the site.
{
  "message": "User not registered. Please register and link Discord before voting.",
  "registerUrl": "https://topdiscordservers.com/login"
}
422 Unprocessable Entity Validation failed (usually bad discord_user_id).
{
  "message": "The given data was invalid.",
  "errors": {
    "discord_user_id": [
      "discord_user_id must be a numeric Discord user ID."
    ]
  }
}
429 Too Many Requests User is on cooldown and cannot vote yet.
{
  "message": "Vote limit reached.",
  "retryAfterSeconds": 20473,
  "retryAfterHuman": "5h 41m",
  "voteLimitPerDay": 4,
  "cooldownWindow": "6h",
  "nextAllowedAt": "2026-08-04T08:43:15+00:00"
}
503 Service Unavailable Temporary backend/API-key storage issue.
{
  "message": "External voting is temporarily unavailable."
}
Handling tip: if you get 429, show a friendly cooldown message in Discord using retryAfterHuman.

04 Command Examples (Tabbed)

Click a language tab to show that bot command example.

Install:

npm install discord.js node-fetch
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const fetch = require('node-fetch');

const API_KEY = process.env.TDS_API_KEY;
const DISCORD_SERVER_ID = process.env.TDS_DISCORD_SERVER_ID;

module.exports = {
  data: new SlashCommandBuilder().setName('vote').setDescription('Vote for our server'),
  async execute(interaction) {
    const response = await fetch(`https://topdiscordservers.com/api/external/discord-servers/${DISCORD_SERVER_ID}/vote`, {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${API_KEY}`,
        'Content-Type': 'application/json',
        Accept: 'application/json',
      },
      body: JSON.stringify({ discord_user_id: interaction.user.id, direction: 'up' }),
    });

    const data = await response.json();
    if (!response.ok) {
      const errorEmbed = new EmbedBuilder()
        .setTitle('Vote Failed')
        .setColor(0xED4245)
        .setDescription(data.message || 'Unknown error')
        .addFields(
          { name: 'Status', value: String(response.status), inline: true },
          { name: 'Code', value: data.error_code || 'n/a', inline: true }
        )
        .setTimestamp();

      if (response.status === 429 && data.retryAfterHuman) {
        errorEmbed.addFields({ name: 'Try Again In', value: data.retryAfterHuman, inline: true });
      }

      await interaction.reply({ embeds: [errorEmbed], ephemeral: true });
      return;
    }

    await interaction.reply({ content: `Vote recorded. Total votes: ${data.data.votes}` });
  },
};

Install:

pip install discord.py aiohttp
import asyncio
import os
        from typing import Any

        import aiohttp
        import discord
        from discord import app_commands
        from discord.ext import commands

        API_BASE_URL = os.getenv("TDS_API_BASE_URL", "https://topdiscordservers.com").rstrip("/")
        API_KEY = os.getenv("TDS_API_KEY", "")
        DISCORD_SERVER_ID = os.getenv("TDS_DISCORD_SERVER_ID", "")


        class Vote(commands.Cog):
          def __init__(self, bot: commands.Bot) -> None:
            self.bot = bot

          @app_commands.command(name="vote", description="Vote for our server")
          async def vote(self, interaction: discord.Interaction) -> None:
            if not API_KEY or not DISCORD_SERVER_ID:
              await interaction.response.send_message(
                "Vote integration is not configured yet.",
                ephemeral=True,
              )
              return

            endpoint = f"{API_BASE_URL}/api/external/discord-servers/{DISCORD_SERVER_ID}/vote"
            payload = {
              "discord_user_id": str(interaction.user.id),
              "direction": "up",
            }
            headers = {
              "Authorization": f"Bearer {API_KEY}",
              "Content-Type": "application/json",
              "Accept": "application/json",
            }

            timeout = aiohttp.ClientTimeout(total=10)
            data: dict[str, Any] = {}
            status = 0

            try:
              async with aiohttp.ClientSession(timeout=timeout) as session:
                async with session.post(endpoint, json=payload, headers=headers) as resp:
                  status = resp.status
                  data = await resp.json(content_type=None)
            except asyncio.TimeoutError:
              await interaction.response.send_message(
                "Vote request timed out. Please try again.",
                ephemeral=True,
              )
              return
            except aiohttp.ClientError:
              await interaction.response.send_message(
                "Vote service is unavailable right now. Please try again later.",
                ephemeral=True,
              )
              return

            if status >= 400:
              message = data.get("message", "Unknown error")
              error_embed = discord.Embed(
                "Vote Failed",
                description=message,
                color=discord.Color.red(),
              )
              error_embed.add_field(name="Status", value=str(status), inline=True)

              if status == 429 and data.get("retryAfterHuman"):
                error_embed.add_field(name="Try Again In", value=str(data["retryAfterHuman"]), inline=True)

              if status == 403 and data.get("registerUrl"):
                error_embed.add_field(name="Register", value=str(data["registerUrl"]), inline=False)

              await interaction.response.send_message(embed=error_embed, ephemeral=True)
              return

            votes = data.get("data", {}).get("votes", "?")
            await interaction.response.send_message(f"Vote recorded. Total votes: {votes}")


        async def setup(bot: commands.Bot) -> None:
          await bot.add_cog(Vote(bot))
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.awt.Color;

public class VoteCommand {
    private static final String API_KEY = System.getenv("TDS_API_KEY");
    private static final String DISCORD_SERVER_ID = System.getenv("TDS_DISCORD_SERVER_ID");

    public static void handle(SlashCommandInteractionEvent event) throws Exception {
        String url = "https://topdiscordservers.com/api/external/discord-servers/" + DISCORD_SERVER_ID + "/vote";
        String payload = "{\"discord_user_id\":\"" + event.getUser().getId() + "\",\"direction\":\"up\"}";

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(url))
            .header("Authorization", "Bearer " + API_KEY)
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(payload))
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
          EmbedBuilder embed = new EmbedBuilder()
            .setTitle("Vote Failed")
            .setDescription("Status " + response.statusCode() + "\\n```json\\n" + response.body() + "\\n```")
            .setColor(Color.RED);
          event.replyEmbeds(embed.build()).setEphemeral(true).queue();
            return;
        }

        event.reply("Vote recorded.").queue();
    }
}
using System.Net.Http;
using System.Text;
using System.Text.Json;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;

public class VoteCommands : ApplicationCommandModule
{
    private static readonly HttpClient Http = new HttpClient();
    private static readonly string ApiKey = Environment.GetEnvironmentVariable("TDS_API_KEY");
    private static readonly string DiscordServerId = Environment.GetEnvironmentVariable("TDS_DISCORD_SERVER_ID");

    [SlashCommand("vote", "Vote for our server")]
    public async Task Vote(InteractionContext ctx)
    {
        var url = $"https://topdiscordservers.com/api/external/discord-servers/{DiscordServerId}/vote";
        var body = JsonSerializer.Serialize(new { discord_user_id = ctx.User.Id.ToString(), direction = "up" });

        using var request = new HttpRequestMessage(HttpMethod.Post, url);
        request.Headers.Add("Authorization", $"Bearer {ApiKey}");
        request.Content = new StringContent(body, Encoding.UTF8, "application/json");

        var response = await Http.SendAsync(request);
        var payload = await response.Content.ReadAsStringAsync();
        if (!response.IsSuccessStatusCode)
        {
          string message = "Unknown error";
          string code = "n/a";
          string retryAfterHuman = null;

          try
          {
            using var doc = JsonDocument.Parse(payload);
            var root = doc.RootElement;
            if (root.TryGetProperty("message", out var m)) message = m.GetString() ?? message;
            if (root.TryGetProperty("error_code", out var c)) code = c.GetString() ?? code;
            if (root.TryGetProperty("retryAfterHuman", out var r)) retryAfterHuman = r.GetString();
          }
          catch
          {
            message = payload;
          }

          var embed = new DiscordEmbedBuilder()
            .WithTitle("Vote Failed")
            .WithDescription(message)
            .WithColor(DiscordColor.Red)
            .AddField("Status", ((int)response.StatusCode).ToString(), true)
            .AddField("Code", code, true);

          if ((int)response.StatusCode == 429 && !string.IsNullOrWhiteSpace(retryAfterHuman))
          {
            embed.AddField("Try Again In", retryAfterHuman, true);
          }

          await ctx.CreateResponseAsync(new DiscordInteractionResponseBuilder().AddEmbed(embed), true);
            return;
        }

        await ctx.CreateResponseAsync("Vote recorded.");
    }
}
use GuzzleHttp\Client;

$client = new Client();
$apiKey = getenv('TDS_API_KEY');
$discordServerId = getenv('TDS_DISCORD_SERVER_ID');

$response = $client->post("https://topdiscordservers.com/api/external/discord-servers/{$discordServerId}/vote", [
    'headers' => [
        'Authorization' => 'Bearer '.$apiKey,
        'Accept' => 'application/json',
    ],
    'json' => [
        'discord_user_id' => (string) $discordUserId,
        'direction' => 'up',
    ],
]);

$payload = json_decode((string) $response->getBody(), true);
package main

import (
  "bytes"
  "net/http"
  "os"
)

func vote(discordUserID string) (*http.Response, error) {
  discordServerID := os.Getenv("TDS_DISCORD_SERVER_ID")
  apiKey := os.Getenv("TDS_API_KEY")
  body := []byte(`{"discord_user_id":"` + discordUserID + `","direction":"up"}`)

  req, _ := http.NewRequest("POST", "https://topdiscordservers.com/api/external/discord-servers/"+discordServerID+"/vote", bytes.NewBuffer(body))
  req.Header.Set("Authorization", "Bearer "+apiKey)
  req.Header.Set("Content-Type", "application/json")
  req.Header.Set("Accept", "application/json")

  client := &http.Client{}
  return client.Do(req)
}
curl -X POST "https://topdiscordservers.com/api/external/discord-servers/123456789012345678/vote" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"discord_user_id":"123456789012345678","direction":"up"}'
Tip: send the slash-command user’s ID as discord_user_id so cooldowns apply to the right person.

05 Safety Checklist

  • Store the API key in an environment variable. Never hard-code it in source control.
  • Use ephemeral Discord replies for errors and cooldown notices.
  • Log non-200 responses so you can trace invalid keys and malformed payloads.
  • Use one API key per bot or environment. That makes rotation easier.
  • Run every change through the API Tester before deploying.
TopDiscordServers

A place to find Discord servers and bots worth joining, sorted by real votes from real members.

Quick Links

Discord Servers Discord Bots Server Categories Bot Categories Statistics

Support

Contact Support FAQ Community Rules

Tools

Platform Features Discord Vote Bot New Discord Emoji Library New Discord Embed Builder New Discord Vote API Docs

Company

About Us Partnership Blog Privacy Policy Terms of Service

© 2026 TopDiscordServers. All rights reserved. Not affiliated with Discord.