Truly async Python SDK for the DiscordForge bot listing platform
Project description
discordforge-sdk-python
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file discordforge_sdk_python-1.0.0.tar.gz.
File metadata
- Download URL: discordforge_sdk_python-1.0.0.tar.gz
- Upload date:
- Size: 14.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
adf0d072679179df39309adb3c4dabcf25664aadc390b0af11f314b846491d2f
|
|
| MD5 |
1d237e1d5764d798504778d8cd580cbc
|
|
| BLAKE2b-256 |
2a2a7fb2b1c726263e070c42c1821d410919d033c9c6c411b157bd69756a4c86
|
Provenance
The following attestation bundles were made for discordforge_sdk_python-1.0.0.tar.gz:
Publisher:
publish.yml on TermuxHackz/discordforge-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
discordforge_sdk_python-1.0.0.tar.gz -
Subject digest:
adf0d072679179df39309adb3c4dabcf25664aadc390b0af11f314b846491d2f - Sigstore transparency entry: 1393350619
- Sigstore integration time:
-
Permalink:
TermuxHackz/discordforge-py@5aeb64008e364abf6e7ab377881f6a463df39382 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/TermuxHackz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5aeb64008e364abf6e7ab377881f6a463df39382 -
Trigger Event:
release
-
Statement type:
File details
Details for the file discordforge_sdk_python-1.0.0-py3-none-any.whl.
File metadata
- Download URL: discordforge_sdk_python-1.0.0-py3-none-any.whl
- Upload date:
- Size: 11.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12797a3ce3209a44e899a89c2268fbe1516028f2d7d6a6c3ff2b9c3bac94dc6d
|
|
| MD5 |
632500671b917331557e859869e846f5
|
|
| BLAKE2b-256 |
b710f6d3ed7a0c7107fb7c4f1ed4c905cce4dfd78bfc51cd479396eb01ba6723
|
Provenance
The following attestation bundles were made for discordforge_sdk_python-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on TermuxHackz/discordforge-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
discordforge_sdk_python-1.0.0-py3-none-any.whl -
Subject digest:
12797a3ce3209a44e899a89c2268fbe1516028f2d7d6a6c3ff2b9c3bac94dc6d - Sigstore transparency entry: 1393350622
- Sigstore integration time:
-
Permalink:
TermuxHackz/discordforge-py@5aeb64008e364abf6e7ab377881f6a463df39382 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/TermuxHackz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5aeb64008e364abf6e7ab377881f6a463df39382 -
Trigger Event:
release
-
Statement type: