This reference documents the Mini App REST API served by FastAPI. All endpoints return a consistent JSON envelope and use Telegram initData for authentication.
If API__DEBUG=true, interactive API docs are available at /api/docs and /api/redoc.
- Local (polling):
http://localhost:8000/api - Docker + nginx:
http://localhost/api - Production:
https://your-domain.com/api
All endpoints except /health require initData:
Authorization: Bearer <initData>The backend validates initData using your bot token and rejects expired auth_date values.
Success:
{
"success": true,
"data": {}
}Error:
{
"success": false,
"error": "Error message"
}The API applies an in-memory rate limit of 100 requests per minute per IP.
Error response:
{
"error": "Too many requests",
"retry_after": 60
}Response header:
Retry-After: 60X-Process-Time: request duration in seconds
Health check endpoint.
Auth: Not required
curl
curl http://localhost:8000/api/healthResponse
{
"status": "ok"
}Validate initData and return user data.
Auth: Required
curl
curl -X POST http://localhost:8000/api/auth/validate \
-H "Authorization: Bearer <initData>"Python
import requests
resp = requests.post(
"http://localhost:8000/api/auth/validate",
headers={"Authorization": f"Bearer {init_data}"},
)
print(resp.json())JavaScript
const res = await fetch("/api/auth/validate", {
method: "POST",
headers: { Authorization: `Bearer ${initData}` }
});
const data = await res.json();TypeScript
const res = await fetch("/api/auth/validate", {
method: "POST",
headers: { Authorization: `Bearer ${initData}` }
});
const data = await res.json();Response 200
{
"success": true,
"data": {
"id": 1,
"telegram_id": 123456789,
"username": "johndoe",
"first_name": "John",
"last_name": "Doe",
"language_code": "en",
"bio": null,
"created_at": "2025-01-10T12:00:00Z",
"updated_at": "2025-01-10T12:00:00Z"
}
}Response 401
{
"success": false,
"error": "Invalid authorization data"
}Return the current user profile.
Auth: Required
curl
curl http://localhost:8000/api/users/me \
-H "Authorization: Bearer <initData>"Response 200
{
"success": true,
"data": {
"id": 1,
"telegram_id": 123456789,
"username": "johndoe",
"first_name": "John",
"last_name": "Doe",
"language_code": "en",
"bio": "Hello",
"created_at": "2025-01-10T12:00:00Z",
"updated_at": "2025-01-10T12:00:00Z"
}
}Response 404
{
"success": false,
"error": "User not found"
}Update the current user profile.
Auth: Required
Request Body
{
"bio": "string (max 500)",
"language_code": "string (max 10)"
}curl
curl -X PATCH http://localhost:8000/api/users/me \
-H "Authorization: Bearer <initData>" \
-H "Content-Type: application/json" \
-d '{"bio":"New bio","language_code":"ru"}'Response 200
{
"success": true,
"data": {
"id": 1,
"telegram_id": 123456789,
"language_code": "ru",
"bio": "New bio",
"created_at": "2025-01-10T12:00:00Z",
"updated_at": "2025-01-10T12:05:00Z"
}
}Get a user profile by Telegram ID.
Auth: Required
curl
curl http://localhost:8000/api/users/123456789 \
-H "Authorization: Bearer <initData>"Response 200
{
"success": true,
"data": {
"id": 1,
"telegram_id": 123456789,
"language_code": "en",
"bio": "Hello",
"created_at": "2025-01-10T12:00:00Z",
"updated_at": "2025-01-10T12:05:00Z"
}
}| Code | Meaning | Common Causes |
|---|---|---|
| 401 | Unauthorized | Missing or invalid initData |
| 404 | Not Found | User not found |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Unhandled error or validation failure |
interface ApiResponse<T> {
success: boolean;
data: T | null;
error: string | null;
}interface UserRead {
id: number;
telegram_id: number;
username?: string | null;
first_name?: string | null;
last_name?: string | null;
language_code: string;
bio?: string | null;
created_at: string;
updated_at?: string | null;
}interface UserUpdate {
bio?: string | null; // max 500
language_code?: string | null; // max 10
}import { api } from "../api/client";
const me = await api.get<ApiResponse<UserRead>>("/users/me");Symptoms: Authorization required error.
Cause: API client not injecting initData.
Solution: Use the shared API client or add Authorization: Bearer <initData>.
Symptoms: Too many requests.
Cause: Rapid polling or frequent calls.
Solution: Batch requests or add client-side throttling.
- DO handle
success=falsein the UI. - DO reuse
initDatawithin the session. - DO keep API calls minimal on page load.
- DO validate user input before PATCH requests.
- See Mini Apps API Guide
- Review Authentication