API
TelegramOS HTTP API:使用 API 密钥进行身份验证,并以编程方式驱动账号、收件箱、机器人、分析和工作流。
仪表盘能做的一切,都是通过这套 HTTP API 完成的。下面的每一个路径、请求体和状态码,在本页发布之前都已在真实工作区中实际验证过。
基础 URL
https://telegramos.net请求和响应均为 JSON(Content-Type: application/json)。导出接口返回文件(.xlsx / .csv),媒体下载接口返回字节流。
身份验证
在设置 → API 密钥下创建一个密钥,然后通过 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 安全字符 |
| 默认有效期 | 90 天(expires_days,1–365) |
| 每个工作区的密钥数 | 20 |
| 撤销 | 即时生效,在 设置 → API 密钥 中操作 |
修改密码、重置密码、关闭 2FA 或在所有设备上退出登录,都会永久撤销在那一刻之前签发的所有密钥。
浏览器会话则使用 Cookie。这两条路径从不混用:带 X-API-Key 的请求完全由该密钥完成身份验证,而密钥管理接口(/api-keys)有意拒绝密钥——一个密钥不能签发或撤销另一个密钥(403)。
权限
创建时勾选的权限会在每一个请求上强制执行。
动词 ——必须至少选择一个:
| 权限 | 授予 |
|---|---|
read | GET、HEAD |
write | POST、PUT、PATCH、DELETE |
区域 ——可选。不勾选任何区域的密钥可以访问所有区域;勾选一个或多个区域的密钥则被限制在这些区域内:
| 权限 | 覆盖范围 |
|---|---|
accounts | 账号、代理、预热、抓取、利基查找器、群发私信、线索包 |
inbox | 会话、消息、群组、快捷回复、自动回复规则、通知 |
bots | 机器人、流程、营销活动、频道同步、机器人数据库 |
analytics | 分析和 AI 接口 |
tasks | 工作流和执行记录 |
仅 read 是一个覆盖整个平台的只读密钥。read + write + inbox 只能在收件箱内做任何事——它在 /api/accounts 上会得到 403。
请求 ID
每个响应都带有 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每个请求都会在我们这边连同该 ID、路径、状态、耗时、密钥前缀(绝不记录完整密钥)和工作区一起记录下来:
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>在你这边也记录这个 ID。平台处于 Beta 阶段期间,这是我们定位你那次具体调用最快的方式——在支持工单中引用它,我们就能不靠猜测地调出完整的请求链路。
错误
| 状态码 | 含义 |
|---|---|
400 | 请求格式错误,或路径中的 ID 不是 UUID |
401 | 密钥缺失、未知、已过期或已撤销 |
402 | 你的套餐不包含此功能,或钱包余额不足以支付本次运行 |
403 | 密钥有效,但其权限不覆盖此调用 |
404 | 资源不存在,或属于另一个工作区 |
409 | 账号当前无法执行此操作(受垃圾信息限制、仍在预热中) |
422 | 请求体未通过验证——响应会指出具体字段 |
429 | 请求过多,或账号已用完每小时/每日发送额度 |
503 | 某个依赖服务不可用;请重试 |
错误响应带有 detail:
{"detail": "This API key is scoped to inbox — not 'accounts'."}另一个工作区的对象返回 404,绝不会是 403——API 从不确认某个 ID 是否存在。
约定
- ID 均为 UUID。非 UUID 的路径段会返回
400或404,绝不会是 500。 - 发送是排队的,不是同步的。让账号执行动作的接口会返回
202和一个task_id。随后账号会按照防封禁节奏规则发送(参见限制与配额)。轮询该资源以查看结果。 - 一切都以工作区为范围。你从不需要传工作区 ID;密钥已经携带了它。
- 列表接口根据资源不同接受
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 | 导入会话文件 |
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 | 开始二维码登录 |
POST | /api/accounts/login/qr/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 完成连接,每一行账号记录都会携带该账号自身的 Telegram 身份:tg_user_id(数字形式的 Telegram 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是整个产品中最严格的接口,因为拉人进群是丢失账号最快的方式。除非账号已完成预热、持有不到 36 小时的干净 @SpamBot 判定结果、且不处于仅回复模式,否则它会以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 | 切换社交预热 |
防封禁限制
本 API 中的每一项节流——冷启动外联和回复额度、预热爬坡、PeerFlood 减速、营销活动每日上限、同群间隔以及拟人化延迟——都是平台自身的保护措施,而非 Telegram 的。在付费套餐上,你可以用 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(你发送的数值;未提供的字段保持平台默认值;per_minute、min_gap_seconds、campaign_daily 或 group_spacing_minutes 为 0 表示不限制)或 off(完全没有平台侧节流)。join_*、forward_*、invite_* 和 report_* 各对字段是按动作划分的额度;massdm_* 字段控制群发私信调度器(massdm_daily 提高单个任务可申请的每账号上限,massdm_circuit 决定当任务的账号返回泛洪或被封锁状态时任务是否中止;只要任务中任一账号保持开启,该任务就仍受保护)。当前配置以 safety 字段随账号对象返回,并在下一次发送时生效——无需重新连接。无论你如何设置,Telegram 自身的 FloodWait 和垃圾信息限制仍然适用,放宽限制后账号的封禁风险由你自行承担。免费套餐会返回 402。“一人一账号”规则独立于此配置,在 off 模式下依然生效;可通过 /api/accounts/{id}/contact-policy 按账号切换。
抓取
| 方法 | 路径 | 作用 |
|---|---|---|
POST GET | /api/scraping/jobs | 启动 / 列出任务 |
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 | 本周期已用配额 |
抓取是一次性的提取,而不是持续监控:一个账号遍历目标的消息历史一次,从中提取电话号码(或你给定的模式)。广播频道可以作为目标,但其帖子来自频道本身,所以对频道的抓取很少能得到号码。若要跟踪频道发布的内容,请改用监控频道。免费试用按结果计数,而不是按扫描的消息数计数,因此一次一无所获的运行不花费任何额度。
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 模式接受你自己的正则表达式。 group_links 同时接受公开群组和公开频道。
付费深度运行按扫描的消息数计费,如果钱包余额无法覆盖最坏情况,则返回 402。免费试用的计数方式不同:它是 50 条 结果,因此一次一无所获的运行不花费任何额度。它在另一侧也有边界—— 免费运行在总共读取 2,000 条消息后停止,无论返回了什么。 GET /api/scraping/usage 会报告两个计数器(used / limit 和 scanned / scan_limit)。
利基查找器
| 方法 | 路径 | 作用 |
|---|---|---|
POST | /api/niche/suggest | 关键词建议 |
POST GET | /api/niche/jobs | 启动 / 列出任务 |
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 会导出原始成员列表;它默认关闭,因为这是有封禁风险的读取操作。
线索包与监视任务
| 方法 | 路径 | 作用 |
|---|---|---|
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 | 列出 / 创建监视任务 |
GET | /api/watches/{id} | 单个监视任务 |
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 二者之一,不能同时提供。禁止联系名单接受一个列表:
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 | 拉取占位符对应的媒体 |
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 并指出缺失的内容。
监控频道
广播频道和其他会话一样——peer_type 是 channel ——但它的帖子是选择加入的。一个活跃的频道每天可能通过账号的代理推送数百兆字节的数据,因此监听器会丢弃所有你未主动请求的频道的帖子。这就是为什么你加入的频道在添加之前不显示任何内容:不是缺少支持,而是被关闭了。
开启一个频道:
- 用你的一个账号(在 Telegram 客户端中)加入该频道。
- 把它加入监控列表:
POST /api/groups,请求体为{"identifier": "@thechannel", "type": "channel", "via_account_id": "<uuid>"}。 - 读取帖子:
GET /api/conversations?peer_type=channel,然后GET /api/conversations/{id}/messages?after_msg_id=<last seen>。
identifier 接受公开的 @username、t.me/name 链接或数字形式的 peer id。type 可以是 group、supergroup 或 channel;无论你传什么,都会在首次同步时根据 Telegram 的数据校正,连同 members_count、 posts_per_day 和带标记的 peer id 一起更新。
私有频道没有 @username,而邀请链接(t.me/+…)不携带 peer id,所以两者都无法识别它。同步一次该账号的聊天列表,频道就会带着数字 ID 出现,然后你按常规方式添加即可:
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>"}在仪表盘中,同样的流程就是 群组 → 跟踪群组 里的频道选择器。
一旦被跟踪,新帖子就会像其他入站消息一样到达:通过 inbox.new_message WebSocket 事件,以及订阅了该事件的 Webhook。你在 Telegram 中已静音的频道仍会同时投递两者,并带有 conversation.muted: true,因此集成永远不会漏掉帖子;只有仪表盘保持静默。
peer_type 有四个值:user、bot、group 和 channel。超级群组属于 group——这一区分只对 /api/groups 有意义,它在首次同步后会报告 supergroup。
一旦频道被监控,其帖子就会像其他消息一样到达:出现在 GET /api/conversations/{id}/messages 中、inbox.new_message WebSocket 事件中,以及订阅了 inbox.new_message 的 Webhook 中。
有两样东西*不是*这个功能:/api/channel-syncs 把一个频道的帖子镜像到你控制的另一个频道中(它是转发器,不是读取器),而 /api/warmup/channels 是新账号在预热期间加入的频道列表。两者都不返回频道内容。POST /api/groups/{id}/sync 只刷新成员数和帖子数——它不会拉取帖子。
跟踪线程
只有消息监听器已开启的账号才会记录入站消息。在 GET /api/accounts 中 power_sender_only: true 的账号只发不收,因此无论你轮询多少次,它的线程都保持为空——请先为它开启监听器。
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=200telegram_msg_id 在同一聊天内单调递增,因此该游标永远不会重复一条消息,也永远不会跳过一条。保存你见过的最大 ID,用它轮询,就没有任何需要去重的东西。如果同时传了 after_msg_id 和 before/before_msg_id,前者优先。
每条消息都带有 direction:in 表示账号收到的消息,out 表示通过本平台发送的消息。在同一账号的 Telegram 客户端中手动输入的消息不会被记录——Telegram 将它们作为你自己的出站更新投递,监听器会忽略它们。
若要推送而非轮询,请参见下方的 Webhook 和实时事件。
发送
在现有线程中回复:
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。两个接口都返回 202:
{"task_id": "...", "conversation_id": null, "queued": true,
"note": "Message queued. It will appear in the inbox once Telegram acknowledges the send."}一旦 Telegram 确认发送,消息就会出现在 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。每小时窗口是连续滚动的,所以应当退避等待,而不是改写消息。健康分数下降的账号会得到按比例缩减的额度。付费套餐可以按账号修改或移除这些额度——参见防封禁限制;自定义配置会在可能的429代码中增加[MINUTE_MESSAGE_LIMIT]和[MESSAGE_GAP_LIMIT]。
只有 202 才表示发送已在路上。如果之后仍然失败——收件人屏蔽了该账号、账号掉线——原因会以带有相同 task_id 的 inbox.message_failed Webhook 送达。
群组、快捷回复、规则、通知
| 方法 | 路径 | 作用 |
|---|---|---|
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 | 角标计数 |
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-mode | 轮询或 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 | 试运行 |
GET | /api/bots/{id}/runs | 流程运行历史 |
GET | /api/bots/{id}/runs/{runId}/steps | 每一步的详情 |
营销活动
| 方法 | 路径 | 作用 |
|---|---|---|
GET POST | /api/campaigns | 列出 / 创建(创建后处于草稿状态) |
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 | 发送数、失败数、触达数 |
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 | 启用 |
POST | /api/channel-syncs/{id}/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/report | 完整报告数据 |
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 额度 |
工作区的分析开关关闭时,这些接口返回空序列而不是错误。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 | 角标计数 |
身份
| 方法 | 路径 | 作用 |
|---|---|---|
GET | /auth/me | 此密钥属于谁,以及所用套餐 |
编辑个人资料(PATCH /auth/me)与密钥管理一样,需要浏览器会话——密钥会得到 403。
Webhook
Webhook 是接收事件的持久化方式:我们先把事件写入数据库,然后 POST 到你的 URL,失败时重试。在你部署期间断开的 Socket 会丢失事件;Webhook 不会。
在设置 → API 密钥 → Webhook下管理它们,或通过 API(区域 inbox):
| 方法 | 路径 | 作用 |
|---|---|---|
GET | /api/webhooks | 列出你的端点 |
POST | /api/webhooks | 注册一个——响应中带有签名用的 secret |
PATCH | /api/webhooks/{id} | 修改 URL、事件列表,或将其关闭 |
DELETE | /api/webhooks/{id} | 移除 |
GET | /api/webhooks/events | 事件目录 |
GET | /api/webhooks/{id}/secret | 读回签名密钥 |
POST | /api/webhooks/{id}/rotate-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 列表为空表示所有类型。每个用户最多十个端点;URL 必须是公网 http(s) 地址(私有地址和回环地址会被拒绝)。
事件
| 类型 | 触发时机 |
|---|---|
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.presence | 账号的 worker 连接到或断开了 Telegram |
notification.new | 平台发出了一条通知 |
webhook.test | 仅由测试按钮/接口触发 |
闭合一次发送的回路。发送只返回 202 和一个 task_id,别无其他——账号仍需让它通过 Telegram 的节奏限制。同时订阅 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 是稳定的,无论消息往哪个方向走:账号的出站消息和对它的回复携带相同的 conversation.id,所以这就是你应当据以订阅的键。peer_id 始终是对方的 Telegram ID,绝不是账号自己的,而 message.direction 说明是谁写的:out 是账号,in 是对方。message.sender_id / message.sender_username 把这一点写得更明确:in 时是对方的 Telegram ID 和用户名,out 时是账号自己的(群组或频道成员为 null,我们不携带其身份)。你自己的两个账号互相对话会产生两个线程(每个账号一个),各有自己的 ID。
验证签名。用你的密钥对 {timestamp}.{raw body} 做 HMAC-SHA256,与 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)时间戳包含在签名内容之中,因此拒绝任何超过几分钟的投递,被截获的投递就无法在之后对你重放。
投递规则
- 任何
2xx都算作已接受。快速响应,事后再处理——我们在 10 秒后放弃请求并将其视为失败。 - 失败后分别在 10 秒、1 分钟、5 分钟、30 分钟和 2 小时后重试——总共六次尝试——然后该投递被标记为
failed。 - 连续五个事件耗尽所有重试会关闭该端点;仪表盘会显示原因。重新开启会清零计数器。
- 不跟随重定向。请把我们指向最终 URL。
- 投递 ID 在多次重试间保持稳定——以它作为去重的键。
- 已投递的记录保留 7 天,失败的记录保留 30 天。
实时事件
仪表盘通过 Socket.IO 流式接收实时更新:
wss://telegramos.net/ws使用会话 JWT(auth.token)、会话 Cookie 或 API 密钥进行身份验证——在握手中以 auth.apiKey 传入,或作为 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 订阅单个账号。
在此基础上构建之前要了解两件事:
- 浏览器受限。握手会检查
Origin,只允许我们自己的域名。服务端客户端不发送Origin,可以正常连接;你自己域名下的页面会被拒绝。请通过你的后端代理。 - Socket 只投递一次。你断开连接期间发布的任何内容都会丢失。对于不能错过的投递请使用 Webhook,或在重连时用
after_msg_id进行对账。
API 不覆盖的内容
- 团队、计费、钱包和市场仅限会话访问:
/wallet、/payments/*、/subscriptions/*、/billing/*、/bundles/purchase、/account-resale/*、/referrals/*和/teams/*对 API 密钥一律返回401,无论其范围如何。没有任何密钥路径可以花钱、租用账号或更改席位——请在仪表盘中完成这些操作。两个例外是公开目录的读取接口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. 如果需要历史记录,先回填一次。 POST /api/accounts/{id}/backfill-history 会排队一次性导入现有聊天(自有账号,不含媒体,每个聊天最多 1000 条消息;广播频道只有在通过 POST /api/groups 被跟踪后才会包含在内)。轮询 GET /api/accounts/{id}/backfill-history 直到 state 为 done——状态有 queued、running、done、cancelled,而 idle 表示没有记录任何任务(要么从未启动,要么状态在 6 小时后已过期)。每个账号只运行一次;它非常消耗代理流量,而之后的一切都会自行到达。
2. 接入实时流。为 inbox.new_message 注册一个 Webhook。要让消息持续流入收件箱,不需要其他任何东西——账号的 worker 已经在监听了。
3. 对账。你这边发生任何中断之后,用你存储的最后一个 ID 作为 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"