modul 00 / start: boți, Bot API & BotFather
ce este un bot Telegram & cum funcționează
Un bot de Telegram e un cont special, condus nu de un om, ci de codul tău. Poate răspunde la mesaje, trimite notificări, integra servicii, accepta plăți, modera grupuri și multe altele. Acest curs urmează documentația oficială Telegram Bot API și te duce de la zero la un bot funcțional în producție.
de ce boți Telegram
- Accesibil — nu trebuie să publici o aplicație în App Store; utilizatorii doar deschid un chat.
- Puternic — mesaje, butoane, meniuri, media, plăți, mini-apps — o platformă completă.
- Ușor de pornit — un token gratuit de la BotFather și câteva linii de cod și ai un bot viu.
- Cazuri reale — notificări, asistenți, automatizări, magazine, suport, jocuri, integrări cu alte servicii.
Bot API — cum vorbește codul tău cu Telegram
Nu te conectezi direct la aplicația Telegram. Telegram oferă un Bot API — o interfață HTTP prin care codul tău trimite comenzi și primește evenimente. Adresa de bază:
https://api.telegram.org/bot<TOKEN>/METODA
Trimiți cereri HTTP către metode (ex: sendMessage, getUpdates) și primești răspunsuri JSON. Practic, un bot e un program care: (1) primește evenimente de la Telegram și (2) răspunde apelând metode ale API-ului. Atât — restul e logica ta.
cum circulă un mesaj
- Un utilizator scrie botului tău în Telegram.
- Serverele Telegram primesc mesajul și îl țin pentru botul tău.
- Codul tău îl preia (prin polling sau webhook — modulul 5).
- Codul tău procesează mesajul și răspunde apelând o metodă API (ex: sendMessage).
- Telegram livrează răspunsul utilizatorului.
Modelul mental: utilizator → Telegram → codul tău → Telegram → utilizator. Botul tău nu „stă” în aplicația Telegram; e un server (sau script) al tău care dialoghează cu Telegram prin API.
de reținut
Un bot Telegram e codul tău conectat la Telegram prin Bot API — o interfață HTTP simplă: trimiți cereri la metode, primești JSON. Nu ai nevoie de o aplicație publicată, doar de un token și un program care primește evenimente și răspunde. Odată ce înțelegi fluxul utilizator → Telegram → cod → Telegram, tot restul cursului e să înveți metodele și tiparele.
modul 00 / start: boți, Bot API & BotFather
BotFather: primul tău bot & token
Orice bot Telegram începe la BotFather — botul oficial care creează și configurează boți. Nu ai nevoie de cod pentru acest pas.
crearea botului, pas cu pas
- În Telegram, caută @BotFather și pornește un chat.
- Trimite comanda /newbot.
- Alege un nume (afișat, poate conține spații) — ex: „Notificări Studio".
- Alege un username — trebuie să fie unic și să se termine în bot (ex: studio_notificari_bot).
- BotFather îți dă token-ul — un șir ca 123456789:AAExxxxxxxxxxxxxxxxxxxx.
token-ul = cheia botului
Token-ul e parola botului tău. Oricine îl are poate controla complet botul. Nu-l pune niciodată în cod public (GitHub), nu-l trimite nimănui. Îl ții într-o variabilă de mediu / fișier de secrete (modulul 9). Dacă îl expui din greșeală, folosește /revoke în BotFather ca să-l regenerezi imediat.
configurări utile din BotFather
| Comandă BotFather | Ce face |
| /setdescription | Textul afișat când deschizi botul prima dată |
| /setabouttext | Scurtă descriere din profil |
| /setuserpic | Poza de profil a botului |
| /setcommands | Lista de comenzi din meniul „/" (ex: start, help) |
| /setprivacy | Dacă botul vede toate mesajele din grupuri sau doar cele care îl menționează |
| /token / /revoke | Afișează / regenerează token-ul |
primul test — fără cod
Poți verifica token-ul direct în browser, apelând metoda getMe:
https://api.telegram.org/bot<TOKEN>/getMe
Dacă token-ul e valid, primești un JSON cu datele botului (id, nume, username). Ai confirmat astfel că botul e viu și API-ul răspunde — înainte să scrii vreo linie de cod.
{
"ok": true,
"result": {
"id": 123456789,
"is_bot": true,
"first_name": "Notificări Studio",
"username": "studio_notificari_bot"
}
}
Observă structura: fiecare răspuns Bot API are "ok": true/false și, la succes, un "result". Vei vedea acest tipar peste tot.
de reținut
BotFather e punctul de start pentru orice bot: /newbot → nume → username (în „bot") → token. Token-ul e cheia sacră — îl protejezi ca pe o parolă. Poți testa imediat botul cu getMe în browser, fără cod, ca să confirmi că totul e valid. Cu token-ul în mână, ești gata să trimiți și să primești mesaje — modulul următor.
modul 01 / mesaje: Update & sendMessage
primirea evenimentelor: obiectul Update
Un bot trăiește reacționând la evenimente: cineva a scris un mesaj, a apăsat un buton, a intrat în grup. Telegram împachetează fiecare eveniment într-un obiect Update. Înțelegerea lui e cheia întregului bot.
preluarea update-urilor cu getUpdates
Cel mai simplu mod (polling — modulul 5) de a primi evenimente e metoda getUpdates:
https://api.telegram.org/bot<TOKEN>/getUpdates
Îți întoarce o listă de obiecte Update — tot ce s-a întâmplat de la ultima verificare. Un Update tipic pentru un mesaj text arată așa:
{
"update_id": 100,
"message": {
"message_id": 5,
"from": { "id": 777, "first_name": "Ana" },
"chat": { "id": 777, "type": "private" },
"text": "Salut bot!"
}
}
câmpurile pe care le folosești mereu
| Câmp | Ce conține |
| update_id | Identificator crescător al update-ului (pentru a nu-l procesa de două ori) |
| message.text | Textul mesajului |
| message.chat.id | ID-ul chat-ului — unde trimiți răspunsul (ESENȚIAL) |
| message.from.id | ID-ul utilizatorului care a scris |
| message.from.first_name | Numele utilizatorului |
chat.id e cea mai importantă valoare: îi spune botului unde să răspundă. Fără el, nu poți trimite nimic înapoi. Într-un chat privat, chat.id = user id; într-un grup, e id-ul grupului.
tipuri de update-uri
Un Update poate conține (pe rând) diferite lucruri, nu doar message:
- message — un mesaj nou (text, foto, document...).
- edited_message — un mesaj editat.
- callback_query — apăsarea unui buton inline (modulul 3).
- inline_query — inline mode (modulul 8).
Codul tău verifică ce fel de update a venit și reacționează corespunzător. Bibliotecile (modulul 7) fac asta elegant, dar principiul rămâne: examinezi Update-ul și decizi.
de reținut
Fiecare eveniment ajunge la tine ca un Update — un obiect JSON. Îl examinezi ca să afli ce s-a întâmplat (mesaj? buton apăsat?) și extragi ce-ți trebuie. Valoarea-cheie e chat.id — „unde răspund". Un bot, la nivel fundamental, e o buclă: primește Update → decide → răspunde. Restul cursului adaugă tipuri de conținut și tipare peste acest schelet.
modul 01 / mesaje: Update & sendMessage
răspunsul: sendMessage & primul bot-ecou
sendMessage e metoda pe care o vei folosi cel mai des — trimite un mesaj text într-un chat. Are nevoie de două lucruri esențiale: unde (chat_id) și ce (text).
sendMessage direct
https://api.telegram.org/bot<TOKEN>/sendMessage?chat_id=777&text=Salut!
Sau, corect, printr-o cerere HTTP POST cu parametrii. În Python cu biblioteca requests:
import requests
TOKEN = "123456:AAxxxx" # din variabilă de mediu!
url = f"https://api.telegram.org/bot{TOKEN}/sendMessage"
requests.post(url, json={
"chat_id": 777,
"text": "Salut, lume!"
})
parametri utili ai sendMessage
| Parametru | Rol |
| chat_id | Unde trimiți (obligatoriu) |
| text | Conținutul (obligatoriu) |
| parse_mode | „HTML" sau „MarkdownV2" pentru text formatat (modulul 4) |
| reply_markup | Tastaturi/butoane (modulul 3) |
| reply_to_message_id | Răspunde la un anumit mesaj |
primul bot complet: ecou
Un „echo bot" repetă tot ce i se scrie — micul „Hello World" al boților. Iată-l cu polling manual, ca să vezi mecanica pură:
import requests
API = f"https://api.telegram.org/bot{TOKEN}"
offset = 0
while True:
# 1. preiau update-uri noi (long polling)
r = requests.get(f"{API}/getUpdates",
params={"offset": offset, "timeout": 30}).json()
for upd in r["result"]:
offset = upd["update_id"] + 1 # nu reprocesez
msg = upd.get("message")
if msg and "text" in msg:
# 2. răspund cu același text
requests.post(f"{API}/sendMessage", json={
"chat_id": msg["chat"]["id"],
"text": msg["text"]
})
- offset — spune lui getUpdates „dă-mi doar update-uri mai noi decât acesta", ca să nu procesezi de două ori același mesaj.
- timeout: 30 — long polling: cererea așteaptă până la 30s pentru un update nou (eficient, nu bombardezi serverul).
- Extragi chat.id și trimiți înapoi cu sendMessage. Bucla se repetă la infinit.
Ai deja un bot funcțional! E scheletul brut; bibliotecile (modulul 7) automatizează bucla, dar acum înțelegi ce fac ele dedesubt.
de reținut
sendMessage (unde: chat_id, ce: text) e metoda ta de bază pentru a răspunde. Combinată cu getUpdates într-o buclă cu offset, ai un bot complet: preiei update-uri, extragi chat.id, răspunzi. Acesta e „Hello World"-ul boților. Ai văzut mecanica pură — de aici încolo adăugăm comenzi, butoane, media și tipare profesioniste peste acest fundament.
modul 02 / comenzi & handlers
comenzi: /start, /help & argumente
Comenzile sunt modul standard prin care utilizatorii dau instrucțiuni unui bot. Sunt mesaje care încep cu / — ex: /start, /help, /vreme Chișinău. Un bot bine făcut e organizat în jurul comenzilor sale.
ce e o comandă, tehnic
O comandă e doar un mesaj text care începe cu /. Nu există „tip de update" separat pentru comenzi — tu (sau biblioteca ta) verifici dacă textul începe cu / și îl tratezi ca pe o comandă.
text = msg.get("text", "")
if text.startswith("/start"):
# tratează comanda start
elif text.startswith("/help"):
# tratează help
comenzi obligatorii prin convenție
| Comandă | Rol convențional |
| /start | Prima interacțiune — botul se prezintă (Telegram o trimite automat la prima deschidere) |
| /help | Explică ce poate face botul și cum |
| /settings | Preferințe (dacă e cazul) |
/start e specială: când un utilizator deschide botul prima dată, Telegram trimite automat /start. E locul unde botul salută și explică pe scurt ce face. Un bot fără /start bun pare stricat.
argumente ale comenzilor
O comandă poate avea argumente — text după comandă: /vreme Chișinău. Le extragi despărțind textul:
text = "/vreme Chișinău"
parti = text.split(maxsplit=1)
comanda = parti[0] # "/vreme"
argument = parti[1] if len(parti) > 1 else "" # "Chișinău"
comenzi în grupuri: /start@nume_bot
În grupuri, unde sunt mai mulți boți, comenzile pot fi adresate specific: /start@studio_bot. Trebuie să tratezi și forma cu @username. Bibliotecile fac asta automat; manual, elimini partea @... înainte de a compara.
meniul de comenzi (BotFather sau setMyCommands)
Ca utilizatorii să vadă comenzile disponibile într-un meniu frumos (butonul „/"), le înregistrezi — fie din BotFather (/setcommands), fie programatic:
requests.post(f"{API}/setMyCommands", json={
"commands": [
{"command": "start", "description": "Pornește botul"},
{"command": "help", "description": "Ajutor"}
]
})
de reținut
O comandă e un mesaj text care începe cu / — nimic mai mult. Convenția cere măcar /start (salut + prezentare, trimisă automat la prima deschidere) și /help. Argumentele sunt textul de după comandă, extras prin despărțire. Iar setMyCommands le face vizibile în meniul „/". Comenzile sunt „interfața" botului tău — merită gândite clar.
modul 02 / comenzi & handlers
handlers: organizarea logicii botului
Pe măsură ce botul crește, un lanț uriaș de if/elif devine imposibil de întreținut. Soluția, pe care o folosesc toate bibliotecile serioase, sunt handler-ele: funcții dedicate, fiecare pentru un tip de eveniment.
ideea de handler
Un handler e o funcție care se ocupă de un anumit tip de update. „Când vine comanda /start → rulează funcția start". „Când vine orice text → rulează funcția echo". Registrezi handler-ele, iar dispatcher-ul (din bibliotecă) le cheamă pe cele potrivite.
# conceptual (stil python-telegram-bot, modulul 7):
async def start(update, context):
await update.message.reply_text("Bun venit!")
async def help_cmd(update, context):
await update.message.reply_text("Iată ce pot face...")
app.add_handler(CommandHandler("start", start))
app.add_handler(CommandHandler("help", help_cmd))
Fiecare handler primește update (evenimentul) și context (utilitare, argumente, date). E mult mai curat decât un if gigant — fiecare comandă are funcția ei, ușor de citit și testat.
tipuri de handlers
| Handler | Reacționează la |
| CommandHandler | O comandă anume (/start, /help) |
| MessageHandler | Mesaje (după filtre: text, foto, orice) |
| CallbackQueryHandler | Apăsarea butoanelor inline (modulul 3) |
| ConversationHandler | Dialoguri cu stare/pași (modulul 6) |
ordinea & filtrele contează
- Handler-ele sunt evaluate în ordine; primul care se potrivește tratează update-ul.
- Filtrele restrâng ce prinde un handler: „doar text", „doar foto", „doar de la adminul X".
- Pui comenzile specifice înaintea unui handler „prinde-tot", altfel acesta le-ar înghiți.
reply_text vs sendMessage
Bibliotecile oferă scurtături: update.message.reply_text("...") e echivalent cu sendMessage către chat.id-ul curent — dar mai scurt și mai lizibil. Sub capotă, tot sendMessage e.
de reținut
Handler-ele transformă botul dintr-un if gigant într-o colecție ordonată de funcții, fiecare pentru un tip de eveniment (comandă, mesaj, buton). Un dispatcher rutează fiecare update la handler-ul potrivit, în funcție de tip și filtre. E tiparul central al oricărei biblioteci serioase (modulul 7) și modul în care scrii boți curați, mentenabili. Gândește botul ca „un set de handlers", nu „un lanț de if-uri".
modul 03 / tastaturi & butoane
reply keyboards & inline keyboards
Mesajele text sunt de bază, dar boții cu adevărat plăcuți folosesc butoane. Telegram oferă două tipuri de tastaturi, cu roluri diferite. Alegerea corectă între ele e o decizie de design importantă.
1. reply keyboard — înlocuiește tastatura utilizatorului
Apare în locul tastaturii normale, sub câmpul de text. Când utilizatorul apasă un buton, se trimite un mesaj text cu eticheta butonului — ca și cum ar fi tastat-o.
reply_markup = {
"keyboard": [
[{"text": "📋 Meniu"}, {"text": "ℹ️ Ajutor"}],
[{"text": "📞 Contact"}]
],
"resize_keyboard": True
}
- Butoanele sunt un array de rânduri (fiecare rând = listă de butoane).
- La apăsare, botul primește un mesaj text obișnuit cu textul butonului — îl tratezi ca pe orice text.
- Bun pentru: meniuri principale persistente, opțiuni frecvente.
2. inline keyboard — butoane atașate de un mesaj
Apar sub un mesaj anume (nu înlocuiesc tastatura). La apăsare, NU trimit text vizibil — trimit un callback query (lecția următoare), pe care botul îl procesează discret.
reply_markup = {
"inline_keyboard": [
[{"text": "👍 Da", "callback_data": "da"},
{"text": "👎 Nu", "callback_data": "nu"}],
[{"text": "🌐 Site", "url": "https://romeo.studio"}]
]
}
- Fiecare buton are callback_data (un cod ascuns trimis botului) SAU url (deschide un link).
- Nu poluează chat-ul cu mesaje — interacțiune curată.
- Bun pentru: acțiuni pe un mesaj (vot, confirmări, navigare, paginare).
reply vs inline — când folosești care
| Reply keyboard | Inline keyboard |
| Unde apare | În locul tastaturii | Sub un mesaj |
| La apăsare | Trimite text vizibil | Trimite callback_data (ascuns) |
| Ideal pentru | Meniu principal persistent | Acțiuni pe mesaj, confirmări, navigare |
de reținut
Două tastaturi, două roluri: reply keyboard = meniu persistent care „tastează" text la apăsare (bun pentru navigare principală); inline keyboard = butoane lipite de un mesaj care trimit un callback discret (bun pentru acțiuni, confirmări, paginare). Alegerea corectă face botul intuitiv. Inline-ul e cel mai puternic — dar are nevoie de callback queries, exact ce urmează.
modul 03 / tastaturi & butoane
callback queries: procesarea apăsărilor inline
Când utilizatorul apasă un buton inline, botul primește un callback query — un tip special de Update. Procesarea lui corect e esențială pentru boți interactivi.
ce primești la apăsare
{
"callback_query": {
"id": "abc123",
"from": { "id": 777, "first_name": "Ana" },
"data": "da", // callback_data al butonului apăsat
"message": { ... } // mesajul de care e atașat butonul
}
}
- data — codul pe care l-ai pus în butonul apăsat (callback_data). După el decizi ce a apăsat utilizatorul.
- message — mesajul cu butoanele; îți dă chat.id și message_id (util ca să editezi mesajul).
answerCallbackQuery — OBLIGATORIU
La fiecare callback, TREBUIE să apelezi answerCallbackQuery. Altfel, butonul rămâne cu un „ceas" care se învârte la utilizator, ca și cum botul s-ar fi blocat.
requests.post(f"{API}/answerCallbackQuery", json={
"callback_query_id": "abc123"
# opțional: "text": "Mesaj scurt", "show_alert": True
})
Poți afișa opțional un mic mesaj (toast) sau o alertă pop-up. Dar chiar și fără text, apelul e obligatoriu ca să oprești animația de încărcare.
editarea mesajului ca răspuns
Puterea inline keyboards: în loc să trimiți un mesaj nou, editezi mesajul existent — pentru meniuri navigabile, paginare, pași. Metode: editMessageText, editMessageReplyMarkup.
# înlocuiesc textul ȘI butoanele mesajului la apăsare:
requests.post(f"{API}/editMessageText", json={
"chat_id": chat_id,
"message_id": message_id,
"text": "Ai ales: Da ✅",
"reply_markup": {"inline_keyboard": [...noile butoane...]}
})
Așa creezi meniuri care se „transformă" la apăsare — un singur mesaj devine o mică interfață navigabilă, fără să umple chat-ul.
de reținut
Un callback query sosește când se apasă un buton inline; îi citești data (ce buton) și mesajul asociat. Reguli de aur: (1) apelează MEREU answerCallbackQuery (altfel butonul pare blocat); (2) folosește editMessageText ca să transformi mesajul existent în loc să trimiți unul nou. Cu aceste două tipare, construiești meniuri inline curate, navigabile — semnătura boților profesioniști.
modul 04 / media & formatarea textului
trimiterea de media
Boții nu se limitează la text. Poți trimite poze, documente, audio, video, locații — fiecare cu metoda ei. Toate urmează același tipar ca sendMessage: chat_id + conținutul.
metodele de media
| Metodă | Trimite |
| sendPhoto | Imagini (afișate în chat) |
| sendDocument | Orice fișier (PDF, zip, etc.) |
| sendAudio / sendVoice | Audio / mesaje vocale |
| sendVideo / sendAnimation | Video / GIF-uri |
| sendLocation | O locație pe hartă |
| sendMediaGroup | Un album (mai multe media într-un mesaj) |
trei moduri de a furniza un fișier
Pentru orice metodă de media, poți da conținutul în trei feluri:
- URL — un link public către fișier; Telegram îl descarcă. Cel mai simplu.
requests.post(f"{API}/sendPhoto", json={
"chat_id": chat_id,
"photo": "https://example.com/poza.jpg",
"caption": "O poză frumoasă"
})
- Upload direct — trimiți fișierul din calculatorul tău (multipart/form-data).
with open("raport.pdf", "rb") as f:
requests.post(f"{API}/sendDocument",
data={"chat_id": chat_id},
files={"document": f})
- file_id — dacă Telegram deja are fișierul (trimis anterior), refolosești id-ul lui — instant, fără re-upload. Cel mai eficient pentru fișiere repetate.
file_id — optimizare importantă
Când trimiți sau primești un fișier, Telegram îi dă un file_id. Dacă vei trimite același fișier de multe ori (ex: un logo, un PDF standard), salvează file_id-ul și refolosește-l — evită re-încărcarea, e mult mai rapid și economisește bandă.
caption & primirea de media
- caption — text sub media (poate fi formatat cu parse_mode).
- Când un utilizator îți trimite media, update-ul conține photo, document etc. (nu text) — le procesezi după caz, luând file_id ca să le descarci sau refolosești.
de reținut
Toate metodele de media urmează tiparul chat_id + conținut, cu conținutul furnizat prin URL (simplu), upload (fișier local) sau file_id (refolosire instantă). Reține file_id-ul pentru fișiere repetate — e cheia eficienței. Cu media + text formatat (lecția următoare), botul tău poate livra orice tip de conținut, nu doar mesaje simple.
modul 04 / media & formatarea textului
formatare, editare & ștergere
formatarea textului: parse_mode
Mesajele pot fi formatate — bold, italic, linkuri, cod. Setezi parse_mode la "HTML" sau "MarkdownV2" și folosești marcajele corespunzătoare.
# parse_mode = "HTML" (recomandat — mai ușor de escapat):
text = "<b>Îngroșat</b>, <i>înclinat</i>, "
"<a href='https://romeo.studio'>link</a>, "
"<code>cod</code>"
requests.post(f"{API}/sendMessage", json={
"chat_id": chat_id,
"text": text,
"parse_mode": "HTML"
})
| Efect | HTML | MarkdownV2 |
| Bold | <b>text</b> | *text* |
| Italic | <i>text</i> | _text_ |
| Cod | <code>text</code> | `text` |
| Link | <a href="url">text</a> | [text](url) |
atenție la escaping
HTML e mai sigur decât MarkdownV2: în MarkdownV2 trebuie să escapezi o listă lungă de caractere speciale (_ * [ ] ( ) ~ ` > # + - = | { } . !), altfel mesajul e respins cu eroare. În HTML escapezi doar <, >, &. Dacă afișezi text de la utilizator formatat, escapează-l ca să nu strice marcajul (sau să injecteze). Pentru majoritatea cazurilor, folosește parse_mode="HTML".
editarea mesajelor
Boții pot modifica mesaje deja trimise — util pentru cronometre, scoruri live, meniuri, statusuri care se actualizează.
requests.post(f"{API}/editMessageText", json={
"chat_id": chat_id,
"message_id": message_id, // care mesaj editez
"text": "Text actualizat"
})
- Ai nevoie de message_id (îl primești când trimiți mesajul).
- editMessageText (text), editMessageReplyMarkup (doar butoanele), editMessageCaption (caption la media).
- Editarea în loc de mesaj nou = chat mai curat (esențial la meniuri inline).
ștergerea mesajelor
requests.post(f"{API}/deleteMessage", json={
"chat_id": chat_id,
"message_id": message_id
})
Șterge un mesaj (al botului sau, cu drepturi de admin în grup, al altcuiva). Util pentru moderare, curățarea mesajelor temporare, ștergerea comenzilor procesate.
de reținut
parse_mode aduce text bogat — preferă "HTML" (escaping simplu: doar < > &) față de MarkdownV2 (multe caractere de escapat). editMessageText îți permite să actualizezi mesaje existente (statusuri, meniuri, live) fără a umple chat-ul, iar deleteMessage le șterge (moderare, curățenie). Aceste trei capacități — formatare, editare, ștergere — transformă boți simpli în interfețe dinamice, curate.
modul 05 / polling vs webhooks
long polling: botul întreabă
Am menționat că botul „preia" update-uri. Există două mecanisme fundamental diferite pentru asta: polling și webhooks. Alegerea între ele e o decizie de arhitectură importantă — să le înțelegem pe ambele.
long polling — modelul „întreb eu"
Cu polling, botul tău întreabă activ Telegram „ai ceva nou pentru mine?" prin getUpdates, într-o buclă continuă. E ceea ce ai văzut în echo bot (modulul 1).
while True:
updates = requests.get(f"{API}/getUpdates",
params={"offset": offset, "timeout": 30}).json()
for upd in updates["result"]:
# procesez...
offset = upd["update_id"] + 1
„long" polling — de ce e eficient
Cheia e parametrul timeout. La long polling, cererea getUpdates nu răspunde imediat cu „nimic nou" — ci așteaptă (până la timeout, ex: 30s) până apare un update, apoi răspunde. Astfel eviți să bombardezi serverul cu mii de cereri goale pe secundă.
avantaje & dezavantaje ale polling-ului
| ➕ Avantaje | ➖ Dezavantaje |
| Simplu de configurat — funcționează oriunde | Botul trebuie să ruleze non-stop (un proces mereu activ) |
| Nu ai nevoie de server public / HTTPS / domeniu | Mică întârziere (până la următoarea verificare) |
| Perfect pentru dezvoltare & boți mici | Se scalează mai greu la volum foarte mare |
| Merge din spatele unui NAT / calculator personal | Un singur proces poate face polling la un moment dat |
de reținut
Long polling = botul întreabă activ Telegram, într-o buclă, cu o cerere care așteaptă (timeout) apariția unui update. E simplu și funcționează oriunde — nu-ți trebuie server public, HTTPS sau domeniu. Ideal pentru dezvoltare, boți mici și medii. Compromisul: un proces trebuie să ruleze permanent. Pentru scală și eficiență maximă, alternativa e webhook-ul.
modul 05 / polling vs webhooks
webhooks: Telegram te sună
Cu webhooks, inversezi modelul: în loc să întrebi tu Telegram, Telegram trimite update-urile la tine, apelând o adresă (URL) a ta, în momentul în care se întâmplă ceva.
cum funcționează
- Îi spui lui Telegram o adresă publică HTTPS a ta cu metoda setWebhook.
- Când apare un update, Telegram trimite un POST cu obiectul Update la acea adresă.
- Serverul tău primește POST-ul, procesează update-ul și răspunde.
requests.post(f"{API}/setWebhook", json={
"url": "https://botul-meu.ro/webhook"
})
# de acum, Telegram va POST-a fiecare update la acest URL
cerințe pentru webhook
- Un server public accesibil (nu localhost).
- HTTPS obligatoriu — cu certificat valid (Telegram refuză HTTP). SSL gratuit via Let's Encrypt / Cloudflare.
- Un endpoint care primește POST-uri și le procesează rapid (răspunde repede; munca grea o pui în fundal).
polling vs webhook — comparație & decizie
| Long polling | Webhook |
| Cine inițiază | Botul întreabă | Telegram trimite |
| Server public | Nu trebuie | Obligatoriu (HTTPS) |
| Latență | Mică întârziere | Instant |
| Eficiență la scală | Mai slabă | Excelentă (reacționează doar când e nevoie) |
| Ideal pentru | Dev, boți mici/medii | Producție, volum mare, serverless |
regula practică
- Dezvoltare & boți personali → polling (simplu, zero infrastructură).
- Producție serioasă / volum mare / serverless → webhook (instant, scalabil).
- Nu poți folosi ambele simultan pentru același bot — setWebhook oprește polling-ul și invers (deleteWebhook revine la polling).
de reținut
Două modele opuse: polling (botul întreabă — simplu, oriunde, dev) vs webhook (Telegram trimite la un URL HTTPS al tău — instant, scalabil, producție). Alege polling ca să pornești rapid și pentru boți mici; treci la webhook când ai nevoie de scală, latență minimă sau găzduire serverless. Nu le poți rula pe amândouă pentru același bot — setWebhook și getUpdates se exclud reciproc.
modul 06 / stare, conversații & persistență
stare & conversații pe pași (FSM)
Până acum, fiecare mesaj a fost tratat izolat. Dar boții reali au conversații: „Cum te cheamă?" → utilizatorul răspunde → „Ce vârstă ai?" → răspunde. Botul trebuie să-și amintească unde e în dialog. Aici intervine starea.
problema: botul nu are memorie implicit
Fiecare update vine independent. Dacă întrebi „Cum te cheamă?" și utilizatorul scrie „Ana", botul nu știe din start că „Ana" e un răspuns la întrebarea despre nume — dacă nu a reținut că aștepta un nume. Trebuie să ții tu starea conversației per utilizator.
FSM — mașina cu stări finite
Modelul standard e o mașină cu stări finite (FSM): conversația e o serie de stări, iar utilizatorul trece dintr-una în alta pe măsură ce răspunde.
Stări: AȘTEPT_NUME → AȘTEPT_VÂRSTĂ → GATA
/start → întreb numele, setez stare = AȘTEPT_NUME
(text) → dacă stare == AȘTEPT_NUME: salvez numele,
întreb vârsta, stare = AȘTEPT_VÂRSTĂ
(text) → dacă stare == AȘTEPT_VÂRSTĂ: salvez vârsta,
confirm, stare = GATA
Fiecare utilizator are propria stare. Când vine un mesaj, verifici starea lui curentă ca să știi ce reprezintă mesajul și ce faci mai departe.
ConversationHandler — sprijin din bibliotecă
Bibliotecile serioase (modulul 7) oferă un ConversationHandler care gestionează aceste tranziții pentru tine: definești stările și ce funcție rulează în fiecare, iar biblioteca ține evidența în ce stare e fiecare utilizator.
# conceptual:
ConversationHandler(
entry_points=[CommandHandler("start", cere_nume)],
states={
NUME: [MessageHandler(filtre.text, salveaza_nume)],
VARSTA: [MessageHandler(filtre.text, salveaza_varsta)],
},
fallbacks=[CommandHandler("anuleaza", anuleaza)],
)
de reținut
Boții nu au memorie implicit — fiecare mesaj vine izolat. Pentru conversații pe pași ții starea fiecărui utilizator: în ce etapă a dialogului e. Modelul e o mașină cu stări (FSM) — utilizatorul trece dintr-o stare în alta pe măsură ce răspunde. Bibliotecile oferă ConversationHandler care automatizează tranzițiile. Fără gestionarea stării, nu poți construi dialoguri (formulare, wizard-uri, comenzi în mai mulți pași).
modul 06 / stare, conversații & persistență
persistența: baze de date pentru bot
Starea unei conversații e temporară. Dar botul are nevoie și de date durabile: utilizatorii înregistrați, preferințe, comenzi, scoruri. Acestea trebuie să supraviețuiască repornirii botului — deci într-o bază de date, nu în memorie.
de ce nu în memorie
Dacă ții datele în variabile Python (un dicționar), la repornirea botului (deploy nou, crash, restart server) se pierd tot. Memoria e bună doar pentru stare temporară de conversație; orice trebuie păstrat merge în stocare persistentă.
opțiuni de stocare, după complexitate
| Opțiune | Bun pentru |
| SQLite | Boți mici/medii — un singur fișier, zero configurare, perfect pentru start |
| PostgreSQL / MySQL | Boți serioși, mulți utilizatori, date relaționale complexe |
| Redis | Stare rapidă, cache, cozi — deseori alături de o bază principală |
| Fișier JSON | Prototipuri simple (dar nu pentru producție reală) |
ce salvezi tipic
- Utilizatori — id-ul Telegram (cheia unică), nume, data înregistrării, setări.
- Date de business — comenzi, mesaje, scoruri, abonamente, ce face botul tău.
- Stare persistentă — dacă vrei ca o conversație lungă să reziste la repornire (opțional).
Cheia naturală pentru orice e user id-ul Telegram (din from.id) — unic și stabil per utilizator. Îl folosești ca să legi datele de persoana potrivită.
exemplu conceptual
# la /start, înregistrez utilizatorul (dacă e nou):
user_id = update.message.from_user.id
db.execute(
"INSERT OR IGNORE INTO utilizatori (id, nume) VALUES (?, ?)",
(user_id, update.message.from_user.first_name)
)
reține și limitele Telegram
- Telegram are rate limits: ~30 mesaje/secundă în total, ~1 mesaj/secundă către același chat. La trimiteri în masă, folosește cozi și pauze.
- Pentru broadcast la mulți utilizatori, salvezi id-urile în DB și trimiți controlat (cu delay), nu tot deodată.
de reținut
Distinge starea temporară (în memorie / conversație) de datele durabile (bază de date). Orice trebuie să supraviețuiască repornirii — utilizatori, comenzi, preferințe — merge într-o bază de date (SQLite pentru start, PostgreSQL pentru scală). Cheia universală e user id-ul Telegram. Iar la trimiteri multiple, respectă rate limits-urile (cozi, pauze). Cu stare + persistență, botul devine o aplicație reală, nu o jucărie.
modul 07 / o bibliotecă reală: structura unui bot
de ce o bibliotecă & cum arată
Ai văzut mecanica pură (getUpdates, sendMessage cu requests). Funcționează, dar pentru boți reali scrii cu o bibliotecă: gestionează bucla, rutarea, stările, erorile — tu scrii doar logica. Cele mai populare în Python: python-telegram-bot și aiogram.
ce îți dă o bibliotecă
- Bucla de update-uri gata făcută (polling sau webhook) — nu o mai scrii tu.
- Handlers & dispatcher — rutarea automată a fiecărui update la funcția potrivită.
- Obiecte convenabile — update.message.reply_text(...) în loc de a construi cereri HTTP manual.
- Tastaturi, conversații, filtre, erori — abstracții curate pentru tot.
- Async — gestionează mii de utilizatori simultan, eficient.
un bot complet cu python-telegram-bot
from telegram import Update
from telegram.ext import (Application, CommandHandler,
MessageHandler, filters, ContextTypes)
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text("Bun venit! 👋")
async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text(update.message.text)
app = Application.builder().token(TOKEN).build()
app.add_handler(CommandHandler("start", start))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))
app.run_polling()
Compară cu bucla manuală din modulul 1 — aceeași funcționalitate, dar curat, structurat, extensibil. Adaugi comportamente pur și simplu adăugând handlers.
async — de ce contează
Boții moderni sunt asincroni (async/await). Motivul: un bot așteaptă des după rețea (apeluri API, baze de date). Cu async, cât timp un handler așteaptă un răspuns, botul poate servi alți utilizatori — în loc să stea blocat. Așa gestionezi mii de conversații simultan cu un singur proces. De aceea vezi async def și await peste tot în boți moderni.
de reținut
O bibliotecă (python-telegram-bot, aiogram) îți dă bucla, dispatcher-ul, handler-ele, tastaturile, conversațiile și async — tu scrii doar logica. Trecerea de la HTTP brut la bibliotecă e saltul de la „înțeleg cum funcționează" la „construiesc eficient". Async permite unui singur bot să servească mii de utilizatori simultan, ne-blocându-se în timpul așteptărilor de rețea. Cunoașterea mecanicii brute (module 1–6) face ca biblioteca să nu fie o „cutie neagră" — știi ce face dedesubt.
modul 07 / o bibliotecă reală: structura unui bot
structura unui proiect real
Un bot serios nu e un singur fișier gigant. Ca orice aplicație, se organizează pe module, cu o structură clară. Iată tiparele care fac un bot mentenabil.
structura de foldere tipică
bot/
main.py # pornirea aplicației + înregistrarea handler-elor
config.py # token din variabile de mediu, setări
handlers/ # câte un fișier pe grup de comenzi
start.py
meniu.py
admin.py
keyboards.py # definițiile tastaturilor
database.py # accesul la baza de date
services/ # logica de business, integrări externe
.env # TOKEN & secrete (NU în Git)
requirements.txt
principii de organizare
- Separă responsabilitățile — handler-ele (ce răspunde botul) separat de logica de business (ce face efectiv) și de accesul la date.
- Token-ul din variabile de mediu (fișierul .env), niciodată hardcodat — vezi modulul 9.
- Tastaturile într-un loc (keyboards.py) — refolosibile, ușor de modificat.
- Un fișier de handlers per zonă funcțională (start, meniu, admin) — nu totul într-unul.
configurarea sigură a token-ului
import os
from dotenv import load_dotenv
load_dotenv() # citește fișierul .env
TOKEN = os.environ["BOT_TOKEN"] # din mediu, nu din cod
middleware & error handling
- Middleware — cod care rulează înainte/după fiecare handler (logging, verificarea abonării, rate limiting per user). aiogram le are native; PTB are echivalente.
- Error handler global — prinde excepțiile ca botul să nu „moară" la o eroare într-un handler; loghezi și, eventual, anunți adminul.
de reținut
Un bot real se organizează ca orice aplicație: handlers separate de logica de business, de accesul la date și de configurare. Token-ul stă în variabile de mediu (.env), tastaturile într-un loc refolosibil, iar un error handler global ține botul viu la excepții. Această structură — plus middleware pentru logging/verificări — transformă un script într-un proiect mentenabil, gata de producție. Următorul pas: funcții avansate și livrarea în producție.
modul 08 / funcții avansate
inline mode, deep linking & grupuri
Boții de bază răspund în chat. Dar Telegram oferă capabilități avansate care deschid cazuri de utilizare puternice. Nu trebuie să le stăpânești pe toate din prima, dar e important să știi ce există.
inline mode — botul în orice chat
Inline mode permite folosirea botului în orice conversație, tastând @nume_bot interogare. Ex: @gif_bot pisici într-un chat cu un prieten → botul propune GIF-uri de ales, fără a părăsi conversația.
- Primești un inline_query (nu un mesaj); răspunzi cu answerInlineQuery, o listă de rezultate.
- Se activează din BotFather (/setinline).
- Ideal pentru: căutare, generatoare de conținut, boți-utilitare folosiți peste tot.
deep linking — start cu parametru
Poți trimite pe cineva direct într-o acțiune a botului printr-un link: https://t.me/nume_bot?start=promo2024. La deschidere, botul primește /start promo2024 — parametrul îți spune de unde vine utilizatorul.
- Perfect pentru: campanii (ce reclamă a adus utilizatorul), referral-uri, acces la un conținut anume, coduri de invitație.
- Parametrul ajunge ca argument al comenzii /start.
boți în grupuri & permisiuni
- Privacy mode (setat în BotFather): dacă e ON, botul vede doar mesajele care îl menționează / comenzile către el — nu tot chatul. Dacă e OFF, vede toate mesajele (necesită mai multă grijă).
- Ca admin de grup, botul poate: șterge mesaje, bloca/da ban utilizatori, restricționa, promova — util pentru moderare automată.
- Update-uri specifice grupurilor: cineva a intrat/ieșit (new_chat_members, left_chat_member) — pentru mesaje de bun venit, verificări anti-spam.
de reținut
Trei capabilități care extind mult ce poate face un bot: inline mode (botul folosit în orice chat via @nume), deep linking (linkuri /start cu parametru — campanii, referral), și rolul de admin în grupuri (moderare: ban, ștergere, bun venit). Nu-ți trebuie toate de la început, dar ele transformă un bot personal într-un instrument care poate ajunge la mulți utilizatori și poate modera comunități.
modul 08 / funcții avansate
plăți, meniuri & Mini Apps
plăți — vinde direct în bot
Telegram are un sistem de plăți integrat: poți vinde produse/servicii direct în chat, fără a scoate utilizatorul din Telegram.
- Conectezi un furnizor de plăți (ex: Stripe și alții) prin BotFather.
- Trimiți o factură cu sendInvoice (produs, preț, monedă).
- Telegram gestionează interfața de plată; primești confirmarea printr-un update special (successful_payment).
- Cazuri: magazine, abonamente, donații, conținut premium, comenzi.
Detaliile de card sunt gestionate de furnizorul de plăți — botul tău nu vede și nu stochează datele cardului (important pentru securitate).
butonul de meniu & comenzi
- Menu button — butonul din stânga câmpului de text; poate afișa lista de comenzi sau deschide o Mini App.
- setMyCommands (modulul 2) — lista din meniul „/", personalizabilă chiar pe limbă sau pe tip de chat.
Telegram Mini Apps — aplicații web în bot
Mini Apps (Web Apps) sunt aplicații web complete care rulează în interiorul Telegram, lansate dintr-un buton al botului. Practic, o pagină web (HTML/JS) cu acces la contextul Telegram (utilizator, temă, plăți).
- Deschizi o interfață bogată (formular complex, catalog, hartă, joc) — dincolo de ce pot butoanele.
- Comunică cu botul tău și cu Telegram printr-un SDK JavaScript.
- Cazuri: magazine complete, dashboard-uri, jocuri, formulare complexe — tot fără a ieși din Telegram.
de reținut
Telegram e o platformă completă, nu doar mesagerie: plăți integrate (vinzi în chat, fără să vezi datele cardului), meniuri personalizabile, și Mini Apps (aplicații web întregi rulate în Telegram) pentru interfețe bogate. Aceste capabilități avansate îți permit să construiești produse reale — magazine, abonamente, jocuri, dashboard-uri — pe infrastructura Telegram. Alege ce ai nevoie pentru cazul tău; nu totul e necesar de la început, dar știind ce există, poți gândi ambițios.
modul 09 / deploy, securitate, proiect & test final
deploy, securitate & bune practici de producție
Un bot pe calculatorul tău trăiește doar cât ține laptopul pornit. Ca să fie mereu disponibil, trebuie găzduit undeva care rulează non-stop. Plus, producția cere grijă la securitate și robustețe.
unde găzduiești un bot
| Opțiune | Bun pentru |
| VPS (DigitalOcean, Hetzner, etc.) | Control total; rulezi cu polling sau webhook; ieftin, flexibil |
| PaaS (Railway, Render, Fly.io) | Deploy simplu din Git, fără administrare de server |
| Serverless (funcții cloud) | Webhook → funcție; plătești per execuție; scalează automat |
| Raspberry Pi / server propriu | Boți personali, hobby (cu polling) |
Pe VPS, ca botul să pornească automat și să repornească la crash, îl rulezi ca serviciu (systemd) sau în Docker — nu într-un terminal deschis.
menținerea botului viu
- Proces manager: systemd, Docker, sau supervisor — repornește botul dacă pică.
- Polling: un singur proces care rulează continuu. Webhook: un server web care primește POST-uri.
- Logging — scrii ce se întâmplă (erori, evenimente) ca să poți diagnostica probleme fără să „ghicești".
securitatea — reguli obligatorii
- Token-ul în variabile de mediu, niciodată în cod sau Git. Dacă s-a expus → /revoke imediat în BotFather.
- Validează input-ul — nu ai încredere în ce trimit utilizatorii; sanitizează înainte de a-l folosi (mai ales în interogări DB — parametri, nu concatenare).
- Verifică permisiunile — la comenzi de admin, confirmă că user id-ul chiar e admin, nu te baza doar pe ascunderea butonului.
- Rate limiting — protejează-te de utilizatori care spamează comenzi (limitează per user).
- Webhook: folosește un secret_token ca să confirmi că POST-urile vin chiar de la Telegram.
robustețe
- Error handling global — botul nu trebuie să moară la o excepție într-un handler.
- Gestionează erorile API — Telegram poate întoarce erori (utilizator care a blocat botul, rate limit) — tratează-le, nu le ignora.
- Backup la baza de date.
de reținut
Producția înseamnă: găzduire non-stop (VPS/PaaS/serverless), botul rulat ca serviciu care repornește singur, logging pentru diagnostic, și securitate serioasă — token în variabile de mediu, validarea input-ului, verificarea permisiunilor, rate limiting. Plus error handling ca botul să reziste la excepții. Aceste discipline separă un experiment de un bot de încredere pe care se pot baza utilizatori reali.
modul 09 / deploy, securitate, proiect & test final
proiect ghidat: un bot util complet
Pui tot cursul la lucru construind un bot Telegram complet și util — tiparul pe care se construiesc nenumărați boți reali. Lucrează pas cu pas, local (cu polling), apoi îl poți duce în producție.
ce construiești: un bot de „memento-uri" (reminders)
Utilizatorii își pot salva memento-uri prin conversație, le pot lista și șterge, iar botul îi notifică. Acoperă toate conceptele cheie: comenzi, conversații cu stare, tastaturi, persistență.
cerințe funcționale
- /start — salut + explicație (înregistrează utilizatorul în DB).
- /add — pornește o conversație: cere textul mementoului, apoi data/ora (stare/FSM).
- /list — afișează memento-urile utilizatorului, fiecare cu un buton inline „🗑 Șterge".
- Butonul de ștergere (callback query) elimină mementoul și editează mesajul cu lista actualizată.
- /help — lista comenzilor; plus setMyCommands pentru meniul „/".
- Datele (utilizatori + memento-uri) în SQLite, legate de user id.
planul, pe modulele cursului
- Setup (mod. 0, 9): bot la BotFather, token în .env, proiect cu python-telegram-bot (mod. 7).
- Structură (mod. 7): main.py + handlers/ + database.py + keyboards.py; error handler global.
- Comenzi (mod. 2): handlers pentru /start, /help, /list; setMyCommands.
- Conversație /add (mod. 6): ConversationHandler cu stările AȘTEPT_TEXT → AȘTEPT_DATA → salvare.
- Persistență (mod. 6): tabele utilizatori și memento-uri în SQLite; cheie = user id.
- Tastaturi & callback (mod. 3): buton inline „Șterge" la fiecare memento; handler de callback + answerCallbackQuery + editMessageText cu lista actualizată.
- Notificări (mod. 6): un job periodic (scheduler) care verifică memento-urile scadente și trimite mesaje — respectând rate limits.
- Producție (mod. 9): rulare ca serviciu, logging, validarea input-ului (data corectă), gestionarea erorilor API.
definiția lui „gata"
- Utilizatorii pot adăuga, lista și șterge memento-uri prin dialog și butoane.
- Datele supraviețuiesc repornirii botului (SQLite).
- Botul notifică la scadență; butoanele răspund instant (answerCallbackQuery), lista se actualizează prin editare.
- Token-ul e în .env; input-ul e validat; erorile nu dobară botul.
- Bonus: deep linking pentru partajare, o Mini App pentru interfața de listă, deploy real cu webhook.
felicitări
Ai parcurs boții Telegram de la Bot API la un bot real, complet: BotFather & token, Update & sendMessage, comenzi & handlers, tastaturi & callback, media & formatare, polling vs webhooks, stare & persistență, biblioteci, funcții avansate și producție — combinate într-un bot de memento-uri funcțional. Ai acum abilitatea de a construi boți utili, siguri, gata de utilizatori reali. Urmează testul final: 20 de întrebări din tot cursul. Prag: 70%. Succes!