Bot API docs

Bot API Reference

From bot review and authentication to webhooks, long polling, sendMessage, rich messages, and the official SDKs.

API overview

Base URL
https://www.sochatlive.com
Auth
Authorization: Bearer sbot_<token>
API version
v1
Last updated
2026-05

Positioning and scope

SoChat Open Platform provides bot identity, message routing, delivery guarantees, and security boundaries. Your bot logic runs in your own service. The platform reliably delivers events to your code and routes responses back to conversations.

Access after review

Any signed-in user can submit a bot application. A Bot Token is issued only after the platform review to prevent abuse and impersonation.

Self-hosted logic

Your bot logic runs in your own service. SoChat does not host business code and does not require a specific infrastructure.

Isolated authentication

All Bot APIs are called with a Bot Token and are fully isolated from end-user identities, which makes automation integrations straightforward.

Reliable async delivery

Updates are delivered via an async queue with at-least-once guarantees. Failed deliveries are retried, and you can re-deliver from the delivery log.

Platform scope

  • Send and receive messages — 15+ message types: text, photo, document, video, audio, voice, video note, animation, sticker, dice, poll, contact, location, venue, media groups, and more.
  • Edit, delete, forward — Supports editMessage, editMessageReplyMarkup, deleteMessage, forwardMessage, copyMessage, and the related delivery events.
  • Rich interactions — InlineKeyboard callbacks (callback_query / answerCallbackQuery), Inline Mode (inline_query / answerInlineQuery), and command menus.
  • Group read and moderation — getChat*, setChat*, pin/unpin, kick/ban/unban, sendChatAction, and manual friend request review.
  • Event subscriptions — message, edited_message, message_deleted, message_read, message_delivered, callback_query, inline_query, friend_request, my_chat_member / chat_member / chat_join_request.
  • Two delivery modes — Webhook (push) or getUpdates long polling. They are mutually exclusive and are switched by setWebhook / deleteWebhook.
  • Token governance — Tokens are issued after review. The plaintext token is shown only once. Rotation, revocation, and token_prefix auditing are supported.
  • Rate limits — Global defaults plus per-bot quotas. When exceeded, you get 429 with Retry-After and X-BotRateLimit-Remaining.
  • Observability and troubleshooting — Query delivery logs by status, re-deliver dead letters, and review recent delivery and call metrics.
  • Official SDKs — Node.js/TypeScript and Java SDKs with signature verification, de-duplication, routing, polling, and media uploads.

Quick start

Follow these four steps to go from application to your first inbound update.

Step 01

Submit an application

Sign in to the Developer Console, or create a bot from “My bots” in the SoChat App. Both paths go through the same review queue.

  • Any signed-in user can apply
  • You provide name, username, description, and avatar
  • After submission, the status becomes pending for review
Step 02

Wait for review

After approval, the platform issues a Bot Token. The plaintext token is shown only once in your Developer Console.

  • Approved → sbot_ token is issued
  • Plaintext is only returned once; the server stores only a hash
  • You can rotate or revoke tokens any time in the console
Step 03

Configure webhook (or polling)

Retrieve your one-time token from the console. Webhook with HTTPS is recommended; if you cannot expose a public endpoint, use getUpdates long polling.

  • Webhook: URL must be https://; secret_token is used for HMAC-SHA256 verification
  • Polling: call deleteWebhook, then poll updates via getUpdates
  • The two modes are mutually exclusive; the platform manages delivery_mode
Step 04

Start sending and receiving

Add the bot to a chat. Send a message/command or @mention to trigger an inbound update. Reply via sendMessage/sendPhoto and you can edit or delete your own messages.

  • In groups, Privacy Mode is on by default; disable via setMyGroupPrivacy or the console; admins bypass; DMs deliver all messages
  • Message types include text, photo, document, video, voice, sticker, dice, polls, contacts, venues, media groups, etc.
  • Rich interactions: InlineKeyboard callbacks, Inline Mode, command menus
  • editMessage / deleteMessage only apply to messages sent by this bot

Onboarding flow

1

Submit the application

Use the Developer Console or the SoChat App to submit a bot name, username, description, and the intended use case. The status becomes pending.

2

Platform review

The platform reviews your identity and use case, and returns the result via review_status with an optional rejection reason.

3

Retrieve token and configure delivery

After approval, the first console visit shows the plaintext token (once). You can then register a webhook, set allowed_updates, and configure IP allowlists.

4

Join a chat and validate

Add the bot to a DM or group, send a test message, observe inbound updates, and reply via sendMessage to complete the minimum loop.

Minimum checklist

Bot Token

Auth

Prefix `sbot_`. The plaintext token is returned only once after approval; the server stores only a hash. You can rotate or revoke it any time.

Two delivery modes

Inbound

Configure HTTPS webhook via `setWebhook` for push delivery, or call `deleteWebhook` to switch to `polling` and pull updates via `getUpdates`. The modes are mutually exclusive and tracked by `Bot.delivery_mode`.

Messaging APIs

Outbound

Text plus photos/documents/videos/audios/voices/video notes/animations/stickers/dice/polls/contacts/locations/venues/media groups. After sending you can `editMessage` / `deleteMessage` / `editMessageReplyMarkup`.

Rich interactions

UX

InlineKeyboard `callback_data` triggers `callback_query` and should be answered within 5s via `answerCallbackQuery`. Inline Mode is handled via `answerInlineQuery`.

Group administration

Admin

Use `getChat*` to read group information; `setChatTitle / Description / Photo`, pin APIs, and `kickChatMember` / `banChatMember` require the bot to be the owner or admin.

Privacy Mode

Visibility

Groups deliver slash commands, @mentions, replies, and mentions by default. Disable via `setMyGroupPrivacy` or the developer console to receive all messages. Bots that are group owners/admins always receive everything. DMs are fully delivered.

Rate limits

Stability

Global defaults plus per-bot quotas. When exceeded, you get 429 with `Retry-After` and `X-BotRateLimit-Remaining`.

API conventions

All Bot APIs share the same contract for base URLs, authentication, request and response envelopes, timestamps, error structures, rate-limit headers, and naming. Each endpoint later in the page only documents its own unique parameters and fields.

Base URL

HTTPS only

Production traffic must go through HTTPS, and every endpoint lives under /api/v1/bots/**.

  • ·In production, use the Base URL shown at the top of this page
  • ·All requests and callbacks must use HTTPS

Authentication

Bearer token

Bot business APIs use the bot token, while developer management APIs use an account JWT. The two token types stay fully isolated.

  • ·Bot traffic: Authorization: Bearer sbot_<token>
  • ·Developer console: Authorization: Bearer <jwt>
  • ·The plaintext token is shown only once after approval

Request body format

application/json

All POST and PATCH payloads use UTF-8 JSON. GET parameters are passed through the query string.

  • ·Content-Type: application/json; charset=utf-8
  • ·Protocol field names use snake_case
  • ·Booleans are true / false, and timestamps follow the rules below

Time and timezone

Unix timestamp

All timestamps are UTC. Update payloads use Unix seconds, while some response fields use ISO strings or millisecond precision depending on the field name.

  • ·date: Unix seconds (for example 1735692000)
  • ·createdAt / updatedAt: ISO 8601 strings
  • ·Clients should convert them to the local timezone as needed

Pagination

page / pageSize

List endpoints use page and pageSize consistently and return total alongside the current page information.

  • ·Defaults: page=1, pageSize=20
  • ·pageSize max: 100
  • ·Response shape: { items, total, page, pageSize }

Idempotency key

update_id

Webhook and long-poll deliveries carry a stable update_id. Retries keep the same value, and clients should de-duplicate against it.

  • ·update_id stays unchanged across retries
  • ·Persist de-duplication in Redis or your database

Error envelope

success: false

Failed responses use { success:false, code, message }, and the HTTP status maps to the code semantics.

  • ·400 VALIDATION / 401 INVALID_BOT_TOKEN
  • ·403 FORBIDDEN / 404 NOT_FOUND
  • ·409 CONFLICT / 429 BOT_RATE_LIMIT

Naming

snake_case

The HTTP layer uses snake_case. Official SDKs map the same behavior into language-native naming styles such as camelCase for Node.js and Java.

  • ·HTTP fields: chat_id / message_id / file_id
  • ·Node SDK fields: chatId / messageId / fileId
  • ·Only the naming style changes, not the underlying behavior

Unified response envelope

Every Bot API response follows the same structure. On success success=true, and the business payload lives in data;On failure success=falsecode maps to the error code table.

JSON
// Success
{
  "success": true,
  "data": {
    "message_id": "6530ab12c9a0ff00123abc88",
    "chat": { "id": "6530ab12c9a0ff00123abc55", "type": "group" },
    "from": { "id": "<bot_user_id>", "is_bot": true },
    "text": "Hello",
    "date": 1735692000
  }
}

// Failure
{
  "success": false,
  "code": "VALIDATION",
  "message": "chat_id is required"
}

Rate limits and response headers

When a bot-level quota is exhausted, the API returns 429 BOT_RATE_LIMITand declares the backoff window through response headers.

HeaderExampleDescription
Retry-After1Recommended backoff in seconds. Always wait for at least this long before retrying a 429 response.
X-BotRateLimit-Remaining0Remaining sends in the current quota window. A value of 0 means the bot has hit the limit.
X-BotRateLimit-Reset1735692060Unix timestamp in seconds for when the current rate-limit window resets.
X-StarIM-Request-Id<uuid>Unique request ID. Include it when contacting support so the platform can trace the exact request.

HTTP API reference

Endpoints are split into two auth groups: developer endpoints use an account JWT to manage the bots you created, while bot runtime endpoints use a Bot Token (`Authorization: Bearer sbot_<token>`). Every path is prefixed with /api/v1/bots/** . Shared behavior is documented in the API conventions.

Developer endpoints (JWT)

Call these with your account session to apply for bots, list them, read the one-time token, and register or remove webhooks.

POST/api/v1/bots/applicationsJWT

Submit Bot Application

登录用户提交创建申请,等待平台审核。

  • ·必填:`name` (<=100)
  • ·可选:`username` (<=64,全局唯一)、`description`、`avatar`、`scopes[]`
  • ·默认 `scopes = ["messages:send", "messages:receive"]`
  • ·返回:机器人对象(`review_status=pending`)
GET/api/v1/bots/myJWT

我的机器人列表

列出当前开发者提交的所有机器人,含状态与 Token 前缀。

  • ·返回:`items[]`,每项含 `review_status`、`status`、`has_token`、`token_prefix`
GET/api/v1/bots/my/:idJWT

机器人详情(含一次性 Token)

审核通过后首次读取会返回 `one_time_token`,读后即销毁(7 天有效)。

  • ·返回:机器人基础信息、`webhook`(脱敏)、`one_time_token?`
  • ·`one_time_token` 仅首次访问返回,请妥善保存
POST/api/v1/bots/my/:id/webhookJWT

登记 Webhook(开发者)

使用账号 JWT 为自己的机器人配置 Webhook,无需使用 Bot Token。

  • ·必填:`url` (必须以 `https://` 开头)
  • ·可选:`secret_token`、`allowed_updates[]`、`allowed_ips[]`
  • ·返回:`webhook`(脱敏,去除 `secret_token`)
DELETE/api/v1/bots/my/:id/webhookJWT

删除 Webhook(开发者)

移除当前机器人的 Webhook 配置,停止接收 Update。

  • ·返回:`bot_id`
GET/api/v1/bots/my/:id/deliveriesJWT

查看 Webhook 投递日志

分页查看机器人最近的 Webhook 投递记录,辅助排查失败或死信。

  • ·可选查询:`page`、`pageSize` (默认 20,最大 100)、`status` (`pending` / `delivering` / `success` / `failed` / `dead_letter`)
  • ·返回:`items[]`(含 `update_id`、`status`、`attempts`、`last_error`、`dead_letter_at`)、`total`、`page`、`pageSize`
POST/api/v1/bots/my/:id/regenerate-tokenJWT

重新生成 Bot Token

签发新 Token 并立即吊销旧 Token;返回的 `one_time_token` 仅本次响应可读,请妥善保存。

  • ·返回:`bot`、`one_time_token`(一次性明文)
  • ·限频:5 次 / 5 分钟;旧 Token 立即失效,正在使用旧 Token 的进程会收 401,请及时切换
PATCH/api/v1/bots/my/:idJWT

更新机器人资料

审核通过后调整机器人名称 / 头像 / 描述 / Profile 元信息。

  • ·可选:`name`(显示名,≤100,非空,可中文;@username 不可自助改)
  • ·可选:`avatar`、`description`、`short_description` (≤120)、`about` (≤512)、`cover_url`
  • ·可选:`links.{website, privacy_policy, terms_of_service, support}`、`contact.{organization, email, phone}`
  • ·可选:`supports_inline_queries` (Boolean,开启后才会收 `inline_query`)、`friend_request_mode` (`auto_accept` / `auto_reject` / `manual`)、`group_privacy` (Boolean,默认 `true`;`false` 时群里收全部普通消息)
  • ·返回:更新后的 `bot` 对象(脱敏)

Bot runtime endpoints (Bot Token)

Call these with the bot token itself. Requests use `Authorization: Bearer sbot_<token>`, and endpoints are grouped by capability so you can jump from the table of contents.

机器人信息 / Profile

15 endpoints

查看自身、设置命令菜单与短 / 长描述、好友申请策略、群隐私模式。

GET/api/v1/bots/meBot Token

获取当前机器人信息

基于 Bot Token 解析并Returns机器人基础信息。

  • ·Returns:`id`、`name`、`username`、`review_status`、`status`、`scopes`、`system_user_id`、`group_privacy`(群隐私模式,默认 `true`)
POST/api/v1/bots/setMyShortDescriptionBot Token

Set Short Description

设置机器人在主页 / 私聊「ⓘ」面板顶部展示的一句话短描述(≤120)。

  • ·Optional:`short_description`(≤120,留空清空)
  • ·Returns:`bot_id` / `short_description`
GET/api/v1/bots/getMyShortDescriptionBot Token

Get Short Description

与 `setMyShortDescription` 配对,便于客户端回填。

  • ·Returns:`{ short_description }`
POST/api/v1/bots/setMyDescriptionBot Token

Set Description

设置机器人在「关于」面板的多行说明。

  • ·Optional:`description`(≤512,留空清空)
  • ·Returns:`bot_id` / `about`
GET/api/v1/bots/getMyDescriptionBot Token

Get Description

与 `setMyDescription` 配对。

  • ·Returns:`{ description }`(即 `Bot.about`)
POST/api/v1/bots/setMyCommandsBot Token

Set Commands

配置 `/start`、`/help` 等命令;App 内输入 `/` 会拉出下拉提示。可按 `scope` / `language_code` 分组。

  • ·Required:`commands` (`{ command, description }[]`,1..100 项;command 仅 a-z0-9_,1..32 字符)
  • ·Optional:`scope`(`default` / `all_private_chats` / `all_group_chats` / `all_chat_administrators` 等,或 `{ type, chat_id?, user_id? }`)
  • ·Optional:`language_code` (BCP-47)
  • ·Returns:`{ ok: true }`
GET/api/v1/bots/getMyCommandsBot Token

Get Commands

与 `setMyCommands` 配对,可按 `scope` / `language_code` 过滤。

  • ·Optional query:`scope`、`language_code`
  • ·Returns:`{ commands }`
POST/api/v1/bots/deleteMyCommandsBot Token

Delete Commands

删除某个 `scope` + `language_code` 组合下的命令清单。

  • ·Optional:`scope`、`language_code`
  • ·Returns:`{ ok: true }`
POST/api/v1/bots/setMyFriendRequestModeBot Token

Set Friend Request Mode

配置 `auto_accept` / `auto_reject` / `manual`;`manual` 时由机器人通过 `answerFriendRequest` 决定。

  • ·Required:`friend_request_mode`
  • ·Returns:`{ friend_request_mode }`
GET/api/v1/bots/getMyFriendRequestModeBot Token

Get Friend Request Mode

与 `setMyFriendRequestMode` 配对。

  • ·Returns:`{ friend_request_mode }`
POST/api/v1/bots/setMyGroupPrivacyBot Token

Set Group Privacy Mode

对标 TG BotFather `/setprivacy`:`enabled=false` 时机器人在群里收到全部普通消息;私聊不受影响。

  • ·Required:`enabled` (Boolean,`true`=开启隐私 / `false`=收全部群消息)
  • ·也可传 `group_privacy`(与 `enabled` 同义)
  • ·Returns:`{ group_privacy }`
GET/api/v1/bots/getMyGroupPrivacyBot Token

Get Group Privacy Mode

与 `setMyGroupPrivacy` 配对;开发者控制台也可通过 `PATCH /bots/my/:id` 修改 `group_privacy`。

  • ·Returns:`{ group_privacy }`
GET/api/v1/bots/getFriendRequestsBot Token

List Friend Requests

列出当前机器人收到的 pending 申请;需要先把策略改为 `manual`。

  • ·Returns:`items[]`(含 `id`、`fromUserId`、`fromUsername`、`requestMessage`、`source`、`status`)
POST/api/v1/bots/answerFriendRequestBot Token

Answer Friend Request

在 `manual` 模式下机器人主动接受 / 拒绝某个好友申请;接受后双方关系自动生效。

  • ·Required:`friendship_id`、`action` (`accept` / `reject`)
  • ·Returns:处理结果
POST/api/v1/bots/verify-token无(请求体带 token)

Verify Bot Token

For debugging: use `token` in request body to verify validity (public endpoint).

  • ·Required:`token`
  • ·Returns:`bot` 对象或错误

Webhook / 长轮询

4 endpoints

webhook 配置、查询、长轮询 getUpdates。

POST/api/v1/bots/setWebhookBot Token

Configure Webhook

使用 Bot Token 直接Configure Webhook;与开发者 JWT 接口二选一。调用后机器人投递模式自动切到 `webhook`。

  • ·Required:`url` (必须 HTTPS)
  • ·Optional:`secret_token`、`allowed_updates[]` (默认 `["message"]`;可含 `edited_message` / `message_deleted` / `callback_query`)、`allowed_ips[]`
  • ·Returns:`webhook`(脱敏)
  • ·Side effects:`Bot.delivery_mode = webhook`
POST/api/v1/bots/deleteWebhookBot Token

Delete Webhook

移除当前 Webhook 配置,停止主动 POST 投递;机器人投递模式自动切到 `polling`,可改用 `getUpdates` 拉取。

  • ·Returns:`bot_id` / `delivery_mode = "polling"`
POST/api/v1/bots/getUpdatesBot Token

getUpdates Long Polling

在 `polling` 模式下拉取等待中的 Update。无公网 IP 也能起 bot;与 webhook 模式互斥(webhook 模式下调用该端点会Returns 409)。

  • ·Optional:`offset`(拉取 `update_seq >= offset` 的条目;推荐用「上一批最后一条 update_seq + 1」做下次 offset,等价 ack)
  • ·Optional:`limit`(1..100,默认 100)
  • ·Optional:`timeout`(long-poll 秒数,0 立即Returns,最大 50;默认 0)
  • ·Optional:`allowed_updates[]`(如 `["message","callback_query"]`,缺省 = 全部)
  • ·Returns:`{ updates: [{ update_id, type, message?, callback_query?, update_seq }] }`
  • ·冲突:webhook 模式下调用 → 409 `Conflict: can't use getUpdates method while webhook is active`
GET/api/v1/bots/getWebhookInfoBot Token

Get Webhook Info

Returns当前 Webhook 配置摘要 + 平台出站 IP,方便客户在防火墙做白名单。

  • ·Returns:`{ url, has_custom_certificate, pending_update_count, allowed_updates, last_error_date, last_error_message, max_connections, platform_egress_ips[] }`
  • ·`platform_egress_ips` 为平台对你的 Webhook 发起请求时使用的出站 IP,便于在防火墙做白名单

消息发送

16 endpoints

文本、富媒体与扩展消息类型。

POST/api/v1/bots/sendMessageBot Token

Send Text消息

向指定会话Send Text消息,对外以机器人系统账号身份发送。

  • ·Required:`chat_id` (会话 ID)、`text` (文本内容)
  • ·Optional:`reply_to_message_id` (引用回复:被引用消息的 ID,与 TG 同义)、`reply_markup`
  • ·Returns:消息对象(含 `message_id`、`chat`、`from`、`date`)
  • ·多媒体请使用 `sendPhoto / sendDocument / sendVideo / sendAudio`
  • ·提示:`reply_to_message_id` 同样适用于 `sendPhoto` / `sendDocument` / `sendVideo` / `sendAudio` / `sendVoice` / `sendVideoNote` / `sendAnimation` / `sendSticker` / `sendLocation` / `sendVenue` / `sendDice` / `sendPoll` / `sendContact` / `sendMediaGroup`(媒体组作用于首条)
POST/api/v1/bots/sendPhotoBot Token

发送图片消息

以图片形式发送已上传的文件,`file_id` 来源于 `/files/complete`。

  • ·Required:`chat_id`、`file_id`
  • ·Optional:`caption` (图片说明文字,附件配文本即混合消息)、`reply_to_message_id` (引用回复)、`width` / `height` (像素,数值,>0 时写入 `metadata.width / height`)
  • ·`file_id` 对应 File 文档若已写入 `metadata.dimensions`,平台会自动补齐
  • ·Returns:消息对象(`message_type=image`)
POST/api/v1/bots/sendDocumentBot Token

Send Document消息

以文档 / 附件形式发送已上传的文件。

  • ·Required:`chat_id`、`file_id`
  • ·Optional:`caption` (附件配文本即混合消息)、`reply_to_message_id` (引用回复)、`thumbnail_url` (文件缩略图 URL,写入 `metadata.thumbnailUrl`)
  • ·Returns:消息对象(`message_type=file`)
POST/api/v1/bots/sendVideoBot Token

Send Video消息

以视频形式发送已上传的文件。

  • ·Required:`chat_id`、`file_id`
  • ·Optional:`caption` (附件配文本即混合消息)、`reply_to_message_id` (引用回复)、`duration` (秒)、`width` / `height` (像素)、`thumbnail_url`
  • ·所有Optional字段 `>0` / 非空时才写入 `metadata.*`;未提供时客户端会在播放时自动读取元数据
  • ·Returns:消息对象(`message_type=video`)
POST/api/v1/bots/sendAudioBot Token

Send Voice消息

以音频 / 语音形式发送已上传的文件。

  • ·Required:`chat_id`、`file_id`
  • ·Optional:`caption` (附件配文本即混合消息)、`reply_to_message_id` (引用回复)、`duration` (秒,语音气泡显示用)、`performer` (表演者 / 上传者)、`title` (曲目 / 标题)
  • ·`performer` / `title` 主要面向音乐 / 播客场景,进入 `metadata` 与 Webhook Update `message.file`
  • ·Returns:消息对象(`message_type=audio`)
POST/api/v1/bots/sendLocationBot Token

发送位置消息

发送一个包含经纬度和Optional地名的位置消息。

  • ·Required:`chat_id`、`latitude`、`longitude`
  • ·Optional:`name` (地点名)、`address` (结构化地址)
  • ·Returns:消息对象(`message_type=location`)
POST/api/v1/bots/sendVenueBot Token

发送地点

在 `sendLocation` 基础上要求标题;客户端会以「带标题地址卡片」样式展示。

  • ·Required:`chat_id`、`latitude`、`longitude`、`title`
  • ·Optional:`address`、`reply_markup`
  • ·Returns:消息对象(`message_type=venue`,`metadata.isVenue=true`)
POST/api/v1/bots/sendVoiceBot Token

Send Voice消息

与 `sendAudio` 同样上传后用 `file_id` 发送;客户端按「语音气泡」样式渲染。

  • ·Required:`chat_id`、`file_id`
  • ·Optional:`caption`、`duration` (秒)、`performer`、`title`
  • ·Returns:消息对象(`message_type=voice`)
POST/api/v1/bots/sendVideoNoteBot Token

Send Video笔记

圆形短视频;客户端会按 `width = height` 圆形播放器渲染。

  • ·Required:`chat_id`、`file_id`
  • ·Optional:`duration` 或 `length` (秒)、`width` / `height` (像素)、`thumbnail_url`
  • ·Returns:消息对象(`message_type=video_note`)
POST/api/v1/bots/sendAnimationBot Token

发送动图

通常是 GIF / MP4 短动画;客户端按视频自动循环播放。

  • ·Required:`chat_id`、`file_id`
  • ·Optional:`caption`、`duration` (秒)、`width` / `height` (像素)、`thumbnail_url`
  • ·Returns:消息对象(`message_type=animation`)
POST/api/v1/bots/sendStickerBot Token

Send Sticker

`file_id` 来源同其他多媒体;推荐 webp / lottie。

  • ·Required:`chat_id`、`file_id`
  • ·Optional:`width` / `height`、`thumbnail_url`
  • ·Returns:消息对象(`message_type=sticker`)
POST/api/v1/bots/sendDiceBot Token

Send Dice / Random Emoji

服务端掷点;🎲 / 🎯 / 🏀 / ⚽ / 🎳 / 🎰 等表情各自有不同取值区间。

  • ·Required:`chat_id`
  • ·Optional:`emoji` (默认 `🎲`;🎰 → 1–64,⚽/🏀 → 1–5,其余默认 1–6)、`reply_markup`
  • ·Returns:消息对象(`message_type=dice`;`metadata.diceEmoji` / `metadata.diceValue`,`text` 形如 `🎲 4`)
POST/api/v1/bots/sendPollBot Token

Send Poll

当前仅支持 `regular` / `quiz` 两种类型;客户端以投票气泡渲染。

  • ·Required:`chat_id`、`question`、`options[]` (2..12)
  • ·Optional:`is_anonymous` (默认 `true`)、`type` (`regular` / `quiz`)、`correct_option_id` (`quiz` 时Required)、`reply_markup`
  • ·Returns:消息对象(`message_type=poll`;`metadata.poll = { question, options, ... }`)
POST/api/v1/bots/sendContactBot Token

Send Contact

客户端以名片气泡展示电话号码与姓名。

  • ·Required:`chat_id`、`phone_number`、`first_name`
  • ·Optional:`last_name`、`reply_markup`
  • ·Returns:消息对象(`message_type=contact`;`metadata.contact = { phone_number, first_name, last_name }`)
POST/api/v1/bots/sendMediaGroupBot Token

Send Media Group

将 2..10 条媒体作为一组发送;平台会拆分为多条独立消息存储,仅最后一条带 `reply_markup`。

  • ·Required:`chat_id`、`media[]` (2..10)
  • ·`media[i]` Required:`type` (`photo` / `video` / `document` / `audio`)、`media` 或 `file_id`;Optional `caption`
  • ·Optional:`reply_markup` (仅作用于最后一条)、`reply_to_message_id` (引用回复,仅作用于首条)
  • ·Returns:消息对象数组
POST/api/v1/bots/sendChatActionBot Token

sendChatAction

Broadcast chat action(`typing` / `upload_photo` 等)。Client shows "typing..." for 3..5s.

  • ·Required:`chat_id`、`action`(如 `typing` / `upload_photo` / `record_voice` 等)
  • ·Returns:`{ ok: true }`

编辑 / 撤回 / 转发

5 endpoints

修改、撤回、转发 / 复制本机器人发送的消息。

POST/api/v1/bots/editMessageBot Token

Edit Bot Message

仅支持编辑由本机器人(同一 `system_user_id`)发送的文本消息;触发 `edited_message` Update。

  • ·Required:`message_id` (或 `messageId`)、`text` (或 `content`)
  • ·仅限本机器人发送的消息;其他消息Returns 403
  • ·编辑成功后消息 `metadata.isEdited=true`,客户端会显示“已编辑”标记
POST/api/v1/bots/deleteMessageBot Token

Delete Bot Message

仅支持删除由本机器人发送的消息;触发 `message_deleted` Update。

  • ·Required:`message_id` (或 `messageId`)
  • ·仅限本机器人发送的消息;其他消息Returns 403
  • ·删除后下游会广播 `message.deleted`,客户端从历史中移除
POST/api/v1/bots/editMessageReplyMarkupBot Token

Edit InlineKeyboard Only

替换某条本机器人消息的 `reply_markup`;不改正文与多媒体。传 `null` 表示清空按钮。

  • ·Required:`message_id`
  • ·`reply_markup` 为 `null` 等价于「清空按钮」;提供新键盘则按 8×8 / `text` 1–64 / `callback_data` ≤ 64 字节 / `url` 必须 `http(s)://` 校验
  • ·仅限本机器人发送的消息;其他消息Returns 403
POST/api/v1/bots/forwardMessageBot Token

forwardMessage

Forward a history message to target chat; bot must be active member in both source / target chats.

  • ·Required:`from_chat_id`、`chat_id` (目标)、`message_id`
  • ·Optional:`caption`
  • ·Returns:转发后的消息对象
POST/api/v1/bots/copyMessageBot Token

copyMessage

Sync with `forwardMessage`, but without "forwarded from" mark.

  • ·Required:`from_chat_id`、`chat_id`、`message_id`
  • ·Optional:`caption`
  • ·Returns:复制后生成的消息对象(`metadata.isForwarded` 不被写入)

文件上传

3 endpoints

S3 直传两步法与 getFile 元数据查询。

POST/api/v1/bots/files/upload-credentialsBot Token

Apply for S3 Upload Credentials

为即将上传的多媒体文件获取 S3 预签名凭证;多媒体消息第一步。

  • ·Required:`fileName`、`fileSize` (字节)
  • ·Optional:`fileType` (MIME)、`checksum`、`metadata`
  • ·Returns:`uploadUrl`、`key`、`headers`、`expiresAt` 等直传参数
POST/api/v1/bots/files/completeBot Token

S3 Upload Completion Registration

客户端完成 PUT 上传后回调登记,获取后续 `sendPhoto / sendDocument` 需要的 `file_id`。

  • ·Required:`key`、`fileName`、`fileSize`
  • ·Optional:`fileType`、`checksum`、`category` (默认 `bot`)、`isPublic`
  • ·Returns:`file_id`、`url`、`thumbnail_url?` 等文件对象
GET/api/v1/bots/getFileBot Token

getFile

Get platform file metadata (including temp download URL) by `file_id`.

  • ·Required query:`file_id`
  • ·Returns:`{ file_id, file_name, mime_type, file_size, url, thumbnail_url? }`

富交互 / Inline Mode

2 endpoints

InlineKeyboard 应答、Inline Mode 应答。

POST/api/v1/bots/answerCallbackQueryBot Token

Answer InlineKeyboard Click

收到 `callback_query` Webhook 后 5 秒内必须调一次,否则 App 端按钮一直转圈;同一 `callback_query_id` 仅可应答一次(重复 410)。

  • ·Required:`callback_query_id`
  • ·Optional:`text` (≤200,App 显示 toast / alert)、`show_alert` (Boolean)、`url` (打开外链)、`cache_time` (秒)
  • ·Returns:`{ ok: true }`
POST/api/v1/bots/answerInlineQueryBot Token

Answer Inline Query

回应用户输入框中针对机器人的 inline 查询;当前 results 仅支持 `article` + `InputTextMessageContent`。

  • ·Required:`inline_query_id`、`results[]` (1..50)
  • ·Optional:`cache_time` (秒)、`is_personal` (Boolean)、`next_offset`
  • ·需配合 `Bot.supports_inline_queries = true` 与 `allowed_updates` 含 `inline_query`

群信息读取

4 endpoints

查询会话、群成员、群管理员。

GET/api/v1/bots/getChatBot Token

getChat

查询单条会话(私聊或群)的基础信息;机器人必须为该会话的活跃参与者。

  • ·Required query:`chat_id`(会话 ID)
  • ·Returns:`{ id, type, title?, name?, member_count?, pinned_message_id? }`
GET/api/v1/bots/getChatMemberBot Token

getChatMember

查询群内某成员的状态;Returns成员资料、所在角色与权限。

  • ·Required query:`chat_id`、`user_id`
  • ·Returns:`{ user: { id, username?, first_name?, is_bot }, status }`
GET/api/v1/bots/getChatMemberCountBot Token

getChatMemberCount

获取群成员人数。

  • ·Required query:`chat_id`
  • ·Returns:`{ count }`
GET/api/v1/bots/getChatAdministratorsBot Token

getChatAdministrators

群管理员(含群主)列表。

  • ·Required query:`chat_id`
  • ·Returns:`administrators[]`(每项含 `user` 与 `status`)

群信息修改

6 endpoints

改群名、群描述、群头像;置顶 / 取消置顶。

POST/api/v1/bots/setChatTitleBot Token

setChatTitle

Change group title; bot must be owner / admin.

  • ·Required:`chat_id`、`title` (1..128)
  • ·Failure 403 时提示机器人需先成为群主或群管理员
POST/api/v1/bots/setChatDescriptionBot Token

setChatDescription

Change group description; bot must be owner / admin.

  • ·Required:`chat_id`、`description` (≤512)
POST/api/v1/bots/setChatPhotoBot Token

setChatPhoto

Change group photo URL; bot must be owner / admin.

  • ·Required:`chat_id`、`photo` (公开可访问的图片 URL)
  • ·可改用先 `/files/upload-credentials` + `/files/complete` 拿 `objectUrl` 再传
POST/api/v1/bots/pinChatMessageBot Token

pinChatMessage

Pin a message in chat; writes `Conversation.pinnedMessageId`。

  • ·Required:`chat_id`、`message_id`
  • ·Must be owner / admin in group; both can pin in private chat by default
POST/api/v1/bots/unpinChatMessageBot Token

unpinChatMessage

Unpin a single message.

  • ·Required:`chat_id`、`message_id`
POST/api/v1/bots/unpinAllChatMessagesBot Token

unpinAllChatMessages

Unpin all messages in chat.

  • ·Required:`chat_id`

群治理 / chatAction

4 endpoints

踢人 / 拉黑 / 解封;广播聊天状态。

POST/api/v1/bots/sendChatActionBot Token

sendChatAction

Broadcast chat action(`typing` / `upload_photo` 等)。Client shows "typing..." for 3..5s.

  • ·Required:`chat_id`、`action`(如 `typing` / `upload_photo` / `record_voice` 等)
  • ·Returns:`{ ok: true }`
POST/api/v1/bots/kickChatMemberBot Token

kickChatMember

Kick member from group (no blacklist); bot must be owner / admin.

  • ·Required:`chat_id`、`user_id`
  • ·Failure 403 时提示「机器人需为群主或群管理员」
POST/api/v1/bots/banChatMemberBot Token

banChatMember

Kick and add to group blacklist, can attach `reason`.

  • ·Required:`chat_id`、`user_id`
  • ·Optional:`reason`
POST/api/v1/bots/unbanChatMemberBot Token

unbanChatMember

Remove member from group blacklist (will not automatically re-invite).

  • ·Required:`chat_id`、`user_id`

调度成员(增值能力)

2 endpoints

在群内列出可调度成员、并以其身份发送文本。默认未开放,需联系开放平台支持申请开通后使用。

GET/api/v1/bots/listChatVirtualMembersBot Token

listChatVirtualMembers (Value-added Capability)

List dispatchable members in group. Requires bot to be active member; not open by default, apply via support.

  • ·Required query:`chat_id`(群会话 ID)
  • ·Optional query:`limit` (1-200,默认 50)、`offset` (≥0,默认 0)
  • ·Returns:`{ items: [{ virtual_user_id, name, username, avatar, joined_at }], pagination: { total, limit, offset } }`
  • ·403:能力未开通、机器人不在该群或会话非群聊
POST/api/v1/bots/simulateSendMessageBot Token

simulateSendMessage (Value-added Capability)

Send text in group as specific dispatchable member. Access requirements same as `listChatVirtualMembers`; text only initially(`type=text`),长度 ≤ 1000;全部调用均会被记录用于合规追溯。

  • ·Required:`chat_id`、`virtual_user_id`(来自 `listChatVirtualMembers`)、`type=text`、`text` (1-1000)
  • ·Optional:`reply_to_message_id`
  • ·Returns:与 `sendMessage` 等价的消息对象
  • ·400:参数缺失或文本超长;403:能力未开通 / 目标成员不在该群 / 目标成员状态不可用;404:目标成员不存在

Example request: sendMessage

A basic text message example that shows the standard request and response shape.

cURL
curl -X POST 'https://www.sochatlive.com/api/v1/bots/sendMessage' \
  -H 'Authorization: Bearer sbot_<token>' \
  -H 'Content-Type: application/json' \
  -d '{
    "chat_id": "6530ab...9c1",
    "text": "Hello from SoChat bot"
  }'

Example request: sendPhoto (4-step media flow)

The same upload flow applies to `sendDocument`, `sendVideo`, and `sendAudio`; only the endpoint path changes.

cURL
# Step 1: request direct-upload credentials
curl -X POST 'https://www.sochatlive.com/api/v1/bots/files/upload-credentials' \
  -H 'Authorization: Bearer sbot_<token>' \
  -H 'Content-Type: application/json' \
  -d '{
    "fileName": "screenshot.png",
    "fileSize": 204800,
    "fileType": "image/png"
  }'
# => { "uploadUrl": "...", "key": "bots/xxx.png", "headers": {...} }

# Step 2: upload the file to S3 with the returned uploadUrl / headers
curl -X PUT "<uploadUrl>" -H 'Content-Type: image/png' --data-binary @screenshot.png

# Step 3: finalize the upload and get a file_id
curl -X POST 'https://www.sochatlive.com/api/v1/bots/files/complete' \
  -H 'Authorization: Bearer sbot_<token>' \
  -H 'Content-Type: application/json' \
  -d '{
    "key": "bots/xxx.png",
    "fileName": "screenshot.png",
    "fileSize": 204800,
    "fileType": "image/png"
  }'
# => { "file_id": "6530ab...f2", "url": "...", ... }

# Step 4: send the photo message (width / height are optional and can be inferred from file metadata)
curl -X POST 'https://www.sochatlive.com/api/v1/bots/sendPhoto' \
  -H 'Authorization: Bearer sbot_<token>' \
  -H 'Content-Type: application/json' \
  -d '{
    "chat_id": "6530ab...9c1",
    "file_id": "6530ab...f2",
    "caption": "Deployment screenshot",
    "width": 1920,
    "height": 1080
  }'

Example request: editMessage / deleteMessage

You can only edit or delete messages sent by the current bot. Successful calls trigger `edited_message` or `message_deleted` updates.

cURL
# Edit a text message previously sent by this bot
curl -X POST 'https://www.sochatlive.com/api/v1/bots/editMessage' \
  -H 'Authorization: Bearer sbot_<token>' \
  -H 'Content-Type: application/json' \
  -d '{
    "message_id": "6530ab12c9a0ff00123abc88",
    "text": "Deployment status updated: success"
  }'

# Delete a message sent by the current bot
curl -X POST 'https://www.sochatlive.com/api/v1/bots/deleteMessage' \
  -H 'Authorization: Bearer sbot_<token>' \
  -H 'Content-Type: application/json' \
  -d '{ "message_id": "6530ab12c9a0ff00123abc88" }'

Example request: inspect webhook deliveries

Uses an account JWT and helps you investigate failed deliveries and terminal `dead_letter` items.

cURL
# Inspect webhook deliveries from the developer console API (account JWT required)
curl -G 'https://www.sochatlive.com/api/v1/bots/my/<bot_id>/deliveries' \
  -H 'Authorization: Bearer <jwt>' \
  --data-urlencode 'page=1' \
  --data-urlencode 'pageSize=20' \
  --data-urlencode 'status=dead_letter'
# => { "items": [ { "update_id": "...", "status": "dead_letter", "attempts": 5, "dead_letter_at": "...", "last_error": "..." } ], "total": 3 }

Example request: setWebhook

Provide a `secret_token` so your service can verify signatures. If you need edited or deleted events, declare them explicitly in `allowed_updates`.

cURL
curl -X POST 'https://www.sochatlive.com/api/v1/bots/setWebhook' \
  -H 'Authorization: Bearer sbot_<token>' \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://example.com/webhook/sochat",
    "secret_token": "replace-with-your-secret",
    "allowed_updates": [
      "message",
      "edited_message",
      "message_deleted",
      "message_read",
      "message_delivered",
      "callback_query",
      "inline_query",
      "friend_request",
      "my_chat_member",
      "chat_member",
      "chat_join_request"
    ],
    "allowed_ips": []
  }'

Webhook and updates

Updates are delivered asynchronously and never block the primary messaging flow. Besides webhooks, you can also pull them with getUpdates long polling. It is mutually exclusive with webhooks: calling setWebhook switches the bot to webhook mode, while deleteWebhook switches it back to polling mode. In groups, Privacy Mode is enabled by default so only commands, @mentions, replies to the bot, and service events are delivered. Disable via setMyGroupPrivacy or the developer console to receive all messages.

Supported update types

Declare subscriptions explicitly in setWebhook.allowed_updates or getUpdates.allowed_updates . Omitting the field, or passing an empty array, subscribes to everything.

typeTrigger
messageA new message, including text, photo, document, video, audio, voice, video note, animation, sticker, dice, poll, contact, location, and venue. Inspect subtype-specific payloads under fields such as `message.file` or `message.location`.
edited_messageTriggered when `editMessage` is called by the same bot or by an allowed client. A single message may be edited multiple times, each with its own `update_id`.
message_deletedTriggered after `deleteMessage` is called by the same bot or by an allowed client.
message_readEmitted when the recipient reads a message sent by this bot. It is delivered only when the original sender is the current bot and is included by default unless you narrow `allowed_updates`.
message_deliveredEmitted when a bot message reaches the recipient device. It applies only when the original sender is the current bot.
callback_queryTriggered when a user clicks an InlineKeyboard button. You should call `answerCallbackQuery` within five seconds.
inline_queryTriggered when a user types `@botname <query>`. It requires `Bot.supports_inline_queries=true`, and the response is sent via `answerInlineQuery`.
friend_requestTriggered when a user sends the bot a friend request. It requires `friend_request_mode=manual` and an explicit subscription.
my_chat_memberTriggered when this bot’s own membership or role changes in a chat, such as joining, leaving, or being promoted/demoted. Explicit subscription required.
chat_memberTriggered when another member’s state changes in the same chat, such as role changes or joins/leaves. Explicit subscription required.
chat_join_requestTriggered when a user requests to join a chat where the bot is an administrator. Explicit subscription required.

my_chat_member / chat_member / chat_join_request are not delivered by default and must be added explicitly to allowed_updates . Other types are included when setWebhook uses the default allowed_updates behavior.

  • Two modesUse webhook push delivery (`setWebhook` switches `Bot.delivery_mode=webhook`) or polling (`deleteWebhook` switches `Bot.delivery_mode=polling` and you then call `getUpdates`). The two modes are mutually exclusive for the same bot.
  • Async outbound flowOnce a message is persisted, the platform dispatcher matches visible bots and generates updates. In webhook mode they are pushed asynchronously to your endpoint; in polling mode they are queued until the next `getUpdates` request returns them immediately.
  • Group Privacy ModeGroups deliver slash commands, @mentions, replies, and mentions by default. Set `group_privacy=false` via `setMyGroupPrivacy` or the developer console to receive all ordinary messages. Group owners/admins bypass privacy automatically. DMs deliver everything.
  • Stable idempotency keyInbound updates use `update_id = sha256(botId + messageId + updateType)`. Retries keep the same `update_id` and `X-StarIM-Update-Id`; use that key to de-duplicate on your side.
  • Retry policyFailed webhooks are retried on a fixed 1min / 5min / 15min / 1h schedule. That is the initial attempt plus four retries, for five total attempts, after which the update becomes a terminal `dead_letter`. In polling mode, acknowledgements are driven by the client `offset`.
  • Signature digestThe signature is `HMAC-SHA256(body, secret_token)`. If `secret_token` is not configured, delivery fails, so always provide one.
  • Egress IPsCall `GET /bots/getWebhookInfo` and read `platform_egress_ips` when you need firewall allowlists.
  • Payload identifiersEvery update includes `bot_id` and a stable `update_id`. Polling mode also adds `update_seq`; use “last update_seq from the previous batch + 1” as the next `offset`.

Request headers

Fixed headers sent by the platform to your webhook endpoint.

HeaderExampleDescription
Content-Typeapplication/jsonAlways encoded as UTF-8 JSON.
X-StarIM-Signaturesha256=<hex>Computed as HMAC-SHA256(raw_body, secret_token). Verify it against the raw request bytes instead of a re-serialized body.
X-StarIM-Update-Id<uuid>Matches `payload.update_id` and should be treated as the idempotency key.

Your endpoint must return a 2xx response within 15 seconds ; otherwise the delivery is treated as failed and retried on a fixed schedule ( 1min / 5min / 15min / 1h ), for a total of 5 attempts . Failed deliveries eventually land in dead_letter, and can then be re-delivered manually from the console.

Privacy Mode rules

Groups deliver only the cases below by default. Disable group privacy or make the bot a group admin to receive everything. Direct messages are not filtered.

ScenarioDeliveredDescription
Direct messagesAllThe bot receives all user messages in a direct conversation.
Group: slash commandsYesFor example `/deploy` or `/help`; the token before the first space must start with `/`.
Group: `@username`YesDelivered when the text contains `@<bot_username>` (case-insensitive).
Group: reply to a bot messageYesDelivered when the user quotes or replies to a message sent by the bot.
Group: mention list hitYesDelivered when the mentions list contains the bot `userId` or `username`.
Group: other regular messagesNoRegular group chatter is not forwarded to the bot by default.
Group: Privacy Mode disabledAllCall `setMyGroupPrivacy({enabled:false})` or turn it off in the developer console.
Group: bot is owner/adminAllGroup admins bypass privacy even when Privacy Mode stays enabled (same as Telegram).

Sample update payloads (JSON)

The sample below walks through common update types including text, photo, edited, deleted, callback query, inline query, read receipt, member state changes, and friend requests.

JSON
// 1) 文本消息(type=message)
{
  "update_id": "3fb4e65c-4d6b-4b0d-9d9a-3a1b9c4f0e12",
  "type": "message",
  "bot_id": "6530ab12c9a0ff00123abc01",
  "message": {
    "message_id": "6530ab12c9a0ff00123abc88",
    "from": { "id": "6530ab12c9a0ff00123ab801", "username": "alice", "is_bot": false },
    "chat": { "id": "6530ab12c9a0ff00123abc55", "type": "group", "title": "研发协作群" },
    "text": "/deploy status",
    "date": 1735689600
  }
}

// 2) 图片消息(type=photo;文件元数据在 message.file;width / height 等元数据若已知会一并带出)
{
  "update_id": "5ac9d1d4-3f9e-4a17-8dd6-7b0a1a3a8a01",
  "type": "photo",
  "bot_id": "6530ab12c9a0ff00123abc01",
  "message": {
    "message_id": "6530ab12c9a0ff00123abc91",
    "from": { "id": "6530ab12c9a0ff00123ab801", "username": "alice", "is_bot": false },
    "chat": { "id": "6530ab12c9a0ff00123abc55", "type": "group", "title": "研发协作群" },
    "text": "看下这张截图 @bot",
    "file": {
      "file_id": "6530ab12c9a0ff00123abcf2",
      "file_name": "screenshot.png",
      "mime_type": "image/png",
      "file_size": 204800,
      "url": "https://s3.example.com/bots/6530.../screenshot.png",
      "thumbnail_url": "https://s3.example.com/bots/6530.../screenshot_thumb.png",
      "width": 1920,
      "height": 1080
    },
    "date": 1735692000
  }
}

// 3) 消息编辑(type=edited_message,由 editMessage 触发)
{
  "update_id": "7c33b8f2-7d24-4f4b-8a2c-1f4b2e0e10bd",
  "type": "edited_message",
  "bot_id": "6530ab12c9a0ff00123abc01",
  "message": {
    "message_id": "6530ab12c9a0ff00123abc88",
    "chat": { "id": "6530ab12c9a0ff00123abc55" },
    "text": "/deploy status — 已更新",
    "date": 1735693500
  }
}

// 4) 消息撤回(type=message_deleted,由 deleteMessage 触发)
{
  "update_id": "91dd6d01-3c52-4c98-907e-6b8e8a01dd3a",
  "type": "message_deleted",
  "bot_id": "6530ab12c9a0ff00123abc01",
  "message": {
    "message_id": "6530ab12c9a0ff00123abc88",
    "chat": { "id": "6530ab12c9a0ff00123abc55" },
    "date": 1735695000
  }
}

// 5) 按钮点击(type=callback_query,5 秒内须调 answerCallbackQuery)
{
  "update_id": "8b3a1c0c-12cd-4e08-9def-2a7c33b9bd44",
  "type": "callback_query",
  "bot_id": "6530ab12c9a0ff00123abc01",
  "callback_query": {
    "id": "6530ab12c9a0ff00123abccb",
    "from": { "id": "6530ab12c9a0ff00123ab801", "username": "alice", "is_bot": false },
    "message": {
      "message_id": "6530ab12c9a0ff00123abc88",
      "chat": { "id": "6530ab12c9a0ff00123abc55", "type": "group" }
    },
    "data": "approve:order:123",
    "chat_instance": "6530ab12c9a0ff00123abc55"
  }
}

// 6) Inline 查询(type=inline_query,需 supports_inline_queries=true)
{
  "update_id": "2f6e6a51-c4ad-4d2f-bb6c-7f0e22115011",
  "type": "inline_query",
  "bot_id": "6530ab12c9a0ff00123abc01",
  "inline_query": {
    "id": "6530ab12c9a0ff00123abcd0",
    "from": { "id": "6530ab12c9a0ff00123ab801", "username": "alice", "is_bot": false },
    "query": "天气 北京",
    "offset": "",
    "chat_type": "private"
  }
}

// 7) 已读 / 已送达(type=message_read / message_delivered,仅原消息发送者为本机器人时触发)
{
  "update_id": "a1d92c52-2e94-44b4-be17-44b3ff97b3a4",
  "type": "message_read",
  "bot_id": "6530ab12c9a0ff00123abc01",
  "message": {
    "message_id": "6530ab12c9a0ff00123abc88",
    "chat": { "id": "6530ab12c9a0ff00123abc55", "type": "private" },
    "date": 1735695200
  }
}

// 8) 自己角色 / 群成员变化(须显式订阅 my_chat_member / chat_member / chat_join_request)
{
  "update_id": "c3e0a99a-3d5e-4f31-89e2-1c4b9c1d20a1",
  "type": "my_chat_member",
  "bot_id": "6530ab12c9a0ff00123abc01",
  "my_chat_member": {
    "chat": { "id": "6530ab12c9a0ff00123abc55", "type": "group", "title": "研发协作群" },
    "from": { "id": "6530ab12c9a0ff00123ab8aa", "username": "owner", "is_bot": false },
    "date": 1735695300,
    "old_chat_member": { "user": { "id": "<bot_user_id>", "is_bot": true }, "status": "member" },
    "new_chat_member": { "user": { "id": "<bot_user_id>", "is_bot": true }, "status": "administrator" }
  }
}

// 9) 好友申请(type=friend_request,需 friend_request_mode=manual)
{
  "update_id": "9bcb1f24-0d4b-4c1f-8b40-aaa3a4f3a201",
  "type": "friend_request",
  "bot_id": "6530ab12c9a0ff00123abc01",
  "friend_request": {
    "id": "6530ab12c9a0ff00123abccc",
    "from": { "id": "6530ab12c9a0ff00123ab801", "username": "alice", "is_bot": false },
    "request_message": "我是 ACME 客服,麻烦通过",
    "source": "search",
    "date": 1735695500
  }
}

Official SDKs

The SDK packages the Bot API, HMAC signature verification, update_id deduplication, and command routing behind a single interface, so you can ship webhook bots in just a few lines. Official SDKs are available for Node.js / TypeScript and Java .

Node.js · TypeScriptPublished
Node ≥ 18

@starim-io/bot-sdk npm v0.1.9

Dual ESM + CJS package, bundled type definitions, built-in Express/native HTTP middleware, and a native fetch implementation with zero runtime dependencies.

JavaPublished
JDK ≥ 17

io.starim:bot-sdk Maven v0.1.5

Uses the JDK built-in HttpClient + jdk.httpserver stack, depends only on Jackson Databind, and works with Spring Boot, Servlet, and Micronaut.

Both official SDKs behave the same way: use Authorization: Bearer <bot_token> to call the Bot API, X-StarIM-Signature for HMAC-SHA256 signature checks, update_id for LRU deduplication, and the same platform retry cadence of 1m/5m/15m/1h. Python, Go, and other languages are not officially maintained yet; contact Open Platform support if you need them.

1. Install

Node 18+ with dual ESM/CJS distribution.

bash
# Pick any package manager
npm install @starim-io/bot-sdk
pnpm add @starim-io/bot-sdk
yarn add @starim-io/bot-sdk

2. Quick start: Echo bot

The high-level StarIMBot client bundles an HTTP server, signature checks, command routing, and deduplication.

TypeScript
import { StarIMBot } from '@starim-io/bot-sdk'

const bot = new StarIMBot({
  token: process.env.STARIM_BOT_TOKEN!,
  secretToken: process.env.STARIM_WEBHOOK_SECRET!,
  baseUrl: process.env.STARIM_API_BASE, // e.g. https://api.example.com/v1
})

// Command routing: reply when the user sends /start
bot.command('start', (ctx) => ctx.reply('Hello, I am the SoChat bot'))

// Generic messages: echo back text
bot.on('message', async (ctx) => {
  if (ctx.message.text) {
    await ctx.reply('You said: ' + ctx.message.text)
  }
})

// Start the built-in HTTP server (signature checks / dedup / routing)
await bot.start({ port: 8787, path: '/webhook' })
console.log('Bot is up on :8787/webhook')

Reverse-proxy public HTTPS traffic to http://<host>:8787/webhook, then configure the webhook URL in the Developer Console as https://your-domain/webhook

3. API-only mode: low-level client

Use StarIMBotClient when you only send proactive messages and do not need webhook handling.

TypeScript
import { StarIMBotClient } from '@starim-io/bot-sdk'

const client = new StarIMBotClient({
  token: process.env.STARIM_BOT_TOKEN!,
  baseUrl: process.env.STARIM_API_BASE,
})

// Configure the webhook
await client.setWebhook({
  url: 'https://example.com/webhook',
  secret_token: 'your-secret',
  allowed_updates: ['message'],
})

// Send proactive messages
const me = await client.getMe()
await client.sendMessage({
  chat_id: '<conversationId>',
  text: 'System notice: scheduled maintenance at 22:00 tonight',
})

// Edit or delete messages sent by the current bot
const sent = await client.sendMessage({ chat_id, text: 'Loading...' })
await client.editMessage({ chat_id, message_id: sent.message_id, text: 'Done ✅' })
await client.deleteMessage({ chat_id, message_id: sent.message_id })

4. Integrate with Express

  • bot.webhookCallback() returns Express-compatible middleware that verifies signatures, deduplicates, and dispatches events for you.
  • Always use express.raw({ type: 'application/json' }) or the raw request bytes will be lost and the signature check will fail.
TypeScript
import express from 'express'
import { StarIMBot } from '@starim-io/bot-sdk'

const app = express()

const bot = new StarIMBot({
  token: process.env.STARIM_BOT_TOKEN!,
  secretToken: process.env.STARIM_WEBHOOK_SECRET!,
})

bot.on('message', async (ctx) => {
  if (ctx.message.text === 'ping') await ctx.reply('pong')
})

// Important: use express.raw so HMAC verification sees the original bytes
app.post(
  '/webhook',
  express.raw({ type: 'application/json' }),
  bot.webhookCallback(),
)

// Other routes can still use express.json()
app.use(express.json())
app.get('/health', (_req, res) => res.json({ ok: true }))

app.listen(8787)

5. One-step media sending

The SDK automates credential issuance -> S3 direct upload -> complete registration -> sendPhoto/sendDocument, so your code only needs a local file path or a Buffer.

TypeScript
import { StarIMBotClient, sendPhotoFromBuffer, sendPhotoFromUrl } from '@starim-io/bot-sdk'
import { readFile } from 'node:fs/promises'

const client = new StarIMBotClient({
  token: process.env.STARIM_BOT_TOKEN!,
  baseUrl: process.env.STARIM_API_BASE,
})

// 1) Local file path (most common)
await client.sendPhotoFromFile(chatId, './chart.png', { caption: 'Today's PV trend' })

// 2) In-memory buffer
const buf = await readFile('./chart.png')
await sendPhotoFromBuffer(client, chatId, buf, {
  fileName: 'chart.png',
  fileType: 'image/png',
})

// 3) Remote URL (the SDK downloads -> uploads -> sends)
await sendPhotoFromUrl(client, chatId, 'https://cdn.example.com/p.png', {
  fileName: 'p.png',
})

6. Error handling

API failures throw StarIMApiError; signature failures throw StarIMSignatureError, which should map to HTTP 401.

TypeScript
import { StarIMApiError, StarIMSignatureError } from '@starim-io/bot-sdk'

try {
  await client.sendMessage({ chat_id, text: 'hello' })
} catch (err) {
  if (err instanceof StarIMApiError) {
    // err.statusCode / err.code / err.message
    if (err.statusCode === 429) {
      // Quota exhausted, retry after the Retry-After delay
    }
    if (err.code === 'invalid_token') {
      // Token expired: refresh it or issue a new one
    }
  }
  throw err
}

// Inside webhook middleware: catch signature errors explicitly
try {
  await bot.processWebhook(rawBody, signatureHeader, updateIdHeader)
} catch (err) {
  if (err instanceof StarIMSignatureError) {
    return res.status(401).end()
  }
  throw err
}

Method mapping

Both SDKs follow the same naming conventions, and response fields map directly to Bot API.

CapabilityNode.jsJavaOther languagesBot API endpoint
Inspect self / verify tokenclient.getMe() · client.verifyToken()client.getMe() · client.verifyToken()Use the HTTP API / contact supportGET /bots/me
Send textclient.sendMessage({chat_id,text})client.sendMessage(chatId, text)Use the HTTP API / contact supportPOST /bots/sendMessage
Send photo / document / video / audioclient.sendPhoto / sendDocument / sendVideo / sendAudioclient.sendPhoto / sendDocument / sendVideo / sendAudioUse the HTTP API / contact supportPOST /bots/send{Photo|Document|Video|Audio}
Rich media: voice / videoNote / animation / stickerclient.sendVoice / sendVideoNote / sendAnimation / sendStickerclient.sendVoice / sendVideoNote / sendAnimation / sendStickerUse the HTTP API / contact supportPOST /bots/send{Voice|VideoNote|Animation|Sticker}
Dice / poll / contact / venue / media groupclient.sendDice · sendPoll · sendContact · sendVenue · sendMediaGroupclient.sendDice · sendPoll · sendContact · sendVenue · sendMediaGroupUse the HTTP API / contact supportPOST /bots/send{Dice|Poll|Contact|Venue|MediaGroup}
Send locationclient.sendLocationclient.sendLocationUse the HTTP API / contact supportPOST /bots/sendLocation
Edit / delete / forwardclient.editMessage · deleteMessage · forwardMessage · copyMessageclient.editMessage · deleteMessage · forwardMessage · copyMessageUse the HTTP API / contact supportPOST /bots/{editMessage|deleteMessage|forwardMessage|copyMessage}
Inline keyboard edit / answerclient.editMessageReplyMarkup · client.answerCallbackQueryclient.editMessageReplyMarkup · client.answerCallbackQueryUse the HTTP API / contact supportPOST /bots/{editMessageReplyMarkup|answerCallbackQuery}
Inline mode answerclient.answerInlineQueryclient.answerInlineQueryUse the HTTP API / contact supportPOST /bots/answerInlineQuery
Command menuclient.setMyCommands / getMyCommands / deleteMyCommandsclient.setMyCommands / getMyCommands / deleteMyCommandsUse the HTTP API / contact supportPOST /bots/{set|get|delete}MyCommands
Webhook config / summaryclient.setWebhook · deleteWebhook · getWebhookInfoclient.setWebhook · deleteWebhook · getWebhookInfoUse the HTTP API / contact supportPOST/GET /bots/{setWebhook|deleteWebhook|getWebhookInfo}
Long pollingclient.getUpdates({offset,timeout}) · bot.startPolling()client.getUpdates(GetUpdatesParams) · bot.startPolling(timeoutSec)Use the HTTP API / contact supportPOST /bots/getUpdates
Profile managementclient.setMyShortDescription / setMyDescription / getMyShortDescription / getMyDescriptionclient.setMyShortDescription / setMyDescription / getMyShortDescription / getMyDescriptionUse the HTTP API / contact supportPOST /bots/{set|get}My{Short,}Description
Chat inspectionclient.getChat / getChatMember / getChatMemberCount / getChatAdministratorsclient.getChat / getChatMember / getChatMemberCount / getChatAdministratorsUse the HTTP API / contact supportGET /bots/getChat*
Chat mutation / pinningclient.setChatTitle / setChatDescription / setChatPhoto · pinChatMessage*client.setChatTitle / setChatDescription / setChatPhoto · pinChatMessage*Use the HTTP API / contact supportPOST /bots/{setChat*|pin*}
Moderation / chatActionclient.kickChatMember · banChatMember · unbanChatMember · sendChatActionclient.kickChatMember · banChatMember · unbanChatMember · sendChatActionUse the HTTP API / contact supportPOST /bots/{kick|ban|unban}ChatMember · POST /bots/sendChatAction
Friend requests / group privacyclient.getFriendRequests · answerFriendRequest · set/getMyFriendRequestMode · set/getMyGroupPrivacyclient.getFriendRequests · answerFriendRequest · set/getMyFriendRequestMode · set/getMyGroupPrivacyUse the HTTP API / contact supportPOST/GET /bots/*FriendRequest* · /bots/*GroupPrivacy
Delivery logs and replay - Developer Console - Developer ConsoleUse the HTTP API / contact supportGET /bots/my/:id/deliveries (account JWT, not Bot Token)
Two-step S3 upload / getFileclient.issueUploadCredentials · completeUpload · getFileclient.issueUploadCredentials · completeUpload · getFileUse the HTTP API / contact supportPOST/GET /bots/{files/...|getFile}
One-step local upload and sendclient.sendPhotoFromFile · sendPhotoFromBuffer · sendPhotoFromUrlclient.sendPhotoFromFile · sendDocumentFromFile · uploadFileUse the HTTP API / contact supportSDK convenience layer
High-level event routingnew StarIMBot(...) · bot.on() · bot.command() · bot.start()StarIMBot.builder() · bot.on() · bot.command() · bot.start()Use the HTTP API / contact supportBuilt-in webhook server / framework agnostic

For the complete API surface and advanced usage, including custom deduplication, allowed_updates filtering, long-poll offset/timeout tuning, and reply_markup passthrough, refer to the Node.js and Java SDK docs. Delivery logs and retries are handled in the Developer Console. Other languages should integrate against the Bot API HTTP contract or contact Open Platform support.

No public IP? Use long polling

Long poll

You can run your bot locally without HTTPS. Call deleteWebhook to switch the bot into polling mode, then start the SDK with startPolling(). It fully supports offset / timeout / allowed_updates parameters, while the platform still handles multi-instance deduplication and instant wake-up. In practice, long polling feels close to webhooks without requiring public ingress.

// Node.js SDK
import { StarIMBot } from '@starim-io/bot-sdk';

const bot = new StarIMBot({
  token: process.env.STARIM_BOT_TOKEN!,
  baseUrl: 'https://your-api-host/api/v1',
  secretToken: 'unused-in-polling-mode'
});
bot.command('start', ctx => ctx.reply('hello from the polling bot'));

await bot.client.deleteWebhook();   // Switch to polling mode
await bot.startPolling({ timeout: 30 });
// Java SDK
StarIMBot bot = StarIMBot.builder()
        .token(System.getenv("STARIM_BOT_TOKEN"))
        .secretToken("unused-in-polling-mode")
        .baseUrl("https://your-api-host/api/v1")
        .build();
bot.command("start", ctx -> ctx.reply("hello from the polling bot"));

bot.getClient().deleteWebhook();
new Thread(() -> bot.startPolling(30)).start();
  • setWebhook and getUpdates are mutually exclusive: calling getUpdates while webhook mode is active returns 409 Conflict so the same update is never consumed through two channels.
  • The SDK already includes LRU deduplication and exponential backoff (2/4/8/.../30s), so you do not need extra client-side retry logic.
  • Horizontal scaling does not create duplicate deliveries and still preserves at-most-once semantics.

Common fields quick reference

A quick reference for frequently used fields across the Bot API and update payloads. chat_id is the conversation identifier in SoChat.

FieldMeaningNotes

Fields follow snake_case. Any breaking or notable changes will be recorded in the changelog.

Error codes

All failed responses return { success: false, code, message }. The HTTP status is aligned with code. The table below lists the most common business errors. For errors not listed here, rely on message and the HTTP status code.

codeTypical HTTPDescriptionSuggested action
codeTypical HTTPDescriptionSuggested action

Enterprise features

An overview of capabilities designed for enterprise integrations, including access control, messaging, group governance, quotas, and monitoring.

DimensionCapability

Signature verification and webhook samples (Node.js)

This section includes minimal HMAC-SHA256 verification, update idempotency, and an Echo Bot example. The signature uses the setWebhook value submitted through secret_token as the key and is calculated from the raw request bytes.

HMAC verification

Always verify against the raw request body bytes; use timingSafeEqual to avoid timing attacks.

JavaScript
import crypto from 'node:crypto'

/**
 * @param rawBody - 与平台计算签名时一致的原始字节
 * @param signatureHeader - 如 X-StarIM-Signature: sha256=...
 * @param secret - setWebhook 时配置的 secret_token
 */
export function verifyWebhookSignature(rawBody, signatureHeader, secret) {
  if (!signatureHeader || !secret) return false
  const body = typeof rawBody === 'string' ? Buffer.from(rawBody) : rawBody
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(body).digest('hex')
  const a = Buffer.from(expected)
  const b = Buffer.from(String(signatureHeader).trim())
  return a.length === b.length && crypto.timingSafeEqual(a, b)
}

Idempotency and deduplication

  • Use `update_id` as the idempotency key; it stays stable across retries.
  • The same user message should trigger only one inbound delivery even if the platform retries it multiple times (`message` / `photo` / `document` / `video` / `audio` / `location`).
  • `edited_message` and `message_deleted` may occur multiple times for the same message, but the event itself should still be deduplicated with `update_id`.
  • Return 2xx quickly and move heavy work to async workers.
JavaScript
const seen = new Set() // 生产环境请换 Redis / DB

function isDuplicateUpdate(updateId) {
  if (seen.has(updateId)) return true
  seen.add(updateId)
  return false
}

Echo Bot (Express)

After signature verification, parse the update and reply with sendMessage.

JavaScript
// POST /webhook — 验签通过后解析 Update,Echo 文本消息
app.post('/webhook/sochat', express.raw({ type: '*/*' }), async (req, res) => {
  const raw = req.body
  const sig = req.get('X-StarIM-Signature') || ''
  if (!verifyWebhookSignature(raw, sig, process.env.WEBHOOK_SECRET)) {
    return res.status(401).end()
  }
  const update = JSON.parse(raw.toString('utf8'))
  if (isDuplicateUpdate(update.update_id)) {
    return res.status(200).json({ ok: true })
  }
  const text = update.message?.text
  const chatId = update.message?.chat?.id
  if (update.type === 'message' && text && chatId) {
    await fetch('https://www.sochatlive.com/api/v1/bots/sendMessage', {
      method: 'POST',
      headers: {
        Authorization: 'Bearer ' + process.env.BOT_TOKEN,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ chat_id: chatId, text }),
    })
  }
  res.status(200).json({ ok: true })
})

Security and compliance

Bot tokens stay isolated from user JWTs, the platform enforces review gates, and delivery plus audit logs are redacted and traceable.

Auth isolation

  • Bot tokens are fully isolated from user JWTs
  • Token verification is enforced by the platform layer
  • Your service receives resolved bot context such as `bot_id` instead of raw credentials

Webhook security

  • HTTPS is required by default
  • HMAC signature headers are supported
  • IP allowlists and time-window validation can be layered on top
  • Failed deliveries fall into `dead_letter` after the initial attempt plus four retries

Token governance

  • Tokens are not issued before review approval
  • The plaintext token is shown only once
  • Rotating a token invalidates the previous one immediately

Rate controls

  • Global defaults stack with per-bot quotas
  • Limits are evaluated across second, minute, and day windows
  • Overflow returns `BOT_RATE_LIMIT` with `Retry-After`
  • Thresholds can be tuned per bot by the platform team

Audit and redaction

  • Review, revoke, disable, and quota-change actions are all traceable
  • Rate-limit hits are recorded for forensic analysis and quota tuning
  • Logs expose only token prefixes and domains; plaintext secrets never hit disk
  • Failed deliveries and abnormal traffic can fan out to alerting hooks

Observability

  • The platform exposes Prometheus metrics at `/metrics`
  • Dashboards track API traffic, delivery success, queue backlog, and limit hits
  • A 24-hour monitoring view helps teams investigate incidents quickly

Changelog

Entries are listed in release order and capture newly available capabilities plus incompatible changes. This guide currently targets API version v1; any future breaking change will ship behind a new versioned path and be documented here with migration notes.

  1. 2026-05

    Rich media, group administration, and receipt events

    • ·Messaging: sendVoice / sendVideoNote / sendAnimation / sendSticker / sendDice / sendPoll / sendContact / sendVenue / sendMediaGroup
    • ·Group read APIs: getChat / getChatMember / getChatMemberCount / getChatAdministrators
    • ·Group write APIs: setChatTitle / setChatDescription / setChatPhoto; pinChatMessage / unpinChatMessage / unpinAllChatMessages
    • ·Group ops: forwardMessage / copyMessage / sendChatAction / getFile / kickChatMember / banChatMember / unbanChatMember
    • ·Events: message_read / message_delivered (subscribed by default when `allowed_updates` is not narrowed)
    • ·Events: my_chat_member / chat_member / chat_join_request (require explicit `allowed_updates` subscription)
    • ·getWebhookInfo now returns `platform_egress_ips` for firewall allowlists
  2. 2026-04

    Friend-request review and member dispatching (premium capability)

    • ·Friend requests: friend_request_mode + getFriendRequests / answerFriendRequest + the friend_request event
    • ·Dispatched members (premium, disabled by default): listChatVirtualMembers / simulateSendMessage with full compliance traces
  3. 2026-03

    Inline Mode

    • ·Handle inline searches triggered from the compose box via the inline_query event and answerInlineQuery
    • ·Requires Bot.supports_inline_queries=true and `allowed_updates` to include inline_query
  4. 2026-02

    InlineKeyboard edit alignment

    • ·editMessageReplyMarkup edits only the keyboard; passing null clears it without touching the text body
  5. 2026-02

    Expanded bot profile fields

    • ·setMyShortDescription / getMyShortDescription (short bio up to 120 chars)
    • ·setMyDescription / getMyDescription (long bio up to 512 chars)
    • ·Structured profile fields such as cover, links, and contact are now available
  6. 2026-01

    Long polling support

    • ·POST /bots/getUpdates (mutually exclusive with webhooks and automatically synced with delivery_mode)
    • ·Node and Java SDKs now expose startPolling() with offset management, backoff, and deduplication
    • ·Bots can run even without a public IP
  7. 2025-12

    Interaction capabilities opened

    • ·InlineKeyboard buttons + callback_query + answerCallbackQuery (must be answered within 5 seconds)
    • ·Command menus: setMyCommands / getMyCommands / deleteMyCommands grouped by scope / language_code
  8. 2025-11

    Messaging capability expansion

    • ·Media: sendPhoto / sendDocument / sendVideo / sendAudio / sendLocation
    • ·editMessage / deleteMessage (only for messages sent by the current bot) + edited_message / message_deleted events
    • ·Per-bot rate limits (send_per_sec / send_per_min / send_per_day)
    • ·Webhook delivery logs are queryable with manual dead-letter re-delivery
  9. 2025-09

    Minimum production-ready loop

    • ·Bot application and review flow with one-time plaintext tokens, hashed storage, revocation, and regeneration
    • ·setWebhook + HMAC-SHA256 signatures with retries on a 1m / 5m / 15m / 1h schedule, then dead-letter after five total attempts
    • ·A full text messaging loop built around sendMessage

FAQ

Why is the bot token not issued immediately after I apply?
SoChat serves enterprise and private-deployment scenarios, so the platform performs a unified review for eligibility, accountability, and abuse prevention. A bot token is only issued after the review passes.
Why must webhook delivery be asynchronous?
Webhook delivery is outbound HTTP traffic, so network jitter, timeouts, and customer-side throttling are common. An asynchronous queue keeps the core messaging path unblocked while enabling retries, dead letters, and concurrency control.
Will every group message be forwarded to my bot?
Not by default. With group privacy enabled, only commands, @mentions, replies to the bot, and service events such as edited_message or message_deleted are forwarded. To receive all ordinary group chatter, call `setMyGroupPrivacy({enabled:false})` or disable group privacy in the developer console. Bots that are group owners or admins always receive everything.
What kinds of scenarios can the platform support today?
Typical scenarios include approvals and monitoring alerts (text, image, file, animation, sticker), assistant bots that can edit or retract their own replies, customer-service bots with inline button callbacks and Inline Mode, random interaction flows such as dice or polls, group operations such as titles, pins, kicks, bans, sendChatAction, manual friend-request review, location or venue check-ins, media-group digests, and knowledge-base Q&A.
Can I run a bot without a public IP?
Yes. Call `POST /api/v1/bots/deleteWebhook` to switch the bot into polling mode, then use `POST /api/v1/bots/getUpdates` for long polling. The Node and Java SDKs expose `startPolling()` to manage offsets, backoff, and deduplication automatically. Calling `getUpdates` while webhook mode is enabled returns 409 Conflict.
How do callback_query and answerCallbackQuery work?
Attach `reply_markup: { inline_keyboard: [[{ text, callback_data }]] }` when calling `sendMessage`. When a user clicks the button, the platform delivers a `callback_query` update. Your bot must call `answerCallbackQuery` within five seconds; repeating the same `callback_query_id` returns 410. Optional fields such as `text`, `show_alert`, and `url` control the client toast, alert, or external jump.
How do I subscribe to member changes, join requests, or friend requests?
When `setWebhook` omits `allowed_updates`, the default set already includes `message / edited_message / message_deleted / message_read / message_delivered / callback_query / inline_query / friend_request`. `my_chat_member`, `chat_member`, and `chat_join_request` must be declared explicitly in `allowed_updates`. Friend requests also require `friend_request_mode=manual`.
How do I send photos, files, or other media?
Use a two-step flow. First call `POST /api/v1/bots/files/upload-credentials` to fetch direct-upload S3 credentials, then upload the file straight to S3. After that, call `POST /api/v1/bots/files/complete` to register the upload, obtain a `file_id`, and pass that `file_id` to `sendPhoto`, `sendDocument`, `sendVideo`, or `sendAudio`.
What are the limits of editMessage and deleteMessage?
They can only edit or delete messages sent by the same bot (`system_user_id`). All other messages return 403 FORBIDDEN. `editMessage` currently supports text replacement only. Successful edits and deletions trigger updates for every webhook subscribed to `edited_message` or `message_deleted`.
What should I do when I receive 429 / BOT_RATE_LIMIT?
Rate limiting combines a platform default with optional per-bot overrides. When you exceed it, the API returns HTTP 429 with `Retry-After` and `X-BotRateLimit-Remaining`. Back off according to `Retry-After`, and contact platform support if your sustained workload needs a higher quota.
How is the webhook signature calculated?
The platform uses the `secret_token` submitted through setWebhook as the key and computes HMAC-SHA256 over the outgoing JSON request body. The hex digest is written into `X-StarIM-Signature: sha256=<hex>`. Always verify against the raw request bytes, otherwise JSON re-serialization may change the byte stream. Deliveries fail if `secret_token` is missing, so always provide one.
How are failed webhooks retried?
The endpoint must return 2xx within 15 seconds. Otherwise the platform retries on a fixed 1 min / 5 min / 15 min / 1 h schedule, for five total attempts including the first one. Failed deliveries then move into `dead_letter`. Every retry keeps the same `update_id`, and you can inspect them in the Developer Console delivery log or via `GET /api/v1/bots/my/:id/deliveries`.
What if I forgot to save the bot token?
After approval, the plaintext `one_time_token` appears only the first time you open Developer Console → Bot details, and it is destroyed immediately after being read. If you lose it, use “Regenerate token” in the Developer Console. The platform issues a new plaintext token and revokes the old one immediately, so any worker still using the previous token will start receiving 401 responses.

Next steps

Once the application is approved, use the Echo Bot flow to validate sendMessage and the webhook loop end to end. If you get stuck, contact support through the official channel.