Serverless Discord interactions framework for AWS Lambda
Project description
cordless
A serverless Discord interactions framework for AWS Lambda.
Build Discord bots without running a server — just functions deployed to Lambda. Discord sends HTTP interactions to your endpoint; you return a JSON response. No WebSockets, no gateway, no persistent runtime.
Discord → API Gateway → Lambda → cordless → your handlers → response
install
pip install cordless
quickstart
import os
from cordless import Cordless
bot = Cordless(public_key=os.environ["DISCORD_PUBLIC_KEY"])
@bot.command("ping", description="Replies with pong")
async def ping(ctx):
await ctx.send("pong")
def handler(event, context):
return bot.handle(event)
Deploy as lambda_function.py and point Discord's Interactions Endpoint URL at your function's URL (via API Gateway or a Lambda function URL).
request verification
Every request from Discord is signed with Ed25519. Pass your application's public key (from the Developer Portal → General Information) to Cordless() and every incoming request is verified automatically — invalid signatures return 401 before your code runs.
bot = Cordless(public_key=os.environ["DISCORD_PUBLIC_KEY"])
Omitting public_key skips verification. Fine for local testing, never do it in production. PING interactions (sent when you first configure your endpoint) are answered automatically.
commands
@bot.command("hello", description="Says hello")
async def hello(ctx):
await ctx.send("Hello!")
Commands with options:
@bot.command(
"echo",
description="Repeats text back to you",
options=[
{"name": "text", "description": "Text to repeat", "type": 3, "required": True},
],
)
async def echo(ctx):
await ctx.send(ctx.options["text"])
Options land on ctx.options as a plain {name: value} dict.
buttons
@bot.button("confirm")
async def confirm(ctx):
await ctx.edit(f"Confirmed (button: {ctx.custom_id})")
ephemeral replies
@bot.command("secret", description="Only you can see this")
async def secret(ctx):
await ctx.send("just for you", ephemeral=True)
registering commands
@bot.command(...) wires up local dispatch — Discord also needs to know your commands exist. Use the CLI after deploying:
export DISCORD_BOT_TOKEN=...
cordless register app:bot # global — up to 1 hour to propagate
cordless register app:bot --guild-id 123456789 # single guild, instant
Pass MODULE:ATTRIBUTE pointing at your Cordless() instance.
No bot user? Authenticate with client credentials instead:
export DISCORD_CLIENT_ID=...
export DISCORD_CLIENT_SECRET=...
cordless register app:bot
Or call it from code:
bot.sync_commands(bot_token=os.environ["DISCORD_BOT_TOKEN"])
bot.sync_commands(client_id=..., client_secret=..., guild_id="123456789")
deploying the layer
cordless has no compiled dependencies. Package it as a Lambda layer and attach it to your function in one step:
cordless upload --function my-discord-bot
cordless upload --function my-discord-bot --region eu-west-1
Uses the AWS CLI under the hood — your existing credentials, profile, and region config all apply.
context reference
Attributes
ctx.options |
Command options as {name: value} |
ctx.custom_id |
Custom ID of the button that was clicked |
ctx.user |
User who triggered the interaction |
ctx.guild_id |
Guild ID, or None in DMs |
ctx.channel_id |
Channel ID |
ctx.interaction_id |
Interaction ID |
ctx.token |
Interaction token |
ctx.interaction |
Raw interaction payload |
Methods
await ctx.send(msg, *, ephemeral=False) |
Reply with a message |
await ctx.edit(msg) |
Edit the original message (button handlers) |
await ctx.defer() |
Acknowledge within 3 s, respond later |
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 cordless-0.6.0.tar.gz.
File metadata
- Download URL: cordless-0.6.0.tar.gz
- Upload date:
- Size: 17.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a403e52a66c5895ac778107a0b5225b4a80ff3aa21be08aa002938e8ac5ee628
|
|
| MD5 |
aed357f383506279564af8dbeac92239
|
|
| BLAKE2b-256 |
a3b1c9eb629ac5b73e74c35e916a5babd60f53686fddbb5a6749100e3507bec3
|
File details
Details for the file cordless-0.6.0-py3-none-any.whl.
File metadata
- Download URL: cordless-0.6.0-py3-none-any.whl
- Upload date:
- Size: 16.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0341ed4fe8ff9e6e733c8903d7b76b27473909ac4e4ae75bd0ac3b16ec8bb7b0
|
|
| MD5 |
6f8ffa55be19dc426ef0315a86b31d21
|
|
| BLAKE2b-256 |
37a51d5134984e29c512b5dfc76bde86e7fabc752d42444edefa58d1e44cb215
|