Skip to content

Telegram Bot Channel #287

Description

@robertocarlous

Problem Statement

WhatsApp is currently the only conversational interface. Telegram is a large, distinct user base — especially within crypto-native communities — with a different (and in some ways simpler) bot API. This issue adds Telegram as a second real channel, proving that the platform's conversational core is actually channel-agnostic rather than hard-wired to WhatsApp/Twilio specifics.

Current State

The WhatsApp integration is src/whatsapp/handler.ts (message ingestion + Twilio signature verification), src/whatsapp/userManager.ts (resolving a WhatsApp number to a User), and src/whatsapp/formatters.ts (the actual reply-formatting layer — richer than the older src/nlp/responses.ts stub, which appears to only cover 5 basic replies and may not even be fully wired into the live handler). Intent parsing itself, src/nlp/parser.ts, is channel-agnostic in principle: it takes a text string and returns an Intent, resolved via a regex fast-path with a Claude Haiku fallback (unless AI_MODE=local). This is the piece that should be shared, unmodified, between channels.

Proposed Solution

Data Model

Extend user identity to support multiple channels — likely a channel + channelId pair replacing (or added alongside) however the WhatsApp number is currently stored on User, e.g.:

model LinkedChannel {
  id        String      @id @default(uuid())
  userId    String
  channel   ChannelType // WHATSAPP, TELEGRAM
  channelId String      // WhatsApp number or Telegram chat id
  linkedAt  DateTime    @default(now())
  user      User @relation(fields: [userId], references: [id], onDelete: Cascade)
  @@unique([channel, channelId])
}
enum ChannelType { WHATSAPP TELEGRAM }

(Exact shape depends on how User↔WhatsApp-number linkage is modeled today — the implementer should check src/whatsapp/userManager.ts and adapt rather than assume this schema is final.)

API Surface

  • POST /api/telegram — new webhook route analogous to /api/whatsapp, verifying the request came from Telegram (Telegram's webhook secret-token header mechanism, the equivalent of Twilio's signature check) before processing.

Integration Points

  • New src/telegram/ module mirroring the shape of src/whatsapp/handler.ts (webhook ingestion + verification), userManager.ts (chat-id-to-User resolution via LinkedChannel), formatters.ts (Telegram-specific reply formatting, e.g. Markdown/HTML message formatting conventions differ from WhatsApp's).
  • Both handler.tss call into the same src/nlp/parser.ts parseIntent(message) — this is the point of the feature. Command coverage (balance, deposit, withdraw, goal/alert queries introduced by the other issues in this batch) stays in sync across channels by construction, because there's only one parser, not because both channels independently reimplement the same logic.
  • Route-level rate limiting: apply a rate limiter group consistent with the existing webhookRateLimiter used for the WhatsApp inbound webhook (src/middleware/rateLimiter.ts), not the general-purpose one, since this is the same class of "inbound webhook from a third party" traffic.
  • Account linking: a user needs a way to link a Telegram chat to an existing account (e.g. a linking code generated via WhatsApp/API and entered in Telegram, or vice versa) — this is new UX, not just a backend wiring exercise, and should be designed explicitly rather than assumed trivial.

Edge Cases & Failure Modes

  • A message arrives from an unlinked Telegram chat id — respond with clear linking instructions, not a silent failure or a confusing "balance" response for a nonexistent account.
  • The same logical command parses differently due to platform-specific text quirks (e.g. Telegram's own emoji/formatting shortcuts leaking into the message text) — the regex fast-path in parser.ts may need minor tolerance additions; these should be additive and not regress WhatsApp parsing (regression tests on both channels' existing fixtures required).
  • Telegram webhook verification failure (missing/incorrect secret token) — reject with 401 the same way an invalid Twilio signature is rejected today, not silently processed.

Security & Privacy Considerations

  • Telegram's webhook authenticity model (secret token in a header) is different from Twilio's HMAC signature scheme — implement it correctly per Telegram's documented mechanism rather than assuming the Twilio pattern transfers directly.
  • Account-linking flow must not allow linking a Telegram chat to an account the requester doesn't control (e.g. a linking code must be single-use, short-lived, and tied to the account that generated it).

Out of Scope

  • Telegram-specific features with no WhatsApp equivalent (inline keyboards, bot commands menu, group chat support) beyond what's needed for basic 1:1 conversational parity.
  • Migrating existing WhatsApp users to Telegram — this is an additive channel, not a replacement.

Suggested Implementation Plan

  1. LinkedChannel model (or equivalent) and account-linking flow design + implementation.
  2. src/telegram/handler.ts with webhook verification, wired through the existing src/nlp/parser.ts.
  3. src/telegram/formatters.ts for Telegram-appropriate reply formatting.
  4. Regression tests confirming WhatsApp parsing is unaffected; new integration tests for the Telegram webhook path.

Acceptance Criteria

  • Telegram webhook receives and verifies messages using Telegram's own authenticity mechanism, replies via the Bot API
  • All existing NLP intents work over Telegram through the shared src/nlp/parser.ts, with zero duplicated intent-parsing logic
  • A user can link one account to both WhatsApp and Telegram and see consistent state across both
  • Account-linking codes are single-use, short-lived, and cannot be used to hijack another user's account
  • Regression tests confirm existing WhatsApp intent parsing is unchanged
  • Integration tests for the Telegram webhook path: signature/token verification, message round-trip, unlinked-chat handling
  • docs/openapi.yaml updated

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions