Channels
Deliver agents to end users via embeddable chat widgets, Slack, email, or phone. Agents meet users where they are — and every channel is AgentCo-branded.
Chat embed
Add a chat widget to any website with a single script tag. Customize colors, position, title, and placeholder text to match your brand.
import { Theazo } from 'theazo'
const theazo = new Theazo({ apiKey: 'th_live_...' })
const widget = await theazo.channels.chatEmbed({
agent: 'support_agent',
theme: {
primaryColor: '#6366f1',
position: 'bottom-right',
title: 'AI Support',
placeholder: 'Ask anything...',
},
})
console.log(widget.id) // 'ch_abc'
console.log(widget.scriptTag)
// '<script src="https://widget.theazo.com/w/ch_abc.js"></script>'Drop the scriptTag into any HTML page. The widget handles conversation creation, message streaming, and reconnection automatically.
Public widget endpoints
Chat widgets run in end-user browsers where there is no API key. Theazo exposes a set of unauthenticated endpoints scoped to a channel ID — the channel ID itself acts as the auth token. These routes are mounted outside the API key auth middleware.
/v1/channels/:id/messagesSend a message (no API key needed, channel ID is the auth)/v1/channels/:id/messagesGet message history for a visitor/v1/channels/:id/streamSSE stream for real-time responsesThese endpoints are designed for browser-side use. No API key or authorization header is required — the channel ID in the URL controls access.
// Send a message from the browser — no API key needed
const res = await fetch('https://api.theazo.com/v1/channels/ch_abc/messages', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
visitorId: 'user_456',
message: 'How do I reset my password?',
}),
})
const data = await res.json()
console.log(data.messageId) // 'msg_x1y2z3'
// Stream the agent's response in real time
const sse = new EventSource(
'https://api.theazo.com/v1/channels/ch_abc/stream?visitorId=user_456'
)
sse.onmessage = (event) => {
const chunk = JSON.parse(event.data)
console.log(chunk.text) // partial response text
}Visitor identity
Visitors are identified by a visitorId string passed by the widget. Each unique visitorId gets its own conversation thread within the channel.
If no visitorId is provided, one is auto-generated per browser session and stored in sessionStorage. This means anonymous visitors keep their conversation for the duration of the tab, but start fresh on reload.
{
"visitorId": "user_456",
"message": "hello"
}visitorId (like your app's user ID) to preserve conversation history across sessions. Anonymous visitors get a random ID scoped to sessionStorage.Rate limiting
Public widget endpoints are rate-limited via a Redis sliding window to prevent abuse. Three independent limits are enforced on every request:
100 messages/minPer channel — total throughput across all visitors20 messages/minPer visitor — scoped by visitorId30 messages/minPer IP address — prevents single-origin floodingWhen any limit is exceeded, the endpoint returns 429 Too Many Requests with a Retry-After header indicating how many seconds to wait.
// 429 Too Many Requests
// Retry-After: 12
{
"error": "rate_limit_exceeded",
"message": "Visitor rate limit exceeded (20/min). Retry after 12 seconds.",
"retryAfter": 12
}Slack
Connect an agent to one or more Slack channels. The bot listens for messages, runs the agent, and replies in-thread.
await theazo.channels.slack({
agent: 'team_assistant',
workspace: 'T01234567',
channels: ['#general', '#support'],
botName: 'Acme Bot',
})
// Bot appears in Slack as "Acme Bot"
// Responds to @mentions and DMschat:write, app_mentions:read, and channels:history scopes. Configure the OAuth redirect URL in your Theazo dashboard under Settings.Route incoming emails to an agent. The agent processes the email content and sends a response from your domain.
await theazo.channels.email({
agent: 'email_handler',
address: 'support@yourproduct.com',
})
// Incoming emails to support@yourproduct.com trigger the agent
// Agent reads the email, processes it, and sends a replyConfigure DNS records (MX, SPF, DKIM) for your domain in Settings to enable email receiving. Theazo handles parsing, threading, and attachment extraction.
Phone
Connect a phone number to an agent for voice conversations. Powered by Twilio for telephony and real-time voice synthesis.
await theazo.channels.phone({
agent: 'phone_agent',
phoneNumber: '+1234567890',
voice: 'alloy',
})
// Incoming calls to +1234567890 connect to the agent
// Agent speaks using the selected voice modelManaging channels
List channels
const channels = await theazo.channels.list()
// channels = [
// { id: 'ch_001', type: 'chat_embed', enabled: true, conversationCount: 1243 },
// { id: 'ch_002', type: 'slack', enabled: true, conversationCount: 872 },
// { id: 'ch_003', type: 'email', enabled: true, conversationCount: 3456 },
// { id: 'ch_004', type: 'phone', enabled: false, conversationCount: 567 },
// ]Update a channel
await theazo.channels.update('ch_001', {
config: {
theme: {
primaryColor: '#10b981',
title: 'Help Center',
},
},
})Disable and enable
Disabling a channel stops it from accepting new conversations. Existing conversations are not affected.
// Disable — stops accepting new conversations
await theazo.channels.disable('ch_001')
// Re-enable
await theazo.channels.enable('ch_001')View conversations
const conversations = await theazo.channels.conversations('ch_001')
// conversations = [
// { id: 'conv_01', userId: 'user_42', messageCount: 12, ... },
// { id: 'conv_02', userId: 'user_99', messageCount: 3, ... },
// ]Test a channel
Send a test message through a channel to verify it's configured correctly.
const result = await theazo.channels.test('ch_001')
console.log(result.ok) // true
console.log(result.message) // 'Test message sent via chat_embed'Delete a channel
await theazo.channels.delete('ch_001')
// Channel is permanently removed
// Existing conversations are preserved in logsAPI reference
theazo.channels.chatEmbed(opts)Promise<Channel>Create a chat embed widget. Returns channel with scriptTag for embedding.theazo.channels.slack(opts)Promise<Channel>Connect an agent to Slack channels. Requires workspace ID and channel names.theazo.channels.email(opts)Promise<Channel>Route emails to an agent. Requires a configured email address.theazo.channels.phone(opts)Promise<Channel>Connect a phone number to an agent. Requires Twilio integration.theazo.channels.list()Promise<Channel[]>List all channels for the platform.theazo.channels.get(id)Promise<Channel>Get a channel by ID.theazo.channels.update(id, opts)Promise<Channel>Update channel config or enabled status.theazo.channels.disable(id)Promise<Channel>Disable a channel. Stops accepting new conversations.theazo.channels.enable(id)Promise<Channel>Re-enable a disabled channel.theazo.channels.delete(id)Promise<void>Permanently delete a channel.theazo.channels.conversations(id)Promise<Conversation[]>List conversations for a channel.theazo.channels.test(id)Promise<TestResult>Send a test message through the channel.REST endpoints
/v1/channelsCreate a channel (type discriminates config shape)/v1/channelsList all channels/v1/channels/:idGet channel by ID/v1/channels/:idUpdate channel config or enabled status/v1/channels/:idDelete a channel/v1/channels/:id/conversationsList conversations for a channel/v1/channels/:id/testSend a test message