Home/Docs/API Reference

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

401 Unauthorized / Missing Bearer token

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
Provider Timeout / Upstream unavailable

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
Missing local model (Ollama/LM Studio)

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:

EventDataDescription
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:

ParameterDefaultDescription
limit50Number 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:

EventDataDescription
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:

ParameterDefaultDescription
limit20Number of conversations to return. Maximum 100.
offset0Pagination offset.
channelFilter 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:

ParameterDefaultDescription
qSearch query. Supports FTS5 syntax.
channelFilter to a specific channel.
fromStart date (ISO 8601).
toEnd date (ISO 8601).
limit20Maximum 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.

EndpointDefault LimitConfig Key
All /api/chat* endpoints60 requests/min per IPrateLimit.chatPerMinute
/api/upload10 requests/min per IPrateLimit.uploadPerMinute

Rate limits are configurable via zubo config set or the config file.

Authentication

When auth.enabled is true in your configuration:

Requests without a valid key receive a 401 Unauthorized response:

{
  "error": "Unauthorized",
  "message": "Valid API key required"
}