Channels

Packages: chanreg/, api/. The channel protocol connects external adapter daemons to the router.

3-endpoint protocol

Every channel adapter is an HTTP server. The router is an HTTP server. They communicate through three endpoints:

DirectionEndpointPurpose
Adapter โ†’ RouterPOST /v1/channels/registerRegister on startup, receive session token
Adapter โ†’ RouterPOST /v1/messagesForward inbound platform message to router
Router โ†’ AdapterPOST /sendDeliver outbound message to platform

The router also calls the adapter's GET /health endpoint every 30 seconds.

Registration

On startup, each adapter POSTs to /v1/channels/register:

{
  "name":         "teled",
  "callbackURL":  "http://teled:8081",
  "jidPrefixes":  ["telegram:"],
  "capabilities": ["send", "send_file", "typing"],
  "secret":       "<CHANNEL_SECRET>"
}

The router returns a session token. The adapter includes this token as a bearer token on all subsequent POST /v1/messages calls.

receive_only: true in capabilities means the adapter only receives messages from the platform โ€” the router never calls its /send endpoint. Used by onbod and dashd.

Inbound flow

Platform event โ†’ Adapter
  โ†’ POST /v1/messages (with session token)
  โ†’ api handler โ†’ store.PutMessage
  โ†’ gateway poll loop picks up on next tick

The inbound message body (InboundMsg from chanlib):

{
  "jid":       "telegram:123456789",
  "sender":    "alice",
  "content":   "hello",
  "replyTo":   "optional message ID being replied to",
  "mediaURL":  "optional media attachment URL",
  "verb":      "message"  // or "reaction", "typing", etc.
}

Outbound flow

gateway โ†’ HTTPChannel.Send(jid, text, replyTo)
  โ†’ POST <callbackURL>/send
  โ†’ { "jid": "...", "text": "...", "replyTo": "..." }
  โ†’ 200 = delivered to platform

The router signs outbound requests with the shared CHANNEL_SECRET (same secret used for registration). The adapter verifies the signature before forwarding to the platform.

Health polling

Auth

CallAuth mechanism
Adapter โ†’ Router registrationShared secret (CHANNEL_SECRET) in request body
Adapter โ†’ Router messagesSession token (from registration response) as bearer token
Router โ†’ Adapter /sendShared secret as X-Channel-Secret header
Router โ†’ Adapter /healthNo auth (read-only liveness check)

chanlib shared library

Package: chanlib/. All Go adapter daemons import this for:

Deregistration and reconnection

Adapters can deregister explicitly via POST /v1/channels/deregister (with session token). On reconnection, they re-register and receive a new session token. The outbox queued during downtime drains automatically.

If an adapter process restarts, its registration is lost. The adapter must re-register on startup. The router treats the new registration as a fresh channel instance.