Documentation
Channels
0trace's multi-channel gateway connects agents to any messaging platform through a unified interface. Each channel adapter normalizes platform-specific messages into a canonical format before they reach the execution engine.
Architecture
All channels route through a single gateway layer. Inbound messages are normalized
to a GatewayMessage struct before any execution logic sees them.
Responses follow the reverse path through the same adapter.
Gateway guarantees
- Every inbound adapter verifies the platform's webhook signature before processing
- Messages are size-limited (64 KB) and attachment-limited (8 attachments) before reaching the agent
- Rate limiting is applied per-channel and per-sender independently
- Channel credentials are isolated per adapter instance — no cross-channel credential sharing
- A maximum of 16 channels can be registered simultaneously
Supported channels
Slack
The Slack adapter uses the Slack Events API for inbound messages and the Slack Web API for outbound delivery. Both plain-text and Block Kit responses are supported.
What it supports
- App mentions (
@your-bot message) - Slash commands (
/zt command) - Direct messages
- Block Kit interactive components (button clicks, select menus)
- Thread replies
- Ephemeral messages (visible only to the sender)
Setup
- Create a Slack app at
api.slack.com/apps. Enable Event Subscriptions and addapp_mentionandmessage.imto the event subscriptions list. - Set the webhook URL to your 0trace endpoint:
https://<your-host>/webhook/slack - Store credentials via
zt credentials store:- Signing secret (from Basic Information → App Credentials)
- Bot token (
xoxb-…from OAuth & Permissions)
- Configure the channel adapter in your 0trace config:
channels: slack: signing_secret_handle: zt:cred:slack-signing-secret bot_token_handle: zt:cred:slack-bot-token workspace_id: T0123456789
Security
Every inbound request is verified against X-Slack-Signature using
HMAC-SHA256 and the signing secret. Requests older than 5 minutes are rejected
to prevent replay attacks. The bot token is never echoed to any channel.
User IDs are treated as PII and redacted in audit logs.
Telegram
The Telegram adapter connects via the Bot API using either webhook or long-polling mode. Webhook mode is recommended for production deployments.
What it supports
- Text messages in private chats and groups
- Bot commands (
/start,/help, custom commands) - Inline keyboard buttons
- File and photo attachments
- Edited messages
Setup
- Create a bot via
@BotFatheron Telegram and copy the bot token. - Store the bot token:
zt credentials store --provider telegram --name bot_token - Configure the adapter:
channels: telegram: bot_token_handle: zt:cred:telegram-bot-token webhook_url: https://<your-host>/webhook/telegram allowed_user_ids: [123456789] # Optional: restrict to specific users - Register the webhook (0trace does this automatically on startup).
A standalone
zt channels telegram register-webhookcommand is planned but not yet wired into the CLI.
Security
Telegram webhook requests are verified using a secret token sent in the
X-Telegram-Bot-Api-Secret-Token header. The adapter generates this token
automatically and registers it with the Telegram API during setup. Use
allowed_user_ids to restrict which Telegram users can invoke your agent.
Discord
The Discord adapter uses the Discord Interactions API (slash commands and message components) and the Gateway API for message events. Both HTTP interaction endpoints and Gateway WebSocket connections are supported.
What it supports
- Slash commands (
/ztapplication commands) - Message component interactions (buttons, select menus)
- Direct messages to the bot
- Guild (server) messages with bot mention
- Thread creation and replies
Setup
- Create a Discord application at the Discord Developer Portal. Under Bot, enable Message Content Intent.
- Set the Interactions Endpoint URL to
https://<your-host>/webhook/discord. - Store credentials:
zt credentials store --provider discord --name bot_token zt credentials store --provider discord --name public_key - Configure the adapter:
channels: discord: bot_token_handle: zt:cred:discord-bot-token public_key_handle: zt:cred:discord-public-key application_id: "123456789012345678"
Security
Interaction requests are verified using Ed25519 signature verification against the application's public key. The bot token is never included in responses.
The WhatsApp adapter uses the WhatsApp Business API (Meta Cloud API) to send and receive messages. A Meta Business Account and approved WhatsApp Business App are required.
What it supports
- Text messages
- Template messages (pre-approved message templates)
- Interactive messages (list messages, reply buttons)
- Media messages (images, documents, audio)
- Read receipts and delivery status
Setup
- Create a Meta Business account and add the WhatsApp product. Get a permanent system user token from Business Settings → System Users.
- Set the webhook URL to
https://<your-host>/webhook/whatsappand subscribe tomessagesevents. - Store credentials:
zt credentials store --provider whatsapp --name access_token zt credentials store --provider whatsapp --name verify_token - Configure the adapter:
channels: whatsapp: access_token_handle: zt:cred:whatsapp-access-token verify_token_handle: zt:cred:whatsapp-verify-token phone_number_id: "123456789"
WebChat
The WebChat adapter provides an embeddable chat widget that connects to the 0trace
agent via WebSocket. It is served directly by zt serve at
/chat and can be embedded in any web page via a script tag.
What it supports
- Real-time bidirectional messaging via WebSocket
- Markdown rendering in responses
- File attachment uploads
- Conversation history (session-scoped)
- Customizable theme (colors, fonts, logo)
- Anonymous or authenticated sessions (JWT-based)
Embedding the widget
<script>
window.ZtChatConfig = {
host: "https://your-0trace-host.example.com",
token: "your-public-widget-token",
theme: {
primaryColor: "#10ffb5",
fontFamily: "Inter, sans-serif"
}
};
</script>
<script src="https://your-0trace-host.example.com/chat/widget.js" async></script> Configuration
channels:
webchat:
public_token: "your-public-widget-token" # Non-secret, embeddable
allowed_origins:
- "https://your-website.com"
session_ttl_hours: 24 Security
WebSocket connections require a public widget token (non-secret, safe to embed).
Authenticated sessions can be enabled by passing a signed JWT from your application.
CORS is enforced against allowed_origins.
Signal
The Signal adapter uses the Signal Messenger REST API via
signal-cli-rest-api.
A running signal-cli instance is required.
signal-cli dependency requires a separate
process and a linked Signal account.
What it supports
- Text messages in direct and group conversations
- File attachments
- Read receipts
Setup
- Run signal-cli-rest-api alongside 0trace (Docker Compose recommended):
services: signal-cli: image: bbernhard/signal-cli-rest-api:latest environment: - MODE=native volumes: - ./signal-data:/home/.local/share/signal-cli ports: - "8080:8080" - Register or link a Signal account via the signal-cli API (see signal-cli docs).
- Configure the adapter:
channels: signal: api_url: "http://signal-cli:8080" phone_number: "+15551234567"
Security
Webhook signature verification
Every channel adapter verifies its platform's webhook signature on every inbound request. Requests with invalid or missing signatures are rejected before any processing occurs.
| Channel | Verification Method |
|---|---|
| Slack | HMAC-SHA256 with signing secret and X-Slack-Signature header |
| Telegram | Secret token in X-Telegram-Bot-Api-Secret-Token header |
| Discord | Ed25519 signature with application public key |
HMAC-SHA256 with X-Hub-Signature-256 header | |
| WebChat | Public widget token (CORS enforced) |
| Signal | Local API (network isolation recommended) |
Credential isolation
Each channel adapter holds its credentials as opaque handles — the raw bot tokens and signing secrets live in the 0trace credential vault and are never written to config files or logs. An adapter compromise cannot escalate to other channels.
Rate limiting
Rate limiting is applied at two levels: per-channel (protecting the execution engine from a flood on one channel) and per-sender (preventing a single user from monopolizing capacity). Requests that exceed limits receive an error response; the gateway queue has a maximum depth of 1,024 pending messages.