dlist.space
v1.0.0
Published
Official Node.js SDK for dlist.space — post bot stats, check votes, and listen for vote webhooks.
Maintainers
Readme
dlist.space
The official Node.js package for dlist.space. Post your bot's stats, check votes, and listen for vote webhooks — without writing boilerplate HTTP code.
npm install dlist.spaceRequires Node.js 16 or later. No production dependencies — just Node's built-in
http/httpsmodules.
Getting started
Grab your bot ID and API token from your bot's dashboard on dlist.space (Settings → API Token), then:
const { DlistClient } = require("dlist.space");
const dlist = new DlistClient({
botId: "YOUR_BOT_ID",
token: "YOUR_API_TOKEN",
});Posting stats
The easiest way is autopost. Call it once after your bot logs in and it handles everything — posts immediately, again every 30 minutes, and also fires on guildCreate / guildDelete.
bot.once("ready", () => {
dlist.autopost(bot);
});Want more control?
const { stop } = dlist.autopost(bot, {
interval: 15 * 60 * 1000, // every 15 min instead of 30
onPost: (res) => console.log("posted:", res.message),
onError: (err) => console.error("failed:", err.message),
});
// call stop() if you ever need to shut it down cleanly
process.on("SIGINT", () => { stop(); process.exit(0); });Or post manually whenever you feel like it:
await dlist.postStats({
server_count: bot.guilds.cache.size, // required
user_count: bot.users.cache.size, // optional
shard_count: bot.shard?.count, // optional
});If you post too often the API will rate limit you (once per 5 minutes). Instead of throwing, postStats logs a warning and returns { rateLimited: true, retry_after: 240 } so your bot doesn't crash.
Checking if a user voted
Votes are valid for 12 hours. Use hasVoted in your reward commands:
const { voted, timeLeft } = await dlist.hasVoted(interaction.user.id);
if (voted) {
await interaction.reply("Thanks for voting! Here's your reward.");
} else {
const hrs = (timeLeft / 3_600_000).toFixed(1);
await interaction.reply(`You already claimed this — vote again in ${hrs}h.`);
}Vote webhooks
dlist.space POSTs to your server every time someone votes. You need a public URL and a secret key configured in your bot's dashboard (Settings → Webhooks).
Standalone server — simplest option if you don't already have an HTTP server running:
const { WebhookListener } = require("dlist.space");
const listener = new WebhookListener({
webhookKey: process.env.DLIST_WEBHOOK_KEY,
port: 3000,
});
listener.on("vote", ({ user_id, username, weekend, test }) => {
if (test) return; // ignore test pings from the dashboard
const coins = weekend ? 200 : 100; // double rewards on weekends
console.log(`${username} voted — giving ${coins} coins`);
// giveCoins(user_id, coins);
});
await listener.listen();Express middleware — if you already have an Express app:
const express = require("express");
const { WebhookListener } = require("dlist.space");
const app = express();
const listener = new WebhookListener({
webhookKey: process.env.DLIST_WEBHOOK_KEY,
});
listener.on("vote", ({ user_id, username, weekend, test }) => {
if (test) return;
const coins = weekend ? 200 : 100;
console.log(`${username} voted — giving ${coins} coins`);
// giveCoins(user_id, coins);
});
app.use(express.json());
app.post("/dlist/webhook", listener.middleware());
app.listen(3000, () => console.log("Running on port 3000"));The middleware handles the auth header check for you. It also works whether or not express.json() has already run — if the body is already parsed it'll use it, otherwise it reads the stream itself.
Payload
Every vote and bump event includes:
user_id — Discord user ID
username — Discord username
avatar — avatar hash (can be null)
weekend — true on Saturday/Sunday UTC (good for double-reward logic)
test — true when sent from the dashboard "Test Webhook" buttonFull example
A minimal Discord.js bot with stats autoposting and vote rewards:
require("dotenv").config();
const { Client, GatewayIntentBits } = require("discord.js");
const { DlistClient, WebhookListener } = require("dlist.space");
const bot = new Client({ intents: [GatewayIntentBits.Guilds] });
const dlist = new DlistClient({
botId: process.env.BOT_ID,
token: process.env.DLIST_TOKEN,
});
bot.once("ready", () => {
console.log(`Logged in as ${bot.user.tag}`);
dlist.autopost(bot);
});
const listener = new WebhookListener({
webhookKey: process.env.DLIST_WEBHOOK_KEY,
port: 3000,
});
listener.on("vote", async ({ user_id, username, weekend }) => {
const coins = weekend ? 200 : 100;
console.log(`${username} voted — awarding ${coins} coins`);
// await db.addCoins(user_id, coins);
});
listener.listen();
bot.login(process.env.DISCORD_TOKEN);Error handling
Methods throw a DlistError (extends Error) on API failures. It has a .status property with the HTTP status code.
const { DlistError } = require("dlist.space/src/DlistClient");
try {
await dlist.postStats({ server_count: bot.guilds.cache.size });
} catch (err) {
if (err instanceof DlistError) {
console.error(`dlist error ${err.status}: ${err.message}`);
}
}Rate limits (429) don't throw — they're handled internally with a console warning. See the postStats section above.
Links
MIT © dlist.space
