Scheduling and command hooks
Schedule and cancel delayed BJS commands, configure periodic Auto Retry with an explicit Telegram destination, and understand before/after command hooks.
Use Bot.run to run another command or schedule it after a delay. Use Auto Retry for a recurring interval configured in command metadata. Use callbacks for remote results. BJS does not provide a long-lived JavaScript event loop for setTimeout, Promises, or background threads.
A complete reminder
Create /remind:
if (!user || !chat) { return; }
var label = "tea-reminder:" + user.id;
Bot.clearRunAfter({ label: label });
Bot.run({
command: "/tea-ready",
run_after: 60,
label: label,
options: { text: "Your tea reminder is ready." }
});
Bot.sendMessage("Reminder scheduled. Use /cancel-reminder to cancel it.");Create /tea-ready:
if (!options || typeof options.text !== "string") { return; }
Bot.sendMessage(options.text, { parse_mode: null });Create /cancel-reminder:
if (!user) { return; }
Bot.clearRunAfter({ label: "tea-reminder:" + user.id });
Bot.sendMessage("Pending tea reminder cancelled.");run_after is in seconds. A scheduled request is not a guarantee of execution at an exact wall-clock instant: queue availability, bot state, and limits still apply.
For a reminder that resets when the user returns, follow remind a user after inactivity. That recipe tracks activity and includes opt-in and cancellation.
Bot.run options
command
Required target command, optionally followed by text parameters
options
Structured data available as options in the target
run_after
Positive delay in seconds; without it, the ordinary path calls a subcommand
label
Label used to find pending scheduled requests for cancellation
user_id, chat_id
Internal Bots.Business IDs for execution context
user_telegramid
Telegram user ID for a known user
bot_id
Another bot accessible to the current owner
ignoreMissingCommand
Relax a missing-command error in the immediate subcommand path
Changing destination context can cause an automatic one-second scheduled path. The background option is not forwarded by the current Bot.run wrapper; do not depend on it to remove context or change time limits.
Bot.runCommand("/next", {step: 2}) is the simpler command-call form. Its result is not a JavaScript return value. Keep command chains short: the backend limits nested command/callback calls and reports “Too many sub commands” when the chain exceeds that limit.
Cancellation scope
Labels belong to scheduled requests for a bot. Include a user or task identifier when the reminder should be individual. Bot.clearRunAfter() without a label clears pending scheduled requests for the bot, including other tasks. Cancelling a pending request does not undo a command that has already executed.
Auto Retry: run periodically
Auto Retry runs a command's BJS at an interval set in Auto retry time in seconds. Each automatic run starts without a current user, chat, or Telegram request, and skips metadata Answer and Keyboard. The reminder above depends on a user's chat context; do not copy it into Auto Retry unchanged.
Send an hourly reminder to a fixed chat
Use a test bot and a destination where you intend to receive recurring messages.
Create a temporary
/chat-idcommand with empty Answer and Keyboard, and this BJS:
Send
/chat-idin the intended Telegram conversation. For a private chat, start the bot there first; for a group, add the bot and allow it to send messages. Copy the returned Telegram chat ID, including a leading minus sign for a group. It ischat.chatid, not the internalchat.id.In the mobile app, open the bot's Commands and create
/hourly-reminder. Keep Answer and Keyboard empty, Wait for answer off, and the auto-retry interval empty until the code is ready.Paste the BJS below, replace
YOUR_TELEGRAM_CHAT_IDwith that chat ID, keeping the quotes, and tap Save. Configure the destination yourself in the editor; do not let visitors set a shared destination from chat input.
Open ⋮ → Options, set Auto retry time in seconds to
3600, and tap Edit to save. Ensure the bot is running. On a new command, the first automatic run can happen as soon as the scheduler picks it up; it does not necessarily wait a full interval first.Check the message in the destination and the bot's Errors. For a short test, use
60seconds, observe successive messages, then save3600or disable the interval. Remove/chat-idwhen finished.
The first check ignores incoming Telegram messages. It is not authentication for a public endpoint: do not expose this periodic command as a webhook or call it from user-controlled code. Api.sendMessage needs the explicit Telegram chat_id because automatic runs have no default destination. Use bot properties for shared persistent state; user properties require a user context.
The interval is in seconds, measured from the previous automatic run; it is not a calendar rule such as “every day at 09:00.” Scheduler availability, bot status and limits affect timing. Repeated work consumes iterations, so choose the interval for the task.
Stop Auto Retry
Open the command's ⋮ → Options, clear Auto retry time in seconds (or set it to 0), and tap Edit. This stops future automatic runs after the setting is saved; it does not undo a run already in progress. Bot.clearRunAfter cancels queued Bot.run requests, not this metadata interval.
Always-running commands
The special @ command provides BJS inserted before a selected command; @@ provides BJS inserted after it. Use these hooks for small shared checks or setup. They are not independent background jobs.
Example @ code:
Because the hook and command share an execution body, return in @ prevents the selected command's BJS and later @@ BJS from running. It does not suppress the selected command's metadata Answer or Keyboard, which are processed separately. For muted-user checks or access restrictions that must also prevent replies, leave those fields empty and send replies from BJS after the check; see Guard. A thrown error or an early return in a command can prevent @@; it is not a guaranteed finally block. Shared hooks must also work for callbacks and triggers without user/chat context.
The * command handles unmatched input, including incoming messages without text. It is distinct from the @ hook. See receiving Telegram updates and collecting input.
Troubleshooting
For a missing reminder, check the label, delay, bot status, target command, and error log. For a missing user, compare the original and supplied context. For repeated reminders, confirm whether the scheduling command ran more than once and whether cancellation used the exact label.
Use broadcast tasks to reach many chats and HTTP callbacks for service responses; neither needs a JavaScript timer loop.
Last updated
Was this helpful?