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_sdk_python-1.0.0.tar.gz (14.6 kB view details)

Uploaded Source

Built Distribution

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

discordforge_sdk_python-1.0.0-py3-none-any.whl (11.5 kB view details)

Uploaded Python 3

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

Hashes for discordforge_sdk_python-1.0.0.tar.gz
Algorithm Hash digest
SHA256 adf0d072679179df39309adb3c4dabcf25664aadc390b0af11f314b846491d2f
MD5 1d237e1d5764d798504778d8cd580cbc
BLAKE2b-256 2a2a7fb2b1c726263e070c42c1821d410919d033c9c6c411b157bd69756a4c86

See more details on using hashes here.

Provenance

The following attestation bundles were made for discordforge_sdk_python-1.0.0.tar.gz:

Publisher: publish.yml on TermuxHackz/discordforge-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for discordforge_sdk_python-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 12797a3ce3209a44e899a89c2268fbe1516028f2d7d6a6c3ff2b9c3bac94dc6d
MD5 632500671b917331557e859869e846f5
BLAKE2b-256 b710f6d3ed7a0c7107fb7c4f1ed4c905cce4dfd78bfc51cd479396eb01ba6723

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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