7eve9مستندات ورود به نسخهٔ وب

ربات بسازید، در چند دقیقه

API ربات‌های 7eve9 با Bot API تلگرام سازگار است؛ کد و کتابخانه‌هایی که برای تلگرام نوشته‌اید با عوض کردن یک آدرس کار می‌کنند. اینجا از ساخت ربات تا مینی‌اپ را قدم‌به‌قدم می‌آموزید.

معرفی

ربات چیست و API چطور کار می‌کند.

ربات یک حساب ویژه است که به‌جای آدم، برنامهٔ شما پشتش کار می‌کند. هر ربات یک توکن دارد و با فرستادن درخواست‌های ساده (HTTPS) به سرور 7eve9، پیام می‌گیرد و پیام می‌فرستد، دکمه نشان می‌دهد، فایل رد و بدل می‌کند، در گروه‌ها مدیریت می‌کند و حتی یک مینی‌اپ (وب‌اپ داخل پیام‌رسان) باز می‌کند.

مهم‌ترین نکته: API ما با Bot API تلگرام سازگار است. فرمت درخواست و پاسخ یکی است، پس هر کتابخانه یا کدی که برای ربات تلگرام ساخته‌اید، فقط با عوض کردن آدرس سرور کار می‌کند.

آدرس پایه (Base URL)
https://api.7echat.ir/bot<TOKEN>/<METHOD>

سازگار با تلگرام

۸۳ متد، همان نام‌ها و همان قالب JSON. کتابخانه‌های معروف بدون تغییر کار می‌کنند.

دو روش دریافت پیام

long polling با getUpdates یا وب‌هوک که سرور شما را صدا می‌زند.

مینی‌اپ

صفحهٔ وب خودتان داخل پیام‌رسان باز می‌شود و کاربر را با امضای امن می‌شناسد.

تا ۲۰ ربات

هر حساب تا ۲۰ ربات می‌تواند بسازد و همه را از داخل برنامه مدیریت کند.

اگر قبلاً با Bot API تلگرام کار کرده‌اید، از بخش «محدودیت‌ها و تفاوت‌ها» شروع کنید تا ببینید چه چیزهایی فرق دارد.

شروع سریع

از صفر تا اولین پیام ربات، در حدود پنج دقیقه.

  1. با BotFather گفتگو کنیددر برنامه عبارت botfather را جستجو کنید (یا https://7echat.ir/botfather را باز کنید) و /newbot را بفرستید.
  2. یک نام نمایشی بدهیدمثلاً «ربات فروشگاه من». نام می‌تواند فارسی باشد و تا ۶۴ نویسه.
  3. یک یوزرنیم انتخاب کنیدباید با bot تمام شود، با حرف انگلیسی شروع شود و فقط حروف انگلیسی، عدد و _ داشته باشد (۵ تا ۳۲ نویسه)، مثل my_shop_bot.
  4. توکن را بگیریدBotFather توکن را می‌فرستد؛ شبیه 154457014047128:AAH…. آن را مثل رمز عبور نگه دارید و در کد عمومی نگذارید.

قوانین ساخت ربات

ربات باید مطابق قوانین کشور و قوانین 7eve9 باشد؛ محتوای مجرمانه، کلاهبرداری و فیشینگ، اسپم، جمع‌آوری یا سوءاستفاده از اطلاعات کاربران و تبلیغ موارد غیرقانونی ممنوع است.

اگر رباتتان غیرمجاز باشد، ربات مسدود می‌شود و حساب کاربری شما هم بن می‌شود. در صورت پیگیری رسمی مراجع قانونی از جمله پلیس فتا، اطلاعات ثبت‌شدهٔ شما طبق قانون در اختیار آن‌ها قرار می‌گیرد. با ساخت ربات، این قوانین را می‌پذیرید.

هر کسی توکن را داشته باشد ربات را کامل کنترل می‌کند. اگر لو رفت، همان لحظه در BotFather دستور /revoke را بزنید؛ توکن قبلی از کار می‌افتد و توکن تازه می‌گیرید.

اولین درخواست

توکن را در یک متغیر محیطی بگذارید و getMe را صدا بزنید تا مطمئن شوید همه‌چیز درست است:

export TOKEN="154457014047128:AAH-your-token-here"
curl "https://api.7echat.ir/bot$TOKEN/getMe"
const TOKEN = process.env.TOKEN;
const r = await fetch(`https://api.7echat.ir/bot${TOKEN}/getMe`);
console.log(await r.json());
import os, requests
TOKEN = os.environ["TOKEN"]
print(requests.get(f"https://api.7echat.ir/bot{TOKEN}/getMe").json())

پاسخ درست این شکل است (مقادیر نمونه‌اند):

پاسخ
{
  "ok": true,
  "result": {
    "id": 154457014047128,
    "is_bot": true,
    "first_name": "ربات فروشگاه من",
    "username": "my_shop_bot",
    "language_code": "fa",
    "can_join_groups": true,
    "can_read_all_group_messages": false,
    "supports_inline_queries": false,
    "has_main_web_app": false
  }
}

اولین پیام

  1. ربات را Start کنیدربات خودش نمی‌تواند به کسی پیام بدهد؛ اول باید از حساب خودتان به ربات /start بفرستید.
  2. پیام را بخوانیدبا getUpdates می‌بینید ربات چه گرفته است. chat.id همان شناسهٔ شما است.
  3. جواب بدهیدبا sendMessage و همان chat.id.
bash
# 1) ببینید چه آپدیتی آمده
curl "https://api.7echat.ir/bot$TOKEN/getUpdates"

# 2) جواب بدهید (CHAT_ID را از خروجی بالا بردارید)
curl "https://api.7echat.ir/bot$TOKEN/sendMessage" \
  -d chat_id=CHAT_ID \
  --data-urlencode "text=سلام! من ربات شما هستم."

خروجی getUpdates برای /start این شکل است:

json
{
  "ok": true,
  "result": [{
    "update_id": 1,
    "message": {
      "message_id": 300002506,
      "date": 1792326271,
      "chat": { "id": 109270360158361, "type": "private", "first_name": "نیما" },
      "from": { "id": 109270360158361, "is_bot": false, "first_name": "نیما", "language_code": "fa" },
      "text": "/start",
      "entities": [{ "type": "bot_command", "offset": 0, "length": 6 }]
    }
  }]
}

برای یک ربات واقعی از بخش دریافت پیام‌ها و نمونه‌های کامل ادامه دهید؛ آنجا یک ربات کامل با دکمه آمده است.

ساخت ربات با BotFather

BotFather ربات رسمی مدیریت رباتهاست؛ هر چیزی دربارهٔ ربات شما از همین‌جا تنظیم می‌شود.

همهٔ دستورها را در چت botfather می‌فرستید. اگر چند ربات دارید، BotFather فهرست دکمه‌ای نشان می‌دهد؛ یا آخر دستور یوزرنیم بنویسید، مثل /setname @my_shop_bot. دستور /cancel هر مرحله را لغو می‌کند و /help راهنمای کامل را می‌فرستد.

دستورکاربرد
/newbotساخت ربات تازه (نام، یوزرنیم، دریافت توکن). حداکثر ۲۰ ربات برای هر حساب.
/mybotsفهرست ربات‌هایتان با دکمه‌های توکن، ویرایش، تنظیمات و حذف.
/tokenنمایش توکن یک ربات.
/revokeباطل کردن توکن و گرفتن توکن تازه (وقتی لو رفته).
/setnameتغییر نام نمایشی (تا ۶۴ نویسه).
/setdescriptionمتنی که قبل از زدن Start، در صفحهٔ خالی چت با عنوان «این ربات چه کاری می‌کند؟» دیده می‌شود.
/setabouttextبیوی کوتاه در پروفایل ربات (تا ۱۲۰ نویسه). پاک کردن: /empty.
/setuserpicعکس پروفایل ربات (یک عکس بفرستید).
/setcommandsفهرست دستورات (هر خط command - توضیح)؛ وقتی کاربر «/» می‌زند نشان داده می‌شود.
/deletecommandsپاک کردن فهرست دستورات.
/setinlineروشن کردن حالت اینلاین با متن راهنمای کادر پیام. خاموش: /empty.
/setinlinefeedbackدریافت آپدیت chosen_inline_result (انتخاب کاربر).
/setjoingroupsاجازهٔ اضافه شدن ربات به گروه‌ها (Enable / Disable).
/setprivacyحالت حریم خصوصی در گروه‌ها؛ توضیح.
/setmenubuttonدکمهٔ منوی کنار کادر پیام را به یک مینی‌اپ (آدرس https) وصل می‌کند. برگرداندن: /empty.
/setwebappتنظیم مینی‌اپ اصلی ربات (آدرس https و متن دکمه در خط دوم).
/setwebhookتنظیم آدرس وب‌هوک. حذف و برگشت به getUpdates: /empty یا /deletewebhook.
/newgame، /listgamesساخت و فهرست بازی‌های ربات (short_name انگلیسی).
/botinfoاطلاعات و وضعیت ربات.
/deletebotحذف همیشگی ربات. برای تأیید باید دقیقاً بنویسید: Yes, I am totally sure.

نام، عکس و بیوی ربات را از داخل برنامه هم می‌توانید عوض کنید (پروفایل ربات ← ویرایش)، و تغییرها فوری برای همه اعمال می‌شود.

درخواست و پاسخ

قالب همهٔ درخواست‌ها و خطاها.

آدرس و روش

هر متد یک آدرس دارد: https://api.7echat.ir/bot<TOKEN>/<METHOD>. نام متد به بزرگی و کوچکی حروف حساس نیست (getme هم کار می‌کند). فقط GET و POST مجازند؛ روش‌های دیگر خطای 405 می‌گیرند.

پارامترها

پارامترها را به هر یک از این شکل‌ها می‌توانید بفرستید و با هم قاطی هم می‌شوند:

  • query string (?chat_id=1&text=hi)
  • فرم application/x-www-form-urlencoded
  • application/json (پیشنهادی برای ساختارهای تودرتو مثل reply_markup)
  • multipart/form-data (برای آپلود فایل)

پاسخ

پاسخ همیشه JSON است. موفق: {"ok": true, "result": …}. ناموفق: {"ok": false, "error_code": …, "description": "…"}.

کدمعنینمونه توضیح
400درخواست نادرستBad Request: chat not found، message is too long، message text is empty، invalid file_id
401توکن نامعتبرUnauthorized
404متد وجود نداردNot Found: method not found
405روش HTTP مجاز نیستفقط GET و POST
409تداخل وب‌هوک و getUpdatesConflict: can't use getUpdates method while webhook is active…
413حجم بدنهٔ درخواست زیاد استبیش از ۵۰ مگابایت
403اجازه نداریدForbidden: bot was blocked by the user، bot is not a member of the chat
429درخواست‌های زیادکمی صبر کنید؛ parameters.retry_after می‌گوید چند ثانیه

شناسه‌ها

شناسهقاعده
user.idعدد صحیح بزرگ (کمتر از ۲۵۳؛ در همهٔ زبان‌ها بدون مشکل در عدد معمولی جا می‌شود).
chat.idچت خصوصی = شناسهٔ همان کاربر (عدد مثبت). گروه و کانال = عدد منفی. به‌جای آن می‌توانید @username هم بدهید.
message_idعدد صحیح؛ در همهٔ متدها (ویرایش، حذف، ریپلای…) قابل استفاده است.

دریافت پیام‌ها

چطور ربات بفهمد کسی چیزی نوشته یا دکمه‌ای زده.

هر رویداد (پیام تازه، زدن دکمه، …) یک آپدیت است. دو راه برای گرفتنش هست و همزمان فقط یکی فعال است.

روش اول: getUpdates (long polling)

ربات خودش مدام می‌پرسد «چیزی آمده؟». ساده است و برای شروع و برنامه‌هایی که آدرس عمومی ندارند عالی است.

پارامترتوضیح
offsetشناسهٔ آپدیتی که می‌خواهید از آن شروع شود. بعد از پردازش هر آپدیت، update_id + 1 را بدهید تا آپدیت‌های قبلی پاک شوند.
timeoutچند ثانیه سرور منتظر آپدیت تازه بماند (حداکثر ۵۰). با 0 فوراً جواب می‌دهد.
limitتعداد آپدیت در هر پاسخ، ۱ تا ۱۰۰.
allowed_updatesآرایهٔ نوع آپدیت‌هایی که می‌خواهید (مثل ["message","callback_query"]).

آپدیت‌های خوانده‌نشده ۲۴ ساعت نگه داشته می‌شوند. اگر وب‌هوک فعال باشد، getUpdates خطای 409 می‌دهد.

روش دوم: وب‌هوک

سرور 7eve9 هر آپدیت را با POST به آدرس شما می‌فرستد. سریع‌تر است و برای ربات‌های بزرگ مناسب‌تر.

bash
curl "https://api.7echat.ir/bot$TOKEN/setWebhook" \
  -d url=https://example.com/hook \
  -d secret_token=یک-رشته-تصادفی-بلند \
  -d 'allowed_updates=["message","callback_query"]'
  • آدرس باید عمومی باشد؛ آدرس‌های داخلی و محلی (مثل 127.0.0.1) رد می‌شوند.
  • هر آپدیت با هدر X-Telegram-Bot-Api-Secret-Token (همان secret_token شما) می‌آید؛ آن را چک کنید تا کسی نتواند آپدیت جعلی بفرستد.
  • مهلت پاسخ ۱۵ ثانیه است و تغییر مسیر (redirect) دنبال نمی‌شود. با خطا، سه بار دیگر تلاش می‌شود (بعد از ۵ ثانیه، ۳۰ ثانیه و ۲ دقیقه).
  • وضعیت را با getWebhookInfo ببینید؛ برای حذف: deleteWebhook (با drop_pending_updates=true آپدیت‌های منتظر را هم پاک می‌کند).

انواع آپدیت

فیلدچه وقت می‌آید
messageپیام تازه (متن، عکس، فایل، موقعیت، …) در چت خصوصی یا گروه.
edited_messageپیامی ویرایش شد.
channel_post / edited_channel_postپست کانال (فقط وقتی ربات ادمین کانال است).
callback_queryکاربر یک دکمهٔ شیشه‌ای را زد.
inline_query / chosen_inline_resultحالت اینلاین.
my_chat_memberربات اضافه، حذف یا ادمین شد.
chat_join_requestدرخواست عضویت در گروه/کانال با تأیید ادمین.
poll_answerکسی در نظرسنجی رأی داد.
message_reactionواکنش (ایموجی) روی پیامی تغییر کرد.

هر آپدیت update_id دارد و دقیقاً یکی از فیلدهای بالا. نمونهٔ callback_query (وقتی کاربر دکمه‌ای با callback_data=vote:yes می‌زند):

json
{
  "update_id": 2,
  "callback_query": {
    "id": "1792326314626932",
    "from": { "id": 109270360158361, "is_bot": false, "first_name": "نیما", "language_code": "fa" },
    "chat_instance": "154457014047173",
    "message": {
      "message_id": 300002509,
      "date": 1792326314,
      "chat": { "id": 109270360158361, "type": "private", "first_name": "نیما" },
      "from": { "id": 154457014047128, "is_bot": true, "first_name": "ربات فروشگاه من", "username": "my_shop_bot" },
      "text": "یکی را انتخاب کنید:",
      "reply_markup": { "inline_keyboard": [[ { "text": "بله", "callback_data": "vote:yes" }, { "text": "خیر", "callback_data": "vote:no" } ]] }
    },
    "data": "vote:yes"
  }
}

ارسال و ویرایش پیام

sendMessage و دوستانش.

پارامتر sendMessageتوضیح
chat_idشناسهٔ چت (یا @username). برای چت خصوصی، کاربر باید قبلاً ربات را Start کرده باشد.
textمتن پیام، حداکثر ۴۰۹۶ نویسه.
parse_modeHTML، MarkdownV2 یا Markdown؛ یا به‌جایش آرایهٔ entities.
reply_markupدکمه‌ها؛ بخش ۷.
reply_parameters / reply_to_message_idریپلای به یک پیام (reply_parameters شامل message_id؛ با allow_sending_without_reply اگر پیام نبود خطا نمی‌دهد).
disable_web_page_preview / link_preview_optionsخاموش کردن پیش‌نمایش لینک ({"is_disabled": true}).
curl "https://api.7echat.ir/bot$TOKEN/sendMessage" \
  -H "Content-Type: application/json" \
  -d '{
    "chat_id": 109270360158361,
    "text": "<b>سلام!</b> این یک پیام <i>قالب‌بندی‌شده</i> است.",
    "parse_mode": "HTML"
  }'
await fetch(`https://api.7echat.ir/bot${TOKEN}/sendMessage`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    chat_id: 109270360158361,
    text: "<b>سلام!</b> این یک پیام <i>قالب‌بندی‌شده</i> است.",
    parse_mode: "HTML",
  }),
});
requests.post(f"https://api.7echat.ir/bot{TOKEN}/sendMessage", json={
    "chat_id": 109270360158361,
    "text": "<b>سلام!</b> این یک پیام <i>قالب‌بندی‌شده</i> است.",
    "parse_mode": "HTML",
})

پاسخ، خود پیام فرستاده‌شده است (با message_id که برای ویرایش و حذف لازم دارید):

json
{
  "ok": true,
  "result": {
    "message_id": 300002507,
    "date": 1792326272,
    "chat": { "id": 109270360158361, "type": "private", "first_name": "نیما" },
    "from": { "id": 154457014047128, "is_bot": true, "first_name": "ربات فروشگاه من", "username": "my_shop_bot" },
    "text": "سلام! این یک پیام قالب‌بندی‌شده است.",
    "entities": [{ "type": "bold", "offset": 0, "length": 5 }, { "type": "italic", "offset": 18, "length": 13 }]
  }
}

قالب‌بندی متن

حالتچه چیزهایی
HTML<b> <i> <u> <s> <tg-spoiler> <a href="…"> <code> <pre> <blockquote>. منشن: <a href="tg://user?id=123">نام</a>
MarkdownV2*bold* _italic_ __underline__ ~strike~ ||spoiler|| `code` [متن](url) و نقل‌قول با > اول خط. نویسه‌های خاص را با \ بگریزانید.
Markdownنسخهٔ قدیمی و ساده‌تر.

در حالت HTML فقط سه نویسهٔ < > & باید به &lt; &gt; &amp; تبدیل شوند؛ برای متن کاربر از HTML استفاده کنید تا گریز دادن ساده‌تر باشد.

ویرایش، حذف و واکنش

  • editMessageText، editMessageCaption، editMessageReplyMarkup، editMessageMedia: با chat_id و message_id پیام خودِ ربات را عوض کنید.
  • deleteMessage و deleteMessages: حذف پیام.
  • forwardMessage، copyMessage (و نسخهٔ چندتایی): فوروارد و کپی بدون نام فرستنده.
  • setMessageReaction: واکنش ربات روی یک پیام.
  • sendChatAction با action=typing و… نشان می‌دهد ربات در حال نوشتن است.
  • sendLocation، sendVenue، sendContact، sendPoll، sendDice: انواع دیگر پیام.

دکمه‌ها و کیبورد

دکمه‌های شیشه‌ای زیر پیام و کیبورد جایگزین.

دکمهٔ شیشه‌ای (inline keyboard)

آرایه‌ای از ردیف‌ها، هر ردیف آرایه‌ای از دکمه‌ها:

json
{
  "chat_id": 109270360158361,
  "text": "یکی را انتخاب کنید:",
  "reply_markup": {
    "inline_keyboard": [
      [ { "text": "بله", "callback_data": "vote:yes" }, { "text": "خیر", "callback_data": "vote:no" } ],
      [ { "text": "باز کردن سایت", "url": "https://7echat.ir" } ],
      [ { "text": "مینی‌اپ", "web_app": { "url": "https://example.com/app" } } ],
      [ { "text": "جستجو در هر چت", "switch_inline_query": "" } ]
    ]
  }
}
فیلد دکمهرفتار
callback_dataبا زدن دکمه، آپدیت callback_query می‌آید و data همین رشته است.
urlباز کردن یک لینک.
web_appباز کردن مینی‌اپ (آدرس https).
switch_inline_queryکاربر را به چت دیگری می‌برد تا حالت اینلاین ربات را با آن عبارت شروع کند.

جواب دادن به دکمه

وقتی callback_query آمد، حتماً با answerCallbackQuery جواب بدهید تا نشانهٔ «در حال بارگذاری» روی دکمه تمام شود. پارامترها: callback_query_id، text (پیام کوتاه)، show_alert (true = پنجرهٔ هشدار) و url (برای بازی).

برنامه فقط ۶ ثانیه منتظر جواب می‌ماند. بعد از آن شناسهٔ callback منقضی می‌شود و answerCallbackQuery خطای query is too old… می‌دهد. جواب را اول بدهید و کار سنگین را بعدش.

js
if (update.callback_query) {
  const q = update.callback_query;
  await call("answerCallbackQuery", { callback_query_id: q.id, text: "ثبت شد" });   // اول جواب
  await call("editMessageText", {                                                    // بعد پیام را عوض کن
    chat_id: q.message.chat.id,
    message_id: q.message.message_id,
    text: q.data === "vote:yes" ? "رأی شما: بله" : "رأی شما: خیر",
  });
}

کیبورد معمولی

به‌جای دکمه‌های زیر پیام، دکمه‌هایی جای کیبورد می‌نشینند و با زدن، متن همان دکمه به‌عنوان پیام فرستاده می‌شود:

json
{ "keyboard": [[{ "text": "منو" }, { "text": "سفارش من" }]], "resize_keyboard": true, "one_time_keyboard": true }
  • حذف کیبورد: {"remove_keyboard": true}
  • مجبور کردن کاربر به ریپلای: {"force_reply": true}

فایل و رسانه

فرستادن و گرفتن عکس، ویدیو، صدا و فایل.

متدهای sendPhoto، sendVideo، sendAnimation، sendAudio، sendVoice، sendDocument، sendSticker، sendVideoNote و sendMediaGroup (۱ تا ۱۰ مورد) هر کدام یک پارامتر فایل می‌گیرند. فایل را به سه شکل می‌توانید بدهید:

۱. آدرس اینترنتی

یک آدرس http(s). سرور 7eve9 خودش دانلود می‌کند (تا ۵۰ مگابایت).

۲. file_id

شناسهٔ فایلی که قبلاً فرستاده یا گرفته‌اید؛ بدون آپلود دوباره.

۳. آپلود (multipart)

خود فایل را در multipart/form-data بفرستید (تا ۵۰ مگابایت).

bash
# با آدرس اینترنتی
curl "https://api.7echat.ir/bot$TOKEN/sendPhoto" -d chat_id=CHAT_ID \
  -d photo=https://7echat.ir/site-assets/logo.png --data-urlencode "caption=لوگوی 7eve9"

# با آپلود فایل
curl "https://api.7echat.ir/bot$TOKEN/sendDocument" -F chat_id=CHAT_ID -F document=@report.pdf

پاسخ شامل file_id و file_unique_id است؛ برای عکس، آرایه‌ای از اندازه‌ها:

json
"photo": [{ "file_id": "FL3VwbG9hZHMvYm90LTNh…", "file_unique_id": "Ay8TjbgtFWEs1QTG", "width": 192, "height": 192, "file_size": 28977 }]

دانلود فایلی که کاربر فرستاده

  1. file_id را برداریداز آپدیت پیام (مثلاً message.photo[-1].file_id یا message.document.file_id).
  2. getFile را صدا بزنیدپاسخ file_path دارد.
  3. دانلود کنیدhttps://api.7echat.ir/file/bot<TOKEN>/<file_path> (فقط GET).

گروه و کانال

ربات در گروه‌ها و کانال‌ها، مدیریت و حریم خصوصی.

اضافه کردن ربات

اگر /setjoingroups روی Enable باشد (پیش‌فرض)، کاربر می‌تواند ربات را به گروه اضافه کند. ربات آپدیت my_chat_member می‌گیرد. برای کانال، ربات باید ادمین باشد تا channel_post بیاید.

حالت حریم خصوصی (Privacy mode)

به‌طور پیش‌فرض ربات در گروه فقط این‌ها را می‌بیند: دستورات (/cmd یا /cmd@your_bot)، پیام‌هایی که منشنش می‌کنند، ریپلای به پیام‌های خودش و ورود و خروج اعضا. برای دیدن همهٔ پیام‌ها، با /setprivacy آن را Disable کنید یا ربات را ادمین گروه کنید.

شناسهٔ گروه

chat.id گروه‌ها و کانال‌ها منفی است. برای چت با یوزرنیم عمومی، @username هم کار می‌کند.

متدهای مدیریت

ربات باید در گروه ادمین باشد و همان دسترسی را داشته باشد (مثلاً «مسدود کردن کاربران»)؛ دسترسی‌ها دقیقاً مثل ادمین‌های انسانی اعمال می‌شوند.

py
def ban_if_reply(update):
    m = update["message"]
    if m.get("text", "").startswith("/ban") and "reply_to_message" in m:
        call("banChatMember", chat_id=m["chat"]["id"],
             user_id=m["reply_to_message"]["from"]["id"])
        call("sendMessage", chat_id=m["chat"]["id"], text="کاربر مسدود شد.")

متدهای گروه: banChatMember، unbanChatMember، restrictChatMember، promoteChatMember، setChatAdministratorCustomTitle، setChatPermissions، setChatTitle، setChatDescription، setChatPhoto، deleteChatPhoto، setChatSlowModeDelay، pinChatMessage، unpinChatMessage، unpinAllChatMessages، لینک‌های دعوت (exportChatInviteLink، createChatInviteLink، editChatInviteLink، revokeChatInviteLink)، درخواست‌های عضویت (approveChatJoinRequest، declineChatJoinRequest) و leaveChat. اطلاعات: getChat، getChatMember، getChatAdministrators، getChatMemberCount.

حالت اینلاین

استفاده از ربات در هر چتی، بدون اضافه کردنش.

با /setinline این حالت را روشن می‌کنید. کاربر در هر چتی می‌نویسد @your_bot عبارت و ربات آپدیت inline_query می‌گیرد؛ با answerInlineQuery فهرست نتیجه می‌دهید و کاربر یکی را انتخاب می‌کند تا همان‌جا فرستاده شود.

js
if (update.inline_query) {
  const q = update.inline_query;                 // { id, from, query, offset }
  await call("answerInlineQuery", {
    inline_query_id: q.id,
    cache_time: 10,
    results: [
      { type: "article", id: "1", title: `جستجو: ${q.query}`,
        input_message_content: { message_text: `نتیجهٔ ${q.query}` } },
    ],
  });
}

انواع نتیجه: article، photo، gif، mpeg4_gif، video، audio، voice، document، location، venue، contact و sticker. پارامترهای answerInlineQuery: results (تا ۵۰ مورد)، next_offset، cache_time، is_personal و button. اگر /setinlinefeedback را روشن کنید، انتخاب کاربر هم با chosen_inline_result می‌آید.

مثل callback، به inline_query هم باید سریع جواب بدهید؛ شناسهٔ قدیمی خطای query is too old… می‌دهد.

مینی‌اپ

یک وب‌اپ کامل داخل پیام‌رسان.

مینی‌اپ یک صفحهٔ وب معمولی (HTML، CSS، JavaScript) روی سرور خودتان است که داخل 7eve9 باز می‌شود. مزیتش این است که کاربر را بدون ثبت‌نام می‌شناسد: برنامه یک رشتهٔ امضاشده به نام initData به صفحه می‌دهد و سرور شما امضا را بررسی می‌کند.

۱. اتصال به ربات

  • دکمهٔ منو: در BotFather /setmenubutton و آدرس https (در خط دوم، متن دکمه). کنار کادر پیام یک دکمه ظاهر می‌شود.
  • دکمهٔ زیر پیام: در reply_markup یک دکمه با {"text":"باز کردن","web_app":{"url":"https://…"}}.
  • مینی‌اپ اصلی: /setwebapp (آدرس و متن دکمه).
  • با API: setChatMenuButton با {"type":"web_app","text":"…","web_app":{"url":"https://…"}}.

آدرس مینی‌اپ حتماً https باشد.

۲. گرفتن initData در صفحه

برنامه داده را در بخش hash آدرس (بعد از #) می‌گذارد:

js
const params = new URLSearchParams(location.hash.slice(1));
const initData = params.get("tgWebAppData");          // رشتهٔ امضاشده؛ آن را به سرور خودتان بفرستید
const theme = JSON.parse(params.get("tgWebAppThemeParams") || "{}");   // رنگ‌های تم برنامه

const res = await fetch("/api/me", { headers: { "X-Init-Data": initData } });

پروتکل مینی‌اپ با تلگرام سازگار است: صفحه با TelegramWebviewProxy.postEvent به برنامه پیام می‌دهد (مثل بستن یا تنظیم رنگ) و برنامه با window.Telegram.WebView.receiveEvent رویدادها (مثل تغییر تم) را به صفحه می‌دهد.

۳. بررسی امضا در سرور (حتماً)

initData را هرگز بدون بررسی امضا باور نکنید؛ هر کسی می‌تواند یک رشتهٔ ساختگی بفرستد. امضا با HMAC-SHA256 و توکن ربات ساخته می‌شود، دقیقاً مثل تلگرام:

  1. hash را جدا کنیدهمهٔ جفت‌های key=value را بخوانید و hash را کنار بگذارید.
  2. رشتهٔ بررسی بسازیدبقیه را بر اساس نام کلید مرتب کنید و با \n به هم بچسبانید.
  3. کلید مخفیHMAC_SHA256(key="WebAppData", data=bot_token)
  4. مقایسهHMAC_SHA256(key=secret, data=رشتهٔ بررسی) (hex) باید با hash برابر باشد (مقایسهٔ زمان‌ثابت).
  5. تازگیauth_date را چک کنید، مثلاً بیش از یک روز قدیمی رد شود.
import crypto from "node:crypto";

export function verifyInitData(initData, botToken, maxAgeSec = 86400) {
  const p = new URLSearchParams(initData);
  const hash = p.get("hash");
  if (!hash) return null;
  p.delete("hash");
  const check = [...p.entries()].map(([k, v]) => `${k}=${v}`).sort().join("\n");
  const secret = crypto.createHmac("sha256", "WebAppData").update(botToken).digest();
  const ok = crypto.createHmac("sha256", secret).update(check).digest("hex");
  if (ok.length !== hash.length || !crypto.timingSafeEqual(Buffer.from(ok), Buffer.from(hash))) return null;
  if (Date.now() / 1000 - Number(p.get("auth_date") || 0) > maxAgeSec) return null;
  return JSON.parse(p.get("user") || "{}");      // { id, first_name, last_name?, username?, language_code }
}
import hmac, hashlib, json, time
from urllib.parse import parse_qsl

def verify_init_data(init_data: str, bot_token: str, max_age: int = 86400):
    pairs = dict(parse_qsl(init_data, keep_blank_values=True))
    got = pairs.pop("hash", None)
    if not got:
        return None
    check = "\n".join(f"{k}={v}" for k, v in sorted(pairs.items()))
    secret = hmac.new(b"WebAppData", bot_token.encode(), hashlib.sha256).digest()
    ok = hmac.new(secret, check.encode(), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(ok, got):
        return None
    if time.time() - int(pairs.get("auth_date", 0)) > max_age:
        return None
    return json.loads(pairs.get("user", "{}"))

۴. نکتهٔ مهم: نمایش داخل نسخهٔ وب

در اپ اندروید، مینی‌اپ داخل WebView باز می‌شود؛ اما در نسخهٔ وب (web.7echat.ir) داخل یک iframe است. پس سرور شما نباید جلوی قرار گرفتن در iframe را بگیرد:

  • هدر X-Frame-Options: DENY یا SAMEORIGIN نفرستید.
  • اگر Content-Security-Policy دارید، فقط این دو را مجاز کنید: frame-ancestors https://web.7echat.ir https://7echat.ir

علامت این مشکل: در اپ اندروید صفحه باز می‌شود ولی در نسخهٔ وب پیام «اجازهٔ نمایش داخل سایت دیگر را نمی‌دهد» می‌بینید.

۵. ارسال نتیجه به چت

  • answerWebAppQuery: نتیجه‌ای (به‌شکل یک InlineQueryResult) از طرف کاربر داخل چت فرستاده می‌شود.
  • مینی‌اپ می‌تواند با sendData داده‌ای به ربات بفرستد که به‌شکل پیام web_app_data می‌رسد.

بازی‌ها

با /newgame بازی می‌سازید، با sendGame می‌فرستید و وقتی کاربر Play می‌زند، آپدیت callback_query با game_short_name می‌آید و با answerCallbackQuery(url=…) صفحهٔ بازی باز می‌شود.

ثبت و خواندن امتیاز بازی (setGameScore و getGameHighScores) هنوز در Bot API نیست و صدا زدنشان 404 می‌دهد.

مرجع متدها

همهٔ ۸۳ متدی که الان کار می‌کنند. نام‌ها و پارامترها مثل Bot API تلگرام است.

متدی با این نام پیدا نشد.

متدی که اینجا نیست (مثل پرداخت، مدیریت استیکرست یا تاپیک‌های فروم) جواب 404 Not Found: method not found می‌دهد.

کتابخانه‌ها

کتابخانه‌های آمادهٔ تلگرام را فقط با عوض کردن آدرس سرور استفاده کنید.

from telegram.ext import Application

app = (Application.builder().token(TOKEN)
       .base_url("https://api.7echat.ir/bot")
       .base_file_url("https://api.7echat.ir/file/bot")
       .build())
from aiogram import Bot
from aiogram.client.session.aiohttp import AiohttpSession
from aiogram.client.telegram import TelegramAPIServer

session = AiohttpSession(api=TelegramAPIServer.from_base("https://api.7echat.ir"))
bot = Bot(TOKEN, session=session)
import { Telegraf } from "telegraf";
const bot = new Telegraf(TOKEN, { telegram: { apiRoot: "https://api.7echat.ir" } });
import TelegramBot from "node-telegram-bot-api";
const bot = new TelegramBot(TOKEN, { polling: true, baseApiUrl: "https://api.7echat.ir" });
import telebot
telebot.apihelper.API_URL = "https://api.7echat.ir/bot{0}/{1}"
bot = telebot.TeleBot(TOKEN)

نمونه‌های کامل

کدهایی که می‌توانید کپی کنید و اجرا کنید.

ربات با دکمه (long polling)

به /start سلام می‌دهد و دو دکمه نشان می‌دهد؛ با زدن هر دکمه پیام ویرایش می‌شود.

// node bot.mjs   (Node 18 به بالا؛ متغیر BOT_TOKEN را تنظیم کنید)
const TOKEN = process.env.BOT_TOKEN;
const API = "https://api.7echat.ir";

async function call(method, params = {}) {
  const r = await fetch(`${API}/bot${TOKEN}/${method}`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(params),
  });
  const j = await r.json();
  if (!j.ok) throw new Error(`${method}: ${j.error_code} ${j.description}`);
  return j.result;
}

const menu = { inline_keyboard: [[
  { text: "بله", callback_data: "vote:yes" },
  { text: "خیر", callback_data: "vote:no" },
]] };

let offset = 0;
console.log("ربات روشن شد");
for (;;) {
  try {
    const updates = await call("getUpdates", { offset, timeout: 30, allowed_updates: ["message", "callback_query"] });
    for (const u of updates) {
      offset = u.update_id + 1;

      if (u.message?.text === "/start") {
        await call("sendMessage", { chat_id: u.message.chat.id, text: "سلام! نظر شما؟", reply_markup: menu });
      } else if (u.message?.text) {
        await call("sendMessage", { chat_id: u.message.chat.id, text: `گفتید: ${u.message.text}` });
      }

      if (u.callback_query) {
        const q = u.callback_query;
        await call("answerCallbackQuery", { callback_query_id: q.id, text: "ثبت شد" });
        await call("editMessageText", {
          chat_id: q.message.chat.id,
          message_id: q.message.message_id,
          text: q.data === "vote:yes" ? "رأی شما: بله" : "رأی شما: خیر",
        });
      }
    }
  } catch (e) {
    console.error(e.message);
    await new Promise((r) => setTimeout(r, 3000));
  }
}
import os, time, requests

TOKEN = os.environ["BOT_TOKEN"]
API = "https://api.7echat.ir"

def call(method, **params):
    r = requests.post(f"{API}/bot{TOKEN}/{method}", json=params, timeout=70).json()
    if not r["ok"]:
        raise RuntimeError(f'{method}: {r["error_code"]} {r["description"]}')
    return r["result"]

menu = {"inline_keyboard": [[
    {"text": "بله", "callback_data": "vote:yes"},
    {"text": "خیر", "callback_data": "vote:no"},
]]}

offset = 0
print("ربات روشن شد")
while True:
    try:
        for u in call("getUpdates", offset=offset, timeout=30, allowed_updates=["message", "callback_query"]):
            offset = u["update_id"] + 1
            m = u.get("message")
            if m and m.get("text") == "/start":
                call("sendMessage", chat_id=m["chat"]["id"], text="سلام! نظر شما؟", reply_markup=menu)
            elif m and m.get("text"):
                call("sendMessage", chat_id=m["chat"]["id"], text=f'گفتید: {m["text"]}')
            q = u.get("callback_query")
            if q:
                call("answerCallbackQuery", callback_query_id=q["id"], text="ثبت شد")
                call("editMessageText", chat_id=q["message"]["chat"]["id"],
                     message_id=q["message"]["message_id"],
                     text="رأی شما: بله" if q["data"] == "vote:yes" else "رأی شما: خیر")
    except Exception as e:
        print(e)
        time.sleep(3)

وب‌هوک با Express

js
import express from "express";

const TOKEN = process.env.BOT_TOKEN;
const SECRET = process.env.HOOK_SECRET;          // همان secret_token که در setWebhook دادید
const app = express();
app.use(express.json());

app.post("/hook", async (req, res) => {
  if (req.get("X-Telegram-Bot-Api-Secret-Token") !== SECRET) return res.sendStatus(403);
  res.sendStatus(200);                           // اول جواب بدهید؛ پردازش بعدش

  const m = req.body.message;
  if (m?.text) {
    await fetch(`https://api.7echat.ir/bot${TOKEN}/sendMessage`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ chat_id: m.chat.id, text: `گفتید: ${m.text}` }),
    });
  }
});

app.listen(3000);
// سپس: setWebhook?url=https://your.site/hook&secret_token=...

سرور مینی‌اپ (Express + بررسی امضا)

js
import express from "express";
import { verifyInitData } from "./verify.js";        // تابع بخش مینی‌اپ

const app = express();
app.use((_req, res, next) => {
  // اجازهٔ نمایش داخل نسخهٔ وب (iframe)
  res.set("Content-Security-Policy", "frame-ancestors https://web.7echat.ir https://7echat.ir");
  next();
});
app.use(express.static("public"));                // صفحهٔ HTML مینی‌اپ

app.get("/api/me", (req, res) => {
  const user = verifyInitData(req.get("X-Init-Data") || "", process.env.BOT_TOKEN);
  if (!user) return res.status(401).json({ error: "initData نامعتبر است" });
  res.json({ id: user.id, name: user.first_name });
});

app.listen(3000);

محدودیت‌ها و تفاوت‌ها

اعدادی که باید بدانید، و تفاوت‌ها با Bot API تلگرام.

موردمقدار
طول متن پیامحداکثر ۴۰۹۶ نویسه
حجم آپلود فایلحداکثر ۵۰ مگابایت
sendMediaGroup۱ تا ۱۰ مورد
getUpdatestimeout تا ۵۰ ثانیه، limit ۱ تا ۱۰۰، نگهداری آپدیت‌ها ۲۴ ساعت
وب‌هوکمهلت ۱۵ ثانیه، بدون redirect، ۳ تلاش مجدد (۵ ثانیه، ۳۰ ثانیه، ۲ دقیقه)، فقط آدرس عمومی
پاسخ به callback۶ ثانیه
تعداد رباتتا ۲۰ ربات برای هر حساب
نام ربات / بیو۶۴ نویسه / ۱۲۰ نویسه
نرخ درخواستحدود ۲۰ درخواست در ثانیه برای هر آدرس IP و حدود ۳۰ درخواست در ثانیه برای هر ربات (با اندکی تحمل برای اوج‌های کوتاه). بیشتر از آن 429 می‌گیرید.
نرخ ارسال پیامتا ۳۰ پیام در ثانیه برای هر ربات، تا ۱۵ پیام در ۱۰ ثانیه به هر کاربر، و تا ۲۰ پیام در دقیقه در هر گروه یا کانال. بیشتر از آن 429 با parameters.retry_after (ثانیه) برمی‌گردد.
حجم فایل ذخیره‌شدههر ربات در هر ساعت تا ۳۰۰ مگابایت فایل (آپلود یا دریافت از آدرس) می‌تواند اضافه کند.
getUpdates همزمانحداکثر ۳ درخواست long polling هم‌زمان برای هر ربات؛ بیشتر از آن 409.
توکن اشتباهبعد از حدود ۳۰ توکن نادرست در یک دقیقه از یک آدرس، درخواست‌های با توکن اشتباه 429 می‌گیرند. توکن درست هیچ‌وقت تحت تأثیر نیست.

قواعد امنیتی

این قواعد هم از کاربران، هم از خود ربات‌ها و هم از پیام‌رسان محافظت می‌کنند:

  • ربات فقط چت‌هایی را می‌بیند که عضوشان است. خواندن، فوروارد یا کپی از گروه یا کانالی که ربات در آن نیست، جواب chat not found می‌گیرد (مگر گروه یا کانال عمومی با @username).
  • کاربر می‌تواند ربات را مسدود کند. ربات به کسی که آن را مسدود کرده پیام نمی‌تواند بفرستد (403 bot was blocked by the user).
  • ربات پیام اول را نمی‌فرستد و عکس پروفایل را فقط برای کسانی می‌بیند که با آن چت دارند (getUserProfilePhotos).
  • دکمه‌ها اعتبارسنجی می‌شوند: callback_data حداکثر ۶۴ بایت، دکمهٔ url فقط http(s):// یا tg://، و web_app فقط https. نسخه‌های ناامن (مثل javascript:) رد می‌شوند.
  • حذف پیام کاربر در چت خصوصی فقط تا ۴۸ ساعت بعد از ارسال ممکن است.
  • نام و یوزرنیم‌هایی که شبیه خود پیام‌رسان هستند (مثل 7eve9، botfather، support، پشتیبانی، رسمی) برای جلوگیری از جعل هویت رزرو شده‌اند.
  • آدرس وب‌هوک و فایل‌ها هرگز به شبکهٔ داخلی یا سرورهای خود 7eve9 دسترسی ندارند، و برای فایل‌های دریافتی فقط پسوندهای امن نگه داشته می‌شود.
  • آپلود بدون توکن ممکن نیست: درخواست ابتدا احراز هویت می‌شود، بعد بدنه خوانده می‌شود.

فرق با Bot API تلگرام

  • ربات نمی‌تواند اول به کاربر پیام بدهد؛ کاربر باید Start کند.
  • این‌ها وجود ندارند و 404 می‌دهند: پرداخت و فاکتور، مدیریت استیکرست، تاپیک‌های فروم، Passport، setGameScore و getGameHighScores.
  • getUserChatBoosts و getAvailableGifts برای سازگاری هستند و فهرست خالی برمی‌گردانند.
  • setChatSlowModeDelay یک متد اضافه است (در تلگرام نیست).
  • وب‌هوک: آدرس باید عمومی باشد (آدرس‌های محلی پذیرفته نمی‌شوند).

عیب‌یابی

خطاهای رایج و راه رفعشان.

پیامعلت و راه حل
401 Unauthorizedتوکن اشتباه است یا باطل شده. از /token دوباره بگیرید و مطمئن شوید بین توکن و bot در آدرس فاصله یا نویسهٔ اضافه نیست.
400 chat not foundاین کاربر هنوز ربات را Start نکرده، یا chat_id اشتباه است. شناسه را از آپدیت بردارید، نه از حدس.
409 Conflict … webhook is activeوب‌هوک فعال است؛ یا deleteWebhook بزنید یا از وب‌هوک استفاده کنید. چند نمونه از یک ربات هم‌زمان با getUpdates کار نکنند.
400 message is too longمتن بیشتر از ۴۰۹۶ نویسه است؛ تکه‌تکه بفرستید.
400 message text is emptytext خالی یا فرستاده نشده است.
400 bad webhook: the URL must point to a public addressآدرس وب‌هوک محلی یا داخلی است؛ یک آدرس عمومی (ترجیحاً https) بدهید.
400 query is too old…دیر به callback یا inline query جواب داده‌اید (callback: ۶ ثانیه). جواب را اول بدهید.
400 invalid file_idشناسهٔ فایل نامعتبر است. از همان ربات و از آپدیت یا پاسخ قبلی بگیرید.
404 method not foundنام متد غلط است یا متد در 7eve9 نیست (مرجع).
429 Too Many Requestsسرعت درخواست‌ها زیاد است؛ کمی صبر کنید. به‌جای درخواست‌های پشت‌سرهم از getUpdates با timeout استفاده کنید.
مینی‌اپ در وب باز نمی‌شودسرور شما جلوی iframe را می‌گیرد؛ بخش ۴ مینی‌اپ.

سؤال یا مشکلی بود؟ داخل برنامه چت «پشتیبانی 7eve9Chat» را باز کنید و بنویسید.

دربارهٔ تیم 7eve9

ما تیمی از توسعه‌دهندگان ایرانی هستیم که تصمیم گرفتیم یک پیام‌رسان مستقل را از پایه بسازیم؛ پیام‌رسانی که سرورهایش داخل ایران است و با سرعت و روان کار می‌کند، و همهٔ کارهایی که روزانه از اینترنت و موبایلتان می‌خواهید را در همان یک جا برایتان فراهم کند.

گفتگو و تماس، گروه و کانال، ربات و مینی‌اپ، نقشهٔ ایران و جستجو، مترجم آفلاین، ویکی‌پدیا، حتی بازی با دوستان؛ همه روی همین بستر و روی زیرساخت خودمان اجرا می‌شود. این مستندات هم برای این است که شما هم بتوانید خدمات خودتان را روی همین بستر بسازید.

زیرساخت مستقلسرورها، نقشه، موتور جستجو و مترجم همه روی سرورهای خودمان.
همه‌چیز در یک بستراز پیام‌رسانی تا خدمات روزمره، بدون نصب برنامهٔ جداگانه.
باز برای توسعه‌دهندگانBot API سازگار با تلگرام و مینی‌اپ برای ساخت خدمات تازه.

برای ارتباط با ما، داخل برنامه چت «پشتیبانی 7eve9Chat» را باز کنید.