Skip to content

feat(telegram): support custom apiRoot for alternative API endpoints#48842

Merged
obviyus merged 6 commits intoopenclaw:mainfrom
Cypherm:feat/telegram-api-root-v2
Mar 21, 2026
Merged

feat(telegram): support custom apiRoot for alternative API endpoints#48842
obviyus merged 6 commits intoopenclaw:mainfrom
Cypherm:feat/telegram-api-root-v2

Conversation

@Cypherm
Copy link
Copy Markdown
Contributor

@Cypherm Cypherm commented Mar 17, 2026

Summary

Problem: Users behind ISP-level DNS blocks, corporate proxies, or self-hosted Telegram Bot API servers cannot override the hardcoded api.telegram.org endpoint.

Why it matters: Self-hosted Bot API servers remove the 20MB file download limit and reduce latency. Some networks block api.telegram.org entirely. Users need a config-level escape hatch.

What changed:

  • Added apiRoot to TelegramAccountConfig type with Zod .url() validation
  • Created centralized resolveTelegramApiBase() helper in fetch.ts (trim, strip trailing slash, default fallback)
  • Threaded apiRoot through all Telegram API call sites: bot creation, send, probe, audit, media download, api-fetch
  • Extended SSRF policy to dynamically trust custom apiRoot hostname for media downloads
  • Updated test mocks for new resolveTelegramApiBase export

What did NOT change:

  • Transport-layer behavior (dispatcher selection, proxy, DNS fallback, IPv4 fallback chain) is untouched — resolveTelegramTransport signatures unchanged
  • Network error classification and retry logic in network-errors.ts is untouched
  • Polling, webhook, and message handling logic is untouched
  • No new files created; all changes extend existing modules
  • Default behavior when apiRoot is not set is identical to before

Change Type

  • New feature (non-breaking)

Scope

Integrations (Telegram extension + config schema)

Linked Issue

Closes #28535

Security Impact

  • New permissions requested: none
  • Secrets handling changes: none
  • New network calls: none (existing calls route through custom endpoint when configured)
  • New command/tool execution: none
  • Data access changes: buildTelegramMediaSsrfPolicy() dynamically adds custom apiRoot hostname to SSRF allowlist — this is intentional and required for media downloads from self-hosted Bot API servers. Invalid URLs are caught by try/catch fallthrough.

Human Verification

I personally verified:

  • pnpm build passes
  • pnpm check (format + lint) passes — only pre-existing matrix/tlon type errors remain
  • pnpm test -- extensions/telegram — 987/987 tests pass, 2 e2e pass
  • Removed dead TELEGRAM_API_BASE constant from probe.ts (was flagged by Greptile)
  • Removed unused apiRoot from resolveTelegramTransport/resolveTelegramFetch signatures — transport handles HOW to connect (dispatcher/proxy), not WHERE (URL)
  • Config without apiRoot produces identical behavior to upstream main

Evidence

Test Files  75 passed (75)
     Tests  987 passed (987)
  Duration  73.70s

Test Files  2 passed (2)  [e2e]
     Tests  8 passed | 2 skipped (10)

git diff --stat upstream/main...HEAD: 16 files changed, 101 insertions(+), 27 deletions(-)

What I Did NOT Verify

  • Not verified: actual self-hosted Telegram Bot API server (telegram-bot-api --local instance) — tested config plumbing and URL construction only
  • Not verified: --local mode filesystem path responses (local Bot API returns absolute paths instead of HTTP URLs for file downloads — this is a separate transport concern for a follow-up PR)
  • Not verified: apiRoot with non-standard ports or path prefixes (e.g., https://proxy.example.com:8443/bot-api/)

Failure Recovery

If this breaks in production:

  • Detection: Telegram bot fails to connect when apiRoot is set to an invalid/unreachable endpoint
  • Rollback: Remove apiRoot from config — all paths fall back to default api.telegram.org
  • Blast radius: Only affects accounts with explicit apiRoot config. Accounts without it are completely unaffected.

Example usage

channels:
  telegram:
    apiRoot: "https://my-telegram-proxy.example.com"

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 [email protected]

@openclaw-barnacle openclaw-barnacle bot added channel: telegram Channel integration: telegram size: M labels Mar 17, 2026
@Cypherm Cypherm force-pushed the feat/telegram-api-root-v2 branch from f9bcd0b to 48a5bd9 Compare March 17, 2026 08:06
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 17, 2026

Greptile Summary

This PR exposes grammy's apiRoot option through channels.telegram.apiRoot config, letting operators route the Telegram Bot API through a custom endpoint (self-hosted Bot API server, reverse proxy, or alternative IP). The implementation is thorough: the option is Zod-validated at config load, plumbed through every transport/URL-construction call site, included in all cache keys, and the SSRF allowlist is extended to trust the custom hostname. Two minor cleanup items were found:

  • const TELEGRAM_API_BASE in probe.ts (line 7) is now dead code — its only consumer was replaced by resolveTelegramApiBase(options?.apiRoot).
  • options.apiRoot appears in the resolveTelegramTransport / resolveTelegramFetch signatures but is never referenced inside those functions. The transport layer doesn't use it (base-URL construction happens at call sites), so the parameter either needs a clarifying comment or should be removed to avoid implying it changes dispatcher behaviour.

Confidence Score: 4/5

  • This PR is safe to merge; the two issues found are minor dead code and a misleading function signature, not runtime bugs.
  • The feature is well-scoped, validated at the config layer, and consistently threaded through all relevant call sites. The fallback-IP dispatcher logic correctly handles custom hostnames (DNS pinning only applies to api.telegram.org). The only deductions are a leftover unused constant and an apiRoot parameter that is part of the transport function signature without actually influencing transport behaviour.
  • extensions/telegram/src/probe.ts (dead constant), extensions/telegram/src/fetch.ts (unused apiRoot in transport signatures)
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/telegram/src/probe.ts
Line: 7

Comment:
**Unused constant left behind**

`TELEGRAM_API_BASE` is defined but never referenced after the refactoring — its only use was `const base = `${TELEGRAM_API_BASE}/bot${token}`;`, which was replaced on line 109 with `resolveTelegramApiBase(options?.apiRoot)`. This is now dead code.

```suggestion

```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/telegram/src/fetch.ts
Line: 450-453

Comment:
**`apiRoot` accepted but never consumed in the transport function**

`options.apiRoot` is part of the `resolveTelegramTransport` (and `resolveTelegramFetch`) signature, but the value is never read anywhere inside the function body. The transport layer only configures dispatchers; base-URL construction happens at call sites via `resolveTelegramApiBase`. Carrying the unused parameter in the signature can mislead callers into thinking passing `apiRoot` here changes connection behavior.

If the parameter is only there to maintain a uniform options shape, a comment explaining that would clarify intent. Otherwise the parameter should be removed from both `resolveTelegramTransport` and `resolveTelegramFetch`.

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 48a5bd9

@Cypherm Cypherm force-pushed the feat/telegram-api-root-v2 branch 2 times, most recently from 2243832 to 1b80f66 Compare March 20, 2026 08:09
@Cypherm Cypherm force-pushed the feat/telegram-api-root-v2 branch 3 times, most recently from 8d379a7 to 712a7bb Compare March 20, 2026 09:15
@Cypherm Cypherm force-pushed the feat/telegram-api-root-v2 branch 6 times, most recently from 7760660 to 6a06d71 Compare March 21, 2026 00:42
@Cypherm
Copy link
Copy Markdown
Contributor Author

Cypherm commented Mar 21, 2026

@obviyusapiRoot config for custom Telegram Bot API endpoints (self-hosted servers, DNS-blocked networks). 16 files, +101/-27. Closes #28535.

All Telegram call sites covered: bot, send, probe, audit, media download (with dynamic SSRF policy), api-fetch. Default behavior unchanged when apiRoot is not set.

@obviyus obviyus self-assigned this Mar 21, 2026
@openclaw-barnacle openclaw-barnacle bot added commands Command implementations size: M and removed size: S labels Mar 21, 2026
@obviyus
Copy link
Copy Markdown
Contributor

obviyus commented Mar 21, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9eedbd8a6d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Cypherm and others added 3 commits March 21, 2026 10:03
Add `apiRoot` config option to allow users to specify custom Telegram Bot
API endpoints (e.g., self-hosted Bot API servers). Threads the configured
base URL through all Telegram API call sites: bot creation, send, probe,
audit, media download, and api-fetch. Extends SSRF policy to dynamically
trust custom apiRoot hostname for media downloads.

Closes openclaw#28535

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@obviyus obviyus force-pushed the feat/telegram-api-root-v2 branch from c25f07c to c1ba65d Compare March 21, 2026 04:37
@obviyus obviyus merged commit 6b4c24c into openclaw:main Mar 21, 2026
13 checks passed
@obviyus
Copy link
Copy Markdown
Contributor

obviyus commented Mar 21, 2026

Landed on main.

Thanks @Cypherm.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d8bd3d4f4f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 123 to +126
resolveTelegramAllowFromEntries({
credentialValue: credentialValues.token,
entries,
apiRoot: resolveTelegramAccount({ cfg, accountId }).config.apiRoot,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pass proxy and network into setup-surface allowFrom lookups

Fresh evidence relative to the earlier chat-id fix: this setup wizard path still calls resolveTelegramAllowFromEntries with only apiRoot. If an account relies on channels.telegram.proxy or channels.telegram.network to reach Telegram, @username resolution from the setup surface ignores those transport overrides, so the allowlist step still fails even though send/probe/audit now use the configured transport.

Useful? React with 👍 / 👎.

JohnJAS pushed a commit to JohnJAS/openclaw that referenced this pull request Mar 22, 2026
…penclaw#48842)

* feat(telegram): support custom apiRoot for alternative API endpoints

Add `apiRoot` config option to allow users to specify custom Telegram Bot
API endpoints (e.g., self-hosted Bot API servers). Threads the configured
base URL through all Telegram API call sites: bot creation, send, probe,
audit, media download, and api-fetch. Extends SSRF policy to dynamically
trust custom apiRoot hostname for media downloads.

Closes openclaw#28535

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(telegram): thread apiRoot through allowFrom lookups

* fix(telegram): honor lookup transport and local file paths

* refactor(telegram): unify username lookup plumbing

* fix(telegram): restore doctor lookup imports

* fix: document Telegram apiRoot support (openclaw#48842) (thanks @Cypherm)

---------

Co-authored-by: Cypherm <[email protected]>
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
pholpaphankorn pushed a commit to pholpaphankorn/openclaw that referenced this pull request Mar 22, 2026
…penclaw#48842)

* feat(telegram): support custom apiRoot for alternative API endpoints

Add `apiRoot` config option to allow users to specify custom Telegram Bot
API endpoints (e.g., self-hosted Bot API servers). Threads the configured
base URL through all Telegram API call sites: bot creation, send, probe,
audit, media download, and api-fetch. Extends SSRF policy to dynamically
trust custom apiRoot hostname for media downloads.

Closes openclaw#28535

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(telegram): thread apiRoot through allowFrom lookups

* fix(telegram): honor lookup transport and local file paths

* refactor(telegram): unify username lookup plumbing

* fix(telegram): restore doctor lookup imports

* fix: document Telegram apiRoot support (openclaw#48842) (thanks @Cypherm)

---------

Co-authored-by: Cypherm <[email protected]>
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
frankekn pushed a commit to artwalker/openclaw that referenced this pull request Mar 23, 2026
…penclaw#48842)

* feat(telegram): support custom apiRoot for alternative API endpoints

Add `apiRoot` config option to allow users to specify custom Telegram Bot
API endpoints (e.g., self-hosted Bot API servers). Threads the configured
base URL through all Telegram API call sites: bot creation, send, probe,
audit, media download, and api-fetch. Extends SSRF policy to dynamically
trust custom apiRoot hostname for media downloads.

Closes openclaw#28535

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(telegram): thread apiRoot through allowFrom lookups

* fix(telegram): honor lookup transport and local file paths

* refactor(telegram): unify username lookup plumbing

* fix(telegram): restore doctor lookup imports

* fix: document Telegram apiRoot support (openclaw#48842) (thanks @Cypherm)

---------

Co-authored-by: Cypherm <[email protected]>
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 23, 2026
…penclaw#48842)

* feat(telegram): support custom apiRoot for alternative API endpoints

Add `apiRoot` config option to allow users to specify custom Telegram Bot
API endpoints (e.g., self-hosted Bot API servers). Threads the configured
base URL through all Telegram API call sites: bot creation, send, probe,
audit, media download, and api-fetch. Extends SSRF policy to dynamically
trust custom apiRoot hostname for media downloads.

Closes openclaw#28535

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(telegram): thread apiRoot through allowFrom lookups

* fix(telegram): honor lookup transport and local file paths

* refactor(telegram): unify username lookup plumbing

* fix(telegram): restore doctor lookup imports

* fix: document Telegram apiRoot support (openclaw#48842) (thanks @Cypherm)

---------

Co-authored-by: Cypherm <[email protected]>
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
(cherry picked from commit 6b4c24c)
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 23, 2026
…penclaw#48842)

* feat(telegram): support custom apiRoot for alternative API endpoints

Add `apiRoot` config option to allow users to specify custom Telegram Bot
API endpoints (e.g., self-hosted Bot API servers). Threads the configured
base URL through all Telegram API call sites: bot creation, send, probe,
audit, media download, and api-fetch. Extends SSRF policy to dynamically
trust custom apiRoot hostname for media downloads.

Closes openclaw#28535

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(telegram): thread apiRoot through allowFrom lookups

* fix(telegram): honor lookup transport and local file paths

* refactor(telegram): unify username lookup plumbing

* fix(telegram): restore doctor lookup imports

* fix: document Telegram apiRoot support (openclaw#48842) (thanks @Cypherm)

---------

Co-authored-by: Cypherm <[email protected]>
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
(cherry picked from commit 6b4c24c)
Copilot AI added a commit to nathan77886/openclaw that referenced this pull request Mar 24, 2026
…API_HOST

Merge upstream/main into the fork, resolving conflicts in Telegram extension
files. The upstream added support for config-based apiRoot (openclaw#48842); this merge
preserves the fork's TELEGRAM_BOT_API_HOST environment variable approach by
making both work together with the following priority:

  1. Explicit apiRoot config (channels.telegram.accounts.default.apiRoot)
  2. TELEGRAM_BOT_API_HOST environment variable
  3. Default https://api.telegram.org

Key changes:
- fetch.ts: resolveTelegramApiBase(apiRoot?) falls back to env var via api-base.ts
- api-fetch.ts: use upstream's richer implementation (threads apiRoot + fetchImpl)
- audit-membership-runtime.ts, probe.ts: import from fetch.ts, pass apiRoot
- bot.ts, send.ts: resolve via resolveTelegramApiBase(config apiRoot) with env fallback
- bot/delivery.resolve-media.ts: buildTelegramMediaSsrfPolicy uses effective API
  hostname (config or env var)
furaul pushed a commit to furaul/openclaw that referenced this pull request Mar 24, 2026
…penclaw#48842)

* feat(telegram): support custom apiRoot for alternative API endpoints

Add `apiRoot` config option to allow users to specify custom Telegram Bot
API endpoints (e.g., self-hosted Bot API servers). Threads the configured
base URL through all Telegram API call sites: bot creation, send, probe,
audit, media download, and api-fetch. Extends SSRF policy to dynamically
trust custom apiRoot hostname for media downloads.

Closes openclaw#28535

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(telegram): thread apiRoot through allowFrom lookups

* fix(telegram): honor lookup transport and local file paths

* refactor(telegram): unify username lookup plumbing

* fix(telegram): restore doctor lookup imports

* fix: document Telegram apiRoot support (openclaw#48842) (thanks @Cypherm)

---------

Co-authored-by: Cypherm <[email protected]>
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
Interstellar-code pushed a commit to Interstellar-code/operator1 that referenced this pull request Mar 24, 2026
…penclaw#48842)

* feat(telegram): support custom apiRoot for alternative API endpoints

Add `apiRoot` config option to allow users to specify custom Telegram Bot
API endpoints (e.g., self-hosted Bot API servers). Threads the configured
base URL through all Telegram API call sites: bot creation, send, probe,
audit, media download, and api-fetch. Extends SSRF policy to dynamically
trust custom apiRoot hostname for media downloads.

Closes openclaw#28535

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(telegram): thread apiRoot through allowFrom lookups

* fix(telegram): honor lookup transport and local file paths

* refactor(telegram): unify username lookup plumbing

* fix(telegram): restore doctor lookup imports

* fix: document Telegram apiRoot support (openclaw#48842) (thanks @Cypherm)

---------

Co-authored-by: Cypherm <[email protected]>
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
(cherry picked from commit 6b4c24c)
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 28, 2026
…penclaw#48842)

* feat(telegram): support custom apiRoot for alternative API endpoints

Add `apiRoot` config option to allow users to specify custom Telegram Bot
API endpoints (e.g., self-hosted Bot API servers). Threads the configured
base URL through all Telegram API call sites: bot creation, send, probe,
audit, media download, and api-fetch. Extends SSRF policy to dynamically
trust custom apiRoot hostname for media downloads.

Closes openclaw#28535

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(telegram): thread apiRoot through allowFrom lookups

* fix(telegram): honor lookup transport and local file paths

* refactor(telegram): unify username lookup plumbing

* fix(telegram): restore doctor lookup imports

* fix: document Telegram apiRoot support (openclaw#48842) (thanks @Cypherm)

---------

Co-authored-by: Cypherm <[email protected]>
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
(cherry picked from commit 6b4c24c)

# Conflicts:
#	CHANGELOG.md
#	extensions/telegram/src/api-fetch.ts
#	extensions/telegram/src/bot/delivery.resolve-media.ts
#	extensions/telegram/src/probe.ts
#	extensions/telegram/src/setup-core.ts
#	extensions/telegram/src/setup-surface.ts
#	src/commands/doctor-config-flow.test.ts
#	src/commands/doctor-config-flow.ts
#	src/config/schema.help.ts
#	src/config/schema.labels.ts
#	src/config/types.telegram.ts
#	src/config/zod-schema.providers-core.ts
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 28, 2026
…penclaw#48842)

* feat(telegram): support custom apiRoot for alternative API endpoints

Add `apiRoot` config option to allow users to specify custom Telegram Bot
API endpoints (e.g., self-hosted Bot API servers). Threads the configured
base URL through all Telegram API call sites: bot creation, send, probe,
audit, media download, and api-fetch. Extends SSRF policy to dynamically
trust custom apiRoot hostname for media downloads.

Closes openclaw#28535

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(telegram): thread apiRoot through allowFrom lookups

* fix(telegram): honor lookup transport and local file paths

* refactor(telegram): unify username lookup plumbing

* fix(telegram): restore doctor lookup imports

* fix: document Telegram apiRoot support (openclaw#48842) (thanks @Cypherm)

---------

Co-authored-by: Cypherm <[email protected]>
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
(cherry picked from commit 6b4c24c)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: telegram Channel integration: telegram commands Command implementations size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(telegram): expose apiRoot config for custom Bot API server

2 participants