Documentation menu

Tutorials

Telegram Forwarding Tutorials & Recipes

Reproducible recipes: first task, many-to-many routing, anti-spam cleaning, branding with shortcodes, AI rewriting, protected channels and burst-safe delivery.

Verified against the checkout built for v2.2.4 · updated 20 Oct 2026

On this page

Eight recipes, each one a task you can finish in a few minutes. They are written against the current release: the commands are real, the endpoints exist, and the log signals are the ones the stack actually emits.

Your first task, end to end

Beginner

Forward everything from a news channel into your own broadcast channel, as your own post rather than a forward.

  1. Add the bot as an administrator of the destination with permission to post messages.
  2. In Telegram, open the bot and send /settings, then choose Create task.
  3. Enter the source: @MarketNews (or the numeric id for a private channel).
  4. Enter the target: @MyBroadcast.
  5. Pick Copy mode so the post arrives without a "Forwarded from" banner.
  6. Save and enable. The task appears in atf rules list immediately.
Commands
atf rules list                     # confirm the task exists
atf rules simulate <id> --text "Test post"   # dry run, nothing is sent
atf logs tail --follow -n 20       # watch the first real delivery

Many sources into many targets

Routing

One task can watch several channels and publish to several destinations. Use it when a topic set should be mirrored as one stream.

  1. Create a task with the first source and the first target.
  2. Add the remaining sources: atf rules sources <id> add -1001111111111.
  3. Add the remaining targets the same way, or edit the task in the dashboard with the target list editor.
  4. Address a forum topic on a target with the topic id so the mirror lands in the right thread.
  5. Decide the policy once — every source in the task is read with the same rules.
Commands
atf rules create --name "Market news" --source -1001111111111 --target -1003333333333
atf rules sources <id> add -1002222222222
atf rules show <id> --json | jq '.source_chats, .target_chats'

Scrub ads, links and mentions

Cleaning

Turn a channel full of sponsor links into clean text without breaking the formatting of what remains.

  1. Open the task settings and enable Remove URLs, Remove mentions and Remove hashtags.
  2. Add sponsor phrases to the custom word list — folding means one entry catches Latin and Arabic-script spellings.
  3. Enable phone-number stripping if the source posts contact numbers.
  4. Add a blacklist rule if any post containing a word should be dropped entirely rather than cleaned.
  5. Preview with the playground or atf rules simulate before enabling on live traffic.
Commands
atf rules settings set <id> clean_links=true
atf rules settings set <id> clean_mentions=true
atf rules settings set <id> clean_hashtags=true
atf rules settings set <id> custom_words="Sponsor,Join VIP,50% Off"

atf rules simulate <id> --text "Join VIP t.me/spam @admin #deal"

Brand with header and footer shortcodes

Branding

Credit the original channel with a real clickable link, and stamp every delivery with its origin.

  1. Set a header template and a footer template on the task.
  2. Use shortcodes for anything that changes per message — origin name, post id, date and link.
  3. Check the rendered result in the playground before saving.
  4. Note that only validated shortcodes interpolate; an unknown token is left as written rather than silently dropped.
Commands
Header: 📢 [[ORIGIN_NAME]] · post [[ORIGIN_POST_ID]]
Footer: ─────────────
🔗 Original: [[ORIGIN_NAME_URL]]
📅 [[ORIGIN_POST_DATE]]

Rewrite posts with an AI provider

AI

Re-headline and re-word a source feed so the mirror reads as your own editorial voice, without letting a provider outage break delivery.

  1. Create an AI configuration: provider, model and a prompt template (or start from a preset).
  2. Test it against sample text before wiring it to live traffic.
  3. Enable rewriting on the task only — it is per task, not global.
  4. Watch the first deliveries in the log history to confirm the rewrite stage ran and how long it took.
  5. If the provider is unreachable, the cleaned text is delivered unchanged; the job is not failed.
Commands
curl -s -X POST localhost:8080/api/ai-configs \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"provider":"openai","model":"gpt-4o-mini","prompt_template":"Rewrite for a channel: {text}"}'

curl -s -X POST localhost:8080/api/ai-configs/<id>/test \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"text":"Sample post from the source channel"}' | jq

Mirror a copy-protected channel

Advanced

When a channel forbids forwarding, the pipeline downloads the media and re-uploads it instead of failing.

  1. Nothing to configure: the fallback engages automatically when Telegram refuses the native forward.
  2. Expect the log signal [PIPELINE:RESTRICTED_BYPASS] on those deliveries.
  3. Check disk headroom — re-upload paths briefly stage media locally.
  4. For large archives, import a session and use ordered lanes so a backfill does not reorder the channel.
Commands
atf logs query --search "RESTRICTED_BYPASS" | head -20
df -h .            # re-upload staging needs headroom

Debug a missing delivery with log history

Ops

The fastest way to answer "why did that post not arrive" is to follow one message through the pipeline.

  1. Query the task's own history first: GET /api/rules/<id>/logs or the dashboard log explorer filtered by task.
  2. Read the last stage that logged for that message: a FILTER_DROP explains a deliberate skip, a QUEUE without DELIVERED means workers are stuck.
  3. Check the queue depth and dead-letter list if the job never left the queue.
  4. Compare the correlation id with the API call that created or changed the task.
Commands
atf logs query --level ERROR | head -30
atf data queue
atf data dlq --replay      # only after the cause is fixed

Survive a burst without reordering

Reliability

A channel that posts ten updates in a minute will not arrive out of order, and a rate limit will not lose any of them.

  1. Leave ordering on for tasks where sequence matters — deliveries are serialized per task.
  2. Keep tasks separate rather than merging unrelated feeds, so one slow target cannot delay another stream.
  3. When a FloodWait hits, deliveries pause and jobs stay queued; nothing is dropped.
  4. Verify after the fact: queue depth returns to zero and the DLQ stays empty.
Commands
atf status --watch          # watch the board drain
atf data queue --json | jq '.pending, .inflight'
atf data dlq                # expect empty