# Teleton Plugin SDK — Complete Reference > @teleton-agent/sdk v1.0.0 — TypeScript SDK for building Teleton Agent plugins with TON blockchain and Telegram integration. ## Installation ```bash npm install @teleton-agent/sdk ``` ## Plugin Structure A plugin exports: manifest (optional), migrate(db) (optional), tools(sdk) (required), start(ctx) (optional), stop() (optional), onMessage(event) (optional), onCallbackQuery(event) (optional). ```typescript import type { PluginSDK, SimpleToolDef, PluginManifest } from "@teleton-agent/sdk"; export const manifest: PluginManifest = { name: "my-plugin", version: "1.0.0", description: "My plugin description", }; export const tools = (sdk: PluginSDK): SimpleToolDef[] => [{ name: "my_tool", description: "Does something", parameters: { type: "object", properties: { input: { type: "string" } }, required: ["input"] }, async execute(params, context) { return { success: true, data: "result" }; } }]; ``` ## PluginSDK Interface ```typescript interface PluginSDK { readonly version: string; // "1.0.0" readonly ton: TonSDK; // TON blockchain (18 methods + dex + dns) readonly telegram: TelegramSDK; // Telegram (52 methods) readonly db: Database | null; // SQLite (null if no migrate()) readonly config: Record; // Sanitized app config readonly pluginConfig: Record; // Plugin-specific config readonly secrets: SecretsSDK; // API keys (3 methods) readonly storage: StorageSDK | null; // KV store (5 methods) readonly log: PluginLogger; // Logger (4 methods) readonly bot: BotSDK | null; // Inline bot (7 methods, null without bot manifest) } ``` --- ## sdk.ton — TON Blockchain (18 methods) ### Wallet & Balance - `getAddress(): string | null` — Bot's wallet address. null if not initialized. - `getBalance(address?: string): Promise` — Balance in TON + nanoTON. Defaults to bot wallet. - `validateAddress(address: string): boolean` — Check if TON address is valid. ### Price - `getPrice(): Promise` — TON/USD price (cached 30s). TonAPI with CoinGecko fallback. ### Transfers - `sendTON(to: string, amount: number, comment?: string): Promise` — IRREVERSIBLE. Uses PAY_GAS_SEPARATELY (exact amount). Throws: WALLET_NOT_INITIALIZED, INVALID_ADDRESS, OPERATION_FAILED. - `getTransactions(address: string, limit?: number): Promise` — Recent transactions (max 50, default 10). ### Payment Verification - `verifyPayment(params: SDKVerifyPaymentParams): Promise` — Verify TON payment with memo matching and replay protection. REQUIRES used_transactions table in migrate(). Params: { amount, memo, gameType, maxAgeMinutes? }. Returns: { verified, txHash?, amount?, playerWallet?, date?, secondsAgo?, error? }. ### Jettons - `getJettonBalances(ownerAddress?: string): Promise` — Token balances for owner (default: bot wallet). - `getJettonInfo(jettonAddress: string): Promise` — Token metadata: name, symbol, decimals, supply, holders. - `sendJetton(jettonAddress: string, to: string, amount: number, opts?: { comment?: string }): Promise` — IRREVERSIBLE. Transfer jetton tokens. - `getJettonWalletAddress(ownerAddress: string, jettonAddress: string): Promise` — Resolve jetton wallet address. ### Jetton Analytics - `getJettonPrice(jettonAddress: string): Promise` — USD/TON price with 24h/7d/30d changes. - `getJettonHolders(jettonAddress: string, limit?: number): Promise` — Top holders (max 100, default 10). - `getJettonHistory(jettonAddress: string): Promise` — Market analytics: volume, FDV, market cap. ### NFTs - `getNftItems(ownerAddress?: string): Promise` — NFTs owned (default: bot wallet). - `getNftInfo(nftAddress: string): Promise` — Single NFT metadata. ### Utilities - `toNano(amount: number | string): bigint` — Convert TON to nanoTON. - `fromNano(nano: bigint | string): string` — Convert nanoTON to TON string. ### Sub-namespaces - `readonly dex: DexSDK` — DEX trading (6 methods) - `readonly dns: DnsSDK` — DNS domains (8 methods) --- ## sdk.ton.dex — DEX Trading (6 methods) - `quote(params: DexQuoteParams): Promise` — Compare quotes from STON.fi and DeDust. Returns recommended DEX. - `quoteSTONfi(params: DexQuoteParams): Promise` — STON.fi only quote. - `quoteDeDust(params: DexQuoteParams): Promise` — DeDust only quote. - `swap(params: DexSwapParams): Promise` — Execute swap (auto-selects best DEX unless dex param specified). - `swapSTONfi(params: DexSwapParams): Promise` — Swap on STON.fi. - `swapDeDust(params: DexSwapParams): Promise` — Swap on DeDust. DexQuoteParams: { fromAsset: string, toAsset: string, amount: number, slippage?: number } DexSwapParams extends DexQuoteParams: { dex?: "stonfi" | "dedust" } --- ## sdk.ton.dns — DNS & Domains (8 methods) - `check(domain: string): Promise` — Check domain availability, owner, auction status. - `resolve(domain: string): Promise` — Resolve .ton domain to wallet address. - `getAuctions(limit?: number): Promise` — List active domain auctions. - `startAuction(domain: string): Promise` — Start auction for unclaimed domain. - `bid(domain: string, amount: number): Promise` — Place bid on active auction. - `link(domain: string, address: string): Promise` — Link domain to wallet address. - `unlink(domain: string): Promise` — Remove domain link. - `setSiteRecord(domain: string, adnlAddress: string): Promise` — Set TON Site ADNL record. NOTE: DnsCheckResult.auction field exists in types but is NOT populated by implementation (reserved for future). --- ## sdk.telegram — Telegram (52 methods) ### Core - `sendMessage(chatId: string, text: string, opts?: SendMessageOptions): Promise` — Send text message. opts: { replyToId?, inlineKeyboard? }. Returns message ID. - `editMessage(chatId: string, messageId: number, text: string, opts?: EditMessageOptions): Promise` — Edit message. - `sendDice(chatId: string, emoticon: string, replyToId?: number): Promise` — Dice animation. Emoticons: dice, darts, basketball, football, bowling, slots. - `sendReaction(chatId: string, messageId: number, emoji: string): Promise` — React to message. - `getMe(): TelegramUser | null` — Bot's own user info. ### Media - `sendPhoto(chatId: string, photo: string | Buffer, opts?: MediaSendOptions): Promise` - `sendVideo(chatId: string, video: string | Buffer, opts?: MediaSendOptions): Promise` - `sendVoice(chatId: string, voice: string | Buffer, opts?: MediaSendOptions): Promise` — OGG/Opus format. - `sendFile(chatId: string, file: string | Buffer, opts?: MediaSendOptions & { fileName?: string }): Promise` - `sendGif(chatId: string, gif: string | Buffer, opts?: MediaSendOptions): Promise` - `sendSticker(chatId: string, sticker: string | Buffer): Promise` — WEBP format. - `downloadMedia(chatId: string, messageId: number): Promise` ### Messages - `getMessages(chatId: string, limit?: number): Promise` — Recent messages (default: 50). - `searchMessages(chatId: string, query: string, limit?: number): Promise` - `getReplies(chatId: string, messageId: number, limit?: number): Promise` - `deleteMessage(chatId: string, messageId: number, revoke?: boolean): Promise` - `forwardMessage(fromChatId: string, toChatId: string, messageId: number): Promise` - `pinMessage(chatId: string, messageId: number, opts?: { silent?: boolean; unpin?: boolean }): Promise` ### Scheduling - `scheduleMessage(chatId: string, text: string, scheduleDate: number): Promise` — Schedule for future delivery (Unix timestamp). - `getScheduledMessages(chatId: string): Promise` - `deleteScheduledMessage(chatId: string, messageId: number): Promise` - `sendScheduledNow(chatId: string, messageId: number): Promise` ### Chat & Users - `getChatInfo(chatId: string): Promise` — Returns: { id, title, type, membersCount?, username?, description? } - `getUserInfo(userId: number | string): Promise` — Returns: { id, firstName, lastName?, username?, isBot } - `resolveUsername(username: string): Promise` — Resolve @username to entity. - `getParticipants(chatId: string, limit?: number): Promise` — Group/channel members (default: 100). - `getDialogs(limit?: number): Promise` — All conversations (default: 50, max: 100). - `getHistory(chatId: string, limit?: number): Promise` — Chat message history. ### Interactive - `createPoll(chatId: string, question: string, answers: string[], opts?: PollOptions): Promise` — opts: { isAnonymous?, multipleChoice? } - `createQuiz(chatId: string, question: string, answers: string[], correctIndex: number, explanation?: string): Promise` ### Moderation - `banUser(chatId: string, userId: number | string): Promise` - `unbanUser(chatId: string, userId: number | string): Promise` - `muteUser(chatId: string, userId: number | string, untilDate: number): Promise` — 0 = permanent. - `kickUser(chatId: string, userId: number | string): Promise` — Ban + immediate unban. ### Stars & Gifts - `getStarsBalance(): Promise` - `getStarsTransactions(limit?: number): Promise` - `sendGift(userId: number | string, giftId: string, opts?: { message?: string; anonymous?: boolean }): Promise` - `getAvailableGifts(): Promise` - `getMyGifts(limit?: number): Promise` - `getResaleGifts(giftId: string, limit?: number): Promise` - `buyResaleGift(giftId: string): Promise` ### Collectibles - `transferCollectible(msgId: number, toUserId: number | string): Promise` - `setCollectiblePrice(msgId: number, price: number): Promise` — 0 to unlist. - `getCollectibleInfo(slug: string): Promise` — Fragment collectible (username/phone). - `getUniqueGift(slug: string): Promise` — NFT gift by slug (t.me/nft/). - `getUniqueGiftValue(slug: string): Promise` — Market value of NFT gift. - `sendGiftOffer(userId: number | string, giftSlug: string, price: number, opts?: GiftOfferOptions): Promise` — Buy offer on NFT. ### Stories - `sendStory(mediaPath: string, opts?: { caption?: string }): Promise` — Path restrictions: /tmp, Downloads/, Pictures/, Videos/, teleton workspace. ### Advanced - `setTyping(chatId: string): Promise` — Show typing indicator. - `getRawClient(): unknown | null` — Raw GramJS TelegramClient for MTProto. - `isAvailable(): boolean` — Check if connected. --- ## sdk.bot — Bot SDK (7 methods) IMPORTANT: sdk.bot is null unless manifest declares `bot: { inline: true }`. - `readonly isAvailable: boolean` — Whether bot is ready. - `readonly username: string` — Bot username. - `onInlineQuery(handler: (ctx: InlineQueryContext) => Promise): void` — Handle inline queries. - `onCallback(pattern: string, handler: (ctx: CallbackContext) => Promise): void` — Handle button callbacks (glob patterns). - `onChosenResult(handler: (ctx: ChosenResultContext) => Promise): void` — Handle chosen results. - `editInlineMessage(inlineMessageId: string, text: string, opts?: { keyboard?: ButtonDef[][]; parseMode?: string }): Promise` - `keyboard(rows: ButtonDef[][]): BotKeyboard` — Build keyboard. Returns { toTL() (colored), toGrammy() (standard), rows }. ButtonDef: { text, callback? (auto-prefixed), url?, copy?, style?: "success" | "danger" | "primary" } Styled buttons (green/red/blue) only work with .toTL() (GramJS Layer 222). .toGrammy() falls back to standard buttons. --- ## sdk.secrets — Secrets (3 methods) Resolution order: 1. Env var (${PLUGIN_NAME_UPPER}_${KEY_UPPER}), 2. Secrets store (/plugin set), 3. pluginConfig. NOTE: The `env` field in manifest.secrets is defined but IGNORED — env naming is always auto-derived. - `get(key: string): string | undefined` — Get secret value. - `require(key: string): string` — Get or throw SECRET_NOT_FOUND. - `has(key: string): boolean` — Check if configured. --- ## sdk.storage — Key-Value Storage (5 methods) Auto-creates `_kv` table. Values are JSON-serialized. Optional TTL for auto-expiration. - `get(key: string): T | undefined` — Get value (undefined if expired). - `set(key: string, value: T, opts?: { ttl?: number }): void` — Set value. TTL in milliseconds. - `delete(key: string): boolean` — Delete key. Returns true if existed. - `has(key: string): boolean` — Check if exists (not expired). - `clear(): void` — Delete all keys. --- ## sdk.log — Logger (4 methods) Auto-prefixed with [plugin:name]. - `info(...args: unknown[]): void` - `warn(...args: unknown[]): void` - `error(...args: unknown[]): void` - `debug(...args: unknown[]): void` — Only visible with DEBUG or VERBOSE env. --- ## sdk.db — SQLite Database Type: `Database.Database | null` (better-sqlite3). null if plugin doesn't export `migrate()`. Each plugin gets an isolated database. Sync API. ```typescript export const migrate = (db: any) => { db.exec(`CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY, name TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP)`); }; ``` --- ## Error Handling ```typescript import { PluginSDKError } from "@teleton-agent/sdk"; try { await sdk.ton.sendTON(address, 1.0); } catch (err) { if (err instanceof PluginSDKError) { switch (err.code) { case "WALLET_NOT_INITIALIZED": // TON wallet not configured case "INVALID_ADDRESS": // Malformed TON address case "OPERATION_FAILED": // Generic failure case "BRIDGE_NOT_CONNECTED": // Telegram not ready case "SECRET_NOT_FOUND": // Missing required secret } } } ``` --- ## Plugin Manifest ```typescript interface PluginManifest { name: string; // Lowercase, 1-64 chars version: string; // Semver author?: string; description?: string; // Max 256 chars dependencies?: string[]; // Required built-in modules defaultConfig?: Record; sdkVersion?: string; // Range: ">=1.0.0" secrets?: Record; bot?: BotManifest; // Enables sdk.bot } ``` ## Tool Definition ```typescript interface SimpleToolDef { name: string; // Unique identifier (e.g. "casino_spin") description: string; // For LLM parameters?: Record; // JSON Schema execute: (params, context) => Promise; scope?: "always" | "dm-only" | "group-only" | "admin-only"; category?: "data-bearing" | "action"; } interface ToolResult { success: boolean; data?: unknown; error?: string; } ``` ## Event Hooks ```typescript export const onMessage = async (event: PluginMessageEvent) => { // event: { chatId, senderId, senderUsername?, text, isGroup, hasMedia, messageId, timestamp } }; export const onCallbackQuery = async (event: PluginCallbackEvent) => { // event: { data, action, params[], chatId, messageId, userId, answer(text?, alert?) } }; ``` --- ## Important Gotchas 1. SDK object is frozen — plugins cannot modify or extend it. 2. sdk.bot is null if manifest doesn't declare `bot: { inline: true }`. 3. sdk.db is null if plugin doesn't export `migrate()`. 4. sdk.storage is null if no database is available. 5. sendTON() uses PAY_GAS_SEPARATELY — amount sent is exact. 6. Float precision: SDK uses string-based decimal conversion, NOT Math.floor(amount * 10**d). 7. verifyPayment() requires `used_transactions` table for replay protection. 8. sendStory() has path allowlist: /tmp, Downloads/, Pictures/, Videos/, teleton workspace. 9. Secrets env naming: auto-derived ${PLUGIN_NAME_UPPER}_${KEY_UPPER} — manifest `env` field is IGNORED. 10. DnsCheckResult.auction field exists in types but is NOT populated (reserved). 11. Bot SDK callback data is auto-prefixed with plugin name. 12. Styled buttons (colors) only work with .toTL() (GramJS), .toGrammy() falls back to standard. 13. getRawClient() returns GramJS client — BigInteger requires `BigInt(value) as any` cast.