Recipes
Recipes are pre-built, parameterized building blocks for common bot patterns β guards, confirmations, pagination, retries, broadcasts. Each takes named parameters and provides named handler blocks you fill in.
The recipe insertion palette offers preset templates β pre-filled calls with sensible defaults β so you can drop in a recipe and edit only what differs. The editor also detects common verbose patterns and suggests the equivalent recipe. For example, if you write send.answer_callback(...) immediately followed by edit.text(...), the editor offers to replace the pair with a single telegram.answerAndEditOrigin call.
guard.adminOnly() {
body { send.text("Secret admin command ran.") }
onDeny { send.text("π« Admins only.") }
}
A recipe's handlers (body, onDeny, on_select, β¦) are written as blocks inside the call. Parameters with ! are required.
Guardsβ
Gate a body so it runs only when a condition holds; otherwise the deny handler runs.
| Recipe | Signature | Handlers |
|---|---|---|
guard.adminOnly() | β | body, onDeny |
guard.groupOnly() | β | body, onDeny |
guard.privateChatOnly() | β | body, onDeny |
guard.subscribedOnly() | β | body, onDeny |
guard.callbackPayloadMatches(pattern!) | pattern: string | body, onDeny |
flow secret on command "/secret" {
guard.adminOnly() {
body { send.text("π The launch code is 1234.") }
onDeny { send.text("π« You can't run this.") }
}
}
Flow helpersβ
| Recipe | Signature | Handlers |
|---|---|---|
flow.confirm(prompt!, yesLabel, noLabel, timeout) | a yes/no dialog | on_confirm, on_cancel |
flow.paginate(items!, page_size, header, doneLabel, timeout) | a paginated list | on_select, on_done |
flow.rateLimit(key!, max!) | a shared counter gate | body, on_limited |
flow.validateInput(prompt!, validatorExpr!, errorPrompt, max_retries, timeout, localName) | ask + validate with retries | on_valid, on_exhausted |
flow delete_all on command "/wipe" {
flow.confirm(prompt: "Delete everything? This can't be undone.", yesLabel: "Yes, delete", noLabel: "Cancel", timeout: "60s") {
on_confirm {
set { user.items = [] }
send.text("π All items deleted.")
}
on_cancel { send.text("Cancelled.") }
}
}
flow set_age on command "/age" {
flow.validateInput(prompt: "How old are you?", validatorExpr: "types.int(value) >= 13", errorPrompt: "Please enter a number 13 or older.", max_retries: 3, timeout: "120s", localName: "age") {
on_valid { send.text(`Thanks! You're ${age}.`) }
on_exhausted { send.text("Too many invalid tries β start over with /age.") }
}
}
HTTPβ
| Recipe | Signature | Handlers |
|---|---|---|
http.retry(url!, method, body, headers, max_attempts, backoff, localName) | request with backoff | onSuccess, onFailed |
http.retry(url: "https://api.example.com/data", method: "GET", max_attempts: 3, backoff: "2s", localName: "res") {
onSuccess { send.text(`β
${res.status_code}`) }
onFailed { send.text("β Still failing after retries.") }
}
Telegram helpersβ
| Recipe | Signature | Notes |
|---|---|---|
telegram.broadcastMessage(text!) | broadcast text to the audience (paced) | β |
telegram.broadcastMedia() | broadcast a photo/video/document | β |
telegram.broadcastFlow() | run a subflow per audience member | β |
telegram.statusMessage(text!) | send a status message, capture its ref for editing | β |
telegram.safeEdit(text!, messageRef, fallbackSend) | edit a message, fall back to sending if it fails | β |
telegram.replyAndAutoDelete(text!, ttl) | reply, then auto-delete after a delay | β |
telegram.answerAndEditOrigin(newText!, callbackText) | answer a callback and edit its origin message | β |
flow loading on command "/work" {
telegram.statusMessage(text: "β³ Workingβ¦")
// β¦ do the work β¦
telegram.safeEdit(text: "β
Done!", fallbackSend: true)
}