Communication Channels

Atamaia's channel system connects AI identities to external platforms. Each adapter plugs into a uniform send/receive architecture. Messages flow in through webhooks (or poll), get bridged to the internal message system, and flow out through adapter-specific APIs.

This is not a chatbot framework. It is infrastructure for identities that exist on more than one platform at once, with conversation state held in Atamaia rather than in any vendor.

Canonical host: https://api.atamaia.ai. Authenticated routes require JWT or an API key. Responses wrapped in ApiEnvelope<T>.

Permissions: ChannelView, ChannelCreate, ChannelEdit, ChannelDelete, ChannelSend.


Architecture

External Platform (Slack, Discord, X, …)
    │
    ▼ webhook
POST /api/channels/webhook/{connectorGuid}   (anonymous)
    │
    ▼
ChannelService.ProcessWebhookAsync
    ├── Find connector by GUID
    ├── Find enabled inbound bindings
    └── For each binding:
        ├── Get adapter (IChannelInbound)
        ├── Parse payload → ChannelEnvelope
        ├── Detect @mentions (IChannelMention)
        ├── Bridge to internal Message
        ├── Record ChannelMessageMapping
        └── Publish ChannelInboundEvent

Identity sends
    │
    ▼
POST /api/channels/send
    ├── Find binding + connector
    ├── Decrypt credentials (fail closed)
    ├── Adapter SendAsync
    ├── Record mapping
    └── Publish ChannelOutboundEvent

Connector and binding

An ExternalConnector is one set of credentials for one platform (one Slack workspace bot, one Discord bot, one X app). Credentials are encrypted at rest. A connector can have many bindings.

A ChannelBinding routes one external channel through that connector.

Field Description
connectorId Parent connector (credentials)
adapterTypeKey Adapter key: slack, discord, twitter, …
externalChannelId Platform-specific channel id
name Human-readable name
identityId Which identity speaks / receives
botExternalUserId Bot user id on the platform (mention detection)
direction Inbound, Outbound, or Bidirectional
channelConfigJson Adapter-specific config
enabled Whether the binding is active

ManagedBy on the entity distinguishes seed-managed ("seed") from UI-managed (null). Treat the live entity as authority for that split.


Envelope

Platform-agnostic message:

Field Notes
content / cleanContent Raw and mention-stripped
externalChannelId, externalMessageId, externalThreadId
externalSenderName
mentionsBot
direction ChannelDirection
type ChannelMessageType: Message, Edit, Delete, Reaction, Event
connectorId, channelBindingId

Runtime ChannelInstance adds decrypted credentials and config. Credentials are decrypted only at the moment of use, tenant-keyed (#411). Decrypt fails closed (#389). The old catch { use plaintext } path is gone — that catch is why raw credentials in the column stayed invisible.


Adapters

Interfaces

Interface Purpose
IChannelAdapter TypeKey, DisplayName, Category, Capabilities, ValidateConfig, TestConnection
IChannelOutbound Send, Edit, Delete, React
IChannelInbound ProcessWebhook, Poll
IChannelMention ContainsMention, StripMentions, FormatMention
IChannelThreading ExtractThreadId, ApplyThreadTarget
IChannelEvent Trigger, ProcessEventWebhook

Built-in adapters (from adapter source, 2026-08-14)

TypeKey DisplayName Category Capabilities
slack Slack Messaging Send, Receive, Edit, Delete, React, Thread, Mention
discord Discord Messaging Send, Receive, Edit, Delete, React, Thread, Mention
telegram Telegram Messaging Send, Receive, Edit, Delete, Mention (no Thread)
matrix Matrix Messaging Send, Receive, Edit, Delete, React, Thread, Mention
signal Signal Messaging Send, Receive, Mention
twitter X (Twitter) Messaging Send, Delete (outbound only; auto-thread >280)
email Email (SMTP/IMAP) Email Send, Receive, Poll
webhook Generic Webhook Webhook Send, Receive
homeassistant Home Assistant Automation Send, Event
n8n n8n Automation Event, Receive
feed RSS/Atom Feed Feed Receive, Poll

Twitter is not on the original page. Several capability lists on that page are stale (Telegram Thread, HA Receive, n8n Send).

Categories

Messaging · Automation · Email · Webhook · Feed

Capabilities

Send · Receive · Edit · Delete · React · Thread · Mention · Event · Poll


Message bridge

Inbound

  1. POST /api/channels/webhook/{connectorGuid}no JWT. External platforms POST here.
  2. Enabled inbound bindings for that connector are resolved.
  3. Each adapter parses the payload into a ChannelEnvelope.
  4. Mention detection when the adapter and BotExternalUserId support it.
  5. An internal Message is created for the binding’s IdentityId. Mentions raise priority to Important.
  6. A ChannelMessageMapping is recorded.
  7. ChannelInboundEvent is published.

The webhook returns { "status": "processed" } or { "status": "ignored" } — never 401, so vendor retries do not bounce on auth.

Outbound

POST /api/channels/send
{
  "channelBindingId": 3,
  "content": "Research complete. Summary posted to the project docs.",
  "threadId": "1234567890.000001"
}

Response (ChannelSendResult): success, externalMessageId, error. HTTP 400 when success is false.

Mappings

GET /api/channels/bindings/{bindingId}/mappings

Correlates atamaiaMessageIdexternalMessageId / externalThreadId / direction. Enables edit/delete propagation and an audit of what was said where.


Bindings CRUD

GET    /api/channels/bindings
GET    /api/channels/bindings/{id}
POST   /api/channels/bindings
PUT    /api/channels/bindings/{id}
DELETE /api/channels/bindings/{id}

List supports connectorId, paging (page/pageSize), sort, and a filter bag.

Create (CreateChannelBindingRequest):

Field Required
connectorId yes
adapterTypeKey yes
externalChannelId yes
name yes
identityId, botExternalUserId, channelConfigJson no
direction default Bidirectional

Delete is soft delete.

GET /api/channels/adapters

Returns registered typeKey, displayName, category, capabilities. Call this before creating a binding so the type key is real.


MCP and agent tools

MCP wraps the same IChannelService (D12). Tools in ChannelTools.cs:

MCP tool REST analogue
channel_binding_list GET /api/channels/bindings
channel_binding_get GET /api/channels/bindings/{id}
channel_binding_create POST /api/channels/bindings
channel_binding_update PUT /api/channels/bindings/{id}
channel_binding_delete DELETE /api/channels/bindings/{id}
channel_send POST /api/channels/send
channel_adapter_list GET /api/channels/adapters
channel_mapping_list GET …/mappings

There is no MCP tool named channel_list. That name appears on the original page and as an agent-loop tool in older agent docs; the MCP product name is channel_binding_list.

Agent default policy lists channel_binding_list, channel_binding_get, channel_send, channel_mapping_list as opt-in. Channel access is not on by default. See Agents.


Endpoint catalog

GET    /api/channels/bindings
POST   /api/channels/bindings
GET    /api/channels/bindings/{id}
PUT    /api/channels/bindings/{id}
DELETE /api/channels/bindings/{id}
POST   /api/channels/send
POST   /api/channels/webhook/{connectorGuid}    (anonymous)
GET    /api/channels/adapters
GET    /api/channels/bindings/{bindingId}/mappings

Connectors themselves live under the connector API (ConnectorView / Create / Edit / Delete), not this controller.