git clone https://github.com/TONresistor/teleton-plugins
git clone --depth=1 https://github.com/TONresistor/teleton-plugins ~/.claude/skills/tonresistor-teleton-plugins-teleton-plugins
SKILL.md- eval/exec/Function constructor
- references API keys
Teleton Plugin Builder
You are building a plugin for Teleton, a Telegram AI agent on TON. Ask the user what plugin or tools they want to build, then follow this workflow.
Reference documentation
Before building, read the relevant reference files from the teleton-plugins repo:
- Full rules & SDK reference:
— complete guide with tool definition, SDK API tables, error handling, lifecycle, best practices, testingCONTRIBUTING.md - Simple plugin example:
— Pattern A (array of tools, no SDK)plugins/example/index.js - SDK plugin example:
— Pattern B (tools(sdk) with database, TON balance, Telegram messaging)plugins/example-sdk/index.js - Advanced SDK plugin:
— real-world SDK plugin with TON payments, payment verification, isolated database, payout logicplugins/casino/index.js - Registry:
— list of all existing plugins (check for name conflicts)registry.json - README.md — project overview, plugin list, SDK section
Read at least
CONTRIBUTING.md and the relevant example before building.
Workflow
- Ask the user what they want (plugin name, what it does, which API or bot)
- Decide — determine if the plugin needs the SDK (see decision tree below)
- Plan — present a structured plan and ask for validation
- Build — create all files once the user approves
- Install — copy to
and restart~/.teleton/plugins/
Step 1 — Understand the request
Determine:
- Plugin name — short, lowercase folder name (e.g.
,pic
,deezer
)weather - Plugin type:
- Inline bot — wraps a Telegram inline bot (@pic, @vid, @gif, @DeezerMusicBot…)
- Public API — calls an external REST API, no auth
- Auth API — external API with Telegram WebApp auth
- Local logic — pure JavaScript, no external calls
- Tools — list of tool names, what each does, parameters
- Does it need GramJS? — yes for inline bots and WebApp auth
- Does it need the SDK? — use the decision tree below
SDK Decision Tree
The Plugin SDK (
tools(sdk)) gives high-level access to TON, Telegram, database, logging, and config. Use it only when needed — simpler plugins should use Pattern A.
Use
(Pattern B) if ANY of these apply:tools(sdk)
| Need | SDK namespace | Example |
|---|---|---|
| Check TON balance or wallet address | , | Casino checking balance before payout |
| Send TON or verify payments | , | Casino auto-payout, paid services |
| Get TON price or transactions | , | Portfolio tracker |
| Query jetton balances or metadata | , | Token portfolio, DEX tools |
| Send jettons (TEP-74 transfers) | | Token payments, swaps |
| Query NFT items or metadata | , | NFT gallery, collection tools |
| Convert TON units or validate addresses | , , | Any TON plugin |
| Send Telegram messages programmatically | | Announcements, notifications |
| Edit messages or send reactions | , | Interactive UIs |
| Send dice/slot animations | | Casino dice game |
| Send media (photos, videos, files, stickers) | , | Media bots, file sharing |
| Delete, forward, pin, or search messages | , | Moderation, archival |
| Schedule messages | | Reminders, timed announcements |
| Create polls or quizzes | , | Engagement, trivia bots |
| Moderate users (ban/mute/unban) | , | Group moderation |
| Stars & gifts (balance, send, buy) | , | Gift trading, rewards |
| Post stories | | Promotional content |
| Lookup users, chats, or participants | , | Analytics, admin tools |
| Need an isolated database | (requires ) | Tracking user scores, history, state |
| Key-value storage with TTL | (auto-created, no migrate needed) | Caching, rate limits, temp state |
| Manage API keys or secrets | | Plugins that call authenticated APIs |
| Plugin-specific config with defaults | + | Customizable thresholds, modes |
| Structured logging | , | Debug, monitoring |
| Swap tokens on DEX | , | DEX aggregator, trading bots |
| Compare DEX prices (STON.fi vs DeDust) | , | Arbitrage, price comparison |
| Check/register .ton domains | , | Domain tools, DNS management |
| Auction .ton domains | , | Domain marketplace |
| Link domain to wallet or TON Site | , | Domain configuration |
| Jetton analytics (price, holders, history) | , | Token analytics, dashboards |
| Manage scheduled messages | , | Schedulers, reminders |
| Browse conversations or message history | , | Analytics, search tools |
| Collectibles & unique gifts | , | NFT gift trading, valuation |
| Inline bot features (queries, buttons) | , | Inline bots, interactive UIs |
| Observe agent events (hooks) | | Audit, logging, enrichment |
Use
(Pattern A) if ALL of these apply:tools = [...]
- Only calls external APIs (REST, GraphQL) — no TON blockchain interaction
- Does not need to send Telegram messages from code (only returns data to LLM)
- Does not need persistent state (no database)
- Does not need plugin-specific config
Examples:
| Plugin | Pattern | Why |
|---|---|---|
| A (array) | Calls Open-Meteo API, returns data |
| A (array) | Calls Gas111 API, uses WebApp auth |
| B (SDK) | Uses for inline bot |
| B (SDK) | Needs sdk.ton (payments), sdk.telegram (dice), sdk.db (history) |
| B (SDK) | Needs sdk.db (counters), sdk.ton (balance), sdk.telegram (messages) |
Note: Inline bots and WebApp auth plugins can use either
context.bridge.getClient().getClient() (Pattern A with permissions: ["bridge"]) or sdk.telegram.getRawClient() (Pattern B, preferred).
Step 2 — Present the plan
Show this to the user and wait for approval:
Plugin: [name] Pattern: [A (simple) | B (SDK)] Reason: [why SDK is/isn't needed] Tools: | Tool | Description | Params | |-------------|--------------------------|-------------------------------------| | `tool_name` | What it does | `query` (string, required), `index` (int, optional) | SDK features used: [none | sdk.ton, sdk.db, sdk.telegram, sdk.log, sdk.pluginConfig] Files: - plugins/[name]/index.js - plugins/[name]/manifest.json - plugins/[name]/README.md - registry.json (update)
Do NOT build until the user says go.
Step 3 — Build
Create all files in
plugins/[name]/ following the patterns below.
index.js
ESM only — always
export const tools, never module.exports.
Choose the right pattern:
Pattern A: Simple tools (array)
For plugins that don't need TON, Telegram messaging, or persistent database.
Reference:
plugins/example/index.js
const myTool = { name: "tool_name", description: "The LLM reads this to decide when to call the tool. Be specific.", parameters: { type: "object", properties: { query: { type: "string", description: "Search query" }, index: { type: "integer", description: "Which result (0 = first)", minimum: 0, maximum: 49 }, }, required: ["query"], }, execute: async (params, context) => { try { // logic here return { success: true, data: { result: "..." } }; } catch (err) { return { success: false, error: String(err.message || err).slice(0, 500) }; } }, }; export const tools = [myTool];
Pattern B: SDK tools (function)
For plugins that need TON blockchain, Telegram messaging, isolated database, or config.
Reference:
plugins/example-sdk/index.js (basic), plugins/casino/index.js (advanced)
export const manifest = { name: "my-plugin", version: "1.0.0", sdkVersion: ">=1.0.0", description: "What this plugin does", defaultConfig: { some_setting: "default_value", }, }; // Optional: export migrate() to get sdk.db (isolated SQLite per plugin) export function migrate(db) { db.exec(`CREATE TABLE IF NOT EXISTS my_table ( id TEXT PRIMARY KEY, value TEXT )`); } export const tools = (sdk) => [ { name: "my_tool", description: "What this tool does", parameters: { type: "object", properties: {}, }, scope: "always", // "always" | "dm-only" | "group-only" | "admin-only" category: "data-bearing", // "data-bearing" (reads/queries) | "action" (writes/modifies) execute: async (params, context) => { try { // SDK namespaces: // sdk.ton — getAddress(), getBalance(), getPrice(), sendTON(), getTransactions(), verifyPayment() // getPublicKey(), getWalletVersion(), createJettonTransfer() // getJettonBalances(), getJettonInfo(), sendJetton(), getJettonWalletAddress() // getNftItems(), getNftInfo(), toNano(), fromNano(), validateAddress() // sdk.telegram — sendMessage(), editMessage(), deleteMessage(), forwardMessage(), pinMessage() // sendDice(), sendReaction(), getMessages(), searchMessages(), getReplies() // sendPhoto(), sendVideo(), sendVoice(), sendFile(), sendGif(), sendSticker() // downloadMedia(), setTyping(), getChatInfo(), getUserInfo(), resolveUsername() // getParticipants(), createPoll(), createQuiz(), banUser(), unbanUser(), muteUser() // getStarsBalance(), sendGift(), getAvailableGifts(), getMyGifts(), getResaleGifts() // buyResaleGift(), sendStory(), scheduleMessage(), getMe(), isAvailable(), getRawClient() // sdk.db — better-sqlite3 instance (null if no migrate()) // sdk.storage — get(), set(key, val, {ttl?}), delete(), has(), clear() — auto-created KV, no migrate needed // sdk.secrets — get(key), require(key), has(key) — resolves ENV → secrets file → pluginConfig // sdk.log — info(), warn(), error(), debug() // sdk.config — sanitized app config (no secrets) // sdk.pluginConfig — plugin-specific config from config.yaml merged with defaultConfig // sdk.bot — isAvailable, username, onInlineQuery(), onCallback(), onChosenResult(), // editInlineMessage(), keyboard() — null if no bot manifest // sdk.on — on(hookName, handler, opts?) — 13 hooks: tool:before/after/error, // prompt:before/after, session:start/end, message:receive, etc. const balance = await sdk.ton.getBalance(); sdk.log.info(`Balance: ${balance?.balance}`); return { success: true, data: { balance: balance?.balance } }; } catch (err) { return { success: false, error: String(err.message || err).slice(0, 500) }; } }, }, ]; // Optional: runs after Telegram bridge connects export async function start(ctx) { // ctx.bridge, ctx.db, ctx.config, ctx.pluginConfig, ctx.log } // Optional: runs on shutdown export async function stop() { // cleanup }
SDK error handling:
- Read methods (
,getBalance
,getPrice
,getTransactions
,getMessages
,getJettonBalances
) returngetNftItems
ornull
on failure — never throw[] - Write methods (
,sendTON
,sendJetton
,createJettonTransfer
,sendMessage
,sendDice
,sendPhoto
) throwbanUser
withPluginSDKError
:.code
— wallet not set upWALLET_NOT_INITIALIZED
— bad TON addressINVALID_ADDRESS
— Telegram not readyBRIDGE_NOT_CONNECTED
—SECRET_NOT_FOUND
called for missing secretsdk.secrets.require()
— generic failureOPERATION_FAILED
GramJS import (only if plugin needs raw Telegram MTProto)
import { createRequire } from "node:module"; import { realpathSync } from "node:fs"; const _require = createRequire(realpathSync(process.argv[1])); const { Api } = _require("telegram");
Per-plugin npm dependencies
Plugins can have their own npm deps. Add
package.json + package-lock.json to the plugin folder — teleton auto-installs at startup via npm ci --ignore-scripts.
Use two
createRequire instances to separate core and plugin-local deps:
import { createRequire } from "node:module"; import { realpathSync } from "node:fs"; // Core deps (from teleton runtime) const _require = createRequire(realpathSync(process.argv[1])); // Plugin-local deps (from plugin's node_modules/) const _pluginRequire = createRequire(import.meta.url); const { Address } = _require("@ton/core"); // core const { getHttpEndpoint } = _pluginRequire("@orbs-network/ton-access"); // plugin-local
Setup:
cd plugins/your-plugin && npm init -y && npm install <deps>. Commit both package.json and package-lock.json. The node_modules/ folder is auto-created at startup.
With SDK plugins, prefer
sdk.telegram.getRawClient() over context.bridge.getClient().getClient().
API fetch helper (for plugins calling external APIs)
const API_BASE = "https://api.example.com"; async function apiFetch(path, params = {}) { const url = new URL(path, API_BASE); for (const [key, value] of Object.entries(params)) { if (value !== undefined && value !== null) { url.searchParams.set(key, String(value)); } } const res = await fetch(url, { signal: AbortSignal.timeout(15000) }); if (!res.ok) { throw new Error(`API error: ${res.status} ${await res.text().catch(() => "")}`); } return res.json(); }
Inline bot pattern (@pic, @vid, @gif, @DeezerMusicBot…)
Preferred (SDK Pattern B) — define tools inside the
(sdk) => [...] closure:
export const tools = (sdk) => [{ name: "my_inline_bot", description: "...", parameters: { ... }, execute: async (params, context) => { const client = sdk.telegram.getRawClient(); // ... same GramJS API calls }, }];
Legacy (Pattern A) — uses
context.bridge directly:
execute: async (params, context) => { try { const client = context.bridge.getClient().getClient(); const bot = await client.getEntity("BOT_USERNAME"); const peer = await client.getInputEntity(context.chatId); const results = await client.invoke( new Api.messages.GetInlineBotResults({ bot, peer, query: params.query, offset: "", }) ); if (!results.results || results.results.length === 0) { return { success: false, error: `No results found for "${params.query}"` }; } const index = params.index ?? 0; if (index >= results.results.length) { return { success: false, error: `Only ${results.results.length} results, index ${index} out of range` }; } const chosen = results.results[index]; await client.invoke( new Api.messages.SendInlineBotResult({ peer, queryId: results.queryId, id: chosen.id, randomId: BigInt(Math.floor(Math.random() * 2 ** 62)), }) ); return { success: true, data: { query: params.query, sent_index: index, total_results: results.results.length, title: chosen.title || null, description: chosen.description || null, type: chosen.type || null, }, }; } catch (err) { return { success: false, error: String(err.message || err).slice(0, 500) }; } }
WebApp auth pattern (Telegram-authenticated APIs)
let cachedAuth = null; let cachedAuthTime = 0; const AUTH_TTL = 30 * 60 * 1000; async function getAuth(bridge, botUsername, webAppUrl) { if (cachedAuth && Date.now() - cachedAuthTime < AUTH_TTL) return cachedAuth; const client = bridge.getClient().getClient(); const bot = await client.getEntity(botUsername); const result = await client.invoke( new Api.messages.RequestWebView({ peer: bot, bot, platform: "android", url: webAppUrl }) ); const fragment = new URL(result.url).hash.slice(1); const initData = new URLSearchParams(fragment).get("tgWebAppData"); if (!initData) throw new Error("Failed to extract tgWebAppData"); cachedAuth = initData; cachedAuthTime = Date.now(); return cachedAuth; }
Payment verification pattern (SDK)
Reference:
plugins/casino/index.js
export function migrate(db) { db.exec(`CREATE TABLE IF NOT EXISTS used_transactions ( tx_hash TEXT PRIMARY KEY, user_id TEXT NOT NULL, amount REAL NOT NULL, game_type TEXT NOT NULL, used_at INTEGER NOT NULL DEFAULT (unixepoch()) )`); } export const tools = (sdk) => [{ name: "verify_and_process", execute: async (params, context) => { const payment = await sdk.ton.verifyPayment({ amount: params.amount, memo: params.username, gameType: "my_service", maxAgeMinutes: 10, }); if (!payment.verified) { const address = sdk.ton.getAddress(); return { success: false, error: `Send ${params.amount} TON to ${address} with memo: ${params.username}` }; } // Process the verified payment... // payment.playerWallet — sender's address (for refunds/payouts) // payment.compositeKey — unique tx identifier // payment.amount — verified amount return { success: true, data: { verified: true, from: payment.playerWallet } }; } }];
manifest.json
{ "id": "PLUGIN_ID", "name": "Display Name", "version": "1.0.0", "description": "One-line description", "author": { "name": "teleton", "url": "https://github.com/TONresistor" }, "license": "MIT", "entry": "index.js", "teleton": ">=1.0.0", "tools": [ { "name": "tool_name", "description": "Short description" } ], "permissions": [], "tags": ["tag1", "tag2"], "repository": "https://github.com/TONresistor/teleton-plugins", "funding": null }
Notes:
- Add
only if using"sdkVersion": ">=1.0.0"
(Pattern B)tools(sdk) - Add
only if using"permissions": ["bridge"]
directly (not needed with SDK)context.bridge
ispermissions
for most plugins[]- Add
to declare required/optional secrets (see Secrets section below)"secrets"
Declaring secrets in manifest
If your plugin needs API keys or other secrets, declare them in the manifest:
{ "secrets": { "api_key": { "required": true, "description": "API key for service X" }, "webhook_url": { "required": false, "description": "Optional webhook endpoint" } } }
Then access them via
sdk.secrets.get("api_key") or sdk.secrets.require("api_key") in your tools.
README.md
# Plugin Name One-line description. | Tool | Description | |------|-------------| | `tool_name` | What it does | ## Install mkdir -p ~/.teleton/plugins cp -r plugins/PLUGIN_ID ~/.teleton/plugins/ ## Usage examples - "Natural language prompt the user would say" - "Another example prompt" ## Tool schema ### tool_name | Param | Type | Required | Default | Description | |-------|------|----------|---------|-------------| | `query` | string | Yes | — | Search query |
registry.json
Add to the
plugins array:
{ "id": "PLUGIN_ID", "name": "Display Name", "description": "One-line description", "author": "teleton", "tags": ["tag1", "tag2"], "path": "plugins/PLUGIN_ID" }
Step 4 — Install and commit
- Copy:
cp -r plugins/PLUGIN_ID ~/.teleton/plugins/ - Commit:
git add plugins/PLUGIN_ID/ registry.json && git commit -m "PLUGIN_NAME: short description" - Ask user if they want to push.
Rules
- ESM only —
, neverexport const toolsmodule.exports - JS only — the plugin loader reads
files only.js - Tool names —
, globally unique across all plugins, prefixed with plugin namesnake_case - Defaults — use
(nullish coalescing), never??|| - Errors — always try/catch in execute, return
, slice to 500 chars{ success: false, error } - Timeouts —
on all external fetch callsAbortSignal.timeout(15000) - Per-plugin npm deps — plugins needing external packages add
+package.json
; teleton auto-installs at startup. Use the dual-require pattern (see below)package-lock.json - GramJS — always
, nevercreateRequire(realpathSync(process.argv[1]))import from "telegram" - Client chain —
ORcontext.bridge.getClient().getClient()
for raw GramJSsdk.telegram.getRawClient() - SDK preferred — when using SDK, prefer
oversdk.telegram
,context.bridge
oversdk.dbcontext.db - Scope — add
on financial/private tools,scope: "dm-only"
on moderation tools,scope: "group-only"
for admin-only toolsscope: "admin-only" - Category — add
for read/query tools,category: "data-bearing"
for write/modify toolscategory: "action" - Secrets — use
instead of hardcoded keys; declare insdk.secretsmanifest.secrets - Storage — prefer
for caching and temp state oversdk.storage
(nosdk.db
needed)migrate() - SDK decision — only use Pattern B if the plugin actually needs TON, Telegram messaging, database, secrets, storage, or config (see decision tree)
Context object
Available in
execute(params, context) for all plugins (Pattern A and B):
| Field | Type | Description |
|---|---|---|
| TelegramBridge | Send messages, reactions, media (low-level) |
| Database | SQLite (shared — prefer for isolation) |
| string | Current chat ID |
| number | Telegram user ID of caller |
| boolean | = group, = DM |
| Config? | Agent config (may be undefined) |
SDK object
Available only in
tools(sdk) function plugins (Pattern B):
| Namespace | Methods |
|---|---|
| Wallet: , , , , , , , |
Jettons: , , , , | |
NFT: , | |
Utilities: , , | |
| Messages: , , , , , , , , |
Media: , , , , , , , | |
Social: , , , | |
Interactive: , , , | |
Moderation: , , | |
Stars & Gifts: , , , , , | |
Stories: | |
Core: , , | |
| instance (requires ) |
| , , , , — auto-created KV store with optional TTL, no needed |
| , , — resolves from: ENV var () → secrets file → |
| , , , |
| Sanitized app config (no API keys) |
| Plugin config from merged with |
| (getter), (getter), , , , , — if no bot in manifest |
| — 13 hooks: , , , , , , , , , , , , |
sdk.secrets — Secret management
Resolves secrets from multiple sources in priority order: environment variable (
PLUGINNAME_KEY) → secrets store (~/.teleton/plugins/data/name.secrets.json) → pluginConfig.
// Check if a secret is available if (sdk.secrets.has("api_key")) { const key = sdk.secrets.get("api_key"); // string | undefined } // Require a secret (throws PluginSDKError with code SECRET_NOT_FOUND if missing) const apiKey = sdk.secrets.require("api_key");
Declare required secrets in
manifest.json so users know what to configure:
{ "secrets": { "api_key": { "required": true, "description": "API key for service X" } } }
sdk.storage — Key-value storage with TTL
Auto-created
_kv table — no migrate() export needed. Returns null if no database is available.
// Set a value with optional TTL (milliseconds) sdk.storage.set("rate_limit:user123", { count: 1 }, { ttl: 60000 }); // expires in 60s // Get a value (returns undefined if missing or expired) const data = sdk.storage.get("rate_limit:user123"); // Check existence (respects TTL) if (sdk.storage.has("rate_limit:user123")) { /* ... */ } // Delete a key (returns true if it existed) sdk.storage.delete("rate_limit:user123"); // Clear all keys for this plugin sdk.storage.clear();
sdk.bot — Inline bot features
null if no bot field in manifest.json. Provides inline query handling, callback buttons, and keyboard building.
// Check if bot is available if (sdk.bot.isAvailable) { const botName = sdk.bot.username; // string — bot username // Register inline query handler sdk.bot.onInlineQuery(async (query) => { // handle inline query }); // Register callback handler for a pattern sdk.bot.onCallback("action:*", async (data) => { // handle callback }); // Register chosen inline result handler sdk.bot.onChosenResult(async (result) => { // handle chosen result }); // Edit an inline message await sdk.bot.editInlineMessage(inlineMessageId, "Updated text", { parseMode: "HTML" }); // Build a keyboard const kb = sdk.bot.keyboard([ [{ text: "Button 1", callback: "action:1" }, { text: "Button 2", callback: "action:2" }], ]); // BotKeyboard }
sdk.on — Event hooks
Register handlers for agent lifecycle and tool execution events. 13 hook types available.
// Tool hooks sdk.on("tool:before", (event) => { /* before any tool executes */ }); sdk.on("tool:after", (event) => { /* after any tool executes */ }); sdk.on("tool:error", (event) => { /* when a tool throws */ }); // Prompt hooks sdk.on("prompt:before", (event) => { /* before prompt is sent to LLM */ }); sdk.on("prompt:after", (event) => { /* after LLM responds */ }); // Session hooks sdk.on("session:start", (event) => { /* session begins */ }); sdk.on("session:end", (event) => { /* session ends */ }); // Message hooks sdk.on("message:receive", (event) => { /* incoming message */ }); // Response hooks sdk.on("response:before", (event) => { /* before response is sent */ }); sdk.on("response:after", (event) => { /* after response is sent */ }); sdk.on("response:error", (event) => { /* response error */ }); // Agent hooks sdk.on("agent:start", (event) => { /* agent starts */ }); sdk.on("agent:stop", (event) => { /* agent stops */ }); // Optional: pass options sdk.on("tool:after", handler, { priority: 10 });
sdk.ton — Jetton & NFT methods
Jettons (TEP-74)
// Get all jetton balances for the agent wallet (or a specific address) const balances = await sdk.ton.getJettonBalances(); // JettonBalance[] const otherBalances = await sdk.ton.getJettonBalances("UQ..."); // Get jetton metadata const info = await sdk.ton.getJettonInfo("EQ...jetton_master"); // JettonInfo | null // Send jettons const result = await sdk.ton.sendJetton( "EQ...jetton_master", // jetton master address "UQ...recipient", // destination "1000000000", // amount in smallest units { comment: "payment" } // optional ); // JettonSendResult // Get jetton wallet address const wallet = await sdk.ton.getJettonWalletAddress("UQ...owner", "EQ...jetton"); // string | null
NFTs
// Get all NFTs for the agent wallet (or a specific address) const nfts = await sdk.ton.getNftItems(); // NftItem[] // Get NFT metadata const nft = await sdk.ton.getNftInfo("EQ...nft_address"); // NftItem | null
Wallet info
const pubKey = sdk.ton.getPublicKey(); // string | null — hex ed25519 public key const version = sdk.ton.getWalletVersion(); // string — always "v5r1"
Jetton transfer (sign without broadcast)
// Sign a jetton transfer (TEP-74) without broadcasting const transfer = await sdk.ton.createJettonTransfer( "EQ...jetton_master", // jetton master address "UQ...recipient", // destination "1000000000", // amount in smallest units { comment: "payment" } // optional ); // SignedTransfer — throws WALLET_NOT_INITIALIZED, OPERATION_FAILED
Utilities
const nano = sdk.ton.toNano(1.5); // bigint — 1500000000n const tons = sdk.ton.fromNano(1500000000n); // string — "1.5" const valid = sdk.ton.validateAddress("UQ..."); // boolean
sdk.telegram — Extended methods
Media
// photo/video/voice/file/gif can be a file path (string) or Buffer await sdk.telegram.sendPhoto(chatId, "/path/to/image.jpg", { caption: "Look!" }); await sdk.telegram.sendVideo(chatId, videoBuffer, { caption: "Video" }); await sdk.telegram.sendVoice(chatId, voiceBuffer, { caption: "Listen" }); await sdk.telegram.sendFile(chatId, "/path/to/doc.pdf", { caption: "Document" }); await sdk.telegram.sendGif(chatId, gifBuffer); await sdk.telegram.sendSticker(chatId, stickerBuffer); // Download media from a message const buffer = await sdk.telegram.downloadMedia(chatId, messageId); // Buffer | null // Show typing indicator await sdk.telegram.setTyping(chatId);
Message management
await sdk.telegram.deleteMessage(chatId, messageId, true); // revoke=true deletes for everyone await sdk.telegram.forwardMessage(fromChatId, toChatId, messageId); await sdk.telegram.pinMessage(chatId, messageId, { silent: true }); const results = await sdk.telegram.searchMessages(chatId, "query", 20); const replies = await sdk.telegram.getReplies(chatId, messageId, 10); await sdk.telegram.scheduleMessage(chatId, "Reminder!", new Date("2026-03-01T10:00:00Z"));
Social & lookup
const chat = await sdk.telegram.getChatInfo(chatId); // ChatInfo | null const user = await sdk.telegram.getUserInfo(userId); // UserInfo | null const peer = await sdk.telegram.resolveUsername("username"); // ResolvedPeer | null const members = await sdk.telegram.getParticipants(chatId, 100); // UserInfo[]
Interactive
await sdk.telegram.createPoll(chatId, "Favorite color?", ["Red", "Blue", "Green"], { anonymous: false }); await sdk.telegram.createQuiz(chatId, "2+2=?", ["3", "4", "5"], 1, "Basic math!");
Moderation
await sdk.telegram.banUser(chatId, userId); await sdk.telegram.unbanUser(chatId, userId); await sdk.telegram.muteUser(chatId, userId, Math.floor(Date.now() / 1000) + 3600); // mute 1h
Stars & Gifts
const balance = await sdk.telegram.getStarsBalance(); // number await sdk.telegram.sendGift(userId, giftId, { message: "Enjoy!" }); const gifts = await sdk.telegram.getAvailableGifts(); // StarGift[] const mine = await sdk.telegram.getMyGifts(10); // ReceivedGift[] const resale = await sdk.telegram.getResaleGifts(10); // StarGift[] await sdk.telegram.buyResaleGift(giftId);
Stories
await sdk.telegram.sendStory("/path/to/media.jpg", { caption: "Check this out!" });
Raw GramJS client
const client = sdk.telegram.getRawClient(); // raw GramJS TelegramClient | null // Use for inline bots, WebApp auth, custom MTProto calls
SDK Types reference
| Type | Key fields |
|---|---|
| , , (name, symbol, decimals, image) |
| , , (name, symbol, decimals, image, description) |
| , , |
| Signed transfer BOC (from ) |
| , , (name, description, image), |
| , , , , |
| , , , , , |
| , , |
| , , |
| , , |
| , , , , |
| , , , , |
| (boolean), (string) |
| , , , , |
| , , |
| | |
| , , , , |
Bridge methods (legacy)
Only needed for Pattern A plugins that use
context.bridge directly:
await context.bridge.sendMessage({ chatId, text, replyToId?, inlineKeyboard? }); await context.bridge.sendReaction(chatId, messageId, emoji); await context.bridge.editMessage({ chatId, messageId, text, inlineKeyboard? }); await context.bridge.setTyping(chatId); const msgs = await context.bridge.getMessages(chatId, limit); const peer = context.bridge.getPeer(chatId); const gramjs = context.bridge.getClient().getClient();