Admin panel: all routes and API contracts
Documentation of every route in the built-in telesrv admin panel — the SPA
page addresses and the API routes behind them. The panel server lives in
cmd/telesrv-admin; routes are declared in (*server).routes()
(server.go:50).
The panel is a plain HTTP server: it serves the built frontend (/) and a
JSON API under the /api/ prefix. Every API path requires a session (cookie),
and every mutating request additionally requires a CSRF token. Many routes also
check an operator permission (permission).
How to use this document
- For each GET endpoint, the request parameters (query) and a short response shape are listed.
- For each POST endpoint under
/api/actions/*and the verification decisions, the request body (JSON) is given. They all share common fields (see below) plus their own specific fields. int64in JSON may be sent either as a number or as a string (e.g."user_id": "123"or"user_id": 123) — the server accepts both (flexInt64).flexUnixaccepts Unix seconds or a date in2006-01-02/ RFC3339 form.- All mutating requests go to the Admin API. A command's response is either
{"status":..., "message":..., "command_id":...}on success (HTTP 200) or{"error":..., "code":...}on error. An optimistic-locking conflict is409.
Authentication and session
| Method | Path | Description |
|---|---|---|
| POST | /api/login |
Log in. Body: {"secret": "..."}. Validates the config secret, issues a signed session cookie and CSRF cookie. The only mutating route without a CSRF token (no session yet); only Origin is checked. |
| POST | /api/logout |
Log out. Destroys the session and CSRF cookie. |
| GET | /api/session |
Returns {"actor": "...", "permissions": [...], "csrf_token": "..."}. Called by the panel on startup. |
The session lives in a signed cookie (default TTL 12 hours); there is no
server-side session store. Every request except GET/HEAD/OPTIONS and
/api/login must present:
- the
telesrv_admin_csrfcookie; - the
X-CSRF-Tokenheader with the same value; - an Origin matching the host (when Origin is present).
Violating any of the three — 403 Forbidden.
Permissions and their checks
The panel distinguishes plain authorization (requireAuthAPI) from a
permission check (requirePermission). Permission names match the strings in
TELESRV_ADMIN_UI_PERMISSIONS, and the list below is exactly what
assignablePermissions() (cmd/telesrv-admin/security.go) offers the
operator-accounts screen — a right that is not in that list cannot be granted
to a named operator account.
| Permission | Grants |
|---|---|
| People and chats | |
accounts.read |
View accounts — Browse users, their profiles and sessions |
accounts.manage |
Edit accounts — Change profiles, usernames, freeze and revoke sessions |
channels.read |
View groups and channels — Browse supergroups and channels |
channels.manage |
Edit groups and channels — Change settings, usernames and avatars |
messages.read |
View messages — Read private and group message history |
messages.manage |
Delete messages — Remove messages and clear history |
| Moderation and verification | |
moderation.review |
Handle reports — Work the moderation queue and decide cases |
verification.review |
Verify accounts — Work the verification queue and grant badges |
verification.revoke |
Remove verification — Take a granted badge away (needs the right above too) |
botverification.review |
Handle third-party marks — Work the third-party verification queue |
botverification.manage |
Appoint verifiers — Grant verifier status and curate mark icons |
| Content | |
content.read |
View stickers, emoji and GIFs — Browse the packs and the GIF catalogue |
content.manage |
Edit stickers, emoji and GIFs — Create, rename and remove packs and catalogue entries |
usernames.read |
View NFT usernames — Browse collectible usernames |
usernames.manage |
Manage NFT usernames — Mint, transfer and revoke collectible usernames |
phones.read |
View anonymous numbers — Browse the +888 number registry |
phones.manage |
Manage anonymous numbers — Issue, transfer and burn +888 numbers |
| Bots | |
bots.read |
View bots — Browse the bot list and their details |
bots.manage |
Create and delete bots — Add new bots and remove existing ones |
bots.token.read |
Reveal bot tokens — Export a bot's live credential |
| Broadcasting | |
broadcasts.read |
View broadcasts — See past and scheduled broadcasts |
broadcasts.send |
Send broadcasts — Deliver a message to many users at once |
| Gifts and ratings | |
gifts.read |
View the gift catalogue — Browse star gifts, auctions and official gifts |
gifts.manage |
Edit the gift catalogue — Import gifts, publish collectibles and give gifts |
ratings.read |
View account ratings — Browse the account-rating leaderboard |
ratings.manage |
Adjust account ratings — Recompute ratings and apply manual corrections |
| Storage and overview | |
storage.read |
View storage — See media usage per account |
storage.manage |
Purge storage — Manually delete stored media |
dashboard.read |
View the dashboard — See the overview counters and server health |
| Billing | |
premium.manage |
Manage Premium — Grant, revoke and refund Premium |
stars.read |
View the Stars ledger — Browse Stars balances and signed per-account history |
prices.manage |
Manage shop prices — Edit product prices, hide products and set the Stars rate |
donations.manage |
Manage crypto donations — Watch the deposit wallet, configure chains and read the deposit ledger |
| The console itself | |
admins.manage |
Manage operators — Create operators and decide what everyone can do |
audit.read |
View the audit log — See who did what across the console |
server.manage |
Manage server settings — Edit the server identity, login-notification templates and .env, and view service status |
* |
Every right, including ones added later (wildcard). |
Most sections are a read/manage pair: the read right opens the page, the manage
right is what the buttons on it need. The panel checks the read right for the
page's own GET endpoints and the manage right per action, so granting only
accounts.read gives a working read-only account screen.
A few rights are deliberately independent of the section they sit in:
verification.review and botverification.review are granted separately
because the two queues are separate mechanisms over separate tables, and
verification.revoke is checked in addition to verification.review.
admins.manage is the one right that can hand out every other right, so it is
never implied by anything, and audit.read is supervisory rather than riding on
the sections it covers.
The session's permission list is returned from /api/session, and the frontend
uses it to decide which sidebar sections to show and which pages to refuse — see
"Navigation and permissions in the UI" below.
Navigation and permissions in the UI
The panel's sidebar, its in-page tab bars and its route table are three views of
one declaration: cmd/telesrv-admin/web/src/nav.ts. That file lists every
section, the paths that belong to it, and the right each of those paths enforces
server-side. Layout.tsx renders the sidebar from it and, above every page, the
active section's tab bar through SectionTabs.tsx, which reads that section's
tab list from it; Routes.tsx asks it a single question --
routePermission(path) -- and gates the whole surface in one place.
Two consequences worth knowing before changing anything here:
- A section is rendered when the session holds any of its tabs' rights, and
its link resolves to the first visible tab. An operator holding only
prices.managegets one Economy row that opens on Bot prices. A section reduced to a single visible tab draws no tab bar at all. - A page can never be advertised and then answer 403. Before this table
existed, twelve sidebar entries rendered unconditionally while every endpoint
behind them was gated -- an operator without
accounts.readstill saw Accounts, and clicking it produced a bare 403 rather than the explanationPermissionDeniedgives. The gate is now derived from the same strings the sidebar reads.
Adding a page to the panel
In order, because skipping a step produces the drift this section exists to prevent:
- Decide whether it is a new section or a tab of an existing one. If the page is a sibling of something already there -- it serves the same job over a different slice -- it is a tab, not a second sidebar row. Economy already holds Stars balances, Premium, Bot prices, Donations and Account Rating; Server holds Storage, Operators and the Audit log. A new sidebar row is only for a genuinely new job.
- Add it to
nav.ts, with the right its route enforces server-side. If you need a right that does not exist yet, add it topermissions.tsx(permissionLabelsandpermissionGroups) and toassignablePermissions()insecurity.go-- a right that is not assignable cannot be granted, and the operator-accounts picker will not show it. - Add the route in
Routes.tsx. Do not wrap it inPermissionGate: the gate is already applied fromroutePermission, and a hand-wrapped branch is the thing that let the old gaps accumulate. - Add the page in
web/src/pages/, and take anavigateprop if it needs one. Do not render<SectionTabs>in it: the shell (Layout.tsx) already draws the active section's tab bar above every page fromnav.ts, so a page that renders its own shows two.gen_admin_panel_doc_tables.py --checkfails on any<SectionTabsunderpages/. - Translate it. Every user-visible string goes through
useI18n()and gets an entry in all three language blocks ofi18n.tsx. - Rebuild the bundle.
cmd/telesrv-admin/server.godoes//go:embed web/dist, soweb/distis what a non-Docker build ships. Runnpm run buildand commit the result, including the deletion of the old hashed assets. Asrcchange without a rebuiltdistdoes not ship. - Regenerate the tables in this document:
python3 scripts/gen_admin_panel_doc_tables.py --write.
The generated tables
Both the navigation table below and the permission table above are produced by
scripts/gen_admin_panel_doc_tables.py from nav.ts, permissions.tsx and
security.go. They drifted badly once -- a dozen routes were missing entirely --
because nothing checked them. Do not hand-edit them; edit the source and rerun.
--check exits non-zero when they are stale, which is the form worth putting in
CI.
SPA routes are declarative: any unknown frontend path is served as /
(index.html) and the router decides what to render
(web/src/pages/Routes.tsx). The tables below come from nav.ts, the single
declaration the sidebar and the router both read.
Section tabs
Every tab of every section, with the right its route enforces. /statistics is
the one path with no tab: the statistics charts were folded into the overview,
and the old URL still lands there rather than 404ing on a bookmark.
| Sidebar section | Tab | Path | Required right |
|---|---|---|---|
| Overview | Overview | / |
dashboard.read |
| Users and chats | Accounts | /accounts |
accounts.read |
| Users and chats | Groups / Channels | /channels |
channels.read |
| Users and chats | Bots | /bots |
bots.read |
| Users and chats | Broadcasts | /broadcasts |
broadcasts.read |
| Moderation | Messages | /messages/private |
messages.read (also served at /messages) |
| Moderation | Groups | /messages/groups |
messages.read |
| Moderation | Reports | /moderation |
moderation.review |
| Moderation | Shared devices | /accounts/shared-devices |
accounts.read |
| Verification | Official | /verification |
verification.review |
| Verification | Third-party | /bot-verification |
botverification.review |
| Content | Stickers | /stickers |
content.read |
| Content | Emoji | /emoji |
content.read |
| Content | GIFs | /gif-catalog |
content.read |
| Economy | Stars balances | /stars |
stars.read |
| Economy | Premium | /monetization |
premium.manage (also served at /premium, /star-issue) |
| Economy | Bot prices | /prices |
prices.manage |
| Economy | Donations | /donations |
donations.manage |
| Economy | Account Rating | /account-ratings |
ratings.read |
| Gifts | Star Gift Catalog | /gifts |
gifts.read |
| Gifts | Give Gifts | /give-gifts |
gifts.read |
| Gifts | Auctions & Drops | /auctions |
gifts.read |
| NFT items | NFT Usernames | /collectible-usernames |
usernames.read |
| NFT items | NFT Numbers | /collectible-phones |
phones.read |
| NFT items | NFT Gifts | /nft-gifts |
gifts.read |
| Server | Server Settings | /server-settings |
server.manage |
| Server | Storage | /storage |
storage.read |
| Server | Operators | /admin-users |
admins.manage |
| Server | Audit log | /audit-log |
audit.read |
A section with one visible tab shows no tab bar, and its sidebar link points at that tab directly.
Detail and sub-routes
These paths belong to the section above but are not tabs of it -- they are a specific record inside one, and each is gated by the same right as its list.
| Path | Page |
|---|---|
/accounts/{id} |
Account card: profile, actions, authorizations, recent admin actions. |
/channels/{id} |
Channel card. |
/bots/{id} |
Bot card. |
/moderation/{id} |
Moderation case detail. |
/collectible-usernames/{id} |
Collectible username card. |
/account-ratings/{user_id} |
Account rating card. |
/stars/{user_id} |
Per-account Stars balance and signed history. |
/verification/{id} |
Official verification application detail. |
/bot-verification/{id} |
Third-party verification request detail. |
/emoji/documents |
Documents inside an emoji pack. |
/messages/detail, /messages/private/detail |
Private message detail (?owner_user_id=&msg_id=). |
/messages/groups/detail |
Group message detail (?channel_id=&msg_id=). |
/premium is a permanent alias of /monetization. /messages is an alias of
/messages/private.
An unknown API path returns 404 {"error":"api route not found"}; any unknown
frontend path is served as /.
Response conventions
- Successful reads —
200+ JSON; files (avatars, animations, previews) — the file itself. - Errors — JSON of the form
{"error": "...", "code": "..."}with the corresponding HTTP status. 401— missing/expired session;403— CSRF/Origin violation or missing permission (inrequirePermissionthe body gets an addedpermissionfield);409— optimistic-locking conflict (moderation case, verification);502— Admin API unreachable.- Errors from commands sent to the Admin API are returned as
{"status": ..., "message": ..., "error": ...}.
Common command fields (POST /api/actions/*)
Every mutating request carries in its body:
| Field | Type | Description |
|---|---|---|
command_id |
string | Idempotency key for the command. Repeating the same command_id does not execute the action twice. If empty — generated by the server. |
reason |
string | Mandatory operation reason (audit). |
confirm |
bool | Operator confirmation (true). |
API: dashboard and storage
| Method | Path | Description |
|---|---|---|
| GET | /api/dashboard |
Summary: counts, storage, and optionally host. |
| GET | /api/storage/stats |
Object storage statistics. |
API: accounts
| Method | Path | Parameters / response |
|---|---|---|
| GET | /api/accounts |
Params: q (search), before_id (int64), before_active_us (int64, microseconds), limit (int). Response: query, limit, rows, has_more, next_before_id, next_before_active_us, listing. |
| GET | /api/accounts/{id} |
Account card: profile, flags, statistics. |
| GET | /api/accounts/{id}/avatar |
Account avatar (file). |
| GET | /api/account-ratings |
Params: q, min_level (int), user_id (int64), before_id (int64), limit (int). Response: rows, has_more, next_before_id. |
| GET | /api/account-ratings/{user_id} |
Response: rating, events. |
API: channels and supergroups
| Method | Path | Parameters / response |
|---|---|---|
| GET | /api/channels |
Params: q, before_id (int64), before_updated_us (int64, microseconds), limit (int). Response: query, limit, rows, has_more, next_before_id, next_before_updated_us, listing. |
| GET | /api/channels/{id} |
Channel card. |
| GET | /api/channels/{id}/avatar |
Channel avatar (file). |
API: bots and broadcasts
| Method | Path | Parameters / response |
|---|---|---|
| GET | /api/bots |
Params: q, before_id (int64), limit (int). Response: query, limit, rows, has_more, next_before_id, listing. |
| GET | /api/bots/{id} |
Bot card. |
| GET | /api/broadcasts |
Params: before_id (int64), limit (int). Response: limit, rows, has_more, next_before_id. |
API: media catalogs
| Method | Path | Parameters / response |
|---|---|---|
| GET | /api/emoji |
Params: q, before_id (int64), limit (int). Response: query, rows, has_more, next_before_id, listing. |
| GET | /api/emoji/{id}/animation |
Emoji Lottie animation (file). |
| GET | /api/stickers |
Param: kind (string, type filter). Response: rows, max_items. |
| GET | /api/stickers/{id}/documents |
Response: document_ids. |
| GET | /api/stickers/documents/{id}/animation |
Sticker animation (file). |
| GET | /api/gif-catalog |
Response: proxied from Admin API (/v1/gif-catalog). |
| GET | /api/gif-catalog/documents/{id}/preview |
GIF preview (file). |
API: message audit
| Method | Path | Parameters / response |
|---|---|---|
| GET | /api/messages |
Params: owner_user_id (int64, required with peer_id), peer_id (int64), before_date (int64), before_id (int), limit (int). Response: owner_user_id, peer_id, before_date, before_id, limit, rows. |
| GET | /api/messages/detail |
Params: owner_user_id (int64, req.), msg_id (int, req.). Response: message card. |
| GET | /api/messages/groups |
Params: channel_id (int64, req.), before_date (int64), before_id (int), limit (int). Response: channel_id, before_date, before_id, limit, rows. |
| GET | /api/messages/groups/detail |
Params: channel_id (int64, req.), msg_id (int, req.). Response: message card. |
| GET | /api/live/chats |
Params: user_id (int64, req.), limit (int, 1-200; any other value means 100), before_date (int64), before_peer_id (int64). Response: user_id, chats (PeerType, PeerID, TopMessageID, TopMessageDate, UnreadCount), has_more. A user's dialogs for the live review console, ordered by (top_message_date, peer_id) descending. before_date + before_peer_id is a keyset cursor: for the next page, pass the last row's TopMessageDate and PeerID. The cursor is present when before_peer_id > 0 (before_date may be 0). has_more is true when another page exists. Requires messages.read. |
| GET | /api/live/peers |
Params: users (comma-separated int64), channels (comma-separated int64). Response: users and channels maps of id to display name. Requires messages.read. |
| GET | /api/live/media |
Params: key (location key such as photo:<id> or doc:<id>). Proxies the internal admin API, which reads through the blob backend and sniffs the type from the bytes. Raster images (image/jpeg, image/png, image/gif, image/webp), video/mp4 and audio/* are served inline with that type; anything else is application/octet-stream with Content-Disposition: attachment. Objects over 16 MiB return 413, an empty key returns 400, and an unknown key or a key outside photo:, doc: and blob: returns 404. Served objects and the 413 reply carry X-Content-Type-Options: nosniff, Content-Security-Policy: sandbox and Cache-Control: no-store. Requires messages.read. |
API: star gifts and collectibles
| Method | Path | Parameters / response |
|---|---|---|
| GET | /api/gifts |
Response: Gifts (gift list). |
| GET | /api/auctions |
Response: Auctions — live state of all operator-authored auctions and scheduled drops. |
| GET | /api/official-gifts |
Response: proxied from Admin API (/v1/official-gifts). |
| GET | /api/official-gifts/{id}/animation |
Official gift animation (file). |
| GET | /api/gifts/{id}/animation |
Gift animation (file). |
| GET | /api/gifts/{id}/collectibles |
Response: proxied from Admin API (/v1/gifts/{id}/collectibles). |
| GET | /api/gifts/{id}/collectibles/{kind}/{attribute_id}/animation |
Collectible attribute animation (file). kind ∈ {model, pattern}. |
| GET | /api/collectible-usernames |
Params: status (`` |
| GET | /api/collectible-usernames/{id} |
Response: asset, transfers. |
| GET | /api/collectible-phones |
Params are passed through to the Admin API as-is (/v1/collectible-phones?...). |
| GET | /api/collectible-phones/{id} |
Params are passed through to the Admin API (/v1/collectible-phones/{id}?...). |
API: Premium
All routes in this section require the premium.manage permission (checked both
at the panel and at the Admin API).
| Method | Path | Description |
|---|---|---|
| GET | /api/premium/plans |
Premium plan catalog (proxied to Admin API /v1/premium/plans). |
API: moderation
All reads pass query parameters through to the Admin API as-is
(/v1/moderation/...). Decisions are POST (see below).
| Method | Path | Description |
|---|---|---|
| GET | /api/moderation/cases |
Moderation case list. |
| GET | /api/moderation/cases/{id} |
Moderation case. |
| GET | /api/moderation/reports/{id} |
Report. |
| POST | /api/moderation/cases/{id}/claim |
Claim the case. Body: common fields + version (int64), internal_note (string). |
| POST | /api/moderation/cases/{id}/decide |
Decide the case. Body: common fields + version (int64), internal_note (string). |
| POST | /api/moderation/cases/{id}/appeals/{appeal_id}/review |
Review an appeal. Body: common fields + version (int64), internal_note (string). |
API: official verification
All routes require the verification.review permission. Reads go straight to
PostgreSQL; decisions always go through the Admin API (command journal, state
machine, optimistic locking).
| Method | Path | Parameters / body |
|---|---|---|
| GET | /api/verification/applications |
Params: status, target_type, reviewer, q, before_id, limit. Response: rows, has_more, next_before_id. |
| GET | /api/verification/applications/{id} |
Response: application, events, applicant_controls_target, target_verified. |
| GET | /api/verification/counts |
Application counts by status. |
| POST | /api/verification/applications/{id}/claim |
Decision body: common fields + version (int64), internal_note (string). |
| POST | /api/verification/applications/{id}/approve |
Body: common fields + version (int64), internal_note (string). Grants badge. |
| POST | /api/verification/applications/{id}/reject |
Body: common fields + version (int64), internal_note (string). |
| POST | /api/actions/revoke-verification |
Strip a badge. Requires verification.review and verification.revoke. Body — see actions section below. |
A "decided by another moderator" conflict is returned as 409 Conflict.
API: third-party (bot) verification
A separate mechanism with separate tables, permissions, and routes. Queue reads
and decisions require botverification.review; managing verifiers, the icon
catalog, and stripping marks requires botverification.manage.
| Method | Path | Parameters / body |
|---|---|---|
| GET | /api/botverification/verifiers |
Params: enabled_only (bool), limit (int). Response: rows. |
| GET | /api/botverification/icons |
Params: active_only (bool), limit (int). Response: rows. |
| GET | /api/botverification/marks |
Params: peer_type, verifier_bot_id (int64), q, before_id (int64), limit (int). Response: rows, has_more, next_before_id. |
| GET | /api/botverification/requests |
Params: status, peer_type, verifier_bot_id (int64), q, before_id (int64), limit (int). Response: rows, has_more, next_before_id. |
| GET | /api/botverification/requests/{id} |
Response: request, verifier, mark_active. |
| GET | /api/botverification/counts |
Request counts by status. Response: counts. |
| POST | /api/botverification/requests/{id}/approve |
Decision body: common fields + version (int64), internal_note (string). |
| POST | /api/botverification/requests/{id}/reject |
Body: common fields + version (int64), internal_note (string). |
| POST | /api/botverification/requests/{id}/revoke |
Body: common fields + version (int64), internal_note (string). |
| POST | /api/actions/grant-bot-verifier |
Appoint a bot as verifier. Requires botverification.manage. Body — see below. |
| POST | /api/actions/set-bot-verifier-enabled |
Enable/disable a verifier. Requires botverification.manage. Body — see below. |
| POST | /api/actions/revoke-bot-verifier |
Strip a bot's verifier status. Requires botverification.manage. Body — see below. |
| POST | /api/actions/upsert-verification-icon |
Add/edit a catalog icon. Requires botverification.manage. Body — see below. |
| POST | /api/actions/set-verification-icon-active |
Enable/disable an icon. Requires botverification.manage. Body — see below. |
| POST | /api/actions/revoke-custom-verification |
Strip a third-party mark. Requires botverification.manage. Body — see below. |
API: account actions
All routes are POST /api/actions/..., require a session and CSRF. The request
body always contains the common command fields (command_id, reason,
confirm) plus the fields from the table below.
| Path | Specific body fields | Permission |
|---|---|---|
set-frozen |
user_id (int64), frozen (bool), freeze_until (time, opt.), freeze_appeal_url (string, opt.) |
— |
grant-premium |
user_id (int64), months (int) |
premium.manage |
upsert-premium-plan |
months (int), duration_days (int), amount_stars (int64), fiat_currency (string), fiat_amount (int64), store_product (string), store_quantity (int), enabled (bool), sort_order (int), label (string), expected_version (int64) |
premium.manage |
grant-stars |
user_id (int64), amount (int64) |
— |
debit-stars |
user_id (int64), amount (int64, 1..1000000000); insufficient balance rejects the debit |
— |
set-verified |
user_id (int64), verified (bool) |
— |
set-account-flags |
user_id (int64), scam (bool), fake (bool) |
— |
set-support |
user_id (int64), support (bool) |
— |
set-account-username |
user_id (int64), username (string) |
— |
set-account-profile |
user_id (int64), first_name (string), last_name (string) |
— |
set-account-phone |
user_id (int64), phone (string) |
— |
set-account-login-email |
user_id (int64), email (string) |
— |
set-account-avatar |
multipart: metadata field (JSON with common fields + user_id (int64)) and a file in file |
— |
set-account-color |
user_id (int64), for_profile (bool), has_color (bool), color (int), background_emoji_id (int64) |
— |
set-account-emoji-status |
user_id (int64), document_id (int64), until (int, seconds) |
— |
revoke-sessions |
user_id (int64), hash (int64, opt.), keep_hash (int64, opt.), revoke_all (bool) |
— |
Example (granting Premium, the case from above):
POST /api/actions/grant-premium
Content-Type: application/json
X-CSRF-Token: <csrf from /api/session>
{
"command_id": "grant-premium-001",
"reason": "Incident compensation",
"confirm": true,
"user_id": 123456789,
"months": 12
}
API: machine account lookup (v1)
POST /v1/accounts/resolve-by-phone — bearer-token-protected, read-only
account lookup used by the Telegram store bot's "fetch my ID" flow. It resolves
the numeric account ID from a phone number without viewer privacy projection,
so the bot can auto-save a user's server ID when they have already set up an
account there. Unlike every /api/actions/... route it carries no command
metadata, because the endpoint never mutates state and writes no audit entry.
| Field | Type | Description |
|---|---|---|
phone |
string | Phone in any formatting (spaces, dashes, leading +); normalized server-side by domain.NormalizePhone. |
Response 200 OK:
| Field | Type | Description |
|---|---|---|
found |
bool | Whether an account with this phone exists. |
user_id |
int64 | The numeric account ID; 0 when found is false. |
Errors: 401 — invalid/absent bearer token; 500 — lookup failure;
501 — deployment built without a lookup backend. Missing numbers are a
success with found: false, never 404.
Example:
POST /v1/accounts/resolve-by-phone
Authorization: Bearer <token>
Content-Type: application/json
{ "phone": "+79991234567" }
// 200
{ "found": true, "user_id": 1780243207 }
API: channel actions
| Path | Specific body fields | Permission |
|---|---|---|
set-channel-flags |
channel_id (int64), scam (bool), fake (bool) |
— |
set-channel-settings |
channel_id (int64), gigagroup (*bool), antispam (*bool), participants_hidden (*bool), noforwards (*bool), join_to_send (*bool), join_request (*bool), slowmode_seconds (*int) — all optional pointers |
— |
set-channel-username |
channel_id (int64), username (string) |
— |
set-channel-color |
channel_id (int64), for_profile (bool), has_color (bool), color (int), background_emoji_id (int64) |
— |
set-channel-emoji-status |
channel_id (int64), document_id (int64), until (int) |
— |
set-channel-avatar |
multipart: metadata (JSON with common fields + channel_id (int64)) and a file file |
— |
set-channel-verified |
channel_id (int64), verified (bool) |
— |
API: bot actions
| Path | Specific body fields | Permission |
|---|---|---|
create-bot |
owner_user_id (int64), name (string), username (string) |
— |
delete-bot |
bot_user_id (int64) |
— |
export-bot-token |
bot_user_id (int64) |
bots.token.read |
create-broadcast |
message (string), target_mode (string), user_ids ([]int64, opt.) |
— |
API: sticker and emoji actions
| Path | Specific body fields | Permission |
|---|---|---|
create-sticker-set |
multipart: metadata (JSON: common fields + title, short_name, kind, emoji, keywords) and a file file |
— |
rename-sticker-set |
set_id (int64), title (string) |
— |
add-sticker-to-set |
multipart: metadata (JSON: common fields + set_id (string), emoji, keywords) and a file file |
— |
remove-sticker-from-set |
set_id (int64), document_id (int64) |
— |
set-sticker-set-archived |
set_id (int64), archived (bool) |
— |
set-sticker-set-sort-order |
set_id (int64), sort_order (int) |
— |
delete-sticker-set |
set_id (int64) |
— |
API: GIF catalog actions
| Path | Specific body fields | Permission |
|---|---|---|
create-gif-catalog-entry |
multipart: metadata (JSON: common fields + title) and a file file |
— |
set-gif-catalog-enabled |
id (int64, sent as string), enabled (bool) |
— |
set-gif-catalog-sort-order |
id (int64, string), sort_order (int) |
— |
delete-gif-catalog-entry |
id (int64, string) |
— |
API: gift and collectible actions
| Path | Specific body fields | Permission |
|---|---|---|
import-gift |
multipart: metadata (JSON: common fields + gift_id (int64), title, stars (int64), convert_stars (int64), enabled (bool), sort_order (int), auction (bool), auction_slug, gifts_per_round (int), auction_start_date (int), auction_round_duration (int), availability_total (int), locked_until_date (int)) and a file file |
— |
import-official-gift |
common fields + source_gift_id (string), gift_id (int64), title, stars (int64), convert_stars (int64), enabled (bool), sort_order (int), include_collectible (bool), upgrade_stars (int64), supply_total (int), slug_prefix (string), locked_until_date (int) |
— |
publish-gift-collectibles |
multipart, gift_id sent in query (?gift_id=): metadata (JSON: common fields + upgrade_stars (int64), supply_total (int), slug_prefix (string), models ([]object), patterns ([]object), backdrops ([]object)); animations are files keyed by the models/patterns entries |
— |
set-gift-enabled |
gift_id (int64), enabled (bool) |
— |
set-gift-sort-order |
gift_id (int64), sort_order (int) |
— |
give-gift |
common fields + sender_user_id (int64), user_id (int64), channel_id (int64), gift_id (int64), hide_name (bool), message (string), upgrade (bool), model_attribute_id (int64), pattern_attribute_id (int64), backdrop_attribute_id (int64) |
— |
set-nft-gift-wallet |
common fields + ref (string: slug, NFT address or numeric id), wallet_name (string, defaults to the typed wallet_address value), wallet_address (string: a TON mainnet address; a .ton name resolved on chain through TON DNS, falling back to the flashfragment username of the same name when DNS has no record; or a Telegram identity — rayo, @rayo, rayo.t.me, t.me/rayo — resolved only through flashfragment records: username claim, username mint, verified wallet of the collectible username owner, TON Connect. The typed name is never stored as an address, and the record that matched is reported as wallet_source in details), host_user_id (int64, optional), clear (bool, releases the gift back to its Telegram owner instead of binding a wallet) |
— |
API: collectible username actions
| Path | Specific body fields | Permission |
|---|---|---|
mint-collectible-username |
username (string), owner_user_id (int64), owner_channel_id (int64), currency (string), amount (int64), crypto_currency (string), crypto_amount (int64), url (string), purchase_date (int/unix or date) |
— |
transfer-collectible-username |
username (string), to_user_id (int64), to_channel_id (int64) |
— |
revoke-collectible-username |
username (string), burn (bool) |
— |
delete-collectible-username |
username (string) |
— |
API: anonymous number actions
| Path | Specific body fields | Permission |
|---|---|---|
mint-collectible-phone |
phone (string), tier (string), owner_user_id (int64), currency (string), amount (int64), crypto_currency (string), crypto_amount (int64), url (string), purchase_date (int/unix or date) |
— |
update-collectible-phone-price |
phone (string), currency (string), amount (int64), crypto_currency (string), crypto_amount (int64) |
— |
transfer-collectible-phone |
phone (string), to_user_id (int64) |
— |
revoke-collectible-phone |
phone (string), burn (bool) |
— |
delete-collectible-phone |
phone (string) |
— |
Gift inventory when importing or replacing a revision
For a new official gift, enabling include_collectible uses supply_total as
both the unique-gift supply and the base gift's initial sales cap. If omitted,
the collectible supply is derived from the snapshot's availability or upgrade
variants. With collectible import disabled, this input does not limit ordinary
base gifts. Auctions still require their own finite supply.
An existing gift_id keeps its original base supply, limited flag, remaining
stock, resale counters and sale dates. Replacement never replenishes exhausted
stock or converts it to unlimited. A different base cap or auction/non-auction
mode requires a new gift identity; requesting it on an existing identity fails
without publishing either revision. The separate collectible-pool editor does
not change base stock. Inventory is rechecked under the purchase/catalog lock
at execution, and the result reports the committed remaining stock. Dry-run
does not reserve stock. The catalog badge shows remaining / total copies.
API: account rating actions
| Path | Specific body fields | Permission |
|---|---|---|
recompute-account-rating |
user_id (int64) |
— |
adjust-account-rating |
user_id (int64), amount (int64) |
— |
API: message deletion
| Path | Specific body fields | Permission |
|---|---|---|
delete-messages |
owner_user_id (int64), peer_id (int64), ids ([]int), revoke (bool) |
— |
delete-history |
owner_user_id (int64), peer_id (int64), max_id (int), min_date (int), max_date (int), max_batches (int), just_clear (bool), revoke (bool) |
— |
API: verification decisions (request bodies)
Official verification — revoke-verification:
| Field | Type | Description |
|---|---|---|
target_type |
string | Target type (user / channel, etc., validated by domain.VerificationTargetType.Valid()). |
target_id |
int64 | Target identifier (not the application!). |
internal_note |
string | Operator-only internal note (opt.). |
| + common fields | command_id, reason, confirm. |
Third-party verification — verifier/mark actions (botverification.manage):
| Path | Specific body fields |
|---|---|
grant-bot-verifier |
bot_id (int64), icon_document_id (int64), company_name (string, req.), default_description (string), can_modify_custom_description (bool), version (int64, 0 for new) |
set-bot-verifier-enabled |
bot_id (int64), enabled (bool) |
revoke-bot-verifier |
bot_id (int64) |
upsert-verification-icon |
document_id (int64), name (string, req.), owner_bot_id (int64, opt., 0 = shared) |
set-verification-icon-active |
icon_id (int64), active (bool) |
revoke-custom-verification |
verifier_bot_id (int64), peer_type (string, validated), peer_id (int64) |
All of these also carry the common fields (command_id, reason, confirm).