API documentation

Markdown version (for your AI)

This API lets your bot post its server count (rankings, charts) and check whether a user voted for it.

Authentication

Generate a token on your bot’s edit page (Dashboard → My bots → Edit → API and statistics). It starts with dbt_ and is shown only once: generating a new one revokes the old one.

Send it in the header Authorization (Bearer is accepted but optional):

Authorization: dbt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

The token is secret: keep it server-side (environment variable), never in published code or in a browser. A token only works for its own bot.

Post statistics

POST /api/v1/bots/{bot_id}/stats — token required

Field Type Required Description
server_count integer yes Server count (0 to 50,000,000)
shard_count integer no Shard count (1 to 100,000)

Response: 200 { "ok": true }

Post them on startup, then about every 30 minutes. Limit: 30 requests per minute per token.

curl -X POST "https://discordbot.fr/api/v1/bots/BOT_ID/stats" \
  -H "Authorization: $DISCORDBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"server_count": 1234, "shard_count": 1}'

discord.js (Node 18+)

async function postStats(client) {
  const res = await fetch(`https://discordbot.fr/api/v1/bots/${client.user.id}/stats`, {
    method: "POST",
    headers: { Authorization: process.env.DISCORDBOT_TOKEN, "Content-Type": "application/json" },
    body: JSON.stringify({ server_count: client.guilds.cache.size, shard_count: client.shard?.count ?? 1 }),
  });
  if (!res.ok) console.warn("discordbot.fr stats:", res.status, await res.text());
}

client.once("ready", () => {
  postStats(client);
  setInterval(() => postStats(client), 30 * 60 * 1000);
});

With several shards, post the total from a single shard (for example the sum of client.shard.fetchClientValues("guilds.cache.size") on shard 0), otherwise each shard overwrites the others’ count.

discord.py

import os, aiohttp
from discord.ext import tasks

@tasks.loop(minutes=30)
async def post_stats():
    async with aiohttp.ClientSession() as session:
        await session.post(
            f"https://discordbot.fr/api/v1/bots/{bot.user.id}/stats",
            headers={"Authorization": os.environ["DISCORDBOT_TOKEN"]},
            json={"server_count": len(bot.guilds), "shard_count": bot.shard_count or 1},
        )

@post_stats.before_loop
async def before_post_stats():
    await bot.wait_until_ready()

# in setup_hook or on_ready: post_stats.start()

Check a vote

GET /api/v1/bots/{bot_id}/check?userId={user_id} — token required

Tells whether the user voted in the last 12 hours (one vote every 12 h). Limit: 120 requests per minute per token.

{ "voted": 1, "nextVoteAt": "2026-01-01T12:00:00.000Z" }

voted is 1 or 0; nextVoteAt is when the user can vote again, or null.

Vote webhook

Set a webhook URL (public HTTPS) on the edit page: on every vote we send a JSON POST. If you set a secret, it is sent as is in the Authorization header: check it before trusting the request. The “Test the webhook” button sends a test call.

{ "bot": "BOT_ID", "user": "USER_ID", "type": "upvote", "isWeekend": false, "query": "" }

type is upvote or test. Answer with a 2xx code within 5 seconds; redirects are not followed and failed calls are not retried.

Public endpoints

No token, CORS open, published bots only.

  • GET /api/v1/bots/{bot_id} — bot profile (cached 60 s):
{
  "id": "BOT_ID",
  "name": "My bot",
  "avatar_url": "https://cdn.discordapp.com/avatars/...",
  "short_description": "...",
  "tags": ["moderation"],
  "server_count": 1234,
  "shard_count": 1,
  "votes_total": 56,
  "votes_month": 7,
  "url": "https://discordbot.fr/bot/BOT_ID"
}
  • GET /api/v1/bots/{bot_id}/history?days=90 — daily history, days from 1 to 730 (cached 5 min, 120 requests per minute per IP):
{ "id": "BOT_ID", "days": 90, "points": [{ "day": "2026-01-01", "server_count": 1234, "shard_count": 1, "votes": 3 }] }

Errors

Errors return { "error": "code" }.

HTTP Code Meaning
400 invalid_fields Invalid field, listed in fields
401 invalid_token Missing or revoked token
403 token_mismatch The token belongs to another bot
404 not_found Unknown or unpublished bot
429 rate_limited Too many requests, retry in a minute
503 directory_unavailable Directory temporarily unavailable