# API Integration Guide for Telegram Bot ## Overview The bot can authenticate users in two ways: 1. **Email/Password Registration** - Users create account with email 2. **Telegram Direct Binding** - Direct binding via telegram_id ## 1. Email/Password Registration Flow ### Step 1: Register User ```bash POST /api/v1/auth/register { "email": "user@example.com", "password": "securepass123", "first_name": "John", "last_name": "Doe" } ``` **Response:** ```json { "success": true, "user_id": 123, "message": "User registered successfully", "access_token": "eyJ...", "refresh_token": "eyJ...", "expires_in": 900 } ``` ### Step 2: Bot Uses Token ```python headers = { "Authorization": "Bearer eyJ...", "Content-Type": "application/json" } response = requests.get("/api/v1/accounts", headers=headers) ``` --- ## 2. Telegram Direct Binding Flow ### Step 1: Generate Binding Code ```bash POST /api/v1/auth/telegram/start { "chat_id": 556399210 } ``` **Response:** ```json { "code": "PgmL5ZD8vK...", "expires_in": 600 } ``` ### Step 2: User Confirms Binding (Frontend) User clicks link and confirms in web/app: ```bash POST /api/v1/auth/telegram/confirm { "code": "PgmL5ZD8vK...", "chat_id": 556399210, "username": "john_doe", "first_name": "John", "last_name": "Doe" } ``` Requires user to be authenticated first (email login). ### Step 3: Bot Gets Token ```bash POST /api/v1/auth/telegram/register { "chat_id": 556399210, "username": "john_doe", "first_name": "John" } ``` Or get token for existing user: ```bash POST /api/v1/auth/token/get { "chat_id": 556399210 } ``` **Response:** ```json { "success": true, "access_token": "eyJ...", "expires_in": 900, "user_id": 123 } ``` --- ## 3. Bot Implementation Example ### In Python Bot Code ```python import aiohttp import asyncio from datetime import datetime, timedelta class BotAuthManager: def __init__(self, api_base_url: str, redis_client): self.api_base_url = api_base_url self.redis = redis_client self.session = None async def start(self): self.session = aiohttp.ClientSession() async def register_user(self, email: str, password: str, name: str) -> dict: """Register new user and return token""" response = await self.session.post( f"{self.api_base_url}/api/v1/auth/register", json={ "email": email, "password": password, "first_name": name } ) data = await response.json() if response.status == 200: # Store token in Redis self.redis.setex( f"user:{data['user_id']}:token", data['expires_in'], data['access_token'] ) return data else: raise Exception(f"Registration failed: {data}") async def bind_telegram(self, chat_id: int, username: str) -> dict: """Quick bind Telegram user""" response = await self.session.post( f"{self.api_base_url}/api/v1/auth/telegram/register", params={ "chat_id": chat_id, "username": username } ) data = await response.json() if response.status == 200 or data.get("success"): # Store token for bot self.redis.setex( f"chat_id:{chat_id}:jwt", 86400 * 30, # 30 days data['jwt_token'] ) return data else: raise Exception(f"Telegram binding failed: {data}") async def get_token(self, chat_id: int) -> str: """Get fresh token for chat_id""" response = await self.session.post( f"{self.api_base_url}/api/v1/auth/token/get", json={"chat_id": chat_id} ) data = await response.json() if response.status == 200: # Store token self.redis.setex( f"chat_id:{chat_id}:jwt", data['expires_in'], data['access_token'] ) return data['access_token'] else: raise Exception(f"Token fetch failed: {data}") async def make_api_call(self, method: str, endpoint: str, chat_id: int, **kwargs): """Make authenticated API call""" token = self.redis.get(f"chat_id:{chat_id}:jwt") if not token: # Try to get fresh token token = await self.get_token(chat_id) headers = { "Authorization": f"Bearer {token.decode() if isinstance(token, bytes) else token}", "Content-Type": "application/json" } url = f"{self.api_base_url}{endpoint}" async with self.session.request(method, url, headers=headers, **kwargs) as response: return await response.json() ``` --- ## 4. Error Handling ### 400 - Bad Request - Invalid email format - Missing required fields - Email already registered ### 401 - Unauthorized - Invalid credentials - Token expired - No authentication provided ### 404 - Not Found - User not found - Chat ID not linked to user ### 500 - Server Error - Database error - Server error --- ## 5. Token Refresh Strategy ### Access Token (15 minutes) - Short-lived token for API calls - Expires every 15 minutes - Automatic refresh with refresh_token ### Refresh Token (30 days) - Long-lived token to get new access tokens - Stored in Redis - Use to refresh access_token without re-login ### Bot Storage Strategy ```python # On successful binding redis.setex(f"chat_id:{chat_id}:jwt", 86400*30, access_token) # Before API call token = redis.get(f"chat_id:{chat_id}:jwt") if not token: token = await get_fresh_token(chat_id) ``` --- ## 6. Environment Variables ```bash # In docker-compose.yml API_BASE_URL=http://web:8000 BOT_TOKEN=your_telegram_bot_token REDIS_URL=redis://redis:6379/0 DB_PASSWORD=your_db_password ``` --- ## 7. Testing API Endpoints ### Using cURL ```bash # Register new user curl -X POST http://localhost:8000/api/v1/auth/register \ -H "Content-Type: application/json" \ -d '{ "email": "test@example.com", "password": "test123", "first_name": "Test" }' # Get token for Telegram user curl -X POST http://localhost:8000/api/v1/auth/token/get \ -H "Content-Type: application/json" \ -d '{"chat_id": 123456}' # Make authenticated request curl -X GET http://localhost:8000/api/v1/accounts \ -H "Authorization: Bearer eyJ..." ``` ### Using Python requests ```python import requests BASE_URL = "http://localhost:8000" # Register resp = requests.post(f"{BASE_URL}/api/v1/auth/register", json={ "email": "test@example.com", "password": "test123", "first_name": "Test" }) print(resp.json()) # Get token resp = requests.post(f"{BASE_URL}/api/v1/auth/token/get", json={ "chat_id": 556399210 }) token = resp.json()["access_token"] # Use token headers = {"Authorization": f"Bearer {token}"} resp = requests.get(f"{BASE_URL}/api/v1/accounts", headers=headers) print(resp.json()) ``` --- ## Next Steps 1. Apply migration: `alembic upgrade head` 2. Test endpoints with cURL/Postman 3. Update bot code to use new endpoints 4. Deploy with docker-compose