Skip to content

Channels

Komand supports multiple messaging channels through a unified adapter architecture. Each channel normalises messages to a common internal format, so agents work identically regardless of the source.

ChannelTransportStatus
WebChatREST API + SignalRAvailable
SlackEvents API + Socket ModePlanned
Microsoft TeamsBot FrameworkPlanned
DiscordGateway + InteractionsPlanned
TelegramWebhookPlanned
WhatsAppBusiness APIPlanned
SignalSignal CLIPlanned
SMSTwilio / VonagePlanned

The WebChat adapter is the built-in channel — a REST endpoint for synchronous messaging plus a SignalR hub for real-time streaming.

Terminal window
curl -X POST http://localhost:5000/api/webchat/message \
-H "Content-Type: application/json" \
-d '{
"senderId": "user-1",
"text": "What are your business hours?",
"displayName": "Alice",
"accountId": "default"
}'

Parameters:

FieldTypeRequiredDefaultDescription
senderIdstringYesUnique user identifier
textstringYesMessage content (max 10,000 chars)
displayNamestringNonullUser’s display name
accountIdstringNo"default"Account identifier for multi-tenant setups

Response:

{
"success": true,
"data": {
"sessionId": "WebChat:default:user-1",
"text": "Our office hours are Monday to Friday, 9 AM to 5 PM AEST.",
"timestamp": "2026-02-23T10:30:02Z"
}
}

The session key is constructed as "WebChat:{accountId}:{senderId}".

The web dashboard connects via SignalR for real-time bi-directional messaging:

MethodDirectionPurpose
SendMessageClient → ServerSend a message to the agent
ReceiveMessageServer → ClientReceive the agent’s response
AgentTypingServer → ClientAgent is generating a response

The connection uses exponential backoff for reconnection and gracefully handles disconnects.

All adapters produce the same InboundMessage format regardless of the source channel:

{
"messageId": "msg-uuid",
"channel": "Telegram",
"channelAccountId": "bot-token-id",
"senderId": "telegram-user-id",
"senderDisplayName": "Alice",
"text": "Hello!",
"timestamp": "2026-02-23T10:30:00Z",
"attachments": [],
"metadata": {}
}

Responses use the corresponding OutboundMessage format:

{
"SessionId": "Telegram:bot-token-id:telegram-user-id",
"Channel": "Telegram",
"RecipientId": "telegram-user-id",
"Text": "Hi Alice! How can I help you today?",
"Timestamp": "2026-02-23T10:30:02Z",
"Attachments": []
}

Messages can include file attachments:

{
"fileName": "proposal.pdf",
"contentType": "application/pdf",
"url": "https://files.komand.ai/uploads/proposal.pdf"
}

The metadata field carries channel-specific data without polluting the core message format:

ChannelExample Metadata
TelegramtelegramChatId, telegramMessageId
SlackslackThreadTs, slackTeamId
DiscorddiscordGuildId, discordChannelId
WhatsAppwhatsappPhoneNumber
TeamsteamsConversationId, teamsTenantId

Channel adapters are implemented as ASP.NET Core minimal API endpoints in the Gateway. Each adapter follows the same pattern:

Accept the channel-native webhook payload and validate the request signature:

POST /api/{channel}/webhook

Map the channel-specific fields to the common format:

var inbound = new InboundMessage
{
MessageId = Guid.NewGuid().ToString(),
Channel = Channel.Telegram,
ChannelAccountId = botId,
SenderId = telegramUserId,
SenderDisplayName = telegramUserName,
Text = update.Message.Text,
Timestamp = DateTimeOffset.UtcNow,
Attachments = [],
Metadata = new Dictionary<string, string>
{
["telegramChatId"] = update.Message.Chat.Id.ToString()
}
};

Construct the session key and route:

var sessionKey = $"{Channel.Telegram}:{botId}:{telegramUserId}";
var session = grainFactory.GetGrain<ISessionGrain>(sessionKey);
var response = await session.HandleMessageAsync(inbound);

Convert the OutboundMessage back to the channel’s native format and send it:

await telegramClient.SendTextMessageAsync(
chatId: telegramChatId,
text: response.Text
);

A single agent can serve multiple channels simultaneously. The agent’s behaviour is consistent across channels — the same system prompt, skills, and memory apply everywhere.

[Telegram] "What's my next meeting?"
[Slack] "What's my next meeting?"
[WebChat] "What's my next meeting?"
→ Same agent, same skills, same answer (adjusted for context)

Session state is channel-specific, so a user on Telegram and the same user on Slack have separate conversation threads. However, the agent’s memory is shared across all sessions — information stored during a Telegram conversation is available in Slack.

You can restrict which channels an agent operates on via allowedChannels in the agent configuration, and bind sessions to specific agents per channel:

ChannelAgentUse Case
WebChatsales-botWebsite visitor lead capture
Slackinternal-botTeam operations and status
Telegramsupport-botCustomer support
WhatsAppdefaultGeneral inquiries

See Sessions for how to bind agents to sessions.