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.
- Base URL:
https://discordbot.fr/api/v1 - Format: JSON (
Content-Type: application/json) - Markdown version of this page, to give to an AI: https://discordbot.fr/en/bots/api.md
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,daysfrom 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 |