Skip to main content

tutorial: building a "new mints" telegram bot for postfun

introduction: bridging postfun and your community

postfun is a dynamic marketplace, with new content pools being minted constantly. as a developer or community manager, you might want to keep your audience updated in real-time. this tutorial will guide you through building a simple python-based telegram bot that monitors for new postfun mints and automatically posts them to your telegram channel or group.

this is a great starting point for understanding how to interact with the postfun api and can be easily extended to track other events like level-ups, major trades, or graduations.

prerequisites

before you begin, make sure you have the following:

  • python 3.8+: installed on your system.
  • requests library: for making http requests to the postfun api.
  • python-telegram-bot library: a powerful and easy-to-use library for building telegram bots. (we'll use requests for simplicity in this example, but for a full bot, this is recommended).
  • a telegram bot token: you'll need to create a new bot via telegram's botfather (@botfather).
  • a telegram chat id: the id of the group or channel where your bot will send messages. (you can get this by adding your bot to a group and sending /my_id@yourbotname in the group, or using a service like @get_id_bot).

step 1: scaffolding the bot and configuration

create a new python file (e.g., postfun_bot.py) and set up your basic configurations.

import requests
import time
import json
import os # for environment variables

# --- bot configuration ---
# base url for the postfun api
api_base_url = "https://api.postfun.xyz" # using the official api endpoint for the backend

# telegram bot token (get this from botfather)
# it's best practice to use environment variables for sensitive info
telegram_bot_token = os.getenv("telegram_bot_token", "your_telegram_bot_token_here")
# telegram chat id (your group/channel id)
telegram_chat_id = os.getenv("telegram_chat_id", "your_telegram_chat_id_here")

# --- state management ---
# file to store the id of the last tweet we've seen to avoid re-sending old notifications
last_seen_file = "last_seen_tweet_id.txt"

# --- polling interval ---
# how often the bot will check for new mints (in seconds)
polling_interval_seconds = 300 # 5 minutes

step 2: fetching the latest mints from postfun api

we'll define a function to call the postfun backend's /tweets endpoint. we'll sort by "new" to get the most recently minted pools.

def get_latest_mints():
"""
fetches the latest minted tweets from the postfun api.
"""
params = {
"by": "new", # sort by newly minted
"limit": 10 # get a few recent ones to check for new additions
}
try:
response = requests.get(f"{api_base_url}/tweets", params=params, timeout=10)
response.raise_for_status() # raise an exception for bad status codes (4xx or 5xx)
return response.json()
except requests.exceptions.requestexception as e:
print(f"error fetching latest mints: {e}")
return [] # return empty list on error

step 3: managing bot state - last_seen_tweet_id

to ensure your bot only sends notifications for new mints and doesn't spam your channel with old ones every time it runs, we need a way to store the id of the last tweet it successfully processed.

def get_last_seen_id():
"""
reads the last seen tweet id from a local file.
returns none if the file doesn't exist or is empty.
"""
try:
with open(last_seen_file, 'r') as f:
content = f.read().strip()
return int(content) if content.isdigit() else none
except filenotfounderror:
return none
except exception as e:
print(f"error reading last seen id file: {e}")
return none

def save_last_seen_id(tweet_id):
"""
saves the given tweet id to a local file.
"""
try:
with open(last_seen_file, 'w') as f:
f.write(str(tweet_id))
except exception as e:
print(f"error saving last seen id file: {e}")

step 4: formatting the telegram message

we need to format the data received from the postfun api into a user-friendly message for telegram. telegram supports markdown for rich text formatting.

def format_message(tweet_data):
"""
formats a single tweet's data into a telegram markdown message.
"""
tweet_id = tweet_data.get('id', 'n/a')
tweet_username = tweet_data.get('tweetusername', 'n/a')
# truncate content for brevity
tweet_content = tweet_data.get('description', 'no content available.')[:150] + "..." if len(tweet_data.get('description', '')) > 150 else tweet_data.get('description', 'no content available.')
minter_npub = tweet_data.get('minterid', 'n/a')[:12] + "..." if len(tweet_data.get('minterid', '')) > 12 else tweet_data.get('minterid', 'n/a')

# basic stats for the mint
current_price_sats = tweet_data.get('pricesatspertoken', 'n/a') # assuming api returns this
volume_24h_sats = tweet_data.get('volume24h', 'n/a')
liquidity_sats = tweet_data.get('liquidity', 'n/a')
current_level = tweet_data.get('level', 'n/a')

return f"""
🚨 *new mint alert!* 🚨

*content:* `{tweet_content}`
*from:* @{tweet_username}

*minter:* `{minter_npub}`
*current level:* {current_level}

*current price:* {current_price_sats} sats/token
*24h volume:* {volume_24h_sats} sats
*liquidity:* {liquidity_sats} sats

[➡️ view on postfun.xyz](https://postfun.xyz/tweet/{tweet_id})

#postfun #newmint
"""

note: the tweet_data dictionary structure in format_message assumes the /tweets api returns id, tweetusername, description, minterid, pricesatspertoken, volume24h, liquidity, and level. adjust based on your actual api response.

step 5: sending the message to telegram

this function handles the actual communication with the telegram bot api.

def send_telegram_message(message):
"""
sends a formatted markdown message to the specified telegram chat.
"""
if not telegram_bot_token or not telegram_chat_id:
print("telegram bot token or chat id not configured. skipping message.")
return

url = f"https://api.telegram.org/bot{telegram_bot_token}/sendmessage"
payload = {
"chat_id": telegram_chat_id,
"text": message,
"parse_mode": "markdown", # use markdown for formatting
"disable_web_page_preview": false # allow link previews
}
try:
response = requests.post(url, json=payload, timeout=10)
response.raise_for_status()
print(f"message sent to telegram. response: {response.json()}")
except requests.exceptions.requestexception as e:
print(f"error sending message to telegram: {e}")

step 6: the main bot loop

this is where all the pieces come together to create a continuously running bot.

def main_bot_loop():
"""
the main loop of the bot. continuously checks for new mints and sends notifications.
"""
print("postfun telegram bot started...")
while true:
last_seen_id = get_last_seen_id()
print(f"checking for new mints (last seen id: {last_seen_id})...")

new_mints = get_latest_mints()

if new_mints:
# sort by id to ensure we process in ascending order (oldest new mint first)
# this is crucial for correctly updating last_seen_id
new_mints.sort(key=lambda x: x.get('id', '')) # assuming 'id' is comparable

for tweet in new_mints:
# assuming 'id' is a string. if it's an integer, compare as int.
# here, we assume ids are sequential or can be compared lexicographically.
# for real tweet ids, it's safer to use creation time or a numerical internal id.
if last_seen_id is none or tweet.get('id', '') > str(last_seen_id):
message = format_message(tweet)
send_telegram_message(message)
save_last_seen_id(tweet.get('id', '')) # update last seen after successful send
else:
print("no new mints found or error occurred.")

print(f"next check in {polling_interval_seconds} seconds.")
time.sleep(polling_interval_seconds)

if __name__ == "__main__":
main_bot_loop()

running your bot

  1. save the code: save the entire script as postfun_bot.py.
  2. install dependencies: pip install requests
  3. set environment variables: before running, set your telegram_bot_token and telegram_chat_id as environment variables:
    export telegram_bot_token="your_actual_bot_token"
    export telegram_chat_id="your_actual_chat_id"
    python postfun_bot.py
  4. run: python postfun_bot.py

your bot will now start polling the postfun api and sending notifications to your telegram chat!

next steps & enhancements

this is a basic bot, but it can be significantly enhanced:

  • error handling & logging: add more robust logging (logging module) for debugging and monitoring, especially for api errors or network issues.
  • asynchronous operations: for more complex bots handling many users or real-time events, consider using python-telegram-bot's built-in asynchronous features (e.g., asyncio).
  • interactive commands: add telegram commands like /stats to fetch current postfun platform statistics, or /price [tweet_id] to get the current price of a specific pool.
  • database for state: for more persistent and reliable state management (especially if the bot is restarted frequently), use a small database (e.g., sqlite) instead of a text file for last_seen_tweet_id.
  • monitoring: set up basic monitoring to ensure your bot is always running.
  • deployment: deploy your bot to a cloud server (e.g., aws ec2, digitalocean droplet, railway) to ensure it runs 24/7.