DEV Community

Daniel Ioni
Daniel Ioni

Posted on

Building a Multi-Channel AI Gateway: Facebook Messenger, Telegram, Zorgax and the MyZubster Metaverse

Building a Multi-Channel AI Gateway: Facebook Messenger, Telegram, Zorgax and the MyZubster Metaverse

Building an AI chatbot is relatively easy.

Building an AI assistant that can live across multiple communication platforms, preserve application truth, route users into different services, deliver media, survive serverless execution, and remain maintainable is a different problem.

Over the last development cycle, we built a production bridge between Facebook Messenger, MyZubster, and Zorgax.

Now we're using what we learned from that integration to design the next channel: Telegram.

This article explains the architecture, the mistakes we encountered, and how we're moving toward a shared multi-channel gateway instead of creating a different AI bot for every platform.

The architecture we already have

Our Facebook Messenger integration currently follows this path:

Facebook User

MyZubster Community Page

Meta Messenger

Meta Webhook

MyZubster API

Validation / Normalization / Deduplication

Zorgax or Deterministic Router

Marketplace
Seller
Metaverse
LIFE Pilot
Community
Comic Universe

Meta Send API

Messenger

The important part is the middle.

Messenger isn't connected directly to an unrestricted LLM.

There is an application layer between the messaging platform and Zorgax.

That distinction became increasingly important as the integration grew.

  1. Start with the webhook — but don't stop there

Meta sends Messenger events to our webhook:

POST /api/meta/messenger/webhook

Before processing anything, the bridge verifies that the request is legitimate.

The production implementation includes:

Webhook verification
X-Hub-Signature-256 validation
HMAC-SHA256
timing-safe comparisons
echo protection
event normalization
deduplication

But we discovered an important serverless lesson.

Returning:

200 OK

doesn't mean the AI workflow completed.

Meta wants the webhook acknowledged quickly, while the actual workflow may still need to:

receive message

normalize it

retrieve conversation context

call Zorgax

route application intent

call Meta Send API

On Vercel, we therefore use waitUntil() to keep the asynchronous processing alive after acknowledging the webhook.

Conceptually:

app.post("/api/meta/messenger/webhook", (req, res) => {
const work = processMessengerEvent(req.body);

waitUntil(work);

res.sendStatus(200);
});

The actual implementation contains additional validation and error handling, but the architectural lesson is simple:

Webhook acknowledgement and workflow completion are two separate states.

  1. Normalize the channel before calling the AI

Messenger doesn't send only plain text.

A user can interact through:

text
quick replies
postbacks
attachments

Instead of making Zorgax understand raw Meta payloads, the bridge normalizes those events first.

Conceptually:

Meta payload

Channel Adapter

Normalized message

Zorgax / Router

This gives us a much cleaner boundary.

The same idea becomes especially important when adding Telegram.

  1. Don't let the LLM own application truth

This was probably the most important lesson from production testing.

During one conversation, a user asked about becoming a Seller.

A follow-up question was:

How much does it cost?

Zorgax correctly understood that the user was still talking about Seller onboarding.

But the model generated unsupported assumptions about pricing and transaction fees.

The application already knew the configured Seller information.

The LLM shouldn't have been guessing.

We changed the architecture so commercial information is grounded in MyZubster state.

This eventually became an explicit architectural decision:

ADR-001 — Application Truth Before Generative Output

The principle is:

When MyZubster already knows a fact, application state takes precedence over unconstrained model generation.

This applies to things like:

commercial configuration
canonical URLs
public resource availability
Comic Universe assets
Metaverse destinations
verified application features

Zorgax can explain those facts.

It shouldn't invent them.

  1. Deterministic routing is sometimes better than AI

We discovered the same issue while connecting the MyZubster Comic Universe.

A user asked:

Show me the MyZubster comic

Initially, the request could still fall through to the generic AI path.

During testing, Zorgax incorrectly answered that the comic wasn't publicly available.

But MyZubster already knew:

the Comic Universe exists
the public route exists
public visual assets exist

There was nothing to reason about.

So we introduced deterministic routing.

User message

Comic intent?
↓ yes
Select approved visual

Send image

Send grounded Comic response

Comic Universe URL

The model no longer gets an opportunity to contradict known application state.

  1. Messenger became a gateway into the ecosystem

Once this architecture was working, Messenger stopped being just a chatbot interface.

It became a conversational gateway.

A user can ask Zorgax about:

Marketplace
Seller
Metaverse
LIFE Pilot
Community
Comic Universe

without knowing the site's navigation beforehand.

For example:

User:
Tell me about the Metaverse.

Enter fullscreen mode Exit fullscreen mode

Messenger

Enter fullscreen mode Exit fullscreen mode

Zorgax

Enter fullscreen mode Exit fullscreen mode

MyZubster routing

Enter fullscreen mode Exit fullscreen mode

https://www.myzubster.com/metaverse

That leads to a useful architectural distinction:

Facebook is the channel.

Messenger is the transport.

Zorgax is the conversational guide.

MyZubster is the ecosystem and application truth layer.

  1. The next mistake would be building everything again for Telegram

After getting Messenger working, the obvious approach would be:

metaMessengerRoutes.js
telegramBotRoutes.js

Messenger prompts
Telegram prompts

Messenger routing
Telegram routing

Messenger commercial logic
Telegram commercial logic

That would work initially.

It would also become technical debt quickly.

Imagine changing Seller pricing rules.

Now two integrations need updating.

Add Discord?

Three.

Add another channel?

Four.

Instead, we're designing Telegram around a shared channel architecture.

  1. The target multi-channel architecture

The direction is:

                     MyZubster
                         │
                         ▼
                      Zorgax
                         │
                         ▼
                Shared Channel Core
                  /       |       \
                 /        |        \
                ▼         ▼         ▼
         Messenger    Telegram    Future
Enter fullscreen mode Exit fullscreen mode

A more detailed version:

                MyZubster Application
                        │
                        ▼
              Application Truth Layer
                        │
                        ▼
                     Zorgax
                        │
          ┌─────────────┴─────────────┐
          │                           │
  Deterministic Router        Conversational AI
          │                           │
          └─────────────┬─────────────┘
                        │
                 Channel Core
                  /          \
                 /            \
                ▼              ▼
         Meta Adapter    Telegram Adapter
                │              │
                ▼              ▼
          Messenger       Telegram Bot
Enter fullscreen mode Exit fullscreen mode

The transport changes.

The application intelligence doesn't need to.

  1. What belongs in a channel adapter?

The Telegram adapter should understand Telegram.

The Messenger adapter should understand Meta.

For example, the Telegram layer should own:

Telegram webhook validation
Update parsing
chat_id
user_id
callback queries
Telegram commands
sendMessage
sendPhoto
inline keyboards
Telegram API errors

Messenger owns things such as:

Meta webhook signatures
Page sender IDs
quick replies
postbacks
Meta Send API
Messenger attachments
is_echo

Neither should independently decide what the current Seller plan means.

That belongs higher in the architecture.

  1. Telegram webhook design

The proposed Telegram endpoint is:

POST /api/telegram/zorgax/webhook

with a status endpoint:

GET /api/telegram/zorgax/status

The processing pipeline would be:

Telegram Update

Validate webhook secret

Check update_id

Deduplicate

Normalize

Shared router

Known intent?
↙ ↘
yes no
↓ ↓
deterministic Zorgax
route
↘ ↙
Telegram response

  1. Telegram security

We don't want to treat possession of the bot endpoint as authorization.

The planned configuration separates credentials:

TELEGRAM_BOT_TOKEN
TELEGRAM_WEBHOOK_SECRET
TELEGRAM_BOT_USERNAME

The webhook secret authenticates inbound webhook traffic.

The Bot Token authorizes calls to Telegram's Bot API.

Those are different responsibilities.

Secrets should never appear in:

Git commits
documentation
screenshots
PR descriptions
runtime logs
status endpoints

  1. Deduplicate Telegram updates

Telegram provides an update_id.

That gives us a natural idempotency key.

Conceptually:

if (recentUpdates.has(update.update_id)) {
return;
}

recentUpdates.add(update.update_id);

await processUpdate(update);

A bounded in-memory cache is enough for an initial implementation.

At larger scale, this should become a distributed idempotency mechanism.

The important rule is:

Never design a webhook consumer assuming delivery happens exactly once.

  1. Private chats and groups are different products

One important Telegram design decision is not to make Zorgax automatically answer everything inside a group.

In private chat:

User → Zorgax

Automatic conversational replies make sense.

In a Telegram group, responding to every message could quickly become annoying.

Our proposed initial group policy is:

/command
@bot mention
reply to Zorgax
explicit button interaction

Only those interactions invoke the assistant.

That makes the bot participate in the community rather than dominate it.

  1. Commands should be shortcuts, not separate applications

The first command surface could be:

/start
/help
/marketplace
/seller
/metaverse
/life
/comic
/culture
/privacy

But /metaverse shouldn't contain a separate implementation of Metaverse logic.

It should simply produce an intent for the shared router:

/metaverse

Telegram adapter

intent: metaverse

shared MyZubster router

Natural language:

Where is the MyZubster Metaverse?

should reach the same destination.

  1. Media should also be shared conceptually

Messenger can already deliver Comic Universe imagery.

Telegram can eventually implement the same application behavior using sendPhoto.

Comic request

Shared Comic routing

Approved public asset

Channel adapter
/ \
/ \
Meta Telegram
│ │
image sendPhoto

The application decides what should be sent.

The adapter decides how that platform sends it.

  1. Keep fiction and evidence separate

MyZubster contains narrative visual material.

We explicitly distinguish:

FICTION / CONCEPT

from evidence of real-world events.

That semantic rule belongs in the shared application layer.

It should therefore apply equally to:

Website
Messenger
Telegram
future channels

Changing communication platforms should never change the meaning of the underlying content.

  1. From messaging integration to community continuity

There's another reason Telegram is interesting for this architecture.

We're exploring how MyZubster can preserve connections formed around physical events.

Think about a gathering involving:

music
art
people
local initiatives
recycling
community activity

Normally the event finishes and much of that temporary network disappears.

A multi-channel MyZubster gateway creates another possibility:

Physical Event

People meet

Local / recycling activity

QR code
↙ ↘
Messenger Telegram
↘ ↙
Zorgax

MyZubster

┌─────┼─────────┐
▼ ▼ ▼
LIFE Culture Metaverse

Community

Next activity

The digital layer doesn't replace the event.

Its purpose is to preserve and extend connections created in the physical world.

  1. Culture and Subculture

This also opens an interesting direction for MyZubster Culture/Subculture spaces.

A community around:

electronic music
sound systems
digital art
environmental action
local culture
open technology
creative communities

could use Messenger or Telegram as its lightweight communication entry point.

Zorgax can then guide people toward the corresponding MyZubster space.

But there's an important grounding rule here too.

The assistant must never invent:

a Culture that doesn't exist
an event that hasn't been registered
a partnership that hasn't been verified
an official affiliation that hasn't been established

Again:

application truth before generation.

  1. Recycling and LIFE Pilot

The same model can connect event participation with environmental initiatives.

For example:

Event

QR

Telegram

Zorgax

"How can I help with cleanup?"

LIFE Pilot

Eventually this could help communities distribute cleanup instructions, organize volunteers, preserve public resources and document real initiatives.

But environmental claims need the same grounding discipline.

If MyZubster doesn't have evidence that something was collected, recycled or measured, Zorgax shouldn't claim that it happened.

  1. Identity requires special care

A Telegram identity is not automatically a MyZubster identity.

Neither is a Facebook identity.

If we eventually connect accounts, the flow should require explicit authorization.

Something like:

Telegram user

/link

Temporary MyZubster authorization URL

MyZubster login

Explicit consent

Server-side account link

Never:

Telegram username == MyZubster username

Usernames aren't identity proof.

  1. Cross-channel memory is a later problem

Messenger currently uses lightweight short-term conversation context.

Telegram can initially do the same.

But we shouldn't pretend that:

Facebook user A

and:

Telegram user B

are the same person simply because their names look similar.

Cross-channel continuity should only happen after explicit account linking.

Until then:

Messenger context ≠ Telegram context

That's safer and architecturally cleaner.

  1. Proposed implementation phases

We're planning the Telegram work incrementally.

Phase 1 — Private chat MVP
Telegram Bot
Webhook
Secret validation
Text messages
Commands
Zorgax
Seller grounding
Metaverse routing
Deduplication
Logging
Phase 2 — Media and navigation
Comic sendPhoto
Inline keyboards
Culture routing
LIFE routing
Better fallbacks
Phase 3 — Community mode
Groups
Mention-only interaction
Command mode
Admin-controlled behavior
Context isolation
Event deep links
Phase 4 — Cross-channel architecture
Messenger ─┐
Telegram ──┼→ Shared session/application layer
Future ────┘

Only after explicit identity and privacy rules are defined.

  1. What “done” means

We don't consider the Telegram integration complete simply when /start replies.

The first production milestone should require:

✓ real Telegram user can message the bot
✓ webhook authentication works
✓ duplicate updates don't duplicate replies
✓ Zorgax follows the user's language
✓ short-term Seller context works
✓ commercial information is grounded
✓ Metaverse route works
✓ Comic media works or safely falls back
✓ unsupported media gets an honest response
✓ secrets don't appear in logs
✓ group behavior is controlled
✓ operational documentation matches production

That's a much more useful definition of “working”.

The documentation is open source

We documented the existing production Messenger architecture here:

Meta Messenger ↔ Zorgax Bridge Guide

The production operations runbook is here:

Meta Messenger Operations Runbook

And the new Telegram architecture and implementation plan is here:

Telegram ↔ Zorgax Bridge Plan

The complete project:

MyZubster on GitHub

You can also explore the connected application surfaces:

MyZubster

MyZubster Metaverse

MyZubster Marketplace

MyZubster Comic Universe

Final takeaway

The architecture we're moving toward isn't:

Facebook AI bot
Telegram AI bot
another AI bot
another set of prompts
another copy of business logic

It's:

           PEOPLE
              │
   ┌──────────┼──────────┐
   ▼          ▼          ▼
Enter fullscreen mode Exit fullscreen mode

Messenger Telegram Future
└──────────┼──────────┘

CHANNEL ADAPTERS


ZORGAX CORE


MYZUBSTER
┌─────────┼─────────┐
▼ ▼ ▼
Marketplace Metaverse LIFE
│ │ │
└──── Culture ──────┘


COMMUNITY

The messaging platform should be replaceable.

The application's truth should not be.

And the AI should be the layer that helps people navigate the system — not the layer that invents the system.

That's the direction we're taking with Zorgax and MyZubster.

OpenSource #TelegramBot #FacebookMessenger #AI #AIAgents #NodeJS #Vercel #Webhooks #SystemDesign #Metaverse #Community #Sustainability #LLM #BuildInPublic #MyZubster #Zorgax

Top comments (0)