Skip to main content

Truly async Python SDK for the DiscordForge bot listing platform

Project description

discordforge-sdk-python

Banner

A fully async Python SDK for the DiscordForge bot listing platform. Works with small bots and large sharded/auto-sharded bots equally.

Requirements

  • Python 3.11+
  • httpx >= 0.27

Installation

pip install discordforge-sdk-python

Quickstart

import os
import discord
from discordforge import ForgeClient, AutoPoster

bot = discord.Client(intents=discord.Intents.default())
forge = ForgeClient(os.environ["DISCORDFORGE_API_KEY"], bot_id=os.environ["BOT_ID"])

async def setup_hook():
    await forge.sync_from_discordpy(bot.tree, category="General")
    AutoPoster(forge, bot).start()

bot.setup_hook = setup_hook
bot.run(os.environ["BOT_TOKEN"])

AutoPoster posts your stats every 5 minutes automatically. It waits until all shards are ready before the first post, so counts are always accurate.

Want to post every 30 minutes instead? Pass interval=1800.0. Minimum is 300s (API limit).

AutoPoster(forge, bot, interval=1800.0).start()

Usage with discord.py

AutoPoster

poster = AutoPoster(forge, bot, interval=300.0)  # minimum 300s
poster.on("post", lambda stats: print(f"Posted {stats.server_count} servers"))
poster.on("error", lambda err: print(f"Error: {err}"))
poster.start()

Callbacks can be sync or async. The poster keeps running even if a post fails.

Manual stat posting

from discordforge import ForgeClient, BotStats

forge = ForgeClient("YOUR_API_KEY", bot_id="YOUR_BOT_ID")

@bot.event
async def on_ready():
    await forge.post_stats(BotStats(
        server_count=len(bot.guilds),
        shard_count=bot.shard_count,
        user_count=len(bot.users),
    ))

Check if a user voted

vote = await forge.check_vote("USER_DISCORD_ID")

if vote.has_voted:
    print(f"Voted at {vote.voted_at}, next vote available at {vote.next_vote_at}")
else:
    await ctx.send("You haven't voted yet! https://discordforge.org/bots/YOUR_BOT_ID")

Get your bot's public listing info

info = await forge.get_bot()
print(f"{info.name} has {info.vote_count} votes across {info.server_count} servers")

Sync slash commands

Pass your discord.py command tree and it maps commands automatically:

async def setup_hook():
    await bot.tree.sync()
    await forge.sync_from_discordpy(bot.tree, category="General")

Or pass a raw list if you want full control:

from discordforge import DiscordCommand

await forge.sync_commands([
    DiscordCommand(name="ping", description="Check bot latency"),
    DiscordCommand(name="help", description="Show help menu"),
])

Configuration

from discordforge import ForgeClient, ClientOptions

forge = ForgeClient(
    "YOUR_API_KEY",
    bot_id="YOUR_BOT_ID",
    options=ClientOptions(
        timeout=10.0,               # seconds per request
        retries=3,                  # retries on 5xx / network errors
        max_connections=10,         # httpx connection pool size
        max_keepalive_connections=5,
    ),
)

Error handling

from discordforge.errors import ForgeAPIError, ForgeRateLimitError, ForgeAuthError, ForgeNotFoundError

try:
    await forge.post_stats(BotStats(server_count=100))
except ForgeRateLimitError as e:
    print(f"Rate limited, retry in {e.retry_after}s")
except ForgeAuthError:
    print("Invalid API key")
except ForgeAPIError as e:
    print(f"API error {e.status}: {e}")
Exception When raised
ForgeRateLimitError 429 — backs off and retries automatically, only raises after all retries exhausted
ForgeAuthError 401 — invalid or missing API key
ForgeNotFoundError 404 — bot ID not found on DiscordForge
ForgeAPIError any other non-2xx response

AutoPoster reference

poster = AutoPoster(
    forge,                      # ForgeClient instance
    bot,                        # any discord client (discord.py, nextcord, py-cord, eris-style)
    interval=300.0,             # seconds between posts (minimum 300 — API rate limit)
    start_immediately=True,     # post as soon as ready fires
)

poster.on("post", callback)     # called after each successful post with BotStats
poster.on("error", callback)    # called on failure — poster keeps running

poster.start()                  # start the background task
poster.stop()                   # cancel the task (can restart with start())
poster.destroy()                # stop + clear all listeners
poster.is_running               # bool

Callbacks can be sync or async — both work:

async def on_post(stats):
    await log_channel.send(f"Posted {stats.server_count} servers")

def on_error(err):
    print(f"Error: {err}")

poster.on("post", on_post)
poster.on("error", on_error)

Types reference

Type Fields
BotStats server_count, shard_count, user_count, voice_connections
VoteMetadata has_voted, voted_at, next_vote_at
BotInfo id, name, vote_count, server_count
DiscordCommand name, description, type, options
CustomCommand name, description, usage, category

Examples

The examples/ folder has ready-to-run scripts covering every API feature:

File What it shows
post_stats.py Post server/shard/user counts
check_vote.py Check if a user voted in the last 12h
get_bot.py Fetch your bot's public listing info
sync_commands.py Sync commands using DiscordCommand or CustomCommand
sync_commands_discordpy.py Auto-sync directly from bot.tree
autoposter.py AutoPoster with post/error callbacks
vote_reward.py Full vote reward flow with role assignment
error_handling.py Catching all error types
bot.py Complete bot with all slash commands and AutoPoster

All examples use environment variables for credentials — copy and set these before running:

export DISCORDFORGE_API_KEY="your_api_key"
export BOT_ID="your_bot_discord_id"
export BOT_TOKEN="your_bot_token"       # discord.py examples only
export VOTER_ROLE_ID="role_id"          # vote_reward.py only

Running tests

pip install -e ".[dev]"
pytest tests/ -v

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

discordforge-1.0.0.tar.gz (20.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

discordforge-1.0.0-py3-none-any.whl (12.3 kB view details)

Uploaded Python 3

File details

Details for the file discordforge-1.0.0.tar.gz.

File metadata

  • Download URL: discordforge-1.0.0.tar.gz
  • Upload date:
  • Size: 20.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for discordforge-1.0.0.tar.gz
Algorithm Hash digest
SHA256 f163795980bb67b244ae31e2524f7aa29509d58a7a70c90ed5b47974b000af66
MD5 ac60bb542855257f64c6efc57f92de48
BLAKE2b-256 a5e2f898d738a9c731e4252ca71b1efaed929198a48e8e33c834d02fbfa81fd6

See more details on using hashes here.

File details

Details for the file discordforge-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: discordforge-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 12.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for discordforge-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 12748b80d7b6427be75842bd4730d1fb27e4eba52adb6b3d35032fb0e6bb94c7
MD5 270189ffde4cbf6e35ef77537582d5a5
BLAKE2b-256 7c1fb07e34da5606104877525c8e9a2a3736ca79e267be0060f4b718f98bd8d2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page