enrich-api-page
Enrich API Reference Page
You are enriching the user-maintained sections of one or more Telegram Bot API reference pages in GramIO docs.
Arguments
The user provides one or more method/type names, space-separated:
sendPhoto
sendMessage sendPhoto getUpdates
Message InlineKeyboardMarkup
Process each name sequentially. After finishing all pages, give a summary of what was done.
What You Must NEVER Touch
- Anything between
<!-- GENERATED:START -->and<!-- GENERATED:END -->markers in the page body
The frontmatter IS yours to update — SEO optimization is a primary goal of enrichment.
Steps (repeat for each name)
1. Read the existing page
Find the file:
- Methods:
docs/telegram/methods/{name}.md - Types:
docs/telegram/types/{name}.md
Note which sections are empty/placeholder vs. already have content. Don't overwrite sections that already have good content — only improve or fill missing ones.
2. Fetch the official Telegram docs
https://core.telegram.org/bots/api#{lowercasename}
Extract:
- Full description nuances and caveats
- All constraints mentioned (limits, timing, chat-type restrictions)
- Which methods/types are cross-referenced
3. Update SEO frontmatter
SEO is critical — people searching Google for sendMessage telegram, telegram bot api sendMessage etc. should find GramIO docs.
Update the frontmatter fields:
title — exact search-match format:
sendMessage — Telegram Bot API | GramIO
Message Object — Telegram Bot API | GramIO
description (meta) — action-oriented, 140–160 chars, mentions GramIO and TypeScript:
Send text messages using GramIO with TypeScript. Complete sendMessage parameter reference,
entity formatting examples, reply_markup, and common error handling.
Good description anatomy: [Action verb] [what it does] using GramIO. [Key features]: [param1], [param2], [use case].
keywords (meta) — include all of:
- The method/type name itself (highest priority)
telegram bot api,telegram botgramio {name},{name} typescript,{name} example- All required parameter names
- Common search phrases:
how to {action} telegram bot,telegram {name} method - Return type name if notable
Example for sendMessage:
sendMessage, telegram bot api, send message telegram bot, gramio sendMessage,
telegram send text message, sendMessage typescript, chat_id, parse_mode, reply_markup,
telegram bot send message example, how to send message telegram bot
4. Research errors
For methods only (skip for types).
Use this error knowledge base, then add method-specific ones from official docs:
Universal (any method):
400 Bad Request: chat not found— invalid/inaccessiblechat_id400 Bad Request: message not found— referenced message doesn't exist403 Forbidden: bot was blocked by the user— user blocked the bot403 Forbidden: bot is not a member of the channel chat— bot not in channel403 Forbidden: not enough rights— bot lacks required permissions429 Too Many Requests: retry after N— flood control, checkretry_after
sendMessage:
400 TEXT_TOO_LONG— text > 4096 chars400 can't parse entities— malformed entities or wrong parse_mode markup
sendPhoto / sendDocument / sendVideo / sendAudio:
400 PHOTO_INVALID_DIMENSIONS— image dimensions too large400 wrong file identifier/HTTP URL specified— bad file_id or inaccessible URL
answerCallbackQuery:
400 query is too old and response timeout expired— must answer within 10 seconds
answerInlineQuery:
400 QUERY_ID_INVALID— query expired (>10s) or already answered
editMessage*:
400 message is not modified— new content identical to current400 message can't be edited— message too old, or sent by a different bot
5. Verify types via local .d.ts (primary) or JSR (fallback)
CRITICAL: Never invent types or properties. Before writing any code example, verify the actual type signatures.
Context naming convention — camelCase only:
- GramIO contexts use camelCase for all properties and methods:
ctx.text,ctx.from,ctx.chat,ctx.replyMessage,ctx.senderChat, etc. - NEVER use snake_case on context objects —
ctx.reply_to_messageis WRONG,ctx.update.message?.textis WRONG - Snake_case exists only in the raw Telegram payload:
ctx.payload.reply_to_message— but always prefer the typed camelCase accessors - NEVER pass object to
ctx.send()—ctx.send({ sticker: id })is WRONG; each media type has its own method
Primary: Grep the local .d.ts
The most reliable and fastest way. The .d.ts for @gramio/contexts is available locally:
node_modules/@gramio/contexts/dist/index.d.ts
Use Grep to find exact method signatures before using them:
# Find a specific method on a context:
Grep "sendSticker" node_modules/@gramio/contexts/dist/index.d.ts
Grep "replyWithSticker" node_modules/@gramio/contexts/dist/index.d.ts
# Find all properties on a context class:
Grep "get text\|get from\|get chat\|get caption" node_modules/@gramio/contexts/dist/index.d.ts
Built-in cheat sheet — MessageContext
These methods are confirmed from @gramio/contexts/dist/index.d.ts. Use this before grepping.
Send methods — chat_id is injected automatically, first arg is the media/content:
| Method | First arg | Notes |
|---|---|---|
ctx.send(text, params?) |
string | sendMessage shorthand |
ctx.sendPhoto(photo, params?) |
file | — |
ctx.sendDocument(document, params?) |
file | — |
ctx.sendAudio(audio, params?) |
file | — |
ctx.sendVideo(video, params?) |
file | — |
ctx.sendAnimation(animation, params?) |
file | — |
ctx.sendVoice(voice, params?) |
file | — |
ctx.sendVideoNote(videoNote, params?) |
file | — |
ctx.sendSticker(sticker, params?) |
file | — |
ctx.sendLocation(lat, lon, params?) |
numbers | — |
ctx.sendDice(emoji, params?) |
string | — |
ctx.sendPoll(params) |
— | full params |
ctx.sendContact(params) |
— | full params |
ctx.sendVenue(params) |
— | full params |
ctx.sendInvoice(params) |
— | full params |
ctx.sendMediaGroup(media, params?) |
array | returns MessageContext[] |
ctx.sendPaidMedia(media, starCount, params?) |
array, number | — |
ctx.sendChatAction(action, params?) |
string | returns true |
Reply methods — same as send* but also set reply_parameters pointing to the current message:
| Method | Notes |
|---|---|
ctx.reply(text, params?) |
reply to current message with text |
ctx.replyWithPhoto(photo, params?) |
— |
ctx.replyWithDocument(document, params?) |
— |
ctx.replyWithAudio(audio, params?) |
— |
ctx.replyWithVideo(video, params?) |
— |
ctx.replyWithAnimation(animation, params?) |
— |
ctx.replyWithVoice(voice, params?) |
— |
ctx.replyWithVideoNote(videoNote, params?) |
— |
ctx.replyWithSticker(sticker, params?) |
— |
ctx.replyWithLocation(lat, lon, params?) |
— |
ctx.replyWithMediaGroup(media, params?) |
returns MessageContext[] |
ctx.replyWithDice(emoji, params?) |
— |
ctx.replyWithPoll(params) |
— |
ctx.replyWithContact(params) |
— |
ctx.replyWithVenue(params) |
— |
ctx.replyWithInvoice(params) |
— |
Edit/delete methods:
| Method | Notes |
|---|---|
ctx.editText(text, params?) |
alias: editMessageText |
ctx.editCaption(caption, params?) |
alias: editMessageCaption |
ctx.editMedia(media, params?) |
alias: editMessageMedia |
ctx.editReplyMarkup(markup, params?) |
alias: editMessageReplyMarkup |
ctx.editChecklist(checklist, params?) |
— |
ctx.delete(params?) |
delete current message |
ctx.deleteMessages(ids) |
delete multiple |
ctx.copy(params?) |
copyMessage shorthand |
ctx.forward(params?) |
forwardMessage shorthand |
Common properties (all camelCase):
| Property | Type | Notes |
|---|---|---|
ctx.text |
string | undefined |
message text |
ctx.caption |
string | undefined |
media caption |
ctx.from |
User | undefined |
sender (undefined in channel posts) |
ctx.chat |
Chat |
current chat |
ctx.attachment |
varies | message media (photo, sticker, etc.) |
ctx.replyMessage |
MessageContext | undefined |
replied-to message |
ctx.payload |
raw TelegramMessage | raw snake_case data |
Fallback: JSR (for uncommon context classes)
For context classes not covered by the cheat sheet above (e.g. CallbackQueryContext, InlineQueryContext, ChatJoinRequestContext), use Grep on the local .d.ts first. JSR is a last resort only when the .d.ts is not available:
| Package | JSR URL |
|---|---|
@gramio/contexts |
https://jsr.io/@gramio/contexts/doc |
@gramio/types |
https://jsr.io/@gramio/types/doc |
If a method/property is not found via Grep — don't use it.
6. Write the enriched sections
## GramIO Usage
Write 3–6 TypeScript examples:
- Context shorthand first (
ctx.send,ctx.reply,ctx.answerCallbackQuery) - Direct
bot.api.methodName({...})call second - One example per key use case
- Imports when needed
Code format — use ts twoslash:
All code blocks MUST use ```ts twoslash instead of ```typescript. This enables build-time type checking — if you use a type that doesn't exist, the VitePress build will fail.
Pattern for examples:
```ts twoslash
import { Bot } from "gramio";
const bot = new Bot("");
// ---cut---
// The visible example starts after ---cut---
bot.command("start", (ctx) => ctx.send("Hello!"));
```
// ---cut---hides the setup code (imports, Bot creation) from the rendered page but keeps it for type checking// ^?shows an inline type hover annotation — use sparingly for key types- If the example needs extra imports (format, keyboards, etc.), put them before
// ---cut--- - If the example is a standalone snippet (not inside a handler), you may omit
// ---cut---
Code rules:
formattagged template builds entities, never addparse_modealongside itctx.send()→ shorthand forsendMessageto current chatctx.reply()→ additionally setsreply_parameters- For files:
await MediaUpload.path("./file.jpg")orawait MediaUpload.url("https://...")— both are async, always useawait MediaUpload.buffer(buf, "name.ext")andMediaUpload.text("content", "name.txt")are synchronous (noawaitneeded)MediaInputbuilds completeTelegramInputMedia*objects — use it for methods that acceptInputMediaarrays/objects (sendMediaGroup,editMessageMedia):MediaInput.photo(media, options?)→TelegramInputMediaPhoto({ type: "photo", media, ...options })MediaInput.video(media, options?)→TelegramInputMediaVideoMediaInput.audio(media, options?)→TelegramInputMediaAudioMediaInput.document(media, options?)→TelegramInputMediaDocumentMediaInput.animation(media, options?)→TelegramInputMediaAnimation- The
mediaargument is a file_id string or aMediaUploadresult;optionscan includecaption,parse_mode, etc. - Do NOT use
MediaInputforInputStoryContent— story content uses{ type, photo/video }(different field name), not{ type, media }. Use plainMediaUpload+ manual object construction for stories.
- Always link to
/files/media-uploadin See Also when the method involves file uploads - Always link to
/formattingin See Also when the method acceptstext,caption, ormessage_text(formatting is applicable) - Always link to
/keyboards/overviewin See Also when the method involvesreply_markup, inline keyboards, or callback queries
Import convention — prefer importing from "gramio" directly:
Keyboard,InlineKeyboard,ForceReply,RemoveKeyboardare re-exported from"gramio"— import them from"gramio", not"@gramio/keyboards"MediaUploadandMediaInputare re-exported from"gramio"— import them from"gramio", not"@gramio/files"format,bold,italic,code,link, etc. are re-exported from"gramio"— import them from"gramio", not"@gramio/format"- Only use the individual package imports (
@gramio/keyboards,@gramio/files,@gramio/format) when explicitly working outside of the maingramiopackage
Good:
import {
Bot,
InlineKeyboard,
MediaUpload,
MediaInput,
format,
bold,
} from "gramio";
Avoid:
import { InlineKeyboard } from "@gramio/keyboards";
import { MediaUpload } from "@gramio/files";
import { MediaInput } from "@gramio/files";
## Errors
Write a markdown table with context annotations in the Cause column:
| Code | Error | Cause |
| ---- | ---------------------------------------- | ------------------------------------------------------------------------------------------- |
| 400 | `Bad Request: TEXT_TOO_LONG` | `text` exceeds 4096 chars — use [Split plugin](/plugins/official/split) |
| 403 | `Forbidden: bot was blocked by the user` | User blocked the bot — catch and mark user as inactive |
| 429 | `Too Many Requests: retry after N` | Rate limit hit — check `retry_after`, use [auto-retry plugin](/plugins/official/auto-retry) |
The Cause column is user-maintained non-generated data — make it maximally useful:
- Don't just repeat what the error says — explain why it happens
- Add a short action hint: what should the developer do? (catch, retry, validate, etc.)
- Link to relevant plugins or docs pages when applicable
- For rate limits, always mention
retry_afterand the auto-retry plugin
Add a tip block if auto-retry is relevant:
::: tip
Use GramIO's [auto-retry plugin](/plugins/official/auto-retry) to handle `429` errors automatically.
:::
## Tips & Gotchas
Write 3–6 bullet points. These are also user-maintained — make them actionable annotations, not just paraphrased docs:
Good pattern: **Key point.** Explanation of why it matters + what to do.
- **Text limit is 4096 characters.** For longer content, use the [Split plugin](/plugins/official/split) — it handles entity preservation automatically.
- **`parse_mode` and `entities` are mutually exclusive.** GramIO's `format` helper always produces `entities`, so never pass `parse_mode` alongside it.
- **`chat_id` accepts `@username` strings** for public groups/channels. Private chats always require the numeric ID.
Focus on:
- Constraints with consequences (limits, timing, rate limits)
- Mutually exclusive parameters
- Chat-type behavioral differences (private / group / supergroup / channel)
- Common pitfalls that cause silent bugs or unexpected behavior
- GramIO-specific patterns that simplify the task
## See Also
4–8 links. Always verify with Glob that the target page exists before linking.
# Check if page exists:
ls docs/telegram/methods/sendPhoto.md
ls docs/telegram/types/Message.md
ls docs/plugins/official/auto-retry.md
Include:
- Related methods (same category)
- Return type and key parameter types (link to their
/telegram/types/pages) - Relevant GramIO guides that exist:
/formatting,/keyboards/overview,/files - Plugins that apply
7. Report progress
After each page, briefly list:
- ✅ Sections added/updated
- ⚠️ Anything uncertain or that needs human review
- → Suggested next: related pages worth enriching
After all pages are done, print a summary table:
| Page | SEO | Usage | Errors | Tips | See Also |
|------|-----|-------|--------|------|----------|
| sendMessage | ✅ | ✅ | ✅ | ✅ | ✅ |
| sendPhoto | ✅ | ✅ | ✅ | ✅ | ✅ |
Quality Bar
- SEO: title matches the exact search query people use; keywords include all major variants
- Types: every property access, method call, and type annotation must exist in the real GramIO/Telegram types — verified via Grep on local
.d.tsor the cheat sheet above. Zero invented types.ctx.send({ sticker })is WRONG — usectx.sendSticker(id). - Examples:
ts twoslashcode blocks, correct imports, realistic values, idiomatic GramIO. Build MUST pass — if twoslash fails, the type is wrong - Errors: accurate (mark uncertain ones with
*); Cause column is a useful annotation, not just error text - Tips: actionable, non-obvious, each one saves a developer real time
- Links: only link pages that exist
More from gramiojs/documentation
gramio
Invoke for ANY Telegram bot code — `gramio`/`@gramio/*` imports, `new Bot()`, `bot.command`/`bot.callbackQuery`/`bot.on`/`bot.updates.on`, scenes/FSM, inline & reply keyboards, message entities, file uploads, sessions, plugins, webhooks vs long-polling, Telegram Stars, Mini Apps (TMA), broadcasting, Docker. Type-safe TypeScript framework (Node.js/Bun/Deno) with full Bot API coverage. Also covers migrations from Telegraf/grammY/puregram/node-telegram-bot-api. When delegating to a subagent, pass relevant reference files (callback-data, scenes, formatting, context, middleware-routing, ux-patterns) inline — this skill does not auto-load in subagent sessions.
164add-doc-page
Create a new documentation page in both EN and RU with proper frontmatter, sidebar registration, and automatic Russian translation.
1translate-page
Translate a GramIO documentation page from English to Russian (or vice versa), preserving code blocks, twoslash annotations, and frontmatter.
1gramio-help
Internal knowledge skill — provides Claude with GramIO framework context by reading documentation files dynamically.
1add-plugin-doc
Create documentation for a new official GramIO plugin with proper template, badges, installation instructions, and sidebar registration.
1gramio-pick-username
Pick an available Telegram bot username. Takes a topic (and optional audience/language), generates candidates respecting BotFather's rules, batch-checks availability on t.me via the bundled `check-usernames.mjs` script, and returns a ranked shortlist of free names. Use whenever the user asks "find a bot username", "check if @foo_bot is taken", "придумай юзернейм для бота", "неминг бота".
1