Writing GoyGram code
This is the shortest useful path from an empty folder to a working bot.
1. Create a bot
Create bot.py:
import asyncio
from goygram import GoyGram
app = GoyGram(bot_token="YOUR_BOT_TOKEN")
@app.on_cmd("start")
async def start(msg):
await msg.reply("Hello from GoyGram")
if __name__ == "__main__":
asyncio.run(app.run())Run it with:
python bot.pybot_token is the password of your bot. Keep it out of Git and logs.
2. Listen for messages
from goygram import filters
@app.on_msg(filt=filters.text)
async def echo(msg):
await msg.reply("I received: " + msg.text)on_msg registers a function. The function receives a MsgObj. msg.text is the incoming text and msg.reply() sends a reply in the same chat.
3. Add a command
@app.on_cmd("ping")
async def ping(msg):
await msg.reply("pong")The handler runs for /ping. Write the command name without /.
4. Combine filters
@app.on_msg(filt=filters.text & ~filters.me)
async def text_from_other_people(msg):
await msg.reply("I received a message from someone else")&means both conditions must match;|means either condition may match;~means not;filters.mematches messages from the current bot or account.
The F magic filter builds the same conditions from attribute paths:
from goygram.filters import F
@app.on_msg(filt=F.text == "hi" & ~F.is_me)
async def only_hi(msg):
await msg.reply("hi back")After a command filter matches, msg.cmd holds the command name and msg.args holds the rest of the text.
5. Use an MTProto account
import asyncio
from goygram import GoyGram
app = GoyGram(
api_id=YOUR_API_ID,
api_hash="YOUR_API_HASH",
session_name="main",
)
@app.on_cmd("ping")
async def ping(msg):
await msg.reply("pong from MTProto")
asyncio.run(app.run())On the first run, GoyGram asks for the phone number, Telegram login code, and the 2FA password when needed. The session is stored in a vault file. Do not put these values in source code.
6. Call Bot API methods
await app.get_chat(chat_id=123456789)
await app.send_document(chat_id=123456789, document=file_object)
await app.set_my_commands(commands=[])Bot API names can be written in snake case. Bot API and MTProto are different interfaces, so their method names and arguments are not interchangeable.
7. Enable complete IDE autocomplete
GoyGram resolves Telegram methods dynamically at runtime. Generate local stubs once after installation so VS Code, PyCharm, basedpyright, and other type-aware editors can see the same surface:
python -m goygram.stubgenThe generator reads the current MTProto and Bot API schemas and writes client.pyi plus telegram.py next to the installed package. The editor then completes direct dynamic calls such as app.messages_send_message(...) and app.send_message(...), all mt_ aliases, and method-specific mt_req() or bot_req() arguments. Unknown keyword arguments are reported before runtime. Regenerate after upgrading GoyGram or when Telegram publishes new methods. This path works on Python 3.13 and newer.
8. Handle errors
try:
await msg.reply("Reply")
except Exception as error:
import logging
logging.getLogger("goygram.app").exception("Could not send reply: %s", error)Do not print tokens, vault files, or authentication keys.
9. Add a new feature
- Choose Bot API or MTProto.
- Choose the event your feature needs.
- Write one small handler.
- Add a filter.
- Test the normal case and the error case.
- If the handler changes state, test restart and state cleanup.
- Reuse the application client instead of opening a new network client per message.
More detail: handlers and updates, filters, events, and client reference.