Communication Channels API
Channels connect external messaging platforms, email, and automation triggers to Kaman agents and workflows. Each channel type has a channel definition (registered at startup) and one or more channel instances (configured by users). When a message arrives on an external platform, the channel instance parses it, routes it downstream to an agent or workflow, and sends the response back through the same platform.
Base URLs
Channel operations use two route groups:
/api/agent/channels # Channel definitions and legacy webhooks
/api/agent/channel-instances # Channel instance CRUD
/api/agent/verification # Identity verification
For self-hosted installations, prepend your instance URL: http://kaman.ai/api/agent/channels
Channel Definitions
Channel definitions are registered automatically at server startup from the implementation files. Each definition describes a channel type, its configuration schema, and setup instructions.
List All Channel Definitions
GET /api/agent/channels
Returns all registered channel definitions.
curl -X GET "http://kaman.ai/api/agent/channels" \
-H "Authorization: Bearer kam_your_api_key"
Response
[
{
"id": "slack",
"name": "Slack Channel",
"description": "Channel for sending and receiving messages via Slack Bot API and slash commands.",
"configDefinition": "[{\"name\":\"botToken\",\"type\":\"string\",\"description\":\"...\",\"required\":true}, ...]",
"type": "slack",
"setupInstructions": {
"webhookRequired": true,
"webhookPath": "webhook",
"title": "Slack App Webhook Setup",
"steps": ["..."],
"docsUrl": "https://api.slack.com/apis/connections/events-api"
}
}
]
Get Channel Definition by ID
GET /api/agent/channels/:type
| Parameter | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | Channel definition ID (e.g., slack, telegram, cron) |
curl -X GET "http://kaman.ai/api/agent/channels/slack" \
-H "Authorization: Bearer kam_your_api_key"
Get Channel Status
Returns the status of connected channel microservices (WebSocket connections).
GET /api/agent/channels/status
curl -X GET "http://kaman.ai/api/agent/channels/status" \
-H "Authorization: Bearer kam_your_api_key"
Response
{
"success": true,
"connectedChannels": { ... },
"timestamp": "2026-02-17T10:00:00.000Z"
}
Channel Instances
Channel instances are user-created configurations that bind a channel definition to a downstream agent or workflow.
List My Channel Instances
GET /api/agent/channel-instances
Returns all active channel instances for the authenticated user.
curl -X GET "http://kaman.ai/api/agent/channel-instances" \
-H "Authorization: Bearer kam_your_api_key"
Response
[
{
"id": 1,
"channelId": "slack",
"channelName": "Sales Bot",
"downStreamResourceId": "agent::42_0",
"config": {
"botToken": "xoxb-...",
"signingSecret": "abc123..."
},
"userId": "user-123",
"status": "active",
"channelType": "Slack Channel",
"channelTypeName": "slack"
}
]
Get Channel Instance by ID
GET /api/agent/channel-instances/:instanceId
| Parameter | Type | Required | Description |
|---|---|---|---|
| instanceId | string | Yes | Channel instance ID |
curl -X GET "http://kaman.ai/api/agent/channel-instances/1" \
-H "Authorization: Bearer kam_your_api_key"
Create Channel Instance
POST /api/agent/channel-instances
Also available at POST /api/agent/channels (legacy route). Both routes accept the same payload.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| channelId | string | Yes | Channel definition ID (e.g., slack, telegram) |
| channelName | string | Yes | Display name for this instance |
| config | object | Yes | Channel-specific configuration (see per-channel docs below) |
| downStreamResourceId | string | No | Target resource. Format: agent::agentId_expertIndex, workflow::workflowId, or function::functionId |
| id | number | No | If provided and exists, updates the existing instance (upsert) |
curl -X POST "http://kaman.ai/api/agent/channel-instances" \
-H "Authorization: Bearer kam_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"channelId": "telegram",
"channelName": "Support Bot",
"downStreamResourceId": "agent::5_0",
"config": {
"botToken": "123456:ABC-DEF..."
}
}'
Response (201 Created)
{
"success": true,
"message": "Channel instance created.",
"instanceId": 7,
"microserviceConnected": false,
"operation": "created",
"webhookRegistered": true,
"webhookError": null
}
The webhookRegistered field is only present for Telegram channels, where the webhook is automatically registered with the Telegram Bot API on creation.
Uniqueness Constraint
The combination of userId + channelName + channelId must be unique among active instances. Attempting to create a duplicate returns 409 Conflict.
Update Channel Instance
PUT /api/agent/channel-instances/:instanceId
| Parameter | Type | Required | Description |
|---|---|---|---|
| instanceId | string | Yes | Channel instance ID |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| config | object | Yes | Updated channel configuration |
| downStreamResourceId | string | No | Updated target resource |
| channelName | string | No | Updated display name |
curl -X PUT "http://kaman.ai/api/agent/channel-instances/7" \
-H "Authorization: Bearer kam_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"config": {
"botToken": "123456:ABC-DEF...",
"parseMode": "MarkdownV2"
}
}'
Response (200 OK)
{
"success": true,
"message": "Channel instance updated successfully.",
"instanceId": 7,
"microserviceConnected": false,
"webhookRegistered": true
}
Ownership is enforced: only the user who created the instance can update it. Returns 403 Forbidden on mismatch.
Delete Channel Instance
DELETE /api/agent/channel-instances/:instanceId
Also available at DELETE /api/agent/channels/instance/:instanceId (legacy route).
| Parameter | Type | Required | Description |
|---|---|---|---|
| instanceId | string | Yes | Channel instance ID |
curl -X DELETE "http://kaman.ai/api/agent/channel-instances/7" \
-H "Authorization: Bearer kam_your_api_key"
Response (200 OK)
{
"success": true,
"message": "Channel instance deleted successfully.",
"instanceId": "7"
}
Deletion permanently removes the instance from the database. For Telegram channels, the webhook is automatically deleted from the Telegram Bot API. For cron-based channels, all scheduled jobs are cleaned up.
Request WhatsApp Pairing Code
Only available for WhatsApp (Baileys) channel instances. Forces a new pairing code to be generated.
POST /api/agent/channel-instances/:instanceId/request-pairing
curl -X POST "http://kaman.ai/api/agent/channel-instances/12/request-pairing" \
-H "Authorization: Bearer kam_your_api_key"
Response (200 OK)
{
"success": true,
"pairingCode": "A1B2C3D4",
"message": "Your pairing code is: A1B2C3D4. Open WhatsApp > Settings > Linked Devices > Link with phone number, then enter this code."
}
If the code cannot be generated within 20 seconds, returns success: false with pairingCode: null.
Webhook Callback Endpoint
External platforms (Slack, Telegram, WhatsApp, etc.) send messages to this endpoint:
ALL /api/agent/channels/:type/:instanceId/:callback
| Parameter | Type | Description |
|---|---|---|
| type | string | Channel definition ID (e.g., slack, telegram) |
| instanceId | string | Channel instance ID |
| callback | string | Callback identifier (usually webhook) |
For example, the webhook URL for a Telegram instance with ID 7 is:
POST http://kaman.ai/api/agent/channels/telegram/7/webhook
This endpoint does not require authentication -- it accepts raw webhook payloads from external platforms. Each channel implementation handles its own signature verification (e.g., Slack signing secret, Discord Ed25519, WhatsApp X-Hub-Signature-256).
Downstream Resource Routing
The downStreamResourceId field determines where incoming messages are routed:
| Format | Example | Description |
|---|---|---|
agent::id_index | agent::42_0 | Routes to LangGraph AI agent. The _0 is the expert index (defaults to _0 if omitted). |
app::id_index | app::10_0 | Routes to an application. |
workflow::id | workflow::55 | Routes to a DAG workflow execution. |
function::id | function::101 | Routes to a single function call. |
id (no prefix) | 42 | Defaults to agent::42_0. |
Per-Channel Configuration Reference
Each channel type requires specific configuration fields when creating an instance. All channels also support two optional access control fields:
| Field | Type | Required | Description |
|---|---|---|---|
| identifyUsers | boolean | No | Enable sender identity resolution. Maps external sender IDs to Kaman users. |
| accessMode | string | No | "open" (default) allows anyone; "allowlist" only allows verified Kaman users. |
These fields are listed below per channel only where the channel explicitly supports them.
Slack
Channel ID: slack
Type: Webhook (Events API + Slash Commands)
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
| botToken | string | Yes | Slack Bot User OAuth Token (starts with xoxb-) |
| signingSecret | string | Yes | Slack App Signing Secret for webhook verification |
| defaultChannel | string | No | Default Slack channel ID to send messages to |
| appId | string | No | Slack App ID |
| identifyUsers | boolean | No | Enable sender identity resolution |
| accessMode | string | No | "open" or "allowlist" |
Webhook URL
POST http://kaman.ai/api/agent/channels/slack/{instanceId}/webhook
Message Handling
- Responds to Slack URL verification challenges (
type: "url_verification") - Verifies
X-Slack-Signatureheader using HMAC-SHA256 with the signing secret - Handles slash commands via
msg.command(returns ephemeral acknowledgment, sends full response async) - Handles bot mentions and direct messages via Events API (
msg.event.type === "message") - Sends file artifacts using Slack's three-step upload flow (
files.getUploadURLExternal, upload,files.completeUploadExternal)
Setup Steps
- Go to https://api.slack.com/apps and select or create your app
- Navigate to Event Subscriptions and enable Events
- Paste the Webhook URL shown above
- Subscribe to bot events:
message.im,app_mention,message.channels - Optionally add slash commands under Slash Commands
- Install/reinstall the app to your workspace
Microsoft Teams
Channel ID: teams
Type: Webhook (Bot Framework + Incoming Webhook)
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
| webhookUrl | string | No | Microsoft Teams Incoming Webhook URL |
| appId | string | No | Microsoft Bot Framework App ID |
| appPassword | string | No | Microsoft Bot Framework App Password |
| tenantId | string | No | Azure AD Tenant ID (for enterprise bots) |
| identifyUsers | boolean | No | Enable sender identity resolution |
| accessMode | string | No | "open" or "allowlist" |
At least one of webhookUrl or appId+appPassword should be provided.
Webhook URL
POST http://kaman.ai/api/agent/channels/teams/{instanceId}/webhook
Message Handling
- Handles Bot Framework
messageactivities (text messages) - Handles
invokeactivities for adaptive card actions (adaptiveCard/action) - Dual response mode: sends via incoming webhook (MessageCard format) or via Bot Framework REST API with OAuth2 token
- Sends file artifacts as Hero Cards with download buttons (Bot Framework) or MessageCards with OpenUri actions (webhook)
Setup Steps
- Go to Azure Portal and create a Bot Channels Registration
- Copy the Microsoft App ID and create a client secret (App Password)
- In Bot settings, add Microsoft Teams as a channel
- Set the Messaging Endpoint to the Webhook URL above
- In Teams Admin Center, approve the bot for your organization
- Alternatively, for outgoing messages only, use an Incoming Webhook URL
Mattermost
Channel ID: mattermost
Type: Webhook (Outgoing Webhook)
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
| MM_URL | string | Yes | Mattermost server URL |
| channelId | string | Yes | Mattermost channel ID to post messages in |
| token | string | Yes | Authentication token for Mattermost API access |
| identifyUsers | boolean | No | Enable sender identity resolution |
| accessMode | string | No | "open" or "allowlist" |
Webhook URL
POST http://kaman.ai/api/agent/channels/mattermost/{instanceId}/webhook
Message Handling
- Verifies incoming webhook token against configured
token - Extracts
user_idandtextfrom the outgoing webhook payload - Sends replies via
response_urlwithBearertoken authorization - Sends file artifacts by uploading via
POST /api/v4/filesthen creating a post with the file attached
Setup Steps
- Log in to your Mattermost instance as an admin
- Go to Main Menu > Integrations > Outgoing Webhooks
- Click Add Outgoing Webhook
- Set a Title and Description
- Choose the channel(s) to listen to, or use Trigger Words
- Paste the Callback URL (Webhook URL) shown above
- Click Save and copy the generated Token
Discord
Channel ID: discord
Type: Webhook (Interactions Endpoint)
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
| botToken | string | Yes | Discord Bot Token |
| applicationId | string | Yes | Discord Application ID |
| publicKey | string | No | Application Public Key for Ed25519 webhook verification |
| defaultChannelId | string | No | Default channel ID for sending messages |
| identifyUsers | boolean | No | Enable sender identity resolution |
| accessMode | string | No | "open" or "allowlist" |
Webhook URL
POST http://kaman.ai/api/agent/channels/discord/{instanceId}/webhook
Message Handling
- Responds to Discord PING interactions (
type: 1) with PONG (type: 1) - Verifies Ed25519 signatures using
X-Signature-Ed25519andX-Signature-Timestampheaders - Handles slash commands (
type: 2, APPLICATION_COMMAND) with deferred responses (type: 5) - Handles message components (
type: 3, buttons and selects) - Handles regular bot mentions/DMs (removes mention tags from text)
- Splits messages exceeding Discord's 2000 character limit
- Sends file artifacts as multipart form uploads to Discord's REST API
Setup Steps
- Go to https://discord.com/developers/applications and select your application
- Navigate to General Information and copy the Application ID and Public Key
- Go to Bot section and copy the Bot Token
- Paste the Webhook URL into Interactions Endpoint URL and save
- Discord will verify the endpoint automatically
- Invite the bot to a server using the OAuth2 URL Generator
Telegram
Channel ID: telegram
Type: Webhook (auto-registered)
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
| botToken | string | Yes | Telegram Bot Token (from @BotFather) |
| parseMode | string | No | Message parse mode: HTML (default), Markdown, or MarkdownV2 |
| disableWebPagePreview | boolean | No | Disable link previews in messages |
| identifyUsers | boolean | No | Enable sender identity resolution |
| accessMode | string | No | "open" or "allowlist" |
Webhook URL
POST http://kaman.ai/api/agent/channels/telegram/{instanceId}/webhook
The webhook is automatically registered with the Telegram Bot API when you create or update the channel instance. No manual webhook setup is needed. The webhook is also re-registered on server startup and automatically deleted when the instance is deleted.
Message Handling
- Verifies
X-Telegram-Bot-Api-Secret-Tokenheader using a deterministic SHA-256 hash of the bot token - Handles regular messages (
msg.message) - Handles edited messages (
msg.edited_message) - Handles callback queries (
msg.callback_query) for inline keyboard buttons - Responds to
/startand/helpcommands with a greeting - Splits messages exceeding Telegram's 4096 character limit
- Sends image artifacts via
sendPhoto, all other file types viasendDocument
Setup Steps
- Create a bot with @BotFather on Telegram and get your Bot Token
- Paste the Bot Token in the config and save
- The webhook is registered automatically -- no manual setup needed
- Start chatting with your bot on Telegram
WhatsApp Business
Channel ID: whatsapp
Type: Webhook (Meta Cloud API)
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
| phoneNumberId | string | Yes | WhatsApp Business Phone Number ID |
| accessToken | string | Yes | WhatsApp Business API Access Token |
| webhookVerifyToken | string | Yes | Webhook verification token (you choose this, must match Meta config) |
| appSecret | string | No | Meta App Secret for X-Hub-Signature-256 webhook verification |
| apiVersion | string | No | WhatsApp API version (default: v21.0) |
| identifyUsers | boolean | No | Enable sender identity resolution by phone number |
| accessMode | string | No | "open" or "allowlist" |
Webhook URL
POST http://kaman.ai/api/agent/channels/whatsapp/{instanceId}/webhook
Also accepts GET for Meta's webhook verification challenge (hub.mode, hub.challenge, hub.verify_token).
Message Handling
- Handles
GETrequests for Meta's webhook subscription verification - Verifies
X-Hub-Signature-256header using HMAC-SHA256 with the app secret - Parses the Meta webhook payload structure (
entry[0].changes[0].value.messages[0]) - Extracts text from both
text.bodyandinteractive.button_reply.title - Uses the sender's phone number as the session ID for conversation continuity
- Sends file artifacts by uploading media to WhatsApp Cloud API then sending a media message (image, video, audio, or document)
Setup Steps
- Go to Meta for Developers (https://developers.facebook.com) and select your app
- Navigate to WhatsApp > Configuration
- Under Webhook, click Edit and paste the Webhook URL
- Enter your Webhook Verify Token (must match the
webhookVerifyTokenconfig) - Click Verify and Save
- Subscribe to the
messageswebhook field - Ensure your WhatsApp Business Account is linked
WhatsApp (Baileys)
Channel ID: baileys-whatsapp
Type: Persistent WebSocket connection (pairing code auth)
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
| phoneNumber | string | Yes | Your WhatsApp phone number with country code (e.g., 972501234567) |
| allowedNumbers | string | No | Comma-separated list of allowed phone numbers (e.g., 972501234567,14155551234). Leave empty to allow all. |
| identifyUsers | boolean | No | Enable sender identity resolution by phone number |
| accessMode | string | No | "open" or "allowlist" |
This channel does not use webhooks. It maintains a persistent WebSocket connection to WhatsApp Web using the Baileys library.
Pairing Flow
- Create the channel instance with your phone number
- A pairing code is generated automatically and sent as a notification
- On your phone, open WhatsApp > Settings > Linked Devices > Link a Device
- Choose Link with phone number and enter the pairing code
- Once paired, the channel connects automatically
To request a new pairing code at any time:
curl -X POST "http://kaman.ai/api/agent/channel-instances/{instanceId}/request-pairing" \
-H "Authorization: Bearer kam_your_api_key"
Message Handling
- Receives all incoming messages via the Baileys WebSocket listener
- Filters by
allowedNumbersif configured - Supports text messages, image messages, document messages, video messages, and audio messages
- Downloads received media files and forwards them to the agent as file inputs
- Sends file artifacts natively via WhatsApp (image, video, audio, document)
- Auth state is persisted in S3 storage, surviving server restarts
- Automatically reconnects on connection drops (3-second backoff)
- On logout, clears auth state and requests a new pairing code
Instance Status
The config.waStatus field in the instance reflects the connection state:
| Status | Description |
|---|---|
pairing | Waiting for the user to enter the pairing code |
connected | Successfully connected to WhatsApp |
logged_out | Session was logged out, re-pairing in progress |
Twilio SMS
Channel ID: twilio-sms
Type: Webhook
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
| accountSid | string | Yes | Twilio Account SID |
| authToken | string | Yes | Twilio Auth Token |
| twilioPhoneNumber | string | Yes | Your Twilio phone number in E.164 format (e.g., +1234567890) |
| messagingServiceSid | string | No | Twilio Messaging Service SID for advanced routing |
| identifyUsers | boolean | No | Enable sender identity resolution by phone number |
| accessMode | string | No | "open" or "allowlist" |
Webhook URL
POST http://kaman.ai/api/agent/channels/twilio-sms/{instanceId}/webhook
Message Handling
- Validates incoming
AccountSidagainst configured account - Extracts
From,To,Body, andMessageSidfrom the Twilio form-urlencoded payload - Returns a TwiML
<Response><Message>acknowledgment - Handles status callbacks (
MessageStatus,SmsStatus) - Splits outgoing messages at 1500 characters (Twilio handles concatenation)
- Sends image artifacts via MMS using
MediaUrl; other file types as text with download link - Uses Messaging Service SID when available, otherwise sends from the configured phone number
Setup Steps
- Log in to Twilio Console (https://console.twilio.com)
- Navigate to Phone Numbers > Manage > Active Numbers
- Select the phone number to configure
- Scroll to Messaging Configuration
- Under A MESSAGE COMES IN, select Webhook and paste the URL
- Set HTTP method to HTTP POST
- Click Save configuration
Email (IMAP/SMTP)
Channel ID: email
Type: Polling (IMAP) + SMTP for sending
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
| smtpHost | string | Yes | SMTP server hostname |
| smtpPort | number | Yes | SMTP server port (587 for TLS, 465 for SSL) |
| smtpSecure | boolean | No | Use SSL for SMTP connection |
| imapHost | string | Yes | IMAP server hostname |
| imapPort | number | Yes | IMAP server port (993 for SSL, 143 for plain) |
| imapSecure | boolean | No | Use SSL for IMAP connection |
| username | string | Yes | Email account username |
| password | string | Yes | Email account password or app password |
| fromEmail | string | Yes | From email address for outgoing messages |
| checkInterval | number | No | Email check interval in minutes (default: 5) |
| identifyUsers | boolean | No | Enable sender identity resolution |
| accessMode | string | No | "open" or "allowlist" |
This channel does not use webhooks. It polls for new emails using IMAP.
Message Handling
- Uses BullMQ with Redis for repeatable polling jobs
- Connects to IMAP and searches for
UNSEENemails in the INBOX - Parses email content using
mailparser - Sends replies via SMTP with
Re:prefix on the original subject - Sends file artifacts as text messages with download links
Setup Steps
- Enter your SMTP server details (host, port, secure)
- Enter your IMAP server details (host, port, secure)
- Provide email credentials (username and password)
- For Gmail: use App Passwords (regular password will not work)
- For Office 365: use your full email as username
- Set the check interval in minutes
Gmail
Channel ID: gmail
Type: Polling (Gmail API with OAuth2)
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
| clientId | string | Yes | Google OAuth2 Client ID |
| clientSecret | string | Yes | Google OAuth2 Client Secret |
| refreshToken | string | Yes | Google OAuth2 Refresh Token |
| redirectUri | string | No | OAuth2 Redirect URI |
| checkInterval | number | No | Email check interval in minutes (default: 5) |
| identifyUsers | boolean | No | Enable sender identity resolution |
| accessMode | string | No | "open" or "allowlist" |
This channel does not use webhooks. It uses the Gmail History API for efficient polling.
Message Handling
- Uses OAuth2 with automatic token refresh via refresh token
- Initializes with
users.messages.listto get the starting history ID - Polls using
users.history.listwithhistoryTypes: ["messageAdded"]for efficient change detection - Fetches full message content (
format: "full") and parses headers and body - Handles multipart messages (extracts
text/plainparts) - Sends replies using
users.messages.sendwith base64url-encoded RFC 2822 messages - Uses BullMQ for repeatable polling jobs
Setup Steps
- Go to Google Cloud Console (https://console.cloud.google.com)
- Create or select a project and enable the Gmail API
- Go to Credentials and create an OAuth 2.0 Client ID
- Set up consent screen and add Gmail scopes
- Copy the Client ID and Client Secret
- Complete the OAuth flow to obtain a Refresh Token
HTTP Webhook
Channel ID: http-webhook
Type: Webhook (generic)
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
| responseWebhookUrl | string | No | URL to send responses to (if not provided in incoming payload) |
| webhookSecret | string | No | Secret for HMAC-SHA256 signature verification |
| messageField | string | No | JSON dot-path to the message field in the incoming payload (e.g., data.message) |
| sessionIdField | string | No | JSON dot-path to the session ID field in the incoming payload |
| responseHeaders | string | No | Custom headers for response webhook, in JSON format |
| syncResponse | boolean | No | Wait for AI response before returning (synchronous mode, 30-second timeout) |
| identifyUsers | boolean | No | Enable sender identity resolution |
| accessMode | string | No | "open" or "allowlist" |
Webhook URL
POST http://kaman.ai/api/agent/channels/http-webhook/{instanceId}/webhook
Message Handling
- Verifies
X-Webhook-Signature,X-Hub-Signature-256, orX-Signatureheaders using HMAC-SHA256 with the configured secret - Extracts the message from the configured
messageFieldpath, or falls back tomessage,text,content,body,data.message,payload.text, or the full JSON body - Extracts the session ID from the configured
sessionIdFieldpath, or falls back tosessionId,session_id,userId,user_id,id - In async mode (default): returns immediately with
status: "accepted"and sends the response toresponseUrlorresponse_urlfrom the payload, or the configuredresponseWebhookUrl - In sync mode (
syncResponse: true): blocks up to 30 seconds and returns the AI response inline - Signs outgoing response payloads with
X-Webhook-Signatureif a secret is configured
Async Response Example
{
"status": "accepted",
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"message": "Webhook received, processing asynchronously"
}
Sync Response Example
{
"status": "success",
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"response": "The AI agent's response text..."
}
Setup Steps
- Copy the Webhook URL
- Configure your external service to send POST requests with JSON payloads
- Include a
messageortextfield (or configure a custom field path) - Optionally include
sessionIdfor conversation continuity - For security, configure a webhook secret and send HMAC-SHA256 signatures in
X-Webhook-Signature - Responses are sent to the
responseUrlin the payload or the configured Response Webhook URL
Cron Scheduler
Channel ID: cron
Type: Scheduled (BullMQ + Redis)
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
| cronSchedule | string | Yes | Cron expression in 5-field format: minute hour day month weekday |
| message | string | Yes | Message to send to the agent when triggered |
| timezone | string | No | Timezone for the schedule (default: UTC) |
| enabled | boolean | No | Whether the cron job is active |
This channel does not use webhooks. It schedules jobs using BullMQ with Redis.
Cron Expression Examples
| Expression | Description |
|---|---|
0 9 * * * | Daily at 9:00 AM |
0 9 * * 1-5 | Weekdays at 9:00 AM |
*/15 * * * * | Every 15 minutes |
0 0 1 * * | First day of month at midnight |
30 8 * * 1 | Mondays at 8:30 AM |
Message Handling
- Validates the cron expression format (5 fields, valid ranges)
- Creates a BullMQ repeatable job with the cron pattern and timezone
- On each trigger, sends the configured message to the downstream agent/workflow
- Supports manual triggering via the
manual_triggercallback - Supports
oneShotmode: the instance self-destructs after a single execution - Properly cleans up BullMQ jobs when the instance is updated or deleted
Google Workspace
Channel ID: google-workspace
Type: Polling (Google Drive API with OAuth2)
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
| clientId | string | Yes | Google OAuth2 Client ID |
| clientSecret | string | Yes | Google OAuth2 Client Secret |
| refreshToken | string | Yes | Google OAuth2 Refresh Token |
| folderId | string | Yes | Google Drive Folder ID to monitor |
| checkInterval | number | No | File check interval in minutes (default: 10) |
| fileTypes | string | No | Comma-separated file types to monitor (e.g., pdf,docx,xlsx) |
| webhookUrl | string | No | Webhook URL for Google Drive push notifications |
This channel does not use external webhooks (though it optionally sets up Drive push notifications).
Message Handling
- Polls the specified Drive folder for files modified since the last check
- Filters by file extension if
fileTypesis configured - Sends file event details to the downstream agent:
"File updated: filename.pdf at https://drive.google.com/..." - Creates a response text document in the same Drive folder with the agent's output
- Optionally sets up a Drive
files.watchwebhook for push-based notifications - Uses BullMQ for repeatable polling jobs
Setup Steps
- Go to Google Cloud Console
- Create or select a project and enable the Google Drive API
- Create OAuth 2.0 Client ID credentials
- Set up consent screen and add Drive scopes
- Complete OAuth flow to obtain a Refresh Token
- Enter the Folder ID of the Drive folder to monitor
- Optionally filter by file types (e.g.,
pdf,docx)
Odoo Events
Channel ID: odoo-events
Type: Polling (JSON-RPC API)
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
| odooUrl | string | Yes | Odoo server URL (e.g., https://your-company.odoo.com) |
| database | string | Yes | Odoo database name |
| username | string | Yes | Odoo username |
| password | string | Yes | Odoo password or API key |
| models | string | Yes | Comma-separated list of models to monitor (e.g., sale.order,crm.lead,project.task) |
| events | string | Yes | Comma-separated event types to monitor: create, write, unlink |
| checkInterval | number | No | Event check interval in minutes (default: 5) |
| webhookUrl | string | No | Webhook URL for Odoo notifications (if available) |
This channel does not use external webhooks. It polls Odoo via JSON-RPC.
Message Handling
- Authenticates with Odoo via
POST /web/session/authenticate - Polls each configured model using
search_readwith awrite_date >= lastCheckTimefilter - Distinguishes between
createandwriteevents based on whethercreate_date > lastCheckTime - Sends event details to the downstream agent:
"Odoo create event in sale.order (ID: 42): {...}" - Creates response notes in Odoo using
mail.message(ornote.noteas fallback) - Uses BullMQ for repeatable polling jobs
Setup Steps
- Enter your Odoo instance URL
- Provide database name and admin credentials
- Specify which models to monitor (e.g.,
res.partner,sale.order) - Choose event types:
create,write,unlink - Set the polling interval in minutes
- Ensure API access is enabled for your Odoo user
Identity Verification
The verification system allows users to link their external identities (phone, Telegram, email, Slack, Discord, Mattermost) to their Kaman account. Once verified, channels with identifyUsers: true can resolve incoming messages to Kaman users for access control and billing attribution.
Get Available Verification Providers
GET /api/agent/verification/providers
No authentication required.
curl -X GET "http://kaman.ai/api/agent/verification/providers"
Response
{
"success": true,
"providers": {
"telegram": true,
"email": true,
"slack": false,
"discord": false,
"mattermost": false
}
}
Each provider is true only if the required environment variables are configured on the server.
Get My Verified Identities
GET /api/agent/verification/identities
curl -X GET "http://kaman.ai/api/agent/verification/identities" \
-H "Authorization: Bearer kam_your_api_key"
Response
{
"success": true,
"identities": [
{ "field": "phone", "value": "+972501234567" },
{ "field": "telegram", "value": "123456789" },
{ "field": "whatsapp", "value": "972501234567" },
{ "field": "email", "value": "user@example.com" }
]
}
Known identity types: phone, telegram, whatsapp, email, slack, discord, mattermost, teams.
Telegram Verification
Verifies phone number and Telegram ID simultaneously using a Telegram bot.
Start Verification
POST /api/agent/verification/start-telegram
curl -X POST "http://kaman.ai/api/agent/verification/start-telegram" \
-H "Authorization: Bearer kam_your_api_key"
Response
{
"success": true,
"deepLink": "https://t.me/KamanVerify_bot?start=abc123...",
"expiresInSeconds": 300,
"message": "Open this link to verify your phone and Telegram identity: ..."
}
The user clicks the deep link, opens the verification bot, and shares their contact. The bot verifies the phone number and Telegram user ID, then stores three identities: phone, telegram, and whatsapp.
Verification Bot Webhook (internal)
POST /api/agent/verification/telegram-bot-webhook
This is called by Telegram when users interact with the verification bot. No manual configuration needed.
Callback (internal)
POST /api/agent/verification/telegram-callback
Called by the verification bot after the user shares their contact. Requires INTERNAL_SERVICE_KEY authorization.
Email Verification
Sends a 6-digit OTP to the user's email address.
Start Verification
POST /api/agent/verification/start-email
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | Email address to verify |
curl -X POST "http://kaman.ai/api/agent/verification/start-email" \
-H "Authorization: Bearer kam_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "email": "user@example.com" }'
Response
{
"success": true,
"expiresInSeconds": 600,
"message": "Verification code sent to user@example.com"
}
Verify OTP
POST /api/agent/verification/verify-email
| Field | Type | Required | Description |
|---|---|---|---|
| otp | string | Yes | 6-digit verification code |
curl -X POST "http://kaman.ai/api/agent/verification/verify-email" \
-H "Authorization: Bearer kam_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "otp": "123456" }'
Response
{
"success": true,
"message": "Email user@example.com verified successfully",
"email": "user@example.com"
}
Slack Verification (OAuth)
Links a Slack user ID to the Kaman account via OAuth.
POST /api/agent/verification/start-slack
curl -X POST "http://kaman.ai/api/agent/verification/start-slack" \
-H "Authorization: Bearer kam_your_api_key"
Response
{
"success": true,
"authUrl": "https://slack.com/oauth/v2/authorize?client_id=...&user_scope=identity.basic&..."
}
The user opens the authUrl in a browser, authorizes the app, and the callback at GET /api/agent/verification/callback/slack completes the verification.
Discord Verification (OAuth)
POST /api/agent/verification/start-discord
Returns an authUrl for Discord OAuth with identify scope. Callback at GET /api/agent/verification/callback/discord.
Mattermost Verification (OAuth)
POST /api/agent/verification/start-mattermost
Returns an authUrl for Mattermost OAuth. Callback at GET /api/agent/verification/callback/mattermost. Requires MATTERMOST_VERIFY_URL environment variable.
OAuth Callback (unified)
GET /api/agent/verification/callback/:provider
| Parameter | Type | Description |
|---|---|---|
| provider | string | slack, discord, or mattermost |
This endpoint handles the OAuth redirect. It validates the state parameter from Redis, exchanges the authorization code for user identity, and stores the verified identity. Returns an HTML page that sends a postMessage to the opener window and auto-closes.
Environment Variables
Channel System
| Variable | Default | Description |
|---|---|---|
AGENT_URL | http://localhost:3011 | Base URL for webhook registration (used by Telegram auto-register) |
REDIS_URL | redis://localhost:6379 | Redis URL for BullMQ job queues and session data |
Verification System
| Variable | Default | Description |
|---|---|---|
PLATFORM_URL | http://localhost:3010 | Base URL for OAuth redirect callbacks |
INTERNAL_SERVICE_KEY | kaman-dev-internal-key | Service-to-service auth key |
TELEGRAM_VERIFY_BOT_TOKEN | (built-in) | Bot token for the verification bot |
TELEGRAM_VERIFY_BOT_USERNAME | KamanVerify_bot | Username of the verification bot |
SLACK_VERIFY_CLIENT_ID | Slack OAuth app Client ID for verification | |
SLACK_VERIFY_CLIENT_SECRET | Slack OAuth app Client Secret for verification | |
DISCORD_VERIFY_CLIENT_ID | Discord OAuth app Client ID for verification | |
DISCORD_VERIFY_CLIENT_SECRET | Discord OAuth app Client Secret for verification | |
MATTERMOST_VERIFY_CLIENT_ID | Mattermost OAuth app Client ID | |
MATTERMOST_VERIFY_CLIENT_SECRET | Mattermost OAuth app Client Secret | |
MATTERMOST_VERIFY_URL | Mattermost server URL for verification OAuth | |
EMAIL_HOST / SMTP_HOST | SMTP host for sending verification OTPs | |
EMAIL_PORT / SMTP_PORT | 587 | SMTP port |
EMAIL_USER / SMTP_USER | SMTP username | |
EMAIL_PASSWORD / SMTP_PASS | SMTP password | |
EMAIL_FROM / SMTP_FROM | noreply@example.com | From address for verification emails |
EMAIL_SECURE | false | Use SSL for SMTP (true for port 465) |
Database Tables
channels
Stores channel definitions (populated at startup).
| Column | Type | Description |
|---|---|---|
| id | string | Channel type ID (e.g., slack, telegram) |
| name | string | Display name |
| description | string | Channel description |
| configDefinition | jsonb | Array of configuration field definitions |
| type | string | Channel type identifier |
| setupInstructions | jsonb | Setup instructions and documentation |
channel_instances
Stores user-created channel instances.
| Column | Type | Description |
|---|---|---|
| id | serial | Instance ID |
| channelId | string | Reference to channels.id |
| channelName | string | User-assigned display name |
| downStreamResourceId | string | Target resource identifier |
| config | jsonb | Channel-specific configuration |
| userId | string | Owner user ID |
| status | string | Instance status (active) |
Unique constraint on id. Soft uniqueness enforced by code on userId + channelName + channelId among active instances.
Tool Confirmation via Channels
When an agent encounters a tool that requires human approval, the channel presents a human-readable confirmation prompt:
Tool Confirmation Required
The agent wants to use: sendEmail
Parameters: { "to": "user@example.com", "subject": "Hello" }
Reply:
"yes" -- approve this action
"always" -- approve this tool for the session
"no" -- reject
The pending confirmation is stored in Redis with a 10-minute TTL. The user's next message is checked for confirmation keywords (yes/y/approve/ok/1 for approve, always/2 for session-wide approve, no/n/reject/cancel/3 for reject). If the user sends a non-confirmation message, the pending interrupt is cleared and the message is processed normally.