API Reference
Zubo exposes a REST API on the webchat port. All endpoints are available at http://localhost:<port>. If authentication is enabled, include Authorization: Bearer <key> on all /api/* requests.
Copy-Paste Task Cards
Secure API Access
Enable API auth and create a key before exposing ports beyond localhost.
zubo config set auth.enabled true
zubo auth create-key my-app
Set Local Model Fallback
Keep responses available during provider outages or API quota issues.
zubo config set failover '["openai","ollama"]'
zubo config set providers.ollama.model llama3.3
Common Errors
If auth.enabled is true, all /api/* calls require Authorization: Bearer <key>. Create a new key if needed.
curl -H "Authorization: Bearer YOUR_KEY" http://localhost:3000/api/dashboard/status
Use failover and switch temporarily to a responsive provider or smaller model. Check logs for repeated timeout patterns.
zubo model openai/gpt-4o-mini
zubo logs --follow
If local providers fail, ensure the runtime is running and a model is installed.
ollama serve
ollama pull llama3.3
API Quickstart
# 1) Health check
curl http://localhost:3000/health
# 2) Chat request
curl -X POST http://localhost:3000/api/chat \
-H "Content-Type: application/json" \
-d '{"message":"Hello"}'
# 3) Authenticated request (when auth.enabled=true)
curl -X GET http://localhost:3000/api/dashboard/status \
-H "Authorization: Bearer YOUR_API_KEY"
Prefer /api/chat/stream for interactive UIs and /api/chat for simpler request/response integrations.
Health Check
GET /health
Returns the current health status and uptime of the Zubo agent. This endpoint does not require authentication, even when auth.enabled is true.
Response:
{
"status": "ok",
"uptime": 3600
}
Chat
Send Message
POST /api/chat
Content-Type: application/json
{
"message": "Hello, how are you?"
}
Sends a message to the agent and returns a complete response once the agent has finished processing.
Response:
{
"reply": "I'm doing well! How can I help?"
}
Stream Message (SSE)
POST /api/chat/stream
Content-Type: application/json
{
"message": "Tell me about AI"
}
Sends a message and receives the response as a Server-Sent Events stream. This allows the UI to display partial responses as they are generated. The stream emits the following event types:
| Event | Data | Description |
|---|---|---|
delta | { "text": "partial text" } | A chunk of the response text as it is generated. |
tool | { "name": "web_search", "status": "start" } | Indicates a tool call has started. Status is "start" or "end". |
done | { "reply": "full response text" } | The complete response. Sent once at the end of the stream. |
error | { "error": "error message" } | An error occurred during processing. |
Chat History
GET /api/chat/history?limit=50
Returns the recent conversation history. Tool calls are filtered out — only user and assistant text messages are returned.
Query parameters:
| Parameter | Default | Description |
|---|---|---|
limit | 50 | Number of messages to return. Maximum 200. |
Response:
{
"messages": [
{ "role": "user", "content": "Hello" },
{ "role": "assistant", "content": "Hi! How can I help?" }
]
}
Voice Chat
POST /api/chat/voice
Content-Type: multipart/form-data
audio: <audio file>
tts: "true" (optional)
Send an audio file for speech-to-text transcription, then process the transcribed text through the agent. Requires an STT provider to be configured. If tts=true is included and a TTS provider is configured, the response will include base64-encoded audio of the agent's reply.
Response:
{
"transcript": "What's the weather?",
"reply": "Currently 72°F and sunny.",
"audio": "<base64 audio>",
"audioFormat": "mp3"
}
File Upload
POST /api/upload
Content-Type: multipart/form-data
file: <document>
Upload a document for memory indexing. The file is parsed, chunked, embedded, and stored in the memory database. The agent will be able to recall information from uploaded documents in future conversations.
Limits: 50MB maximum file size.
Allowed extensions: .pdf, .docx, .txt, .md, .csv, .json, .html, .xml, .yaml, .yml, .ts, .js, .py, .sh
Response:
{
"uploaded": true,
"filename": "report.pdf",
"size": 245760,
"chunks": 12,
"wordCount": 5430
}
Dashboard API
All dashboard endpoints are under /api/dashboard/. These power the built-in web UI and can also be used by external tools and integrations.
Status
GET /api/dashboard/status
Returns an overview of the agent's current state, including the active provider, connected channels, message count, memory count, and running status.
{
"Provider": "anthropic/claude-sonnet-4-5",
"Channels": "webchat, telegram",
"Messages": "1234",
"Memories": "567",
"Status": "running"
}
Personality
GET /api/dashboard/system
Retrieve the current system prompt.
PUT /api/dashboard/system
Content-Type: application/json
{
"content": "You are a helpful assistant named Zubo."
}
Update the system prompt. The new prompt takes effect on the next message.
Memory
GET /api/dashboard/memory
Get the current contents of MEMORY.md, the always-loaded memory file.
PUT /api/dashboard/memory
Content-Type: application/json
{
"content": "User's name is Thomas. Prefers concise answers."
}
Update the contents of MEMORY.md. Changes take effect on the next message.
GET /api/dashboard/memory/recent
Returns the last 20 memory chunks with their source, timestamp, and content.
GET /api/dashboard/memory/search?q=programming
Search memory chunks using hybrid retrieval (vector + full-text). Results include confidence and match rationale metadata for easier debugging and tuning.
Skills
GET /api/dashboard/skills
List all installed skills with their metadata.
Response:
{
"skills": [
{
"name": "weather",
"description": "Get current weather for a location",
"status": "active",
"path": "~/.zubo/skills/weather"
}
]
}
Cron Jobs & Reminders
GET /api/dashboard/cron
List all configured cron jobs and one-shot reminders.
Response:
{
"jobs": [
{
"name": "daily-summary",
"schedule": "0 9 * * *",
"task": "Send a daily briefing",
"enabled": true,
"once": false,
"last_run": "2026-02-12T09:00:00Z"
},
{
"name": "marketing-followup",
"schedule": "2026-02-14T15:30:00.000Z",
"task": "Hey! Have you worked on marketing yet?",
"enabled": true,
"once": true,
"last_run": null
}
]
}
Jobs with "once": true are one-shot reminders that auto-delete after firing.
Providers
GET /api/dashboard/providers
List all configured LLM providers with masked API keys, the active provider, and the failover order.
Response:
{
"providers": [
{
"name": "anthropic",
"model": "claude-sonnet-4-5-20250929",
"apiKey": "sk-ant-...xxxx",
"baseUrl": "",
"contextWindow": null,
"streaming": true
},
{
"name": "openai",
"model": "gpt-4o",
"apiKey": "sk-...xxxx",
"baseUrl": "",
"contextWindow": null,
"streaming": true
}
],
"activeProvider": "anthropic",
"failover": ["openai"]
}
PUT /api/dashboard/providers/:name
Content-Type: application/json
{
"model": "gpt-4o",
"apiKey": "sk-...",
"baseUrl": "",
"streaming": true
}
Add or update a provider configuration. If this is the first provider, it is automatically set as active. Masked API key values (containing ...) are ignored to preserve the existing key.
DELETE /api/dashboard/providers/:name
Remove a provider. If the deleted provider was active, the first remaining provider is selected. The provider is also removed from the failover list.
PUT /api/dashboard/providers/active
Content-Type: application/json
{
"provider": "openai"
}
Set the active LLM provider. The change is hot-reloaded into the running agent — no restart is needed.
PUT /api/dashboard/providers/failover
Content-Type: application/json
{
"failover": ["openai", "anthropic"]
}
Update the provider failover order. When the active provider fails, the agent tries each failover provider in the order listed.
MCP Servers
GET /api/dashboard/mcp/servers
List all configured MCP (Model Context Protocol) server connections with their current status and tool count.
Response:
{
"servers": [
{
"name": "filesystem",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem"],
"env": ["HOME"],
"enabled": true,
"connected": true,
"tools": 5
}
]
}
POST /api/dashboard/mcp/servers
Content-Type: application/json
{
"name": "filesystem",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem"],
"env": { "HOME": "/Users/me" },
"enabled": true
}
Add and connect a new MCP server. If a server with the same name already exists, it is replaced. The server is hot-connected immediately if enabled is true (or omitted).
DELETE /api/dashboard/mcp/servers/:name
Disconnect and remove an MCP server. The server process is terminated and the configuration is deleted.
POST /api/dashboard/mcp/servers/:name/restart
Restart an MCP server connection. The server is disconnected and then reconnected using its saved configuration. Returns 404 if the server is not found.
Channels Configuration
GET /api/dashboard/channels/config
Get all channel configurations with masked tokens and running status. Returns an object keyed by channel name (telegram, discord, slack, whatsapp, signal, email), each containing enabled, configured, running, and config fields.
PUT /api/dashboard/channels/:name/config
Content-Type: application/json
{
"botToken": "123456:ABC-DEF...",
"allowedUsers": ["user1"],
"enabled": true
}
Update a channel's configuration. Valid channel names are telegram, discord, slack, whatsapp, signal, and email. If enabled is true, the channel is hot-started immediately. If false, the channel is stopped. Masked token values are preserved.
PUT /api/dashboard/channels/:name/toggle
Content-Type: application/json
{
"enabled": true
}
Enable or disable a channel with immediate start or stop. The channel must already be configured.
OAuth
GET /api/dashboard/oauth/status
Get OAuth connection status for all supported providers. Returns a list of supported providers and their current connection state, including whether each provider has credentials configured.
PUT /api/dashboard/oauth/:provider/config
Content-Type: application/json
{
"clientId": "your-client-id",
"clientSecret": "your-client-secret"
}
Save OAuth client credentials for a provider (e.g. google, github). These credentials are stored in the config file and used when initiating OAuth authorization flows.
DELETE /api/dashboard/oauth/:provider/config
Remove OAuth client credentials for a provider from the configuration.
DELETE /api/dashboard/oauth/:provider
Disconnect an OAuth provider by revoking its stored tokens. The client credentials remain in the configuration.
Budget
GET /api/dashboard/budget
Get budget configuration and current usage, including today's spend, this month's spend, and a daily breakdown for the last 7 days.
Response:
{
"daily_limit_usd": 5.00,
"monthly_limit_usd": 100.00,
"alert_threshold": 0.8,
"paused": false,
"today_spend_usd": 1.2345,
"month_spend_usd": 42.50,
"daily_breakdown": [
{ "day": "2026-02-13", "cost": 1.50, "tokens": 45000 },
{ "day": "2026-02-14", "cost": 1.23, "tokens": 38000 }
]
}
PUT /api/dashboard/budget
Content-Type: application/json
{
"daily_limit_usd": 5.00,
"monthly_limit_usd": 100.00,
"alert_threshold": 0.8
}
Update budget limits. Set a field to null to remove that limit. The alert_threshold is a fraction (0–1) of the limit at which a warning is triggered. Updating the budget also resets the paused state.
Privacy & Data
GET /api/dashboard/privacy/summary
Get a summary of all stored data, including counts of memories, messages, sessions, secrets, cron jobs, API calls, tool calls, and total tokens sent and received.
Response:
{
"memoryCount": 567,
"messageCount": 1234,
"sessionCount": 15,
"secretCount": 3,
"cronCount": 2,
"apiCallCount": 890,
"toolCallCount": 456,
"totalTokensSent": 1500000,
"totalTokensReceived": 750000,
"providerBreakdown": [
{ "provider": "anthropic", "calls": 800, "tokens_sent": 1200000 }
]
}
GET /api/dashboard/privacy/api-log?limit=50&offset=0
View API call history with session ID, provider, model, token counts, cost, and response time. Supports pagination via limit (max 100) and offset query parameters.
GET /api/dashboard/privacy/tool-log?limit=50&offset=0
View tool call history with tool name, session ID, duration, and success status. Supports pagination via limit (max 100) and offset query parameters.
POST /api/dashboard/privacy/wipe-memories
Content-Type: application/json
{ "confirm": "DELETE" }
Delete all memory chunks and full-text search index. Requires { "confirm": "DELETE" } in the request body.
POST /api/dashboard/privacy/wipe-messages
Content-Type: application/json
{ "confirm": "DELETE" }
Delete all stored messages. Requires { "confirm": "DELETE" } in the request body.
POST /api/dashboard/privacy/wipe-usage
Content-Type: application/json
{ "confirm": "DELETE" }
Delete all usage analytics and tool metrics. Requires { "confirm": "DELETE" } in the request body.
POST /api/dashboard/privacy/wipe-all
Content-Type: application/json
{ "confirm": "DELETE_ALL" }
Complete data wipe: deletes all memories, messages, usage analytics, tool metrics, secrets, and cron logs. Requires { "confirm": "DELETE_ALL" } in the request body.
Threads
GET /api/dashboard/threads
List all conversation threads, ordered by most recently updated.
POST /api/dashboard/threads
Content-Type: application/json
{
"title": "Project discussion"
}
Create a new conversation thread. The title field is optional and defaults to "New conversation". Returns the generated thread id and title.
PUT /api/dashboard/threads/:id
Content-Type: application/json
{
"title": "Renamed thread"
}
Rename a thread by its ID.
DELETE /api/dashboard/threads/:id
Delete a thread and its associated session file.
GET /api/dashboard/threads/:id/messages
Get the messages in a thread (up to 100 messages). Returns the session's message array.
GET /api/dashboard/threads/:id/export
Export a thread as a Markdown file. Returns a text/markdown response with a Content-Disposition header for download.
Recipes
GET /api/dashboard/recipes
List all available workflow recipe templates with their install status. Each recipe includes its id, metadata, and an installed flag indicating whether it has already been added as a cron job.
POST /api/dashboard/recipes/install
Content-Type: application/json
{
"recipeId": "daily-summary"
}
Install a recipe as a cron job. The recipe is looked up by recipeId and inserted into the cron jobs table. Returns an error if the recipe is already installed.
POST /api/dashboard/recipes/uninstall
Content-Type: application/json
{
"recipeId": "daily-summary"
}
Uninstall a recipe by removing its cron job.
Smart Routing
GET /api/dashboard/smart-routing
Get the current smart routing configuration. Smart routing automatically directs simple queries to a faster, cheaper model while using the primary model for complex tasks.
Response:
{
"enabled": false,
"fastProvider": "openai",
"fastModel": "gpt-4o-mini"
}
PUT /api/dashboard/smart-routing
Content-Type: application/json
{
"enabled": true,
"fastProvider": "openai",
"fastModel": "gpt-4o-mini"
}
Update smart routing settings. All fields are optional — only the fields you include will be updated.
Logs
GET /api/dashboard/logs
Returns the last 100 log lines from the agent's log output.
Configuration
GET /api/dashboard/config
Returns the current configuration summary with API keys masked.
Response:
{
"agentName": "Zubo",
"activeProvider": "anthropic",
"providers": {
"anthropic": { "model": "claude-sonnet-4-5-20250929", "hasApiKey": true },
"groq": { "model": "llama-3.3-70b-versatile", "hasApiKey": true }
},
"failover": ["groq"],
"channels": {
"webchat": { "enabled": true },
"telegram": { "enabled": true }
},
"smartRouting": { "enabled": true, "fastProvider": "groq" },
"budget": { "dailyLimitUsd": 5, "monthlyLimitUsd": 50, "alertThreshold": 0.8 },
"maxTurns": 50,
"heartbeatMinutes": 30
}
PUT /api/dashboard/config
Content-Type: application/json
{
"key": "budget.dailyLimitUsd",
"value": 10
}
Updates a configuration value using dot-notation paths. The value is validated against the config schema before saving. API keys and tokens cannot be set through this endpoint — use the secrets API instead.
Response:
{
"success": true,
"key": "budget.dailyLimitUsd",
"value": 10,
"message": "Config updated. Changes take effect on next restart."
}
PUT /api/dashboard/config/model
Content-Type: application/json
{
"provider": "anthropic",
"model": "claude-sonnet-4-5-20250929"
}
Update the active LLM provider and model. The change takes effect on the next message.
Settings
GET /api/dashboard/settings/heartbeat
Get the current heartbeat interval.
PUT /api/dashboard/settings/heartbeat
Content-Type: application/json
{
"minutes": 60
}
Update the heartbeat interval. Set to 0 to disable.
Channel Status
GET /api/dashboard/channel-status
Returns the configuration and connection status for each channel (webchat, Telegram, Discord, Slack, WhatsApp, Signal). Each channel reports whether it is configured and whether it is currently enabled.
API Keys Management
GET /api/dashboard/secrets
List all stored secrets. Values are masked in the response for security.
GET /api/dashboard/secrets/:name
Reveal the full value of a single secret by name.
POST /api/dashboard/secrets
Content-Type: application/json
{
"name": "OPENWEATHER_API_KEY",
"value": "abc123...",
"service": "weather"
}
Create or update a secret. The optional service field associates the secret with a specific integration or skill.
DELETE /api/dashboard/secrets/:name
Delete a secret by name.
Analytics API
Analytics endpoints provide insight into usage, cost, performance, and tool activity.
GET /api/dashboard/analytics/summary
Returns aggregate statistics: total tokens used, estimated cost in USD, average response time in milliseconds, and total session count.
GET /api/dashboard/analytics/usage-over-time
Token usage broken down by day for the last 7 days.
GET /api/dashboard/analytics/tools
Tool call counts and average duration for each tool.
GET /api/dashboard/analytics/sessions
Top 20 sessions ranked by token usage, with provider and model information.
GET /api/dashboard/analytics/perf-snapshots
System performance snapshots over time, including RSS memory, heap usage, and database file size.
GET /api/dashboard/analytics/cost-breakdown
Cost aggregated by provider and model, including total tokens, total cost, and request count for each.
GET /api/dashboard/analytics/response-time-trend
Average, minimum, and maximum response times by day over the last 7 days.
GET /api/dashboard/analytics/top-models
Top 10 models ranked by total token usage.
Data Management
POST /api/dashboard/export
Download a full JSON export of the database, including conversations, memory, settings, and analytics.
POST /api/dashboard/backup
Create a SQLite backup file of the database.
POST /api/dashboard/import
Content-Type: multipart/form-data
Upload a JSON export file to import data. Maximum file size is 100MB.
GET /api/dashboard/db-stats
Returns row counts for each table in the database and the total database file size.
Workflows & Agents
GET /api/dashboard/workflows
List all configured workflows with their steps and status.
GET /api/dashboard/agents
List all configured agents (sub-agents) with their names, descriptions, and tool assignments.
Uploads
GET /api/dashboard/uploads
List all uploaded files with their filenames, sizes, chunk counts, and upload timestamps.
Skill Registry API
The Skill Registry runs at zubo.bot. It is not part of your local Zubo instance. The local Zubo CLI commands (zubo search, zubo install, zubo publish) communicate with this central registry via HTTP. All registry endpoints are under /api/registry/.
Public Endpoints
These endpoints require no authentication. Rate-limited to 30 requests per minute per IP.
GET /api/registry/skills?tag=weather&sort=newest&limit=50&offset=0&status=approved
List skills with filtering and sorting. Sort options: newest, stars, installs, trending. Filter by tag and status (approved, flagged, rejected).
Response:
{
"skills": [
{
"id": 1,
"name": "weather",
"description": "Get current weather for a location",
"author": "thomaskanze",
"version": "1.0.0",
"tags": ["weather", "utility"],
"stars_count": 12,
"installs_count": 58,
"status": "approved",
"risk_level": "low",
"created_at": "2026-02-10T09:00:00Z"
}
],
"total": 100
}
GET /api/registry/skills/:id?install=true
Get full skill detail by ID. When install=true is passed, the response includes the handler_code field with the full skill source code.
Response:
{
"skill": {
"id": 1,
"name": "weather",
"description": "Get current weather for a location",
"handler_code": "export const skill = { ... }; export default async function ...",
"skill_md": "# weather\nGet current weather...",
"version": "1.0.0",
"tags": ["weather"],
"secrets": ["WEATHER_API_KEY"],
"repo_url": "https://github.com/user/weather-skill",
"stars_count": 12,
"installs_count": 58,
"status": "approved",
"risk_level": "low"
}
}
GET /api/registry/search?q=weather
Full-text search (FTS5) across skill names and descriptions. Returns matching skills ranked by relevance.
Response:
{
"skills": [...]
}
GET /api/registry/trending
Skills with the most installs in the last 7 days.
Response:
{
"skills": [...]
}
GET /api/registry/popular
Skills with the most stars, all-time.
Response:
{
"skills": [...]
}
GET /api/registry/newest
Most recently submitted skills.
Response:
{
"skills": [...]
}
GET /api/registry/tags
Returns all tags with the number of approved skills using each tag.
Response:
{
"tags": {
"weather": 5,
"automation": 3,
"utility": 12,
"email": 2
}
}
GET /api/registry/profiles/:username
Get a user profile by GitHub username. Includes published skills and aggregate statistics.
Response:
{
"profile": {
"username": "thomaskanze",
"github_id": 12345,
"avatar_url": "https://avatars.githubusercontent.com/u/12345",
"created_at": "2026-02-01T00:00:00Z"
},
"stats": {
"total_skills": 5,
"total_stars": 42,
"total_installs": 230
},
"skills": [...]
}
POST /api/registry/skills/:id/report
Content-Type: application/json
{
"email": "user@example.com",
"reason": "Malicious",
"details": "Contains obfuscated code that phones home to an unknown domain"
}
Report a suspicious or broken skill. Email is required for follow-up but the report is otherwise anonymous. One report per email per skill is allowed.
Response:
{
"reported": true
}
GitHub OAuth Endpoints
These endpoints handle GitHub OAuth authentication for the registry. Users must sign in with GitHub to publish skills, star skills, or build a profile.
GET /api/registry/auth/github
Redirects to the GitHub OAuth authorization page. After the user authorizes, GitHub redirects back to the callback endpoint.
GET /api/registry/auth/github/callback
Handles the GitHub OAuth callback. Exchanges the authorization code for an access token, creates or updates the user profile, sets a session cookie, and redirects the user to the /skills page.
GET /api/registry/auth/me
Returns the currently authenticated user's profile and starred skill IDs, based on the session cookie.
Response (authenticated):
{
"profile": {
"username": "thomaskanze",
"github_id": 12345,
"avatar_url": "https://avatars.githubusercontent.com/u/12345"
},
"stars": [1, 2, 5]
}
Response (not authenticated):
{
"profile": null
}
POST /api/registry/auth/logout
Clears the session cookie and logs the user out.
Response:
{
"ok": true
}
Authenticated Endpoints
These endpoints require a valid GitHub session cookie, set during the OAuth sign-in flow.
POST /api/registry/skills
Content-Type: application/json
{
"name": "my-skill",
"description": "Does useful things",
"handler_code": "export const skill = { ... }; export default async function ...",
"skill_md": "# my-skill\nDoes useful things.",
"version": "1.0.0",
"tags": ["utility"],
"secrets": ["API_KEY"],
"repo_url": "https://github.com/user/my-skill"
}
Submit a new skill to the registry. The auto-review scanner runs immediately on the submitted code and returns the review results. Clean code (low risk) is approved instantly. Medium-risk code is flagged for manual review. High-risk code is rejected with detailed findings.
Response:
{
"skill": {
"id": 42,
"name": "my-skill",
"status": "approved",
"risk_level": "low"
},
"review": {
"status": "approved",
"risk_level": "low",
"findings": []
}
}
POST /api/registry/skills/:id/star
Toggle star on a skill. If the user has already starred it, the star is removed. Returns the new starred state and total star count.
Response:
{
"starred": true,
"stars_count": 5
}
Admin Endpoints
These endpoints require Authorization: Bearer <REGISTRY_ADMIN_KEY>. Used by registry administrators for moderation.
PUT /api/registry/admin/skills/:id/status
Content-Type: application/json
{
"status": "approved"
}
Update a skill's approval status. Valid values: approved, flagged, rejected.
DELETE /api/registry/admin/skills/:id
Permanently delete a skill from the registry.
GET /api/registry/admin/reports
List all skill reports, ordered by most recent. Used for moderation review.
PUT /api/registry/admin/reports/:id
Content-Type: application/json
{
"status": "resolved"
}
Update a report's status. Valid values: pending, resolved, dismissed.
API Keys
POST /api/keys
Content-Type: application/json
{
"label": "my-integration"
}
Create a new API key. The label field is optional. The full key is returned once at creation time and cannot be retrieved again.
Response:
{
"id": "k_abc123",
"key": "zb_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
GET /api/keys
List all API keys. Keys are shown with their IDs, labels, creation dates, and last-used timestamps. The full key value is not included.
DELETE /api/keys/:id
Delete an API key by its ID. The key is immediately revoked and can no longer be used for authentication.
Server-Sent Events
GET /api/events
Opens a long-lived SSE connection for receiving real-time events from the agent. The connection emits the following event types:
| Event | Data | Description |
|---|---|---|
connected | { "timestamp": "2026-02-12T10:00:00Z" } | Sent once when the connection is established. |
ping | { "timestamp": "2026-02-12T10:00:30Z" } | Sent every 30 seconds to keep the connection alive. |
Onboarding
GET /api/dashboard/onboarding
Returns the current onboarding state, including whether setup has been completed and the last completed step.
PUT /api/dashboard/onboarding
Content-Type: application/json
{
"completed": true,
"step": 4
}
Update the onboarding state. Used by the dashboard to track setup progress.
Test LLM
POST /api/dashboard/test-llm
Send a test request to the configured LLM provider to verify connectivity and credentials. Returns a simple confirmation with the model name.
Response:
{
"ok": true,
"response": "OK",
"model": "claude-sonnet-4-5-20250929"
}
Conversations
Endpoints for querying and searching the unified cross-channel conversation history. See Conversation History for full documentation.
List Conversations
GET /api/conversations?limit=20&offset=0&channel=telegram
Returns a paginated list of conversations, ordered by most recent activity. Supports filtering by channel via the channel query parameter.
Query parameters:
| Parameter | Default | Description |
|---|---|---|
limit | 20 | Number of conversations to return. Maximum 100. |
offset | 0 | Pagination offset. |
channel | — | Filter by source channel. |
Response:
{
"conversations": [
{
"id": "conv_abc123",
"title": "Deployment discussion",
"channel": "telegram",
"messageCount": 24,
"firstMessageAt": "2026-02-10T09:15:00Z",
"lastMessageAt": "2026-02-10T11:30:00Z"
}
],
"total": 156,
"limit": 20,
"offset": 0
}
Search Conversations
GET /api/conversations/search?q=kubernetes&channel=slack&limit=20
Full-text search across all conversation messages using FTS5 with BM25 ranking. Supports phrases, prefix matching, boolean operators, channel filtering, and date ranges.
Query parameters:
| Parameter | Default | Description |
|---|---|---|
q | — | Search query. Supports FTS5 syntax. |
channel | — | Filter to a specific channel. |
from | — | Start date (ISO 8601). |
to | — | End date (ISO 8601). |
limit | 20 | Maximum results. |
Response:
{
"results": [
{
"conversationId": "conv_abc123",
"title": "Kubernetes setup",
"channel": "slack",
"matchCount": 3,
"snippet": "...deployed the kubernetes cluster to production...",
"lastMessageAt": "2026-02-12T14:20:00Z"
}
],
"total": 8,
"query": "kubernetes"
}
Conversation Statistics
GET /api/conversations/stats
Returns aggregate statistics: total conversations, total messages, per-channel message counts, and a 30-day activity breakdown.
{
"totalConversations": 156,
"totalMessages": 4280,
"byChannel": {
"webchat": 2100,
"telegram": 1200,
"discord": 680
},
"last30Days": [
{ "date": "2026-02-14", "conversations": 5, "messages": 87 }
]
}
Get Conversation Messages
GET /api/conversations/:id/messages?limit=100&offset=0
Returns messages in a specific conversation, ordered chronologically. Supports pagination via limit (max 500) and offset.
{
"conversationId": "conv_abc123",
"title": "Deployment discussion",
"channel": "telegram",
"messages": [
{ "role": "user", "content": "Check deployment status", "timestamp": "2026-02-10T09:15:00Z" },
{ "role": "assistant", "content": "Deployment completed successfully.", "timestamp": "2026-02-10T09:15:04Z" }
],
"total": 24
}
Email Digests
Endpoints for managing automated email digest summaries. Digests aggregate conversation activity and send periodic email reports.
Get Digest Configuration
GET /api/dashboard/digests/config
Returns the current email digest configuration.
{
"enabled": true,
"frequency": "daily",
"send_time": "09:00",
"email_to": "you@example.com",
"include_conversations": true,
"include_tool_usage": true,
"include_errors": true,
"include_scheduled_tasks": true,
"last_sent_at": "2026-02-14T08:00:00Z"
}
Update Digest Configuration
PUT /api/dashboard/digests/config
Content-Type: application/json
{
"enabled": true,
"frequency": "daily",
"send_time": "09:00",
"email_to": "you@example.com",
"include_conversations": true,
"include_tool_usage": true,
"include_errors": true,
"include_scheduled_tasks": true
}
Updates digest settings and re-schedules the digest job if enabled.
Preview Digest HTML
GET /api/dashboard/digests/preview
Returns rendered digest HTML for preview.
Send Digest Now
POST /api/dashboard/digests/send
Sends a digest immediately using current configuration.
{
"ok": true
}
Webhooks
Endpoints for managing webhook endpoints that receive events from external services. See Webhooks for full documentation including HMAC verification and prompt templates.
List Webhooks
GET /api/webhooks
Returns all configured webhooks with their metadata, URL, event count, and last triggered time.
{
"webhooks": [
{
"id": "wh_a1b2c3",
"name": "github-pushes",
"url": "http://localhost:3000/webhooks/wh_a1b2c3",
"hasSecret": true,
"prompt": "A GitHub push event...",
"createdAt": "2026-02-15T10:00:00Z",
"lastTriggeredAt": "2026-02-15T14:30:00Z",
"eventCount": 12
}
]
}
Create Webhook
POST /api/webhooks
Content-Type: application/json
{
"name": "github-pushes",
"secret": "whsec_abc123...",
"prompt": "Process this event: {{payload}}"
}
Create a new webhook endpoint. The name and prompt fields are required. The secret field is optional but enables HMAC-SHA256 signature verification (X-Hub-Signature-256).
{
"id": "wh_a1b2c3",
"name": "github-pushes",
"url": "http://localhost:3000/webhooks/wh_a1b2c3",
"secret": "whsec_abc123...",
"createdAt": "2026-02-15T10:00:00Z"
}
Update Webhook
PUT /api/webhooks/:id
Content-Type: application/json
{
"name": "github-all-events",
"secret": "new-secret",
"prompt": "Updated prompt: {{payload}}"
}
Update a webhook's name, secret, or prompt template. All fields are optional.
Delete Webhook
DELETE /api/webhooks/:id
Delete a webhook and all its event history. Returns 204 No Content.
Get Webhook Events
GET /api/webhooks/:id/events?limit=20&offset=0
Returns the event history for a specific webhook, ordered by most recent first. Supports pagination via limit (max 100) and offset.
{
"events": [
{
"id": "evt_xyz789",
"webhookId": "wh_a1b2c3",
"timestamp": "2026-02-15T14:30:00Z",
"status": "processed",
"payloadSize": 2048,
"processingTimeMs": 1250
}
],
"total": 12
}
Test Webhook
POST /api/webhooks/:id/test
Content-Type: application/json
{
"payload": {
"action": "push",
"repository": { "full_name": "user/repo" }
}
}
Send a test payload to a webhook. The payload is processed through the prompt template and the agent's response is returned. If no payload is provided, a default sample is used.
{
"reply": "A push to user/repo was received.",
"eventId": "evt_test_001"
}
MCP Marketplace
Endpoints for browsing and installing MCP servers from the official registry. See MCP Marketplace for full documentation.
Browse Marketplace
GET /api/mcp/marketplace?q=filesystem&category=utilities&limit=50
Search and browse the MCP server registry. Supports filtering by search query, category, and pagination.
{
"servers": [
{
"name": "@modelcontextprotocol/server-filesystem",
"description": "MCP server providing file system operations",
"author": "Anthropic",
"category": "utilities",
"toolCount": 11,
"installed": false,
"version": "0.6.2"
}
],
"total": 1
}
Get Marketplace Server Details
GET /api/mcp/marketplace/:name
Get detailed information about a specific server, including available tools, required environment variables, and installation status.
Install Marketplace Server
POST /api/mcp/marketplace/:name/install
Content-Type: application/json
{
"env": { "GITHUB_TOKEN": "ghp_abc123..." }
}
Install an MCP server from the marketplace. The env field provides environment variables the server requires. The server is started immediately and its tools are registered.
{
"success": true,
"name": "@modelcontextprotocol/server-github",
"tools": ["github__create_issue", "github__list_repos"],
"toolCount": 2,
"status": "connected"
}
Uninstall MCP Server
POST /api/mcp/servers/:name/uninstall
Uninstall an MCP server, stop its process, deregister its tools, and remove the configuration. Returns 204 No Content.
Visual Workflows
Endpoints for managing visual workflows built with the dashboard builder. See Visual Workflows for full documentation including step types, triggers, and template variables.
List Visual Workflows
GET /api/workflows/visual
Returns all visual workflows with metadata, step count, trigger type, and execution status.
{
"workflows": [
{
"id": "vw_abc123",
"name": "Daily Report",
"trigger": { "type": "cron", "schedule": "0 9 * * 1-5" },
"stepCount": 4,
"enabled": true,
"lastRunAt": "2026-02-15T09:00:00Z",
"lastRunStatus": "completed"
}
]
}
Get Visual Workflow
GET /api/workflows/visual/:id
Returns the full workflow definition including all steps, connections, and trigger configuration.
Create Visual Workflow
POST /api/workflows/visual
Content-Type: application/json
{
"name": "Daily Report",
"trigger": { "type": "cron", "schedule": "0 9 * * 1-5" },
"steps": [
{ "id": "fetch", "type": "tool", "tool": "web_search", "input": { "query": "tech news" } },
{ "id": "summarize", "type": "agent", "prompt": "Summarize: {{steps.fetch.result}}" },
{ "id": "send", "type": "message", "channel": "telegram", "content": "{{steps.summarize.result}}" }
],
"connections": [
{ "from": "fetch", "to": "summarize" },
{ "from": "summarize", "to": "send" }
]
}
Create a new visual workflow. Returns the created workflow with its generated ID.
Update Visual Workflow
PUT /api/workflows/visual/:id
Content-Type: application/json
{
"name": "Updated Report",
"steps": [...],
"connections": [...]
}
Update a workflow's name, trigger, steps, or connections. All fields are optional.
Delete Visual Workflow
DELETE /api/workflows/visual/:id
Delete a workflow and all its execution history. Returns 204 No Content.
Run Visual Workflow
POST /api/workflows/visual/:id/run
Content-Type: application/json
{
"payload": { "topic": "AI research" }
}
Execute a workflow immediately with an optional payload available as {{trigger.payload}}. Returns the run ID.
{
"runId": "run_xyz789",
"status": "started",
"workflowId": "vw_abc123"
}
Get Workflow Runs
GET /api/workflows/visual/:id/runs?limit=20
Returns the execution history for a workflow, including per-step status and duration.
{
"runs": [
{
"runId": "run_xyz789",
"status": "completed",
"trigger": "manual",
"startedAt": "2026-02-15T14:00:00Z",
"completedAt": "2026-02-15T14:00:12Z",
"durationMs": 12340,
"steps": [
{ "id": "fetch", "status": "completed", "durationMs": 3200 },
{ "id": "summarize", "status": "completed", "durationMs": 8100 }
]
}
]
}
Toggle Visual Workflow
PUT /api/workflows/visual/:id/toggle
Content-Type: application/json
{
"enabled": false
}
Enable or disable a workflow. Disabled workflows do not execute on cron or webhook triggers but can still be run manually.
Rate Limits
Rate limiting is applied per IP address. When a client exceeds the limit, the endpoint returns 429 Too Many Requests with a Retry-After header indicating how many seconds to wait before retrying.
| Endpoint | Default Limit | Config Key |
|---|---|---|
All /api/chat* endpoints | 60 requests/min per IP | rateLimit.chatPerMinute |
/api/upload | 10 requests/min per IP | rateLimit.uploadPerMinute |
Rate limits are configurable via zubo config set or the config file.
Authentication
When auth.enabled is true in your configuration:
- All
/api/*endpoints require anAuthorization: Bearer <key>header. - Create keys using the CLI:
zubo auth create-key [label] - Keys can also be created via the
POST /api/keysendpoint (requires an existing valid key). - The
/healthendpoint does not require authentication, even when auth is enabled.
Requests without a valid key receive a 401 Unauthorized response:
{
"error": "Unauthorized",
"message": "Valid API key required"
}