Python library for parsing, validating, and signing Telegram Mini Apps initialization data on the server side. API-compatible in spirit with @tma.js/init-data-node.
- Validate init data signature and expiration
- Parse URL-encoded init data into typed Python objects
- Sign init data for testing and development
- Full type hints
- Optional FastAPI integration
- Third-party validation (data signed by Telegram directly)
pip install telegram-init-dataWith FastAPI support:
pip install telegram-init-data[fastapi]from telegram_init_data import validate, parse
bot_token = "YOUR_BOT_TOKEN"
init_data = "query_id=AAHdF6IQAAAAAN0XohDhrOrc&user=%7B%22id%22%3A279058397%2C%22first_name%22%3A%22Vladislav%22%2C%22last_name%22%3A%22Kibenko%22%2C%22username%22%3A%22vdkfrost%22%2C%22language_code%22%3A%22ru%22%2C%22is_premium%22%3Atrue%7D&auth_date=1662771648&hash=c501b71e775f74ce10e377dea85a7ea24ecd640b223ea86dfe453e0eaed2e2b2"
try:
validate(init_data, bot_token)
parsed = parse(init_data)
print(parsed["user"]["first_name"])
except Exception as e:
print(f"Validation failed: {e}")from fastapi import FastAPI, Depends, HTTPException
from telegram_init_data import validate, parse
app = FastAPI()
def verify_init_data(init_data: str) -> dict:
bot_token = "YOUR_BOT_TOKEN"
try:
validate(init_data, bot_token)
return parse(init_data)
except Exception as e:
raise HTTPException(status_code=401, detail=str(e))
@app.post("/user/profile")
async def get_profile(init_data: dict = Depends(verify_init_data)):
user = init_data.get("user")
if not user:
raise HTTPException(status_code=400, detail="User data not found")
return {"user_id": user["id"], "name": user["first_name"]}from telegram_init_data import sign, is_valid
from datetime import datetime
bot_token = "YOUR_BOT_TOKEN"
test_data = {
"query_id": "test_query_id",
"user": {
"id": 123456789,
"first_name": "John",
"last_name": "Doe",
"username": "johndoe",
"language_code": "en",
},
"auth_date": datetime.now(),
}
signed_data = sign(test_data, bot_token, datetime.now())
if is_valid(signed_data, bot_token):
print("Valid")Validate Telegram Mini App init data.
| Parameter | Type | Description |
|---|---|---|
value |
`str | dict` |
token |
str |
Bot token from @BotFather |
options |
dict, optional |
expires_in (seconds, default 86400) |
Raises: SignatureMissingError, AuthDateInvalidError, ExpiredError, SignatureInvalidError
Same checks as validate, returns bool instead of raising.
Parse init data into a structured object. Returns InitData.
Sign init data for testing. Returns a URL-encoded string.
class InitData(TypedDict):
query_id: Optional[str]
user: Optional[User]
receiver: Optional[User]
chat: Optional[Chat]
chat_type: Optional[ChatType]
chat_instance: Optional[str]
start_param: Optional[str]
can_send_after: Optional[int]
auth_date: int
hash: str
signature: Optional[str]
class User(TypedDict):
id: int
first_name: str
last_name: Optional[str]
username: Optional[str]
language_code: Optional[str]
is_bot: Optional[bool]
is_premium: Optional[bool]
added_to_attachment_menu: Optional[bool]
allows_write_to_pm: Optional[bool]
photo_url: Optional[str]
class Chat(TypedDict):
id: int
type: ChatType
title: Optional[str]
username: Optional[str]
photo_url: Optional[str]
class ChatType(str, Enum):
SENDER = "sender"
PRIVATE = "private"
GROUP = "group"
SUPERGROUP = "supergroup"
CHANNEL = "channel"| Exception | When |
|---|---|
TelegramInitDataError |
Base class |
AuthDateInvalidError |
Invalid or missing auth_date |
SignatureInvalidError |
Signature mismatch |
SignatureMissingError |
Missing hash / signature |
ExpiredError |
Init data expired |
# Custom TTL (1 hour)
validate(init_data, bot_token, {"expires_in": 3600})
# Disable expiration check
validate(init_data, bot_token, {"expires_in": 0})pip install -e ".[dev]"
pytest
pytest --cov=telegram_init_data --cov-report=htmlSee [examples/](examples/) for basic usage and a FastAPI app.
from fastapi import FastAPI, Depends, HTTPException, Header
from telegram_init_data import parse, is_valid
app = FastAPI()
def get_init_data(authorization: str = Header(None)):
if not authorization:
raise HTTPException(status_code=401, detail="Authorization header missing")
if not authorization.startswith("tma "):
raise HTTPException(status_code=401, detail="Invalid authorization format")
init_data = authorization[4:]
bot_token = "YOUR_BOT_TOKEN"
if not is_valid(init_data, bot_token):
raise HTTPException(status_code=401, detail="Invalid init data")
return parse(init_data)
@app.get("/me")
async def get_current_user(init_data: dict = Depends(get_init_data)):
user = init_data.get("user")
if not user:
raise HTTPException(status_code=400, detail="User data not found")
return {
"id": user["id"],
"name": user.get("first_name", ""),
"username": user.get("username"),
"is_premium": user.get("is_premium", False),
}git clone https://github.com/iCodeCraft/telegram-init-data.git
cd telegram-init-data
python -m venv venv
source venv/bin/activate
pip install -e ".[dev]"
pytest
black telegram_init_data tests
isort telegram_init_data tests
mypy telegram_init_dataMIT. See LICENSE.
- @tma.js/init-data-node — Node.js counterpart
- Telegram Mini Apps documentation
- Download stats (pepy.tech)
See CHANGELOG.md.