رفتن به محتوای اصلی

API

API HTTP در TelegramOS: با کلید API احراز هویت کنید و اکانت‌ها، اینباکس، بات‌ها، آنالیتیکس و ورک‌فلوها را به‌صورت برنامه‌نویسی‌شده مدیریت کنید.

هر کاری که داشبورد انجام می‌دهد، از طریق همین API HTTP انجام می‌شود. تک‌تک مسیرها، بدنه‌ها و کدهای وضعیتی که در ادامه می‌بینید پیش از انتشار این صفحه روی یک فضای کاری واقعی آزمایش شده‌اند.

آدرس پایه

https://telegramos.net

درخواست‌ها و پاسخ‌ها JSON هستند (Content-Type: application/json). خروجی‌های Export یک فایل برمی‌گردانند (.xlsx / .csv) و دانلود رسانه‌ها بایت خام برمی‌گرداند.

احراز هویت

یک کلید در Settings → API keys بسازید و آن را در هدر X-API-Key بفرستید:

curl -H "X-API-Key: tgp_your_key_here" \
     https://telegramos.net/api/accounts

کلید فقط یک بار، در لحظه‌ی ساخت، نمایش داده می‌شود. به‌صورت هش SHA-256 ذخیره می‌شود، بنابراین هیچ‌کس — حتی خود ما — نمی‌تواند آن را بازیابی کند. اگر گمش کردید، یک کلید جدید بسازید.

ویژگیمقدار
هدرX-API-Key
قالبtgp_ و به‌دنبال آن 54 کاراکتر URL-safe
طول عمر پیش‌فرض90 روز (expires_days، بین 1 تا 365)
تعداد کلید در هر فضای کاری20
ابطالآنی، از Settings → API keys

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

نشست (session) مرورگر به‌جای کلید از کوکی استفاده می‌کند. این دو مسیر هرگز با هم قاطی نمی‌شوند: درخواستی که X-API-Key دارد صرفاً با همان کلید احراز هویت می‌شود، و مدیریت کلیدها (/api-keys) عمداً کلید را نمی‌پذیرد — یک کلید نمی‌تواند کلید دیگری بسازد یا باطل کند (403).

دسترسی‌ها

دسترسی‌هایی که هنگام ساخت کلید تیک می‌زنید روی تک‌تک درخواست‌ها اعمال می‌شوند.

فعل‌ها — همیشه یکی از این‌ها لازم است:

دسترسیچه چیزی می‌دهد
readGET، HEAD
writePOST، PUT، PATCH، DELETE

حوزه‌ها — اختیاری. کلیدی که هیچ حوزه‌ای را تیک نزده باشد به همه‌ی حوزه‌ها می‌رسد؛ کلیدی که یک یا چند حوزه را تیک زده باشد فقط به همان‌ها محدود است:

دسترسیچه چیزی را پوشش می‌دهد
accountsاکانت‌ها، پروکسی‌ها، گرم‌کردن (warm-up)، اسکرپینگ، نیچ‌یاب، پیام انبوه، پکیج‌های لید
inboxگفتگوها، پیام‌ها، گروه‌ها، پاسخ‌های ذخیره‌شده، قوانین پاسخ خودکار، اعلان‌ها
botsبات‌ها، فلوها، کمپین‌ها، همگام‌سازی کانال‌ها، دیتابیس بات
analyticsendpointهای آنالیتیکس و AI
tasksورک‌فلوها و اجراها

read به‌تنهایی یک کلید فقط‌خواندنی روی کل پلتفرم است. read + write + inbox می‌تواند فقط در اینباکس هر کاری بکند — روی /api/accounts پاسخ 403 می‌گیرد.

شناسه‌ی درخواست

هر پاسخ یک X-Request-ID دارد. اگر خودتان بفرستید همان را استفاده می‌کنیم؛ اگر چیزی نفرستید، یکی تولید می‌کنیم:

curl -i -H "X-API-Key: $KEY" -H "X-Request-ID: my-job-42" \
     https://telegramos.net/api/accounts
...
x-request-id: my-job-42

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

api.request service=account-service request_id=my-job-42 method=GET
path=/api/accounts status=200 duration_ms=144 auth=key:tgp_t24zIO user=<workspace>

شناسه را در سمت خودتان هم لاگ کنید. تا وقتی پلتفرم در بتاست، این سریع‌ترین راه برای پیداکردن دقیقاً همان فراخوانی شماست — آن را در تیکت پشتیبانی ذکر کنید تا بتوانیم کل مسیر درخواست را بدون حدس‌زدن بیرون بکشیم.

خطاها

وضعیتمعنی
400درخواست بدشکل، یا شناسه‌ای در مسیر که UUID نیست
401کلید وجود ندارد، ناشناخته است، منقضی یا باطل شده
402پلن شما این قابلیت را شامل نمی‌شود، یا کیف پول هزینه‌ی اجرا را پوشش نمی‌دهد
403کلید معتبر است، اما دسترسی‌هایش این فراخوانی را پوشش نمی‌دهد
404چنین منبعی وجود ندارد، یا متعلق به فضای کاری دیگری است
409اکانت الان نمی‌تواند این کار را بکند (محدودیت اسپم دارد، هنوز در حال گرم‌شدن است)
422بدنه از اعتبارسنجی رد شد — پاسخ نام فیلد را می‌گوید
429درخواست‌های بیش از حد، یا اکانت به بودجه‌ی ارسال ساعتی/روزانه‌اش رسیده
503یکی از وابستگی‌ها از دسترس خارج است؛ دوباره تلاش کنید

خطاها فیلد detail دارند:

{"detail": "This API key is scoped to inbox — not 'accounts'."}

شیء متعلق به فضای کاری دیگر 404 است، هرگز 403 — API هیچ‌وقت وجود یک شناسه را تأیید نمی‌کند.

قراردادها

  • شناسه‌ها UUID هستند. یک بخش مسیر که UUID نباشد 400 یا 404 می‌گیرد، هرگز 500.
  • ارسال صف می‌شود، همزمان نیست. endpointهایی که اکانت را وادار به انجام کاری می‌کنند 202 به همراه یک task_id برمی‌گردانند. سپس اکانت طبق قوانین زمان‌بندی ضدبن ارسال می‌کند (به محدودیت‌ها و سهمیه‌ها نگاه کنید). برای دیدن نتیجه، خود منبع را poll کنید.
  • همه‌چیز در محدوده‌ی فضای کاری است. هیچ‌وقت شناسه‌ی فضای کاری را نمی‌فرستید؛ کلید آن را با خود دارد.
  • endpointهای لیست بسته به منبع، limit/offset یا page/page_size می‌گیرند؛ هر دو اختیاری‌اند.

اکانت‌ها

حوزه: accounts.

متدمسیرکار
GET/api/accountsلیست اکانت‌ها
POST/api/accountsافزودن اکانت
GET/api/accounts/{id}یک اکانت
PATCH/api/accounts/{id}تغییر نام، تغییر تگ، تغییر تنظیمات
DELETE/api/accounts/{id}حذف اکانت
POST/api/accounts/importایمپورت فایل نشست (session)
POST/api/accounts/batch-importایمپورت چندتایی
POST/api/accounts/login/phone/send-codeشروع ورود با شماره تلفن
POST/api/accounts/login/phone/verify-codeارسال کد
POST/api/accounts/login/phone/verify-2faارسال رمز 2FA
POST/api/accounts/login/qr/startشروع ورود با QR
POST/api/accounts/login/qr/pollpoll کردن آن (long-poll، حدود 20 ثانیه)
POST/api/accounts/login/cancelانصراف از ورود
POST/api/accounts/{id}/powerخواباندن یا بیدارکردن اکانت
POST/api/accounts/{id}/safetyشل‌کردن یا خاموش‌کردن محدودیت‌های ضدبن (پلن‌های پولی)
POST/api/accounts/bulk/safetyهمان، برای همه‌ی اکانت‌ها یک‌جا
POST/api/accounts/{id}/profileتنظیم نام، بیو، عکس
POST/api/accounts/{id}/clone-profileکپی پروفایل یک اکانت دیگر
GET/api/accounts/{id}/privacyتنظیمات حریم خصوصی
GET/api/accounts/{id}/photosعکس‌های پروفایل
GET/api/accounts/{id}/statsپیام‌های ارسالی/دریافتی امروز
GET/api/accounts/{id}/health-logتاریخچه‌ی امتیاز سلامت
GET/api/accounts/{id}/riskوضعیت فعلی ریسک بن
GET/api/accounts/{id}/connectionsلاگ ممیزی اتصال‌ها
GET/api/accounts/{id}/sessionsدرخواست‌های ورود — فقط اکانت‌های اجاره‌ای
GET/api/accounts/{id}/vaultوضعیت گاوصندوق نشست
GET POST/api/accounts/{id}/backfill-historyخواندن / شروع واکشی چت‌های قدیمی (?discover_only=true = فقط لیست چت‌ها)
POST/api/accounts/{id}/backfill-history/cancelتوقف یک واکشی در حال اجرا
POST/api/accounts/{id}/reset-statusبرگرداندن اکانت error یا paused به active
GET/api/accounts/{id}/avatarعکس پروفایل، به‌صورت بایت
DELETE/api/accounts/{id}/photos/{photoId}حذف یک عکس پروفایل
POST/api/accounts/{id}/username-checkآیا یک نام کاربری آزاد است، پیش از آنکه بگیریدش
POST/api/accounts/{id}/contact-policyقانون «هر نفر، یک اکانت» — {"single_contact": false} اجازه می‌دهد این اکانت به کسی پیام بدهد که یکی دیگر از اکانت‌های شما از قبل با او صحبت می‌کند
POST/api/accounts/{id}/group-invitesافزودن افراد به گروه — یادداشت پایین را ببینید
POST/api/accounts/{id}/skip-warmupعقب‌بردن ساعت گرم‌کردن — اکانت‌های خودتان هر زمان، اکانت‌های اجاره‌ای بعد از 3 روز
GET/api/accounts/{id}/session/exportدانلود نشست — فقط اکانت‌های خودتان
POST/api/accounts/{id}/sessions/{hash}/decisionتأیید یا رد یک درخواست ورود
POST/api/accounts/bulkفعال / غیرفعال / حذف چندتایی
POST/api/accounts/bulk/listenerروشن یا خاموش‌کردن شنونده‌ی ورودی در کل ناوگان
POST/api/accounts/bulk/contact-policyهمان قانون روی همه‌ی اکانت‌ها

هر ردیف اکانت، به‌محض اینکه worker متصل شد، هویت تلگرامی خود اکانت را هم دارد: tg_user_id (شناسه‌ی عددی تلگرام)، tg_username، tg_first_name، tg_last_name. tg_user_id همان مقداری است که وقتی رشته‌ی گفتگوی شخص دیگری به این اکانت اشاره می‌کند، به‌عنوان peer_id ظاهر می‌شود.

گاوصندوق نشست زیر همان اکانت قرار دارد: POST /api/accounts/{id}/vault/enable، /disable، /lock، /unlock، /rotate، و GET /api/accounts/{id}/vault برای وضعیت فعلی.

یادداشت /group-invites سخت‌گیرترین endpoint محصول است، چون افزودن افراد سریع‌ترین راه از دست دادن اکانت است. مگر اینکه اکانت گرم‌کردن را تمام کرده باشد، یک رأی پاک از ⁦@SpamBot⁩ با عمر کمتر از 36 ساعت داشته باشد و در حالت فقط‌پاسخ نباشد، با 409 رد می‌کند.
یادداشت /sessions مخصوص اکانت‌های اجاره‌ای است. روی اکانتی که مال خودتان است پاسخ 404 no live allocation for this account on your workspace می‌دهد — این پاسخ درست است، نه یک خطا.

پروکسی‌ها

متدمسیرکار
GET/api/proxiesلیست پروکسی‌ها
POST/api/proxiesافزودن یکی
POST/api/proxies/bulkافزودن چندتایی
PATCH/api/proxies/{id}ویرایش
POST/api/proxies/{id}/rotateچرخش IP خروجی
DELETE/api/proxies/{id}حذف
PATCH DELETE/api/proxies/{id}/assignاتصال / جداکردن یک اکانت
GET/api/proxies/{id}/usageترافیک مصرف‌شده
POST/api/proxies/{id}/checkتست اتصال

گرم‌کردن

متدمسیرکار
GET PUT/api/warmup/settingsخواندن / جایگزینی تنظیمات گرم‌کردن
GET/api/warmup/overviewوضعیت گرم‌کردن ناوگان
GET/api/warmup/planبرنامه‌ی تولیدشده
POST/api/warmup/plan/applyاعمال آن
DELETE/api/warmup/planدورانداختن آن
POST/api/warmup/dry-runپیش‌نمایش بدون اعمال
GET/api/warmup/pairsکدام اکانت‌ها با کدام‌ها صحبت می‌کنند
GET/api/warmup/groupsگروه‌های داخل برنامه
GET/api/warmup/eventsگرم‌کردن واقعاً چه کرد
GET POST/api/warmup/channelsکانال‌هایی که ناوگان عضو می‌شود
DELETE/api/warmup/channels/{id}حذف یکی
GET/api/warmup/accountsوضعیت گرم‌کردن هر اکانت
POST/api/warmup/accounts/{id}/socialروشن/خاموش‌کردن گرم‌کردن اجتماعی

محدودیت‌های ضدبن

تک‌تک throttleهای این API — بودجه‌ی پیام سرد و پاسخ، شیب گرم‌کردن، کندشدن پس از PeerFlood، سقف روزانه‌ی کمپین، فاصله‌گذاری در یک گروه و تأخیرهای انسان‌نما — محافظت خود پلتفرم است، نه تلگرام. در پلن پولی می‌توانید آن را برای هر اکانت با POST /api/accounts/{id}/safety تغییر دهید یا خاموش کنید، یا برای همه‌ی اکانت‌ها یک‌جا با POST /api/accounts/bulk/safety:

{
  "mode": "custom",
  "cold_hourly": 30, "cold_daily": 200,
  "reply_hourly": 120, "reply_daily": 600,
  "per_minute": 6, "min_gap_seconds": 3,
  "campaign_daily": 200, "group_spacing_minutes": 30,
  "content_filter": true, "spam_circuit": true,
  "warmup_ramp": false, "human_delay": true,
  "trial_cap": true, "spambot_throttle": true,
  "join_hourly": 40, "join_daily": 60,
  "forward_hourly": 20, "forward_daily": 200,
  "invite_hourly": 4, "invite_daily": 20,
  "report_hourly": 5, "report_daily": 20,
  "massdm_daily": 30, "massdm_delay_min": 45, "massdm_delay_max": 120,
  "massdm_warmup_ramp": true, "massdm_flood_hold": true, "massdm_circuit": true
}

mode یکی از default (قوانین پلتفرم)، custom (اعدادی که خودتان می‌فرستید؛ هر چه را جا بگذارید مقدار پلتفرمی‌اش را نگه می‌دارد؛ 0 روی per_minute، min_gap_seconds، campaign_daily یا group_spacing_minutes یعنی بدون محدودیت) یا off (هیچ throttle پلتفرمی‌ای اصلاً وجود ندارد) است. جفت‌های join_*، forward_*، invite_* و report_* بودجه‌ی هر نوع اقدام هستند؛ فیلدهای massdm_* رفتار dispatcher پیام انبوه را کنترل می‌کنند (massdm_daily سقف هر اکانت را که یک job می‌تواند درخواست کند بالا می‌برد، massdm_circuit تعیین می‌کند که وقتی اکانت‌های یک job با flood یا بلاک برمی‌گردند، job متوقف شود یا نه؛ تا وقتی حتی یکی از اکانت‌های job آن را روشن نگه داشته باشد، job محافظت‌شده می‌ماند). پروفایل فعلی به‌عنوان safety روی شیء اکانت برمی‌گردد و از ارسال بعدی اثر می‌کند — بدون نیاز به اتصال مجدد. FloodWait و محدودیت‌های اسپم خود تلگرام هر چه هم تنظیم کنید همچنان اعمال می‌شوند، و ریسک بن یک اکانت شل‌شده پای خودتان است. پلن Free پاسخ 402 می‌دهد. قانون «هر نفر، یک اکانت» از این پروفایل جداست و حتی در حالت off روشن می‌ماند؛ آن را برای هر اکانت با /api/accounts/{id}/contact-policy تغییر دهید.

اسکرپینگ

متدمسیرکار
POST GET/api/scraping/jobsشروع / لیست jobها
GET/api/scraping/jobs/{id}وضعیت
POST/api/scraping/jobs/{id}/cancelلغو
GET/api/scraping/jobs/{id}/resultsنتایج به‌صورت JSON
GET/api/scraping/jobs/{id}/exportنتایج به‌صورت .xlsx
GET/api/scraping/jobs/{id}/export.csvنتایج به‌صورت CSV
POST/api/scraping/jobs/{id}/webhookارسال نتایج به URL شما
GET/api/scraping/usageسهمیه‌ی مصرف‌شده در این دوره

اسکرپینگ یک استخراج یک‌باره است، نه یک مانیتور: یک اکانت یک بار تاریخچه‌ی پیام‌های هدف را می‌گردد و شماره‌های تلفن (یا الگوهایی که به آن می‌دهید) را بیرون می‌کشد. کانال‌های broadcast هم به‌عنوان هدف کار می‌کنند، اما پست‌هایشان از طرف خود کانال است، بنابراین اجرای روی کانال به‌ندرت شماره‌ای برمی‌گرداند. برای دنبال‌کردن چیزی که یک کانال منتشر می‌کند، به‌جای آن از مانیتورکردن یک کانال استفاده کنید. دوره‌ی آزمایشی رایگان نتایج را می‌شمارد، نه پیام‌های اسکن‌شده، بنابراین اجرایی که چیزی پیدا نکند هزینه‌ای ندارد.

POST /api/scraping/jobs
{
  "name": "leads",
  "group_links": ["https://t.me/somepublicgroup"],
  "limit_per_group": 300,
  "max_accounts": 5,
  "patterns": [],
  "keyword_filter": []
}

patterns خالی یعنی شماره‌ی تلفن؛ انواع پیش‌فرض دیگر email، username، url و price هستند، و الگوی custom regex خودتان را می‌گیرد. group_links هم گروه‌های عمومی را می‌پذیرد و هم کانال‌های عمومی.

اجرای عمیق پولی به‌ازای هر پیام اسکن‌شده محاسبه می‌شود و اگر کیف پول بدترین حالت را پوشش ندهد 402 برمی‌گرداند. دوره‌ی آزمایشی رایگان طور دیگری شمرده می‌شود: 50 نتیجه است، بنابراین اجرایی که چیزی پیدا نکند هزینه‌ای برای شما ندارد. از آن طرف هم محدود است — اجراهای رایگان بعد از خواندن مجموعاً 2,000 پیام متوقف می‌شوند، هر چه هم برگردانده باشند. GET /api/scraping/usage هر دو شمارنده را گزارش می‌کند (used / limit و scanned / scan_limit).

نیچ‌یاب

متدمسیرکار
POST/api/niche/suggestپیشنهاد کلیدواژه
POST GET/api/niche/jobsشروع / لیست jobها
GET/api/niche/jobs/{id}وضعیت
GET/api/niche/jobs/{id}/sourcesکدام گروه‌ها را خوانده
POST/api/niche/jobs/{id}/cancelلغو
GET/api/niche/jobs/{id}/resultsمخاطبان کشف‌شده
GET/api/niche/jobs/{id}/exportهمان، به‌صورت .xlsx
POST /api/niche/jobs
{
  "name": "crypto traders",
  "keywords": ["trading", "signals"],
  "active_within_days": 30,
  "msg_scan_limit": 3000,
  "max_accounts": 5,
  "extract_members": false
}

extract_members لیست خام اعضا را بیرون می‌ریزد؛ به‌طور پیش‌فرض خاموش است چون همین خواندن است که ریسک بن دارد.

پکیج‌های لید و watchها

متدمسیرکار
GET/api/packagesپکیج‌های در حال فروش
GET/api/packages/{id}یک پکیج
POST/api/packages/{id}/buyخرید آن (از کیف پول کسر می‌شود)
GET/api/packages/{id}/downloadدانلود پکیج خریده‌شده
POST/api/packages/{id}/publishگذاشتن یکی از پکیج‌های خودتان برای فروش
DELETE/api/packages/{id}برداشتن آن از فروش
GET/api/watches/plansپلن‌های اسکرپ دوره‌ای
GET POST/api/watchesلیست / ساخت watch
GET/api/watches/{id}یک watch
POST/api/watches/{id}/pauseتوقف موقت
POST/api/watches/{id}/resumeادامه
DELETE/api/watches/{id}حذف

پیام انبوه

متدمسیرکار
GET/api/mass-dm/accountsاکانت‌های واجد شرایط ارسال
POST GET/api/mass-dm/jobsساخت / لیست کمپین‌ها
GET/api/mass-dm/jobs/{id}پیشرفت
GET/api/mass-dm/jobs/{id}/recipientsوضعیت هر گیرنده
GET/api/mass-dm/jobs/{id}/repliesکی جواب داده
GET/api/mass-dm/jobs/{id}/exportهمه‌چیز، به‌صورت .xlsx
GET POST/api/mass-dm/suppressionلیست «تماس نگیرید»
DELETE/api/mass-dm/suppression/{tgUserId}حذف یک مورد
POST/api/mass-dm/jobs/{id}/pauseتوقف موقت کمپین در حال اجرا
POST/api/mass-dm/jobs/{id}/resumeادامه‌ی کمپین متوقف‌شده
POST/api/mass-dm/jobs/{id}/cancelتوقف دائمی آن
GET/api/mass-dm/contacts/{tgUserId}آنچه از یک مخاطب می‌دانیم
POST /api/mass-dm/jobs
{
  "recipients": [{"tg_user_id": 123456789, "username": "someone"}],
  "message_text": "hi {first_name}",
  "account_ids": ["<account-uuid>"],
  "per_account_daily_cap": 20,
  "followups": []
}

یا recipients را بدهید یا niche_job_id را، نه هر دو. suppression یک لیست می‌گیرد:

POST /api/mass-dm/suppression
{"tg_user_ids": [777000777], "reason": "opted out"}

اینباکس

حوزه: inbox.

متدمسیرکار
GET/api/conversationsلیست گفتگوها
POST/api/conversationsشروع یک چت جدید (202)
GET/api/conversations/searchجست‌وجوی تمام‌متن (?q=)
GET/api/conversations/{id}/messagesپیام‌های یک رشته‌ی گفتگو
POST/api/conversations/{id}/messagesارسال پاسخ (202)
PATCH/api/conversations/{id}واگذاری، تگ، حل‌شده، بی‌صدا
POST/api/conversations/{id}/mark-readخوانده‌شده کردن
DELETE/api/conversations/{id}حذف رشته‌ی گفتگو
POST/api/conversations/mediaآپلود پیوست و گرفتن media_key
GET/api/conversations/{id}/messages/{msgId}/mediaدانلود پیوست
POST/api/conversations/{id}/messages/{msgId}/fetch-mediaواکشی رسانه‌ی یک placeholder
GET POST/api/conversations/{id}/notesیادداشت‌های داخلی
DELETE/api/conversations/{id}/notes/{noteId}حذف یک یادداشت
POST/api/conversations/{id}/blockبلاک‌کردن طرف مقابل
POST/api/conversations/{id}/leaveخروج از گروه
GET/api/conversations/sla-statsآمار زمان پاسخ
GET/api/conversations/account-statsحجم پیام هر اکانت
GET/api/conversations/activity-seriesحجم پیام در طول زمان
GET/api/conversations/reply-statsنرخ پاسخ — به ?source= نیاز دارد

فیلترهای لیست: account_id، peer_type (user / bot / group / channel)، status، tags، unread_only، source (campaign / mass_dm)، campaign_id، job_id، page، page_size.

reply-stats به source=campaign&campaign_id=... یا source=mass_dm&job_id=... نیاز دارد؛ بدون آن‌ها با 422/400 جواب می‌دهد و می‌گوید چه چیزی کم است.

مانیتورکردن یک کانال

کانال broadcast هم گفتگویی مثل بقیه است — peer_type آن channel است — اما پست‌هایش opt-in هستند. یک کانال پرکار می‌تواند روزانه صدها مگابایت از پروکسی یک اکانت رد کند، بنابراین شنونده پست‌های هر کانالی را که خودتان درخواست نکرده‌اید دور می‌ریزد. به همین دلیل کانالی که عضوش شده‌اید تا وقتی آن را اضافه نکنید هیچ چیزی نشان نمی‌دهد: پشتیبانی‌اش کم نیست، خاموش است.

روشن‌کردن یکی:

  1. با یکی از اکانت‌های خودتان (در خود تلگرام) به کانال بپیوندید.
  2. آن را به فهرست پایش اضافه کنید: POST /api/groups با بدنه‌ی {"identifier": "@thechannel", "type": "channel", "via_account_id": "<uuid>"}.
  3. پست‌ها را بخوانید: GET /api/conversations?peer_type=channel و بعد GET /api/conversations/{id}/messages?after_msg_id=<last seen>.

identifier یک @username عمومی، یک لینک t.me/name یا یک شناسه‌ی عددی peer می‌گیرد. type می‌تواند group، supergroup یا channel باشد؛ هر چه بفرستید در اولین همگام‌سازی از روی تلگرام تصحیح می‌شود، همراه با members_count، posts_per_day و شناسه‌ی marked peer.

کانال‌های خصوصی @username ندارند، و لینک دعوت (t.me/+…) هم شناسه‌ی peer ندارد، بنابراین هیچ‌کدام نمی‌تواند یکی را مشخص کند. یک بار لیست چت‌های اکانت را همگام کنید و کانال با شناسه‌ی عددی‌اش ظاهر می‌شود، که بعد آن را به روش معمول اضافه می‌کنید:

POST /api/accounts/{account_id}/backfill-history?discover_only=true
   → registers the account's chats, pulls no messages, costs almost no proxy data

GET /api/conversations?peer_type=channel
   → the private channel is now listed, with its peer_id

POST /api/groups
{"identifier": "-1001234567890", "type": "channel", "via_account_id": "<uuid>"}

در داشبورد همین جریان همان انتخاب‌گر کانال در Groups → Track group است.

وقتی ردیابی شد، پست‌های جدید مثل هر پیام ورودی دیگری می‌رسند: روی رویداد وب‌سوکت inbox.new_message و روی وب‌هوکی که به آن مشترک شده باشد. کانالی که در تلگرام بی‌صدا کرده‌اید همچنان هر دو را می‌فرستد، با conversation.muted: true، بنابراین یک یکپارچه‌سازی هیچ پستی را از دست نمی‌دهد؛ فقط داشبورد ساکت می‌ماند.

peer_type چهار مقدار دارد: user، bot، group و channel. سوپرگروه‌ها group هستند — این تفاوت فقط برای /api/groups مهم است، که بعد از اولین همگام‌سازی‌اش supergroup را گزارش می‌کند.

وقتی کانالی مانیتور می‌شود، پست‌هایش مثل هر پیام دیگری می‌رسند: در GET /api/conversations/{id}/messages، روی رویداد وب‌سوکت inbox.new_message، و از طریق وب‌هوکی که به inbox.new_message مشترک شده است.

دو چیزی که این قابلیت *نیستند*: /api/channel-syncs پست‌های یک کانال را در کانال دیگری که در کنترل شماست آینه می‌کند (یک forwarder است، نه خواننده)، و /api/warmup/channels لیست کانال‌هایی است که اکانت جدید در حین گرم‌شدن عضوشان می‌شود. هیچ‌کدام محتوای کانال را برنمی‌گردانند. POST /api/groups/{id}/sync فقط شمار اعضا و پست‌ها را تازه می‌کند — پست‌ها را واکشی نمی‌کند.

دنبال‌کردن یک رشته‌ی گفتگو

پیام‌های ورودی فقط برای اکانت‌هایی ثبت می‌شوند که شنونده‌ی پیامشان روشن است. اکانتی که در GET /api/accounts مقدار power_sender_only: true دارد می‌فرستد اما هرگز دریافت نمی‌کند، بنابراین هر چقدر هم poll کنید رشته‌هایش خالی می‌مانند — اول شنونده را برایش روشن کنید.

GET /api/conversations/{id}/messages به‌طور پیش‌فرض رو به عقب صفحه‌بندی می‌کند (before، before_msg_id، limit تا 200) — همان چیزی که یک UI وقتی به بالا اسکرول می‌کنید می‌خواهد.

یک مانیتور برعکسش را می‌خواهد. after_msg_id را با telegram_msg_id جدیدترین پیامی که از قبل دارید بفرستید و فقط آنچه از آن زمان رسیده را، از قدیمی‌ترین به جدیدترین، می‌گیرید:

GET /api/conversations/{id}/messages?after_msg_id=19626585&limit=200

telegram_msg_id داخل یک چت به‌صورت یکنوا افزایش می‌یابد، بنابراین این cursor هیچ پیامی را تکرار نمی‌کند و هیچ‌کدام را جا نمی‌اندازد. بالاترین شناسه‌ای که دیده‌اید را نگه دارید، با آن poll کنید، و دیگر چیزی برای حذف تکراری‌ها نمی‌ماند. اگر هر دو را بفرستید، after_msg_id بر before/before_msg_id غلبه می‌کند.

هر پیام یک direction دارد: in برای پیام‌هایی که اکانت دریافت کرده، out برای پیام‌هایی که از طریق این پلتفرم فرستاده شده‌اند. پیام‌هایی که با دست در یک کلاینت تلگرام روی همان اکانت تایپ شده‌اند ثبت نمی‌شوند — تلگرام آن‌ها را به‌عنوان آپدیت‌های خروجی خودتان می‌فرستد و شنونده آن‌ها را نادیده می‌گیرد.

برای push به‌جای polling، به وب‌هوک‌ها و رویدادهای بلادرنگ در ادامه نگاه کنید.

ارسال

پاسخ در یک رشته‌ی گفتگوی موجود:

POST /api/conversations/{id}/messages
{"content": "Thanks — one moment.", "media_key": null}

شروع گفتگو با کسی که هنوز در اینباکس نیست:

POST /api/conversations
{
  "account_id": "<account-uuid>",
  "recipient_type": "username",
  "recipient": "someone",
  "content": "hello"
}

recipient_type یکی از username، phone یا user_id است. هر دو endpoint پاسخ 202 می‌دهند:

{"task_id": "...", "conversation_id": null, "queued": true,
 "note": "Message queued. It will appear in the inbox once Telegram acknowledges the send."}

پیام به‌محض اینکه تلگرام ارسال را تأیید کند در GET /api/conversations/{id}/messages ظاهر می‌شود — معمولاً چند ثانیه، و اگر اکانت به سقف زمان‌بندی ساعتی‌اش رسیده باشد بیشتر.

گاردهای ضدبن پیش از اینکه چیزی صف شود جواب می‌دهند، پس آن‌ها را مدیریت کنید:

  • اکانتی که محدودیت اسپم دارد و می‌خواهد یک چت را از صفر شروع کند: Telegram has limited this account, so it can't start new conversations right now — it can still reply to people who messaged it.
  • اکانت در حال گرم‌شدن نمی‌تواند گفتگو را شروع کند، فقط می‌تواند پاسخ بدهد.
  • فیلتر محتوا متن را با 422 و یک کد داخل براکت رد می‌کند — [REPEATED_CHARS]، [EXCESSIVE_CAPS]، [TOO_MANY_LINKS]، [BLOCKED_LINK]، [SPAM_PATTERN]. متن را درست کنید و دوباره بفرستید؛ تلاش مجدد با همان بدنه همیشه شکست می‌خورد.
  • بودجه‌ی ارسال لغزان با 429 و [HOURLY_MESSAGE_LIMIT] یا [DAILY_MESSAGE_LIMIT] جواب می‌دهد. پیام سرد به 10 پیام در ساعت و 40 در روز برای هر اکانت محدود است. وقتی طرف مقابل جواب داد، هر پیام بعدی در آن رشته به‌عنوان پاسخ شمرده می‌شود و به‌جایش 60 در ساعت و 300 در روز می‌گیرد — چه از طریق POST /api/conversations/{id}/messages بفرستید و چه همچنان POST /api/conversations را با همان گیرنده فراخوانی کنید. پنجره‌ی ساعتی پیوسته می‌لغزد، پس به‌جای بازنویسی پیام عقب بنشینید. اکانتی که امتیاز سلامتش افت کرده بودجه‌ی متناسباً کوچک‌تری می‌گیرد. پلن‌های پولی می‌توانند این بودجه‌ها را برای هر اکانت تغییر دهند یا حذف کنند — به محدودیت‌های ضدبن نگاه کنید؛ پروفایل custom کدهای [MINUTE_MESSAGE_LIMIT] و [MESSAGE_GAP_LIMIT] را هم به کدهای ممکن 429 اضافه می‌کند.

فقط 202 یعنی ارسال در راه است. اگر بعداً باز هم شکست بخورد — گیرنده اکانت را بلاک کرده، اکانت آفلاین شده — دلیلش به‌صورت وب‌هوک inbox.message_failed با همان task_id می‌رسد.

گروه‌ها، پاسخ‌ها، قوانین، اعلان‌ها

متدمسیرکار
GET POST/api/groupsگروه‌ها و کانال‌های ردیابی‌شده
PATCH DELETE/api/groups/{id}ویرایش / حذف از ردیابی
POST/api/groups/{id}/syncتازه‌کردن شمار اعضا و پست‌ها
GET/api/groups/{id}/statsفعالیت
GET POST/api/saved-repliesپاسخ‌های آماده
PUT DELETE/api/saved-replies/{id}ویرایش / حذف
GET POST/api/auto-reply-rulesقوانین پاسخ خودکار
POST/api/auto-reply-rules/bulkساخت چندتایی
PATCH DELETE/api/auto-reply-rules/{id}ویرایش / حذف
GET/api/notificationsفید اعلان‌ها
GET/api/notifications/unread-countشمارنده‌ی badge
PATCH/api/notifications/read-allخوانده‌شده کردن همه
GET PUT/api/notifications/preferencesتنظیمات هر دسته
PATCH/api/notifications/{id}/readخوانده‌شده کردن یکی
DELETE/api/notifications/{id}رد کردن یکی
GET POST/api/api-connectorsکانکتورهای پاسخ خارجی
GET/api/api-connectors/kindsانواع کانکتوری که می‌توانید بسازید
PATCH DELETE/api/api-connectors/{id}ویرایش / حذف
POST/api/api-connectors/{id}/testتست یکی
GET/api/conversations/{id}/avatarعکس چت، به‌صورت بایت
GET/api/conversations/{id}/peer-avatarعکس طرف مقابل
POST /api/groups
{"identifier": "https://t.me/somepublicgroup", "type": "group", "via_account_id": "<uuid>"}

POST /api/saved-replies
{"title": "greeting", "content": "Hi {first_name}", "variables": ["first_name"]}

POST /api/auto-reply-rules
{
  "account_id": "<account-uuid>",
  "match_type": "contains",
  "match_value": "price",
  "reply_text": "Our pricing is on the site.",
  "is_active": true,
  "delay_min": 2,
  "delay_max": 8
}

match_type یکی از any، exact، contains، regex است.

بات‌ها

حوزه: bots.

متدمسیرکار
GET POST/api/botsلیست / ثبت بات‌ها
DELETE/api/bots/{id}حذف
POST/api/bots/{id}/activeفعال / غیرفعال
POST/api/bots/{id}/delivery-modepolling یا webhook
POST/api/bots/{id}/broadcastارسال همگانی به چت‌هایش
GET/api/bots/{id}/chatsچت‌هایی که به آن‌ها دسترسی دارد
GET POST/api/bots/{id}/flowsفلوهای بصری
GET/api/bots/flows/templatesقالب‌های شروع
POST/api/bots/{id}/flows/templates/{templateId}/instantiateساخت فلو از یک قالب
GET PUT DELETE/api/bots/{id}/flows/{flowId}یک فلو
POST/api/bots/{id}/flows/{flowId}/testاجرای آزمایشی (dry-run)
GET/api/bots/{id}/runsتاریخچه‌ی اجرای فلو
GET/api/bots/{id}/runs/{runId}/stepsجزئیات هر مرحله

کمپین‌ها

متدمسیرکار
GET POST/api/campaignsلیست / ساخت (در حالت draft ساخته می‌شود)
GET/api/campaigns/{id}یک کمپین
POST/api/campaigns/{id}/startشروع
POST/api/campaigns/{id}/pauseتوقف موقت
POST/api/campaigns/{id}/stopتوقف
PATCH/api/campaigns/{id}/assignmentsواگذاری مجدد اکانت‌ها و گروه‌ها
POST/api/campaigns/{id}/import-chatlistافزودن انبوه گروه‌های هدف
GET/api/campaigns/{id}/metricsارسال‌ها، شکست‌ها، دسترسی (reach)
DELETE/api/campaigns/{id}حذف
POST /api/campaigns
{
  "name": "launch",
  "message_a": {"text": "..."},
  "message_b": {"link": "https://t.me/channel/123"},
  "interval_minutes": 30,
  "delay_min_seconds": 15,
  "delay_max_seconds": 90,
  "assignments": [{"account_id": "<uuid>", "group_chat_ids": [-1001234567890]}]
}

ساختن، آن را شروع نمی‌کند — /start را فراخوانی کنید.

همگام‌سازی کانال‌ها و دیتابیس بات

متدمسیرکار
GET POST/api/channel-syncsآینه‌های کانال‌به‌کانال — پست‌ها را فوروارد می‌کند، برای شما نمی‌خواند
GET PATCH DELETE/api/channel-syncs/{id}یک آینه
POST/api/channel-syncs/{id}/armمسلح‌کردن (arm)
POST/api/channel-syncs/{id}/disarmخلع سلاح (disarm)
POST/api/channel-syncs/{id}/runیک بار همین حالا اجرا
GET POST/api/botdb/collectionsکالکشن‌ها
GET PUT DELETE/api/botdb/collections/{id}یک کالکشن
GET POST/api/botdb/collections/{id}/recordsرکوردها
POST/api/botdb/collections/{id}/queryفیلتر / مرتب‌سازی / صفحه‌بندی
PUT DELETE/api/botdb/collections/{id}/records/{recordId}یک رکورد
GET POST/api/botdb/collections/{id}/viewsنماهای ذخیره‌شده
POST /api/botdb/collections
{"name": "leads", "schema": {"fields": [{"key": "email", "type": "text"}]}}

POST /api/botdb/collections/{id}/records
{"data": {"email": "a@b.com"}}

تعریف فیلدها از key استفاده می‌کند (نه name)، و رکوردی که در data کلیدی اعلام‌نشده داشته باشد با unknown field(s): ... رد می‌شود.

آنالیتیکس

حوزه: analytics.

متدمسیرکار
GET/api/analytics/summaryمجموع‌های دوره
GET/api/analytics/dailyسری روز‌به‌روز
GET/api/analytics/timelineخط زمانی رویدادها
GET/api/analytics/accounts/{id}/timelineخط زمانی یک اکانت
GET/api/analytics/velocityسرعت ارسال
GET/api/analytics/anomaliesناهنجاری‌های شناسایی‌شده
GET/api/analytics/anomalies/{accountId}ناهنجاری‌های یک اکانت
POST/api/analytics/ai/anomalies/detectاجرای شناسایی همین حالا
GET/api/analytics/ai-insightsبینش‌های روایی روی ناوگان
GET/api/analytics/reportpayload کامل گزارش
GET/api/analytics/ai/summaryخلاصه‌ی روایی AI
GET/api/analytics/ai/daily-digestخلاصه‌ی روزانه (بر حسب ثانیه، نه میلی‌ثانیه)
POST/api/analytics/ai/suggest-repliesپیشنهاد پاسخ
POST/api/analytics/ai/summarize-conversationخلاصه‌کردن یک رشته‌ی گفتگو
POST/api/analytics/ai/sentimentاحساسات یک رشته‌ی گفتگو
POST/api/analytics/ai/send-riskامتیاز ریسک بن برای یک پیش‌نویس
POST/api/analytics/ai/compose-messageپیش‌نویس یک پیام
POST/api/analytics/ai/suggest-postsایده‌های محتوا
POST/api/analytics/ai/template-variationsتولید نسخه‌های متفاوت از یک قالب
GET/api/analytics/ai/quotaاعتبار AI باقی‌مانده

وقتی سوییچ آنالیتیکس فضای کاری خاموش باشد، این‌ها به‌جای خطا سری‌های خالی برمی‌گردانند. endpointهای AI از سهمیه‌ی AI مصرف می‌کنند: اول /api/analytics/ai/quota را چک کنید، و وقتی تمام شد انتظار 429 داشته باشید.

ورک‌فلوها

حوزه: tasks.

متدمسیرکار
GET POST/api/workflowsلیست / ساخت
GET PUT DELETE/api/workflows/{id}یک ورک‌فلو
POST/api/workflows/{id}/runاجرای همین حالا
GET/api/workflows/{id}/statsتعداد اجراها و نرخ موفقیت
POST DELETE/api/workflows/{id}/scheduleاتصال / حذف زمان‌بندی cron
GET/api/executionsتاریخچه‌ی اجراها
POST/api/executionsشروع یک اجرا
GET/api/executions/{id}یک اجرا
GET/api/executions/{id}/stepsوضعیت هر گره
DELETE/api/executions/{id}لغو یک اجرای در حال انجام
POST /api/workflows
{"name": "nightly", "definition": {"nodes": [], "edges": []}}

پشتیبانی

بدون حوزه — هر کلیدی به این‌ها می‌رسد.

متدمسیرکار
GET POST/api/support/ticketsلیست / ثبت تیکت
GET/api/support/tickets/{id}یک تیکت با رشته‌ی گفتگویش
POST/api/support/tickets/{id}/messagesپاسخ
POST/api/support/tickets/{id}/closeبستن آن
POST/api/support/tickets/{id}/seenخوانده‌شده کردن رشته
GET/api/support/unread-countشمارنده‌ی badge

هویت

متدمسیرکار
GET/auth/meاین کلید متعلق به کیست، و پلن او

ویرایش پروفایل (PATCH /auth/me)، مثل مدیریت کلیدها، به نشست مرورگر نیاز دارد — کلید پاسخ 403 می‌گیرد.

وب‌هوک‌ها

وب‌هوک راه پایدار دریافت رویدادهاست: ما اول رویداد را در دیتابیس خودمان می‌نویسیم، بعد آن را به URL شما POST می‌کنیم و در صورت شکست دوباره تلاش می‌کنیم. سوکتی که در حین دیپلوی شما قطع شده رویداد را از دست می‌دهد؛ وب‌هوک نه.

شکل 8. یک تحویل وب‌هوک: هدرها، امضا، نردبان تلاش مجدد و حذف تکرار.

آن‌ها را در Settings → API keys → Webhooks مدیریت کنید، یا از طریق API (حوزه‌ی inbox):

متدمسیرکار
GET/api/webhooksلیست endpointهای شما
POST/api/webhooksثبت یکی — پاسخ secret امضا را با خود دارد
PATCH/api/webhooks/{id}تغییر URL، لیست رویدادها، یا خاموش‌کردن
DELETE/api/webhooks/{id}حذف آن
GET/api/webhooks/eventsکاتالوگ رویدادها
GET/api/webhooks/{id}/secretخواندن دوباره‌ی secret امضا
POST/api/webhooks/{id}/rotate-secretصدور secret جدید
POST/api/webhooks/{id}/testصف‌کردن یک تحویل webhook.test (202)
GET/api/webhooks/{id}/deliveriesآخرین تحویل‌ها، با وضعیت و خطا
POST /api/webhooks
{"url": "https://your-server.example/telegramos",
 "events": ["inbox.new_message"],
 "description": "prod monitor"}

لیست events خالی یعنی همه‌ی انواع. حداکثر ده endpoint برای هر کاربر؛ URL باید یک آدرس عمومی http(s) باشد (آدرس‌های خصوصی و loopback رد می‌شوند).

رویدادها

نوعزمان اجرا
inbox.new_messageپیامی به یک گفتگو رسید، یا از آن فرستاده شد
inbox.message_failedیک ارسال صف‌شده انجام نشد — error_code، یک message قابل‌خواندن برای انسان، task_id و recipient را با خود دارد
inbox.readیک گفتگو خوانده‌شده شد
account.status_changeوضعیت یک اکانت تغییر کرد (active، paused، error، banned)
account.health_updateامتیاز سلامت یک اکانت تغییر کرد
account.trust_changedسطح اعتماد یک اکانت تغییر کرد
account.power_changedیک اکانت خوابانده یا بیدار شد
account.presenceworker یک اکانت به تلگرام متصل شد یا از آن جدا شد
notification.newیک اعلان پلتفرم صادر شد
webhook.testفقط از دکمه⁦/endpoint⁩ تست

بستن حلقه‌ی یک ارسال. یک ارسال با 202 و یک task_id جواب می‌دهد و دیگر هیچ — اکانت هنوز باید آن را از زمان‌بندی تلگرام رد کند. به هر دو رویداد inbox.new_message و inbox.message_failed مشترک شوید و می‌فهمید کدام اتفاق افتاده: موفقیت به‌صورت پیامی با direction: "out" می‌رسد، شکست به‌صورت inbox.message_failed با همان task_id، یک error_code (blocked_by_user، privacy_restricted، account_offline، cannot_write، account_banned، …) و یک جمله که می‌توانید به کاربر نشان دهید.

درخواستی که ما می‌فرستیم

POST /your-path
Content-Type: application/json
X-TGP-Event: inbox.new_message
X-TGP-Delivery: 82a91c75-7446-4ebe-8f79-3013cceaa1d7
X-TGP-Timestamp: 1787308800
X-TGP-Signature: v1=<hex>

{"id": "<delivery id>", "type": "inbox.new_message",
 "created_at": "2026-08-20T10:27:04+00:00",
 "data": {"user_id": "...", "account_id": "...", "conversation_id": "...",
          "message": {"id": "...", "direction": "in", "sender_id": 123, "sender_username": "...",
                      "content": "...", "sent_at": "..."},
          "conversation": {"id": "...", "title": "...", "peer_id": 123,
                           "peer_username": "...", "peer_type": "channel", "muted": false}}}

conversation.id برای رشته‌ی گفتگوی یک اکانت با یک peer ثابت است، پیام از هر طرفی که برود: پیام خروجی یک اکانت و پاسخ به آن همان conversation.id را دارند، پس همین کلیدی است که باید روی آن مشترک شوید. peer_id همیشه شناسه‌ی تلگرام طرف مقابل است، هرگز شناسه‌ی خود اکانت نیست، و message.direction می‌گوید کی آن را نوشته: out اکانت است، in طرف مقابل. message.sender_id / message.sender_username آن را صریح می‌کنند: در in شناسه و نام کاربری تلگرام طرف مقابل، در out شناسه و نام کاربری خود اکانت (null برای عضو گروه یا کانال، که هویتش را حمل نمی‌کنیم). دو اکانت خودتان که با هم صحبت می‌کنند دو رشته‌ی گفتگو تولید می‌کنند (یکی برای هر اکانت)، هر کدام با شناسه‌ی خودش.

تأیید امضا. HMAC-SHA256 روی {timestamp}.{raw body} با secret شما، که با مقدار hex بعد از v1= مقایسه می‌شود. از بایت‌های خام استفاده کنید — سریال‌سازی دوباره‌ی JSON آن‌ها را تغییر می‌دهد.

import hmac, hashlib

def verify(secret: str, headers, raw_body: bytes) -> bool:
    ts = headers["X-TGP-Timestamp"]
    expected = "v1=" + hmac.new(
        secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(headers["X-TGP-Signature"], expected)

timestamp داخل محتوای امضاشده است، بنابراین هر چیزی را که بیش از چند دقیقه قدمت دارد رد کنید تا یک تحویل ضبط‌شده بعداً نتواند دوباره روی شما replay شود.

قواعد تحویل

  • هر 2xx به‌معنای پذیرش است. سریع جواب بدهید و کار را بعدش انجام دهید — ما بعد از 10 ثانیه از یک درخواست دست می‌کشیم و آن را شکست حساب می‌کنیم.
  • شکست‌ها بعد از 10 ثانیه، 1 دقیقه، 5 دقیقه، 30 دقیقه و 2 ساعت دوباره تلاش می‌شوند — در مجموع شش تلاش — و بعد تحویل failed علامت می‌خورد.
  • پنج رویداد پشت‌سرهم که همه‌ی تلاش‌های مجدد را تمام کنند endpoint را خاموش می‌کنند؛ داشبورد دلیلش را نشان می‌دهد. روشن‌کردن دوباره شمارنده را صفر می‌کند.
  • ریدایرکت‌ها دنبال نمی‌شوند. ما را به URL نهایی هدایت کنید.
  • شناسه‌ی تحویل در تلاش‌های مجدد ثابت می‌ماند — حذف تکراری‌ها را روی آن کلید کنید.
  • رکوردهای تحویل‌شده 7 روز نگه داشته می‌شوند، شکست‌خورده‌ها 30 روز.

رویدادهای بلادرنگ

داشبورد آپدیت‌های زنده را از طریق Socket.IO استریم می‌کند:

wss://telegramos.net/ws

با JWT نشست (auth.token)، کوکی نشست، یا یک کلید API احراز هویت کنید — آن را به‌صورت auth.apiKey در handshake یا به‌صورت هدر X-API-Key بفرستید. کلید به read نیاز دارد، و اگر اصلاً محدود به حوزه است باید inbox را شامل شود.

import { io } from 'socket.io-client'

const socket = io('https://telegramos.net', {
  path: '/ws',
  transports: ['websocket'],
  auth: { apiKey: process.env.TGP_API_KEY },
})
socket.on('inbox.new_message', (e) => console.log(e.conversation_id, e.message.content))

رویدادها به‌صورت پیام‌های نام‌دار Socket.IO می‌رسند: system.connected هنگام اتصال، بعد inbox.new_message، notification.new، account.status_change، account.power_changed و امثال آن؛ برای اشتراک روی یک اکانت از subscribe:account استفاده کنید.

دو چیز که پیش از ساختن روی آن باید بدانید:

  • مرورگرها محدود هستند. handshake هدر Origin را چک می‌کند و فقط دامنه‌های خود ما مجازند. کلاینت سمت سرور Origin نمی‌فرستد و بی‌مشکل متصل می‌شود؛ صفحه‌ای روی دامنه‌ی خودتان رد می‌شود. از طریق بک‌اند خودتان پروکسی کنید.
  • سوکت فقط یک بار تحویل می‌دهد. هر چیزی که در زمان قطع‌بودن شما منتشر شده باشد از دست رفته است. برای تحویلی که نمی‌توانید از دستش بدهید از وب‌هوک استفاده کنید، یا هنگام اتصال مجدد با after_msg_id وضعیت را همگام کنید.

چه چیزهایی را API پوشش نمی‌دهد

  • تیم‌ها، صورت‌حساب، کیف پول و مارکت‌پلیس فقط با نشست کار می‌کنند: /wallet، /payments/*، /subscriptions/*، /billing/*، /bundles/purchase، /account-resale/*، /referrals/* و /teams/* به کلید API، با هر محدوده‌ای که داشته باشد، 401 می‌دهند. هیچ مسیر مبتنی بر کلیدی برای خرج‌کردن پول، اجاره‌ی اکانت یا تغییر seatها وجود ندارد — این‌ها را در داشبورد انجام دهید. دو استثنا خواندن‌های کاتالوگ عمومی GET /listings و GET /bundles/availability هستند که اصلاً به احراز هویت نیاز ندارند.
  • SDK ندارد. HTTP ساده؛ از هر کلاینتی که دارید استفاده کنید.
  • محدودیت نرخ به‌ازای کلید ندارد. درخواست‌ها ارزان‌اند، اما اقدامات پشت آن‌ها به‌ازای هر اکانت با محدودیت‌های ضدبن در محدودیت‌ها و سهمیه‌ها زمان‌بندی می‌شوند، بنابراین یک رگبار ارسال صف می‌شود، نه اینکه یک‌جا شلیک شود.

یک مثال عملی

پاسخ به جدیدترین گفتگوی خوانده‌نشده و انتظار برای رسیدن ارسال:

KEY="tgp_your_key_here"
BASE="https://telegramos.net"

CONV=$(curl -s -H "X-API-Key: $KEY" \
  "$BASE/api/conversations?unread_only=true&page_size=1" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['id'])")

curl -s -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
     -H "X-Request-ID: reply-$CONV" \
     -d '{"content":"Thanks for reaching out — one moment."}' \
     "$BASE/api/conversations/$CONV/messages"
# -> 202 {"task_id": "...", "queued": true, ...}

curl -s -H "X-API-Key: $KEY" "$BASE/api/conversations/$CONV/messages" | tail -c 400

مانیتورکردن یک گفتگو

سه جزء متحرک، به ترتیبی که راهشان می‌اندازید.

1. اگر تاریخچه را می‌خواهید، یک بار backfill کنید. POST /api/accounts/{id}/backfill-history یک ایمپورت یک‌باره از چت‌های موجود را صف می‌کند (اکانت‌های خودتان، بدون رسانه، تا 1000 پیام در هر چت؛ کانال‌های broadcast فقط وقتی شامل می‌شوند که از طریق POST /api/groups ردیابی شده باشند). GET /api/accounts/{id}/backfill-history را poll کنید تا state به done برسد — وضعیت‌ها queued، running، done، cancelled هستند، و idle یعنی هیچ job‌ای ثبت نشده (یا هرگز شروع نشده یا وضعیتش بعد از 6 ساعت منقضی شده). برای هر اکانت یک بار اجرایش کنید؛ روی داده‌ی پروکسی سنگین است و هر چه بعد از آن باشد خودش می‌رسد.

2. استریم زنده را بگیرید. یک وب‌هوک برای inbox.new_message ثبت کنید. برای اینکه پیام‌ها همچنان به اینباکس بریزند چیز دیگری لازم نیست — worker اکانت از قبل در حال شنیدن است.

3. همگام کنید. بعد از هر قطعی در سمت شما، هر گفتگو را با after_msg_id از آخرین شناسه‌ای که ذخیره کرده‌اید رو به جلو بگردید. این کار شکاف را بدون بازخوانی کل رشته می‌بندد.

KEY="tgp_your_key_here"
BASE="https://telegramos.net"

curl -s -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
     -d '{"url":"https://your-server.example/telegramos","events":["inbox.new_message"]}' \
     "$BASE/api/webhooks"
# -> 201 {"id": "...", "secret": "whsec_...", ...}   <- store the secret

curl -s -H "X-API-Key: $KEY" \
     "$BASE/api/conversations/$CONV/messages?after_msg_id=$LAST_SEEN&limit=200"
گزارش مشکل در این صفحه
⁨API⁩ | مستندات TelegramOS