# WizChat Documentation > Build AI-powered chatbots with your own knowledge base - [WizChat Documentation](/index.md) ## search - [Search the documentation](/search.md) ## ai-agents Use the WizChat documentation from Claude Code, Codex, Cursor, and other AI tools — clean Markdown, an llms.txt index, and a full-text corpus. - [Docs for AI Agents](/ai-agents.md): Use the WizChat documentation from Claude Code, Codex, Cursor, and other AI tools — clean Markdown, an llms.txt index, and a full-text corpus. ## analytics ### costs Track and monitor your AI usage costs - [Cost Monitoring](/analytics/costs.md): Track and monitor your AI usage costs ### queries Analyze chatbot queries and user interactions - [Query Analytics](/analytics/queries.md): Analyze chatbot queries and user interactions ### reports Generate and schedule usage reports - [Usage Reports](/analytics/reports.md): Generate and schedule usage reports ## api ### authentication How to authenticate with the WizChat API - [API Authentication](/api/authentication.md): How to authenticate with the WizChat API ### chatbots API endpoints for interacting with chatbots - [Chatbot API Endpoints](/api/chatbots.md): API endpoints for interacting with chatbots ### documents API endpoints for managing knowledge base documents - [Document API Endpoints](/api/documents.md): API endpoints for managing knowledge base documents ### errors API error codes and troubleshooting - [API Error Codes](/api/errors.md): API error codes and troubleshooting ### teams API endpoints for managing teams - [Team API Endpoints](/api/teams.md): API endpoints for managing teams ## billing ### invoices View and download your billing invoices - [Invoices](/billing/invoices.md): View and download your billing invoices ### plans Compare WizChat subscription plans and features - [Subscription Plans](/billing/plans.md): Compare WizChat subscription plans and features ### top-up Purchase additional AI budget when you need more usage - [Top-Up Credits](/billing/top-up.md): Purchase additional AI budget when you need more usage ### usage Monitor your WizChat usage and AI budget - [Usage Tracking](/billing/usage.md): Monitor your WizChat usage and AI budget ## changelog WizChat release notes and updates - [Changelog](/changelog.md): WizChat release notes and updates ## chatbot-users ### access-modes Configure how users can access your chatbot - [Access Modes](/chatbot-users/access-modes.md): Configure how users can access your chatbot ### access-protection Restrict chatbot access with URL-based app keys or JWT tokens - [Access Protection](/chatbot-users/access-protection.md): Restrict chatbot access with URL-based app keys or JWT tokens ### authentication Require users to authenticate before using your chatbot - [Authentication Setup](/chatbot-users/authentication.md): Require users to authenticate before using your chatbot ### inviting Invite specific users to access your chatbot - [Inviting Users](/chatbot-users/inviting.md): Invite specific users to access your chatbot ### managing View and manage users who access your chatbot - [Managing Users](/chatbot-users/managing.md): View and manage users who access your chatbot ### sso Set up enterprise SSO with Azure AD, Okta, or other OIDC providers for your chatbot - [SSO (Single Sign-On)](/chatbot-users/sso.md): Set up enterprise SSO with Azure AD, Okta, or other OIDC providers for your chatbot ## chatbots ### ai-settings Configure the AI model, prompts, and behavior for your chatbot - [AI Model Settings](/chatbots/ai-settings.md): Configure the AI model, prompts, and behavior for your chatbot ### appearance Customize your chatbot's visual appearance - [Appearance & Branding](/chatbots/appearance.md): Customize your chatbot's visual appearance ### configuration Configure your chatbot's basic settings - [Configuration & Settings](/chatbots/configuration.md): Configure your chatbot's basic settings ### conversation-memory Two memory strategies for personalized chatbot conversations — Graph-based knowledge graph or Conventional summarization - [Conversation Memory](/chatbots/conversation-memory.md): Two memory strategies for personalized chatbot conversations — Graph-based knowledge graph or Conventional summarization ### creating Learn how to create a new chatbot in WizChat - [Creating a Chatbot](/chatbots/creating.md): Learn how to create a new chatbot in WizChat ### deployment Deploy your chatbot and make it accessible to users - [Deployment](/chatbots/deployment.md): Deploy your chatbot and make it accessible to users ### managing Edit, pause, archive, and manage your chatbots - [Managing Chatbots](/chatbots/managing.md): Edit, pause, archive, and manage your chatbots ### media-attachments Attach an audio or video file in the chat and ask questions about it - [Audio and video in chat](/chatbots/media-attachments.md): Attach an audio or video file in the chat and ask questions about it ### sales-agent Configure and manage the Sales Agent for lead capture and delivery - [Sales Agent](/chatbots/sales-agent.md): Configure and manage the Sales Agent for lead capture and delivery ### voice-input Dictate messages with the in-chat microphone and pick your speech language - [Voice input](/chatbots/voice-input.md): Dictate messages with the in-chat microphone and pick your speech language ## getting-started ### first-chatbot Step-by-step tutorial to create your first WizChat chatbot - [Your First Chatbot](/getting-started/first-chatbot.md): Step-by-step tutorial to create your first WizChat chatbot ### key-concepts Understand the fundamental concepts of WizChat - [Key Concepts](/getting-started/key-concepts.md): Understand the fundamental concepts of WizChat ### quick-start Get up and running with WizChat in 5 minutes - [Quick Start Guide](/getting-started/quick-start.md): Get up and running with WizChat in 5 minutes ## integrations ### ai-gateway-byok Use your own API keys through the Vercel AI Gateway - [AI Gateway BYOK (Bring Your Own Key)](/integrations/ai-gateway-byok.md): Use your own API keys through the Vercel AI Gateway ### byoi Use your own LLM, embeddings, vector store, and databases - [BYOI (Bring Your Own Infrastructure)](/integrations/byoi.md): Use your own LLM, embeddings, vector store, and databases ### external-api Access your chatbot programmatically via API - [External API](/integrations/external-api.md): Access your chatbot programmatically via API ### mcp - [Built-in MCP Servers](/integrations/mcp/built-in.md): Pre-configured MCP integrations available in WizChat - [Custom MCP Servers](/integrations/mcp/custom.md): Add your own MCP server integrations - [Interactive UI (MCP-UI)](/integrations/mcp/interactive-ui.md): Let a trusted MCP server render its own interactive dialogs and forms inside the chat - [Local Execution (Return-Script)](/integrations/mcp/local-execution.md): Build an MCP server whose tools run on the user's machine instead of in the cloud - [Model-backed tools](/integrations/mcp/model-backed-tools.md): Let a tool's result be produced by an AI model you declare in the tool's MCP metadata — no API key, no agent - [OAuth Configuration](/integrations/mcp/oauth.md): Set up OAuth authentication for MCP integrations - [MCP Servers Overview](/integrations/mcp/overview.md): Extend your chatbot with Model Context Protocol integrations - [Tool Approval (HITL)](/integrations/mcp/tool-approval.md): Ask users to approve MCP tool calls before they run ### postgresql Query PostgreSQL databases using natural language - [PostgreSQL Integration (QueryWeaver)](/integrations/postgresql.md): Query PostgreSQL databases using natural language ### youtube Import YouTube videos into your knowledge base - [YouTube Integration](/integrations/youtube.md): Import YouTube videos into your knowledge base ## knowledge-base ### access-control Control who can access specific documents in your knowledge base - [Document Access Control](/knowledge-base/access-control.md): Control who can access specific documents in your knowledge base ### crawl-drift See which pages a crawled site added or removed since your last crawl - [Check for Changes (Crawl Drift)](/knowledge-base/crawl-drift.md): See which pages a crawled site added or removed since your last crawl ### managing Manage, organize, and maintain your knowledge base documents - [Managing Documents](/knowledge-base/managing.md): Manage, organize, and maintain your knowledge base documents ### overview Understand how knowledge bases work in WizChat - [Knowledge Base Overview](/knowledge-base/overview.md): Understand how knowledge bases work in WizChat ### scheduled-crawling Automatically keep website content up to date - [Scheduled Crawling](/knowledge-base/scheduled-crawling.md): Automatically keep website content up to date ### scopes Partition your knowledge base into separate scopes with independent access control, behavior, and budgets - [Knowledge Scopes](/knowledge-base/scopes.md): Partition your knowledge base into separate scopes with independent access control, behavior, and budgets ### transcript-corrections Review and resolve AI-suggested transcript corrections for video content - [Transcript Corrections](/knowledge-base/transcript-corrections.md): Review and resolve AI-suggested transcript corrections for video content ### uploading - [Uploading CHM Files](/knowledge-base/uploading/chm.md): Upload Windows CHM help files into your knowledge base - [In-Chat Data Analysis](/knowledge-base/uploading/data-analysis.md): Upload Excel or CSV files in a conversation for instant data analysis - [Excel & Spreadsheets](/knowledge-base/uploading/excel.md): Upload spreadsheet data to your knowledge base - [Images (OCR)](/knowledge-base/uploading/images.md): Extract text from images using OCR - [Uploading PDFs](/knowledge-base/uploading/pdfs.md): Upload and process PDF documents for your knowledge base - [Videos & YouTube](/knowledge-base/uploading/videos.md): Add video content to your knowledge base through transcription ### website-crawling Import content from websites into your knowledge base - [Website Crawling](/knowledge-base/website-crawling.md): Import content from websites into your knowledge base ## management-api ### guides - [Add knowledge base content via the API](/management-api/guides/adding-content.md): Add text or Markdown straight to a chatbot's knowledge base with a single API call — no file upload needed. - [Authentication & scopes](/management-api/guides/authentication.md): How to authenticate Management API requests and how scopes constrain a key. - [Config-as-code](/management-api/guides/config-as-code.md): Export a chatbot's configuration, edit it, and apply the desired state declaratively. - [Errors & rate limits](/management-api/guides/errors-and-rate-limits.md): The Management API error envelope, status codes, and rate-limit behavior. - [OAuth 2.0](/management-api/guides/oauth.md): Authenticate to the Management API with OAuth 2.0 — client-credentials tokens for server-to-server access, plus the interactive flow used by MCP clients. - [Quickstart](/management-api/guides/quickstart.md): Make your first WizChat Management API call in under five minutes. ### overview Programmatic, config-as-code control plane for your WizChat chatbots. - [Management API (v1)](/management-api/overview.md): Programmatic, config-as-code control plane for your WizChat chatbots. ### reference - [Apply a desired-state config document](/management-api/reference/apply-chatbot-config.md): Declarative config-as-code apply. Diffs a desired-state document against the chatbot's CURRENT config and either returns the PLAN (dry-run) or executes it via the shared reconcile services. `prune` defaults to true: array sections (mcpServers, skills, domains) are AUTHORITATIVE — resources present on the chatbot but absent from the document are DELETED. Every delete is surfaced in the dry-run plan before any apply. prune:false = merge-only (create/update, never delete). Only sections present in `spec` are reconciled; absent sections are left untouched (never pruned). Scope model (least-privilege, per present section): dry-run requires the READ scope, apply the WRITE scope, of every section present, PLUS baseline chatbots:read (dry-run) / chatbots:write (apply). Section→scope: core/scopes→chatbots, mcpServers→mcp, skills→skills, accessProtection/externalApi/accessLists/telemetry→security, domains→domains. Execution stops on the FIRST failing op (apply is idempotent, so a stopped apply is recoverable after fixing the offending section); a partial failure returns HTTP 422 with the ops applied so far plus the offending op. - [Authorize a custom domain](/management-api/reference/authorize-chatbot-domain.md): Adds a custom domain to the chatbot's authorized login domain list. Requires a paid plan tier that supports custom domains. On success returns the updated domain status. On failure (the domain authorization call failed) returns 400 with `PublicDomainStatus` (status: `pending_manual`) or a standard `Error` envelope for validation/config failures. Required scope: `domains:write`. - [Start the YouTube connect flow](/management-api/reference/connect-you-tube.md): Begins connecting the caller's YouTube account. Returns an `authorizeUrl` the caller opens in a browser to grant access; the connection is completed by the browser callback. Account-scoped (no chatbot). Required scope: `videos:write`. - [Create an access-protection key](/management-api/reference/create-access-protection-key.md): Mint a new widget access-protection key. The full plaintext key is returned ONCE in the response body. **Store it immediately — it cannot be retrieved again.** Subsequent reads expose only the `keyPrefix` display hint. Required scope: `security:write`. - [Create a chatbot](/management-api/reference/create-chatbot.md): Creates a new chatbot with `status: 'draft'` and `deployment.status: 'pending'`. Creation does not provision any infrastructure or start a deployment. **The first deploy must be done from the WizChat dashboard**, which provisions the underlying infrastructure; the v1 `/deploy` endpoint only re-deploys a chatbot that has already been deployed once. Restricted API keys (those locked to specific chatbot IDs) cannot create chatbots. Plan limits are enforced transactionally. **Note:** newly created chatbots have no `aiConfig` (no LLM model). Before triggering a deployment, use `POST /api/v1/chatbots/{id}/apply` to set `spec.core.aiConfig.llmModel` and related fields. Required scope: `chatbots:write`. - [Create a scheduled crawl](/management-api/reference/create-chatbot-scheduled-crawl.md): Creates a recurring scheduled crawl that re-ingests the given URLs into the chatbot's knowledge base on the chosen cadence. `dayOfWeek` is required for `weekly`; `dayOfMonth` (1-28) for `monthly`. Limited to 3 schedules per chatbot and 100 URLs per schedule (a violation returns 400). Requires admin-level chatbot access. Required scope: `documents:write`. - [Create a knowledge scope](/management-api/reference/create-chatbot-scope.md): Create a single knowledge scope. The scope `id` is derived by slugifying `id` (if given) else `label` (lowercase; `[^a-z0-9_-]` → `-`). Returns 409 if a scope with that id already exists. Unlike PATCH /scopes (which replaces the whole array), this updates one scope in place, so `costLimit`, `authorizedEmails`, and `authorizedDomains` are preserved. Required scope: `chatbots:write`. - [Create an email group](/management-api/reference/create-email-group.md): Creates an email group (name + member emails). Emails are normalized and de-duplicated. Group names must be unique per owner. Required scope: `security:write`. - [Create an external-API key](/management-api/reference/create-external-api-key.md): Mint a new external-API key. The full plaintext key is returned ONCE in the response body (`key` field). **Store it immediately — it cannot be retrieved again.** Subsequent reads expose only the `keyPrefix` display hint. Maximum 5 active keys per chatbot. Required scope: `security:write`. - [Create an MCP server](/management-api/reference/create-mcp-server.md): Create a new MCP server configuration for a chatbot. Stdio transport is not supported via the management API (use HTTP transport). Tool discovery is attempted automatically for HTTP servers. OAuth flows, PostgreSQL scan, and metrics are dashboard-only (deferred). Required scope: `mcp:write`. - [Register an OAuth client](/management-api/reference/create-o-auth-client.md): Register an OAuth client - [Issue an access token (client credentials)](/management-api/reference/create-o-auth-token.md): Public endpoint — no bearer auth required. Exchange `client_id` + `client_secret` for a short-lived access token. Supports `client_credentials` grant type only (RFC 6749 §4.4). Accepts both `application/json` (developer convenience) and `application/x-www-form-urlencoded` (RFC 6749 §4.4.2 standard). Returns `400 invalid_request` for any other Content-Type. Rate-limited: returns `429 rate_limited` + `Retry-After` header when the IP bucket is exceeded. - [Create a skill](/management-api/reference/create-skill.md): Create a new skill for a chatbot. Auto-enables the skills feature on first creation. Name must be unique within the chatbot (max 25 skills per chatbot). Required scope: `skills:write`. - [Deauthorize a custom domain](/management-api/reference/deauthorize-chatbot-domain.md): Removes a custom domain from the chatbot's authorized login domain list. Required scope: `domains:write`. - [Delete a chatbot](/management-api/reference/delete-chatbot.md): Permanently deletes a chatbot and cascades its cleanup (knowledge base, storage, deployment, and configuration). Requires the chatbot OWNER or a team owner/admin (stricter than edit access). Returns 200 on full deletion, or 207 Multi-Status if the chatbot was removed but some downstream cleanup failed (see `errors`). Returns 409 if a shared resource (e.g. a knowledge base still used by another chatbot) blocks deletion — nothing is deleted in that case. Required scope: `chatbots:write`. - [Delete chatbot memory data](/management-api/reference/delete-chatbot-memory-data.md): Permanently deletes the chatbot's graph conversation memory for the given scope. `scope=long-term` removes stored facts + session summaries; `scope=short-term` removes within-session conversation nodes. Destructive and irreversible. Required scope: `chatbots:write`. - [Delete a scheduled crawl](/management-api/reference/delete-chatbot-scheduled-crawl.md): Deletes a scheduled crawl and its run history. Pass `deleteVectors=true` to also purge the vectors this schedule ingested into the KB. Fails closed: if the vector purge fails, the schedule is NOT deleted (its metadata is preserved so the purge can be retried) and a 502 is returned. Required scope: `documents:write`. - [Delete a knowledge scope](/management-api/reference/delete-chatbot-scope.md): Remove one knowledge scope from a chatbot. Also unassigns the scope from the knowledge-base tree and any workflows that referenced it. Returns 409 if the scope still has documents/vectors — reassign or delete them in the dashboard first (no destructive document/vector cascade). Required scope: `chatbots:write`. - [Delete a document](/management-api/reference/delete-document.md): Delete a document and all its data (embedding vectors, storage, metadata). Required scope: `documents:write`. `success` is `false` when any cleanup step produced a warning (honest semantics). `warnings` is always present (empty array on clean delete). - [Delete an email group](/management-api/reference/delete-email-group.md): Delete an email group. Required scope: `security:write`. - [Delete an MCP server](/management-api/reference/delete-mcp-server.md): Remove an MCP server from a chatbot. For PostgreSQL servers, the associated schema graph is also deleted (non-fatal on error). Required scope: `mcp:write`. - [Revoke an OAuth client](/management-api/reference/delete-o-auth-client.md): Revoke an OAuth client - [Delete a lead-delivery channel](/management-api/reference/delete-sales-agent-handoff.md): Removes a lead-delivery channel. Idempotent — deleting an unknown channel still returns success. Required scope: `chatbots:write`. - [Delete a skill](/management-api/reference/delete-skill.md): Remove a skill from a chatbot. Required scope: `skills:write`. - [Delete a video](/management-api/reference/delete-video.md): Delete a video and all its data (embedding vectors, transcript, storage, metadata). Required scope: `videos:write`. `success` is `false` when any cleanup step produced a warning (honest semantics). `warnings` is present when non-empty. - [Trigger a redeploy](/management-api/reference/deploy-chatbot.md): Re-runs the production build with the chatbot's CURRENT build-time environment. Runtime config (model, behavior, appearance, prompts, etc.) is read live and does NOT require a deploy. This endpoint does NOT re-sync build-time settings (e.g. chatbot name, requireAuth, region); if you changed a build-time field, use the dashboard redeploy. Long-running operation (up to 5 min). The response is returned immediately with status `deploying`; poll GET /deployment for the final status. If a build exceeds ~60s the status may remain `deploying`; the already-deploying guard clears after ~10 minutes. Required scope: `deploy`. - [DSAR-erase a sales-agent lead's PII (destructive)](/management-api/reference/erase-sales-agent-lead.md): DESTRUCTIVE. GDPR DSAR hard-erase of a single lead's PII: scrubs the encrypted captured-fields envelope, HMAC hashes, and PII-adjacent geo (IP/region/city/timezone) to null while RETAINING the anonymous row (disposition, capturedAt, geo.countryCode) so aggregate metrics stay intact. Idempotent — a repeat erase on an already-erased lead returns 409 and preserves the original piiErasedAt (GDPR Article 17 audit-trail integrity). Owner/admin gated. Required scope: `security:write`. - [Export sales-agent leads as CSV (with decrypted PII)](/management-api/reference/export-sales-agent-leads.md): Exports a chatbot's captured sales-agent leads as a CSV, over the requested window and filters. Unlike the metadata-only list, this DECRYPTS the captured contact fields (name/email/phone/company) server-side and includes the coarse geo columns. Cells are CSV-injection-hardened (a leading =+@- is escaped with a single quote). Each row carries a `pii_decrypt_status` (ok / failed / erased / none). Capped at 5000 rows after filters — a larger result returns 413 (narrow the window / filters). Owner/admin gated (bulk PII decrypt). Required scope: `security:read`. - [Get access lists](/management-api/reference/get-access-lists.md): Returns the authorizedEmails, authorizedDomains, and allowedEmbedDomains lists for a chatbot. Unlike the PublicChatbot listing (which collapses these to counts for privacy), this endpoint returns the full rosters for headless config-as-code use cases. Requires admin-level access (`canManageAccess`). Required scope: `security:read`. - [Get access-protection config](/management-api/reference/get-access-protection.md): Returns the widget access-protection configuration for a chatbot. jwtConfig.secret is collapsed to a boolean `hasSecret` flag — the raw secret is never returned. Key hashes are stripped; only safe key metadata (id, label, keyPrefix, status, usageCount, timestamps) is returned. Required scope: `security:read`. - [Get workspace usage overview](/management-api/reference/get-aggregate-analytics.md): Owner-level (NOT chatbot-scoped) 7-day cross-chatbot usage overview: per-day query trend + total queries, total chatbots, and deployed-chatbot count. Loops all chatbots the caller owns. FULL-ACCESS CALLER REQUIRED: a chatbot-scoped key (allowedChatbotIds set) receives 403 `chatbot_not_in_key_scope` — it cannot read workspace-wide totals. The dashboard `success` flag and `debug` block are never emitted. Tier-gated (usage, starter+). Required scope: `analytics:read`. - [Get a chatbot](/management-api/reference/get-chatbot.md): Returns a single chatbot by ID. Required scope: `chatbots:read`. - [Export aggregate config](/management-api/reference/get-chatbot-config.md): Assembles the chatbot's CURRENT configuration into a single canonical desired-state document (the 'export current config' / drift baseline for the declarative apply). Reuses every section serializer; never returns secrets — accessProtection.jwtConfig.secret is collapsed to hasSecret, and the access-protection / external-api key arrays are excluded entirely. Baseline scope: `chatbots:read`. Per-section read-scope gating (least-privilege): a section is OMITTED from `spec` when the caller's key lacks its read scope, and listed in `_omittedSections` (core/scopes→chatbots:read, mcpServers→mcp:read, skills→skills:read, accessProtection/externalApi/accessLists/telemetry→security:read, domains→domains:read). Firebase callers hold all scopes. - [Get conversation-intelligence analytics](/management-api/reference/get-chatbot-conversation-analytics.md): Conversation-intelligence aggregates for a single chatbot at dashboard parity: top topics, knowledge gaps, language distribution, scope usage, hourly heatmap, conversation depth. topTopics/knowledgeGaps titles are k-anonymity-gated (≥3 distinct sessions) and exposed exactly as the dashboard shows the owner. No raw session or user identifiers are ever returned — only aggregated, anonymized results. Tier-gated (pro-plus+). Required scope: `analytics:read`. - [Get cost analytics](/management-api/reference/get-chatbot-cost-analytics.md): Returns cost analytics for a single chatbot over the requested period. Tier-gated: the plan's analytics day-cap is applied automatically; a 403 is returned when the plan does not include cost analytics access. Combines completed-day cost rollups with the current day's partial usage. No PII — ownerEmail, userId, and per-other-chatbot breakdowns are always stripped. Required scope: `analytics:read`. - [Detect website crawl drift](/management-api/reference/get-chatbot-crawl-drift.md): Compares a chatbot's crawled URL set for a domain against the domain's CURRENT sitemap.xml, reporting pages ADDED (in the sitemap but not yet crawled) and REMOVED (crawled but no longer in the sitemap). The domain MUST be one the chatbot has already crawled (SSRF-bounded). Content changes on already-crawled pages are NOT detected — no per-page baseline is stored for existing crawls. Required scope: `documents:read`. - [Get deployment status](/management-api/reference/get-chatbot-deployment.md): Returns the deployment status for a chatbot. Internal hosting and credential identifiers are never included in the response. Required scope: `chatbots:read`. - [List authorized domains](/management-api/reference/get-chatbot-domains.md): Returns the authorized login domains and custom domain status for a chatbot. Internal IDs and auth tokens are stripped. Required scope: `domains:read`. Requires admin-level access (`canManageAccess`); callers with only editor access will receive 404 here. - [Get infrastructure analytics](/management-api/reference/get-chatbot-infra-analytics.md): Infrastructure signals for a single chatbot at dashboard parity: latency and TTFT percentiles + histograms, region split, deploy-version timeline (regression detection), and warm-vs-cold ratio. deploymentVersion and dataRegion are owner-facing operational metadata, not user machine ids. Tier-gated (pro+). Required scope: `analytics:read`. - [Get agent quality analytics](/management-api/reference/get-chatbot-quality-analytics.md): Agent behavior & quality aggregates for a single chatbot at dashboard parity (aggregate metrics only — no raw traces, no PII). Answer-quality breakdown, agent decisions, average latency, and MCP tool-error tracking. The chatbot scope is derived server-side from the authenticated owner — no email parameter is accepted. Tier-gated (pro-plus+). Required scope: `analytics:read`. `answerRate` is `number | null`, computed only over turns the chatbot classified; it is `null` (distinct from a genuine 0%) whenever `answerRateTracked` is false — i.e. no classified turns in the window, or the metrics were temporarily unavailable. Consumers must handle `null` before arithmetic and can read `answerRateTracked` to explain the absence. - [Get query-log analytics](/management-api/reference/get-chatbot-queries-analytics.md): Row-level query log for a single chatbot at dashboard parity — the owner's own conversation log. Question and answer text are PII-redacted at insert and the end-user's email is masked. Internal session, row, and network identifiers are never emitted. Each row's sources[] is reshaped to a public citation {title, source, pdfSource} — the raw retrieved chunk text and all other internal source metadata are dropped. Tier-gated (starter+). Required scope: `analytics:read`. - [Get a scheduled crawl](/management-api/reference/get-chatbot-scheduled-crawl.md): Returns one scheduled crawl including its recent run history. No PII (authorized emails/groups are returned only as counts). Required scope: `documents:read`. - [Get a knowledge scope](/management-api/reference/get-chatbot-scope.md): Returns a single knowledge scope by id. Billing detail (costLimit) is stripped and PII rosters (emails/domains) are collapsed to counts. Required scope: `chatbots:read`. - [Get knowledge scopes](/management-api/reference/get-chatbot-scopes.md): Returns the knowledge-scope configuration for a chatbot. Required scope: `chatbots:read`. - [Get search / retrieval-quality analytics](/management-api/reference/get-chatbot-search-analytics.md): Retrieval-effectiveness aggregates for a single chatbot at dashboard parity: score histogram, per-scope retrieval quality, skip-RAG ratio, sources-per-query, and weakest queries. weakestQueries titles are k-anonymity-gated (≥3 sessions) and exposed exactly as the dashboard shows the owner. Tier-gated (pro+). Required scope: `analytics:read`. - [Get token-efficiency analytics](/management-api/reference/get-chatbot-token-analytics.md): Token-usage & latency aggregates for a single chatbot at dashboard parity: total/avg/percentile tokens, model mix, context-growth buckets, and TTFT-by-model. Aggregate-only (no raw text). Tier-gated (pro+). Required scope: `analytics:read`. - [Get video-transcription analytics](/management-api/reference/get-chatbot-transcription-analytics.md): Video-transcription aggregates for a single chatbot at dashboard parity: totals (videos, duration, cost, char/word counts) and breakdowns by service, language, platform, and model. Per-other-chatbot breakdowns are stripped. NOT tier-gated — matches the ungated dashboard route (auth + `analytics:read` + ownership only). All-time totals; no `days` parameter is applied. Required scope: `analytics:read`. - [Get usage analytics](/management-api/reference/get-chatbot-usage-analytics.md): Returns usage analytics for a single chatbot. tokenCount and queryCount are derived from cost rollup data (same tier-gating as cost analytics). Note: queryCount counts recorded cost/usage events (model calls — embeddings, completions, reranks, tool calls — plus other cost events), not user Q&A turns, so expect it to run several × the conversations/quality turn counts. documentCount is the current KB size (total docs in user_documents — not time-windowed). No PII. Required scope: `analytics:read`. - [Get a document](/management-api/reference/get-document.md): Returns a single document by ID (IDOR-guarded). Required scope: `documents:read`. - [Get an email group](/management-api/reference/get-email-group.md): Fetch one of the owner's email groups by id. Required scope: `security:read`. - [Get external-API config](/management-api/reference/get-external-api-config.md): Returns the external-API configuration for a chatbot. Key hashes are stripped; only safe key metadata is returned. Required scope: `security:read`. - [Get an MCP server](/management-api/reference/get-mcp-server.md): Returns a single MCP server by ID. Credentials, headers, and access-key hashes are stripped. Required scope: `mcp:read`. - [Get MCP server access control](/management-api/reference/get-mcp-server-access.md): Returns the access-control settings for an MCP server: authorizedEmails, authorizedGroups, isPublic, accessKeyHint. The access-key hash is never returned. Required scope: `mcp:read`. - [Get an OAuth client](/management-api/reference/get-o-auth-client.md): Get an OAuth client - [Get the Sales Agent configuration](/management-api/reference/get-sales-agent.md): Returns the chatbot's Sales Agent configuration (persona, prompt slots/overlay, model override, lead-capture fields, guardrails, and sales-trigger settings), plus `salesAgentEnabled` — whether the agent is live at runtime. Returns an empty config with `salesAgentEnabled:false` when no agent has been configured yet. Never returns access-key material or internal fields. Required scope: `chatbots:read`. - [Get a sales-agent lead (with decrypted PII)](/management-api/reference/get-sales-agent-lead.md): Reads a single captured sales-agent lead WITH decrypted PII (the audit-logged per-lead detail path). Returns the metadata the list returns PLUS the decrypted contact `pii` (name/email/phone/company/custom), the coarse geo detail (countryCode + region/city/timezone), and a `decryptError` string when server-side decrypt failed (the raw envelope, HMAC hashes, and IP hash are NEVER emitted). 404 for a missing, soft-deleted, or unauthorized lead (IDOR-safe). Owner/admin gated (PII reveal). Required scope: `security:read`. - [Get a skill](/management-api/reference/get-skill.md): Returns a single skill by ID. Required scope: `skills:read`. - [Get telemetry config](/management-api/reference/get-telemetry-config.md): Returns the telemetry configuration for a chatbot. Fields: level (anonymized|identified|full), endUserOptOutAllowed, pseudonymizeIdentifiers, retentionMonths. Required scope: `security:read`. - [Get daily API quota status](/management-api/reference/get-usage.md): Get daily API quota status - [Get a video](/management-api/reference/get-video.md): Returns a single video by ID (IDOR-guarded). Required scope: `videos:read`. - [Get YouTube connection status](/management-api/reference/get-you-tube-status.md): Reports whether the caller's YouTube account is connected, and the connected channel title when available. Never returns tokens. Account-scoped (no chatbot). Required scope: `videos:read`. - [Ingest a PDF document from a URL](/management-api/reference/ingest-chatbot-document.md): Ingests a PDF into the chatbot's knowledge base by fetching it from a PUBLIC URL (SSRF-safe: http(s) only, public-IP-pinned + rebind-safe, size- and time-bounded), then running the standard extract → chunk → embed pipeline. This endpoint is PDF-only (the fileName / URL must end in .pdf); to ingest a local file, host it at a public URL first. Asynchronous — processing continues in the background; poll GET /documents for status. Required scope: `documents:write`. - [Add text or a .txt/.md file to the knowledge base](/management-api/reference/ingest-chatbot-text.md): Adds text or Markdown straight into the chatbot's knowledge base — no file upload needed. Send a single `text` string (with an optional `fileName`) or a batch of `items` (for example curated question/answer pairs). Each entry becomes its own searchable, listable, deletable knowledge source. Processing is synchronous — the response reports per-entry results. Long entries are split automatically. Required scope: `documents:write`. - [Ingest YouTube videos into a chatbot](/management-api/reference/ingest-you-tube-videos.md): Ingests videos from the caller's connected YouTube channel into the chatbot's knowledge base. Videos already in the knowledge base are skipped (`skippedAlreadyImported`). Returns a `jobId` for the ingest. Required scope: `videos:write`. - [Invite a deployed user](/management-api/reference/invite-chatbot-user.md): Invites an end-user to the chatbot by email; the user receives a verification email. Required scope: `security:write`. - [List access-protection keys](/management-api/reference/list-access-protection-keys.md): Returns all access-protection keys for a chatbot. Key hashes are stripped; only safe metadata (id, label, keyPrefix, status, usageCount, timestamps) is returned. Required scope: `security:read`. - [List a chatbot's transcript-correction review queue](/management-api/reference/list-chatbot-corrections.md): Returns every transcript correction across the chatbot's videos as one needs-review-first queue, with per-status totals. Never returns the transcript body or the resolver identity. Required scope: `documents:read`. - [List website crawls](/management-api/reference/list-chatbot-crawls.md): Lists the chatbot's website crawls (most recent first), with live progress. Non-terminal crawls are refreshed against the crawler on read (an API-initiated crawl has no dashboard poller, so this read is what advances its status). Pass `crawlId` to fetch a single crawl. No PII (authorized emails/groups are not returned). Required scope: `documents:read`. - [List sales-agent leads (metadata only)](/management-api/reference/list-chatbot-sales-agent-leads.md): Lists a chatbot's captured sales-agent leads over the requested window. Returns METADATA ONLY — disposition, handoff status, country code, timestamps, coarse attribution, and disposition/country aggregates. NO decrypted PII (name/email/phone/custom capture fields, city, region, IP) is exposed by this list. Owner/admin gated (mirrors the dashboard leads view — CRM-sensitive disposition labels are not readable by domain-grant viewers). Required scope: `analytics:read`. - [List scheduled crawls](/management-api/reference/list-chatbot-scheduled-crawls.md): Lists the chatbot's scheduled (recurring) website crawls, most recent first. A scheduled crawl periodically re-ingests a set of URLs into the KB on an hourly/daily/weekly/monthly cadence. No PII (authorized emails/groups are returned only as counts). Required scope: `documents:read`. - [List deployed users](/management-api/reference/list-chatbot-users.md): Lists the chatbot's deployed (invited) end-users — each user's email, display name, role, status, email-verification flag, and timestamps. Requires admin-level chatbot access. Required scope: `security:read`. - [List chatbots](/management-api/reference/list-chatbots.md): Returns the chatbots you own, created on behalf of a team owner, were granted admin access to, or that are shared with a team you own or administer. Required scope: `chatbots:read`. Chatbots shared with a team where you are a plain member, and chatbots where you have only viewer/editor (non-admin) access, are not listed here — access those directly by id via `GET` / `PATCH /api/v1/chatbots/{chatbotId}`. - [List documents](/management-api/reference/list-documents.md): Returns all documents owned by the authenticated user. Required scope: `documents:read`. Optional `?chatbotId=` filter (restricted keys are scoped to their allowed chatbots automatically). Lists only documents you own, even when `chatbotId` is supplied; a chatbot's full knowledge base is not enumerated here. - [List email groups](/management-api/reference/list-email-groups.md): Lists the owner's email groups (reusable email allow-lists shared across their chatbots). Pass `includeUsage=true` to include how many documents use each group. Email groups are OWNER-scoped, not per-chatbot: a key restricted to specific chatbots still has full access to all of the owner's email groups. Required scope: `security:read`. - [List external-API keys](/management-api/reference/list-external-api-keys.md): Returns all external-API keys for a chatbot. Key hashes are stripped; only safe metadata is returned. Required scope: `security:read`. - [List MCP servers](/management-api/reference/list-mcp-servers.md): Returns all MCP servers configured for a chatbot. Credentials, headers, env vars, and access-key hashes are stripped. Email/group rosters are collapsed to counts. OAuth flows, PostgreSQL scan, and metrics are dashboard-only (not yet in v1 API). Required scope: `mcp:read`. - [List OAuth clients](/management-api/reference/list-o-auth-clients.md): List OAuth clients registered by the authenticated user. Requires Firebase authentication. - [List lead-delivery channels](/management-api/reference/list-sales-agent-handoffs.md): Lists the Sales Agent's lead-delivery (hand-off) channels. Each channel reports its recipients/routing and whether a sending secret is configured (`hasSecret`/`hasWebhookHmac`) without ever exposing the secret itself. Creating a channel is done from the dashboard (it is inseparable from storing the sending secret). Required scope: `chatbots:read`. - [List skills](/management-api/reference/list-skills.md): Returns all skills configured for a chatbot. Required scope: `skills:read`. - [List the owner's team members](/management-api/reference/list-team-members.md): Returns the caller's team/workspace + its members (userId, email, displayName, role, status, invite/accept/last-active timestamps). Workspace-level — no chatbotId. Returns the team from the caller's OWN membership (their active team), so a caller can only read a team they belong to (never cross-tenant); a member/admin sees the roster, matching the dashboard. Returns team:null for a solo user. Internal fields (permissionOverrides, invitedBy) are dropped. Required scope: `security:read`. - [List a video's transcript corrections](/management-api/reference/list-video-corrections.md): Returns a page of transcript corrections for a single video (IDOR-guarded), each with a short context snippet from the surrounding transcript so a caller can judge the most probable word. Never returns the full transcript body or the resolver identity. Required scope: `documents:read`. - [List videos](/management-api/reference/list-videos.md): Returns all videos owned by the authenticated user. Required scope: `videos:read`. Optional `?chatbotId=` filter (restricted keys are scoped to their allowed chatbots automatically). Lists only videos you own, even when `chatbotId` is supplied; a chatbot's full knowledge base is not enumerated here. - [List the caller's YouTube videos](/management-api/reference/list-you-tube-videos.md): Lists videos from the caller's own connected YouTube channel. Without `search`, returns one page plus a `nextPageToken`; with `search`, scans the whole channel by title. Returns `connected:false` as data (not an error) when no channel is connected. Exposes only public video metadata — never tokens. Account-scoped (no chatbot). Required scope: `videos:read`. - [Update access lists](/management-api/reference/patch-access-lists.md): Replace one or more access lists. Each supplied list is replaced wholesale; omitted lists are unchanged. At least one list must be provided. Requires admin-level access (`canManageAccess`). Required scope: `security:write`. - [Update access-protection config](/management-api/reference/patch-access-protection.md): Update access-protection enabled flag and/or jwtConfig (enabled, emailClaim, secret). If a new JWT secret is provided it is encrypted at rest; the plaintext is never stored. Returns the updated config (secret collapsed to hasSecret). Required scope: `security:write`. - [Update a chatbot](/management-api/reference/patch-chatbot.md): Partial update of chatbot configuration fields. Only top-level scalar/object fields accepted; nested arrays are replaced wholesale (not merged). Required scope: `chatbots:write`. The response `chatbot` field may be `null` if the document was deleted concurrently during the update (write-then-read race). - [Update a knowledge scope](/management-api/reference/patch-chatbot-scope.md): Partial update of ONE knowledge scope. Only the supplied fields change; absent fields (including `costLimit`, `authorizedEmails`, `authorizedDomains`) are preserved server-side. `null` on an optional field clears it; `[]` clears an array; `costLimit` is replaced atomically. `id` is immutable (ignored). Required scope: `chatbots:write`. - [Update knowledge scopes](/management-api/reference/patch-chatbot-scopes.md): Partial update of the knowledge-scope configuration. Write set matches GET read set exactly: `scopes`, `uiTree`, `slotWorkflows`, `defaultSlotId`, `defaultScopeLabel`, `showDefaultScopeInSelector`. Unknown fields are ignored. Legacy scope fields (knowledgeScopes, defaultScopeId, scopeRelationships, scopeCanvasLayout, scopeWorkflows, activeScopeWorkflowId) are not managed via this endpoint. Required scope: `chatbots:write`. - [Update external-API config](/management-api/reference/patch-external-api-config.md): Update the external-API enabled flag and/or rate limit. Required scope: `security:write`. - [Update an MCP server](/management-api/reference/patch-mcp-server.md): Partial update of an MCP server configuration. Supports: enabled toggle, modelOverride, credential update, tool re-discovery, accessKeyAction (generate/clear), executionMode, allowUiResources, allowLlmCompletion. OAuth flows, PostgreSQL scan, and metrics are dashboard-only (deferred). Required scope: `mcp:write`. - [Update a skill](/management-api/reference/patch-skill.md): Partial update of a skill. Can update: name, description, body, enabled, mode, linkedServerIds, linkedAgentIds. Immutable fields (id, createdAt, source, sourceServerId) are ignored in the request body. Name must remain unique within the chatbot. Required scope: `skills:write`. - [Replace authorized email list](/management-api/reference/put-document-authorized-emails.md): Replace the authorized email list for a document. Required scope: `documents:write`. - [Update MCP server access control](/management-api/reference/put-mcp-server-access.md): Replace the access-control settings for an MCP server. Supports: isPublic, authorizedEmails, authorizedGroups, and accessKeyAction. When accessKeyAction=generate a one-time plaintext accessKey is returned. Required scope: `mcp:write`. - [Replace telemetry config](/management-api/reference/put-telemetry-config.md): Replace the telemetry configuration for a chatbot. All four fields are required. When `containsSensitiveData` is true on the chatbot, `level` must be 'anonymized' and `endUserOptOutAllowed` will be forced to false. Required scope: `security:write`. - [Revoke a deployed user](/management-api/reference/remove-chatbot-user.md): Revokes a deployed user's access to the chatbot (disables their account). Required scope: `security:write`. - [Resolve a transcript correction](/management-api/reference/resolve-video-correction.md): Resolves a single correction on a video (IDOR-guarded): accept a suggested/candidate word, reject it, apply custom text, or undo a previous resolution. Accepting or applying custom text rebuilds the transcript and re-embeds it in the background. Required scope: `documents:write`. - [Revoke an access-protection key](/management-api/reference/revoke-access-protection-key.md): Revoke (soft-delete) an access-protection key. Revoked keys are immediately rejected; they remain in the list with status=revoked for audit purposes. Required scope: `security:write`. - [Revoke an external-API key](/management-api/reference/revoke-external-api-key.md): Revoke (soft-delete) an external-API key. Revoked keys are immediately rejected. Required scope: `security:write`. - [Start a website crawl](/management-api/reference/start-chatbot-crawl.md): Crawls one or more website URLs into the chatbot's knowledge base (embedded as searchable vectors), mirroring the dashboard website-crawl flow. Provide a single `url` or a `urls` array (max 100; the App batches into ≤10-per-request worker calls). Asynchronous — returns 202 with a crawlId + jobId; poll `GET /crawls` to track progress. Refuses a second in-flight crawl for the same domain + version (409). Requires admin-level chatbot access (owner / team admin / per-chatbot admin) — plain team editors cannot crawl via this API. Required scope: `documents:write`. - [Update a scheduled crawl](/management-api/reference/update-chatbot-scheduled-crawl.md): Updates a scheduled crawl. Any subset of the mutable fields may be provided; at least one is required. Changing the cadence recalculates the next run time. Required scope: `documents:write`. - [Update chatbot runtime settings](/management-api/reference/update-chatbot-settings.md): Updates the chatbot's runtime toggles: web search, unanswered-question tracking, long-term conversation memory, and short-term memory strategy. Mirrors the dashboard settings screen. Enabling long-term memory requires a Pro (or higher) plan AND authentication-required access. Disabling long-term memory, or switching the memory strategy away from 'graph', permanently deletes the stored memory and therefore requires `confirmDelete: true`. Only provided fields change; at least one must be present. Required scope: `chatbots:write`. - [Update document privacy](/management-api/reference/update-document-privacy.md): Update the privacy/access level of a document. Required scope: `documents:write`. - [Update an email group](/management-api/reference/update-email-group.md): Update an email group's name and/or member emails (provide at least one). Required scope: `security:write`. - [Update the Sales Agent configuration](/management-api/reference/update-sales-agent.md): Upserts the Sales Agent configuration. The agent doc is created on the first update (`created:true`). Only known config fields are applied; unknown fields are ignored. Configuring the agent does not enable it at runtime — enablement is a separate control. Required scope: `chatbots:write`. - [Update a lead-delivery channel](/management-api/reference/update-sales-agent-handoff.md): Updates an existing lead-delivery channel (recipients, routing mode, verified sender, webhook URL, included fields, enable/disable). The sending secret cannot be set here — it is managed from the dashboard, and enabling a channel requires its secret to already exist. Required scope: `chatbots:write`. - [Verify domain DNS](/management-api/reference/verify-chatbot-domain.md): Triggers a DNS verification check for the given domain. Returns `verified: true` when DNS is correctly configured; `verified: false` with a pending message when DNS is not yet propagated. Required scope: `domains:write`. - [WizChat Management API](/management-api/reference/wizchat-management-api.md): Programmatic control plane for WizChat chatbots. Authenticate with a `wpk_live_…` Management API key or a Firebase ID token. All endpoints are scoped — see the `x-scope` extension on each operation. ## security ### access-control Role-based access control and permissions in WizChat - [Access Control](/security/access-control.md): Role-based access control and permissions in WizChat ### data-residency Control where your data is stored for GDPR compliance - [Data Residency](/security/data-residency.md): Control where your data is stored for GDPR compliance ### data-retention Understand how long different types of data are kept on WizChat - [Data Retention](/security/data-retention.md): Understand how long different types of data are kept on WizChat ### encryption How WizChat protects your data with encryption - [Encryption](/security/encryption.md): How WizChat protects your data with encryption ### pii-protection How WizChat detects and redacts personally identifiable information - [PII Protection](/security/pii-protection.md): How WizChat detects and redacts personally identifiable information ### zdr Maximum privacy with zero data retention mode - [Zero Data Retention (ZDR)](/security/zdr.md): Maximum privacy with zero data retention mode ## teams ### chatbot-transfer Transfer ownership of a chatbot to another user - [Chatbot Ownership Transfer](/teams/chatbot-transfer.md): Transfer ownership of a chatbot to another user ### creating Create a team to collaborate with others on chatbots - [Creating a Team](/teams/creating.md): Create a team to collaborate with others on chatbots ### invitations Invite people to join your team - [Inviting Members](/teams/invitations.md): Invite people to join your team ### roles-permissions Understand team roles and what each can do - [Roles & Permissions](/teams/roles-permissions.md): Understand team roles and what each can do ### share-requests How team members can request to share chatbots with the team - [Share Request Workflow](/teams/share-requests.md): How team members can request to share chatbots with the team ### sharing Share chatbots with your team or specific individuals - [Sharing Chatbots](/teams/sharing.md): Share chatbots with your team or specific individuals ### team-ownership-transfer Transfer ownership of your entire team to another member - [Team Ownership Transfer](/teams/team-ownership-transfer.md): Transfer ownership of your entire team to another member ## troubleshooting ### common-issues Solutions to frequently encountered problems - [Common Issues](/troubleshooting/common-issues.md): Solutions to frequently encountered problems ### errors Reference for error messages and their solutions - [Error Messages](/troubleshooting/errors.md): Reference for error messages and their solutions ### faq Frequently asked questions about WizChat - [Frequently Asked Questions](/troubleshooting/faq.md): Frequently asked questions about WizChat --- # Full Documentation Content [Skip to main content](#__docusaurus_skipToContent_fallback) [![WizChat](/img/wizchat-logo.svg)![WizChat](/img/wizchat-logo.svg)](/index.md) [****](/index.md)[Documentation](/index.md)[Management API](/management-api/overview.md) ✨ Ask AI [Go to WizChat](https://wizchat.com) Search # Search the documentation Documentation * [Getting Started](/getting-started/quick-start.md) * [Chatbots](/chatbots/creating.md) * [Knowledge Base](/knowledge-base/overview.md) Features * [Teams & Collaboration](/teams/creating.md) * [Integrations](/integrations/mcp/overview.md) * [Management API](/management-api/overview.md) Support * [Troubleshooting](/troubleshooting/common-issues.md) * [FAQ](/troubleshooting/faq.md) * [Contact Support](mailto:support@wizchat.com) Company * [WizChat Home](https://wizchat.com) * [Privacy Policy](https://wizchat.com/privacy) * [Terms of Service](https://wizchat.com/terms) Copyright © 2026 WizChat. All rights reserved. --- # Docs for AI Agents These docs are built to be read by AI tools, not just people. If you're using Claude Code, Codex, Cursor, or any assistant that can fetch a URL, you can pull in clean documentation instead of scraping rendered HTML. ## Clean Markdown for any page Append `.md` to any documentation URL to get a clean Markdown version of that page: ``` https://docs.wizchat.com/getting-started/quick-start ← the page https://docs.wizchat.com/getting-started/quick-start.md ← clean Markdown ``` Point your assistant at the `.md` URL and it gets the content without navigation, styling, or scripts in the way. ## Index of every page — `llms.txt` The [`llms.txt`](https://docs.wizchat.com/llms.txt) file is a compact, machine-readable index of the whole documentation set, grouped by section, with a one-line summary and a link to the Markdown for each page. It follows the [llmstxt.org](https://llmstxt.org) standard. ``` https://docs.wizchat.com/llms.txt ``` Give this to an agent first so it can find the right pages, then let it fetch the specific `.md` files it needs. ## Full corpus — `llms-full.txt` If you'd rather hand the assistant everything at once, [`llms-full.txt`](https://docs.wizchat.com/llms-full.txt) is the entire documentation set concatenated into a single Markdown file. ``` https://docs.wizchat.com/llms-full.txt ``` Best for smaller context windows where a single fetch is simpler than following links. ## Ask the assistant on this site Every page has an **Ask AI** button and an **Ask a question** action that open an assistant with access to these docs — handy when you're reading in the browser rather than working from a terminal. ## Connect an AI client (MCP) For tools that speak the [Model Context Protocol](https://modelcontextprotocol.io) (Claude Code, Cursor, and others), WizChat runs a small **docs MCP server** so your assistant can search and read these docs directly — no scraping, no guessing URLs. Endpoint (public, read-only): `https://www.wizchat.com/api/docs-mcp` **Claude Code** ``` claude mcp add --transport http wizchat-docs https://www.wizchat.com/api/docs-mcp ``` **Cursor** — use the **Connect to Cursor** item in any page's **More actions** menu for a one-click install, or add an MCP server pointing at the endpoint above. It exposes two tools: * `search_docs(query)` — find the most relevant documentation pages. * `fetch_page(path)` — read a page's clean Markdown. --- # Cost Monitoring Track AI model costs and optimize spending. ## Cost Dashboard 1. Go to **"Analytics" > "Costs"** 2. View cost breakdown ## Cost Metrics | Metric | Description | | ------------------ | ---------------------- | | **Total cost** | All AI costs in period | | **Cost per query** | Average cost per query | | **Input tokens** | Tokens sent to AI | | **Output tokens** | Tokens generated by AI | ## Cost Breakdown ### By Model See costs for each AI model: | Model | Input Cost | Output Cost | | ----------- | ---------- | ----------- | | GPT-4o | $0.005/1K | $0.015/1K | | GPT-4 Turbo | $0.01/1K | $0.03/1K | | Claude 3.5 | $0.003/1K | $0.015/1K | ### By Chatbot See which chatbots cost the most: 1. Click **"By Chatbot"** 2. View per-chatbot costs 3. Identify high-cost chatbots ### By Feature * RAG (retrieval) * MCP integrations * Document processing ## Cost Alerts Set up alerts for cost thresholds: 1. Go to **"Settings" > "Notifications"** 2. Enable **"Cost Alerts"** 3. Set threshold (e.g., $50) 4. Choose notification channel ## Cost Optimization ### Reduce Token Usage * Use concise system prompts * Limit context window size * Reduce retrieved chunks ### Choose Efficient Models * Use GPT-4o for most queries * Reserve GPT-4/Claude Opus for complex tasks * Consider model routing ### Optimize Retrieval * Improve chunk quality * Use relevance thresholds * Cache common queries ## Cost Trends View cost patterns: * Daily/weekly/monthly trends * Cost per query over time * Model usage distribution ## Budget Management ### Setting Budgets 1. Go to **"Settings" > "Billing"** 2. Click **"Budget"** 3. Set budget for your billing cycle 4. Choose action when reached: * Alert only * Reduce to cheaper models * Pause chatbots ### Budget Tracking View budget vs actual: 1. Go to **"Analytics" > "Costs"** 2. See budget utilization 3. Track remaining budget ## Cost Reports Generate cost reports: 1. Go to **"Analytics" > "Costs"** 2. Click **"Generate Report"** 3. Select date range 4. Download PDF/CSV ## Related * [Query Analytics](/analytics/queries.md) * [Usage Reports](/analytics/reports.md) * [Subscription Plans](/billing/plans.md) --- # Query Analytics Understand how users interact with your chatbot. ## Overview Dashboard 1. Open your chatbot 2. Go to **"Analytics"** 3. View the overview dashboard ## Key Metrics ### Query Volume | Metric | Description | | -------------------- | -------------------------- | | **Total queries** | All queries in period | | **Unique users** | Distinct users who queried | | **Queries per user** | Average queries per user | | **Peak hours** | Busiest times | ### Query Success | Metric | Description | | ---------------- | ---------------------------------- | | **Answered** | Questions successfully answered | | **No answer** | Questions without relevant content | | **Errors** | Failed queries | | **Success rate** | Percentage answered successfully | ## Query Trends View query patterns over time: * Daily/weekly/monthly trends * Hour-of-day distribution * Day-of-week patterns * Seasonal trends ## Top Questions See the most common questions: 1. Go to **"Analytics" > "Top Questions"** 2. View ranked list of queries 3. See frequency and trends Use this to: * Identify content gaps * Improve documentation * Add suggested questions ## Query Search Search through query history: 1. Go to **"Analytics" > "Queries"** 2. Use search and filters 3. Find specific queries Filters: * Date range * User * Status (answered, failed) * Contains text ## Query Details Click on any query to see: * Full question text * Response provided * Sources used * Response time * User information (if authenticated) ## Unanswered Questions Find queries without good answers: 1. Go to **"Analytics" > "Unanswered"** 2. Review questions 3. Identify content to add Use this to improve your knowledge base. ## Response Time Monitor response performance: | Metric | Description | | ----------- | -------------------- | | **Average** | Mean response time | | **P50** | Median response time | | **P95** | 95th percentile | | **P99** | 99th percentile | ## Exporting Data Export query data: 1. Go to **"Analytics"** 2. Click **"Export"** 3. Select date range 4. Choose format (CSV, JSON) 5. Download ## Related * [Cost Monitoring](/analytics/costs.md) * [Usage Reports](/analytics/reports.md) --- # Usage Reports Generate comprehensive reports on chatbot usage. ## Generating Reports 1. Go to **"Analytics" > "Reports"** 2. Click **"Generate Report"** 3. Configure options: * Date range * Chatbots to include * Metrics to include 4. Click **"Generate"** ## Report Types ### Summary Report High-level overview including: * Total queries * Unique users * Success rate * Cost summary * Top questions ### Detailed Report In-depth analysis with: * All summary metrics * Hour-by-hour breakdown * User-level statistics * Query-level details * Source document usage ### Comparison Report Compare periods: * This month vs last month * This quarter vs last quarter * Year-over-year ## Report Contents ### Query Metrics * Total queries * Queries by day/hour * Query success rate * Average response time * Unanswered queries ### User Metrics * Unique users * New vs returning users * Queries per user * Session duration * User satisfaction (if collected) ### Content Metrics * Most used documents * Documents never used * Content gaps identified * Suggested improvements ### Cost Metrics * Total AI costs * Cost by model * Cost by chatbot * Cost trends ## Scheduled Reports Set up automatic reports: 1. Go to **"Analytics" > "Reports"** 2. Click **"Schedule Report"** 3. Configure: * Report type * Frequency (daily, weekly, monthly) * Recipients * Format (PDF, CSV) 4. Click **"Save"** ### Report Frequency | Frequency | Delivery | | --------- | -------------- | | Daily | Every morning | | Weekly | Monday morning | | Monthly | 1st of month | ## Exporting Reports ### PDF Export * Professional formatting * Charts and graphs * Ready for presentation ### CSV Export * Raw data * For further analysis * Import into spreadsheets ### API Access For Business plans: * Fetch reports via API * Integrate with BI tools * Automate reporting ## Custom Reports Business plans can create custom reports: 1. Select specific metrics 2. Add custom filters 3. Create branded templates 4. Save for reuse ## Sharing Reports Share reports with stakeholders: 1. Generate the report 2. Click **"Share"** 3. Enter email addresses 4. Add a message 5. Send Or download and share manually. ## Analytics via the Management API Analytics can be pulled programmatically for BI tools and custom dashboards. Every analytics endpoint requires the `analytics:read` scope. **Per-chatbot analytics** ``` GET /api/v1/chatbots/{chatbotId}/analytics/usage GET /api/v1/chatbots/{chatbotId}/analytics/cost GET /api/v1/chatbots/{chatbotId}/analytics/queries GET /api/v1/chatbots/{chatbotId}/analytics/quality GET /api/v1/chatbots/{chatbotId}/analytics/conversations GET /api/v1/chatbots/{chatbotId}/analytics/search GET /api/v1/chatbots/{chatbotId}/analytics/tokens GET /api/v1/chatbots/{chatbotId}/analytics/infra GET /api/v1/chatbots/{chatbotId}/analytics/transcription ``` | Endpoint | Returns | | --------------- | ----------------------------------------- | | `usage` | Query volume and user activity | | `cost` | AI spend broken down over the period | | `queries` | Query-log analytics | | `quality` | Agent quality metrics (e.g. `answerRate`) | | `conversations` | Conversation-intelligence analytics | | `search` | Search / retrieval-quality analytics | | `tokens` | Token-efficiency analytics | | `infra` | Infrastructure analytics | | `transcription` | Video-transcription analytics | **Workspace-level overview** ``` GET /api/v1/analytics/aggregate ``` Returns a usage overview across all chatbots in the workspace. ## Related * [Query Analytics](/analytics/queries.md) * [Cost Monitoring](/analytics/costs.md) * [Usage Tracking](/billing/usage.md) * [Management API Reference — Get usage analytics](/management-api/reference/get-chatbot-usage-analytics.md) * [Management API Reference — Get query-log analytics](/management-api/reference/get-chatbot-queries-analytics.md) * [Management API Reference — Get agent quality analytics](/management-api/reference/get-chatbot-quality-analytics.md) * [Management API Reference — Get workspace usage overview](/management-api/reference/get-aggregate-analytics.md) --- # API Authentication Learn how to authenticate your API requests to WizChat. ## Overview All API requests require authentication using an API key. ## Getting an API Key 1. Go to **"Settings" > "API"** 2. Click **"Generate API Key"** 3. Give the key a name (e.g., "Production API") 4. Select permissions 5. Click **"Create"** 6. Copy the key immediately warning API keys are shown only once. Store them securely. ## Using Your API Key Include the API key in the `Authorization` header: ``` curl -H "Authorization: Bearer YOUR_API_KEY" \ https://api.wizchat.com/v1/chatbots ``` ### Header Format ``` Authorization: Bearer YOUR_API_KEY ``` ## Key Permissions When creating a key, choose permissions: | Permission | Description | | ---------- | ------------------------------ | | **Read** | View chatbots, queries | | **Write** | Send messages, update settings | | **Admin** | Full access including delete | ### Read-Only Key ``` { "name": "Analytics Integration", "permissions": ["read"] } ``` ### Full Access Key ``` { "name": "Backend Service", "permissions": ["read", "write", "admin"] } ``` ## Key Management ### Viewing Keys 1. Go to **"Settings" > "API"** 2. See all active keys 3. View last used date ### Revoking Keys 1. Find the key in the list 2. Click **"Revoke"** 3. Confirm revocation Revoked keys stop working immediately. ### Rotating Keys Best practice: rotate keys periodically. 1. Create a new key 2. Update your applications 3. Revoke the old key ## Security Best Practices ### Do * Store keys in environment variables * Use different keys for different environments * Rotate keys regularly * Use minimum required permissions * Monitor key usage ### Don't * Commit keys to version control * Share keys via email or chat * Use production keys in development * Give more permissions than needed ## Environment Variables Store your API key in environment variables: ``` # .env file WIZCHAT_API_KEY=your_api_key_here ``` ``` // Access in code const apiKey = process.env.WIZCHAT_API_KEY; ``` ## Error Responses ### Invalid Key ``` { "error": { "code": "UNAUTHORIZED", "message": "Invalid API key" } } ``` ### Missing Key ``` { "error": { "code": "UNAUTHORIZED", "message": "API key required" } } ``` ### Revoked Key ``` { "error": { "code": "UNAUTHORIZED", "message": "API key has been revoked" } } ``` ## IP Restrictions Optionally restrict keys to specific IPs: 1. Go to **"Settings" > "API"** 2. Click on a key 3. Add allowed IP addresses 4. Save ## Related * [API Reference - Chatbots](/api/chatbots.md) * [Error Codes](/api/errors.md) * [External API](/integrations/external-api.md) --- # Chatbot API Endpoints Query and manage chatbots via the API. ## Base URL ``` https://api.wizchat.com/v1 ``` ## Query a Chatbot Send a message to a chatbot and get a response. ### Endpoint ``` POST /chatbots/{chatbotId}/query ``` ### Request ``` curl -X POST https://api.wizchat.com/v1/chatbots/cb_123/query \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "message": "What is your return policy?" }' ``` ### Request Body | Field | Type | Required | Description | | ---------------- | ------ | -------- | ------------------------------ | | `message` | string | Yes | The user's question | | `conversationId` | string | No | Continue existing conversation | | `userId` | string | No | Identify the user | | `metadata` | object | No | Additional context | ### Response ``` { "response": "Our return policy allows returns within 30 days...", "conversationId": "conv_abc123", "sources": [ { "documentId": "doc_xyz", "title": "Return Policy", "chunk": "Returns within 30 days...", "relevance": 0.95 } ], "usage": { "inputTokens": 150, "outputTokens": 200, "cost": 0.0025 } } ``` ### Response Fields | Field | Type | Description | | ---------------- | ------ | -------------------------------- | | `response` | string | The chatbot's response | | `conversationId` | string | ID to continue this conversation | | `sources` | array | Documents used for the response | | `usage` | object | Token usage and cost | ## List Chatbots Get all chatbots you have access to. ### Endpoint ``` GET /chatbots ``` ### Request ``` curl https://api.wizchat.com/v1/chatbots \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Response ``` { "chatbots": [ { "id": "cb_123", "name": "Support Bot", "description": "Customer support assistant", "status": "active", "createdAt": "2024-01-15T10:00:00Z" } ], "pagination": { "page": 1, "perPage": 20, "total": 1 } } ``` ## Get Chatbot Details Get details about a specific chatbot. ### Endpoint ``` GET /chatbots/{chatbotId} ``` ### Request ``` curl https://api.wizchat.com/v1/chatbots/cb_123 \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Response ``` { "id": "cb_123", "name": "Support Bot", "description": "Customer support assistant", "status": "active", "settings": { "model": "gpt-4o", "temperature": 0.7, "systemPrompt": "You are a helpful assistant..." }, "stats": { "totalQueries": 1500, "documentsCount": 25 }, "createdAt": "2024-01-15T10:00:00Z", "updatedAt": "2024-02-01T15:30:00Z" } ``` ## Get Conversation History Retrieve messages from a conversation. ### Endpoint ``` GET /chatbots/{chatbotId}/conversations/{conversationId} ``` ### Request ``` curl https://api.wizchat.com/v1/chatbots/cb_123/conversations/conv_abc \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Response ``` { "conversationId": "conv_abc123", "messages": [ { "role": "user", "content": "What is your return policy?", "timestamp": "2024-02-01T10:00:00Z" }, { "role": "assistant", "content": "Our return policy allows...", "timestamp": "2024-02-01T10:00:01Z" } ], "metadata": { "userId": "user_123", "startedAt": "2024-02-01T10:00:00Z" } } ``` ## Streaming Responses Get streamed responses for real-time display. ### Endpoint ``` POST /chatbots/{chatbotId}/query/stream ``` ### Request ``` curl -X POST https://api.wizchat.com/v1/chatbots/cb_123/query/stream \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: text/event-stream" \ -d '{"message": "Tell me about your products"}' ``` ### Response (Server-Sent Events) ``` data: {"type": "start", "conversationId": "conv_abc"} data: {"type": "chunk", "content": "We offer "} data: {"type": "chunk", "content": "a variety of "} data: {"type": "chunk", "content": "products..."} data: {"type": "done", "usage": {"inputTokens": 100, "outputTokens": 150}} ``` ## Related * [API Authentication](/api/authentication.md) * [Document Endpoints](/api/documents.md) * [Error Codes](/api/errors.md) --- # Document API Endpoints Upload and manage documents via the API. ## Base URL ``` https://api.wizchat.com/v1 ``` ## Upload a Document Upload a file to a chatbot's knowledge base. ### Endpoint ``` POST /chatbots/{chatbotId}/documents ``` ### Request (Multipart Form) ``` curl -X POST https://api.wizchat.com/v1/chatbots/cb_123/documents \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "file=@document.pdf" \ -F "name=Product Guide" \ -F "accessLevel=public" ``` ### Form Fields | Field | Type | Required | Description | | ------------- | ------ | -------- | --------------------------------- | | `file` | file | Yes | The document file | | `name` | string | No | Display name | | `accessLevel` | string | No | public, authenticated, restricted | | `tags` | string | No | Comma-separated tags | ### Response ``` { "id": "doc_xyz", "name": "Product Guide", "status": "processing", "size": 1024000, "mimeType": "application/pdf", "createdAt": "2024-02-01T10:00:00Z" } ``` ## Upload via URL Import a document from a URL. ### Endpoint ``` POST /chatbots/{chatbotId}/documents/url ``` ### Request ``` curl -X POST https://api.wizchat.com/v1/chatbots/cb_123/documents/url \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/document.pdf", "name": "External Document" }' ``` ### Request Body | Field | Type | Required | Description | | ------------- | ------ | -------- | -------------------------- | | `url` | string | Yes | URL to fetch document from | | `name` | string | No | Display name | | `accessLevel` | string | No | Access level | ## List Documents Get all documents in a chatbot's knowledge base. ### Endpoint ``` GET /chatbots/{chatbotId}/documents ``` ### Request ``` curl https://api.wizchat.com/v1/chatbots/cb_123/documents \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Query Parameters | Parameter | Type | Description | | --------- | ------ | ---------------------------- | | `page` | number | Page number (default: 1) | | `perPage` | number | Items per page (default: 20) | | `status` | string | Filter by status | | `type` | string | Filter by document type | ### Response ``` { "documents": [ { "id": "doc_xyz", "name": "Product Guide", "status": "ready", "type": "pdf", "size": 1024000, "chunks": 45, "createdAt": "2024-02-01T10:00:00Z" } ], "pagination": { "page": 1, "perPage": 20, "total": 1 } } ``` ## Get Document Details Get details about a specific document. ### Endpoint ``` GET /chatbots/{chatbotId}/documents/{documentId} ``` ### Request ``` curl https://api.wizchat.com/v1/chatbots/cb_123/documents/doc_xyz \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Response ``` { "id": "doc_xyz", "name": "Product Guide", "status": "ready", "type": "pdf", "size": 1024000, "mimeType": "application/pdf", "chunks": 45, "accessLevel": "public", "tags": ["product", "guide"], "metadata": { "pageCount": 20, "author": "Marketing Team" }, "createdAt": "2024-02-01T10:00:00Z", "processedAt": "2024-02-01T10:01:00Z" } ``` ## Delete a Document Remove a document from the knowledge base. ### Endpoint ``` DELETE /chatbots/{chatbotId}/documents/{documentId} ``` ### Request ``` curl -X DELETE https://api.wizchat.com/v1/chatbots/cb_123/documents/doc_xyz \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Response ``` { "success": true, "message": "Document deleted" } ``` ## Check Processing Status Check if a document has finished processing. ### Endpoint ``` GET /chatbots/{chatbotId}/documents/{documentId}/status ``` ### Response ``` { "id": "doc_xyz", "status": "ready", "progress": 100, "chunks": 45, "error": null } ``` ### Status Values | Status | Description | | ------------ | -------------------- | | `pending` | Waiting to process | | `processing` | Currently processing | | `ready` | Processing complete | | `failed` | Processing failed | ## Related * [API Authentication](/api/authentication.md) * [Chatbot Endpoints](/api/chatbots.md) * [Error Codes](/api/errors.md) --- # API Error Codes Reference for API error responses and troubleshooting. ## Error Response Format All errors follow this format: ``` { "error": { "code": "ERROR_CODE", "message": "Human-readable description", "details": { "field": "Additional context" } } } ``` ## HTTP Status Codes | Status | Description | | ------ | -------------------------------------- | | `400` | Bad Request - Invalid parameters | | `401` | Unauthorized - Authentication failed | | `403` | Forbidden - Insufficient permissions | | `404` | Not Found - Resource doesn't exist | | `429` | Too Many Requests - Rate limited | | `500` | Internal Error - Server issue | | `503` | Service Unavailable - Temporary outage | ## Authentication Errors ### UNAUTHORIZED ``` { "error": { "code": "UNAUTHORIZED", "message": "Invalid or missing API key" } } ``` **Causes:** * Missing Authorization header * Invalid API key * Revoked API key * Expired key **Solutions:** * Check API key is correct * Verify header format: `Authorization: Bearer YOUR_KEY` * Generate a new key if revoked ### FORBIDDEN ``` { "error": { "code": "FORBIDDEN", "message": "You don't have permission to access this resource" } } ``` **Causes:** * API key lacks required permissions * Not a team member * Chatbot not shared with you **Solutions:** * Use a key with appropriate permissions * Request access from owner * Check team membership ## Resource Errors ### NOT\_FOUND ``` { "error": { "code": "NOT_FOUND", "message": "Chatbot not found", "details": { "chatbotId": "cb_invalid" } } } ``` **Causes:** * Resource doesn't exist * Resource was deleted * Incorrect ID **Solutions:** * Verify the resource ID * List resources to find correct ID * Check if resource was deleted ### ALREADY\_EXISTS ``` { "error": { "code": "ALREADY_EXISTS", "message": "A resource with this name already exists" } } ``` **Causes:** * Duplicate name * Unique constraint violation **Solutions:** * Use a different name * Update existing resource instead ## Validation Errors ### INVALID\_REQUEST ``` { "error": { "code": "INVALID_REQUEST", "message": "Invalid request body", "details": { "message": "Field is required" } } } ``` **Causes:** * Missing required field * Invalid field value * Malformed JSON **Solutions:** * Check required fields * Validate field values * Verify JSON syntax ### INVALID\_FILE ``` { "error": { "code": "INVALID_FILE", "message": "File type not supported", "details": { "reference": "See /knowledge-base/uploading for current supported formats" } } } ``` **Causes:** * Unsupported file type * File too large * Corrupted file **Solutions:** * Check supported file types * Reduce file size * Try a different file ## Rate Limiting ### RATE\_LIMIT\_EXCEEDED ``` { "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Too many requests", "details": { "limit": 60, "remaining": 0, "resetAt": "2024-02-01T10:01:00Z" } } } ``` **Headers:** ``` X-RateLimit-Limit: 60 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1706781660 ``` **Solutions:** * Wait for rate limit reset * Implement request throttling * Upgrade plan for higher limits ## Usage Errors ### QUOTA\_EXCEEDED ``` { "error": { "code": "QUOTA_EXCEEDED", "message": "Monthly query limit exceeded", "details": { "limit": 1000, "used": 1000 } } } ``` **Solutions:** * Wait for billing cycle reset * Purchase additional credits * Upgrade your plan ### STORAGE\_LIMIT ``` { "error": { "code": "STORAGE_LIMIT", "message": "Storage limit reached", "details": { "limit": "Depends on plan", "used": "Current usage" } } } ``` **Solutions:** * Delete unused documents * Upgrade your plan * Check per-file upload caps by plan and file type: `/billing/plans#file-upload-size-limits` ## Server Errors ### INTERNAL\_ERROR ``` { "error": { "code": "INTERNAL_ERROR", "message": "An unexpected error occurred" } } ``` **Solutions:** * Retry the request * Check status page * Contact support if persistent ### SERVICE\_UNAVAILABLE ``` { "error": { "code": "SERVICE_UNAVAILABLE", "message": "Service temporarily unavailable" } } ``` **Solutions:** * Wait and retry * Check status page * Implement retry with backoff ## Error Handling Best Practices ### Retry Logic ``` async function apiCall(fn, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await fn(); } catch (error) { if (error.status === 429 || error.status >= 500) { await sleep(Math.pow(2, i) * 1000); continue; } throw error; } } } ``` ### Error Logging Log errors with context for debugging: ``` try { const response = await api.query(chatbotId, message); } catch (error) { console.error('API Error:', { code: error.code, message: error.message, chatbotId, timestamp: new Date().toISOString() }); } ``` ## Related * [API Authentication](/api/authentication.md) * [Rate Limits](/integrations/external-api.md#rate-limits) * [Troubleshooting](/troubleshooting/common-issues.md) --- # Team API Endpoints Manage teams and team members via the API. ## Base URL ``` https://api.wizchat.com/v1 ``` ## List Teams Get all teams you're a member of. ### Endpoint ``` GET /teams ``` ### Request ``` curl https://api.wizchat.com/v1/teams \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Response ``` { "teams": [ { "id": "team_abc", "name": "Engineering", "role": "admin", "memberCount": 5, "createdAt": "2024-01-01T00:00:00Z" } ] } ``` ## Get Team Details Get details about a specific team. ### Endpoint ``` GET /teams/{teamId} ``` ### Request ``` curl https://api.wizchat.com/v1/teams/team_abc \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Response ``` { "id": "team_abc", "name": "Engineering", "description": "Engineering team chatbots", "memberCount": 5, "chatbotCount": 3, "owner": { "id": "user_123", "email": "owner@example.com" }, "createdAt": "2024-01-01T00:00:00Z" } ``` ## List Team Members Get all members of a team. ### Endpoint ``` GET /teams/{teamId}/members ``` ### Request ``` curl https://api.wizchat.com/v1/teams/team_abc/members \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Response ``` { "members": [ { "id": "user_123", "email": "user@example.com", "name": "John Doe", "role": "admin", "status": "active", "joinedAt": "2024-01-01T00:00:00Z" } ], "pagination": { "page": 1, "perPage": 20, "total": 5 } } ``` ## Invite Team Member Send an invitation to join the team. ### Endpoint ``` POST /teams/{teamId}/invitations ``` ### Request ``` curl -X POST https://api.wizchat.com/v1/teams/team_abc/invitations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "email": "newuser@example.com", "role": "member" }' ``` ### Request Body | Field | Type | Required | Description | | ------- | ------ | -------- | --------------- | | `email` | string | Yes | Email to invite | | `role` | string | Yes | admin or member | ### Response ``` { "id": "inv_xyz", "email": "newuser@example.com", "role": "member", "status": "pending", "expiresAt": "2024-02-08T00:00:00Z", "createdAt": "2024-02-01T00:00:00Z" } ``` ## Remove Team Member Remove a member from the team. ### Endpoint ``` DELETE /teams/{teamId}/members/{userId} ``` ### Request ``` curl -X DELETE https://api.wizchat.com/v1/teams/team_abc/members/user_456 \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Response ``` { "success": true, "message": "Member removed" } ``` ## Update Member Role Change a team member's role. ### Endpoint ``` PATCH /teams/{teamId}/members/{userId} ``` ### Request ``` curl -X PATCH https://api.wizchat.com/v1/teams/team_abc/members/user_456 \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "role": "admin" }' ``` ### Response ``` { "id": "user_456", "role": "admin", "updatedAt": "2024-02-01T10:00:00Z" } ``` ## List Team Chatbots Get chatbots shared with the team. ### Endpoint ``` GET /teams/{teamId}/chatbots ``` ### Request ``` curl https://api.wizchat.com/v1/teams/team_abc/chatbots \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Response ``` { "chatbots": [ { "id": "cb_123", "name": "Support Bot", "owner": { "id": "user_123", "email": "owner@example.com" }, "accessLevel": "edit", "sharedAt": "2024-01-15T00:00:00Z" } ] } ``` ## Related * [API Authentication](/api/authentication.md) * [Chatbot Endpoints](/api/chatbots.md) * [Error Codes](/api/errors.md) --- # Invoices Access your billing history and download invoices. ## Viewing Invoices 1. Go to **"Settings" > "Billing"** 2. Click **"Invoices"** 3. See all past invoices ## Invoice Information Each invoice includes: | Field | Description | | ------------- | ---------------------- | | **Invoice #** | Unique identifier | | **Date** | Invoice date | | **Amount** | Total charged | | **Status** | Paid, pending, failed | | **Period** | Billing period covered | ## Downloading Invoices 1. Find the invoice 2. Click **"Download PDF"** 3. Save for your records ## Invoice Details Click on an invoice to see: * Line items (subscription, top-up purchases) * Payment method used * Tax information * Company details ## Updating Billing Information ### Company Details Add company name and address for invoices: 1. Go to **"Settings" > "Billing"** 2. Click **"Billing Details"** 3. Enter company information 4. Click **"Save"** ### Tax ID Add VAT or tax ID: 1. Go to **"Settings" > "Billing"** 2. Click **"Tax Information"** 3. Enter tax ID 4. Click **"Save"** ## Payment Methods ### View Payment Methods 1. Go to **"Settings" > "Billing"** 2. Click **"Payment Methods"** 3. See saved cards ### Add Payment Method 1. Click **"Add Payment Method"** 2. Enter card details 3. Click **"Save"** ### Remove Payment Method 1. Find the payment method 2. Click **"Remove"** 3. Confirm removal note You must have at least one payment method for paid plans. ## Failed Payments If a payment fails: 1. You receive an email notification 2. Invoice shows "Failed" status 3. Update payment method 4. Retry payment ### Retry Payment 1. Go to **"Invoices"** 2. Find the failed invoice 3. Click **"Retry Payment"** ## Billing Cycle * Subscriptions bill monthly or annually * Billing date is your signup date * Usage resets at each billing cycle ## Receipts Email receipts are sent for: * Subscription charges * Top-up purchases Configure email receipts in **"Settings" > "Notifications"**. ## Related * [Subscription Plans](/billing/plans.md) * [Usage Tracking](/billing/usage.md) * [Top-Up Credits](/billing/top-up.md) --- # Subscription Plans Choose the plan that fits your needs. ## Plan Comparison | Feature | Free | Starter | Pro | Pro+ | Business | Enterprise | | ------------------------------------------------------------------------------------------- | ----------- | ------- | --------- | --------- | --------- | ---------- | | **Price** | $0 | $20/mo | $50/mo | $100/mo | $200/mo | Custom | | **AI Budget** | $5 one-time | $20/mo | $50/mo | $100/mo | $200/mo | Unlimited | | **Chatbots** | 1 | 5 | Unlimited | Unlimited | Unlimited | Unlimited | | **Storage** | 100 MB | 1 GB | 4 GB | 10 GB | 20 GB | Unlimited | | **Custom Domain** | - | - | Yes | Yes | Yes | Yes | | **Remove Branding** | - | - | Yes | Yes | Yes | Yes | | **Top-ups** | - | Yes | Yes | Yes | Yes | - | | **Team Seats** | - | - | - | 5 | 20 | Unlimited | | **Support** | Community | Email | Priority | Priority | Dedicated | Dedicated | | **Chat Retention** | 30 days | 90 days | 180 days | 365 days | 365 days | Unlimited | | **File Upload Retention** | 3 days | 7 days | 14 days | 30 days | 30 days | Unlimited | | **[Knowledge Scopes](/knowledge-base/scopes.md)** | - | - | - | - | Yes | Yes | | **[Long-term Conversation Memory](/chatbots/ai-settings.md#long-term-conversation-memory)** | - | - | Yes | Yes | Yes | Yes | | **SLA** | - | - | - | - | - | Yes | | **SSO/SAML** | - | - | - | - | - | Yes | ## Free Plan Get started with a lifetime $5 credit: * 1 chatbot (can delete and redeploy) * **$5 lifetime AI budget** (never resets) * 100 MB storage * 30-day chat history / 3-day file upload retention * Basic features * Community support * WizChat subdomain hosting Perfect for trying out WizChat. When your credit runs out, upgrade to a paid plan to continue. Important The free plan budget is a **lifetime grant**. Unlike paid plans, it does **not** reset or renew. Once depleted, you must upgrade to continue using your chatbots. ## Starter Plan For individuals and small projects: * 5 chatbots * **$20/month AI budget** (resets each billing cycle) * 1 GB storage * 90-day chat history / 7-day file upload retention * Top-up credits available * Email support **$20/month** ## Pro Plan For growing businesses: * Unlimited chatbots * **$50/month AI budget** (resets each billing cycle) * 4 GB storage * 180-day chat history / 14-day file upload retention * Custom domains * Remove "Powered by ChatFactory" branding * [Long-term Conversation Memory](/chatbots/ai-settings.md#long-term-conversation-memory) for personalized chat across sessions (requires chatbot authentication) * MCP integrations * Priority support **$50/month** ## Pro+ Plan For teams that need more: * Everything in Pro * **$100/month AI budget** (resets each billing cycle) * 10 GB storage * 365-day chat history / 30-day file upload retention * 5 team seats included * Priority support **$100/month** ## Business Plan For larger organizations: * Unlimited chatbots * **$200/month AI budget** (resets each billing cycle) * 20 GB storage * 365-day chat history / 30-day file upload retention * 20 team seats included * Full MCP integrations * Custom domains * Dedicated support **$200/month** ## Enterprise For organizations with custom needs: * Unlimited AI budget * Unlimited storage * Unlimited data retention * Unlimited team seats * [AI Gateway BYOK](/integrations/ai-gateway-byok.md) — Use your own API keys with zero markup * On-premise options * SLA guarantees * Dedicated success manager * Custom integrations [Contact sales](mailto:sales@wizchat.com) for pricing. ## Understanding AI Budget WizChat uses **cost-based billing** rather than query-based. Your AI budget is consumed based on actual AI usage costs: * Different AI models have different costs per token * Complex queries with more context cost more * Simple queries cost less * You can monitor your spending in real-time This model is fairer than query-based billing because you pay for what you actually use. *\* Starter, Pro, Pro+, and Business tiers apply a 32% platform markup on raw AI API costs. Enterprise plans use custom pricing terms.* ### Your Billing Cycle Your AI budget resets based on **your personal billing cycle** — the date you subscribed, not the 1st of the month. For example, if you subscribe to the Pro plan on **January 15th**, your billing cycle runs from the **15th of each month** to the **14th of the next month**. Your $50 budget resets every January 15th, February 15th, March 15th, and so on. You can always see your exact reset date on your **Dashboard** or in **"Settings" > "Usage"**. ### Budget Behavior | Plan Type | Budget Behavior | | ----------------------------- | ------------------------------------------------------ | | **Free** | Lifetime $5 credit — never resets | | **Starter/Pro/Pro+/Business** | Budget resets on your personal billing date each month | | **Enterprise** | Contract-based (typically uncapped) | ### What Happens When Budget Runs Out * **Free Plan:** Chatbots are paused. Upgrade to continue. * **Starter/Pro/Pro+/Business:** Chatbots are paused until budget resets, or purchase a top-up. * **Enterprise:** Budget behavior is contract-based (typically uncapped). ## Storage Storage includes: * Uploaded documents (PDFs, DOCX, etc.) * Crawled web pages * Video transcripts * Processed embeddings ## File Upload Size Limits Per-file upload limits are enforced by both plan and file type. **Effective per-file limit = min(plan limit, file-type limit)** ### Plan per-file limits | Plan | Max file size | | ---------- | ------------- | | Free | 25 MB | | Starter | 200 MB | | Pro | 500 MB | | Pro+ | 1 GB | | Business | 2 GB | | Enterprise | 5 GB | ### File-type hard limits | File type | Max file size | | --------------- | ------------- | | PDF | 500 MB | | CHM | 350 MB | | Excel/CSV | 200 MB | | Video | 1 GB | | Image | 50 MB | | Other documents | 500 MB | info If your plan allows a larger file than a file-type hard limit, the file-type limit still applies. Example: Enterprise allows up to 5 GB per file, but image uploads are still capped at 50 MB. ## Team Seats Team members can access shared chatbots based on their role (Owner, Admin, Member). ## Changing Plans ### Upgrade 1. Go to **"Settings" > "Billing"** 2. Click **"Change Plan"** 3. Select the new plan 4. Confirm and pay Upgrades take effect immediately. You're charged the prorated difference. ### Downgrade 1. Go to **"Settings" > "Billing"** 2. Click **"Change Plan"** 3. Select the lower plan 4. Confirm the change Downgrades take effect at the end of your billing period. warning Ensure you're within the new plan's limits before downgrading. ## Related * [Data Retention](/security/data-retention.md) * [Usage Tracking](/billing/usage.md) * [Top-Up Credits](/billing/top-up.md) * [Invoices](/billing/invoices.md) --- # Top-Up Credits Purchase additional AI budget when you need more than your plan includes. ## How Top-Ups Work * Top-ups add budget in USD to your account * Top-up balance is used after your monthly plan budget is depleted * Top-up balance does not expire * Top-ups are available on Starter, Pro, Pro+, and Business plans WizChat billing is cost-based (not query-based). Budget consumption depends on model/token cost. For Starter, Pro, Pro+, and Business tiers, budget usage applies the same **32% platform markup** used for regular plan budgets. ## Purchasing Top-Ups 1. Go to **"Settings" > "Billing"** 2. Click **"Buy Top-Up"** 3. Select package 4. Complete payment ## Top-Up Packages | Package | You Pay | Budget Added | | ------- | ------- | ------------ | | Small | $10 | $10 | | Medium | $25 | $25 | | Large | $50 | $50 | ## Budget Usage Order When budget is consumed: 1. Monthly plan budget is used first 2. Then top-up budget is used ## Viewing Top-Up Balance 1. Go to **"Settings" > "Billing"** 2. See **"Top-Up Balance"** 3. View remaining budget ## Top-Up History View top-up purchases and usage: 1. Go to **"Settings" > "Billing"** 2. Open transaction history 3. See all transactions | Transaction | Type | | ----------- | ----------------- | | Purchase | Budget added | | Usage | Budget consumed | | Refund | Budget adjustment | ## Team Credits For teams: * Team owner purchases top-ups * Top-up budget is shared across team * Usage is tracked per member ## Refunds Top-ups are non-refundable but: * Never expire * Transfer if you change plans * Can be used across all chatbots ## Related * [Subscription Plans](/billing/plans.md) * [Usage Tracking](/billing/usage.md) * [Invoices](/billing/invoices.md) --- # Usage Tracking Monitor your AI budget usage to stay informed about your spending. ## How Billing Works WizChat uses **cost-based billing**. Instead of counting queries, we track the actual AI costs incurred by your chatbot conversations: * Each AI model has different costs per token * More complex conversations cost more * Simple queries cost less * You only pay for what you actually use For Starter, Pro, Pro+, and Business tiers, usage applies a **32% platform markup** on raw model API costs. This is fairer than query-based billing because a simple "hello" doesn't cost the same as a detailed analysis. ## Viewing Usage 1. Go to **"Dashboard"** to see the usage overview card 2. Or go to **"Settings" > "Usage"** for detailed metrics You'll see: * Current AI cost this period * Budget remaining * Cost percentage used * Chatbots created ## Free Plan vs Other Plans ### Free Plan The free plan gives you a **lifetime $5 AI budget**: * Tracks usage from account creation — never resets * Once depleted, chatbots are paused * Upgrade to a paid plan to continue warning Free plan budget is a lifetime credit. It does not renew. Plan accordingly. ### Starter, Pro, Pro+, and Business Plans These plans have **monthly recurring budgets** that reset on your personal billing date: | Plan | Monthly Budget | | -------- | -------------- | | Starter | $20/month | | Pro | $50/month | | Pro+ | $100/month | | Business | $200/month | **How your billing cycle works:** Your budget resets on the same date you originally subscribed — not the 1st of the month. For example, if you signed up on March 10th, your budget resets every month on the 10th. * Unused budget does **not** roll over to the next cycle * You can purchase [top-ups](/billing/top-up.md) anytime if you need more before your reset date * Your exact reset date is shown on your Dashboard tip You can check your current billing period and reset date anytime in **"Settings" > "Usage"**. Enterprise plans use contract-based budget terms (typically uncapped). ## Usage Metrics ### AI Budget | Metric | Description | | ---------------- | ------------------------------------- | | **Current Cost** | AI costs incurred this billing period | | **Budget Limit** | Your plan's AI budget | | **Remaining** | Budget left to use | | **Percentage** | How much of your budget is used | ### Storage | Metric | Description | | ------------- | ----------------------------- | | **Documents** | Space used by uploads | | **Web pages** | Space used by crawled content | | **Videos** | Space used by transcriptions | | **Total** | Combined storage used | ## Usage by Chatbot See which chatbots consume the most AI budget: 1. Go to **"Analytics" > "Costs"** 2. View per-chatbot breakdown 3. Identify high-usage chatbots ## Usage History View historical usage: 1. Go to **"Settings" > "Usage"** 2. Click **"History"** 3. Select date range 4. View trends over time ## Usage Alerts Get notified before hitting limits: 1. Go to **"Settings" > "Notifications"** 2. Enable usage alerts 3. Set thresholds (e.g., 80%, 90%, 100%) Alert channels: * Email * In-app notification * Webhook (Business plans) ## What Happens at Limits ### Budget Limit Reached **Free Plan:** * Chatbots are paused for new conversations * Existing conversations can continue briefly * Upgrade to a paid plan to restore service **Starter/Pro/Pro+/Business:** * Chatbots are paused until: * Budget resets on your next Stripe billing date, OR * You purchase a top-up * Users see a friendly limit message **Enterprise:** * Budget behavior is contract-based (typically uncapped) ### Storage Limit Reached When you reach storage limit: * New uploads are blocked * Existing content remains accessible * Delete content or upgrade to continue * Per-file upload caps also apply by plan and file type See [Subscription Plans](/billing/plans.md#file-upload-size-limits) for per-file limits. ## Top-Up Credits If you run out of budget before your reset date on Starter, Pro, Pro+, or Business, purchase a top-up: 1. Go to **"Settings" > "Billing"** 2. Click **"Buy Top-Up"** 3. Select a package 4. Budget is added immediately Top-up balance is used after your monthly budget is depleted. See [Top-Up Credits](/billing/top-up.md) for details. ## Reducing AI Costs ### Optimize Conversations * Use efficient system prompts * Configure appropriate context limits * Choose cost-effective AI models for simple use cases ### Reduce Storage * Delete unused documents * Remove old web crawls * Compress large files before uploading * Archive unused chatbots ## Team Usage For team accounts, view usage by member: 1. Go to **"Teams" > "Usage"** 2. See per-member breakdown 3. Identify usage patterns ## Exporting Usage Data Export usage data for reporting: 1. Go to **"Settings" > "Usage"** 2. Click **"Export"** 3. Select date range 4. Download CSV ## Related * [Subscription Plans](/billing/plans.md) * [Top-Up Credits](/billing/top-up.md) * [Cost Analytics](/analytics/costs.md) --- # Changelog Recent updates and improvements to WizChat. ## August 2026 ### 2026-08-13 **New Features** * **[Native (in-page) embed rendering](/chatbots/deployment.md#native-in-page-render-mode)** — The script embed can now render the chat panel directly in your page inside a Shadow DOM instead of an iframe, with `renderMode: "native"`. The native panel streams answers from the chatbot's public chat endpoint — no iframe and no secret key in the browser — and composes with both the corner bubble and the docked sidebar. The default iframe embed is unchanged. * **[Connect OAuth MCP servers from the chat](/integrations/mcp/oauth.md#connecting-from-the-chat)** — Visitors can now connect and disconnect OAuth-based MCP servers — for example a Microsoft / SharePoint server — directly from the chat's MCP menu, signing in through a popup with a full-page redirect fallback. Each visitor authorizes with their own account, and a server can be limited to specific users or groups. **Bug Fixes** * **Group-restricted MCP servers now appear and connect** — An MCP server limited to an allowed user group could be filtered out for every visitor, so it never showed up or connected. Group membership now resolves correctly, and the "Connect" sign-in no longer fails on a redirecting host. * **MCP tool answers are no longer dropped for dynamically-discovered servers** — For MCP servers whose tool catalog is discovered at connect time, a tool's result could be left unattributed and ignored, causing the chatbot to answer as if the tool had returned nothing. Results from these servers are now attributed to the live connection, so the answer reflects what the tool actually returned. ### 2026-08-12 **New Features** * **[Ask about an audio file in chat](/chatbots/media-attachments.md#uploading-audio)** — Visitors can attach an audio file (MP3 or WAV, up to 25 MB) from the composer's **+** menu and ask about it. When the chatbot's [BYOI](/integrations/byoi.md) chat endpoint is audio-capable, the model listens to the clip directly; otherwise WizChat transcribes it and answers from the transcript. A transcript is carried into the conversation, so follow-up questions run through the normal knowledge-base pipeline with the audio as context. On zero-data-retention / EU-residency chatbots, audio requires self-hosted speech-to-text and text endpoints. * **[Ask about a video in chat](/chatbots/media-attachments.md#uploading-video)** — Visitors can attach a video (MP4, WebM, or MOV, up to 100 MB) and ask about it. Video understanding is BYOI-only: it works when the chatbot's [BYOI](/integrations/byoi.md) chat endpoint is a self-hosted, video-capable model, which watches the video through a short-lived signed URL. Chatbots without a video-capable endpoint return a clear message instead. ### 2026-08-10 **New Features** * **[Docked sidebar embed mode](/chatbots/deployment.md#docked-sidebar-mode)** — The script embed can now render the chatbot as a full-height right rail that pushes your page content aside when it opens, instead of the corner bubble. Opt in with `displayMode: "sidebar"`; you can point it at the element to reflow, hide the corner launcher, and open it from your own button via a `data-wizchat-open` attribute or Ctrl/Cmd + /. The default bubble embed is unchanged. * **[Restrict an MCP server to specific embedding sites](/integrations/mcp/overview.md#restricting-a-server-to-specific-embedding-sites)** — When the same chatbot is embedded on more than one website, an individual MCP server can now be pinned to a list of allowed embedding domains, so its tools are exposed only on the sites you trust and hidden everywhere else. Servers with no list stay available everywhere (unchanged); once a list is set, requests from unknown hosts are fail-closed. ### 2026-08-09 **New Features** * **[Pick your speech language for voice input](/chatbots/voice-input.md#choosing-a-speech-language)** — The in-chat microphone's options popover now has a **Speech language** picker. The Web Speech API recognizes one language per session and cannot auto-detect, so choosing a language means speech in that language (for example Hebrew) is transcribed correctly instead of coming out as English gibberish. The choice is remembered per browser; it also passes a language hint to server transcription, but only when explicitly chosen, so the auto-detecting fallback is unchanged for visitors who never open the picker. **Improvements** * **Owner config changes apply to open chats automatically** — An already-open chat tab now picks up an owner's configuration changes the next time the visitor returns to that tab, without a manual page reload. The refresh is silent — it never flickers the microphone's loading state or replaces good config on a transient network error. **Bug Fixes** * **[Slow self-hosted models no longer time out mid-answer](/integrations/byoi.md#troubleshooting)** — A [BYOI](/integrations/byoi.md) query against a slow or cold-starting self-hosted model could fail after about two minutes — even while the model was still working — because the chat request hit its time limit. WizChat now allows a chat to run up to five minutes end-to-end and gives each call to your endpoint up to 90 seconds, so a slow or cold-starting model has time to respond. On very slow endpoints, WizChat also bounds how many reasoning steps a single answer takes, so the reply still comes back within the limit. ### 2026-08-08 **New Features** * **[Transcribe voice input through your own endpoint](/integrations/byoi.md#voice-input-speech-to-text)** — For chatbots using BYOI, when your endpoint configuration routes speech-to-text to one of your own endpoints, the in-chat microphone now transcribes through your model instead of the platform's default speech-to-text service. Audio is relayed to your endpoint server-side — it still transits WizChat but is only ever sent to your own model, never to the platform's speech-to-text provider. Transcription is fail-closed — it never silently falls back to the platform service. **Improvements** * **[Owner-configurable AI-action limits for MCP dialogs](/integrations/mcp/interactive-ui.md#security--limits)** — In-dialog `wizchat/llm` completions and model-backed tools are now bounded by a per-user, per-chatbot rate limit across three fixed windows (per minute / hour / day; defaults 10 / 60 / 300, `0` = unlimited) that owners can tune per chatbot, replacing the previous fixed 5-completions-per-dialog cap. Hitting a limit returns a clear `429` that names the limit and how long to wait. **Bug Fixes** * **MCP dialogs no longer dead-end at the action limit** — Reaching an MCP-UI dialog's action limit now returns a clear, recoverable error instead of breaking the dialog with an "Unknown UI resource" failure that forced a reopen. *** ## July 2026 ### 2026-07-30 **Improvements** * **Sharper source selection and citations** — The sources shown with an answer are now ranked and filtered by a keyword-free relevance ("meaning") score, so the most on-topic sources appear first and weak keyword-only matches no longer take up slots. Citations into multi-page PDFs open the page that best fits your question, preferring the start of the relevant section when two pages are a near tie. * **More relevant, less redundant sources** — Retrieval now blends keyword and semantic matching based on how a question reads and merges multiple chunks from the same document into a single source, so distinct sources surface instead of being crowded out by repeats of the same file. * **[Balanced Sources surfaces on-topic videos in the answer](/chatbots/ai-settings.md#balanced-sources)** — When Balanced Sources is enabled and a genuinely on-topic video is retrieved, the chatbot now reads that video and factors it into the answer, so a relevant video reaches both the answer and the displayed sources instead of being crowded out by higher-scoring text. No video is forced when none is on-topic. * **[Video sources deep-link to the right moment](/knowledge-base/uploading/videos.md#video-sources-in-responses)** — Video source cards now show the timestamp of the cited moment and open the video at that point when clicked, including for older transcripts that store times as `[MM:SS]`. * **[Clearer text-ingestion error responses](/management-api/guides/adding-content.md#errors)** — When every entry in a `POST /api/v1/chatbots/{chatbotId}/text` request fails, the `500` response now returns a structured `error` object (`code: "ingest_failed"` with a human-readable `message`) alongside the per-entry `documents[]` reasons, so failures are easier to diagnose programmatically. **Bug Fixes** * **No more theme flash on reload** — The chat page no longer briefly flashes the light theme before applying a saved dark preference when reloading. * **No more broken images in answers** — When an answer references an image that does not actually exist in the knowledge base, the chatbot now removes the broken image instead of showing a broken-image icon, keeping only the image's caption text. Images that do exist are unaffected, and a temporary storage hiccup never causes a valid image to be dropped. *** ### 2026-07-28 **Improvements** * **[Ingest YouTube videos by link](/integrations/youtube.md#ingest-youtube-videos-into-a-chatbot)** — `POST /api/v1/chatbots/{chatbotId}/youtube/videos` now accepts a `links` array (watch, `youtu.be`, embed, or shorts URLs, or bare 11-character IDs) alongside `videoIds`, so you can ingest a video even when it is not shown in the channel list. Provide `videoIds` and/or `links`; any link that cannot be parsed to a video ID is ignored and returned in the response's `invalidLinks` array. *** ### 2026-07-27 **New Features** * **[Restrict web search to specific domains](/chatbots/ai-settings.md#restrict-web-search-to-specific-domains)** — When web search is enabled, you can now provide an allowlist of up to 20 domains so the chatbot only pulls live results from sources you trust. Leaving it empty keeps web search unrestricted (the default). * **[Hide the default scope from the selector](/knowledge-base/scopes.md#the-default-scope)** — Chatbots with knowledge scopes can now hide the default (base-namespace) entry from the scope picker so end users only see your named scopes. Exposed on the Management API via `showDefaultScopeInSelector` on `GET`/`PATCH /api/v1/chatbots/{chatbotId}/scopes`. *** ### 2026-07-25 **New Features** * **[Add knowledge base content via the API](/management-api/guides/adding-content.md)** — A new `POST /api/v1/chatbots/{chatbotId}/text` endpoint adds text or Markdown straight to a chatbot's knowledge base with no file upload. Send a single `text` (with an optional `fileName`) or a batch of up to 50 `items` — for example curated question/answer pairs. Each entry becomes its own searchable, listable, deletable source; processing is synchronous and returns per-entry results (`207` on partial success). Supports `viewAccessLevel`, `authorizedEmails`/`authorizedGroups`, and `scopeId`. Requires the `documents:write` scope. *** ### 2026-07-19 **New Features** * **[Analytics API](/analytics/reports.md#analytics-via-the-management-api)** — Rich per-category analytics endpoints under `GET /api/v1/chatbots/{chatbotId}/analytics/*`: `queries`, `quality`, `conversations`, `search`, `tokens`, `infra`, and `transcription` (alongside the existing `usage` and `cost`). A new workspace-level `GET /api/v1/analytics/aggregate` returns a usage overview across all chatbots. All require the `analytics:read` scope. * **[Scheduled Crawls API](/knowledge-base/scheduled-crawling.md#managing-scheduled-crawls-via-the-management-api)** — Full CRUD for scheduled website crawls: `GET`/`POST /api/v1/chatbots/{chatbotId}/scheduled-crawls` and `GET`/`PATCH`/`DELETE .../{scheduleId}`. Knowledge-base infrastructure (region and index) is derived server-side. Requires `documents:read` / `documents:write`. **Improvements** * **Quality analytics `answerRate`** — Now returns `null` instead of `0` when a period has no classified conversations, so "no data yet" is distinguishable from a genuine zero. Label-analytics count denominators were also corrected. *** ### 2026-07-16 **New Features** * **[Knowledge Scopes API](/knowledge-base/scopes.md#managing-scopes-via-the-management-api)** — Per-scope endpoints `POST /api/v1/chatbots/{chatbotId}/scopes`, `GET`/`PATCH`/`DELETE .../scopes/{scopeId}`, complementing the existing list and bulk-update calls. Requires `chatbots:read` / `chatbots:write`. **Improvements** * **More reliable math** — Numeric questions now run through a dedicated `run_python` compute tool with LaTeX-rendered formulas, and pure-math queries are routed straight to it. This fixes cases where calculations were approximated or formatting was inconsistent. * **Steadier tool use** — When a connected MCP tool is called repeatedly with identical arguments, the chatbot now breaks the loop and routes to Code Mode instead of stalling. * **Faster, clearer response preparation** — Pre-agent setup steps now run concurrently and show descriptive progress (e.g. "Searching knowledge base"), so users can see what's happening during longer turns. *** ### 2026-07-14 **Bug Fixes** * Document uploads now self-heal by creating the storage bucket on demand if it is missing, preventing upload failures for newly deployed chatbots. *** ### 2026-07-13 **Improvements** * **Faster responses on strong-RAG turns** — The chatbot now skips the quality-evaluation step when the retrieval engine returns a strong, unambiguous match. This reduces response latency by up to 5–6 seconds on those turns with no change to answer quality. The improvement applies automatically to all chatbots with no configuration required; chatbot owners can override the behavior per deployment via the `EVALUATOR_SKIP_MODE` environment variable. *** ### 2026-07-12 **New Features** * **[Sales Agent — Single Lead Detail (PII)](/chatbots/sales-agent.md#viewing-a-single-lead-with-pii)** — New `GET /api/v1/chatbots/{chatbotId}/sales-agent/leads/{leadId}` endpoint returns full decrypted contact PII (name, email, phone, company, custom fields) plus coarse geo for one lead. Audit-logged. Requires `security:read` scope (owner/admin only). * **[Sales Agent — Leads CSV Export](/chatbots/sales-agent.md#exporting-leads-as-csv)** — New `GET /api/v1/chatbots/{chatbotId}/sales-agent/leads/export` endpoint exports up to 5,000 leads as a CSV with decrypted contact fields and a `pii_decrypt_status` column per row. Requires `security:read` scope (owner/admin only). * **[Sales Agent — GDPR DSAR Lead Erasure](/chatbots/sales-agent.md#gdpr-dsar-lead-erasure)** — New `POST /api/v1/chatbots/{chatbotId}/sales-agent/leads/{leadId}/dsar-erase` endpoint hard-erases a lead's PII while retaining the anonymous row for aggregate metrics. Idempotent; repeat erasure returns 409 with original `piiErasedAt` preserved. Requires `security:write` scope (owner/admin only). * **[Chatbot Users API](/chatbot-users/managing.md#via-the-management-api)** — Three new endpoints manage deployed end-users: `GET /api/v1/chatbots/{chatbotId}/users` lists all invited users; `POST` invites a new user by email (with optional display name and role); `DELETE ?userId=` revokes access. Requires `security:read` / `security:write` scope. * **[Chatbot Settings API](/chatbots/conversation-memory.md#via-the-management-api)** — New `PATCH /api/v1/chatbots/{chatbotId}/settings` endpoint updates runtime toggles (web search, unanswered-question tracking, long-term memory, memory strategy). Destructive changes (disabling memory or switching strategy) require `confirmDelete: true`. Requires `chatbots:write` scope. * **[Memory Data Deletion API](/chatbots/conversation-memory.md#via-the-management-api)** — New `DELETE /api/v1/chatbots/{chatbotId}/memory-data?scope=` permanently clears graph memory by scope (`long-term` or `short-term`). Requires `chatbots:write` scope. * **[Email Groups API](/knowledge-base/access-control.md#managing-email-groups-via-the-management-api)** — Full CRUD for owner-scoped email allow-list groups: `GET /api/v1/email-groups` (list, with optional `includeUsage`), `POST` (create), `GET /{groupId}` (fetch), `PUT /{groupId}` (full replace), `DELETE /{groupId}`. Requires `security:read` / `security:write` scope. *** ### 2026-07-11 **Improvements** * **ZDR final-answer routing** — Final answers are now routed through Zero Data Retention-compliant providers when ZDR mode is active, ensuring the complete response pipeline is ZDR-compliant end-to-end. * **Per-agent evaluator reasoning effort** — Each agent's evaluator call now uses the reasoning effort configured for that agent rather than a fixed default, giving chatbot owners finer control over quality vs. cost trade-offs per scope. **Bug Fixes** * Scope submenu now expands inline on narrow viewports instead of overlapping the parent menu (#445). * Scope menu no longer opens centered and jumps left on first render (#444). * `return_script` MCP servers now work correctly alongside `remote_http` MCP servers on the same chatbot — mixed-mode configurations no longer error (#446). *** ### 2026-07-09 **New Features** * **[Sales Agent API](/chatbots/sales-agent.md)** — New endpoints manage the Sales Agent via the Management API: `GET /PATCH /api/v1/chatbots/{chatbotId}/sales-agent` reads and updates the configuration (prompt overlay, model override, lead-capture fields, guardrail, trigger sensitivity); `GET /api/v1/chatbots/{chatbotId}/sales-agent/handoffs` lists lead-delivery channels; `PATCH /DELETE /api/v1/chatbots/{chatbotId}/sales-agent/handoffs/{handoffId}` updates or removes a channel. Requires `chatbots:read` / `chatbots:write` scope. * **[YouTube Management API](/integrations/youtube.md#management-api)** — Four new endpoints automate YouTube ingestion: `GET /api/v1/youtube/status` (connection status), `POST /api/v1/youtube/connect` (start OAuth flow), `GET /api/v1/youtube/videos` (list channel videos with pagination and title search), and `POST /api/v1/chatbots/{chatbotId}/youtube/videos` (ingest videos into the knowledge base). Requires `videos:read` / `videos:write` scope. * **[Transcript Corrections API](/knowledge-base/transcript-corrections.md)** — Three new endpoints expose the AI-generated transcript correction workflow: `GET /api/v1/chatbots/{chatbotId}/corrections` returns a chatbot-wide review queue; `GET /api/v1/videos/{videoId}/corrections` returns paginated corrections for one video (with context snippets); `PATCH /api/v1/videos/{videoId}/corrections` resolves a correction (accept candidate, reject, apply custom text, or undo — accepted or custom corrections trigger automatic re-embedding). Requires `documents:read` / `documents:write` scope. **Improvements** * Persistent pre-indexed MCP tool vectors — MCP tool embeddings are now computed and stored at index time, significantly reducing latency for tool discovery on large MCP servers. *** ### 2026-07-08 **New Features** * **[Delete a chatbot API](/management-api/reference/delete-chatbot.md)** — New `DELETE /api/v1/chatbots/{chatbotId}` endpoint permanently deletes a chatbot and cascades cleanup across the knowledge base, storage, deployment, and configuration. Requires the chatbot owner or a team owner/admin (`chatbots:write` scope). Returns 200 on full deletion, 207 Multi-Status if the chatbot was removed but some downstream cleanup failed, or 409 if a shared resource (e.g. a knowledge base used by another chatbot) blocks deletion. The error schema gains two new codes: `conflict` and `deletion_failed`. * **[Document Ingestion API](/management-api/reference/ingest-chatbot-document.md)** — New `POST /api/v1/chatbots/{chatbotId}/documents` endpoint ingests a PDF into the chatbot's knowledge base directly from a public URL. The PDF is fetched, extracted, chunked, and embedded asynchronously; poll `GET /documents` for status. Requires `documents:write` scope. SSRF-safe: http(s)-only, public-IP-pinned, size- and time-bounded. *** ### 2026-07-07 **New Features** * **[Website Crawl Management API](/management-api/reference/start-chatbot-crawl.md)** — Three new endpoints bring the dashboard website-crawl flow to the Management API: * `POST /api/v1/chatbots/{chatbotId}/crawls` — start a crawl for one URL or a batch of up to 100 URLs; the chatbot's knowledge base is updated with the crawled content as vectors. * `GET /api/v1/chatbots/{chatbotId}/crawls` — list crawls (most recent first) with live progress; non-terminal crawls are refreshed against the crawler on read. * `GET /api/v1/chatbots/{chatbotId}/crawls/drift` — compare the chatbot's crawled URL set against the domain's current `sitemap.xml` to surface pages added or removed since the last crawl. * **[Team Members API](/management-api/reference/list-team-members.md)** — New `GET /api/v1/team` endpoint lists the account owner's team members. *** ### 2026-07-06 **New Features** * **[Sales-agent leads API](/management-api/reference/list-chatbot-sales-agent-leads.md)** — `GET /api/v1/chatbots/{chatbotId}/sales-agent/leads` lists captured lead metadata (disposition, handoff status, country code, timestamps, and aggregates) without exposing PII. Requires `analytics:read` scope; owner/admin only. * **User session credential source** — Embedded chatbots can adopt an authenticated host-dashboard session via a custom token, enabling seamless single-sign-on for co-pilot integrations. * **New Chat button in embed widget** — Users can start a fresh conversation from within the embedded widget without refreshing the page. *** ### 2026-07-05 **Improvements** * **Per-MCP-server reasoning effort** — Each MCP server's model override now accepts a `reasoningEffort` field (`none` / `minimal` / `low` / `medium` / `high` / `default`) to set thinking intensity independently per server. * Wide markdown tables in the chat widget now scroll horizontally instead of collapsing. * `
` tags now render correctly inside markdown table cells. * `@provider` model pins fall back gracefully when the requested provider variant is unavailable. * MCP servers that return tool calls as plain text are handled without errors. *** ### 2026-07-01 **New Features** * **Tool approval policies** — Chatbot owners can configure per-tool approval policies for MCP servers. Each tool can require user confirmation before the AI acts. Users can grant persistent "Allow always" approval from within the dialog without leaving the chat. *** ## June 2026 ### 2026-06-30 **Improvements** * MCP tool results are now replayed to the model across conversation turns, ensuring consistent tool context in multi-turn sessions. * Code-mode agent no longer enters a loop when a change is already staged for the current step. * Graceful cancellation when a user denies a tool call mid-flow in code mode. *** ## March 2026 ### 2026-03-03 **New Features** * **[In-chat data analysis](/knowledge-base/uploading/data-analysis.md)** — End users can upload Excel and CSV files directly in the chat for instant analysis. Ask questions in natural language and get answers with interactive charts and tables. * **[Knowledge Scopes](/knowledge-base/scopes.md)** — Partition your knowledge base into named scopes with independent access control, behavior overrides, MCP server filtering, and budget caps (Business & Enterprise). * **[Per-plan data retention](/security/data-retention.md)** — Chat history, Q\&A logs, and in-chat file uploads are now retained based on your subscription plan, from 30 days (Free) to unlimited (Enterprise). * **Per-scope cost limits** — Set monthly or weekly budget caps on individual knowledge scopes to control spending. **Improvements** * Smarter sheet selection for multi-sheet Excel workbooks — the AI automatically picks the most relevant sheet based on your question. * Follow-up questions remember context (selected sheet, metrics) across the conversation, so you don't need to repeat details. * Automatic chart type selection based on question intent — trend questions get line charts, comparisons get bar charts. * Web search is automatically disabled when querying internal data (spreadsheets, databases) to avoid irrelevant external results. *** ## February 2026 ### 2026-02-25 **New Features** * **Image understanding in chat** — Upload images directly in the chat and ask questions about them. The AI analyzes your image and answers your question directly. * **Network visibility on user rows** — For open-access chatbots, each user row now shows a masked network badge, question count, and last-seen timestamp. **Improvements** * Faster responses to image questions — roughly 2x faster than before. * Analytics data is now always up to date when you open the page. *** ### 2026-02-23 **New Features** * Per-metric access control — restrict individual dashboard metrics to specific users or email groups * Web search toggle — enable or disable Perplexity web search per chatbot from the Settings tab * Domain-based access control — restrict chatbot access to specific email domains * PostgreSQL metrics dashboard — auto-detected metrics and custom metric charts for your databases * Multiple PostgreSQL schema support — select multiple schemas per connection **Improvements** * MCP servers can now be edited after creation (update credentials, endpoints, or settings in place) * PostgreSQL metrics panel supports multiple database connections with clear server labels * CHM upload hard cap increased from 250 MB to 350 MB * Video uploads now use signed URLs for improved security **Bug Fixes** * Fixed mixed-case PostgreSQL table names not being detected in the metric wizard * Fixed duplicate server names when multiple PostgreSQL databases share a host * Fixed video upload progress bar jumping backward during processing *** ## February 2024 ### 2024-02-01 **New Features** * Added Zero Data Retention (ZDR) mode for maximum privacy * Cerebras model routing for fast ZDR-compatible inference * Cost tracking across all AI usage **Improvements** * Improved document processing speed by 40% * Better error messages for failed uploads * Enhanced search relevance **Bug Fixes** * Fixed OAuth token refresh for Atlassian integration * Fixed team invitation emails not sending * Fixed analytics date range picker *** ## January 2024 ### 2024-01-15 **New Features** * Team billing with ownership transfer * Share request workflow for non-owners * Scheduled website crawling **Improvements** * Redesigned chatbot settings UI * Faster deployment times * Improved mobile responsiveness **Bug Fixes** * Fixed PDF processing for certain encrypted files * Fixed conversation history not loading * Fixed duplicate document upload detection ### 2024-01-01 **New Features** * MCP server support (Salesforce, Atlassian, PostgreSQL) * Custom MCP server integration * Document access control by email **Improvements** * New analytics dashboard * Improved embedding quality * Better handling of large documents *** ## December 2023 ### 2023-12-15 **New Features** * YouTube channel integration * Video transcription improvements * Bulk document upload **Improvements** * Faster knowledge base search * Improved chat UI * Better mobile experience **Bug Fixes** * Fixed team member permissions * Fixed export functionality * Fixed timezone issues in analytics ### 2023-12-01 **New Features** * Team collaboration features * Role-based access control * Chatbot sharing **Improvements** * Redesigned dashboard * Improved onboarding flow * Better documentation *** ## Earlier Releases For release notes prior to December 2023, please contact support. *** ## Upcoming We're working on: * Additional AI model options * Enhanced analytics * More MCP integrations * Improved embedding models Stay tuned for updates! *** ## Feedback Have suggestions for new features? We'd love to hear from you: * Email: * Feature requests: [feedback.wizchat.com](https://feedback.wizchat.com) --- # Access Modes Control who can access your chatbot and how. ## Access Mode Options | Mode | Description | Best For | | ------------- | ------------------------------- | ---------------- | | **Open** | Anyone can access | Public chatbots | | **Managed** | Only invited users | Private chatbots | | **Anonymous** | Track sessions without accounts | Semi-public | ## Open Access Anyone with the chatbot URL can use it. ### Enable Open Access 1. Go to **"Settings" > "Users"** 2. Set Access Mode to **"Open"** 3. Click **"Save"** ### Considerations * No user tracking (unless they optionally sign in) * No access control * Best for public-facing chatbots ## Managed Access Only invited users can access. ### Enable Managed Access 1. Go to **"Settings" > "Users"** 2. Set Access Mode to **"Managed"** 3. Click **"Save"** 4. [Invite users](/chatbot-users/inviting.md) ### Considerations * Full control over who accesses * User activity tracking * Requires user management ## Anonymous Access Users can chat without creating accounts, but sessions are tracked. ### Enable Anonymous Access 1. Go to **"Settings" > "Users"** 2. Set Access Mode to **"Anonymous"** 3. Click **"Save"** ### How It Works * Users get temporary session IDs * Sessions are tracked for analytics * No personal data collected * Sessions can expire/reset ### Session Cleanup Configure when anonymous sessions are removed: | Setting | Description | | -------------------- | ------------------------------ | | **After inactivity** | Remove after X days inactive | | **After time** | Remove after X days regardless | | **Manual** | Only remove manually | ## Domain-based Access Restrictions You can restrict chatbot access to users from specific email domains. This is useful for internal chatbots that should only be accessible to your organization. ### Configure Authorized Domains 1. Open your chatbot 2. Go to the **"Settings"** tab 3. Open **"Manage Access"** 4. Add one or more authorized domains (e.g., `acme.com`, `partner.org`) 5. Click **"Save"** When domain restrictions are active, only users whose email address matches an authorized domain can access the chatbot. Users from other domains will be denied access. note Domain restrictions work alongside other access modes. For example, you can use Managed access with domain restrictions to ensure only invited users from your organization can sign in. ## Combining Options You can combine modes: ### Open with Optional Sign-in * Access Mode: Open * Show sign-in option: Yes * Users can optionally create accounts ### Managed with Guests * Access Mode: Managed * Allow guests: Yes * Invited users sign in, others are guests ## Access Mode Comparison | Feature | Open | Managed | Anonymous | | ----------------------- | ------- | ------- | ------------- | | Account required | No | Yes | No | | User tracking | No | Yes | Session only | | Access control | No | Yes | No | | Document access control | No | Yes | No | | Analytics | Limited | Full | Session-based | ## Changing Access Mode warning Changing access mode may affect existing users. When switching modes: * **Open → Managed**: Existing users need invitations * **Managed → Open**: All users can access * **Any → Anonymous**: User accounts remain but aren't required ## Related * [Authentication Setup](/chatbot-users/authentication.md) * [Inviting Users](/chatbot-users/inviting.md) * [Document Access Control](/knowledge-base/access-control.md) --- # Access Protection Gate your chatbot behind a secret URL key so that only authorized users can access it — even before the login page. ## Overview Access Protection adds a layer **before** authentication. Without a valid key in the URL, visitors are completely blocked from seeing any part of the chatbot, including the login page. This is useful when you want to: * Share a chatbot only with specific partners or customers via a secret link * Embed a chatbot in your app and restrict access to your users * Prevent the general public from discovering or accessing the chatbot | Method | URL Parameter | Use Case | | ------------- | --------------- | ------------------------------------------------------------- | | **App Key** | `?appkey=` | Simple link protection — share with team, embed in wiki | | **JWT Token** | `?token=` | Expiring access links, backend-generated tokens with identity | info Access Protection works alongside [Authentication](/chatbot-users/authentication.md) and [SSO](/chatbot-users/sso.md). When both are enabled, the user first needs a valid key to get past the gate, then logs in normally. *** ## Setting Up Access Protection ### Step 1: Enable Access Protection 1. Open your chatbot in the WizChat dashboard 2. Go to the **Edit** page 3. Scroll to the **Access Protection** section (under Authentication) 4. Toggle the switch to **Active** ### Step 2: Create an App Key 1. In the Access Protection section, enter a **label** for your key (e.g., "Production", "Partner A") 2. Click **"+ Generate Key"** 3. Copy the generated key immediately warning The full key is only shown once. Store it securely — you won't be able to retrieve it later. 4. Click **"Save Access Protection Settings"** ### Step 3: Share the Protected URL Append the key to your chatbot URL: ``` https://your-chatbot.wizchat.app/?appkey=YOUR_KEY_HERE ``` Users visiting this URL will have access. Users visiting without the key will see an "Access Restricted" page. *** ## App Keys App keys are static secrets appended to the chatbot URL. They're the simplest way to restrict access. ### How It Works 1. You generate a key in the dashboard 2. The key is hashed (SHA-256) and stored — the original key is never saved 3. When a user visits with `?appkey=`, the server hashes the provided key and compares it against stored hashes 4. If the hash matches, access is granted and the key is removed from the URL bar 5. The validated session is stored in the browser tab (sessionStorage) so the user doesn't need to re-validate on every page ### Managing Keys You can have up to **10 active keys** per chatbot. This lets you issue different keys to different partners and revoke them individually. #### Generate a Key 1. Enter a descriptive label 2. Click **"+ Generate Key"** 3. Copy and store the key securely #### Import an Existing Key If you already have a key you'd like to use: 1. Check **"Import an existing key instead"** 2. Paste your key (minimum 16 characters) 3. Enter a label 4. Click **"+ Add Key"** #### Revoke a Key 1. Find the key in the **Active Keys** list 2. Click the trash icon 3. Confirm revocation in the dialog Revoked keys stop working immediately. Users with that key will be blocked on their next visit. *** ## JWT Token Support For more advanced scenarios, you can accept signed JWT tokens instead of static keys. This allows: * **Expiring links** — tokens that automatically stop working after a set time * **User identity** — extract an email address from the token for tracking * **Backend integration** — your server generates tokens for authenticated users ### Configure JWT 1. In the Access Protection section, enable **JWT Token Support** 2. Enter your **JWT signing secret** (used to verify token signatures) 3. Optionally set the **email claim** field (default: `email`) to extract user identity from the token 4. Click **"Save Access Protection Settings"** warning The JWT secret is encrypted and stored securely. It is only shown once when you enter it. ### Supported Algorithm Currently only **HS256** (HMAC-SHA256) is supported. ### Generating JWT Tokens Generate tokens from your backend using the secret you configured. The token should include: ``` { "exp": 1700000000, "email": "user@company.com" } ``` | Claim | Required | Description | | ------- | ----------- | ----------------------------------------------------------------- | | `exp` | Recommended | Expiration time (Unix timestamp). Expired tokens are rejected. | | `email` | Optional | User's email address. Extracted if the email claim is configured. | Example using Node.js: ``` const jwt = require('jsonwebtoken'); const token = jwt.sign( { email: 'user@company.com' }, 'YOUR_JWT_SECRET', { expiresIn: '24h' } ); const chatbotUrl = `https://your-chatbot.wizchat.app/?token=${token}`; ``` ### Using JWT Tokens Append the token to the chatbot URL: ``` https://your-chatbot.wizchat.app/?token=eyJhbGciOiJIUzI1NiIs... ``` *** ## Embedding with Access Protection When embedding a chatbot with access protection, include the key or token in the iframe URL: ``` ``` ### Docked sidebar mode By default the script embed shows the chatbot as a **corner bubble** that opens a floating panel. You can instead dock it as a **full-height right rail** that pushes your page content aside when it opens — a more integrated look for documentation sites and apps. Opt in with `displayMode: "sidebar"`: ``` ``` Options for sidebar mode: | Option | Default | Description | | -------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `displayMode` | `"bubble"` | Set to `"sidebar"` for the docked right rail. Any other value falls back to the bubble. | | `reflowTarget` | auto-detect | CSS selector of the element whose right margin is pushed to make room for the rail. When omitted, WizChat targets the Docusaurus root (`#__docusaurus`) if present, otherwise ``. | | `showLauncher` | `true` | Set to `false` to drop the corner launcher bubble and open the rail only from your own triggers (see below). | | `width` | `400` | Rail width in pixels. | **Opening the rail from your own UI.** Add the attribute `data-wizchat-open` to any element on your page (for example a navbar "Ask AI" button) and clicking it toggles the widget. In sidebar mode, visitors can also toggle it with **Ctrl/Cmd + /**. ``` ``` Mobile On narrow screens the sidebar falls back to a full-width overlay and does not reflow the page. ### Native (in-page) render mode By default the script embed renders the chat UI inside an **iframe**. You can instead render the chat panel **directly in your page** — inside a Shadow DOM, so it stays CSS-isolated from your site — by setting `renderMode: "native"`: ``` ``` In native mode the panel streams answers from the chatbot's public `/api/chat-stream` endpoint over Server-Sent Events — there is no iframe and no secret key in the browser (it calls the same CORS- and domain-gated public endpoint the widget already uses, gated by your allowed embedding domains). Model output is rendered through a small escape-first Markdown renderer that allows only a fixed subset — code, bold/italic, headings, lists, and `http(s)` links — so untrusted answer text can't inject HTML into your page. `renderMode` is independent of `displayMode`: use native rendering with the default `"bubble"` corner popup or with the `"sidebar"` docked rail. | Option | Default | Description | | ------------ | ---------- | ---------------------------------------------------------------------------------------------------------------------------- | | `renderMode` | `"iframe"` | Set to `"native"` to draw the chat panel in the host page (Shadow DOM, no iframe). Any other value falls back to the iframe. | note Native mode is additive — existing iframe embeds are unchanged unless you explicitly set `renderMode: "native"`. ## Custom Domains For Business and Enterprise plans: 1. Go to **"Settings" > "Domain"** 2. Click **"Add Custom Domain"** 3. Enter your domain (e.g., `chat.yourcompany.com`) 4. Add the provided DNS records to your domain 5. Click **"Verify"** ## Embedding a chatbot that requires login Only matters for login-gated chatbots If your chatbot is fully public (no login), the embed snippet above works on any site — skip this section. This applies when your chatbot **requires login**, or has features that unlock **after a user signs in** (for example an in-widget account assistant / copilot). A web browser treats an embedded chat bubble as a small window into *another* website (an iframe). For privacy, browsers **partition the login storage** of a site shown inside a *different* site — so when a user signs in **inside the widget**, the browser drops that login and the chatbot behaves as if logged out. Anonymous chat still works; only the **logged-in** experience breaks. ### The fix: serve the chatbot on a subdomain of the page that embeds it Put the chatbot on a **subdomain of the same site** you embed it on, using [Custom Domains](#custom-domains). Because the chatbot and the host page are then the *same site*, the browser no longer partitions the login — signing in inside the widget **persists**, and logged-in features work. | Page hosting the widget | Give the chatbot this domain | Same site? | In-widget login | | ----------------------- | ---------------------------- | ---------------------- | ---------------- | | `www.yourcompany.com` | `copilot.yourcompany.com` | ✅ yes | ✅ works | | `www.yourcompany.com` | `yourbot.wizchat.app` | ❌ no (different site) | ❌ won't persist | **Setup (≈3 steps):** 1. **Custom Domain** → add a subdomain of your site, e.g. `copilot.yourcompany.com` (add the CNAME at your DNS provider; WizChat issues the TLS certificate). 2. **Embed** on `yourcompany.com` using the standard snippet, pointed at that subdomain: ``` ``` 3. Open the page, sign in inside the widget — the login now sticks. > The chatbot, its knowledge base, and all settings are unchanged — only the domain it's served from. (Email/password sign-in needs no extra configuration; if you use Google/SSO sign-in, also add the subdomain to Firebase Auth's authorized domains and any identity-provider redirect allowlist you manage.) Embedding on a site that is NOT yours The same-site approach covers embedding a login-gated widget on **your own** site (on a subdomain of it). Embedding a *logged-in* widget on a **third party's** domain that can't share a subdomain with the chatbot isn't supported yet — contact if you need that (it's on the roadmap). ## Redeployment Redeploy when you make changes to: * Knowledge base content * AI settings * Appearance settings To redeploy: 1. Go to the chatbot **Edit** page 2. Save your changes — a redeployment banner will appear when needed 3. Click the **"Redeploy"** button on the banner and confirm note Some changes take effect immediately without redeployment. Check the specific setting's documentation. ## Deployment Status | Status | Description | | ---------------- | -------------------------------- | | **Not Deployed** | Chatbot has never been deployed | | **Deploying** | Deployment in progress | | **Deployed** | Live and accessible | | **Failed** | Deployment failed (check errors) | ## Troubleshooting ### Deployment Failed Common causes: * Missing required settings * Invalid custom domain configuration * Temporary service issue **Solution:** Check error messages and retry. ### Changes Not Appearing **Solution:** Clear browser cache or use incognito mode to test. ## Related * [Appearance & Branding](/chatbots/appearance.md) * [Managing Chatbots](/chatbots/managing.md) * [Troubleshooting](/troubleshooting/common-issues.md) --- # Managing Chatbots Learn how to manage your chatbots throughout their lifecycle. ## Viewing Your Chatbots From the dashboard, you'll see all your chatbots with: * Name and description * Status (Active, Paused, Archived) * Last updated date * Quick actions ## Editing a Chatbot 1. Click on the chatbot name to open it 2. Navigate to the settings you want to change 3. Make your changes 4. Click **"Save"** ## Pausing a Chatbot Temporarily disable access to your chatbot: 1. Open the chatbot 2. Click the status dropdown 3. Select **"Pause"** **What happens when paused:** * Users see a "currently unavailable" message * No queries are processed * Data and settings are preserved ## Resuming a Chatbot Reactivate a paused chatbot: 1. Open the chatbot 2. Click the status dropdown 3. Select **"Resume"** ## Archiving a Chatbot Archive chatbots you no longer need: 1. Open the chatbot 2. Go to **"Settings" > "General"** 3. Click **"Archive"** 4. Confirm the action **What happens when archived:** * Removed from active chatbot list * Not accessible to users * Data is preserved * Can be restored later ## Restoring an Archived Chatbot 1. Go to **"Chatbots" > "Archived"** 2. Find the chatbot 3. Click **"Restore"** ## Deleting a Chatbot Permanent Action Deleting a chatbot permanently removes all data, including documents, settings, and conversation history. This cannot be undone. To delete: 1. Open the chatbot 2. Go to **"Settings" > "General"** 3. Click **"Delete"** 4. Type the chatbot name to confirm 5. Click **"Delete Permanently"** ## Duplicating a Chatbot Create a copy of an existing chatbot: 1. Open the chatbot 2. Click the **"..."** menu 3. Select **"Duplicate"** 4. Enter a name for the copy 5. Click **"Create"** The duplicate includes: * All settings * Knowledge base content * AI configuration ## Bulk Actions Select multiple chatbots for bulk actions: 1. Check the boxes next to chatbot names 2. Choose an action from the bulk actions menu: * Pause selected * Archive selected * Export settings ## Related * [Creating a Chatbot](/chatbots/creating.md) * [Configuration](/chatbots/configuration.md) * [Teams & Sharing](/teams/sharing.md) --- # Audio and video in chat Alongside [image understanding](/chatbots/ai-settings.md#image-understanding), visitors can attach an **audio** or **video** file in the chat and ask about it. The chat composer's **+** (add) menu offers: * **Upload image** — ask about a picture (see [Image understanding](/chatbots/ai-settings.md#image-understanding)) * **Upload audio** — ask about a sound or voice recording * **Upload video** — ask about a video clip * **Attach file** — add a document to the conversation Audio and video pickers are mutually exclusive with each other on a single message — attach one media file per turn. ## Uploading audio Choose **Upload audio** from the **+** menu, pick a file, and ask your question. | | | | ---------------- | -------- | | **Formats** | MP3, WAV | | **Maximum size** | 25 MB | On the turn the audio is attached, the chatbot answers from the audio itself — the [knowledge base](/knowledge-base/overview.md) is not searched for that message. There are two ways the audio is understood, depending on the chatbot's setup: * **A model that listens to the audio directly.** If the chatbot uses [Bring Your Own Inference (BYOI)](/integrations/byoi.md) and its chat endpoint is **audio-capable**, the audio file is sent to that model, which listens to it and answers in one step. * **Transcribe, then answer.** Otherwise, the audio is transcribed to text and the chatbot answers from the transcript. Transcription uses your [speech-to-text endpoint](/integrations/byoi.md#voice-input-speech-to-text) when one is assigned, and WizChat's transcription service otherwise. Either way, a **transcript of the audio is captured and carried into the conversation**, so your follow-up questions run through the normal knowledge-base pipeline with the audio's content available as context. Data residency On chatbots configured for [zero data retention or EU residency](/security/data-retention.md), audio requires self-hosted (BYOI) speech-to-text **and** text endpoints. If those aren't configured, audio is unavailable on that chatbot and the message returns an error rather than falling back to the platform service. ## Uploading video Choose **Upload video** from the **+** menu, pick a file, and ask your question. | | | | ---------------- | -------------- | | **Formats** | MP4, WebM, MOV | | **Maximum size** | 100 MB | Video understanding is **BYOI-only**: it works only when the chatbot's [Bring Your Own Inference](/integrations/byoi.md) chat endpoint is a **self-hosted, video-capable** model. The uploaded video is made available to that endpoint, which watches it and answers your question; the knowledge base is not searched for that message. If the chatbot has no video-capable endpoint, the message returns: > Video understanding requires a self-hosted video-capable endpoint on this chatbot. Why BYOI-only? WizChat's platform models do not accept video input, so there is no platform fallback for video — a self-hosted video-capable endpoint is required. Audio, images, and text are unaffected. ## Where files are stored Uploaded audio and video files are stored in a **private, per-user** location and are never made public. The model reads a file through a **short-lived signed URL** (valid for about 15 minutes) that only grants access to that one file. For BYOI video, the signed URL is handed to your own endpoint, which fetches the video itself — WizChat streams the URL, not the video bytes. See [Data retention](/security/data-retention.md) for how uploaded media is retained and deleted. --- # Sales Agent The Sales Agent turns your chatbot into a lead-capture assistant. It detects when a conversation has sales intent, collects configurable lead fields from the user, and delivers captured leads through one or more delivery channels (email or webhook). ## Overview The Sales Agent has two independent controls: * **Configuration** — the prompt overlay, lead fields to collect, model override, guardrails, and trigger sensitivity. Configured via the dashboard or the Management API. * **Enablement** — whether the agent is live at runtime (`salesAgentEnabled`). Configuring the agent does not automatically enable it; enablement is a separate control. ## Configuring the Sales Agent ### Via the dashboard Open the chatbot dashboard, then go to **Agents → Sales Agent**. The Sales Agent detail view contains **Overview**, **Configure**, **Hand-offs**, **Leads**, and **Analytics** sections. Use the **Enable/Pause** control in the Sales Agent header to change the runtime `salesAgentEnabled` state. ### Via the Management API **Get current configuration** ``` GET /api/v1/chatbots/{chatbotId}/sales-agent ``` Required scope: `chatbots:read` Returns the public Sales Agent configuration plus `salesAgentEnabled` — whether the agent is live at runtime. When no Sales Agent configuration document exists yet, the response contains only the runtime enablement flag. **Update configuration** ``` PATCH /api/v1/chatbots/{chatbotId}/sales-agent ``` Required scope: `chatbots:write` Creates the Sales Agent document on first update (the response includes `created: true` when that happens). Only the fields you send are applied; omitted fields are unchanged. Common writable configuration fields include: | Field | Type | Description | | ---------------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | boolean | Enable or disable this Sales Agent configuration. This is not the runtime live/paused switch; runtime enablement is `salesAgentEnabled`. | | `promptOverlay` | string | Custom prompt text that overlays the base agent persona. | | `promptSlots` | object | Structured prompt fields such as persona, value propositions, qualifying questions, and forbidden topics. | | `promptEditorMode` | string | Prompt editor mode: `free-form` or `structured`. | | `modelOverride` | string \| null | Override the model in `model@provider` form, or `null` to clear. | | `componentModels` | object \| null | Per-component model overrides. | | `fieldsToCapture` | array | Lead fields the agent should collect from the user. | | `guardrailEnabled` | boolean | Enable the built-in sales guardrail rules. | | `guardrailRules` | array | Built-in guardrail rule IDs. | | `guardrailCustomRules` | array | Custom guardrail rules. | | `triggerCategories` | array | Sales-intent categories that can trigger the agent. | | `triggerCustomRules` | array | Custom trigger rules. | | `triggerExclusions` | array | Situations that should not trigger the Sales Agent. | | `triggerSensitivity` | string | How aggressively the agent triggers on sales intent. | | `scopeOverrides` | object | Per-knowledge-scope overrides for supported prompt, capture, guardrail, and trigger fields. | | `evalEnabled` | boolean | Enable Sales Agent quality-evaluation calls. | Use `PATCH /api/v1/chatbots/{chatbotId}/apply` to update chatbot-level runtime configuration such as `salesAgentEnabled` through the config-as-code surface. ## Lead Delivery Channels (Handoffs) Captured leads are delivered through *handoff channels*. Each channel sends lead data to a configured recipient via email (`smtp` or `resend`) or webhook. Creating channels requires the dashboard A channel can only be *created* from the dashboard — creating one is inseparable from storing its sending secret (email credentials or webhook HMAC). Once a channel exists, its routing and recipient settings can be managed via the API. ### Listing channels ``` GET /api/v1/chatbots/{chatbotId}/sales-agent/handoffs ``` Required scope: `chatbots:read` Returns all handoff channels. Each channel includes: * `channel` — delivery type: `smtp`, `resend`, or `webhook` * `routingMode` — how recipients are selected: `single`, `distribution`, `country`, or `scope` * `hasSecret` / `hasWebhookHmac` — whether a sending secret is configured (the secret itself is never returned) * `enabled` — whether the channel is active ### Updating a channel ``` PATCH /api/v1/chatbots/{chatbotId}/sales-agent/handoffs/{handoffId} ``` Required scope: `chatbots:write` Writable fields: | Field | Type | Description | | ------------------- | ------- | ---------------------------------------------------------------------------------------- | | `enabled` | boolean | Activate or deactivate the channel. Enabling requires a secret to already be configured. | | `routingMode` | string | `single` \| `distribution` \| `country` \| `scope` | | `routingConfig` | object | Routing-mode-specific recipient configuration. | | `verifiedSender` | string | Verified sender email address (email channels). | | `webhookUrl` | string | Webhook endpoint URL (webhook channels). | | `fieldsToInclude` | array | Which captured lead fields to include in the delivery payload. | | `templateVersionId` | string | Email template version to use. | ### Deleting a channel ``` DELETE /api/v1/chatbots/{chatbotId}/sales-agent/handoffs/{handoffId} ``` Required scope: `chatbots:write` Idempotent — deleting an unknown channel ID still returns success. ## Viewing Captured Leads ``` GET /api/v1/chatbots/{chatbotId}/sales-agent/leads ``` Required scope: `analytics:read` (owner/admin only) Returns captured lead metadata — disposition, handoff status, country code, timestamps, and aggregates — without exposing PII. See the [API reference](/management-api/reference/list-chatbot-sales-agent-leads.md) for the full response schema. ### Viewing a Single Lead (with PII) ``` GET /api/v1/chatbots/{chatbotId}/sales-agent/leads/{leadId} ``` Required scope: `security:read` (owner/admin only) Returns the same metadata as the list **plus** the decrypted contact PII (name, email, phone, company, any custom fields) and coarse geo detail (region, city, timezone). This path is audit-logged. A `decryptError` field is present if server-side decryption failed; the raw encrypted envelope and HMAC hashes are never returned. Returns 404 for a missing, soft-deleted, or unauthorized lead (IDOR-safe). ### Exporting Leads as CSV ``` GET /api/v1/chatbots/{chatbotId}/sales-agent/leads/export ``` Required scope: `security:read` (owner/admin only) Returns a CSV with decrypted contact fields (name, email, phone, company) and coarse geo columns. Each row includes a `pii_decrypt_status` column (`ok` / `failed` / `erased` / `none`). Cells are hardened against CSV injection. The export is capped at 5,000 rows — narrow the time window or filters if you receive a 413 response. ### GDPR DSAR Lead Erasure ``` POST /api/v1/chatbots/{chatbotId}/sales-agent/leads/{leadId}/dsar-erase ``` Required scope: `security:write` (owner/admin only) Hard-erases a single lead's PII: scrubs the encrypted contact fields, HMAC hashes, and PII-adjacent geo (IP, region, city, timezone) while retaining the anonymous row (disposition, `capturedAt`, country code) so aggregate metrics remain intact. Idempotent — repeating the request on an already-erased lead returns 409 and preserves the original `piiErasedAt` timestamp (GDPR Article 17 audit-trail integrity). ## Related * [Management API Reference — Get Sales Agent](/management-api/reference/get-sales-agent.md) * [Management API Reference — Update Sales Agent](/management-api/reference/update-sales-agent.md) * [Management API Reference — List Handoffs](/management-api/reference/list-sales-agent-handoffs.md) * [Management API Reference — Update Handoff](/management-api/reference/update-sales-agent-handoff.md) * [Management API Reference — Delete Handoff](/management-api/reference/delete-sales-agent-handoff.md) * [Management API Reference — List Leads](/management-api/reference/list-chatbot-sales-agent-leads.md) * [Management API Reference — Get Lead (with PII)](/management-api/reference/get-sales-agent-lead.md) * [Management API Reference — Export Leads CSV](/management-api/reference/export-sales-agent-leads.md) * [Management API Reference — DSAR Erase Lead](/management-api/reference/erase-sales-agent-lead.md) --- # Voice input Visitors can dictate a message instead of typing it. The chat composer has a **microphone** button; how it starts and stops recording depends on the **Hold to record** setting (see [Microphone options](#microphone-options)): * **Hold to record off (the default).** Click the microphone to start speaking. While recording, a panel shows a "Listening" status and a level waveform with two controls: a **✓** button to stop and insert the transcribed text, and a **✕** button to cancel and discard it. * **Hold to record on.** Press and hold the microphone while you speak; releasing it stops recording and inserts the transcribed text. Either way, the spoken words are transcribed into the message box. ## How transcription works Voice input uses one of two paths, depending on the visitor's browser: * **Browser speech recognition.** On browsers that support the Web Speech API (such as Chrome and Edge), the browser handles speech recognition itself and returns the text live as the visitor talks. Note this is not on-device transcription — these browsers stream the audio to their own speech backend (for example, Google's for Chrome), not to WizChat. * **Server transcription.** When the browser has no built-in speech recognition — or if the in-browser recognizer fails partway through a session — the recorded audio is sent to WizChat's transcription service and transcribed there. BYOI If the chatbot uses [Bring Your Own Inference (BYOI)](/integrations/byoi.md) and an endpoint is assigned the **Speech-to-text** role, server transcription is routed to *your* model instead of the platform service. See [Voice input (speech-to-text)](/integrations/byoi.md#voice-input-speech-to-text) for that owner-side setup and its fail-closed behavior. ## Microphone options Next to the microphone button is a **Microphone options** control that opens a small settings popover. It contains: * A live **input-level meter** so the visitor can confirm the mic is picking up sound. * A **microphone device** picker, for choosing which input device to use when more than one is available. * A **Speech language** picker (see below). * A **Hold to record** toggle, switching between push-to-talk (hold the button while speaking) and click-to-toggle recording. These choices are remembered in the visitor's browser, so they only need to be set once per browser. ## Choosing a speech language The Web Speech API recognizes **one language per session and cannot auto-detect** the spoken language — so if it is set to English, speech in another language (for example Hebrew) is transcribed as English gibberish. The **Speech language** picker in the microphone options lets the visitor choose the language they will speak. * **Default.** If a language has not been chosen yet, WizChat uses the browser's language — or its primary language, so a `he-IL` or `he` browser gets Hebrew — when it matches a supported option, and otherwise falls back to **English (US)**. * **Browser speech recognition.** The chosen language is used as the recognition language, so speech is transcribed in that language. * **Server transcription.** The chosen language is passed to the transcription service as a hint **only when it has been explicitly chosen**; otherwise the service is left to auto-detect the language, so nothing changes for visitors who never open the picker. The picker offers the following languages, listed alphabetically: Arabic, Chinese, Dutch, English (UK), English (US), French, German, Hebrew, Hindi, Italian, Japanese, Korean, Polish, Portuguese, Russian, Spanish, Turkish. note Which languages a browser can actually recognize with the Web Speech API varies by browser and platform. The list above is the set of languages WizChat offers in the picker. --- # Your First Chatbot This tutorial walks you through creating a fully functional chatbot from scratch. ## What You'll Build By the end of this tutorial, you'll have: * A chatbot with your own knowledge base * Custom AI settings tuned for your use case * A deployed chatbot accessible via URL **Estimated time:** 15 minutes ## Step 1: Sign Up and Log In 1. Go to [wizchat.com](https://wizchat.com) 2. Click **"Get Started"** or **"Sign Up"** 3. Create your account using email or Google 4. Verify your email if required ## Step 2: Create Your Chatbot 1. From the dashboard, click **"Create Chatbot"** 2. Enter a name (e.g., "Product Support Bot") 3. Optionally add a description 4. Click **"Create"** Naming your chatbot Choose a name that reflects its purpose. You can change it later in settings. ## Step 3: Add Your First Document 1. Click on your new chatbot to open it 2. Navigate to **"Knowledge Base"** 3. Click **"Upload Document"** 4. Select a PDF file from your computer 5. Wait for the upload and processing to complete The processing status will show: * **Uploading** - File is being uploaded * **Processing** - Content is being extracted and embedded * **Ready** - Document is searchable ## Step 4: Test the Chatbot 1. Click the **"Test"** button (usually in the top right) 2. The chat interface opens 3. Type a question about your document 4. Press Enter and wait for the response **Example questions to try:** * "What is this document about?" * "Summarize the main points" * Ask specific questions about content in your document ## Step 5: Configure AI Settings 1. Go to **"Settings" > "AI Settings"** 2. Adjust these key settings: | Setting | Recommendation | | ----------------- | -------------------------------------------------- | | **Model** | Start with the default (GPT-4o or Claude) | | **Temperature** | Lower (0.3) for factual, higher (0.7) for creative | | **System Prompt** | Add context about your chatbot's purpose | 3. Click **"Save"** ## Step 6: Customize Appearance 1. Go to **"Settings" > "Appearance"** 2. Upload your logo 3. Choose your brand colors 4. Customize the chat bubble style 5. Click **"Save"** ## Step 7: Deploy Your Chatbot 1. Go to **"Settings" > "Deployment"** 2. Click **"Deploy"** 3. Wait for deployment to complete 4. Copy your chatbot URL Your chatbot is now live! Share the URL with users. ## Next Steps Congratulations! You've created your first chatbot. Here's what to explore next: * **[Add more documents](/knowledge-base/overview.md)** - Expand your knowledge base * **[Crawl a website](/knowledge-base/website-crawling.md)** - Import web content * **[Invite team members](/teams/invitations.md)** - Collaborate with your team * **[Set up authentication](/chatbot-users/authentication.md)** - Control who can access * **[Connect integrations](/integrations/mcp/overview.md)** - Add external tools Need help? If you run into issues, check the [Troubleshooting](/troubleshooting/common-issues.md) section or contact support. --- # Key Concepts Before diving in, it helps to understand the core concepts that make WizChat work. ## Chatbots A **chatbot** is your AI assistant. Each chatbot has: * A unique name and identity * Its own knowledge base (documents) * Configuration settings (AI model, prompts, appearance) * A deployment URL for users to access You can create multiple chatbots for different purposes (support, sales, internal docs, etc.). ## Knowledge Base The **knowledge base** is the collection of information your chatbot uses to answer questions. It includes: * **Documents** - PDFs, Word files, spreadsheets, images * **Web content** - Pages crawled from websites * **Videos** - YouTube videos and uploaded video files (transcribed) When you upload content, WizChat processes it and creates **embeddings** - mathematical representations that allow the AI to find relevant information quickly. ## Embeddings **Embeddings** are how WizChat understands and searches your content. When a user asks a question: 1. The question is converted to an embedding 2. Similar content is found in your knowledge base 3. Relevant context is sent to the AI model 4. The AI generates an answer based on that context This process is called **Retrieval-Augmented Generation (RAG)**. ## Teams A **team** lets you collaborate with others. Team features include: * **Members** - People who can access shared chatbots * **Roles** - Owner, Admin, Member with different permissions * **Shared chatbots** - Chatbots accessible to all team members ## Chatbot Users **Chatbot users** are the people who interact with your deployed chatbot. You can: * Allow **open access** - Anyone with the link can chat * Require **authentication** - Users must log in * **Manage users** - Invite specific people, track sessions ## MCP Servers **MCP (Model Context Protocol) servers** extend your chatbot's capabilities by connecting to external tools: * Query databases (PostgreSQL) * Access business tools (Salesforce, Atlassian) * Perform calculations * And more ## Plans and Usage WizChat offers different **subscription plans** with varying limits on: * Number of chatbots * **AI budget** (cost-based, not query-based) * Storage space * Team seats * Features (custom domains, remove branding, etc.) ### How AI Budget Works WizChat uses cost-based billing. Your AI budget is consumed based on actual AI usage costs, not a fixed number of queries. This is fairer because complex queries cost more than simple ones. | Plan | AI Budget | | -------- | -------------------------- | | Free | $5 one-time (never resets) | | Starter | $20/month | | Pro | $50/month | | Pro+ | $100/month | | Business | $200/month | note The free plan budget is a one-time lifetime grant that does not renew. Paid plan budgets reset on your personal billing date each month (the date you subscribed, not the 1st of the month). Enterprise plans are contract-based. ## Summary | Concept | Description | | -------------- | ---------------------------------------------------- | | Chatbot | Your AI assistant with its own identity and settings | | Knowledge Base | Collection of documents your chatbot learns from | | Embeddings | How content is indexed for AI retrieval | | Team | Group of people collaborating on chatbots | | Chatbot Users | End users who interact with deployed chatbots | | MCP Servers | Integrations that extend chatbot capabilities | --- # Quick Start Guide Get your first AI chatbot up and running in just a few minutes. ## Prerequisites * A WizChat account ([Sign up here](https://wizchat.com/signup)) * A document to upload (PDF, Word, or text file) ## Step 1: Create a Chatbot 1. Log in to your WizChat dashboard 2. Click **"Create Chatbot"** 3. Enter a name for your chatbot 4. Click **"Create"** ## Step 2: Upload a Document 1. In your chatbot's dashboard, go to **"Knowledge Base"** 2. Click **"Upload Document"** 3. Select a PDF or document file 4. Wait for processing to complete ## Step 3: Test Your Chatbot 1. Click the **"Test"** button in the top right 2. Ask a question about your document 3. See the AI respond with information from your knowledge base ## Step 4: Deploy 1. Go to **"Settings" > "Deployment"** 2. Click **"Deploy"** to create your chatbot's public URL 3. Share the URL or embed on your website ## What's Next? * [Configure AI settings](/chatbots/ai-settings.md) - Adjust model, temperature, and prompts * [Customize appearance](/chatbots/appearance.md) - Add your branding * [Invite team members](/teams/invitations.md) - Collaborate with your team * [Add more documents](/knowledge-base/overview.md) - Expand your knowledge base tip Start with a small document to test, then add more content as you refine your chatbot. --- # AI Gateway BYOK (Bring Your Own Key) Use your own provider API keys through the Vercel AI Gateway for direct billing, zero markup, and full key control. ## Overview BYOK allows enterprise customers to use their own API keys for supported AI providers while still routing through the Vercel AI Gateway. This gives you: * **Zero markup** — Provider charges go directly to your account * **Direct billing** — You see exact usage on your provider dashboard * **Gateway benefits** — Keep routing, observability, and fallback capabilities * **Per-provider control** — Use your keys for some providers, system keys for others ## BYOK vs BYOI | Feature | BYOK | BYOI | | ----------------------------- | --------------------- | --------------------- | | **Routes through AI Gateway** | Yes | No | | **Uses your API keys** | Yes | Yes (custom endpoint) | | **Provider auto-detection** | Yes (from model name) | N/A | | **Gateway observability** | Full | None | | **Fallback routing** | Automatic | Manual | | **Setup complexity** | API key only | Full endpoint config | | **Best for** | Cost control | Custom infrastructure | Enterprise Feature BYOK is available exclusively on the Enterprise plan. ## Supported Providers | Provider | Slug | Credential | | -------------- | ------------ | ---------- | | **OpenAI** | `openai` | API key | | **Anthropic** | `anthropic` | API key | | **Google** | `google` | API key | | **Mistral** | `mistral` | API key | | **xAI (Grok)** | `xai` | API key | | **DeepSeek** | `deepseek` | API key | | **Perplexity** | `perplexity` | API key | | **Cohere** | `cohere` | API key | Complex credential providers (Vertex AI, AWS Bedrock) will be added in a future update. ## Setting Up BYOK ### Step 1: Create or Edit a Chatbot 1. Go to **Dashboard > Chatbots** 2. Click **"Create New Chatbot"** or edit an existing one 3. Navigate to the **Infrastructure** tab ### Step 2: Enable BYOK 1. Scroll down to the **"AI Gateway BYOK"** panel 2. Toggle **"Enable BYOK"** 3. For each provider you want to use your own key: * Enter your API key * Click **"Test Key"** to validate 4. Complete the chatbot setup ### Step 3: Verify After saving your keys: 1. Wait up to 5 minutes for the credential cache to refresh (no redeploy needed) 2. Send a test message to your chatbot 3. The gateway will automatically use your key for the active provider 4. Check your provider dashboard to confirm direct billing No Redeploy Required BYOK keys are fetched dynamically at runtime. You can add, change, or remove keys at any time from the edit page — changes take effect within 5 minutes without redeploying the chatbot. ## How It Works When a chat message is processed: 1. The system detects which AI provider the current model belongs to (e.g., `gpt-4o` → OpenAI) 2. If a BYOK key exists for that provider, it's passed to the AI Gateway as a per-request credential 3. The gateway authenticates with the provider using your key instead of the system key 4. If no BYOK key exists for the provider, the system falls back to default credentials ``` User Message → Chat Stream → AI Gateway → Provider (your API key) ↕ Observability / Routing ``` ## Security ### Credential Storage * All API keys are **encrypted at rest** in secure, isolated storage * Keys are never logged or exposed in responses * Access is limited to your account and your deployed chatbot ### Key Rotation To rotate a key: 1. Go to the chatbot's Infrastructure tab 2. Enter the new API key for the provider 3. Click **"Test Key"** to validate 4. Save — the new key takes effect within 5 minutes (cache TTL) ### Best Practices * Use API keys with minimal required permissions * Set spending limits on your provider accounts * Rotate keys regularly * Monitor usage on your provider dashboard ## FAQ ### What happens if my BYOK key fails? The AI Gateway will return an error. It does **not** fall back to system credentials — this ensures you maintain billing control. ### Does cost tracking still work? Yes. Usage is still recorded for observability. However, the cost may show as $0 in WizChat's cost tracking since the provider bills you directly. ### Can I use BYOK for some providers and system keys for others? Yes. BYOK is per-provider. If you only add an OpenAI key, Anthropic models will use system credentials. ### Can I use BYOK and BYOI together? No. BYOI takes priority — if BYOI is enabled, it bypasses the gateway entirely. BYOK only applies when using the standard AI Gateway path. ### How quickly do key changes take effect? Within 5 minutes (the credential cache TTL). ## Related * [BYOI (Bring Your Own Infrastructure)](/integrations/byoi.md) * [Plans & Pricing](/billing/plans.md) * [Data Residency](/security/data-residency.md) --- # BYOI (Bring Your Own Infrastructure) Connect your own infrastructure components for complete control over your chatbot's backend. ## Overview BYOI allows you to replace WizChat's default infrastructure with your own: * **Custom LLM** - Use your own OpenAI-compatible endpoint (or several, one per role) * **Custom Embeddings** - Use your own embedding service * **Custom Vector Store** - Use your own PostgreSQL with pgvector * **Custom FalkorDB** - Use your own graph database for GraphRAG * **Custom Conversations DB** - Use your own PostgreSQL for chat history ## Who Is This For? BYOI is ideal for: * **Enterprise customers** with data residency requirements * **Organizations** with existing AI infrastructure investments * **Teams** requiring specific model configurations * **Companies** with compliance needs requiring self-hosted components Paid Feature BYOI is available on Pro, Pro+, Business, and Enterprise plans. ## Supported Components ### Custom LLM Use any OpenAI-compatible API endpoint as your language model. You can register a single endpoint, or several and assign a different model to each role — see [Using more than one model](#using-more-than-one-model-endpoint-pool). **Compatible with:** * Azure OpenAI * AWS Bedrock (via proxy) * Google Vertex AI (via proxy) * Ollama * vLLM * LocalAI * Any OpenAI-compatible endpoint **Configuration:** | Field | Description | | ---------------- | -------------------------------------------------- | | **API Endpoint** | Base URL (e.g., `https://your-api.com/v1`) | | **API Key** | Authentication key | | **Model Name** | Model identifier (e.g., `gpt-4o`, `llama-3.1-70b`) | ### Custom Embeddings Use your own embedding service for document vectorization. **Compatible with:** * Azure OpenAI Embeddings * Cohere Embeddings * Voyage AI * Any OpenAI-compatible embedding endpoint **Configuration:** | Field | Description | | ---------------- | ------------------------------------------------ | | **API Endpoint** | Base URL for embeddings | | **API Key** | Authentication key | | **Model Name** | Embedding model (e.g., `text-embedding-3-large`) | | **Dimensions** | Vector dimensions (default: 3072) | ### Custom Vector Store Use your own PostgreSQL database with pgvector extension for document storage. **Requirements:** * PostgreSQL 14+ * pgvector extension installed * SSL connection supported **Configuration:** | Field | Description | | ------------ | ----------------------------- | | **Host** | Database host | | **Port** | Database port (default: 5432) | | **Database** | Database name | | **Username** | Database user | | **Password** | Database password | | **SSL Mode** | SSL connection mode | note WizChat will create required tables automatically on first use. ### Custom FalkorDB Use your own FalkorDB instance for GraphRAG capabilities. **Requirements:** * FalkorDB 4.0+ * Redis-compatible connection **Configuration:** | Field | Description | | ------------ | ------------------------------ | | **Host** | FalkorDB host | | **Port** | FalkorDB port (default: 6379) | | **Password** | Connection password (optional) | | **SSL** | Enable SSL connection | ### Custom Conversations Database Use your own PostgreSQL for storing chat conversations. **Requirements:** * PostgreSQL 14+ * SSL connection supported **Configuration:** | Field | Description | | ------------ | ----------------------------- | | **Host** | Database host | | **Port** | Database port (default: 5432) | | **Database** | Database name | | **Username** | Database user | | **Password** | Database password | | **SSL Mode** | SSL connection mode | ## Preparing Your Self-Hosted LLM Endpoint When you add a custom LLM, WizChat runs a one-time **capability probe** against your endpoint — it confirms the endpoint works and detects what it supports (tools/function calling, JSON mode, streaming, vision). The probe runs from **WizChat's servers**, not your browser, so your endpoint needs a few things set up correctly. ### Endpoint requirements * **Publicly reachable over HTTPS.** Because the probe connects from WizChat's cloud, `localhost`, private/internal IP ranges (`10.0.0.0/8`, `192.168.0.0/16`, `172.16.0.0/12`), link-local, and cloud-metadata addresses are **rejected for security**. Expose the endpoint behind a public HTTPS URL (reverse proxy, cloud load balancer, or a tunnel). * **Serve the OpenAI-compatible API under `/v1`.** Enter the base URL including `/v1` — e.g. `https://llm.example.com/v1`. If you omit it, WizChat may auto-append `/v1`. * **Expose `GET /v1/models`.** WizChat uses it to normalize the URL and to show your available model names if the one you entered isn't found. * **Use the exact model id** your server reports at `/v1/models` (e.g. `Qwen/Qwen2.5-7B-Instruct`), not a friendly alias. * **The probe can take up to \~2 minutes** on a cold or slow endpoint. That's expected — it isn't a hang. Using a tunnel (ngrok / Cloudflare Tunnel)? Keep the tunnel **running** while you set up and test. An offline tunnel returns an HTML error page, which the probe reports as "endpoint appears offline." ### What the probe detects (and how to enable each) Only a basic chat completion is **required** — if that works, your endpoint is accepted. Every other capability is detected, and if it's missing that feature simply falls back to WizChat's platform model, so your chatbot still works. | Capability | Used for | How to enable on your server | | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | | **Chat completion** (required) | All text generation | Serve `POST /v1/chat/completions` | | **Tools / function calling** | MCP tools, agent actions | Launch with a tool-call parser (see examples) | | **JSON mode** | Structured extraction, classifiers | Support `response_format: {"type":"json_object"}` / structured outputs | | **Streaming** | Live token-by-token replies | Support `stream: true` (SSE) | | **Vision** | Answering questions about images | Serve a vision model (VLM) that accepts image `data:` URLs | | **Audio input** | Listening to [uploaded audio](/chatbots/media-attachments.md#uploading-audio) directly (otherwise audio is transcribed) | Serve a chat model that accepts an `input_audio` content part | | **Video** | [Answering questions about uploaded video](/chatbots/media-attachments.md#uploading-video) (required — no platform fallback) | Serve a chat model that accepts a `video_url` content part | ### Server setup examples **vLLM** ``` vllm serve Qwen/Qwen2.5-7B-Instruct \ --enable-auto-tool-choice --tool-call-parser hermes # OpenAI-compatible API at http://:8000/v1 ``` **SGLang** ``` python -m sglang.launch_server --model-path Qwen/Qwen2.5-7B-Instruct \ --tool-call-parser qwen25 --host 0.0.0.0 # OpenAI-compatible API at http://:30000/v1 ``` **Ollama** ``` ollama serve # OpenAI-compatible API at http://:11434/v1 ollama pull llama3.1 # model name: "llama3.1" ``` For tools, use a tool-capable model; for vision, pull a vision model such as `llava`. **LocalAI** — start the server and use its `/v1` base URL; the model name is the configured model id. Tools & vision are model- and flag-dependent * **Tools:** most servers only emit tool calls when launched with the matching parser flag (vLLM `--enable-auto-tool-choice --tool-call-parser`, SGLang `--tool-call-parser`) **and** the model's tool chat template. Without it, WizChat detects no tool support and routes tool-using steps to the platform model. * **Vision:** requires a vision-language model (e.g. Qwen-VL, Llava). A text-only model will show vision as unsupported. ## Using more than one model (Endpoint Pool) You can register several endpoints and choose which one handles each part of a conversation — for example a fast model for the main answer, a stronger model for code, and an image-capable model for pictures. Open your chatbot's settings, find the **BYOI** panel, and use the **Endpoint Pool**: 1. **Add endpoint** — give it a name, its base URL (ending in `/v1`), the model name, and an API key if it needs one. WizChat runs the capability check (the **Test & Probe** button) and shows what the endpoint supports. 2. **Role routing** — point each role at one of your endpoints, or leave it on **Platform default** to keep using WizChat's managed model. | Role | Handles | | ------------------------ | --------------------------------------------------------------- | | **Chat answers** | The main answer your users see | | **Utility** | Rephrasing questions, summarizing, and sorting requests | | **Code generation** | Running code and database queries to build an answer | | **Quality evaluation** | Automatic answer-quality checks | | **Excel & CSV analysis** | Understanding the structure of uploaded spreadsheets | | **Vision** | Answering questions about images (needs an image-capable model) | | **Speech-to-text** | Transcribing microphone input (see below) | Anything left on **Platform default** keeps working with WizChat's model, so you can move one role at a time and test as you go. tip A role is only offered an endpoint that can actually serve it — for example **Vision** only appears for image-capable endpoints. If an endpoint can't do what a role needs, that role stays on the platform default. Changes take effect right away for new chats. A chat that's already open picks them up the next time you return to its tab. ### Voice input (speech-to-text) By default the microphone uses your browser's built-in speech recognition or WizChat's transcription. Assign the **Speech-to-text** role to one of your endpoints and the in-chat microphone transcribes through *your* model instead. Two kinds of endpoint work: * **A dedicated transcription model** — a Whisper-compatible endpoint that serves `POST /v1/audio/transcriptions`. * **A multimodal model that accepts audio** — a chat model that can listen to an audio clip and write down what it hears. You can set an optional **language** hint if your users speak a specific language. The recorded audio is relayed to your endpoint server-side — it still passes through WizChat's servers in transit, but it is only ever sent to your own model, never to the platform's speech-to-text provider. * **Fail-closed.** When a speech-to-text endpoint is configured, WizChat transcribes through it or returns an error; it never silently falls back to the platform service. * **Loading state.** The microphone button is disabled and shows a **"Preparing microphone…"** tooltip until the chatbot's configuration loads, then enables. If the configuration fails to load, the mic stays disabled (a fail-safe, so voice input can't bypass a configured endpoint) — reload the page to retry. ## Setting Up BYOI ### Step 1: Create a New Chatbot You can turn BYOI on while creating a chatbot, and manage it any time afterwards from the chatbot's settings: 1. Go to **Dashboard > Chatbots** 2. Create a new chatbot, or open an existing one and go to its settings 3. Find the **"BYOI (Bring Your Own Infrastructure)"** panel note Your first endpoint can be set up at creation. The full **Endpoint Pool** and **Role routing** (assigning models to each role, and adding more endpoints) are managed from an existing chatbot's settings — see [Using more than one model](#using-more-than-one-model-endpoint-pool) above. ### Step 2: Enable and Configure Components 1. Toggle **"Enable BYOI"** to expand the configuration panel 2. For each component you want to customize: * Toggle the component switch (LLM, Embeddings, Vector Store, etc.) * Fill in the required connection details * Click **"Test Connection"** to validate 3. Complete the rest of the chatbot creation form 4. Click **"Create Chatbot"** ### Step 3: Verify Configuration After creating the chatbot: 1. Check that all BYOI components show green checkmarks 2. Test the chatbot with a sample query 3. Verify data flows to your infrastructure correctly ## Environment Variables When deploying your chatbot, BYOI settings are injected as environment variables: **LLM:** ``` CUSTOM_LLM_ENDPOINT=https://your-api.com/v1 CUSTOM_LLM_API_KEY=*** CUSTOM_LLM_MODEL=gpt-4o ``` **Embeddings:** ``` CUSTOM_EMBEDDINGS_ENDPOINT=https://your-api.com/v1 CUSTOM_EMBEDDINGS_API_KEY=*** CUSTOM_EMBEDDINGS_MODEL=text-embedding-3-large CUSTOM_EMBEDDINGS_DIMENSIONS=3072 ``` **Vector Store:** ``` CUSTOM_PGVECTOR_HOST=your-db.com CUSTOM_PGVECTOR_PORT=5432 CUSTOM_PGVECTOR_DATABASE=vectors CUSTOM_PGVECTOR_USER=*** CUSTOM_PGVECTOR_PASSWORD=*** CUSTOM_PGVECTOR_SSL_MODE=require ``` **FalkorDB:** ``` CUSTOM_FALKORDB_HOST=your-falkor.com CUSTOM_FALKORDB_PORT=6379 CUSTOM_FALKORDB_PASSWORD=*** CUSTOM_FALKORDB_SSL=true ``` **Conversations:** ``` CUSTOM_CONVERSATIONS_HOST=your-db.com CUSTOM_CONVERSATIONS_PORT=5432 CUSTOM_CONVERSATIONS_DATABASE=conversations CUSTOM_CONVERSATIONS_USER=*** CUSTOM_CONVERSATIONS_PASSWORD=*** CUSTOM_CONVERSATIONS_SSL_MODE=require ``` ## Security ### Credential Storage * All credentials are **encrypted at rest** * Credentials are stored in secure, isolated storage * Access is limited to your account only * Credentials can be rotated at any time ### Network Security * Connections use **SSL/TLS** when available * API keys are never logged * Connection strings are not exposed in UI after saving ### Best Practices * Use dedicated service accounts with minimal permissions * Rotate credentials regularly * Enable SSL for all connections * Use network firewalls to restrict access * Monitor connection logs for anomalies warning Never use production database admin credentials. Create dedicated service accounts with only the required permissions. ## Validation & Testing ### Testing Connections Use the **"Test Connection"** button to verify: * Network connectivity * Authentication * Required permissions * SSL configuration ### Validation Checklist | Component | Validation | | ----------------- | -------------------------------- | | **LLM** | Test chat completion request | | **Embeddings** | Test vector generation | | **Vector Store** | Test insert and query operations | | **FalkorDB** | Test graph write and read | | **Conversations** | Test table creation and queries | ### Troubleshooting **Connection Timeout:** * Check firewall rules * Verify host is reachable * Confirm port is open **Authentication Failed:** * Verify API key or password * Check user permissions * Confirm account is active **SSL Error:** * Match SSL mode with server configuration * Verify certificate validity * Try different SSL modes **Capability probe failed (custom LLM):** * *"502 Bad Gateway" / "503 Service Unavailable" / "504 Gateway Timeout" (or an error page mentioning your proxy or web server)* — your endpoint's address is reachable, but the model server behind it isn't responding. This usually means the model server hasn't started yet, is still loading a large model, has crashed, or the proxy in front of it is pointing at the wrong place. Make sure your model server is running and that your proxy forwards requests to it, then run **Test & Probe** again. * *"not an OpenAI-compatible API" / 404* — the base URL is missing `/v1`, points at the wrong service, or (for a tunnel) the tunnel is offline. Confirm `GET /v1/models` returns JSON. * *"Model not found — Available: …"* — use one of the exact model ids listed (from your server's `/v1/models`). * *"private / loopback / link-local / cloud-metadata address refused"* — the endpoint isn't publicly reachable; expose it over a public HTTPS URL. * *Tools or vision show as unsupported* — add the tool-call parser launch flag, or use a vision model. See [Preparing Your Self-Hosted LLM Endpoint](#preparing-your-self-hosted-llm-endpoint). **A chat against a slow self-hosted model fails after \~2 minutes:** * A query can take a while on a slow or cold-starting self-hosted model, especially when the answer needs several reasoning steps. WizChat now allows a single chat to run up to **five minutes** end-to-end and gives each individual call to your endpoint up to **90 seconds**, so a slow or cold-starting model has time to respond instead of being cut off. * On very slow endpoints, WizChat also **bounds how many reasoning steps** a single answer takes, so the reply still comes back within the limit rather than looping until it times out. * If a query still doesn't finish in time, the model is likely far slower than expected — check that the endpoint isn't cold-starting on every request (keep the model loaded/warm), that it has enough GPU/CPU for the model size, and that a reverse proxy or tunnel in front of it isn't adding its own timeout. ## Migration ### Moving to BYOI 1. Set up your infrastructure components 2. Configure BYOI settings in WizChat 3. Test with a new chatbot first 4. Migrate existing chatbots gradually ### Moving from BYOI 1. Disable custom components 2. WizChat will use default infrastructure 3. Note: Data in custom infrastructure is not migrated ## Related * [Data Residency](/security/data-residency.md) * [Encryption](/security/encryption.md) * [PostgreSQL Integration](/integrations/postgresql.md) --- # External API Integrate WizChat chatbots into your applications using our REST API. ## Overview The External API allows you to: * Send messages to your chatbot * Retrieve responses programmatically * Integrate chatbot functionality into your apps * Build custom interfaces ## Getting API Keys 1. Go to **"Settings" > "API"** 2. Click **"Generate API Key"** 3. Copy and securely store the key 4. Note: Keys are shown only once ## Authentication All API requests require authentication: ``` curl -H "Authorization: Bearer YOUR_API_KEY" \ https://api.wizchat.com/v1/chatbots/YOUR_CHATBOT_ID/query ``` ## Base URL ``` https://api.wizchat.com/v1 ``` ## Sending a Message ### Request ``` POST /chatbots/{chatbotId}/query Content-Type: application/json Authorization: Bearer YOUR_API_KEY { "message": "What is your return policy?", "conversationId": "optional-conversation-id" } ``` ### Request Body Parameters | Field | Type | Required | Description | | ---------------- | ------ | -------- | --------------------------------------------------------------------------- | | `message` | string | Yes | The message to send to the chatbot | | `conversationId` | string | No | Session ID for conversation continuity | | `images` | array | No | Images for multimodal queries (max 5) | | `scope` | string | No | Knowledge scope ID to query a specific namespace (Business/Enterprise only) | ### Response ``` { "response": "Our return policy allows returns within 30 days of purchase...", "conversationId": "conv_abc123", "sources": [ { "documentId": "doc_xyz", "title": "Return Policy", "relevance": 0.95 } ] } ``` ## Conversation Management ### Continue a Conversation Include the `conversationId` from previous response: ``` { "message": "What if the item is damaged?", "conversationId": "conv_abc123" } ``` ### Start New Conversation Omit `conversationId` or pass `null`: ``` { "message": "Hello!", "conversationId": null } ``` ## Knowledge Scopes Business & Enterprise Only Knowledge scopes are available on **Business** and **Enterprise** plans. If your chatbot has Knowledge Scopes configured, you can target a specific scope by passing the `scope` parameter. Each scope queries its own dedicated namespace with optional behavior overrides (system prompt, persona, response length). ### Discovering Available Scopes Send a `GET` request to see which scopes are available: ``` GET /api/external/chat ``` The response includes an `availableScopes` array when scopes are configured: ``` { "name": "External Chat API", "version": "1.2.0", "enabled": true, "availableScopes": [ { "id": "product-a", "label": "Product A" }, { "id": "product-b", "label": "Product B" } ], "documentation": { ... } } ``` ### Querying a Scope Pass the scope ID in the request body: ``` { "message": "What features does Product A have?", "scope": "product-a" } ``` The response metadata will include the scope that was used: ``` { "success": true, "answer": "Product A includes...", "metadata": { "model": "gpt-4o", "responseTimeMs": 1234, "scope": "product-a" } } ``` ### Scope Errors | Error Code | HTTP Status | Description | | --------------------- | ----------- | ------------------------------------------------------ | | `SCOPE_NOT_AVAILABLE` | 403 | Scope requested but plan is not Business or Enterprise | | `INVALID_SCOPE` | 400 | Scope ID does not exist on this chatbot | ## Code Examples ### JavaScript/Node.js ``` const response = await fetch( 'https://api.wizchat.com/v1/chatbots/YOUR_CHATBOT_ID/query', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ message: 'What are your business hours?', }), } ); const data = await response.json(); console.log(data.response); ``` ### Python ``` import requests response = requests.post( 'https://api.wizchat.com/v1/chatbots/YOUR_CHATBOT_ID/query', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json', }, json={ 'message': 'What are your business hours?', }, ) data = response.json() print(data['response']) ``` ### cURL ``` curl -X POST https://api.wizchat.com/v1/chatbots/YOUR_CHATBOT_ID/query \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"message": "What are your business hours?"}' ``` ## Rate Limits | Plan | Requests/Minute | Requests/Day | | -------- | --------------- | ------------ | | Starter | 30 | 1,000 | | Pro | 60 | 10,000 | | Business | 120 | Unlimited | ### Rate Limit Headers ``` X-RateLimit-Limit: 60 X-RateLimit-Remaining: 58 X-RateLimit-Reset: 1640000000 ``` ## Error Handling ### Error Response Format ``` { "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Too many requests. Please try again later.", "retryAfter": 60 } } ``` ### Common Error Codes | Code | HTTP Status | Description | | --------------------- | ----------- | --------------------------------------------------- | | `UNAUTHORIZED` | 401 | Invalid or missing API key | | `FORBIDDEN` | 403 | API key doesn't have access | | `SCOPE_NOT_AVAILABLE` | 403 | Scope requested but plan is not Business/Enterprise | | `INVALID_SCOPE` | 400 | Scope ID does not exist on this chatbot | | `NOT_FOUND` | 404 | Chatbot not found | | `RATE_LIMIT_EXCEEDED` | 429 | Too many requests | | `INTERNAL_ERROR` | 500 | Server error | ## API Key Management ### Viewing Keys 1. Go to **"Settings" > "API"** 2. See all active keys 3. View usage statistics ### Revoking Keys 1. Go to **"Settings" > "API"** 2. Find the key 3. Click **"Revoke"** 4. Confirm revocation warning Revoked keys stop working immediately. ## Best Practices * Store API keys securely (environment variables) * Rotate keys periodically * Use separate keys for different environments * Implement proper error handling * Respect rate limits ## Related * [API Authentication](/api/authentication.md) * [API Reference](/api/chatbots.md) * [Error Codes](/api/errors.md) --- # Built-in MCP Servers WizChat includes several pre-configured MCP servers ready to use. ## Calculator Perform mathematical operations. ### Capabilities * Basic arithmetic * Scientific calculations * Unit conversions * Statistical functions ### Enable Calculator 1. Go to **"Settings" > "Integrations"** 2. Find **"Calculator"** 3. Toggle **"Enable"** 4. Click **"Save"** ### Example Queries * "What's 15% of 249?" * "Convert 100 kilometers to miles" * "Calculate compound interest on $10,000 at 5% for 3 years" ## Weather Get current weather and forecasts. ### Capabilities * Current conditions * Forecasts * Historical data * Multiple locations ### Enable Weather 1. Go to **"Settings" > "Integrations"** 2. Find **"Weather"** 3. Toggle **"Enable"** 4. Click **"Save"** ### Example Queries * "What's the weather in New York?" * "Will it rain in London tomorrow?" * "What's the temperature in Tokyo?" ## Salesforce Access Salesforce CRM data. ### Capabilities * Query accounts, contacts, opportunities * Search records * View recent activity ### Requirements * Salesforce account * OAuth authentication ### Enable Salesforce 1. Go to **"Settings" > "Integrations"** 2. Find **"Salesforce"** 3. Click **"Connect"** 4. Authenticate with Salesforce 5. Configure permissions See [OAuth Configuration](/integrations/mcp/oauth.md) for details. ### Example Queries * "Show me opportunities closing this month" * "Find contact information for Acme Corp" * "What's the status of deal #12345?" ## Atlassian (Jira & Confluence) Access Atlassian products. ### Capabilities **Jira:** * Search issues * View issue details * List projects **Confluence:** * Search pages * View page content * List spaces ### Requirements * Atlassian account * OAuth authentication ### Enable Atlassian 1. Go to **"Settings" > "Integrations"** 2. Find **"Atlassian"** 3. Click **"Connect"** 4. Authenticate with Atlassian 5. Select accessible sites ### Example Queries * "Show me my open Jira tickets" * "Find the onboarding documentation in Confluence" * "What's the status of PROJECT-123?" ## PostgreSQL (QueryWeaver) Query PostgreSQL databases using natural language. ### Capabilities * Natural language to SQL * Schema exploration * Safe query execution * Result formatting ### Requirements * PostgreSQL database * Connection credentials ### Enable PostgreSQL 1. Go to **"Settings" > "Integrations"** 2. Find **"PostgreSQL"** 3. Enter connection details: * Host * Port * Database name * Username/Password 4. Click **"Test Connection"** 5. Click **"Save"** ### Security * Read-only access recommended * Limited to SELECT queries by default * Connection string encrypted ### Example Queries * "How many customers signed up last month?" * "Show me the top 10 products by revenue" * "What's the average order value?" See [PostgreSQL Integration](/integrations/postgresql.md) for details. ## Server Availability by Plan | Server | Free | Starter | Pro | Business | | ---------- | ---- | ------- | --- | -------- | | Calculator | Yes | Yes | Yes | Yes | | Weather | No | Yes | Yes | Yes | | Salesforce | No | No | Yes | Yes | | Atlassian | No | No | Yes | Yes | | PostgreSQL | No | No | Yes | Yes | ## Related * [MCP Overview](/integrations/mcp/overview.md) * [Custom Servers](/integrations/mcp/custom.md) * [OAuth Configuration](/integrations/mcp/oauth.md) --- # Custom MCP Servers Add custom MCP servers to extend your chatbot with your own integrations. ## Server Types | Type | Description | Best For | | --------- | --------------------- | -------------- | | **HTTP** | REST API-based server | Cloud services | | **stdio** | Command-line based | Local tools | ## Adding an HTTP Server 1. Go to **"Settings" > "Integrations"** 2. Click **"Add Custom Server"** 3. Select **"HTTP"** 4. Enter server details: * Name * URL * Authentication (if required) 5. Click **"Test Connection"** 6. Click **"Save"** ### HTTP Server Configuration ``` { "name": "My Custom Server", "type": "http", "url": "https://your-server.example.com/mcp", "headers": { "Authorization": "Bearer your-api-key" } } ``` ## Adding a stdio Server 1. Go to **"Settings" > "Integrations"** 2. Click **"Add Custom Server"** 3. Select **"stdio"** 4. Enter server details: * Name * Command * Arguments 5. Click **"Test"** 6. Click **"Save"** ### stdio Server Configuration ``` { "name": "Local Tool", "type": "stdio", "command": "python", "args": ["-m", "my_mcp_server"] } ``` ## Tool Discovery After adding a server, WizChat discovers available tools: 1. Server is queried for capabilities 2. Tools are listed in the integration settings 3. You can enable/disable specific tools ## Configuring Tools For each discovered tool: 1. Click on the tool 2. Configure parameters 3. Set descriptions for the AI 4. Enable/disable as needed ## Server Requirements Your MCP server must: * Implement the MCP protocol * Respond to capability queries * Handle tool execution requests * Return properly formatted responses ### MCP Protocol Resources * [MCP Specification](https://modelcontextprotocol.io/) * [MCP SDK (TypeScript)](https://github.com/modelcontextprotocol/typescript-sdk) * [MCP SDK (Python)](https://github.com/modelcontextprotocol/python-sdk) ## Testing Custom Servers ### Test Connection 1. Click **"Test Connection"** 2. Verify server responds 3. Check tool discovery ### Test Tools 1. Use the chatbot test feature 2. Ask questions that trigger your tools 3. Verify correct responses ## Error Handling Common issues: | Error | Cause | Solution | | ----------------- | ------------------- | ------------------------ | | Connection failed | Server unreachable | Check URL and network | | Auth failed | Invalid credentials | Verify API key/token | | No tools found | Protocol issue | Check MCP implementation | | Tool error | Execution failed | Check server logs | ## Security Best Practices * Use HTTPS for HTTP servers * Rotate API keys regularly * Limit tool permissions * Monitor server access logs * Validate all inputs ## Example: Building a Custom Server ### Python Example ``` from mcp import Server, Tool server = Server("my-server") @server.tool("get_data") async def get_data(query: str) -> str: # Your logic here return f"Data for: {query}" if __name__ == "__main__": server.run() ``` ### TypeScript Example ``` import { Server, Tool } from '@modelcontextprotocol/sdk'; const server = new Server('my-server'); server.tool('get_data', async (query: string) => { // Your logic here return `Data for: ${query}`; }); server.run(); ``` ## Related * [MCP Overview](/integrations/mcp/overview.md) * [Built-in Servers](/integrations/mcp/built-in.md) * [OAuth Configuration](/integrations/mcp/oauth.md) --- # Interactive UI (MCP-UI) Most MCP tools answer with **text**. Some workflows are far nicer as a **form or dialog** — pick options from a dropdown, fill a few fields, click a button. **MCP-UI** lets a trusted MCP server return its own interactive UI, which WizChat renders **right inside the chat** (in a locked-down frame). When the user clicks a button, it runs a follow-up tool on that same server and the result updates the dialog in place — no page reload, no leaving the conversation. This is built on the open [MCP Apps](https://modelcontextprotocol.io) standard (the `ui://` resource extension). Who this is for **Chatbot owners** decide whether to turn this on for a server (one toggle, below). **Developers** building the MCP server author the actual dialog. If your server only returns text/data, you don't need any of this. ## Turning it on By default, WizChat **ignores** any UI a server tries to render — a server can only draw in your chat if you explicitly allow it. 1. Open **Chatbot → MCP Servers**, then **Add** or **Edit** the server. 2. Enable **"Allow this server to render UI in chat (MCP-UI)"**. 3. Save. Only enable this for servers you trust A server with this on can draw arbitrary interface inside your chatbot's conversation. Leave it **off** for any third-party or unvetted server. WizChat sandboxes the UI heavily (see below), but the toggle is your first line of defense — treat it like granting a capability. ## How it works The dialog is the server's own HTML, but it never runs with your chatbot's privileges — it lives in an isolated sandbox and can only ask WizChat to run that server's tools. ## Security model This feature is **fail-closed** and gated at several layers: * **Login required.** It only works on a chatbot that [requires login](/chatbot-users/authentication.md); every action runs as the signed-in user. * **Sandboxed frame.** The dialog runs with scripts only — no access to your chatbot's page, cookies, or storage, and a default-deny content policy (it can't call external services unless you allow-list them). * **Actions are re-checked server-side.** Every button click is re-verified by WizChat — your identity, your access to that server, and that the requested tool is one this dialog is actually allowed to run. The dialog can never reach a different server or a tool it wasn't given. * **No secrets in the browser.** The server's access key never leaves WizChat's backend. ## For developers: authoring the dialog A tool returns a **UI resource** in its result instead of plain text: * `uri`: `ui:///` * content type **`rawHtml`** — a self-contained HTML document (your own markup, styles, and scripts) with the `text/html;profile=mcp-app` mimeType. * **Buttons drive the workflow** by asking the host to run a follow-up tool, and the result is delivered back to your dialog (shown below). * Keep the dialog **self-contained**: because of the default-deny content policy, it can't fetch external scripts, fonts, or APIs unless those domains are allow-listed. Inline what you need (including the SDK script — see the gotcha). WizChat renders these with the MCP-UI client's **`AppRenderer`** — the host side of the open [**MCP Apps**](https://github.com/modelcontextprotocol/ext-apps) standard (SEP-1865). Communication with your dialog is **MCP-over-postMessage** (the "AppBridge"), *not* a bare `window.parent.postMessage`. Your dialog must be MCP-Apps-compliant — or it renders but stays inert This is the **#1 gotcha**. The host (`AppRenderer`) speaks the MCP Apps **AppBridge** protocol. A dialog that hand-rolls `window.parent.postMessage({type:'tool'})` / `ui-lifecycle-iframe-ready` **with no bridge** will *render* but never connect — buttons do nothing, no initial data arrives, any `wizchat/llm` call falls back to an offline stub. There are exactly **two supported ways** to make a dialog speak AppBridge: 1. **TypeScript servers — `@mcp-ui/server`'s [`createUIResource`](https://mcpui.dev)** *injects the MCP Apps adapter* into your HTML. With the adapter present, the `ui-lifecycle-iframe-ready` + `{type:'tool'}` postMessage code in the example below **just works** — the adapter translates it to AppBridge for you. **Build the resource with `createUIResource`** (don't hand-write the raw HTML and return it directly, or the adapter is missing). 2. **Any language (Python, Go, …) — the native [`@modelcontextprotocol/ext-apps`](https://github.com/modelcontextprotocol/ext-apps) `App` SDK**, inlined in your HTML. You call `app.connect()`, `app.callServerTool(...)`, and listen on `app.ontoolinput`/`ontoolresult`. See [Non-TypeScript servers](#non-typescript-servers-the-mcp-apps-app-sdk) below. This is the right path for FastMCP and other non-TS servers, which have no `@mcp-ui/server`. Use **`@modelcontextprotocol/ext-apps@^1.7.x`** — keep it compatible with `@mcp-ui/client` v7 (WizChat's host currently consumes `@modelcontextprotocol/ext-apps@^1.7.4`). ### A complete minimal dialog (TypeScript / `@mcp-ui/server` adapter path) **1. The server tool** returns the dialog as a UI resource. Build it with `@mcp-ui/server`'s `createUIResource` — that's what **injects the MCP Apps adapter** that makes the postMessage code in step 2 connect. (The resource *shape* below is the same in any language — it's what a Python `EmbeddedResource` serializes to — but a hand-built raw resource carries **no adapter**; non-TS servers use the [App SDK path](#non-typescript-servers-the-mcp-apps-app-sdk) instead.) ``` // tool result return { content: [ { type: 'resource', resource: { uri: 'ui://my-feature/dialog', mimeType: 'text/html;profile=mcp-app', text: DIALOG_HTML, // the self-contained HTML document below }, }, ], }; ``` **2. The dialog HTML** — a self-contained document. The postMessage code below is what the **`createUIResource` adapter** bridges to AppBridge; it does **not** work on its own without that adapter (or the App SDK path): ```


  

```

`result` here is the tool's **CallToolResult** (`{ content: [...] , structuredContent? }`) — read `result.content` / `result.structuredContent` depending on what your tool returns.

### Non-TypeScript servers: the MCP Apps App SDK

If your server isn't TypeScript (e.g. **Python / FastMCP**, Go, …), you can't use `@mcp-ui/server`'s `createUIResource`, so there's **no adapter** — the postMessage code above won't connect. Instead, speak AppBridge directly with the native **[`@modelcontextprotocol/ext-apps`](https://github.com/modelcontextprotocol/ext-apps) `App` SDK** (`^1.7.x`, matching the host). Because of the default-deny content policy, **bundle the SDK into your HTML at build time** — a runtime `import` (remote or relative) is blocked from a `ui://` page, which has no same-origin to fetch from, unless you allow-list a domain in the resource's CSP.

```



  
  


  

```

Same capabilities as the adapter path — `app.callServerTool` is the equivalent of `callTool`, and the `toolinput`/`toolresult` events replace `ui-lifecycle-iframe-render-data`. Use `app.callServerTool({ name: 'wizchat/llm', … })` for [in-dialog AI completions](#using-it-from-the-dialog) (below). Do **not** use `app.createSamplingMessage` for that — WizChat brokers completions through the reserved **tool name**, not MCP sampling.

## AI completions inside a dialog

A dialog can ask WizChat to run an **LLM completion on its behalf** — without going back through the chat agent. This is useful for in-dialog assistants: "rewrite this rule in plain English", "explain what these settings do", "turn this sentence into a config object". The completion runs on **your chatbot's configured model** (including any [per-server model override](/integrations/mcp/custom.md)) and the cost is tracked like any other WizChat usage. Your server needs **no API key of its own** — WizChat brokers the call, and completions are billed to the **chatbot owner's** WizChat usage (not the dialog user's).

Want a *specific* tool answered by a model (incl. images)?

`wizchat/llm` is the *dialog* calling a model with a prompt. If instead you want a **named tool** whose result is produced by a model you pick — including **image generation** — declare it in the tool's metadata. See [Model-backed tools](/integrations/mcp/model-backed-tools.md).

### Turning it on

This is a **second, separate** capability on top of MCP-UI:

1. Open **Chatbot → MCP Servers**, then **Edit** the server.
2. Make sure **"Allow this server to render UI in chat (MCP-UI)"** is on.
3. Enable **"Allow this server's dialogs to run LLM completions"**.
4. Save.

Requires UI rendering

The LLM toggle only takes effect when MCP-UI is also on for that server — a dialog has to exist before it can ask for a completion. Turning UI off automatically disables completions too.

### Using it from the dialog

Inside your dialog, call the reserved tool name **`wizchat/llm`** through the same channel you use for any tool — your adapter `callTool(...)` (TS path) or `app.callServerTool({ name: 'wizchat/llm', ... })` (App SDK path). WizChat intercepts that reserved name and runs the completion; it is **not** MCP sampling:

```
const result = await callTool('wizchat/llm', {
  prompt: 'Rewrite the following in plain English:\n' + someText,
  systemPrompt: 'You are a concise assistant.', // optional
  maxTokens: 400,                               // optional
});
// `result` is a CallToolResult, NOT a bare string — pull the text out of content[0].text:
const text = (result?.content || []).find((c) => c.type === 'text')?.text ?? '';
```

* **`prompt`** (required) — the user/content prompt.
* **`systemPrompt`** (optional) — a system instruction.
* **`maxTokens`** (optional) — clamped server-side to a safe ceiling (currently **2,000** tokens).
* The combined `prompt` + `systemPrompt` is capped at **\~100 KB** — oversize requests are rejected.

The call returns a **CallToolResult** (`{ content: [{ type: 'text', text }] }`) — read the completion from `content[0].text`, as above. There is **no streaming** — you get the full answer when it's done. The call has a **30-second timeout**: if the gateway hangs you'll get a failure result, not a partial one. Keep all prompt-building in the dialog, and **validate before you apply**: if the model returns a config object, run it through your own validation tool before committing it.

The model can be wrong

Treat completions as suggestions. Always show the result to the user and validate any structured output (e.g. with your server's existing validation tool) before saving or acting on it.

### Security & limits

* **Off by default.** A dialog can only run completions when the owner has enabled **`allowLlmCompletion`** for that server. Otherwise the call is rejected.
* **Re-gated per call.** Like every dialog action, each `wizchat/llm` call re-verifies the signed-in user, their access to that server, and the live owner toggle — server-side.
* **Rate-limited per user.** In-dialog `wizchat/llm` completions are bounded by a per-user, per-chatbot rate limit across three fixed windows — per **minute**, **hour**, and **day** (defaults **10 / 60 / 300**; a window set to `0` means unlimited). Owners can tune these limits per chatbot. When a window is exhausted the call returns a `429` that names the limit hit and roughly how long to wait; reopening the dialog does **not** reset the window. (This replaces the former fixed 5-completions-per-dialog cap.)
* **No prompt/output retention in telemetry.** WizChat records the call for cost/observability but **does not retain the prompt or completion text** in its tracing.
* **Gateway model only.** Completions run on the owner's configured/override model via the AI Gateway — a dialog can't pick its own model or pass its own credentials.

## Opening a dialog directly (deep-link)

Normally a dialog appears when a tool is called **in the chat**. A host that embeds the chatbot — e.g. a desktop add-in pointing a WebView at the chatbot URL — can instead open a dialog **directly**, with no chat turn and no agent, by loading:

```
https:///?app=
```

WizChat runs the auth gates, calls that UI tool, and renders its dialog **full-screen**. It's generic — any server with a UI-returning tool works via `?app=`; nothing is product-specific.

* **Tool arguments** ride as extra query params, e.g. `…/?app=my_tool&someId=42` → passed to the tool as `{ someId: '42' }` (these become the dialog's initial `toolinput`). All query values arrive as **strings** — coerce server-side if your tool schema expects numbers/booleans.
* **`&scope=[,]`** constrains the open to those scopes (the same per-scope allow-list the in-chat path applies).
* **Host-supplied arguments (data the URL can't carry).** A query string can't hold large or structured data. An embedding host can instead set a global **`window.__wizchatAppArgs`** (a plain object) — it's merged into the open arguments (host values win over query params), so data the host can only obtain natively (e.g. a desktop add-in reading the current file/document) reaches the tool and the dialog's initial `toolinput`. Set it **before the page loads** so it's present when the app mounts — in a WebView, inject it at document-creation (e.g. `AddScriptToExecuteOnDocumentCreatedAsync`), the same place you wrap `fetch` for the access key. It's still bounded by the open route's argument size cap; unset (a plain browser) → no effect. Use the same argument keys your dialog expects in its `toolinput` handler.

```
// host side (e.g. the add-in WebView), injected before the chatbot page runs:
window.__wizchatAppArgs = { my_data: nativelyReadValue };
// → reaches open_'s arguments → the guest's toolinput event
```

Key-gated servers: the host must inject the access key

The dialog's client calls (`/api/mcp-ui-open`, `/api/mcp-ui-action`, `/api/mcp-llm`) **don't** carry the server's [access key](/integrations/mcp/custom.md) — by design, the key never sits in page JS. If your server is key-gated, the **host** must attach the `X-Wizchat-Access-Key` header (the same key it already uses for chat). In a WebView, wrap `fetch` at document-creation to add the header on those routes. A plain browser link to a key-gated `?app=` open will get a **403**.

The deep-linked dialog is the **same** MCP-Apps dialog as in-chat — it must be MCP-Apps-compliant (adapter or App SDK) exactly as above.

## Requirements & limits

* The chatbot must **require login** (this won't activate on an open/anonymous chatbot).
* The server keeps its normal access controls (allow-list and/or [access key](/integrations/mcp/custom.md)); MCP-UI is an addition, not a replacement.
* One dialog can drive a bounded number of tool actions (a separate cap, independent of the per-user AI-action rate limit above) before it must be reopened. Reaching that cap now returns a clear, recoverable error instead of breaking the dialog with an "Unknown UI resource" failure.

## FAQ

### Is this standard MCP, or something WizChat-specific?

The UI itself is **standard** — it's the open [MCP Apps](https://github.com/modelcontextprotocol/ext-apps) extension (SEP-1865): `ui://` resources, `rawHtml`, and the **AppBridge** (MCP-over-postMessage) protocol, reached via `@mcp-ui/server`'s adapter or the `@modelcontextprotocol/ext-apps` App SDK. Any MCP-Apps-compliant server renders in WizChat with no WizChat-specific code. The one extension is the reserved tool name **`wizchat/llm`** for in-dialog completions — and that's opt-in and feature-detectable (see below).

### My dialog renders but stays "offline" — buttons do nothing, no data loads. Why?

It's **not MCP-Apps-compliant**, so it never connects to the host's AppBridge. The HTML loads fine, but with no adapter (and no App SDK) its `window.parent.postMessage` calls go nowhere: the host doesn't answer button clicks, no initial `toolinput`/render-data arrives, and `wizchat/llm` returns an offline stub. Fix it by building the resource with **`@mcp-ui/server`'s `createUIResource`** (TS — injects the adapter) or by using the **`@modelcontextprotocol/ext-apps` App SDK** (any language; see [above](#non-typescript-servers-the-mcp-apps-app-sdk)). Returning hand-written raw HTML with bare `postMessage` and neither of those is the most common cause.

### Do I have to add WizChat-specific code to my MCP server?

**No WizChat-specific code** — but your dialog does have to be **MCP-Apps-compliant** (built via `@mcp-ui/server`'s `createUIResource`, or using the `@modelcontextprotocol/ext-apps` App SDK). That's standard MCP Apps, not WizChat-specific. You only touch `wizchat/llm` if you *want* in-dialog AI completions — and even then it's a single reserved tool name on that same standard channel.

### Does using `wizchat/llm` lock my server to WizChat?

No. It's a plain tool name on the standard MCP-Apps channel. On a host that doesn't support it, the call rejects with an unknown-tool error — so you can **feature-detect**: try it, and fall back (hide the AI button, or call your own backend) if it errors. Your server stays a standard MCP server everywhere else.

### Do I need the `@mcp-ui/server` SDK?

It's **one of the two supported paths**, not a hard requirement — but you do need one of them. `@mcp-ui/server`'s `createUIResource` is the easiest for **TypeScript** servers because it injects the MCP-Apps adapter for you. Any other language uses the **`@modelcontextprotocol/ext-apps` App SDK** instead. What you **can't** do is hand-build a raw `ui://` resource with bare `postMessage` and neither of those — the right *shape* alone isn't enough; with no adapter and no App SDK it renders but [stays offline](#my-dialog-renders-but-stays-offline--buttons-do-nothing-no-data-loads-why). If your server only returns text/data, you need none of this.

### Why a reserved tool name instead of MCP "sampling"?

[MCP sampling](https://modelcontextprotocol.io) is the spec's native way for a server to ask the host's LLM for a completion. WizChat's MCP transport layer can't yet advertise the sampling capability to servers, so the reserved-tool approach is the supported path today. Native sampling is tracked as a future enhancement; the dialog-facing contract (`wizchat/llm`) is designed to stay stable regardless.

### Can the `wizchat/llm` AI call my other tools to gather the data it needs?

**No.** `wizchat/llm` is a **single completion, not an agent** — it has **no tool-calling ability**. It receives only the `prompt` (plus optional `systemPrompt`) you send and returns text. It **cannot** call any of your MCP tools on its own — even if your prompt instructs it to. There is no tool loop on this path; that's deliberate, because the feature runs the model **without** the chat agent.

So if the completion needs data that lives behind your other tools (a schema, a list of valid options, an example record), **your dialog must fetch it first and include it in the prompt.** The dialog is the orchestrator: call your own tools through the normal `callTool` channel, then embed their results in the `wizchat/llm` prompt.

```
// 1. Gather whatever context the model needs, using your own tools FIRST.
const context = await callTool('your_data_tool', { /* args */ });

// 2. Hand that data to the LLM in the prompt — it cannot fetch it itself.
const result = await callTool('wizchat/llm', {
  prompt: 'Relevant data:\n' + JSON.stringify(context) +
          '\n\n' + userInstruction,
});
```

If you need a model that **autonomously** decides which tools to call and chains them, that is the **main chat agent** — not an in-dialog completion. The in-dialog `wizchat/llm` is intentionally a one-shot "transform this text" call.

### Can a dialog read or write files on the user's machine?

Not by itself — the dialog runs in a locked-down sandbox with no filesystem access. If your product needs to persist to a local file (e.g. a desktop add-in that embeds the chat), the **host application** does the saving: your dialog returns the data, and your host's code writes it. WizChat never touches the local disk.

### How do I embed this in my own software (not just the chat widget)?

A few ways: render the WizChat **chat widget** inside your app and let dialogs appear there; open a dialog **directly** by pointing a WebView at [`…/?app=`](#opening-a-dialog-directly-deep-link) (no chat turn); or host the chat in a **WebView/embed** and handle host-side actions (like local file saves) yourself. Either way the MCP-Apps and `wizchat/llm` contracts are the same — your server doesn't change. (Key-gated server in a WebView? The host injects `X-Wizchat-Access-Key` — see the deep-link note above.)

## Related

* [Custom MCP servers](/integrations/mcp/custom.md)
* [Local execution (return-script)](/integrations/mcp/local-execution.md)
* [Chatbot user access](/chatbot-users/access-modes.md)


---

# Local Execution (Return-Script)

Most MCP tools execute **server-side** — WizChat calls your endpoint, your code runs, and the result comes back. **Local execution** (also called *return-script* mode) inverts that: WizChat never runs the tool. Instead it hands a **script** to a runtime on the user's machine, that runtime executes it locally, and WizChat synthesizes the final answer from the results.

Use this when the work *has* to happen on the user's device — driving locally-installed software (CAD/CAM automation via COM, desktop apps, hardware), touching the local filesystem, or anything that can't or shouldn't run in WizChat's cloud.

Who this is for

This page is for developers building their **own** MCP server + a local runtime to pair with it. The built-in servers and standard [custom servers](/integrations/mcp/custom.md) run server-side and need none of this.

## How it works: the two legs

A return-script turn is split into two round-trips ("legs") with your local runtime in the middle.



1. **Leg 1 (plan).** The model decides which of your tools to call and with what arguments. Instead of executing, WizChat fetches the matching **script body** from your server via MCP `resources/read`, then emits a `script_plan` event over the chat SSE stream and **stops** — no answer yet.
2. **Your runtime executes.** A program you build on the user's machine receives the `script_plan`, runs each step locally, and collects the output.
3. **Leg 2 (synthesize).** Your runtime POSTs the results back to the chat endpoint. WizChat runs a second LLM pass that turns the raw results into a natural-language answer and streams it to the user.

The two legs are billed and traced separately. Nothing in your script ever executes on WizChat infrastructure.

## What your MCP server must provide

Your server is a **normal MCP server** with two specific obligations:

1. **Tools** — declared the usual way. The model reads their schemas and picks one plus arguments. Tools intended for local execution should share a common name prefix (e.g. `solidcam_`) so the owner can target them with one config.
2. **Script bodies as MCP resources** — the actual code to run, exposed via `resources/read` and addressable by a URI. WizChat resolves a URI template (below) to a concrete URI like `myserver://recipes/session_launch`, calls `resources/read`, and expects:

```
{
  "contents": [
    { "uri": "myserver://recipes/session_launch", "mimeType": "text/vbs", "text": "" }
  ]
}
```

Only the first content item's `text` is used. If the read fails or returns no text, that step's `source` is `null` (the turn still proceeds — your runtime decides how to handle a missing body).

Tool vs. resource

The **tool** is the addressable action the LLM selects (`solidcam_session_launch`). The **resource** is the code that action maps to (`solidcam://recipes/session_launch`). One tool → one script resource, linked by the URI template.

## Owner configuration (`localScriptFormat`)

WizChat itself is server-agnostic — it hardcodes no URI schemes, languages, or invocation patterns. The chatbot owner wires your server up in the dashboard with two settings on the MCP server record:

* `executionMode: "return_script"` — switches the server into local-execution mode.
* `localScriptFormat` — tells WizChat how to map a tool to a fetchable resource, what language to label it, and what shell invocation (if any) to suggest.

### `localScriptFormat` fields

| Field                 | Required | Description                                                                                                                  |
| --------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `resourceUriTemplate` | ✅       | Template for the `resources/read` URI. Example: `myserver://recipes/{toolId}`                                                |
| `language`            | ✅       | Language label for the plan and code fences. Example: `vbscript`, `powershell`, `python`                                     |
| `filenameTemplate`    | ✅       | Suggested filename for the runtime to write. Example: `{toolId}.vbs`                                                         |
| `toolNamePrefix`      | —        | Only tools whose name starts with this are treated as local-execution tools. The prefix is also stripped to form `{toolId}`. |
| `invocationTemplate`  | —        | Shell command hint. Example: `cscript //nologo {filename} {args}`. Omit if your runtime knows how to run the file itself.    |
| `mimeType`            | —        | Expected MIME type. Falls back to whatever the `resources/read` response declares, then `text/plain`.                        |
| `argsFormat`          | —        | How the model's argument object is rendered into `{args}` (see below). Default `cscript-named-slash`.                        |

### Template placeholders

| Token        | Valid in                  | Expands to                                                      |
| ------------ | ------------------------- | --------------------------------------------------------------- |
| `{toolName}` | any template              | Full tool name, e.g. `solidcam_session_launch`                  |
| `{toolId}`   | any template              | Tool name with `toolNamePrefix` stripped, e.g. `session_launch` |
| `{filename}` | `invocationTemplate` only | The rendered `filenameTemplate`                                 |
| `{args}`     | `invocationTemplate` only | The arguments rendered per `argsFormat`                         |

Unknown tokens are left untouched.

### `argsFormat` options

| Value                             | Renders args as                              |
| --------------------------------- | -------------------------------------------- |
| `cscript-named-slash` *(default)* | `/key:value /key2:value2` (Windows cscript)  |
| `posix-double-dash`               | `--key value --key2 value2`                  |
| `posix-equals`                    | `--key=value --key2=value2`                  |
| `space-separated`                 | `value1 value2` (positional)                 |
| `env-vars`                        | `KEY=value KEY2=value2`                      |
| `json`                            | a single JSON-stringified blob               |
| `none`                            | empty (your script reads stdin / env itself) |

### Example

```
{
  "executionMode": "return_script",
  "localScriptFormat": {
    "toolNamePrefix": "solidcam_",
    "resourceUriTemplate": "solidcam://recipes/{toolId}",
    "language": "vbscript",
    "mimeType": "text/vbs",
    "filenameTemplate": "{toolId}.vbs",
    "invocationTemplate": "cscript //nologo {filename} {args}",
    "argsFormat": "cscript-named-slash"
  }
}
```

With this config, a `solidcam_session_launch` call resolves to resource `solidcam://recipes/session_launch`, suggests filename `session_launch.vbs`, and an invocation of `cscript //nologo session_launch.vbs /partPath:"C:\CAM Projects\bracket.prz"`. Argument values are quoted **only when they contain whitespace** — a value without spaces is passed unquoted (e.g. `/partPath:C:\bracket.prz`).

## The runtime contract

This is the program **you** build and ship to the user's machine (an embedded WebView host, a desktop add-in, a CLI bridge — your choice). It has three jobs.

### 1. Receive the `script_plan` event

Open the chat SSE stream as a normal client. When a turn targets your server, you receive a `script_plan` event instead of a streamed answer:

```
{
  "kind": "script_plan",
  "version": 1,
  "steps": [
    {
      "toolName": "solidcam_session_launch",
      "args": { "partPath": "C:\\CAM Projects\\bracket.prz" },
      "source": "",
      "language": "vbscript",
      "mimeType": "text/vbs",
      "sourceUri": "solidcam://recipes/session_launch",
      "filename": "session_launch.vbs",
      "invocation": "cscript //nologo session_launch.vbs /partPath:\"C:\\CAM Projects\\bracket.prz\""
    }
  ],
  "question": "",
  "ragContext": "",
  "sources": [ /* optional citation sources */ ],
  "responseLanguage": "en",
  "leg1TraceId": ""
}
```

Every per-step field **except `toolName` and `args` may be `null`**. If the format resolver can't fully resolve a tool — its name doesn't match `toolNamePrefix`, or `resources/read` returned no text — then `source`, `language`, `mimeType`, `sourceUri`, `filename`, and `invocation` each arrive as `null`. Handle them defensively rather than assuming they're present.

### 2. Execute each step locally

For each step: write `source` to `filename`, run it, and capture the result. Use `invocation` as a hint if present — but see the security note below for when it's **absent**.

### 3. POST results back

POST to the same chat endpoint with an `executionResults` array, **echoing the plan's context fields back unchanged** so Leg 2 can synthesize a grounded answer:

```
{
  "executionResults": [
    {
      "stepIndex": 0,
      "toolName": "solidcam_session_launch",
      "success": true,
      "data": { "openedPart": "C:\\CAM Projects\\bracket.prz", "operations": 12 },
      "durationMs": 1840
    }
  ],
  // echo these back from the script_plan you received:
  "question": "",
  "ragContext": "",
  "sources": [ /* as received */ ],
  "responseLanguage": "en",
  "leg1TraceId": "",
  "mcpModelContext": { /* as received, if present */ }
}
```

WizChat synthesizes the final answer from `executionResults` and streams it to the user.

`mcpModelContext` (optional)

When the chatbot owner sets a per-server **model override** on a local-execution MCP server, the `script_plan` carries an `mcpModelContext` object so the Leg-2 answer synthesis uses the same model. Echo it back **verbatim** if present — WizChat re-validates it against the chatbot's current configuration server-side (it never trusts the echoed model), so the field is observability/scoping only and is safe to forward unchanged. It is omitted entirely when no override applies; just leave it out then.

Send a fresh `harnessRunId`, never a resume token

If your client tracks a `harnessRunId` (or `resumeToken`) for stream resumption, mint a **fresh** `harnessRunId` for the Leg-2 POST and do **not** echo the Leg-1 one. The Leg-1 value targets a resume gate that would replay the deferred plan frame and **silently drop your `executionResults`** — the whole callback would no-op. (WizChat also suppresses the resume token when `executionResults` are present, as a safety net, but the contract is: fresh id, no resume token.)

#### `executionResults` entry fields

| Field        | Description                                        |
| ------------ | -------------------------------------------------- |
| `stepIndex`  | Index into the plan's `steps[]` this result is for |
| `toolName`   | The tool that ran                                  |
| `success`    | `true` / `false`                                   |
| `data`       | Free-form JSON — the tool's output on success      |
| `error`      | Error message string when `success` is `false`     |
| `durationMs` | Local wall-clock duration                          |

Forward unknown fields verbatim

Echo back **every** field you received in the `script_plan`, even ones you don't recognize — don't whitelist. WizChat adds fields over time (`leg1TraceId` links the two legs in tracing; more may follow). A runtime that drops unknown fields keeps working but silently loses those features. A runtime that forwards everything stays forward-compatible for free.

## Security

WizChat treats your tool arguments as untrusted and guards against shell-injection before suggesting an `invocation`:

* If **any** argument value contains a shell metacharacter (`& | ; < > $ \` " % ^`, control chars — plus `( ) '`for PowerShell/quoted templates), the`invocation`field is **omitted** from that step. The`source`, `filename`, `args`, and `sourceUri\` are still delivered.
* Your runtime must **not** naively string-concatenate args into a shell command. When `invocation` is absent, build the command yourself using a safe argument-passing API (argument arrays, parameterized calls) — never a single concatenated shell string.
* The arguments boundary is JSON-only. Pass values to your script as structured arguments or stdin, not by interpolating into a command line.

Treat a missing `invocation` as a signal that an argument needs careful handling, not as an error.

## Checklist

To make your MCP server work with WizChat local execution:

* 
  Declare your tools with a shared name prefix.
* 
  Expose each tool's script body as an MCP resource readable via `resources/read`, returning `{ contents: [{ text, mimeType }] }`.
* 
  Have the owner set `executionMode: "return_script"` + a `localScriptFormat` on the server in the dashboard.
* 
  Build a local runtime that: reads `script_plan` from the SSE stream → executes each step → POSTs `executionResults` back, echoing all plan fields.
* 
  Pass arguments safely; never shell-concatenate, especially when `invocation` is omitted.

## Related

* [MCP Overview](/integrations/mcp/overview.md)
* [Custom MCP Servers](/integrations/mcp/custom.md)
* [OAuth Configuration](/integrations/mcp/oauth.md)
* [MCP Specification](https://modelcontextprotocol.io/)


---

# Model-backed tools

Most MCP tools compute their own result and return it. A **model-backed tool** is different: you declare — **in the tool's MCP metadata** — which AI model should produce the result, and WizChat runs that model through the [Vercel AI Gateway](/integrations/ai-gateway-byok.md) when the tool is called. The tool returns the model's output (text, or a generated **image**) instead of dispatching to your server.

This generalizes the in-dialog [`wizchat/llm`](/integrations/mcp/interactive-ui.md#ai-completions-inside-a-dialog) completion: instead of the *dialog* calling a reserved tool with a prompt, **any tool** can be wired to a model server-side. You pick the model **per tool** — so one tool can be answered by `google/gemini-3.1-flash-image` while everything else uses your chatbot's default.

Who this is for

**Developers** building an MCP server declare the model in the tool's `_meta`. **Chatbot owners** flip one toggle to allow it (the same cost door as in-dialog completions). If your tool computes its own result, you don't need this.

## When to use it

* A tool whose job is **"transform this input with an LLM"** — summarize, rewrite, classify, extract — where you'd rather not run (or pay for, or key) a model on your server.
* A tool that **draws** — render a diagram, chart, or illustration from structured input — by declaring an **image** model.

If the tool needs to *call other tools* or reason over multiple steps, that's the **chat agent**, not a model-backed tool. A model-backed tool is a single, one-shot model call.

## The contract

Add a `wizchat` block to the tool's MCP **`_meta`**:

```
{
  "name": "summarize_record",
  "description": "Summarize the given record in two sentences.",
  "inputSchema": { /* … */ },
  "_meta": {
    "wizchat": {
      "model": "openai/gpt-4.1",   // exact Vercel AI Gateway model id
      "output": "text"              // "text" (default) or "image"
    }
  }
}
```

* **`model`** (required to make a tool model-backed) — the **exact** model id as written in the Vercel AI Gateway catalog, e.g. `openai/gpt-4.1`, `anthropic/claude-sonnet-4.6`, `google/gemini-3.1-flash-image`. (Look up the live id in the catalog — the examples here are illustrative.) The infrastructure-provider suffix is supported too: `alibaba/qwen3-max@bedrock`.
* **`output`** (optional, default `"text"`) — `"text"` runs a text model; `"image"` runs an image model.

WizChat **validates the model when you add or refresh the server**: the id must exist in the live gateway catalog and its type must match `output` (a `"text"` tool needs a language model; an `"image"` tool needs an image model). A mismatch is surfaced as a warning at add/refresh time, and an invalid id is rejected at call time with a clear, model-named error.

### How the prompt is built

A model-backed tool has no prompt field of its own — WizChat assembles one from the tool **call**:

* The tool's **`description`** is the standing instruction (used as the system prompt for text; prepended to the prompt for image, since image generation has no system role).
* The **input** is the call arguments: a string **`prompt`** argument if you pass one, otherwise the JSON-serialized arguments.

So a dialog calls it through the normal bridge and gets the model's output back:

```
// Text tool — returns the model's text as a standard CallToolResult.
const result = await callTool('summarize_record', { record: someObject });
const text = (result?.content || []).find((c) => c.type === 'text')?.text ?? '';
```

## Image output

Set `output: "image"` and declare an image model. The result is one or more MCP **image content blocks** (`{ type: 'image', data: , mimeType }`) — your dialog renders them however it likes (WizChat produces the image; displaying it is your dialog's job, same as any tool result).

```
{
  "name": "render_diagram",
  "description": "Render a clean schematic image from the supplied JSON spec.",
  "_meta": { "wizchat": { "model": "google/gemini-3.1-flash-image", "output": "image" } }
}
```

Image-generation parameters are passed **per call**, inside a single reserved argument named **`wizchatImageOptions`** (all optional, validated + clamped server-side). They live under their own key — never as top-level arguments — so they can't collide with your tool's own domain arguments (a `size` that means "diameter", an `n` that means a count, …). WizChat strips `wizchatImageOptions` before building the prompt, so it never leaks into the model input. (On a **`text`** tool the field is simply ignored — it's stripped from the prompt and otherwise unused.)

| `wizchatImageOptions` field | Meaning                                  | Notes                                                           |
| --------------------------- | ---------------------------------------- | --------------------------------------------------------------- |
| `size`                      | `"{width}x{height}"`, e.g. `"1024x1024"` | each side 64–4096; takes precedence over `aspectRatio`          |
| `aspectRatio`               | `"{w}:{h}"`, e.g. `"16:9"`               | used only when `size` is absent (some image models prefer this) |
| `n`                         | number of images                         | clamped to **1–4**                                              |
| `seed`                      | integer seed for reproducibility         | optional                                                        |

```
const result = await callTool('render_diagram', {
  prompt: 'a labeled flowchart of the steps',
  wizchatImageOptions: { size: '1024x1024' },
});
const image = (result?.content || []).find((c) => c.type === 'image');
// image.data is base64; image.mimeType is e.g. "image/png"
```

Response size

The total image payload is capped (a few MB) to stay under the platform's response limit. A single \~1024² image is fine; if you request several large images and exceed the cap, the call is rejected cleanly rather than truncated. Prefer `n: 1` and a modest `size` unless you need more.

## Turning it on

Model-backed tools spend the **chatbot owner's** gateway budget, so they sit behind the same master switch as in-dialog completions:

1. Open **Chatbot → MCP Servers**, then **Edit** the server.
2. Enable **"Allow this server's dialogs to run LLM completions"** (`allowLlmCompletion`).
3. Save.

Declaring `_meta.wizchat.model` is **necessary but not sufficient** — without the toggle, a model-backed tool is rejected (so a server can't quietly spend your tokens just by declaring a model).

## Limits & security

* **Owner-gated.** Runs only when the owner has enabled completions for that server; otherwise rejected.
* **Re-gated per call.** Like every dialog action, each call re-verifies the signed-in user, their access to the server, and the live owner toggle — server-side.
* **Bounded spend.** Model-backed tool runs count against the same per-user, per-chatbot AI-action rate limit as `wizchat/llm` completions — three fixed windows (per minute / hour / day; defaults **10 / 60 / 300**, `0` = unlimited, owner-tunable per chatbot). The tool input is capped at **\~100 KB**; text output at **2,000 tokens**; image payloads are size-capped.
* **No prompt/output retention.** WizChat records the call for **cost/observability** (gateway model + generation id) but does **not** retain the prompt, the completion text, or the image bytes in its tracing.
* **Gateway only, owner's account.** The model runs through the AI Gateway on the owner's account — the tool can't pass its own API key, and cost is tracked like any other WizChat usage.
* **30-second timeout.** A hung model call fails cleanly rather than hanging the dialog.

The model can be wrong

Treat a model-backed result as a suggestion. Show it to the user and **validate any structured output** (e.g. with your server's own validation tool) before saving or acting on it.

## Scope today

Model-backed tools run on the **MCP-UI dialog path** — i.e. when a tool is fired from a [server-rendered dialog](/integrations/mcp/interactive-ui.md). A tool the **chat agent** chooses to call mid-conversation still dispatches to your server normally.

## Related

* [Interactive UI (MCP-UI)](/integrations/mcp/interactive-ui.md) — render dialogs, and the in-dialog [`wizchat/llm`](/integrations/mcp/interactive-ui.md#ai-completions-inside-a-dialog) completion this builds on.
* [Custom MCP servers](/integrations/mcp/custom.md) — adding and configuring your own MCP servers.
* [AI Gateway & model ids](/integrations/ai-gateway-byok.md) — where the `model` strings come from.


---

# OAuth Configuration

Configure OAuth authentication for MCP servers that require user authorization.

## OAuth Overview

OAuth allows users to authorize your chatbot to access their data in external services without sharing passwords.

## Authentication Types

| Type            | Description           | Use Case             |
| --------------- | --------------------- | -------------------- |
| **User OAuth**  | Each user authorizes  | Personal data access |
| **Centralized** | Admin authorizes once | Shared data access   |
| **API Key**     | Single key            | Simple integrations  |

## User OAuth Flow

1. User interacts with chatbot
2. Chatbot needs external data
3. User is prompted to authorize
4. User logs into external service
5. Access is granted
6. Chatbot can access data



### Setting Up User OAuth

1. Go to **"Settings" > "Integrations"**

2. Select the integration

3. Choose **"User OAuth"**

4. Configure OAuth settings:

   

   * Client ID
   * Client Secret
   * Scopes

5. Click **"Save"**

### OAuth Credentials

You'll need from the service provider:

| Field             | Description           |
| ----------------- | --------------------- |
| **Client ID**     | Your app identifier   |
| **Client Secret** | Your app secret       |
| **Redirect URI**  | WizChat callback URL  |
| **Scopes**        | Permissions requested |

### Getting OAuth Credentials

**Salesforce:**

1. Create a Connected App in Salesforce Setup
2. Enable OAuth settings
3. Copy Client ID and Secret

**Atlassian:**

1. Create an app in Atlassian Developer Console
2. Configure OAuth 2.0
3. Copy credentials

**Google:**

1. Create project in Google Cloud Console
2. Enable required APIs
3. Create OAuth credentials

## Centralized Credentials

For shared access where all users see the same data:

1. Go to **"Settings" > "Integrations"**
2. Select the integration
3. Choose **"Centralized"**
4. Click **"Connect"**
5. Authorize with admin account
6. All chatbot users share this access



### When to Use Centralized

* Accessing shared company data
* When users don't have individual accounts
* For read-only data access

### Security Considerations

* Admin credentials access all data
* Users see admin's accessible data
* Use read-only scopes when possible

## Connecting from the chat

Some MCP servers (for example a Microsoft / SharePoint server) authorize **each visitor individually** rather than through a single admin connection. For these, the visitor connects directly from the chat widget's **MCP menu**:

1. The visitor opens the MCP menu in the chat and finds the server.
2. They click **Connect** and sign in to the provider in a popup window. If the browser blocks the popup, WizChat falls back to a full-page redirect and returns to the chat when authorization completes.
3. Once authorized, the server shows as **connected** and its tools become available in that conversation. The connection is tied to the visitor's own provider account, and the browser remembers it so they don't have to reconnect on every visit.
4. The visitor can **Disconnect** from the same menu at any time, which removes their stored authorization for that server.

Access to an OAuth MCP server can also be **restricted to specific users or groups**. When a server is limited to an allowed group, only members of that group see it in the MCP menu; everyone else never sees the server or its tools.

## Managing OAuth Tokens

### View Connected Accounts

1. Go to **"Settings" > "Integrations"**
2. Click on the integration
3. View connected accounts

### Revoke Access

1. Find the connected account
2. Click **"Revoke"**
3. Confirm revocation

### Token Refresh

Tokens are automatically refreshed when:

* Token expires
* New request is made
* Background refresh runs

## User Experience

### Authorization Prompt

Users see an authorization prompt when:

* First using an OAuth-protected feature
* Token has expired and can't refresh
* Permissions change

### Handling Denied Access

If a user denies authorization:

* Chatbot gracefully handles the denial
* Alternative responses are provided
* User can authorize later

## Troubleshooting

### Authorization Failed

* Verify OAuth credentials
* Check redirect URI configuration
* Ensure required scopes are correct

### Token Expired

* Refresh token should auto-refresh
* If not, user may need to re-authorize
* Check token lifetime settings

### Scope Issues

* Verify scopes match provider settings
* Some providers require exact scope strings
* Additional scopes may need approval

## Related

* [MCP Overview](/integrations/mcp/overview.md)
* [Built-in Servers](/integrations/mcp/built-in.md)
* [Security](/security/access-control.md)


---

# MCP Servers Overview

MCP (Model Context Protocol) servers extend your chatbot's capabilities by connecting to external tools and services.

## What is MCP?

MCP is a standard protocol that allows AI models to:

* Access external data sources
* Execute actions in other systems
* Retrieve real-time information
* Perform calculations and operations

## How It Works



1. User asks a question
2. Chatbot determines if external data is needed
3. If yes, calls the appropriate MCP server
4. Server retrieves/processes data
5. Response is generated with the data

## Available Integrations

### Built-in Servers

Pre-configured integrations ready to use:

| Server         | Description             |
| -------------- | ----------------------- |
| **Calculator** | Mathematical operations |
| **Weather**    | Current weather data    |
| **Salesforce** | CRM data access         |
| **Atlassian**  | Jira/Confluence access  |
| **PostgreSQL** | Database queries        |

See [Built-in Servers](/integrations/mcp/built-in.md) for details.

### Custom Servers

Add your own MCP servers:

* HTTP-based servers
* stdio-based servers
* Custom implementations

See [Custom Servers](/integrations/mcp/custom.md) for details.

## Enabling MCP Servers

1. Open your chatbot
2. Go to **"Settings" > "Integrations"**
3. Find the MCP server
4. Toggle **"Enable"**
5. Configure any required settings
6. Click **"Save"**



## Editing MCP Servers

You can update the configuration of any MCP server after it's been added:

1. Open your chatbot
2. Go to the **"MCP"** tab
3. Click the **edit icon** next to the server you want to change
4. Update connection details, name, or other settings
5. Click **"Save"**

This lets you update credentials, change endpoints, or adjust settings without removing and re-adding the server.

## Authentication

Some MCP servers require authentication:

| Type            | Description               |
| --------------- | ------------------------- |
| **OAuth**       | User authorizes access    |
| **API Key**     | Single key for all users  |
| **Centralized** | Admin credentials for all |

See [OAuth Configuration](/integrations/mcp/oauth.md) for details.

## Restricting a server to specific embedding sites

If the same chatbot is [embedded](/chatbots/deployment.md#embedding-on-your-website) on more than one website, you can restrict an individual MCP server to only the sites you trust. Pin the server to a list of **allowed embedding domains** and it is exposed only when the chatbot is embedded on one of those hosts — on any other page, the server and its tools are hidden.

* **Open by default.** A server with no allowed-domains list stays available everywhere, so existing servers are unaffected.
* **Fail-closed when set.** Once a list is configured, a request from an unknown or unverified host never matches, so the server is withheld rather than exposed by accident.

This lets a chatbot expose sensitive tools — for example a management copilot's actions — only on your trusted internal pages, while hiding them on a public site such as your documentation. Domain matching supports wildcards (for example `*.example.com`), matched against the host page's verified domain.

## Use Cases

### Customer Support

Connect to:

* CRM (Salesforce) for customer data
* Ticketing system for issue history
* Knowledge bases

### Internal Tools

Connect to:

* Databases for live data
* Project management (Jira, Confluence)
* Internal APIs

### Data Analysis

Connect to:

* PostgreSQL for database queries
* Calculator for computations
* External APIs for data

## Best Practices

* Only enable servers you need
* Configure appropriate access controls
* Test thoroughly before deploying
* Monitor usage and performance

## Security Considerations

* MCP servers can access external systems
* Review permissions carefully
* Use least-privilege access
* Audit integrations regularly

## Related

* [Built-in Servers](/integrations/mcp/built-in.md)
* [Custom Servers](/integrations/mcp/custom.md)
* [OAuth Configuration](/integrations/mcp/oauth.md)


---

# Tool Approval (HITL)

Some MCP tools *do* things — query a database, call an external API, trigger an action in another system. **Tool approval** (human-in-the-loop, or HITL) puts the user in control: before the AI runs such a tool, WizChat pauses and asks the user to approve it. Nothing happens until the user chooses.

## The approval prompt

When a tool needs approval, an in-chat dialog appears with the details of what's about to run:

* **Server** — which MCP server the tool belongs to
* **Tool** — the tool name being called
* **Show arguments** — a collapsible view of the exact arguments the AI wants to pass (toggle **Show arguments** / **Hide arguments**)

The dialog is titled **"Approve action?"** and explains, in plain language, that the action needs the user's OK before it runs — allow it to continue, or deny to cancel.

### The three choices

| Button           | What it does                                                                                                                                                   |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Deny**         | Cancels the tool call. The AI does not run it.                                                                                                                 |
| **Allow once**   | Runs the tool this one time. The user is asked again next time.                                                                                                |
| **Always allow** | Runs the tool and remembers the choice, so the user isn't asked again for this tool (see [How "Always allow" is remembered](#how-always-allow-is-remembered)). |



## How "Always allow" is remembered

**Always allow** persists **per tool** (not per server) — approving one tool doesn't approve the others on the same server.

The choice is saved to the signed-in user's own preferences, so it only sticks for **signed-in users**. For anonymous (not-signed-in) users, the **Always allow** button is hidden for MCP tools, because there's no signed-in account to attach the preference to — those users see only **Allow once** and **Deny**.

note

The preference is stored per user. It applies to that user's future conversations with the chatbot; it does not change the approval behavior for other users.

## Web search is conversation-scoped

The built-in **web search** tool uses the same dialog, but its approval works a little differently:

* The dialog is titled **"Allow web search?"** and notes that the search will look at public websites outside the chatbot's knowledge base.
* **Always allow** here applies **only to the current conversation** — the dialog states this explicitly. Starting a new conversation asks again.
* Because it's scoped to the conversation (not to a signed-in account), **Always allow** for web search is offered to everyone, including anonymous users.

## Skip the prompt with Auto-approve

Users who don't want to be asked every time can turn a tool's prompt off from the **MCP menu** (the plug icon in the chat).

Open the MCP menu, select the server, and each tool row has an **Auto** checkbox — *"Auto-approve: skip confirmation prompts when the agent calls this tool."* Tools with auto-approve on show an **AUTO** badge.

This is the same underlying preference as choosing **Always allow** in the dialog: it's **per tool**, saved to the signed-in user's preferences, and can be turned back off from the same checkbox at any time.



## Related

* [MCP Servers Overview](/integrations/mcp/overview.md)
* [Custom MCP Servers](/integrations/mcp/custom.md)
* [Interactive UI (MCP-UI)](/integrations/mcp/interactive-ui.md)


---

# PostgreSQL Integration (QueryWeaver)

Connect PostgreSQL databases and query them using natural language.

## Overview

QueryWeaver allows your chatbot to:

* Understand your database schema
* Convert questions to SQL queries
* Execute queries safely
* Format results for users

## How It Works

1. User asks a question in natural language
2. WizChat understands the database schema
3. AI generates appropriate SQL query
4. Query is executed safely
5. Results are formatted and presented

Example:

* User: "How many orders were placed last month?"
* SQL: `SELECT COUNT(*) FROM orders WHERE created_at >= '2024-01-01' AND created_at < '2024-02-01'`
* Response: "There were 1,247 orders placed last month."

## Connecting a Database

1. Go to **"Settings" > "Integrations"**

2. Click **"PostgreSQL"**

3. Enter connection details:

   

   * Host
   * Port (default: 5432)
   * Database name
   * Username
   * Password

4. Click **"Test Connection"**

5. Click **"Save"**



## Connection Options

| Option                 | Description                     |
| ---------------------- | ------------------------------- |
| **SSL Mode**           | Require, prefer, or disable SSL |
| **Connection Timeout** | Max connection wait time        |
| **Query Timeout**      | Max query execution time        |
| **Read Only**          | Restrict to SELECT queries      |

## Schema Scanning

After connecting, WizChat scans your schema:

1. Tables and columns are discovered
2. Data types are identified
3. Relationships are mapped
4. Descriptions can be added

### Multiple Schema Support

You can select one or more schemas per PostgreSQL connection. This is useful when your database organizes data across schemas (e.g., `public`, `sales`, `analytics`).

1. Go to your PostgreSQL MCP server settings
2. In the **"Schemas"** field, select the schemas you want to expose
3. Click **"Save"**
4. Re-scan to discover tables from all selected schemas

WizChat will automatically prefix table names with the schema name when multiple schemas are selected, so the AI can distinguish between them.

tip

If different schemas contain tables with the same name, WizChat handles this automatically — no manual disambiguation needed.

### Viewing Schema

1. Go to **"Integrations" > "PostgreSQL"**
2. Click **"Schema"**
3. Browse tables and columns



### Adding Descriptions

Help the AI understand your schema:

1. Click on a table or column
2. Add a description
3. Click **"Save"**

Example:

* Table `cust`: "Customer information table"
* Column `amt`: "Order amount in USD"

## Query Safety

### Read-Only Mode

By default, only SELECT queries are allowed:

* No INSERT, UPDATE, DELETE
* No schema changes
* Safe for production databases

### Query Review

Optionally review queries before execution:

1. Go to **"Settings" > "PostgreSQL"**
2. Enable **"Review Queries"**
3. Queries show SQL before running

### Row Limits

Prevent large result sets:

* Default: 100 rows
* Configurable per database
* Pagination for larger results

## Example Queries

| Natural Language              | Generated SQL                                                                |
| ----------------------------- | ---------------------------------------------------------------------------- |
| "Show me top 10 customers"    | `SELECT * FROM customers ORDER BY total_purchases DESC LIMIT 10`             |
| "What's our monthly revenue?" | `SELECT DATE_TRUNC('month', order_date), SUM(amount) FROM orders GROUP BY 1` |
| "Find orders over $1000"      | `SELECT * FROM orders WHERE amount > 1000`                                   |

## Metrics Dashboard

WizChat can automatically detect key metrics from your PostgreSQL data and display them in a visual dashboard.

### How It Works

* WizChat analyzes your schema and suggests metrics (counts, averages, totals)
* Metrics are displayed as charts and summary cards
* You can also define custom metrics with your own SQL

### Using Metrics

1. Open your chatbot
2. Go to the **"MCP"** tab
3. Select a PostgreSQL server
4. Click the **"Metrics"** tab
5. View auto-detected metrics or add your own

### Multiple Servers

If you have more than one PostgreSQL connection, each server gets its own metrics tab. Server names are shown clearly even when multiple databases share the same host.

### Custom Metrics

To add a custom metric:

1. Click **"Add Custom Metric"**
2. Enter a name and SQL query
3. Select the chart type
4. Click **"Save"**



### Metric Access Control

Metric visibility is controlled in **two layers**:

1. **Server access** — controls who can see the PostgreSQL integration at all
2. **Metric access** — additional filtering within the server's user group

Both layers must pass for a user to see a metric. If the server is restricted to specific users, only those users can see any metrics — even ones marked "Public." A public metric means "visible to all server users," not "visible to everyone."

#### Managing per-metric access

By default, all metrics are visible to every user who has access to the server. You can restrict individual metrics further so only specific users or groups can see them.

1. Go to the **"Metrics"** tab for your PostgreSQL server
2. Click the **globe icon** next to the metric you want to restrict
3. Choose **"Restricted"** and add authorized users or groups
4. Click **"Save Changes"**

| Icon         | Meaning                                |
| ------------ | -------------------------------------- |
| Globe (blue) | Visible to all server users            |
| Lock (amber) | Restricted to specific users or groups |

tip

You can use **Email Groups** to manage access for multiple users at once. Create groups in **Settings > Email Groups**, then add them to any metric.

info

When the server itself is restricted, the admin UI shows a purple banner reminding you that server-level access applies first. The "Public" option in the metric access dialog means "all server users" rather than "all chatbot users."

**How it works for end users:**

* Users who don't have server access won't see any metrics from that server
* Within an accessible server, users only see metrics they are authorized for
* Anonymous (unauthenticated) users only see public metrics on public servers
* No error messages or "access denied" notices are shown — restricted metrics are silently hidden

## Best Practices

### Database Setup

* Use a read-only database user
* Grant minimal required permissions
* Consider using a replica
* Set appropriate timeouts

### Schema Optimization

* Add descriptions to tables/columns
* Use clear naming conventions
* Document relationships
* Exclude sensitive tables

### Performance

* Add indexes for common queries
* Set appropriate row limits
* Monitor query performance
* Use query timeouts

## Security

* Credentials are encrypted
* Connections use SSL when available
* Queries are parameterized
* Access can be revoked anytime

warning

Never connect databases containing sensitive data (passwords, PII) without proper security review.

## Troubleshooting

### Connection Failed

* Verify host and port
* Check firewall rules
* Confirm credentials
* Test SSL settings

### Queries Not Working

* Check schema descriptions
* Verify table permissions
* Review generated SQL
* Add more context to questions

### Slow Queries

* Add appropriate indexes
* Reduce row limits
* Check database performance
* Optimize complex queries

## Related

* [MCP Overview](/integrations/mcp/overview.md)
* [Built-in Servers](/integrations/mcp/built-in.md)
* [Security](/security/encryption.md)


---

# YouTube Integration

Connect YouTube to import video content into your knowledge base.

## Overview

The YouTube integration allows you to:

* Add individual YouTube videos
* Import entire channels
* Import playlists
* Automatic transcription

## Connecting YouTube

1. Go to **"Integrations" > "YouTube"**
2. Click **"Connect YouTube"**
3. Sign in with your Google account
4. Grant WizChat access to YouTube
5. Click **"Allow"**



A YouTube connection belongs to the **individual** who connected it — your Google login is never shared with anyone else.

## Sharing a Connected Channel With Your Team

You don't share your Google credentials to let teammates pull videos from your channel. Instead, you **link the channel to a chatbot** and then **grant per-member access**, so chosen members can browse and load videos under your connection.

1. As the chatbot's **owner or an admin**, open the chatbot's **Add Content → YouTube** screen and browse your channel once. This first browse **links the channel to that chatbot** — it now uses your connection.
2. Open the chatbot's **Manage Access** dialog → select the member → tick **"YouTube channel access"** → **Save**. (See [Sharing Chatbots → YouTube Channel Access](/teams/sharing.md#youtube-channel-access).)
3. The granted member can now browse and load that channel's videos from the chatbot's **Add Content → YouTube** screen, under your connection.

Keep in mind:

* **Off by default for regular members** — owners, per-chatbot Admins, and team owners/admins can already browse a linked channel; everyone else needs the explicit grant. The toggle stays disabled until a channel is linked.
* **Loading still requires document-upload permission** (see [who can upload](/teams/sharing.md#access-levels)). Browse access alone lets a member view the channel; loading also needs upload permission.
* **Private videos** are hidden from granted members unless you enable **"Let granted members see private videos"** on the chatbot. You (the member who connected the channel) always see its private videos.
* A video a member loads is **attributed to that member**, but it is fetched and transcribed under your connection.

## Adding Videos

### From Connected Account

1. Go to **"Knowledge Base"**
2. Click **"Add Content" > "YouTube"**
3. Browse your videos
4. Select videos to import
5. Click **"Import"**



## Importing Channels

Import all videos from a channel:

1. Go to **"Knowledge Base"**

2. Click **"Add Content" > "YouTube Channel"**

3. Enter the channel URL or search

4. Select the channel

5. Choose import options:

   

   * All videos
   * Recent videos only
   * Specific playlists

6. Click **"Import"**

## Importing Playlists

1. Go to **"Knowledge Base"**
2. Click **"Add Content" > "YouTube Playlist"**
3. Enter the playlist URL
4. Click **"Import"**

## Processing

When you add a video:

1. **Fetch** - Video metadata is retrieved
2. **Transcribe** - Audio is transcribed to text
3. **Process** - Text is chunked and embedded
4. **Ready** - Content is searchable

### Processing Time

| Video Length  | Estimated Time |
| ------------- | -------------- |
| < 10 minutes  | 1-2 minutes    |
| 10-30 minutes | 2-5 minutes    |
| 30-60 minutes | 5-10 minutes   |
| > 60 minutes  | 10+ minutes    |

## Automatic Updates

Keep channel content synced:

1. Go to **"Integrations" > "YouTube"**
2. Click on a connected channel
3. Enable **"Auto-sync"**
4. Set frequency (daily, weekly)
5. Click **"Save"**

## Viewing Transcripts

1. Go to **"Knowledge Base"**
2. Find the video document
3. Click to view
4. See full transcript

You can edit transcripts to fix errors.

## Limits and Constraints

YouTube imports are subject to:

* Your plan's storage limits
* Provider/API rate limits
* Processing timeouts for very long videos

For direct video file uploads, see [Subscription Plans](/billing/plans.md#file-upload-size-limits).

## Troubleshooting

### Video Not Processing

* Check if video is public
* Very long videos may hit processing timeouts
* Ensure video has audio

### Poor Transcription

* Original audio quality affects results
* Non-English may have lower accuracy
* Edit transcript manually if needed

### OAuth Issues

* Reconnect YouTube if tokens expire
* Check Google account permissions
* Verify API access in Google Console

## Management API

The YouTube integration is accessible via the Management API. Connection and video-list endpoints are account-scoped: they operate on the authenticated caller's YouTube connection. Ingesting videos into a chatbot additionally requires edit/upload access to that chatbot.

### Check connection status

```
GET /api/v1/youtube/status
```

Required scope: `videos:read`

Returns `{ connected: boolean, channelTitle?: string }`. Account-scoped (not per-chatbot).

### Start the YouTube OAuth flow

```
POST /api/v1/youtube/connect
```

Required scope: `videos:write`

Returns an `authorizeUrl` to redirect the user to in order to grant YouTube access. The connection is completed by the browser callback. Account-scoped.

### List your YouTube videos

```
GET /api/v1/youtube/videos
```

Required scope: `videos:read`

Lists videos from the caller's connected YouTube channel. Supports pagination (`nextPageToken`) and title search (`search` query parameter). Returns `connected: false` as a data field (not an error) when no channel is connected.

Response fields vary by mode:

* Normal pagination: `connected`, `videos`, `nextPageToken`, `totalResults`
* Title search (`?search=`): `connected`, `videos`, `search`, `totalScanned`, `totalResults`, `truncated`

Both modes may include `message` when the connected account has no YouTube channel or another non-error condition needs to be shown to the user.

Each video includes: `id` (YouTube video ID), `title`, `publishedAt`, `thumbnail`.

### Ingest YouTube videos into a chatbot

```
POST /api/v1/chatbots/{chatbotId}/youtube/videos
```

Required scope: `videos:write`

Ingests videos into the chatbot's knowledge base. Videos already in the knowledge base are skipped (returned in `skippedAlreadyImported`). Returns a `jobId` to track the async ingest.

Request body:

| Field      | Type      | Description                                                                                                                                                                    |
| ---------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `videoIds` | string\[] | YouTube video IDs to ingest. Optional when `links` is provided.                                                                                                                |
| `links`    | string\[] | YouTube video links (watch, `youtu.be`, embed, or shorts URLs) or bare 11-character IDs, parsed to video IDs. Useful for adding a video that is not shown in the channel list. |
| `scopeId`  | string    | Optional knowledge scope to attach the videos to.                                                                                                                              |
| `isPublic` | boolean   | Whether the ingested videos are public. Defaults to `false`.                                                                                                                   |

Provide at least one video via `videoIds` and/or `links` — you can mix both. Any link that cannot be parsed to a valid video ID is ignored and returned in the response's `invalidLinks` array.

See the full [API reference](/management-api/reference/ingest-you-tube-videos.md) for details.

## Related

* [Uploading Videos](/knowledge-base/uploading/videos.md)
* [Knowledge Base Overview](/knowledge-base/overview.md)
* [Management API Reference — YouTube Status](/management-api/reference/get-you-tube-status.md)
* [Management API Reference — Connect YouTube](/management-api/reference/connect-you-tube.md)
* [Management API Reference — List YouTube Videos](/management-api/reference/list-you-tube-videos.md)
* [Management API Reference — Ingest YouTube Videos](/management-api/reference/ingest-you-tube-videos.md)


---

# Document Access Control

Control which users can access specific documents in your knowledge base.

## Overview

Document access control lets you:

* Restrict documents to specific users
* Create email-based access lists
* Set documents as public or private
* Manage access by email groups

## Access Levels

| Level             | Who Can Access       |
| ----------------- | -------------------- |
| **Public**        | All chatbot users    |
| **Authenticated** | Only logged-in users |
| **Restricted**    | Only specified users |

## Setting Access on a Document

1. Go to **"Knowledge Base"**
2. Click on a document
3. Go to **"Access"** tab
4. Choose access level
5. Add authorized users if restricted
6. Click **"Save"**



## Authorized Emails

For restricted documents, specify who can access:

### Individual Emails

Add specific email addresses:

```
user@example.com
another@example.com
```

### Email Patterns

Use patterns to allow groups:

```
*@yourcompany.com        # All company emails
*@partner.example.com    # Partner emails
```

### Email Groups

Create reusable email groups:

1. Go to **"Settings" > "Email Groups"**
2. Create a group (e.g., "Engineering Team")
3. Add member emails
4. Use the group in document access



## How Access Control Works

When a user queries the chatbot:

1. User's email is verified (if authenticated)
2. Only accessible documents are searched
3. Response only includes permitted content



## Bulk Access Settings

Set access on multiple documents:

1. Go to **"Knowledge Base"**
2. Select multiple documents
3. Click **"Set Access"**
4. Choose settings
5. Apply to all selected



## Access Control by Folder

Organize documents in folders with inherited access:

1. Create a folder
2. Set access on the folder
3. Documents in the folder inherit settings
4. Override per-document as needed

## Best Practices

### Planning Access

* Identify sensitive content
* Group documents by access needs
* Use email groups for easier management

### Security

* Regularly review access settings
* Remove access when no longer needed
* Audit who can access sensitive documents

### User Experience

* Don't over-restrict - users get frustrated
* Provide clear messaging when access is denied
* Consider having a "general" knowledge base for common questions

## Troubleshooting

### User Can't Access Content

Check:

* User is logged in (for authenticated content)
* User's email is on the access list
* Email patterns are correct
* Document access settings

### Wrong Content in Responses

If restricted content appears to unauthorized users:

* Verify access settings on the document
* Check authentication is required
* Review email patterns for errors

## Managing Email Groups via the Management API

Email groups are **owner-scoped** — shared across all your chatbots. Manage them programmatically:

**List email groups**

```
GET /api/v1/email-groups?includeUsage=true
```

Required scope: `security:read`

Returns all of the owner's email groups. Pass `includeUsage=true` to include how many documents use each group.

**Create an email group**

```
POST /api/v1/email-groups
```

Required scope: `security:write`

| Field    | Type   | Description                                           |
| -------- | ------ | ----------------------------------------------------- |
| `name`   | string | Unique name per owner.                                |
| `emails` | array  | Member email addresses; normalized and de-duplicated. |

**Get a single group**

```
GET /api/v1/email-groups/{groupId}
```

Required scope: `security:read`

**Update a group (full replace)**

```
PUT /api/v1/email-groups/{groupId}
```

Required scope: `security:write`

Provide `name`, `emails`, or both. This replaces the group's member list entirely — not a merge.

**Delete a group**

```
DELETE /api/v1/email-groups/{groupId}
```

Required scope: `security:write`

## Related

* [Knowledge Base Overview](/knowledge-base/overview.md)
* [Chatbot Users - Authentication](/chatbot-users/authentication.md)
* [Managing Documents](/knowledge-base/managing.md)
* [Management API Reference — List Email Groups](/management-api/reference/list-email-groups.md)
* [Management API Reference — Create Email Group](/management-api/reference/create-email-group.md)
* [Management API Reference — Get Email Group](/management-api/reference/get-email-group.md)
* [Management API Reference — Update Email Group](/management-api/reference/update-email-group.md)
* [Management API Reference — Delete Email Group](/management-api/reference/delete-email-group.md)


---

# Check for Changes (Crawl Drift)

After you crawl a website, its pages keep changing — new articles get published, old ones get taken down. **Check for changes** compares your chatbot's already-crawled pages against the site's current `sitemap.xml` and shows you what's **new** and what's been **removed**, so you can top up your knowledge base without re-crawling the whole site.

## How it works

The check fetches the domain's live `sitemap.xml` and diffs it against the set of URLs your chatbot has already crawled. The result groups pages into three buckets:

| Bucket        | Meaning                                                   |
| ------------- | --------------------------------------------------------- |
| **New**       | In the site's sitemap, but not yet in your knowledge base |
| **Removed**   | Already crawled, but no longer listed in the sitemap      |
| **Unchanged** | Still present in both                                     |

Open it from the crawled-content card via **"Check for changes"** (or, from a scheduled crawl, **"See what's changed"**). The results dialog is titled **"Changes on"** followed by the domain name.



## It's free

The check itself is **free** — it only fetches the sitemap and compares URLs. **No crawl credits are used** until you choose to backfill the new pages. The dialog says so while it runs: *"Checking for changes… (free — no crawl credits used)."*

## What it detects — and what it doesn't

Check for changes compares the **URL set** only. It tells you which URLs were **added** or **removed** since your last crawl.

important

It does **not** detect content edits on pages you've already crawled. If a page is still listed in the sitemap, it counts as **unchanged** here even if its text was rewritten. To refresh an already-crawled page's content, re-crawl that page as a new version.

## Backfilling new pages

When new pages are found, you can crawl them in one click. Select the new pages you want and start the crawl — the button reads **"Crawl N new pages →"** (with N being how many you selected).

Only this backfill step uses crawl credits. Up to **100** new pages can be crawled per backfill request; if more than 100 are found, the first 100 are selected and you can run the check again to pick up the rest.

### Backfilled pages inherit the original access level

New pages crawled from this dialog inherit the **access level** of the original crawl (along with its authorized-email and group allow-lists). A crawl that was restricted to specific viewers stays restricted for its new pages — they don't land as openly viewable. See [Access Control](/knowledge-base/access-control.md) for what each access level means.

## Related

* [Website Crawling](/knowledge-base/website-crawling.md)
* [Scheduled Crawling](/knowledge-base/scheduled-crawling.md)
* [Managing Documents](/knowledge-base/managing.md)
* Management API: [Get crawl drift](/management-api/reference/get-chatbot-crawl-drift.md)


---

# Managing Documents

Keep your knowledge base organized and up to date.

## Viewing Documents

1. Go to **"Knowledge Base"**

2. View all documents with:

   

   * Name and type
   * Upload date
   * Processing status
   * Size and page count



## Document Details

Click on any document to see:

* **Content preview** - View extracted text
* **Metadata** - File info, dates, status
* **Chunks** - How the document was split
* **Access settings** - Who can access
* **Usage** - How often content is retrieved



## Editing Documents

### Edit Document Text

For documents that allow editing:

1. Click on the document
2. Click **"Edit"**
3. Modify the content
4. Click **"Save"**

note

Editing triggers re-embedding, which may take a moment.

### Update Document Metadata

Change name, description, or tags:

1. Click on the document
2. Go to **"Settings"** tab
3. Update fields
4. Click **"Save"**

## Replacing Documents

To update a document with a new version:

1. Click on the document
2. Click **"Replace"**
3. Upload the new file
4. Confirm replacement

The new content replaces the old while preserving:

* Access settings
* Tags and metadata
* Document ID

## Deleting Documents

### Single Document

1. Click on the document
2. Click **"Delete"**
3. Confirm deletion

### Bulk Delete

1. Select multiple documents
2. Click **"Delete Selected"**
3. Confirm deletion

danger

Deletion is permanent. Consider archiving important documents instead.

## Organizing Documents

### Tags

Add tags to organize documents:

1. Click on the document
2. Add tags (e.g., "product", "support", "v2")
3. Filter by tags in the document list

### Folders

Create folders for organization:

1. Click **"New Folder"**
2. Name the folder
3. Drag documents into folders



### Filtering and Sorting

Filter documents by:

* Type (PDF, web, video, etc.)
* Status (ready, processing, failed)
* Date (uploaded, modified)
* Tags
* Access level

Sort by:

* Name
* Date
* Size
* Type

## Storage Management

### Viewing Usage

1. Go to **"Settings" > "Usage"**
2. View storage breakdown by type
3. See what's consuming the most space



### Reducing Storage

* Delete unused documents
* Remove outdated content
* Compress images before upload
* Archive old versions

## Document Status

| Status         | Description              | Action          |
| -------------- | ------------------------ | --------------- |
| **Ready**      | Processed and searchable | None needed     |
| **Processing** | Being processed          | Wait            |
| **Failed**     | Error occurred           | Retry or delete |
| **Pending**    | Waiting to process       | Wait            |

### Retrying Failed Documents

1. Click on the failed document
2. View the error message
3. Click **"Retry"** or fix the issue

## Best Practices

### Regular Maintenance

* Review documents monthly
* Remove outdated content
* Update stale information
* Check for processing errors

### Organization

* Use consistent naming conventions
* Apply tags systematically
* Group related documents in folders

### Quality

* Ensure documents are relevant
* Remove duplicate content
* Verify content accuracy

## Related

* [Knowledge Base Overview](/knowledge-base/overview.md)
* [Access Control](/knowledge-base/access-control.md)
* [Uploading PDFs](/knowledge-base/uploading/pdfs.md)


---

# Knowledge Base Overview

The knowledge base is the foundation of your chatbot's intelligence. It contains all the information your chatbot uses to answer questions.

## How It Works

When you add content to your knowledge base:

1. **Processing** - Content is extracted from your documents
2. **Chunking** - Content is split into manageable pieces
3. **Embedding** - Each chunk is converted to a vector representation
4. **Indexing** - Vectors are stored for fast retrieval

When a user asks a question:

1. **Query embedding** - The question is converted to a vector
2. **Search** - Similar content is found in your knowledge base
3. **Context** - Relevant chunks are sent to the AI model
4. **Response** - The AI generates an answer using the context

This process is called **Retrieval-Augmented Generation (RAG)**.

## Supported Content Types

| Type             | Formats                                | Description             |
| ---------------- | -------------------------------------- | ----------------------- |
| **Documents**    | PDF, DOCX, TXT, MD, HTML, CHM          | Text and help documents |
| **Spreadsheets** | XLSX, CSV                              | Tabular data            |
| **Videos**       | MP4, AVI, MOV, MKV, WebM, WMV, YouTube | Transcribed content     |
| **Images**       | PNG, JPG, WEBP                         | OCR text extraction     |
| **Websites**     | HTML                                   | Crawled web content     |

## Adding Content

You can add content to your knowledge base by:

* **[Uploading documents](/knowledge-base/uploading/pdfs.md)** - PDFs, Word files, etc.
* **[Adding videos](/knowledge-base/uploading/videos.md)** - YouTube or uploaded videos
* **[Crawling websites](/knowledge-base/website-crawling.md)** - Import web content

## Storage and Limits

Storage limits depend on your plan:

| Plan       | Storage   |
| ---------- | --------- |
| Free       | 100 MB    |
| Starter    | 1 GB      |
| Pro        | 4 GB      |
| Pro+       | 10 GB     |
| Business   | 20 GB     |
| Enterprise | Unlimited |

Per-file upload caps also apply by plan and file type. See [Subscription Plans](/billing/plans.md#file-upload-size-limits).

## Best Practices

### Content Quality

* Use well-structured documents with clear headings
* Ensure text is machine-readable (not scanned images without OCR)
* Remove unnecessary content (headers, footers, page numbers)

### Organization

* Group related documents together
* Use descriptive file names
* Add access controls where needed

### Updates

* Keep content current
* Remove outdated documents
* Use scheduled crawling for websites

## Related

* [Uploading PDFs](/knowledge-base/uploading/pdfs.md)
* [Website Crawling](/knowledge-base/website-crawling.md)
* [Access Control](/knowledge-base/access-control.md)
* [Managing Documents](/knowledge-base/managing.md)


---

# Scheduled Crawling

Set up automatic crawls to keep your knowledge base synchronized with website changes.

## Creating a Schedule

1. Go to **"Knowledge Base" > "Schedules"**

2. Click **"Create Schedule"**

3. Configure the schedule:

   

   * URL to crawl
   * Crawl mode and options
   * Frequency

4. Click **"Save"**



## Schedule Frequencies

| Frequency   | Description    | Best For                 |
| ----------- | -------------- | ------------------------ |
| **Hourly**  | Every hour     | Rapidly changing content |
| **Daily**   | Once per day   | Regular updates          |
| **Weekly**  | Once per week  | Stable content           |
| **Monthly** | Once per month | Documentation            |

note

Higher frequencies use more resources and may count against your plan limits.

## Schedule Options

### Update Mode

| Mode        | Behavior                     |
| ----------- | ---------------------------- |
| **Replace** | Delete old content, add new  |
| **Merge**   | Keep existing, add new pages |
| **Diff**    | Only update changed pages    |

**Diff mode** is recommended for most use cases - it's faster and preserves existing content.

### Notifications

Get notified about crawl results:

* **On completion** - When crawl finishes
* **On failure** - When crawl fails
* **On changes** - When new content is found

## Managing Schedules

### View Schedules

1. Go to **"Knowledge Base" > "Schedules"**

2. See all active schedules with:

   

   * Next run time
   * Last run status
   * Page count



### Edit a Schedule

1. Click on the schedule
2. Modify settings
3. Click **"Save"**

### Pause a Schedule

Temporarily stop scheduled crawls:

1. Click on the schedule
2. Click **"Pause"**

### Delete a Schedule

1. Click on the schedule
2. Click **"Delete"**
3. Confirm deletion

note

Deleting a schedule doesn't delete already crawled content.

## Crawl History

View past crawl runs:

1. Go to **"Knowledge Base" > "Schedules"**
2. Click on a schedule
3. View the **"History"** tab

History shows:

* Run date and time
* Pages crawled
* Errors encountered
* Duration



## URL Management

### Adding URLs

Add multiple URLs to a single schedule:

1. Edit the schedule
2. Add URLs to the list
3. Each URL will be crawled with the same settings

### URL Patterns

Use patterns to include related URLs:

```
https://docs.example.com/v1/*
https://docs.example.com/v2/*
```

## Best Practices

### Choosing Frequency

Consider:

* How often does the content change?
* Plan limits and resource usage
* Impact of stale content

### Monitoring

* Review crawl history regularly
* Check for failed crawls
* Verify content is being updated

### Organization

* Group related URLs in one schedule
* Use descriptive schedule names
* Document schedule purposes

## Troubleshooting

### Scheduled Crawl Not Running

Check:

* Schedule is not paused
* Correct time zone settings
* Plan limits not exceeded

### Content Not Updating

Check:

* Update mode settings
* URL patterns matching correctly
* Website not blocking crawls

## Managing Scheduled Crawls via the Management API

Scheduled crawls can be managed programmatically. Listing requires the `documents:read` scope; creating, updating, and deleting require `documents:write`.

**List scheduled crawls**

```
GET /api/v1/chatbots/{chatbotId}/scheduled-crawls
```

**Create a scheduled crawl**

```
POST /api/v1/chatbots/{chatbotId}/scheduled-crawls
```

You supply the crawl target and schedule. Fields describing storage location (`domain`, `dataRegion`, plus internal vector-store identifiers) are ignored if sent — the crawl always writes to the chatbot's own configured storage.

**Get a scheduled crawl**

```
GET /api/v1/chatbots/{chatbotId}/scheduled-crawls/{scheduleId}
```

**Update a scheduled crawl**

```
PATCH /api/v1/chatbots/{chatbotId}/scheduled-crawls/{scheduleId}
```

**Delete a scheduled crawl**

```
DELETE /api/v1/chatbots/{chatbotId}/scheduled-crawls/{scheduleId}
```

As in the dashboard, deleting a schedule does not remove content that has already been crawled.

## Related

* [Website Crawling](/knowledge-base/website-crawling.md)
* [Check for Changes (Crawl Drift)](/knowledge-base/crawl-drift.md)
* [Managing Documents](/knowledge-base/managing.md)
* [Management API Reference — List scheduled crawls](/management-api/reference/list-chatbot-scheduled-crawls.md)
* [Management API Reference — Create a scheduled crawl](/management-api/reference/create-chatbot-scheduled-crawl.md)
* [Management API Reference — Get a scheduled crawl](/management-api/reference/get-chatbot-scheduled-crawl.md)
* [Management API Reference — Update a scheduled crawl](/management-api/reference/update-chatbot-scheduled-crawl.md)
* [Management API Reference — Delete a scheduled crawl](/management-api/reference/delete-chatbot-scheduled-crawl.md)


---

# Knowledge Scopes

Scopes let you divide a single chatbot's knowledge base into separate partitions, each with its own access rules, behavior, and budget.

Business & Enterprise

Knowledge Scopes are available on **Business** and **Enterprise** plans.

## What Are Scopes?

A scope is a named partition of your knowledge base. Each scope maps to its own vector namespace, so documents in one scope are completely separate from another.

Common use cases:

* **Multi-product chatbot** — One scope per product line, each with its own documentation
* **Internal vs public** — A public scope for customers, a restricted scope for employees
* **Department-specific** — Marketing, Engineering, and Sales each get their own scope with tailored behavior

## Creating Scopes

1. Open your chatbot from the **Dashboard**
2. Go to the **"Knowledge Scopes"** tab
3. Click **"Add Scope"**
4. Enter a **label** (e.g., "Product A Documentation")
5. A **namespace ID** is auto-generated from the label — you can edit it before saving
6. Optionally add a **description** (shown as a tooltip in the chat widget)
7. Click **"Save"**

warning

The namespace ID cannot be changed after creation. Choose a meaningful, permanent name.

## How End Users See Scopes

When your chatbot has **two or more scopes**, end users see a dropdown above the chat input to select which scope to query.

* The dropdown shows each scope's label
* Hovering shows the scope description (if provided)
* The selected scope is highlighted with a checkmark
* Users cannot switch scopes mid-conversation — they need to start a new chat

If your chatbot has only one scope, the dropdown is hidden.

### The Default Scope

Alongside your named scopes, the selector also lists a **default** entry that queries the chatbot's base namespace — the documents that aren't assigned to any named scope. It appears with your **default scope label**, or `" (default)"` if you haven't set a custom label.

You can **hide the default scope** from the selector so end users only see your named scopes. When it's hidden, the chatbot automatically falls back to a configured visible scope instead of the base namespace, so the picker label and the scope being queried stay in sync.

This is controlled by the `showDefaultScopeInSelector` setting (default: shown). Via the [Management API](#managing-scopes-via-the-management-api), read it on `GET /scopes` and set it on `PATCH /scopes`.

## Assigning Documents to Scopes

When you upload documents to your knowledge base, you assign them to a scope. Documents in one scope are only searchable when that scope is selected.

The **Knowledge Bases** page in the dashboard groups documents by scope so you can see what content belongs where.

## Access Control

Each scope can have its own authentication requirements, independent of the chatbot's global settings.

### Access Tiers

| Tier                 | Who Can Access                  |
| -------------------- | ------------------------------- |
| **Public** (default) | Anyone — no sign-in required    |
| **Login required**   | Any signed-in user              |
| **Restricted**       | Only specific emails or domains |

### Setting Up Access

1. Open a scope's settings
2. Toggle **"Require sign-in"** to require authentication
3. To further restrict, toggle **"Restrict to specific users"**
4. Add individual **email addresses** or entire **domains** (e.g., `acme.com`)

Users who don't meet the access requirements won't see the scope in the dropdown at all. If they somehow access it directly, they receive an error message.

## Behavior Overrides

Each scope can override the chatbot's default behavior. Leave any field empty to use the chatbot's defaults.

| Override            | Description                                     |
| ------------------- | ----------------------------------------------- |
| **System Prompt**   | Scope-specific instructions for the AI          |
| **Persona**         | A different personality or expertise area       |
| **Response Length** | Concise, Balanced, or Detailed                  |
| **Welcome Message** | Custom first message when the scope is selected |

This lets you create different "personalities" from the same chatbot. For example, a technical support scope with detailed responses and a sales scope with concise answers.

## Memory Interaction

When [Conversation Memory](/chatbots/conversation-memory.md) is enabled, long-term facts are tagged with the scope they were learned in. Facts only resurface when the user is querying that same scope (or a chained scope), so the chatbot won't offer personalized advice anchored in documentation it can't access from the current scope.

See [Scope-aware recall](/chatbots/conversation-memory.md#scope-aware-recall) for details.

## MCP Server Filtering

If your chatbot has MCP integrations (Jira, Salesforce, PostgreSQL, etc.), you can control which servers are available per scope.

* By default, all MCP servers are available in every scope
* Check specific servers to limit a scope to only those integrations
* Useful for keeping integrations relevant — e.g., only the Salesforce connector in the "Sales" scope

## Cost Limits

Set a budget cap on individual scopes to control spending.

1. Toggle **"Enable cost limit"** on a scope
2. Set the **amount** (in USD)
3. Choose the **reset period** — Monthly or Weekly

### What Happens at the Limit

| Usage     | Behavior                                                                                        |
| --------- | ----------------------------------------------------------------------------------------------- |
| Below 80% | Normal operation                                                                                |
| 80% – 99% | Warning indicator shown                                                                         |
| 100%+     | Scope is blocked — users see "This knowledge scope has reached its usage limit for this period" |

The budget resets automatically at the start of each period.

## Managing Scopes

### Editing a Scope

Update any scope setting (label, description, access, overrides, cost limit) at any time. Changes take effect immediately.

### Deleting a Scope

Deleting a scope removes:

* The scope configuration
* All documents in that scope's namespace
* Associated vector embeddings

warning

Deleting a scope is permanent and cannot be undone. All documents in the scope will be lost.

## Example Setup

**Scenario:** A company chatbot with public docs and an internal knowledge base.

| Setting             | Public Scope           | Internal Scope               |
| ------------------- | ---------------------- | ---------------------------- |
| **Label**           | Documentation          | Internal Wiki                |
| **Access**          | Public                 | Restricted to `@company.com` |
| **Persona**         | Friendly support agent | Technical expert             |
| **Response Length** | Balanced               | Detailed                     |
| **Cost Limit**      | $100/month             | $200/month                   |
| **MCP Servers**     | —                      | Jira, Confluence             |

* External users see only "Documentation" in the dropdown
* Employees with `@company.com` emails see both scopes
* Each scope has its own personality and budget

## Managing Scopes via the Management API

Most scope settings can be managed programmatically — see the reference for the full field list of each request. Read operations require the `chatbots:read` scope; changes require `chatbots:write`.

**List all scopes**

```
GET /api/v1/chatbots/{chatbotId}/scopes
```

Returns every scope defined on the chatbot.

**Create a scope**

```
POST /api/v1/chatbots/{chatbotId}/scopes
```

Creates a single scope. The scope `id` is derived by slugifying the supplied `id` (or the `label` if no `id` is given).

**Get a single scope**

```
GET /api/v1/chatbots/{chatbotId}/scopes/{scopeId}
```

**Update a single scope**

```
PATCH /api/v1/chatbots/{chatbotId}/scopes/{scopeId}
```

Partial update — only the fields you supply change; omitted fields are left untouched.

**Delete a single scope**

```
DELETE /api/v1/chatbots/{chatbotId}/scopes/{scopeId}
```

Removes the scope and unassigns it from the knowledge-base tree and any workflows that referenced it.

warning

Deleting a scope is permanent — as in the dashboard, the scope's documents and their embeddings are removed.

**Bulk-replace all scopes**

```
PATCH /api/v1/chatbots/{chatbotId}/scopes
```

Updates the full scope set in one call.

## Related

* [Document Access Control](/knowledge-base/access-control.md)
* [Subscription Plans](/billing/plans.md)
* [MCP Servers Overview](/integrations/mcp/overview.md)
* [Management API Reference — Get knowledge scopes](/management-api/reference/get-chatbot-scopes.md)
* [Management API Reference — Create a knowledge scope](/management-api/reference/create-chatbot-scope.md)
* [Management API Reference — Get a knowledge scope](/management-api/reference/get-chatbot-scope.md)
* [Management API Reference — Update a knowledge scope](/management-api/reference/patch-chatbot-scope.md)
* [Management API Reference — Delete a knowledge scope](/management-api/reference/delete-chatbot-scope.md)


---

# Transcript Corrections

WizChat automatically detects likely transcription errors in your video content and suggests corrections. You can review and resolve these suggestions — accepting, rejecting, or providing custom replacements — to improve the accuracy of your knowledge base.

Draft content — awaiting human review

This page was auto-drafted during a docs-sync run. Verify dashboard navigation labels against the current product before treating as authoritative.

## How corrections work

When a video is transcribed, the system detects spans that may be mis-transcribed and generates candidate replacement words. Each correction has a status:

| Status           | Meaning                                                        |
| ---------------- | -------------------------------------------------------------- |
| `suggested_auto` | The system has a high-confidence suggestion; not yet reviewed. |
| `needs_review`   | Flagged for human review (lower-confidence span).              |
| `accepted`       | A suggested or candidate word was accepted.                    |
| `rejected`       | The correction was dismissed; the original stands.             |
| `custom`         | A custom replacement text was applied.                         |

Accepting a correction, applying custom text, or undoing a previous transcript-changing resolution can trigger a **transcript rebuild and re-embedding** in the background, so your chatbot's answers reflect the corrected text.

## Reviewing corrections via the Management API

### List all corrections across a chatbot

```
GET /api/v1/chatbots/{chatbotId}/corrections
```

Required scope: `documents:read`

Returns a flat review queue of corrections across all of the chatbot's videos. Each item includes the video ID, video title, timestamp, original text, suggested replacement, and any candidates. Use the per-video endpoint when you need transcript context snippets around each correction span.

Response includes:

* `corrections` — array of `PublicCorrection` objects
* `totals` — per-status counts across the chatbot
* `truncated` — whether the result was capped (paginate by video if you need all)

### List corrections for a single video

```
GET /api/v1/videos/{videoId}/corrections
```

Required scope: `documents:read`

Returns a paginated list of corrections for one video (IDOR-guarded). Includes:

* `corrections` — page of `PublicCorrection` objects
* `correctionTotal` — total correction count for the video
* `hasMoreCorrections` / `correctionPage` — pagination signals
* `correctionSummary` — per-status totals for the video
* `correctionReembedStatus` — current async correction re-embed status, if any

Each `PublicCorrection` object includes:

| Field                   | Description                                                      |
| ----------------------- | ---------------------------------------------------------------- |
| `id`                    | Correction identifier.                                           |
| `status`                | Current status (see table above).                                |
| `original`              | The original transcribed text.                                   |
| `corrected`             | The suggested replacement, or `null`.                            |
| `candidates`            | Alternative candidate replacements.                              |
| `charStart` / `charEnd` | Character offsets in the raw transcript.                         |
| `context`               | A short transcript window around the span, with the span marked. |

### Resolving a correction

```
PATCH /api/v1/videos/{videoId}/corrections
```

Required scope: `documents:write`

Resolves one correction (IDOR-guarded). You can accept a candidate, reject the suggestion, apply custom text, or undo a previous resolution.

Request body:

| Field             | Type    | Description                                                      |
| ----------------- | ------- | ---------------------------------------------------------------- |
| `action`          | string  | `accept` \| `reject` \| `custom` \| `undo`                       |
| `correctionId`    | string  | The correction to resolve (alternative to `correctionIndex`).    |
| `correctionIndex` | integer | Position in the correction list (alternative to `correctionId`). |
| `pickedCandidate` | string  | For `action: "accept"` — the candidate text to apply.            |
| `customText`      | string  | For `action: "custom"` — the replacement text.                   |

Response includes `transcriptChanged` (whether the transcript was modified) and `reembedDispatched` (whether a background re-embed was triggered).

## Related

* [Management API Reference — List Chatbot Corrections](/management-api/reference/list-chatbot-corrections.md)
* [Management API Reference — List Video Corrections](/management-api/reference/list-video-corrections.md)
* [Management API Reference — Resolve Video Correction](/management-api/reference/resolve-video-correction.md)
* [Videos & YouTube](/knowledge-base/uploading/videos.md)


---

# Uploading CHM Files

CHM (`.chm`) files are compiled Windows help files — the format used by many desktop applications for their built-in help. WizChat can turn a CHM file into searchable knowledge for your chatbot.

## Upload a CHM File

1. Open your chatbot
2. Go to **"Knowledge Base"**
3. Click **"Upload Document"**
4. Select your `.chm` file
5. Wait for processing to complete



## Supported Files

| Type                        | Support      |
| --------------------------- | ------------ |
| `.chm` (compiled HTML Help) | Full support |

CHM is one of several document types the uploader accepts alongside PDF, Markdown, HTML, Word, and text files.

## How Processing Works

A CHM file is a compiled archive of HTML pages, so it goes through an extra conversion step before it can be embedded:

1. **Upload** — the `.chm` file is transferred to storage
2. **Convert CHM to PDF** — the compiled help file is unpacked and converted (the upload shows **"Converting CHM to PDF..."** during this stage)
3. **Text extraction** — text is extracted from the converted content
4. **Embedding** — the text is chunked and turned into vector embeddings for search

When it finishes, the document shows **"Completed successfully"** and is available for queries.

## File Limits

CHM uploads use both plan and file-type caps.

**Effective per-file limit = min(plan limit, CHM hard limit)**

* CHM hard limit: **350 MB**

See [Subscription Plans](/billing/plans.md#file-upload-size-limits) for per-plan limits across all file types. When your plan allows a larger file than the 350 MB CHM hard limit, the 350 MB limit still applies.

note

Large or deeply nested CHM files can take longer to process because of the extra conversion step.

## Troubleshooting

### Processing Failed

Common causes:

* Corrupted or partially downloaded `.chm` file
* File larger than your effective upload limit
* An unreadable or non-standard CHM archive

**Solution:** Re-download the original `.chm`, confirm it opens in a Windows help viewer, and re-upload.

### Poor Answer Quality

If your chatbot isn't using the CHM content well:

* Confirm processing finished (**"Completed successfully"**)
* Check that the help file actually contained text (not just images)
* Verify the content is relevant to your chatbot's purpose

## Related

* [Uploading PDFs](/knowledge-base/uploading/pdfs.md)
* [Knowledge Base Overview](/knowledge-base/overview.md)
* [Access Control](/knowledge-base/access-control.md)
* [Managing Documents](/knowledge-base/managing.md)


---

# In-Chat Data Analysis

Your chatbot's end users can upload Excel and CSV files directly in the chat for instant, on-the-fly analysis — no knowledge base setup required.

## How It Works

1. User clicks the **"+"** menu in the chat input
2. Selects **"Upload Document"**
3. Picks an Excel (.xlsx, .xls) or CSV (.csv) file
4. The file processes automatically (a status indicator shows progress)
5. Once ready, the user asks questions about the data in natural language

The chatbot analyzes the data using Python (pandas) and returns answers as text, tables, or interactive charts.

## Supported File Types

| Format | Extensions  |
| ------ | ----------- |
| Excel  | .xlsx, .xls |
| CSV    | .csv        |

**File size limit:** 50 MB

## What Users Can Ask

### Value Lookups

> "What was the revenue in Q3?" "How many employees are in the London office?"

### Trends & Time Series

> "Show the trend for monthly sales over the last year" "How has headcount changed quarter over quarter?"

### Comparisons

> "Compare expenses across all departments" "Which region had the highest growth?"

### Explanations

> "Why did profit change from 5M to 3M?" "What drove the revenue increase between Q1 and Q2?"

### Aggregations

> "What's the average order value by category?" "Sum up all transactions for 2024"

## Multi-Sheet Workbooks

For Excel files with multiple sheets, the chatbot automatically selects the most relevant sheet based on the question. Users don't need to specify which sheet to query — the AI figures it out.

## Follow-Up Questions

The chatbot remembers context within the conversation. After an initial question, users can ask follow-ups without repeating details:

1. **User:** "What was the net profit for 2024?"
2. **User:** "Break that down by quarter" *(chatbot remembers we're talking about net profit)*
3. **User:** "Why did Q3 drop?" *(chatbot remembers the metric and time context)*

## Visualizations

Query results are presented with interactive visualizations:

### Charts

* **Bar charts** — for categorical comparisons
* **Line charts** — for trends and time series
* **Doughnut charts** — for proportional breakdowns (5 or fewer categories)

Users can toggle between chart types using buttons above the visualization. Charts can be downloaded as PNG.

### Tables

* Sortable columns (click to sort)
* Exportable as CSV, JSON, or formatted JSON
* Shows row count and query execution time

Users switch between Chart and Table views using tabs.

## In-Chat Uploads vs Knowledge Base

|                  | In-Chat Upload                                             | Knowledge Base                            |
| ---------------- | ---------------------------------------------------------- | ----------------------------------------- |
| **Who uploads**  | End users during a conversation                            | Chatbot owner via dashboard               |
| **Purpose**      | Temporary analysis of a specific file                      | Permanent searchable knowledge            |
| **Available in** | Only the current conversation                              | All conversations                         |
| **Retention**    | Temporary ([per-plan limits](/security/data-retention.md)) | Permanent (until you delete)              |
| **Setup needed** | None — just upload and ask                                 | Upload via dashboard, wait for processing |

## Limitations

| Limitation         | Details                                  |
| ------------------ | ---------------------------------------- |
| File size          | 50 MB maximum                            |
| Formulas           | Values only — formulas are not evaluated |
| Pivot tables       | Expanded data only                       |
| Charts in file     | Not extracted                            |
| Images in cells    | Not processed                            |
| Password-protected | Not supported                            |

## Related

* [Excel & Spreadsheets (Knowledge Base)](/knowledge-base/uploading/excel.md)
* [Data Retention](/security/data-retention.md)
* [AI Model Settings](/chatbots/ai-settings.md)


---

# Excel & Spreadsheets

Add structured data from spreadsheets to your knowledge base.

## Supported Formats

| Format        | Extension       | Support      |
| ------------- | --------------- | ------------ |
| Excel         | .xlsx, .xls     | Full support |
| CSV           | .csv            | Full support |
| Google Sheets | Export as .xlsx | Via export   |

## Uploading Spreadsheets

1. Go to **"Knowledge Base"**
2. Click **"Upload Document"**
3. Select your spreadsheet file
4. Wait for processing



## How Spreadsheets Are Processed

WizChat processes spreadsheets by:

1. **Reading all sheets** - Each worksheet is processed
2. **Extracting headers** - Column headers become context
3. **Processing rows** - Data is chunked intelligently
4. **Creating embeddings** - Content becomes searchable

### Example

A spreadsheet like:

| Product  | Price  | Category    |
| -------- | ------ | ----------- |
| Widget A | $29.99 | Electronics |
| Widget B | $49.99 | Electronics |

Becomes searchable content that can answer:

* "What is the price of Widget A?"
* "List all electronics products"

## Best Practices

### Structure

* Use clear column headers
* Keep data organized in tables
* Avoid merged cells
* Use consistent formatting

### Content

* Include context in headers
* Avoid abbreviations when possible
* Keep related data together

### File Preparation

Before uploading:

* Remove unnecessary sheets
* Clean up formatting
* Ensure headers are in the first row

## Multi-Sheet Workbooks

For workbooks with multiple sheets:

* All sheets are processed
* Sheet names provide context
* You can view content per sheet



## Limitations

| Limitation       | Details                                                 |
| ---------------- | ------------------------------------------------------- |
| Max file size    | Tier + file-type limited (Excel/CSV hard limit: 200 MB) |
| Complex formulas | Values only, not formulas                               |
| Pivot tables     | Expanded data only                                      |
| Charts           | Not extracted                                           |
| Images in cells  | Not processed                                           |

## File Limits

Excel/CSV uploads use both plan and file-type caps.

**Effective per-file limit = min(plan limit, Excel/CSV hard limit)**

* Excel/CSV hard limit: **200 MB**

| Plan       | Max Excel/CSV Size |
| ---------- | ------------------ |
| Free       | 25 MB              |
| Starter    | 200 MB             |
| Pro        | 200 MB             |
| Pro+       | 200 MB             |
| Business   | 200 MB             |
| Enterprise | 200 MB             |

See [Subscription Plans](/billing/plans.md#file-upload-size-limits) for all file types.

## Troubleshooting

### Processing Failed

Common causes:

* Corrupted file
* Password protected
* Unsupported features

**Solution:** Save as .xlsx or .csv and retry.

### Data Not Searchable

* Check that column headers are meaningful
* Verify data was extracted (view document details)
* Consider restructuring the spreadsheet

## Related

* [Knowledge Base Overview](/knowledge-base/overview.md)
* [Uploading PDFs](/knowledge-base/uploading/pdfs.md)


---

# Images (OCR)

Upload images containing text. WizChat uses OCR (Optical Character Recognition) to extract and index the text.

## Supported Formats

| Format | Extension   | Support      |
| ------ | ----------- | ------------ |
| PNG    | .png        | Full support |
| JPEG   | .jpg, .jpeg | Full support |
| WebP   | .webp       | Full support |

## File Limits

Image uploads use both plan and file-type caps.

**Effective per-file limit = min(plan limit, image hard limit)**

* Image hard limit: **50 MB**

| Plan       | Max Image Size |
| ---------- | -------------- |
| Free       | 25 MB          |
| Starter    | 50 MB          |
| Pro        | 50 MB          |
| Pro+       | 50 MB          |
| Business   | 50 MB          |
| Enterprise | 50 MB          |

See [Subscription Plans](/billing/plans.md#file-upload-size-limits) for all file types.

## Uploading Images

1. Go to **"Knowledge Base"**
2. Click **"Upload Document"**
3. Select your image file(s)
4. OCR processing starts automatically



## OCR Processing

When you upload an image:

1. **Upload** - Image is transferred
2. **OCR** - Text is extracted from the image
3. **Processing** - Extracted text is chunked
4. **Embedding** - Content becomes searchable

## Best Image Quality

For best OCR results:

| Factor          | Recommendation                              |
| --------------- | ------------------------------------------- |
| **Resolution**  | 300 DPI or higher                           |
| **Contrast**    | High contrast (dark text, light background) |
| **Orientation** | Properly aligned (not rotated)              |
| **Focus**       | Sharp, not blurry                           |
| **File size**   | Not overly compressed                       |

## Use Cases

Images with text work well for:

* Scanned documents
* Screenshots
* Diagrams with labels
* Infographics
* Handwritten notes (with good quality)
* Whiteboards

## Viewing Extracted Text

After processing:

1. Go to **"Knowledge Base"**
2. Click on the image document
3. View the extracted text
4. Edit if needed



## Editing OCR Results

OCR isn't perfect. You can edit the extracted text:

1. Open the image document
2. Click **"Edit Text"**
3. Correct any errors
4. Click **"Save"**

tip

Always review OCR results for important documents.

## Limitations

| Limitation        | Details                 |
| ----------------- | ----------------------- |
| Handwriting       | Variable quality        |
| Complex layouts   | May affect accuracy     |
| Low resolution    | Reduced accuracy        |
| Stylized fonts    | May not be recognized   |
| Non-Latin scripts | Language support varies |

## Troubleshooting

### No Text Extracted

Possible causes:

* Image contains no text
* Text too small or blurry
* Unusual fonts

**Solution:** Try a higher quality image or manually enter the text.

### Incorrect Text

Possible causes:

* Low image quality
* Unusual formatting
* OCR limitations

**Solution:** Edit the extracted text manually.

## Related

* [Knowledge Base Overview](/knowledge-base/overview.md)
* [Uploading PDFs](/knowledge-base/uploading/pdfs.md)


---

# Uploading PDFs

PDF documents are the most common content type for knowledge bases.

## Upload a PDF

1. Open your chatbot
2. Go to **"Knowledge Base"**
3. Click **"Upload Document"**
4. Select your PDF file
5. Wait for processing to complete



## Supported PDF Types

| Type               | Support                  |
| ------------------ | ------------------------ |
| Text-based PDFs    | Full support             |
| Scanned PDFs       | OCR processing available |
| Password-protected | Not supported            |
| Encrypted          | Not supported            |

## Processing Status

After upload, your PDF goes through these stages:

| Status         | Description                            |
| -------------- | -------------------------------------- |
| **Uploading**  | File is being transferred              |
| **Processing** | Text extraction and embedding          |
| **Ready**      | Available for queries                  |
| **Failed**     | Processing error (see troubleshooting) |

## File Limits

PDF uploads use both plan and file-type caps.

**Effective per-file limit = min(plan limit, PDF hard limit)**

* PDF hard limit: **500 MB**

| Plan       | Max PDF Size |
| ---------- | ------------ |
| Free       | 25 MB        |
| Starter    | 200 MB       |
| Pro        | 500 MB       |
| Pro+       | 500 MB       |
| Business   | 500 MB       |
| Enterprise | 500 MB       |

note

Very large PDFs can take longer to process. There is no fixed page-count guarantee.

See [Subscription Plans](/billing/plans.md#file-upload-size-limits) for all file types.

## Best Practices

### Before Uploading

* Ensure the PDF has selectable text
* Remove unnecessary pages
* Check that content is relevant to your chatbot's purpose

### Document Quality

Good PDFs have:

* Clear, readable text
* Proper headings and structure
* Machine-readable content (not just images)

### Scanned Documents

For scanned PDFs:

* Enable OCR during upload
* Ensure high scan quality (300 DPI minimum)
* Expect slightly lower accuracy than text-based PDFs

## Viewing Uploaded PDFs

1. Go to **"Knowledge Base"**

2. Find the document in the list

3. Click to view details:

   

   * Page count
   * Processing status
   * Chunk count
   * Access settings



## Troubleshooting

### Processing Failed

Common causes:

* Corrupted file
* Password protection
* File too large
* Unsupported format

**Solution:** Try re-uploading or check file format.

### Poor Answer Quality

If your chatbot isn't using PDF content well:

* Check if the PDF has selectable text
* Try enabling OCR for scanned documents
* Verify content was processed (check chunk count)

## Related

* [Knowledge Base Overview](/knowledge-base/overview.md)
* [Access Control](/knowledge-base/access-control.md)
* [Managing Documents](/knowledge-base/managing.md)


---

# Videos & YouTube

Add video content to your knowledge base. Videos are transcribed, and the text becomes searchable.

## YouTube Videos

Add YouTube videos from a channel you connect. Videos are transcribed, and the text becomes searchable.

### Connect & Import

1. Go to **"Integrations" > "YouTube"**
2. Click **"Connect YouTube"**
3. Authorize WizChat access
4. Select videos or channels to import



See [YouTube Integration](/integrations/youtube.md) for details.

## Uploading Video Files

### Supported Formats

| Format | Support                 |
| ------ | ----------------------- |
| MP4    | Full support            |
| WebM   | Full support            |
| MOV    | Full support            |
| AVI    | Converted during upload |
| MKV    | Converted during upload |
| WMV    | Converted during upload |

### Upload a Video

1. Go to **"Knowledge Base"**
2. Click **"Upload Document"**
3. Select your video file
4. Wait for transcription to complete



## Transcription Process

When you add a video:

1. **Upload/Fetch** - Video is uploaded or fetched from YouTube
2. **Audio extraction** - Audio track is extracted
3. **Transcription** - Speech-to-text processing
4. **Embedding** - Transcript is processed for search

### Transcription Quality

Factors affecting quality:

* Audio clarity
* Speaker accents
* Background noise
* Language

## File Limits

Video uploads use both plan and file-type caps.

**Effective per-file limit = min(plan limit, video hard limit)**

* Video hard limit: **1 GB**

| Plan       | Max Video Size |
| ---------- | -------------- |
| Free       | 25 MB          |
| Starter    | 200 MB         |
| Pro        | 500 MB         |
| Pro+       | 1 GB           |
| Business   | 1 GB           |
| Enterprise | 1 GB           |

note

Long videos may still hit processing timeouts even when file size is within limit.

See [Subscription Plans](/billing/plans.md#file-upload-size-limits) for all file types.

## Viewing Transcripts

1. Go to **"Knowledge Base"**
2. Click on the video document
3. View the full transcript
4. Edit if needed



## Editing Transcripts

You can edit transcripts to fix errors:

1. Open the video document
2. Click **"Edit Transcript"**
3. Make corrections
4. Click **"Save"**

note

Editing a transcript triggers re-embedding, which may affect existing queries.

## Video Sources in Responses

When a chatbot answers using video content, the source card displays a video icon next to the video name so users can distinguish it from PDF sources. When the transcript carries a timestamp for the cited moment, the card shows that time (for example, `At 9:31`) and clicking the source opens the video at that point rather than at the start.

If your knowledge base mixes PDFs and videos, PDF sources may dominate the displayed results since text embeddings typically score higher. Enable **Balanced Sources** in [AI Settings](/chatbots/ai-settings.md#balanced-sources) to ensure video sources appear alongside PDFs when relevant.

## Best Practices

* Use videos with clear audio
* Prefer videos with single speakers
* Consider adding timestamps for navigation
* Edit transcripts to fix obvious errors

## Troubleshooting

### Transcription Failed

Common causes:

* No speech in video
* Unsupported audio format
* Video file too large for current upload limits
* Video processing timed out

**Solution:** Check file format and upload limits, then retry.

### Poor Transcription Quality

* Verify audio quality in the original video
* Consider uploading a higher quality version
* Manually edit the transcript

## Related

* [YouTube Integration](/integrations/youtube.md)
* [Knowledge Base Overview](/knowledge-base/overview.md)


---

# Website Crawling

Crawl websites to automatically import content into your knowledge base.

## Starting a Crawl

1. Go to **"Knowledge Base"**
2. Click **"Add Content" > "Crawl Website"**
3. Enter the website URL
4. Select crawl options
5. Click **"Preview"** to see what will be crawled
6. Click **"Start Crawl"**



## Crawl Modes

| Mode            | Description                 | Best For               |
| --------------- | --------------------------- | ---------------------- |
| **Single Page** | Only the specified URL      | Specific articles      |
| **Shallow**     | URL + directly linked pages | Small sections         |
| **Deep**        | Multiple levels of links    | Larger sections        |
| **Full Site**   | Entire website              | Complete documentation |

### How Modes Work

**Single Page:**

* Crawls exactly one page
* Fastest option

**Shallow (1 level):**

* Crawls the starting page
* Plus all pages linked from it

**Deep (2-3 levels):**

* Follows links to specified depth
* May crawl hundreds of pages

**Full Site:**

* Attempts to crawl all pages
* Respects robots.txt
* May take significant time

## Crawl Options

### URL Patterns

Limit crawling to specific URL patterns:

```
Include: /docs/*, /help/*
Exclude: /blog/*, /news/*
```

### CSS Selectors

Extract only specific content. In the dashboard crawl form, the **Custom CSS Selectors (Optional)** field takes comma-separated selectors for **additional elements to include**:

```
.product-specs, #pricing-table
```



### Excluding elements (Management API)

The [Management API](/management-api/reference/start-chatbot-crawl.md) crawl endpoint also accepts an **`excludeTags`** field — CSS selectors of elements to **skip**. These are added to the crawler's built-in defaults (which already drop cookie banners, chat widgets, and footers); they don't replace them. Up to **50** selectors are allowed.

```
{
  "url": "https://example.com/docs",
  "excludeTags": [".cookie-notice", "nav", ".related-articles"]
}
```

The API also accepts **`includeTags`** (up to 50 selectors of additional content to include), which mirrors the dashboard's **Custom CSS Selectors** field.

note

`excludeTags` is currently available through the Management API. The dashboard crawl form exposes the include-selectors field (**Custom CSS Selectors**) only.

### Page Limits

Set maximum pages to crawl:

| Plan     | Max Pages per Crawl |
| -------- | ------------------- |
| Free     | 10                  |
| Starter  | 100                 |
| Pro      | 500                 |
| Business | 5,000               |

### Crawling multiple URLs at once

You can crawl more than one starting URL in a single request:

* **Dashboard** — the crawl form lets you add **up to 10 URLs** ("Add up to 10 URLs to process"). Each URL is scraped individually.
* **[Management API](/management-api/reference/start-chatbot-crawl.md)** — the `POST /crawls` endpoint accepts a **`urls`** array of **up to 100** URLs in one call (use it instead of the single `url` field).

## Preview Before Crawling

Always preview before starting:

1. Click **"Preview"**
2. Review the list of pages that will be crawled
3. Adjust settings if needed
4. Start the crawl when satisfied



## Crawl Status

| Status        | Description           |
| ------------- | --------------------- |
| **Queued**    | Waiting to start      |
| **Running**   | Actively crawling     |
| **Completed** | Successfully finished |
| **Failed**    | Error occurred        |
| **Partial**   | Some pages failed     |

## Viewing Crawled Content

After crawling:

1. Go to **"Knowledge Base"**
2. Filter by "Web Pages"
3. Click on any page to view content
4. Edit or remove as needed



## Best Practices

### Before Crawling

* Check robots.txt compliance
* Preview the crawl scope
* Start with shallow crawls
* Use URL patterns to limit scope

### Content Quality

* Use CSS selectors to exclude navigation
* Focus on main content areas
* Remove boilerplate content

### Maintenance

* Schedule regular recrawls for changing content
* Remove outdated pages
* Monitor for broken pages

## Troubleshooting

### Crawl Blocked

Some sites block crawlers. Solutions:

* Check if site allows crawling (robots.txt)
* Contact site owner for permission
* Manually copy content instead

### Missing Content

* Check CSS selectors
* Verify pages are publicly accessible
* Look for JavaScript-rendered content issues

### Too Many Pages

* Use URL patterns to limit scope
* Start with single page or shallow mode
* Set page limits

## Related

* [Check for Changes (Crawl Drift)](/knowledge-base/crawl-drift.md)
* [Scheduled Crawling](/knowledge-base/scheduled-crawling.md)
* [Knowledge Base Overview](/knowledge-base/overview.md)
* [Managing Documents](/knowledge-base/managing.md)


---

# Add knowledge base content via the API

Most knowledge lands in a chatbot through a file upload or a crawl. When the content you want to add is already text — a Markdown article, a curated question/answer pair, a snippet pasted from somewhere else — you can send it directly with a single call instead of turning it into a file first:

```
POST /api/v1/chatbots/{chatbotId}/text
```

Each entry you send becomes its own **searchable, listable, deletable** knowledge source, exactly like an uploaded document. Processing is **synchronous** — the response reports the per-entry result — and long entries are split into searchable segments automatically.

Required scope: **`documents:write`**. See [Authentication & scopes](/management-api/guides/authentication.md).

## Add a single entry

Send a `text` string. `fileName` is an optional display name / citation title (up to 300 characters):

```
curl -X POST https://www.wizchat.com/api/v1/chatbots/$CHATBOT_ID/text \
  -H "Authorization: Bearer $WIZCHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "# Refund policy\n\nRefunds are issued within 14 days of purchase.",
    "fileName": "Refund policy",
    "kind": "markdown"
  }'
```

The optional `kind` field (`markdown`, `text`, or `snippet`) controls how the content is split. When omitted, it is inferred from the file name.

A success is a `200` describing what was added:

```
{
  "success": true,
  "ingested": 1,
  "failed": 0,
  "documents": [
    {
      "fileName": "Refund policy",
      "success": true,
      "document_id": "doc_abc123",
      "chunks": 1
    }
  ]
}
```

`document_id` is the id of the new source — use it with the document list/delete operations in the [API reference](/management-api/reference/wizchat-management-api.md). `chunks` is the number of searchable segments the entry was split into.

## Add a batch of entries

To add several entries at once, send an `items` array instead of `text` (use one or the other, not both). Each item needs its own `text`, and may carry its own `fileName` (or `title`, an alias) and `kind`. A single request accepts up to **50** items — useful for seeding curated question/answer pairs:

```
curl -X POST https://www.wizchat.com/api/v1/chatbots/$CHATBOT_ID/text \
  -H "Authorization: Bearer $WIZCHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "text": "Q: Do you ship to the EU?\nA: Yes, to all EU countries.", "fileName": "Shipping — EU" },
      { "text": "Q: How long does delivery take?\nA: 3–5 business days.", "fileName": "Shipping — delivery time" }
    ]
  }'
```

Each entry can hold up to roughly **1 MB** of text.

### Partial success

A batch is not all-or-nothing. If some entries are added and others fail, the response is a **`207 Multi-Status`** and each element of `documents[]` reports its own `success` (with a `document_id` and `chunks` on success, or an `error` on failure):

```
{
  "success": false,
  "ingested": 1,
  "failed": 1,
  "documents": [
    { "fileName": "Shipping — EU", "success": true, "document_id": "doc_1", "chunks": 1 },
    { "fileName": "Shipping — delivery time", "success": false, "error": "..." }
  ]
}
```

Always check `documents[].success` per entry rather than relying on the HTTP status alone. A `500` means **every** entry failed. That response carries a top-level `error` object (`code` is always `"ingest_failed"`, with a human-readable `message`) alongside the same `documents[]` array, so you can read each entry's own `error` for the per-entry reason:

```
{
  "error": {
    "code": "ingest_failed",
    "message": "Failed to add the submitted entries."
  },
  "documents": [
    { "fileName": "Shipping — EU", "success": false, "error": "..." },
    { "fileName": "Shipping — delivery time", "success": false, "error": "..." }
  ]
}
```

## Visibility and scope

By default, added content is **`owner-only`**. To make it more widely available, set `viewAccessLevel` to one of `owner-only`, `authenticated-users`, `anyone-with-link`, or `permanent-public`. When access is restricted, you can grant specific viewers with `authorizedEmails` (up to 200) or `authorizedGroups` (email-group ids, up to 200):

```
curl -X POST https://www.wizchat.com/api/v1/chatbots/$CHATBOT_ID/text \
  -H "Authorization: Bearer $WIZCHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Internal onboarding notes …",
    "fileName": "Onboarding",
    "viewAccessLevel": "authenticated-users",
    "authorizedEmails": ["alex@example.com"]
  }'
```

To place the content in a specific [knowledge scope](/knowledge-base/scopes.md), pass its id as `scopeId`; omit it to use the default scope.

## Errors

| Status | Meaning                                                                                                             |
| ------ | ------------------------------------------------------------------------------------------------------------------- |
| `400`  | Invalid input                                                                                                       |
| `401`  | Missing or invalid API key                                                                                          |
| `403`  | Key lacks the `documents:write` scope                                                                               |
| `404`  | Chatbot not found                                                                                                   |
| `413`  | An entry or the batch exceeds the size limit, or the account storage limit                                          |
| `429`  | Rate limit exceeded — see [Errors & rate limits](/management-api/guides/errors-and-rate-limits.md)                  |
| `500`  | Every entry failed — the response carries `error.code: "ingest_failed"` plus the per-entry reasons in `documents[]` |

## Next steps

* [Add text or a .txt/.md file to the knowledge base](/management-api/reference/ingest-chatbot-text.md) — the full request/response schema with a "try it" console
* [Managing documents](/knowledge-base/managing.md) — organize and maintain knowledge base sources
* [Knowledge scopes](/knowledge-base/scopes.md) — partition a chatbot's knowledge


---

# Authentication & scopes

## The bearer key

Every Management API request must carry a `wpk_live_…` key in the `Authorization` header using the **Bearer** scheme:

```
Authorization: Bearer wpk_live_xxxxxxxxxxxxxxxxxxxx
```

```
curl https://www.wizchat.com/api/v1/chatbots \
  -H "Authorization: Bearer $WIZCHAT_API_KEY"
```

The SDKs add this header for you — you only supply the key:

```
import { createWizChatClient } from '@wizchat/management';
const wizchat = createWizChatClient({ apiKey: process.env.WIZCHAT_API_KEY! });
```

```
from wizchat_management import WizChatClient
wizchat = WizChatClient(api_key=os.environ["WIZCHAT_API_KEY"])
```

A missing or malformed key returns **`401 Unauthorized`**.

## Scopes

Management API keys are **scoped**. Each operation declares a required scope in its reference page (for example, `List chatbots` requires `chatbots:read`). A key that authenticates successfully but lacks the required scope receives **`403 Forbidden`**.

Grant only the scopes a key actually needs. The available scopes are:

| Scope             | Grants                                                                              |
| ----------------- | ----------------------------------------------------------------------------------- |
| `chatbots:read`   | Read chatbot settings and list chatbots                                             |
| `chatbots:write`  | Update chatbot settings                                                             |
| `documents:read`  | List and read documents                                                             |
| `documents:write` | Add text/Markdown content, delete documents, and change privacy / authorized emails |
| `videos:read`     | List and read videos                                                                |
| `videos:write`    | Delete videos                                                                       |
| `mcp:read`        | Read MCP server config and access control                                           |
| `mcp:write`       | Create, update, delete MCP servers and their access control                         |
| `skills:read`     | Read skills                                                                         |
| `skills:write`    | Create, update, delete skills                                                       |
| `security:read`   | Read access-protection, external-API, access-list, and telemetry config             |
| `security:write`  | Update those security settings and manage their keys                                |
| `domains:read`    | List authorized custom domains                                                      |
| `domains:write`   | Authorize, deauthorize, and verify custom domains                                   |
| `deploy`          | Read deployment status and trigger a redeploy                                       |
| `analytics:read`  | Read cost and usage analytics                                                       |

info

The [config-as-code](/management-api/guides/config-as-code.md) `GET /config` and `POST /apply` endpoints require the per-section **read** scopes for an export or dry-run, and the per-section **write** scopes (plus `chatbots:write`) to apply changes. A dry-run never needs write scopes.

## Per-chatbot lock

A key is bound to the chatbots its owner can access. In the current phase, `GET /api/v1/chatbots` returns only the chatbots **owned** by the caller. Team-shared or individually-granted chatbots are still reachable by id via `GET`/`PATCH /api/v1/chatbots/{chatbotId}` but are not enumerated in the list.

## Owner tokens

In addition to `wpk_live_…` keys, the API also accepts a Firebase ID token for owner-authenticated, first-party requests. For programmatic integrations, use a Management API key.

## Rotating and revoking keys

Rotate keys periodically and whenever one may have leaked:

1. Create a new key with the same scopes.
2. Update your integration to use it.
3. Revoke the old key in the dashboard.

Revoked keys stop working immediately and return `401`.


---

# Config-as-code

The Management API lets you treat an entire chatbot's configuration as a single **desired-state document**. The workflow is GitOps-style:

```
GET  /api/v1/chatbots/{id}/config   →   edit the document   →   POST /api/v1/chatbots/{id}/apply
```

You export the current config, change it (in code, in a file, in a PR), then apply the result. The server diffs your document against the live config and reconciles the difference.

## 1. Export the current config

```
curl https://www.wizchat.com/api/v1/chatbots/abc123/config \
  -H "Authorization: Bearer $WIZCHAT_API_KEY"
```

The response is a canonical, re-appliable document:

```
{
  "apiVersion": "wizchat/v1",
  "kind": "ChatbotConfig",
  "prune": true,
  "spec": {
    "chatbot": { "name": "Support Bot" },
    "mcpServers": [ /* ... */ ],
    "skills": [ /* ... */ ],
    "domains": [ /* ... */ ]
  }
}
```

`getConfig` requires `chatbots:read` plus the per-section read scopes. Sections your key cannot read are reported in `_omittedSections` instead of `spec`.

## 2. Edit, then dry-run

Always preview changes first. Pass `?dryRun=true` to compute the **plan** without writing anything:

```
curl -X POST "https://www.wizchat.com/api/v1/chatbots/abc123/apply?dryRun=true" \
  -H "Authorization: Bearer $WIZCHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d @config.json
```

A dry-run response is `{ "dryRun": true, "plan": [...] }` — every create, update, **and delete** the apply would perform.

## 3. Apply

Drop the query flag to execute:

```
curl -X POST "https://www.wizchat.com/api/v1/chatbots/abc123/apply" \
  -H "Authorization: Bearer $WIZCHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d @config.json
```

On full success the response is:

```
{
  "dryRun": false,
  "plan": [ /* the executed plan */ ],
  "applied": [ /* ops that ran */ ],
  "failed": null,
  "config": { /* refreshed config document */ }
}
```

## Prune is on by default

The array sections (`mcpServers`, `skills`, `domains`) are **authoritative**. With `prune: true` (the server default), any resource that exists on the chatbot but is **absent from your document is deleted**. Every delete is surfaced in the dry-run plan, so always dry-run before applying.

Set `prune: false` (on the document, or via the SDK option) for **merge-only** behavior — creates and updates, never deletes.

## Partial failure (422)

Apply stops on the first failing operation and returns **`422 Unprocessable Entity`** with an `ApplyResult` whose `failed` field is populated and whose `applied` lists the ops that succeeded before it. Apply is **idempotent** — fix the offending section and re-run the same document.

```
{
  "dryRun": false,
  "applied": [ /* ops that succeeded */ ],
  "failed": { "op": "...", "error": { "code": "...", "message": "..." } }
}
```

## With the SDKs

`applyConfig` / `apply_config` return an `ApplyResult` for **both** full success (`200`) and partial failure (`422`) — inspect `failed` rather than catching an exception for the partial case. Auth and validation errors (`400`/`401`/`403`/`404`/`429`) still throw.

### TypeScript

```
import { createWizChatClient } from '@wizchat/management';

const wizchat = createWizChatClient({ apiKey: process.env.WIZCHAT_API_KEY! });

// 1. Export
const config = await wizchat.getConfig('abc123');

// 2. Edit
config.spec.chatbot.name = 'Renamed Bot';

// 3. Dry-run, then apply
const plan = await wizchat.applyConfig('abc123', config, { dryRun: true });
console.log(plan.plan);

const result = await wizchat.applyConfig('abc123', config);
if (result.failed) {
  console.error('Partial failure:', result.failed);
} else {
  console.log('Applied:', result.applied);
}
```

### Python

```
import os
from wizchat_management import WizChatClient

with WizChatClient(api_key=os.environ["WIZCHAT_API_KEY"]) as wizchat:
    # 1. Export
    config = wizchat.get_config("abc123")

    # 2. Edit
    config.spec.chatbot.name = "Renamed Bot"

    # 3. Dry-run, then apply
    plan = wizchat.apply_config("abc123", config, dry_run=True)
    print(plan.plan)

    result = wizchat.apply_config("abc123", config)  # prune defaults to True
    if result.failed:
        print("Partial failure:", result.failed)
    else:
        print("Applied:", result.applied)
```

tip

To keep the live config untouched for sections you don't manage, export with `getConfig`, change only what you need, and re-apply the whole document — the diff engine leaves unchanged sections alone.


---

# Errors & rate limits

## Error shape

Every error response uses a consistent envelope:

```
{
  "error": {
    "code": "FORBIDDEN",
    "message": "Key lacks required scope: chatbots:write",
    "details": { }
  }
}
```

* `code` — a stable, machine-readable identifier.
* `message` — a human-readable explanation.
* `details` — *(optional)* additional structured context.

The SDKs surface this as a typed error. In TypeScript, non-2xx responses throw `WizChatApiError` (with `status` and the parsed envelope); in Python they raise `WizChatApiError`.

```
import { createWizChatClient, WizChatApiError } from '@wizchat/management';

try {
  await wizchat.getConfig('abc123');
} catch (err) {
  if (err instanceof WizChatApiError) {
    console.error(err.status, err.message);
  }
}
```

```
from wizchat_management import WizChatClient, WizChatApiError

try:
    wizchat.get_config("abc123")
except WizChatApiError as err:
    print(err.status, err.message)
```

## Status codes

| Status  | Code                   | Meaning                                                            |
| ------- | ---------------------- | ------------------------------------------------------------------ |
| **400** | `BAD_REQUEST`          | Invalid input — malformed body or parameters                       |
| **401** | `UNAUTHORIZED`         | Missing or invalid API key                                         |
| **403** | `FORBIDDEN`            | Key is valid but lacks the required scope                          |
| **404** | `NOT_FOUND`            | The chatbot or resource does not exist or isn't visible to the key |
| **422** | `UNPROCESSABLE_ENTITY` | Partial failure on `apply` — see below                             |
| **429** | `RATE_LIMITED`         | Too many requests — back off and retry                             |

### 422 on apply

The config-as-code [`apply`](/management-api/guides/config-as-code.md) endpoint returns `422` for **partial failure**: execution stopped at the first failing operation. The body is an `ApplyResult` whose `failed` field is populated and whose `applied` field lists the operations that succeeded before it. Apply is idempotent — fix the offending section and re-run the same document. The SDK `applyConfig` / `apply_config` helpers return this result rather than throwing, so inspect `result.failed`.

## Rate limits

The API is rate limited. When you exceed the limit you receive **`429 Too Many Requests`**. Build clients that back off and retry — prefer exponential backoff with jitter — and avoid tight polling loops. For bulk changes, prefer a single [config-as-code](/management-api/guides/config-as-code.md) `apply` over many individual writes.

## Related

* [Authentication & scopes](/management-api/guides/authentication.md) — why a request returns `401` vs `403`
* [Config-as-code](/management-api/guides/config-as-code.md) — the `422` partial-failure flow
* [API Reference](/management-api/reference/wizchat-management-api.md) — per-operation status codes


---

# OAuth 2.0

OAuth 2.0 is an alternative to `wpk_live_…` [API keys](/management-api/guides/authentication.md) for authenticating to the Management API. Instead of a long-lived key, an OAuth client exchanges its credentials for a **short-lived access token** (`oat_…`, valid about one hour) that carries a specific set of scopes.

Which one should you use?

* **API key (`wpk_live_…`)** — simplest for a single first-party integration you control.
* **OAuth client credentials** — server-to-server access with short-lived, independently revocable tokens; register several clients with different scopes.
* **OAuth authorization code** — for interactive apps (such as MCP clients) that act on a user's behalf after a browser consent.

## Discovery

The authorization server publishes its metadata (RFC 8414) at:

```
GET https://www.wizchat.com/.well-known/oauth-authorization-server
```

It advertises the token, registration, and introspection endpoints, the supported scopes, and that PKCE uses `S256`. A conformant OAuth client can bootstrap from this document.

## Server-to-server: client credentials

The client-credentials grant (RFC 6749 §4.4) is the path for backend integrations. You register an OAuth client once, then exchange its `client_id` + `client_secret` for access tokens.

### 1. Register a client

As the account owner, register an OAuth client. Registration is owner-authenticated — it accepts a Firebase ID token (see [Owner tokens](/management-api/guides/authentication.md#owner-tokens)):

```
POST /api/v1/oauth/clients
```

```
{
  "name": "My integration",
  "scopes": ["chatbots:read", "documents:write"],
  "allowedChatbotIds": null
}
```

* `scopes` — the [scopes](/management-api/guides/authentication.md#scopes) this client may request.
* `allowedChatbotIds` — restrict the client to specific chatbots, or `null` for every chatbot you own.

The response returns the credentials **once** — the `clientSecret` is never shown again:

```
{
  "clientId": "occ_xxxxxxxxxxxxxxxx",
  "clientSecret": "ocs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "name": "My integration",
  "scopes": ["chatbots:read", "documents:write"],
  "allowedChatbotIds": null,
  "status": "active",
  "createdAt": "2026-07-08T00:00:00.000Z",
  "lastUsedAt": null
}
```

warning

The `clientSecret` (`ocs_…`) is shown exactly once, on creation. Store it somewhere safe — if you lose it, revoke the client and register a new one.

### 2. Exchange for an access token

The token endpoint is **public** — no bearer is required, because the client credentials authenticate the request. It accepts JSON or `application/x-www-form-urlencoded`:

```
curl -X POST https://www.wizchat.com/api/v1/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "occ_xxxxxxxxxxxxxxxx",
    "client_secret": "ocs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  }'
```

```
{
  "access_token": "oat_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "chatbots:read documents:write"
}
```

* Optionally pass `"scope": "chatbots:read"` (space-separated) to request a **subset** of the client's registered scopes.
* Invalid credentials return **`401`**; a malformed request or unsupported grant type returns **`400`**; exceeding the rate limit returns **`429`** with a `Retry-After` header.

### 3. Call the API

Use the access token as a **Bearer** credential — exactly where you would put a `wpk_live_…` key:

```
curl https://www.wizchat.com/api/v1/chatbots \
  -H "Authorization: Bearer oat_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

The token is valid for `expires_in` seconds (currently `3600` — one hour). When it expires, request a new one: the client-credentials grant does **not** issue a refresh token, so just call the token endpoint again.

info

A token that authenticates but lacks the scope an operation requires returns **`403 Forbidden`**, the same as an under-scoped API key. Each operation's required scope is listed on its API-reference page.

### Managing clients

* **List** your clients: `GET /api/v1/oauth/clients`
* **Fetch** one: `GET /api/v1/oauth/clients/{clientId}`
* **Revoke** one: `DELETE /api/v1/oauth/clients/{clientId}` — its tokens stop working immediately.

These endpoints are owner-authenticated and appear in the API reference under the **OAuth** tag.

## Interactive apps: authorization code + PKCE

Interactive clients that act **on a user's behalf** — such as MCP clients like Claude connecting through `claude mcp add` — use the authorization-code grant with PKCE instead of a static secret. At a high level:

1. **Register** a public client dynamically (RFC 7591): `POST /api/v1/oauth/register` with your `redirect_uris`. You receive a public `client_id` (`dyn_…`) and no secret.
2. **Send the user to consent** at the authorization endpoint (`https://www.wizchat.com/oauth/authorize`) with a PKCE `code_challenge` (`S256`) and a scope tier — **`view`** (read-only) or **`manage`** (read + write, including `deploy`). The user signs in and approves.
3. **Exchange the returned code** at `POST /api/v1/oauth/token` (`grant_type=authorization_code`) with your `code_verifier`. You receive an access token (`oat_…`) plus a rotating **refresh token** (`ort_…`, valid about 30 days).
4. **Refresh** with `grant_type=refresh_token`. Refresh tokens rotate on every use; reusing a rotated token revokes the entire family.

info

Authorization-code tokens are bound to the WizChat management MCP endpoint (RFC 8707 resource binding) and this flow is used primarily for MCP-client onboarding. For your own server-to-server integrations, prefer the [client-credentials](#server-to-server-client-credentials) flow above.

You can list and revoke the apps you have authorized this way with the owner-authenticated OAuth *grants* endpoints (`GET` / `DELETE /api/v1/oauth/grants`).

## Credential reference

| Prefix | What it is                              | Lifetime                |
| ------ | --------------------------------------- | ----------------------- |
| `occ_` | OAuth client id (client credentials)    | until revoked           |
| `ocs_` | OAuth client secret — shown once        | until revoked           |
| `oat_` | Access token (Bearer)                   | about 1 hour            |
| `ort_` | Refresh token (authorization code only) | about 30 days, rotating |
| `dyn_` | Public client id (dynamic registration) | until revoked           |

warning

Treat `ocs_…` secrets and `oat_…` / `ort_…` tokens like passwords — never commit them or expose them in client-side code. Secrets and tokens are stored only as hashes, so a lost secret cannot be recovered; rotate by revoking and re-creating.


---

# Quickstart

This guide takes you from zero to your first authenticated call against the WizChat **Management API**.

## 1. Create a Management API key

Management API keys are **personal, scoped, secret** keys with the `wpk_live_…` prefix. You create one from the WizChat dashboard:

1. Open the WizChat dashboard and go to **Settings → API keys**.
2. Click **Create Management API key**.
3. Give it a name and select the [scopes](/management-api/guides/authentication.md) it needs (for example `chatbots:read`).
4. Copy the key — it is shown **only once**.

Store the key in an environment variable rather than hard-coding it:

```
export WIZCHAT_API_KEY="wpk_live_xxxxxxxxxxxxxxxxxxxx"
```

warning

A `wpk_live_…` key is a secret. Never commit it to source control or expose it in client-side code. Treat it like a password.

## 2. List your chatbots with curl

Every request goes to `https://www.wizchat.com` under the `/api/v1` prefix and carries the key as a bearer token:

```
curl https://www.wizchat.com/api/v1/chatbots \
  -H "Authorization: Bearer $WIZCHAT_API_KEY"
```

A successful response is a JSON object with a `chatbots` array — one entry per chatbot you own or created:

```
{
  "chatbots": [
    {
      "id": "abc123",
      "name": "Support Bot",
      "status": "deployed",
      "deployment": {
        "status": "deployed",
        "deploymentUrl": "https://support-bot.wizchat.app",
        "deployedAt": "2026-06-01T12:00:00Z"
      }
    }
  ]
}
```

If you get a `401`, the key is missing or invalid; a `403` means the key is valid but lacks the `chatbots:read` scope. See [Errors & rate limits](/management-api/guides/errors-and-rate-limits.md).

## 3. Create a chatbot

You can create a new chatbot programmatically with `POST /api/v1/chatbots`. Only `name` is required; `description`, `dataRegion` (`"US"` or `"EU"`), `requireAuth`, and `logoUrl` are optional:

```
curl -X POST https://www.wizchat.com/api/v1/chatbots \
  -H "Authorization: Bearer $WIZCHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "My New Bot", "dataRegion": "US"}'
```

The response is a `201` with the new chatbot in `status: "draft"` and `deployment.status: "pending"`. The **first deploy** still requires going through the WizChat dashboard (which provisions the underlying infrastructure). Subsequent redeploys can be triggered via `POST /api/v1/chatbots/{id}/deploy`.

```
{
  "chatbot": {
    "id": "xyz789",
    "name": "My New Bot",
    "status": "draft",
    "deployment": { "status": "pending" }
  }
}
```

Required scope: `chatbots:write`.

## 4. Use an SDK

Both SDKs are generated from the [same OpenAPI document](https://www.wizchat.com/api/v1/openapi.json) that powers this reference, so their types always match the deployed API.

### TypeScript — `@wizchat/management`

```
npm install @wizchat/management
```

```
import { createWizChatClient } from '@wizchat/management';

const wizchat = createWizChatClient({
  apiKey: process.env.WIZCHAT_API_KEY!,
});

const chatbots = await wizchat.listChatbots();
console.log(chatbots.map((c) => c.id));
```

The SDK unwraps the response envelope, so `listChatbots()` returns the array of chatbots directly — not the `{ "chatbots": [...] }` object shown in the raw HTTP response above.

### Python — `wizchat-management`

```
pip install wizchat-management
```

```
import os
from wizchat_management import WizChatClient

with WizChatClient(api_key=os.environ["WIZCHAT_API_KEY"]) as wizchat:
    chatbots = wizchat.list_chatbots()
    print([c.id for c in chatbots])
```

## Next steps

* [Authentication & scopes](/management-api/guides/authentication.md) — the scope model and per-bot lock
* [Config-as-code](/management-api/guides/config-as-code.md) — export, edit, dry-run, and apply a whole chatbot's config
* [API Reference](/management-api/reference/wizchat-management-api.md) — every operation with a "try it" console


---

# Management API (v1)

The **WizChat Management API** is a programmatic control plane for your chatbots. It lets you manage chatbots, documents, website crawls, videos, knowledge scopes, MCP servers, skills, security settings, custom domains, deployments, analytics, and team members — and, with the config-as-code endpoints, treat an entire chatbot's configuration as a single versionable document.

* **Base URL:** `https://www.wizchat.com`
* **Path prefix:** `/api/v1`
* **Auth:** a `wpk_live_…` Management API key sent as `Authorization: Bearer …`
* **Format:** JSON request and response bodies
* **OpenAPI spec:** [`/api/v1/openapi.json`](https://www.wizchat.com/api/v1/openapi.json) (OpenAPI 3.1)

info

This is a different surface from the older [Legacy API guides](/api/authentication.md). The Management API is the current, scoped, config-as-code control plane and is the one you should build against.

## What you can do

| Area               | Endpoints                                                                                                                                    |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| **Chatbots**       | Create, list, get, update, and delete chatbots                                                                                               |
| **Documents**      | Ingest PDFs from a URL; list, get, delete, and manage document privacy / authorized emails; start, list, and detect drift for website crawls |
| **Videos**         | List, get, and delete uploaded videos                                                                                                        |
| **Scopes**         | Read and update knowledge scopes                                                                                                             |
| **MCP Servers**    | Full CRUD plus per-server access control                                                                                                     |
| **Skills**         | Full CRUD for agent skills                                                                                                                   |
| **Security**       | Access protection, external-API config, access lists, telemetry                                                                              |
| **Domains**        | Authorize, deauthorize, and verify custom domains                                                                                            |
| **Deployment**     | Read deployment status and trigger a redeploy                                                                                                |
| **Analytics**      | Read cost and usage analytics                                                                                                                |
| **Config-as-code** | Export an aggregate config document, then apply a desired state                                                                              |
| **Team**           | List the account owner's team members                                                                                                        |

## The config-as-code workflow

The capstone of the API is a GitOps-style loop:

```
GET  /api/v1/chatbots/{id}/config   →  edit the document  →  POST /api/v1/chatbots/{id}/apply
```

`apply` supports a **dry run** (`?dryRun=true`) that returns the change plan without mutating anything, and **prunes** resources that are absent from your document by default. See [Config-as-code](/management-api/guides/config-as-code.md).

## SDKs

Both SDKs are generated from the same OpenAPI document, so they always match the deployed API.

* **TypeScript** — [`@wizchat/management`](https://www.npmjs.com/package/@wizchat/management)
* **Python** — [`wizchat-management`](https://pypi.org/project/wizchat-management/)

## Next steps

* [Quickstart](/management-api/guides/quickstart.md) — make your first call in under five minutes
* [Authentication & scopes](/management-api/guides/authentication.md) — keys, the bearer header, and the scope model
* [Config-as-code](/management-api/guides/config-as-code.md) — export, edit, dry-run, apply
* [Errors & rate limits](/management-api/guides/errors-and-rate-limits.md) — error shape and status codes
* [API Reference](/management-api/reference/wizchat-management-api.md) — every operation, with a "try it" console


---

# Apply a desired-state config document

```
POST 
/api/v1/chatbots/:chatbotId/apply
```

Declarative config-as-code apply. Diffs a desired-state document against the chatbot's CURRENT config and either returns the PLAN (dry-run) or executes it via the shared reconcile services. `prune` defaults to true: array sections (mcpServers, skills, domains) are AUTHORITATIVE — resources present on the chatbot but absent from the document are DELETED. Every delete is surfaced in the dry-run plan before any apply. prune:false = merge-only (create/update, never delete). Only sections present in `spec` are reconciled; absent sections are left untouched (never pruned). Scope model (least-privilege, per present section): dry-run requires the READ scope, apply the WRITE scope, of every section present, PLUS baseline chatbots:read (dry-run) / chatbots:write (apply). Section→scope: core/scopes→chatbots, mcpServers→mcp, skills→skills, accessProtection/externalApi/accessLists/telemetry→security, domains→domains. Execution stops on the FIRST failing op (apply is idempotent, so a stopped apply is recoverable after fixing the offending section); a partial failure returns HTTP 422 with the ops applied so far plus the offending op.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 422
* 429

Dry-run: the computed plan ({ dryRun:true, plan }). Apply (all ops succeeded): { dryRun:false, plan, applied, failed:null, config }.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Partial failure — execution stopped on the first failing op. Body is an ApplyResult with `failed` populated and `applied` listing the ops that succeeded before it. Re-run after fixing the offending section (idempotent).

Too Many Requests — rate limit exceeded


---

# Authorize a custom domain

```
POST 
/api/v1/chatbots/:chatbotId/domains
```

Adds a custom domain to the chatbot's authorized login domain list. Requires a paid plan tier that supports custom domains. On success returns the updated domain status. On failure (the domain authorization call failed) returns 400 with `PublicDomainStatus` (status: `pending_manual`) or a standard `Error` envelope for validation/config failures. Required scope: `domains:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Domain authorized.

Bad Request — either a validation/config error (Error envelope) or a soft-failure where domain authorization failed but manual DNS setup is possible (PublicDomainStatus with status: pending\_manual).

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Start the YouTube connect flow

```
POST 
/api/v1/youtube/connect
```

Begins connecting the caller's YouTube account. Returns an `authorizeUrl` the caller opens in a browser to grant access; the connection is completed by the browser callback. Account-scoped (no chatbot). Required scope: `videos:write`.

## Responses

* 200
* 401
* 403
* 429

The URL to open to authorize the YouTube connection.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Too Many Requests — rate limit exceeded


---

# Create an access-protection key

```
POST 
/api/v1/chatbots/:chatbotId/access-protection/keys
```

Mint a new widget access-protection key. The full plaintext key is returned ONCE in the response body. **Store it immediately — it cannot be retrieved again.** Subsequent reads expose only the `keyPrefix` display hint. Required scope: `security:write`.

## Request

## Responses

* 201
* 400
* 401
* 403
* 404
* 429

Key created. `key` is the one-time plaintext value.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Create a chatbot

```
POST 
/api/v1/chatbots
```

Creates a new chatbot with `status: "draft"` and `deployment.status: "pending"`. Creation does not provision any infrastructure or start a deployment. **The first deploy must be done from the WizChat dashboard**, which provisions the underlying infrastructure; the v1 `/deploy` endpoint only re-deploys a chatbot that has already been deployed once. Restricted API keys (those locked to specific chatbot IDs) cannot create chatbots. Plan limits are enforced transactionally. **Note:** newly created chatbots have no `aiConfig` (no LLM model). Before triggering a deployment, use `POST /api/v1/chatbots/{id}/apply` to set `spec.core.aiConfig.llmModel` and related fields. Required scope: `chatbots:write`.

## Request

## Responses

* 201
* 400
* 401
* 403
* 429

Chatbot created. `chatbot.status` is `"draft"`; `deployment.status` is `"pending"`. First deploy must use the dashboard.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Too Many Requests — rate limit exceeded


---

# Create a scheduled crawl

```
POST 
/api/v1/chatbots/:chatbotId/scheduled-crawls
```

Creates a recurring scheduled crawl that re-ingests the given URLs into the chatbot's knowledge base on the chosen cadence. `dayOfWeek` is required for `weekly`; `dayOfMonth` (1-28) for `monthly`. Limited to 3 schedules per chatbot and 100 URLs per schedule (a violation returns 400). Requires admin-level chatbot access. Required scope: `documents:write`.

## Request

## Responses

* 201
* 400
* 401
* 403
* 404
* 429

Scheduled crawl created.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Create a knowledge scope

```
POST 
/api/v1/chatbots/:chatbotId/scopes
```

Create a single knowledge scope. The scope `id` is derived by slugifying `id` (if given) else `label` (lowercase; `[^a-z0-9_-]` → `-`). Returns 409 if a scope with that id already exists. Unlike PATCH /scopes (which replaces the whole array), this updates one scope in place, so `costLimit`, `authorizedEmails`, and `authorizedDomains` are preserved. Required scope: `chatbots:write`.

## Request

## Responses

* 201
* 400
* 401
* 403
* 404
* 409
* 429

Scope created.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Conflict — a scope with that id already exists.

Too Many Requests — rate limit exceeded


---

# Create an email group

```
POST 
/api/v1/email-groups
```

Creates an email group (name + member emails). Emails are normalized and de-duplicated. Group names must be unique per owner. Required scope: `security:write`.

## Request

## Responses

* 201
* 400
* 401
* 403
* 409
* 429

Group created.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

A group with this name already exists.

Too Many Requests — rate limit exceeded


---

# Create an external-API key

```
POST 
/api/v1/chatbots/:chatbotId/external-api/keys
```

Mint a new external-API key. The full plaintext key is returned ONCE in the response body (`key` field). **Store it immediately — it cannot be retrieved again.** Subsequent reads expose only the `keyPrefix` display hint. Maximum 5 active keys per chatbot. Required scope: `security:write`.

## Request

## Responses

* 201
* 400
* 401
* 403
* 404
* 429

Key created. `key` is the one-time plaintext value.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Create an MCP server

```
POST 
/api/v1/chatbots/:chatbotId/mcp-servers
```

Create a new MCP server configuration for a chatbot. Stdio transport is not supported via the management API (use HTTP transport). Tool discovery is attempted automatically for HTTP servers. OAuth flows, PostgreSQL scan, and metrics are dashboard-only (deferred). Required scope: `mcp:write`.

## Request

## Responses

* 201
* 400
* 401
* 403
* 404
* 429

MCP server created.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Register an OAuth client

```
POST 
/api/v1/oauth/clients
```

Register an OAuth client

## Request

## Responses

* 201
* 400
* 403

Created — secret shown once

Validation error

Not Firebase auth


---

# Issue an access token (client credentials)

```
POST 
/api/v1/oauth/token
```

Public endpoint — no bearer auth required. Exchange `client_id` + `client_secret` for a short-lived access token. Supports `client_credentials` grant type only (RFC 6749 §4.4). Accepts both `application/json` (developer convenience) and `application/x-www-form-urlencoded` (RFC 6749 §4.4.2 standard). Returns `400 invalid_request` for any other Content-Type. Rate-limited: returns `429 rate_limited` + `Retry-After` header when the IP bucket is exceeded.

## Request

## Responses

* 200
* 400
* 401
* 429

Access token

Invalid request, unsupported grant type, or unsupported Content-Type

Invalid client credentials

Too Many Requests — IP rate limit exceeded


---

# Create a skill

```
POST 
/api/v1/chatbots/:chatbotId/skills
```

Create a new skill for a chatbot. Auto-enables the skills feature on first creation. Name must be unique within the chatbot (max 25 skills per chatbot). Required scope: `skills:write`.

## Request

## Responses

* 201
* 400
* 401
* 403
* 404
* 429

Skill created.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Deauthorize a custom domain

```
DELETE 
/api/v1/chatbots/:chatbotId/domains/:domain
```

Removes a custom domain from the chatbot's authorized login domain list. Required scope: `domains:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Domain deauthorized.

Bad Request — either a validation/config error (Error envelope) or a soft-failure where the domain removal failed (PublicDomainStatus with status: removal\_failed, possibly including a warning field).

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Delete a chatbot

```
DELETE 
/api/v1/chatbots/:chatbotId
```

Permanently deletes a chatbot and cascades its cleanup (knowledge base, storage, deployment, and configuration). Requires the chatbot OWNER or a team owner/admin (stricter than edit access). Returns 200 on full deletion, or 207 Multi-Status if the chatbot was removed but some downstream cleanup failed (see `errors`). Returns 409 if a shared resource (e.g. a knowledge base still used by another chatbot) blocks deletion — nothing is deleted in that case. Required scope: `chatbots:write`.

## Request

## Responses

* 200
* 207
* 401
* 403
* 404
* 409
* 429
* 500

Chatbot fully deleted.

Chatbot removed, but some downstream cleanup failed — see `errors`.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Conflict — a shared resource blocks deletion; nothing was deleted.

Too Many Requests — rate limit exceeded

Deletion failed (nothing deleted, or a partial cascade before an error).


---

# Delete chatbot memory data

```
DELETE 
/api/v1/chatbots/:chatbotId/memory-data
```

Permanently deletes the chatbot's graph conversation memory for the given scope. `scope=long-term` removes stored facts + session summaries; `scope=short-term` removes within-session conversation nodes. Destructive and irreversible. Required scope: `chatbots:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Memory data deleted.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Delete a scheduled crawl

```
DELETE 
/api/v1/chatbots/:chatbotId/scheduled-crawls/:scheduleId
```

Deletes a scheduled crawl and its run history. Pass `deleteVectors=true` to also purge the vectors this schedule ingested into the KB. Fails closed: if the vector purge fails, the schedule is NOT deleted (its metadata is preserved so the purge can be retried) and a 502 is returned. Required scope: `documents:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429
* 502

Scheduled crawl deleted.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded

Vector deletion failed — the schedule was NOT deleted (retry, or remove it in the dashboard).


---

# Delete a knowledge scope

```
DELETE 
/api/v1/chatbots/:chatbotId/scopes/:scopeId
```

Remove one knowledge scope from a chatbot. Also unassigns the scope from the knowledge-base tree and any workflows that referenced it. Returns 409 if the scope still has documents/vectors — reassign or delete them in the dashboard first (no destructive document/vector cascade). Required scope: `chatbots:write`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 409
* 429

Scope deleted.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Conflict — the scope still has documents/vectors.

Too Many Requests — rate limit exceeded


---

# Delete a document

```
DELETE 
/api/v1/documents/:documentId
```

Delete a document and all its data (embedding vectors, storage, metadata). Required scope: `documents:write`. `success` is `false` when any cleanup step produced a warning (honest semantics). `warnings` is always present (empty array on clean delete).

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Document deleted.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Delete an email group

```
DELETE 
/api/v1/email-groups/:groupId
```

Delete an email group. Required scope: `security:write`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Group deleted.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Delete an MCP server

```
DELETE 
/api/v1/chatbots/:chatbotId/mcp-servers/:serverId
```

Remove an MCP server from a chatbot. For PostgreSQL servers, the associated schema graph is also deleted (non-fatal on error). Required scope: `mcp:write`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

MCP server deleted.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Revoke an OAuth client

```
DELETE 
/api/v1/oauth/clients/:clientId
```

Revoke an OAuth client

## Request

## Responses

* 200
* 403
* 404

Revoked

Not Firebase auth or not owner

Not found


---

# Delete a lead-delivery channel

```
DELETE 
/api/v1/chatbots/:chatbotId/sales-agent/handoffs/:handoffId
```

Removes a lead-delivery channel. Idempotent — deleting an unknown channel still returns success. Required scope: `chatbots:write`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Channel deleted (or already absent).

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Delete a skill

```
DELETE 
/api/v1/chatbots/:chatbotId/skills/:skillId
```

Remove a skill from a chatbot. Required scope: `skills:write`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Skill deleted.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Delete a video

```
DELETE 
/api/v1/videos/:videoId
```

Delete a video and all its data (embedding vectors, transcript, storage, metadata). Required scope: `videos:write`. `success` is `false` when any cleanup step produced a warning (honest semantics). `warnings` is present when non-empty.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Video deleted.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Trigger a redeploy

```
POST 
/api/v1/chatbots/:chatbotId/deploy
```

Re-runs the production build with the chatbot's CURRENT build-time environment. Runtime config (model, behavior, appearance, prompts, etc.) is read live and does NOT require a deploy. This endpoint does NOT re-sync build-time settings (e.g. chatbot name, requireAuth, region); if you changed a build-time field, use the dashboard redeploy. Long-running operation (up to 5 min). The response is returned immediately with status `deploying`; poll GET /deployment for the final status. If a build exceeds \~60s the status may remain `deploying`; the already-deploying guard clears after \~10 minutes. Required scope: `deploy`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Deployment triggered.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# DSAR-erase a sales-agent lead's PII (destructive)

```
POST 
/api/v1/chatbots/:chatbotId/sales-agent/leads/:leadId/dsar-erase
```

DESTRUCTIVE. GDPR DSAR hard-erase of a single lead's PII: scrubs the encrypted captured-fields envelope, HMAC hashes, and PII-adjacent geo (IP/region/city/timezone) to null while RETAINING the anonymous row (disposition, capturedAt, geo.countryCode) so aggregate metrics stay intact. Idempotent — a repeat erase on an already-erased lead returns 409 and preserves the original piiErasedAt (GDPR Article 17 audit-trail integrity). Owner/admin gated. Required scope: `security:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 409
* 429

PII scrubbed; anonymous row retained.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Lead PII was already erased; the original piiErasedAt is preserved (idempotent no-op).

Too Many Requests — rate limit exceeded


---

# Export sales-agent leads as CSV (with decrypted PII)

```
GET 
/api/v1/chatbots/:chatbotId/sales-agent/leads/export
```

Exports a chatbot's captured sales-agent leads as a CSV, over the requested window and filters. Unlike the metadata-only list, this DECRYPTS the captured contact fields (name/email/phone/company) server-side and includes the coarse geo columns. Cells are CSV-injection-hardened (a leading =+\@-\t\r is escaped with a single quote). Each row carries a `pii_decrypt_status` (ok / failed / erased / none). Capped at 5000 rows after filters — a larger result returns 413 (narrow the window / filters). Owner/admin gated (bulk PII decrypt). Required scope: `security:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 413
* 429

CSV of the leads slice with decrypted PII + per-row decrypt status.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Export exceeds the 5000-row per-export cap (after filters). Narrow the window/filters.

Too Many Requests — rate limit exceeded


---

# Get access lists

```
GET 
/api/v1/chatbots/:chatbotId/access-lists
```

Returns the authorizedEmails, authorizedDomains, and allowedEmbedDomains lists for a chatbot. Unlike the PublicChatbot listing (which collapses these to counts for privacy), this endpoint returns the full rosters for headless config-as-code use cases. Requires admin-level access (`canManageAccess`). Required scope: `security:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Access lists.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get access-protection config

```
GET 
/api/v1/chatbots/:chatbotId/access-protection
```

Returns the widget access-protection configuration for a chatbot. jwtConfig.secret is collapsed to a boolean `hasSecret` flag — the raw secret is never returned. Key hashes are stripped; only safe key metadata (id, label, keyPrefix, status, usageCount, timestamps) is returned. Required scope: `security:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Access-protection configuration.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get workspace usage overview

```
GET 
/api/v1/analytics/aggregate
```

Owner-level (NOT chatbot-scoped) 7-day cross-chatbot usage overview: per-day query trend + total queries, total chatbots, and deployed-chatbot count. Loops all chatbots the caller owns. FULL-ACCESS CALLER REQUIRED: a chatbot-scoped key (allowedChatbotIds set) receives 403 `chatbot_not_in_key_scope` — it cannot read workspace-wide totals. The dashboard `success` flag and `debug` block are never emitted. Tier-gated (usage, starter+). Required scope: `analytics:read`.

## Request

## Responses

* 200
* 401
* 403
* 429

Workspace-level usage overview for the calling owner.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Too Many Requests — rate limit exceeded


---

# Get a chatbot

```
GET 
/api/v1/chatbots/:chatbotId
```

Returns a single chatbot by ID. Required scope: `chatbots:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Chatbot found.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Export aggregate config

```
GET 
/api/v1/chatbots/:chatbotId/config
```

Assembles the chatbot's CURRENT configuration into a single canonical desired-state document (the "export current config" / drift baseline for the declarative apply). Reuses every section serializer; never returns secrets — accessProtection.jwtConfig.secret is collapsed to hasSecret, and the access-protection / external-api key arrays are excluded entirely. Baseline scope: `chatbots:read`. Per-section read-scope gating (least-privilege): a section is OMITTED from `spec` when the caller's key lacks its read scope, and listed in `_omittedSections` (core/scopes→chatbots:read, mcpServers→mcp:read, skills→skills:read, accessProtection/externalApi/accessLists/telemetry→security:read, domains→domains:read). Firebase callers hold all scopes.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Assembled desired-state config document.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get conversation-intelligence analytics

```
GET 
/api/v1/chatbots/:chatbotId/analytics/conversations
```

Conversation-intelligence aggregates for a single chatbot at dashboard parity: top topics, knowledge gaps, language distribution, scope usage, hourly heatmap, conversation depth. topTopics/knowledgeGaps titles are k-anonymity-gated (≥3 distinct sessions) and exposed exactly as the dashboard shows the owner. No raw session or user identifiers are ever returned — only aggregated, anonymized results. Tier-gated (pro-plus+). Required scope: `analytics:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Conversation analytics for the chatbot.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get cost analytics

```
GET 
/api/v1/chatbots/:chatbotId/analytics/cost
```

Returns cost analytics for a single chatbot over the requested period. Tier-gated: the plan's analytics day-cap is applied automatically; a 403 is returned when the plan does not include cost analytics access. Combines completed-day cost rollups with the current day's partial usage. No PII — ownerEmail, userId, and per-other-chatbot breakdowns are always stripped. Required scope: `analytics:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Cost analytics for the chatbot.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Detect website crawl drift

```
GET 
/api/v1/chatbots/:chatbotId/crawls/drift
```

Compares a chatbot's crawled URL set for a domain against the domain's CURRENT sitemap.xml, reporting pages ADDED (in the sitemap but not yet crawled) and REMOVED (crawled but no longer in the sitemap). The domain MUST be one the chatbot has already crawled (SSRF-bounded). Content changes on already-crawled pages are NOT detected — no per-page baseline is stored for existing crawls. Required scope: `documents:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Crawl-drift report for the domain.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get deployment status

```
GET 
/api/v1/chatbots/:chatbotId/deployment
```

Returns the deployment status for a chatbot. Internal hosting and credential identifiers are never included in the response. Required scope: `chatbots:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Deployment status.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# List authorized domains

```
GET 
/api/v1/chatbots/:chatbotId/domains
```

Returns the authorized login domains and custom domain status for a chatbot. Internal IDs and auth tokens are stripped. Required scope: `domains:read`. Requires admin-level access (`canManageAccess`); callers with only editor access will receive 404 here.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Domain status.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get infrastructure analytics

```
GET 
/api/v1/chatbots/:chatbotId/analytics/infra
```

Infrastructure signals for a single chatbot at dashboard parity: latency and TTFT percentiles + histograms, region split, deploy-version timeline (regression detection), and warm-vs-cold ratio. deploymentVersion and dataRegion are owner-facing operational metadata, not user machine ids. Tier-gated (pro+). Required scope: `analytics:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Infrastructure analytics for the chatbot.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get agent quality analytics

```
GET 
/api/v1/chatbots/:chatbotId/analytics/quality
```

Agent behavior & quality aggregates for a single chatbot at dashboard parity (aggregate metrics only — no raw traces, no PII). Answer-quality breakdown, agent decisions, average latency, and MCP tool-error tracking. The chatbot scope is derived server-side from the authenticated owner — no email parameter is accepted. Tier-gated (pro-plus+). Required scope: `analytics:read`. `answerRate` is `number | null`, computed only over turns the chatbot classified; it is `null` (distinct from a genuine 0%) whenever `answerRateTracked` is false — i.e. no classified turns in the window, or the metrics were temporarily unavailable. Consumers must handle `null` before arithmetic and can read `answerRateTracked` to explain the absence.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Quality analytics for the chatbot.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get query-log analytics

```
GET 
/api/v1/chatbots/:chatbotId/analytics/queries
```

Row-level query log for a single chatbot at dashboard parity — the owner's own conversation log. Question and answer text are PII-redacted at insert and the end-user's email is masked. Internal session, row, and network identifiers are never emitted. Each row's sources\[] is reshaped to a public citation {title, source, pdfSource} — the raw retrieved chunk text and all other internal source metadata are dropped. Tier-gated (starter+). Required scope: `analytics:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Query-log rows + feedback breakdown for the chatbot.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get a scheduled crawl

```
GET 
/api/v1/chatbots/:chatbotId/scheduled-crawls/:scheduleId
```

Returns one scheduled crawl including its recent run history. No PII (authorized emails/groups are returned only as counts). Required scope: `documents:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

The scheduled crawl with recent runs.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get a knowledge scope

```
GET 
/api/v1/chatbots/:chatbotId/scopes/:scopeId
```

Returns a single knowledge scope by id. Billing detail (costLimit) is stripped and PII rosters (emails/domains) are collapsed to counts. Required scope: `chatbots:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Scope found.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get knowledge scopes

```
GET 
/api/v1/chatbots/:chatbotId/scopes
```

Returns the knowledge-scope configuration for a chatbot. Required scope: `chatbots:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Scopes configuration.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get search / retrieval-quality analytics

```
GET 
/api/v1/chatbots/:chatbotId/analytics/search
```

Retrieval-effectiveness aggregates for a single chatbot at dashboard parity: score histogram, per-scope retrieval quality, skip-RAG ratio, sources-per-query, and weakest queries. weakestQueries titles are k-anonymity-gated (≥3 sessions) and exposed exactly as the dashboard shows the owner. Tier-gated (pro+). Required scope: `analytics:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Search analytics for the chatbot.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get token-efficiency analytics

```
GET 
/api/v1/chatbots/:chatbotId/analytics/tokens
```

Token-usage & latency aggregates for a single chatbot at dashboard parity: total/avg/percentile tokens, model mix, context-growth buckets, and TTFT-by-model. Aggregate-only (no raw text). Tier-gated (pro+). Required scope: `analytics:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Token analytics for the chatbot.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get video-transcription analytics

```
GET 
/api/v1/chatbots/:chatbotId/analytics/transcription
```

Video-transcription aggregates for a single chatbot at dashboard parity: totals (videos, duration, cost, char/word counts) and breakdowns by service, language, platform, and model. Per-other-chatbot breakdowns are stripped. NOT tier-gated — matches the ungated dashboard route (auth + `analytics:read` + ownership only). All-time totals; no `days` parameter is applied. Required scope: `analytics:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Transcription analytics for the chatbot.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get usage analytics

```
GET 
/api/v1/chatbots/:chatbotId/analytics/usage
```

Returns usage analytics for a single chatbot. tokenCount and queryCount are derived from cost rollup data (same tier-gating as cost analytics). Note: queryCount counts recorded cost/usage events (model calls — embeddings, completions, reranks, tool calls — plus other cost events), not user Q\&A turns, so expect it to run several × the conversations/quality turn counts. documentCount is the current KB size (total docs in user\_documents — not time-windowed). No PII. Required scope: `analytics:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Usage analytics for the chatbot.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get a document

```
GET 
/api/v1/documents/:documentId
```

Returns a single document by ID (IDOR-guarded). Required scope: `documents:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Document found.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get an email group

```
GET 
/api/v1/email-groups/:groupId
```

Fetch one of the owner's email groups by id. Required scope: `security:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

The email group.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get external-API config

```
GET 
/api/v1/chatbots/:chatbotId/external-api
```

Returns the external-API configuration for a chatbot. Key hashes are stripped; only safe key metadata is returned. Required scope: `security:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

External-API configuration.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get an MCP server

```
GET 
/api/v1/chatbots/:chatbotId/mcp-servers/:serverId
```

Returns a single MCP server by ID. Credentials, headers, and access-key hashes are stripped. Required scope: `mcp:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

MCP server found.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get MCP server access control

```
GET 
/api/v1/chatbots/:chatbotId/mcp-servers/:serverId/access
```

Returns the access-control settings for an MCP server: authorizedEmails, authorizedGroups, isPublic, accessKeyHint. The access-key hash is never returned. Required scope: `mcp:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Access control settings.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get an OAuth client

```
GET 
/api/v1/oauth/clients/:clientId
```

Get an OAuth client

## Request

## Responses

* 200
* 403
* 404

Client

Not Firebase auth or not owner

Not found


---

# Get the Sales Agent configuration

```
GET 
/api/v1/chatbots/:chatbotId/sales-agent
```

Returns the chatbot's Sales Agent configuration (persona, prompt slots/overlay, model override, lead-capture fields, guardrails, and sales-trigger settings), plus `salesAgentEnabled` — whether the agent is live at runtime. Returns an empty config with `salesAgentEnabled:false` when no agent has been configured yet. Never returns access-key material or internal fields. Required scope: `chatbots:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

The Sales Agent configuration.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get a sales-agent lead (with decrypted PII)

```
GET 
/api/v1/chatbots/:chatbotId/sales-agent/leads/:leadId
```

Reads a single captured sales-agent lead WITH decrypted PII (the audit-logged per-lead detail path). Returns the metadata the list returns PLUS the decrypted contact `pii` (name/email/phone/company/custom), the coarse geo detail (countryCode + region/city/timezone), and a `decryptError` string when server-side decrypt failed (the raw envelope, HMAC hashes, and IP hash are NEVER emitted). 404 for a missing, soft-deleted, or unauthorized lead (IDOR-safe). Owner/admin gated (PII reveal). Required scope: `security:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

The lead detail with decrypted PII.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get a skill

```
GET 
/api/v1/chatbots/:chatbotId/skills/:skillId
```

Returns a single skill by ID. Required scope: `skills:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Skill found.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get telemetry config

```
GET 
/api/v1/chatbots/:chatbotId/telemetry
```

Returns the telemetry configuration for a chatbot. Fields: level (anonymized|identified|full), endUserOptOutAllowed, pseudonymizeIdentifiers, retentionMonths. Required scope: `security:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Telemetry configuration.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get daily API quota status

```
GET 
/api/v1/usage
```

Get daily API quota status

## Responses

* 200
* 401
* 429

Quota status

Invalid or missing API key

Quota exceeded


---

# Get a video

```
GET 
/api/v1/videos/:videoId
```

Returns a single video by ID (IDOR-guarded). Required scope: `videos:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Video found.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Get YouTube connection status

```
GET 
/api/v1/youtube/status
```

Reports whether the caller's YouTube account is connected, and the connected channel title when available. Never returns tokens. Account-scoped (no chatbot). Required scope: `videos:read`.

## Responses

* 200
* 401
* 403
* 429

The caller's YouTube connection status.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Too Many Requests — rate limit exceeded


---

# Ingest a PDF document from a URL

```
POST 
/api/v1/chatbots/:chatbotId/documents
```

Ingests a PDF into the chatbot's knowledge base by fetching it from a PUBLIC URL (SSRF-safe: http(s) only, public-IP-pinned + rebind-safe, size- and time-bounded), then running the standard extract → chunk → embed pipeline. This endpoint is PDF-only (the fileName / URL must end in .pdf); to ingest a local file, host it at a public URL first. Asynchronous — processing continues in the background; poll GET /documents for status. Required scope: `documents:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 413
* 415
* 429

Document accepted; processing started in the background.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

File exceeds the plan upload limit or account storage limit.

Unsupported file type (this endpoint ingests PDF only).

Too Many Requests — rate limit exceeded


---

# Add text or a .txt/.md file to the knowledge base

```
POST 
/api/v1/chatbots/:chatbotId/text
```

Adds text or Markdown straight into the chatbot's knowledge base — no file upload needed. Send a single `text` string (with an optional `fileName`) or a batch of `items` (for example curated question/answer pairs). Each entry becomes its own searchable, listable, deletable knowledge source. Processing is synchronous — the response reports per-entry results. Long entries are split automatically. Required scope: `documents:write`.

## Request

## Responses

* 200
* 207
* 400
* 401
* 403
* 404
* 413
* 429
* 500

All entries were added.

Partial success — some entries were added and some failed (see documents\[].success).

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

An entry or the batch exceeds the size limit, or the account storage limit.

Too Many Requests — rate limit exceeded

Every entry failed to be added (see documents\[].error for per-entry reasons).


---

# Ingest YouTube videos into a chatbot

```
POST 
/api/v1/chatbots/:chatbotId/youtube/videos
```

Ingests videos from the caller's connected YouTube channel into the chatbot's knowledge base. Videos already in the knowledge base are skipped (`skippedAlreadyImported`). Returns a `jobId` for the ingest. Required scope: `videos:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Ingest accepted.

Bad Request — invalid input

Unauthorized, or the YouTube connection needs to be re-established (reconnect required).

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Invite a deployed user

```
POST 
/api/v1/chatbots/:chatbotId/users
```

Invites an end-user to the chatbot by email; the user receives a verification email. Required scope: `security:write`.

## Request

## Responses

* 201
* 400
* 401
* 403
* 404
* 429

Invitation sent.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# List access-protection keys

```
GET 
/api/v1/chatbots/:chatbotId/access-protection/keys
```

Returns all access-protection keys for a chatbot. Key hashes are stripped; only safe metadata (id, label, keyPrefix, status, usageCount, timestamps) is returned. Required scope: `security:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

List of access-protection keys.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# List a chatbot's transcript-correction review queue

```
GET 
/api/v1/chatbots/:chatbotId/corrections
```

Returns every transcript correction across the chatbot's videos as one needs-review-first queue, with per-status totals. Never returns the transcript body or the resolver identity. Required scope: `documents:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

The chatbot's correction review queue with per-status totals.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# List website crawls

```
GET 
/api/v1/chatbots/:chatbotId/crawls
```

Lists the chatbot's website crawls (most recent first), with live progress. Non-terminal crawls are refreshed against the crawler on read (an API-initiated crawl has no dashboard poller, so this read is what advances its status). Pass `crawlId` to fetch a single crawl. No PII (authorized emails/groups are not returned). Required scope: `documents:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Website crawls for the chatbot (metadata + live progress).

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# List sales-agent leads (metadata only)

```
GET 
/api/v1/chatbots/:chatbotId/sales-agent/leads
```

Lists a chatbot's captured sales-agent leads over the requested window. Returns METADATA ONLY — disposition, handoff status, country code, timestamps, coarse attribution, and disposition/country aggregates. NO decrypted PII (name/email/phone/custom capture fields, city, region, IP) is exposed by this list. Owner/admin gated (mirrors the dashboard leads view — CRM-sensitive disposition labels are not readable by domain-grant viewers). Required scope: `analytics:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Lead metadata list + disposition/country aggregates for the chatbot.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# List scheduled crawls

```
GET 
/api/v1/chatbots/:chatbotId/scheduled-crawls
```

Lists the chatbot's scheduled (recurring) website crawls, most recent first. A scheduled crawl periodically re-ingests a set of URLs into the KB on an hourly/daily/weekly/monthly cadence. No PII (authorized emails/groups are returned only as counts). Required scope: `documents:read`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Scheduled crawls for the chatbot.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# List deployed users

```
GET 
/api/v1/chatbots/:chatbotId/users
```

Lists the chatbot's deployed (invited) end-users — each user's email, display name, role, status, email-verification flag, and timestamps. Requires admin-level chatbot access. Required scope: `security:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Deployed users for the chatbot.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# List chatbots

```
GET 
/api/v1/chatbots
```

Returns the chatbots you own, created on behalf of a team owner, were granted admin access to, or that are shared with a team you own or administer. Required scope: `chatbots:read`. Chatbots shared with a team where you are a plain member, and chatbots where you have only viewer/editor (non-admin) access, are not listed here — access those directly by id via `GET` / `PATCH /api/v1/chatbots/{chatbotId}`.

## Responses

* 200
* 401
* 403
* 429

List of chatbots owned by or created by the authenticated user.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Too Many Requests — rate limit exceeded


---

# List documents

```
GET 
/api/v1/documents
```

Returns all documents owned by the authenticated user. Required scope: `documents:read`. Optional `?chatbotId=` filter (restricted keys are scoped to their allowed chatbots automatically). Lists only documents you own, even when `chatbotId` is supplied; a chatbot's full knowledge base is not enumerated here.

## Request

## Responses

* 200
* 401
* 403
* 429

List of documents.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Too Many Requests — rate limit exceeded


---

# List email groups

```
GET 
/api/v1/email-groups
```

Lists the owner's email groups (reusable email allow-lists shared across their chatbots). Pass `includeUsage=true` to include how many documents use each group. Email groups are OWNER-scoped, not per-chatbot: a key restricted to specific chatbots still has full access to all of the owner's email groups. Required scope: `security:read`.

## Request

## Responses

* 200
* 401
* 403
* 429

The owner's email groups.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Too Many Requests — rate limit exceeded


---

# List external-API keys

```
GET 
/api/v1/chatbots/:chatbotId/external-api/keys
```

Returns all external-API keys for a chatbot. Key hashes are stripped; only safe metadata is returned. Required scope: `security:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

List of external-API keys.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# List MCP servers

```
GET 
/api/v1/chatbots/:chatbotId/mcp-servers
```

Returns all MCP servers configured for a chatbot. Credentials, headers, env vars, and access-key hashes are stripped. Email/group rosters are collapsed to counts. OAuth flows, PostgreSQL scan, and metrics are dashboard-only (not yet in v1 API). Required scope: `mcp:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

List of MCP servers.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# List OAuth clients

```
GET 
/api/v1/oauth/clients
```

List OAuth clients registered by the authenticated user. Requires Firebase authentication.

## Responses

* 200
* 401
* 403

Client list

Unauthenticated

Not Firebase auth


---

# List lead-delivery channels

```
GET 
/api/v1/chatbots/:chatbotId/sales-agent/handoffs
```

Lists the Sales Agent's lead-delivery (hand-off) channels. Each channel reports its recipients/routing and whether a sending secret is configured (`hasSecret`/`hasWebhookHmac`) without ever exposing the secret itself. Creating a channel is done from the dashboard (it is inseparable from storing the sending secret). Required scope: `chatbots:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

The configured lead-delivery channels.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# List skills

```
GET 
/api/v1/chatbots/:chatbotId/skills
```

Returns all skills configured for a chatbot. Required scope: `skills:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

List of skills.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# List the owner's team members

```
GET 
/api/v1/team
```

Returns the caller's team/workspace + its members (userId, email, displayName, role, status, invite/accept/last-active timestamps). Workspace-level — no chatbotId. Returns the team from the caller's OWN membership (their active team), so a caller can only read a team they belong to (never cross-tenant); a member/admin sees the roster, matching the dashboard. Returns team:null for a solo user. Internal fields (permissionOverrides, invitedBy) are dropped. Required scope: `security:read`.

## Responses

* 200
* 401
* 429

The owner's team + members (team:null if none).

Unauthorized — missing or invalid API key

Too Many Requests — rate limit exceeded


---

# List a video's transcript corrections

```
GET 
/api/v1/videos/:videoId/corrections
```

Returns a page of transcript corrections for a single video (IDOR-guarded), each with a short context snippet from the surrounding transcript so a caller can judge the most probable word. Never returns the full transcript body or the resolver identity. Required scope: `documents:read`.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

A page of corrections for the video.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# List videos

```
GET 
/api/v1/videos
```

Returns all videos owned by the authenticated user. Required scope: `videos:read`. Optional `?chatbotId=` filter (restricted keys are scoped to their allowed chatbots automatically). Lists only videos you own, even when `chatbotId` is supplied; a chatbot's full knowledge base is not enumerated here.

## Request

## Responses

* 200
* 401
* 403
* 429

List of videos.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Too Many Requests — rate limit exceeded


---

# List the caller's YouTube videos

```
GET 
/api/v1/youtube/videos
```

Lists videos from the caller's own connected YouTube channel. Without `search`, returns one page plus a `nextPageToken`; with `search`, scans the whole channel by title. Returns `connected:false` as data (not an error) when no channel is connected. Exposes only public video metadata — never tokens. Account-scoped (no chatbot). Required scope: `videos:read`.

## Request

## Responses

* 200
* 401
* 403
* 429

A page of the caller's channel videos (or connected:false when not connected).

Unauthorized, or the YouTube connection needs to be re-established (reconnect required).

Forbidden — key lacks required scope

Rate limit or YouTube API quota exceeded.


---

# Update access lists

```
PATCH 
/api/v1/chatbots/:chatbotId/access-lists
```

Replace one or more access lists. Each supplied list is replaced wholesale; omitted lists are unchanged. At least one list must be provided. Requires admin-level access (`canManageAccess`). Required scope: `security:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Access lists updated.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Update access-protection config

```
PATCH 
/api/v1/chatbots/:chatbotId/access-protection
```

Update access-protection enabled flag and/or jwtConfig (enabled, emailClaim, secret). If a new JWT secret is provided it is encrypted at rest; the plaintext is never stored. Returns the updated config (secret collapsed to hasSecret). Required scope: `security:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Access-protection configuration updated.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Update a chatbot

```
PATCH 
/api/v1/chatbots/:chatbotId
```

Partial update of chatbot configuration fields. Only top-level scalar/object fields accepted; nested arrays are replaced wholesale (not merged). Required scope: `chatbots:write`. The response `chatbot` field may be `null` if the document was deleted concurrently during the update (write-then-read race).

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Update applied. `chatbot` is `null` only on a concurrent-delete race.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Update a knowledge scope

```
PATCH 
/api/v1/chatbots/:chatbotId/scopes/:scopeId
```

Partial update of ONE knowledge scope. Only the supplied fields change; absent fields (including `costLimit`, `authorizedEmails`, `authorizedDomains`) are preserved server-side. `null` on an optional field clears it; `[]` clears an array; `costLimit` is replaced atomically. `id` is immutable (ignored). Required scope: `chatbots:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Scope updated.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Update knowledge scopes

```
PATCH 
/api/v1/chatbots/:chatbotId/scopes
```

Partial update of the knowledge-scope configuration. Write set matches GET read set exactly: `scopes`, `uiTree`, `slotWorkflows`, `defaultSlotId`, `defaultScopeLabel`, `showDefaultScopeInSelector`. Unknown fields are ignored. Legacy scope fields (knowledgeScopes, defaultScopeId, scopeRelationships, scopeCanvasLayout, scopeWorkflows, activeScopeWorkflowId) are not managed via this endpoint. Required scope: `chatbots:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Scopes updated. Returns refreshed scopes payload.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Update external-API config

```
PATCH 
/api/v1/chatbots/:chatbotId/external-api
```

Update the external-API enabled flag and/or rate limit. Required scope: `security:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

External-API configuration updated.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Update an MCP server

```
PATCH 
/api/v1/chatbots/:chatbotId/mcp-servers/:serverId
```

Partial update of an MCP server configuration. Supports: enabled toggle, modelOverride, credential update, tool re-discovery, accessKeyAction (generate/clear), executionMode, allowUiResources, allowLlmCompletion. OAuth flows, PostgreSQL scan, and metrics are dashboard-only (deferred). Required scope: `mcp:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

MCP server updated.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Update a skill

```
PATCH 
/api/v1/chatbots/:chatbotId/skills/:skillId
```

Partial update of a skill. Can update: name, description, body, enabled, mode, linkedServerIds, linkedAgentIds. Immutable fields (id, createdAt, source, sourceServerId) are ignored in the request body. Name must remain unique within the chatbot. Required scope: `skills:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Skill updated.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Replace authorized email list

```
PUT 
/api/v1/documents/:documentId/authorized-emails
```

Replace the authorized email list for a document. Required scope: `documents:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Authorized emails updated.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Update MCP server access control

```
PUT 
/api/v1/chatbots/:chatbotId/mcp-servers/:serverId/access
```

Replace the access-control settings for an MCP server. Supports: isPublic, authorizedEmails, authorizedGroups, and accessKeyAction. When accessKeyAction=generate a one-time plaintext accessKey is returned. Required scope: `mcp:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Access control updated.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Replace telemetry config

```
PUT 
/api/v1/chatbots/:chatbotId/telemetry
```

Replace the telemetry configuration for a chatbot. All four fields are required. When `containsSensitiveData` is true on the chatbot, `level` must be "anonymized" and `endUserOptOutAllowed` will be forced to false. Required scope: `security:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Telemetry configuration updated.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Revoke a deployed user

```
DELETE 
/api/v1/chatbots/:chatbotId/users
```

Revokes a deployed user's access to the chatbot (disables their account). Required scope: `security:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

User access revoked.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Resolve a transcript correction

```
PATCH 
/api/v1/videos/:videoId/corrections
```

Resolves a single correction on a video (IDOR-guarded): accept a suggested/candidate word, reject it, apply custom text, or undo a previous resolution. Accepting or applying custom text rebuilds the transcript and re-embeds it in the background. Required scope: `documents:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Correction resolved.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Revoke an access-protection key

```
DELETE 
/api/v1/chatbots/:chatbotId/access-protection/keys/:keyId
```

Revoke (soft-delete) an access-protection key. Revoked keys are immediately rejected; they remain in the list with status=revoked for audit purposes. Required scope: `security:write`.

Returns `{ id, status: "revoked", revokedAt }` on success.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Key revoked.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Revoke an external-API key

```
DELETE 
/api/v1/chatbots/:chatbotId/external-api/keys/:keyId
```

Revoke (soft-delete) an external-API key. Revoked keys are immediately rejected. Required scope: `security:write`.

Returns `{ id, status: "revoked", revokedAt }` on success.

## Request

## Responses

* 200
* 401
* 403
* 404
* 429

Key revoked.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Start a website crawl

```
POST 
/api/v1/chatbots/:chatbotId/crawls
```

Crawls one or more website URLs into the chatbot's knowledge base (embedded as searchable vectors), mirroring the dashboard website-crawl flow. Provide a single `url` or a `urls` array (max 100; the App batches into ≤10-per-request worker calls). Asynchronous — returns 202 with a crawlId + jobId; poll `GET /crawls` to track progress. Refuses a second in-flight crawl for the same domain + version (409). Requires admin-level chatbot access (owner / team admin / per-chatbot admin) — plain team editors cannot crawl via this API. Required scope: `documents:write`.

## Request

## Responses

* 202
* 400
* 401
* 403
* 404
* 409
* 429

Crawl accepted and dispatched.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

A crawl for this domain + version is already in progress.

Too Many Requests — rate limit exceeded


---

# Update a scheduled crawl

```
PATCH 
/api/v1/chatbots/:chatbotId/scheduled-crawls/:scheduleId
```

Updates a scheduled crawl. Any subset of the mutable fields may be provided; at least one is required. Changing the cadence recalculates the next run time. Required scope: `documents:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Scheduled crawl updated.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Update chatbot runtime settings

```
PATCH 
/api/v1/chatbots/:chatbotId/settings
```

Updates the chatbot's runtime toggles: web search, unanswered-question tracking, long-term conversation memory, and short-term memory strategy. Mirrors the dashboard settings screen. Enabling long-term memory requires a Pro (or higher) plan AND authentication-required access. Disabling long-term memory, or switching the memory strategy away from 'graph', permanently deletes the stored memory and therefore requires `confirmDelete: true`. Only provided fields change; at least one must be present. Required scope: `chatbots:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Settings applied.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Update document privacy

```
PUT 
/api/v1/documents/:documentId/privacy
```

Update the privacy/access level of a document. Required scope: `documents:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Privacy updated.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Update an email group

```
PUT 
/api/v1/email-groups/:groupId
```

Update an email group's name and/or member emails (provide at least one). Required scope: `security:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 409
* 429

Group updated.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

A group with this name already exists.

Too Many Requests — rate limit exceeded


---

# Update the Sales Agent configuration

```
PATCH 
/api/v1/chatbots/:chatbotId/sales-agent
```

Upserts the Sales Agent configuration. The agent doc is created on the first update (`created:true`). Only known config fields are applied; unknown fields are ignored. Configuring the agent does not enable it at runtime — enablement is a separate control. Required scope: `chatbots:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Configuration applied.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

# Update a lead-delivery channel

```
PATCH 
/api/v1/chatbots/:chatbotId/sales-agent/handoffs/:handoffId
```

Updates an existing lead-delivery channel (recipients, routing mode, verified sender, webhook URL, included fields, enable/disable). The sending secret cannot be set here — it is managed from the dashboard, and enabling a channel requires its secret to already exist. Required scope: `chatbots:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 422
* 429

Channel updated.

Bad Request — invalid input

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Validation failed — see `error.details.errors` for per-field messages.

Too Many Requests — rate limit exceeded


---

# Verify domain DNS

```
POST 
/api/v1/chatbots/:chatbotId/domains/:domain/verify
```

Triggers a DNS verification check for the given domain. Returns `verified: true` when DNS is correctly configured; `verified: false` with a pending message when DNS is not yet propagated. Required scope: `domains:write`.

## Request

## Responses

* 200
* 400
* 401
* 403
* 404
* 429

Verification result.

Bad Request — either a validation/config error (Error envelope) or a soft-failure (e.g. domain\_not\_configured, no active deployment) where the response may include the verification result shape ({verified, domain, message}) or a standard Error envelope.

Unauthorized — missing or invalid API key

Forbidden — key lacks required scope

Not Found

Too Many Requests — rate limit exceeded


---

Version: 1.0.0

Export

* [OpenAPI Spec](https://www.wizchat.com/api/v1/openapi.json)

# WizChat Management API

Programmatic control plane for WizChat chatbots. Authenticate with a `wpk_live_…` Management API key or a Firebase ID token. All endpoints are scoped — see the `x-scope` extension on each operation.

## Authentication

* HTTP: Bearer Auth

A `wpk_live_…` Management API key issued via the WizChat dashboard, or a Firebase ID token for owner-authenticated requests.

| Security Scheme Type:      | http         |
| -------------------------- | ------------ |
| HTTP Authorization Scheme: | bearer       |
| Bearer format:             | wpk\_live\_… |


---

# Access Control

Manage who can access what in WizChat.

## Access Control Model

WizChat uses Role-Based Access Control (RBAC) at multiple levels:

1. **Account level** - Who can access your account
2. **Team level** - Who can access team resources
3. **Chatbot level** - Who can access specific chatbots
4. **Document level** - Who can access specific documents
5. **MCP server level** - Who can use specific integrations
6. **Metric level** - Who can see specific dashboard metrics

## Account Access

### Single Sign-On (SSO)

Business plans can enable SSO:

* SAML 2.0
* Google Workspace
* Microsoft Azure AD
* Okta

### Multi-Factor Authentication (MFA)

Enable MFA for additional security:

1. Go to **"Profile" > "Security"**
2. Click **"Enable MFA"**
3. Scan QR code with authenticator app
4. Enter verification code
5. Save backup codes



## Team Access

See [Roles & Permissions](/teams/roles-permissions.md) for details.

| Role   | Access Level          |
| ------ | --------------------- |
| Owner  | Full access, billing  |
| Admin  | Manage team, chatbots |
| Member | Use shared chatbots   |

## Chatbot Access

Control who can access each chatbot:

| Level           | Who                    |
| --------------- | ---------------------- |
| Owner only      | Just the chatbot owner |
| Team            | All team members       |
| Specific people | Invited individuals    |

See [Sharing Chatbots](/teams/sharing.md) for details.

## Document Access

Control access to individual documents:

| Level         | Description              |
| ------------- | ------------------------ |
| Public        | All chatbot users        |
| Authenticated | Logged-in users only     |
| Restricted    | Specific email addresses |

See [Document Access Control](/knowledge-base/access-control.md) for details.

## Domain Restrictions

Restrict chatbot access to users from specific email domains:

1. Open your chatbot
2. Go to the **"Settings"** tab
3. Open **"Manage Access"**
4. Add authorized email domains

| Example Domain            | Who Can Access                      |
| ------------------------- | ----------------------------------- |
| `acme.com`                | Only `@acme.com` email addresses    |
| `acme.com`, `partner.org` | Both `@acme.com` and `@partner.org` |

See [Access Modes - Domain Restrictions](/chatbot-users/access-modes.md#domain-based-access-restrictions) for details.

## MCP Server Access

Control which chatbot users can use each MCP integration:

| Level      | Description                          |
| ---------- | ------------------------------------ |
| Public     | All chatbot users can use the server |
| Restricted | Only specific users or email groups  |

See [MCP Overview](/integrations/mcp/overview.md) for details.

## Metric Access

Control which chatbot users can see individual dashboard metrics:

| Level            | Description                         |
| ---------------- | ----------------------------------- |
| Public (default) | All chatbot users see the metric    |
| Restricted       | Only specific users or email groups |

Restricted metrics are silently hidden from unauthorized users — they simply don't appear on the dashboard.

See [PostgreSQL Metrics - Access Control](/integrations/postgresql.md#metric-access-control) for details.

## API Access

### API Key Permissions

When creating API keys, set permissions:

* Read-only
* Read-write
* Full access

### IP Allowlisting

Restrict API access to specific IPs:

1. Go to **"Settings" > "API"**
2. Click **"IP Restrictions"**
3. Add allowed IP addresses
4. Click **"Save"**



## Session Management

### Active Sessions

View and manage active sessions:

1. Go to **"Profile" > "Security"**
2. Click **"Active Sessions"**
3. See all logged-in devices
4. Revoke sessions as needed

### Session Timeout

Configure session timeout:

* Default: 30 days
* Configurable per account
* Immediate logout option

## Audit Trail

Business plans include audit logs:

* Who accessed what
* When access occurred
* What actions were taken

Access audit logs:

1. Go to **"Settings" > "Security"**
2. Click **"Audit Log"**
3. Filter and search events

## Best Practices

### Principle of Least Privilege

* Grant minimum necessary access
* Review permissions regularly
* Revoke unused access

### Regular Reviews

* Audit team members monthly
* Review API key usage
* Check shared chatbot access

### Secure Practices

* Enable MFA for all users
* Use SSO where possible
* Rotate API keys regularly

## Related

* [Teams - Roles & Permissions](/teams/roles-permissions.md)
* [Document Access Control](/knowledge-base/access-control.md)
* [Encryption](/security/encryption.md)


---

# Data Residency

Control the geographic location of your data for compliance requirements.

## Overview

WizChat offers data residency options to help you meet regulatory requirements like GDPR.

## Available Regions

| Region            | Location            | Code        |
| ----------------- | ------------------- | ----------- |
| **United States** | US East (Virginia)  | `us-east-1` |
| **Europe**        | EU West (Frankfurt) | `eu-west-1` |

## Selecting a Region

When creating a chatbot:

1. Go to **"Create Chatbot"**
2. Under **"Advanced Settings"**
3. Select **"Data Region"**
4. Choose your region
5. Click **"Create"**



warning

Data region cannot be changed after chatbot creation.

## What's Stored in Region

All chatbot data stays in your selected region:

* Uploaded documents
* Processed embeddings
* User data
* Conversation history
* Analytics data

## GDPR Compliance

For EU data subjects, use the EU region to ensure:

* Data stored in EU
* Processing in EU
* Compliant with GDPR requirements

### Data Processing

| Component        | Location          |
| ---------------- | ----------------- |
| Document storage | Selected region   |
| Vector database  | Selected region   |
| User database    | Selected region   |
| AI processing    | May vary by model |

### AI Model Processing

AI model calls may be processed in different regions depending on the provider:

| Model Provider | Processing Location |
| -------------- | ------------------- |
| OpenAI         | US                  |
| Anthropic      | US                  |
| EU-only models | EU                  |

For strict EU-only processing, use EU-hosted models or enable Zero Data Retention mode.

## Zero Data Retention (ZDR)

For maximum privacy, enable ZDR mode:

* No data sent to AI providers is retained
* Queries not used for model training
* See [ZDR documentation](/security/zdr.md)

## Account-Level Region

Set a default region for all new chatbots:

1. Go to **"Settings" > "Security"**
2. Set **"Default Region"**
3. Click **"Save"**

## Compliance Certifications

WizChat maintains:

* SOC 2 Type II
* GDPR compliance
* HIPAA compliance (Business plans)
* ISO 27001

## Data Transfer

If you need to move data between regions:

1. Export data from current chatbot
2. Create new chatbot in target region
3. Import data

note

This creates a new chatbot with a new ID.

## Related

* [Data Retention](/security/data-retention.md)
* [Encryption](/security/encryption.md)
* [Zero Data Retention](/security/zdr.md)
* [Access Control](/security/access-control.md)


---

# Data Retention

WizChat automatically manages the lifecycle of temporary and session-based data. Your subscription plan determines how long different data types are retained.

## What's Affected

Data retention applies to **session and conversation data** — temporary data generated during chatbot interactions:

| Data Type                | Description                                                                 |
| ------------------------ | --------------------------------------------------------------------------- |
| **Chat history**         | Conversations between end users and your chatbot                            |
| **Questions & Answers**  | Query logs visible in Analytics                                             |
| **In-chat file uploads** | Files uploaded by end users during a chat session (not your knowledge base) |

Knowledge base is permanent

Your **knowledge base** documents (PDFs, web pages, videos, Excel files, etc.) are **not affected** by data retention. They remain available until you manually delete them.

## Retention Periods by Plan

| Data Type                | Free    | Starter | Pro      | Pro+     | Business | Enterprise |
| ------------------------ | ------- | ------- | -------- | -------- | -------- | ---------- |
| **Chat history & Q\&A**  | 30 days | 90 days | 180 days | 365 days | 365 days | Unlimited  |
| **In-chat file uploads** | 3 days  | 7 days  | 14 days  | 30 days  | 30 days  | Unlimited  |

Enterprise

Enterprise plans have **unlimited retention** — no data is automatically deleted.

## What Happens When Data Expires

* **Chat history & Q\&A** — Expired conversations are permanently deleted. They will no longer appear in your Analytics dashboard.
* **In-chat file uploads** — Files uploaded by end users during a chat session are permanently removed. The chatbot will no longer be able to reference them in follow-up messages.

Deletion happens automatically on a daily basis. There is no action required on your part.

## In-Chat File Uploads vs Knowledge Base

It's important to understand the difference:

|                          | In-Chat File Uploads                   | Knowledge Base                      |
| ------------------------ | -------------------------------------- | ----------------------------------- |
| **Who uploads**          | End users during a conversation        | You (the chatbot owner)             |
| **Purpose**              | Temporary analysis in a single session | Permanent knowledge for the chatbot |
| **Subject to retention** | Yes (per-plan limits above)            | No (kept until you delete)          |
| **Where to manage**      | Automatic                              | Dashboard > Knowledge Base          |

## Upgrading for Longer Retention

If you need your data retained for longer, upgrade your plan:

1. Go to **"Settings" > "Billing"**
2. Click **"Change Plan"**
3. Select a plan with longer retention

The new retention period applies immediately to all existing data.

Downgrading

When you downgrade to a plan with shorter retention, data older than the new retention period will be deleted during the next daily cleanup cycle.

## Related

* [Subscription Plans](/billing/plans.md)
* [Data Residency](/security/data-residency.md)
* [Zero Data Retention](/security/zdr.md)


---

# Encryption

WizChat uses industry-standard encryption to protect your data.

## Encryption Overview

| Data State     | Encryption  |
| -------------- | ----------- |
| **At rest**    | AES-256-GCM |
| **In transit** | TLS 1.3     |
| **Backups**    | AES-256     |

## Data at Rest

All stored data is encrypted using AES-256-GCM:

### Documents

* Uploaded files encrypted before storage
* Encryption keys managed by cloud provider
* Customer-managed keys available (Enterprise)

### Databases

* All database fields encrypted
* Transparent data encryption (TDE)
* Encrypted backups

### Embeddings

* Vector embeddings encrypted
* Index data encrypted

## Data in Transit

All network traffic uses TLS 1.3:

* Browser to WizChat
* WizChat to AI providers
* WizChat to databases
* API communications

### Certificate Management

* Certificates auto-renewed
* Modern cipher suites only
* HSTS enabled

## Key Management

### Default Key Management

* Keys managed by WizChat
* Automatic key rotation
* Secure key storage

### Customer-Managed Keys (Enterprise)

Bring your own encryption keys:

* AWS KMS integration
* Google Cloud KMS integration
* Azure Key Vault integration

Contact sales for setup.

## Sensitive Data

### API Keys

* Encrypted at rest
* Never logged
* Shown only once

### OAuth Tokens

* Encrypted with AES-256-GCM
* Refresh tokens protected
* Revocable anytime

### Passwords

* Never stored in plain text
* Bcrypt hashing
* Salted hashes

## Audit Logging

Security events are logged:

* Login attempts
* Permission changes
* Data access
* API key usage

Logs are:

* Encrypted
* Retained per policy
* Available for review (Business plans)

## Security Certifications

| Certification | Status               |
| ------------- | -------------------- |
| SOC 2 Type II | Certified            |
| ISO 27001     | Certified            |
| GDPR          | Compliant            |
| HIPAA         | Available (Business) |

## Penetration Testing

* Regular third-party testing
* Vulnerability assessments
* Bug bounty program

## Related

* [Data Residency](/security/data-residency.md)
* [Access Control](/security/access-control.md)
* [Zero Data Retention](/security/zdr.md)


---

# PII Protection

WizChat automatically detects and redacts personally identifiable information (PII) from conversations before storing them. This protects your end users' sensitive data across all storage systems.

## How It Works

WizChat uses a **two-tier detection system** that runs on every message:

### Tier 1 — Pattern Matching

Fast, deterministic regex-based detection for structured PII patterns. Runs in under 1 millisecond with zero API cost.

### Tier 2 — AI Classification

Contextual PII classification powered by a lightweight language model, piggybacked on the existing input processing step. This catches unstructured PII like names mentioned alongside sensitive context, health conditions, and other data that patterns alone can't identify.

## What Gets Redacted

When PII is detected, sensitive data is replaced with type-specific placeholders **before storage**. The chatbot still sees the original message to generate a quality response — only the stored version is redacted.

| Data Type                     | Replacement                    |
| ----------------------------- | ------------------------------ |
| Credit card numbers           | `[CREDIT_CARD_REDACTED]`       |
| Social Security Numbers (SSN) | `[SSN_REDACTED]`               |
| API keys and tokens           | `[API_KEY_REDACTED]`           |
| Passwords                     | `[PASSWORD_REDACTED]`          |
| Bearer tokens                 | `[BEARER_TOKEN_REDACTED]`      |
| AWS access keys               | `[AWS_KEY_REDACTED]`           |
| Private keys (PEM)            | `[PRIVATE_KEY_REDACTED]`       |
| Database connection strings   | `[CONNECTION_STRING_REDACTED]` |
| Phone numbers                 | `[PHONE_REDACTED]`             |
| IBAN numbers                  | `[IBAN_REDACTED]`              |
| IP addresses                  | `[IP_REDACTED]`                |
| Dates of birth                | `[DOB_REDACTED]`               |
| Passport / ID numbers         | `[ID_REDACTED]`                |

### What Is Kept

**Email addresses** are intentionally preserved. They are needed for user identification in analytics and are not considered high-risk PII in the context of chatbot conversations.

## Where Redaction Applies

PII redaction is applied across **all storage and transit paths**:

| Storage Location                   | Redacted |
| ---------------------------------- | -------- |
| Query Log (Questions & Answers)    | ✅       |
| Conversation History               | ✅       |
| Long-term Memory (extracted facts) | ✅       |
| Short-term Memory (graph nodes)    | ✅       |
| Cost & Usage Analytics             | ✅       |
| Observability Traces               | ✅       |

## Query Log PII Badge

When a message is flagged as containing PII, the [Query Log](/analytics/queries.md) displays a **PII Detected** badge on the affected row. This helps chatbot owners identify conversations that contained sensitive information.

## User Consent

End users are informed about conversation monitoring through the cookie consent dialog, which states:

> "We use cookies for analytics and conversations may be reviewed to improve answer quality."

This satisfies GDPR's requirement for transparent, upfront notice before data collection begins.

## GDPR Compliance

WizChat's PII protection supports GDPR compliance by:

* **Minimizing data collection** — sensitive data is redacted before storage, not after
* **Transparent processing** — users are informed via the consent dialog
* **Access controls** — user emails are masked in the Query Log (displayed as `j***n@example.com`)
* **Data retention** — all conversation data has automatic retention limits based on your plan
* **Right to deletion** — contact support to request deletion of specific user data

## Limitations

* PII detection relies on pattern matching and AI classification, which may not catch every instance
* The chatbot's live response still processes the original unredacted message for answer quality
* Historical data stored before PII protection was enabled is not retroactively redacted
* Very short inputs (under 8 characters) skip PII detection to avoid false positives


---

# Zero Data Retention (ZDR)

Maximum privacy mode where no query data is retained by AI providers.

## What is ZDR?

Zero Data Retention ensures:

* AI providers don't store your queries
* Data isn't used for model training
* Responses aren't logged by providers
* Maximum privacy protection

## How It Works

Without ZDR:



With ZDR:



Provider logs are disabled, and data is not retained.

## Enabling ZDR

1. Open your chatbot
2. Go to **"Settings" > "Security"**
3. Toggle **"Zero Data Retention"**
4. Click **"Save"**



## ZDR-Compatible Models

Not all models support ZDR. Compatible options:

| Provider            | ZDR Support |
| ------------------- | ----------- |
| OpenAI (Enterprise) | Yes         |
| Anthropic           | Yes         |
| Azure OpenAI        | Yes         |
| Cerebras            | Yes         |

## Cerebras Routing

For guaranteed ZDR, enable Cerebras routing:

1. Enable ZDR mode
2. WizChat routes to Cerebras
3. Fast inference with ZDR

Cerebras provides:

* Extremely fast responses
* Zero data retention
* No training on your data

## When to Use ZDR

Consider ZDR for:

* Sensitive business data
* Healthcare information (HIPAA)
* Financial data
* Legal documents
* Personal information

## ZDR Limitations

With ZDR enabled:

| Feature              | Impact                        |
| -------------------- | ----------------------------- |
| Response speed       | Slightly slower (some models) |
| Model options        | Limited to ZDR-compatible     |
| Cost                 | May be higher                 |
| Conversation history | Stored only in WizChat        |

## Verification

Verify ZDR is working:

1. Go to **"Settings" > "Security"**
2. Check ZDR status
3. View provider confirmation

## Compliance

ZDR helps with:

* **HIPAA** - Healthcare data protection
* **GDPR** - Right to be forgotten
* **CCPA** - Consumer privacy
* **SOC 2** - Security compliance

## Per-Chatbot ZDR

ZDR can be enabled per chatbot:

* Enable for sensitive chatbots
* Disable for less sensitive
* Mix based on data type

## Account-Wide ZDR

Force ZDR for all chatbots:

1. Go to **"Settings" > "Security"**
2. Enable **"Account-wide ZDR"**
3. All chatbots will use ZDR

warning

This cannot be overridden per chatbot.

## Monitoring

Track ZDR usage:

1. Go to **"Analytics" > "Security"**
2. View ZDR query count
3. Monitor compliance

## Related

* [Data Residency](/security/data-residency.md)
* [Encryption](/security/encryption.md)
* [Access Control](/security/access-control.md)


---

# Chatbot Ownership Transfer

Transfer ownership of an individual chatbot to another user.

note

This page covers transferring **individual chatbot** ownership. For transferring **team ownership**, see [Team Ownership Transfer](/teams/team-ownership-transfer.md).

## Why Transfer Chatbot Ownership?

* Employee leaving the company
* Reorganizing responsibilities
* Moving chatbot to a different team
* Changing billing arrangements

## Transfer Requirements

To transfer ownership, you must be:

* The current chatbot owner
* The transfer recipient must have an account

## How to Transfer

1. Open the chatbot
2. Go to **"Settings" > "General"**
3. Click **"Transfer Ownership"**
4. Enter the new owner's email
5. Confirm the transfer
6. New owner receives notification and accepts



## Transfer Process

1. **Initiate** - Owner starts the transfer
2. **Notify** - New owner receives email notification
3. **Accept** - New owner confirms acceptance
4. **Complete** - Ownership changes immediately

## What Gets Transferred

| Transferred       | Not Transferred   |
| ----------------- | ----------------- |
| Chatbot ownership | Your subscription |
| All settings      | Other chatbots    |
| Knowledge base    | Team membership   |
| User list         |                   |
| Deployment        |                   |

## Billing Implications

After transfer:

* **Previous owner** - No longer billed for this chatbot
* **New owner** - Chatbot counts toward their plan limits
* **Usage** - Future usage billed to new owner

warning

Ensure the new owner has sufficient plan limits before transferring.

## Canceling a Transfer

Before the new owner accepts:

1. Go to **"Settings" > "General"**
2. Find the pending transfer
3. Click **"Cancel Transfer"**

## Accepting a Transfer

For the new owner:

1. Check email for transfer notification
2. Click the link or go to **"Notifications"**
3. Review the chatbot details
4. Click **"Accept"** or **"Decline"**



## After Transfer

### For Previous Owner

* No longer have access (unless shared)
* Can request access from new owner
* Not responsible for billing

### For New Owner

* Full ownership and control
* Responsible for billing
* Can share, modify, or delete

## Best Practices

* Communicate with the new owner beforehand
* Ensure they have appropriate plan limits
* Document the transfer
* Update team access as needed

## Related

* [Team Ownership Transfer](/teams/team-ownership-transfer.md)
* [Sharing Chatbots](/teams/sharing.md)
* [Billing & Plans](/billing/plans.md)
* [Managing Chatbots](/chatbots/managing.md)


---

# Creating a Team

Teams allow you to collaborate with others on chatbots.

## Create a New Team

1. Go to **"Teams"** in the sidebar
2. Click **"Create Team"**
3. Enter a team name
4. Click **"Create"**



## Team Features

With a team, you can:

* Share chatbots with team members
* Collaborate on knowledge bases
* Manage access and permissions
* Centralize billing (team owner pays)

## Team Limits by Plan

| Plan       | Teams     | Members per Team |
| ---------- | --------- | ---------------- |
| Free       | 0         | -                |
| Starter    | 1         | 3                |
| Pro        | 3         | 10               |
| Business   | Unlimited | Unlimited        |
| Enterprise | Unlimited | Unlimited        |

## Team Settings

After creating a team, configure settings to control what members can do.

### Member Permissions

| Setting                           | What It Controls                              |
| --------------------------------- | --------------------------------------------- |
| **Allow member chatbot creation** | Whether members can create their own chatbots |
| **Allow member document uploads** | Whether members can upload documents          |

### How to Configure

1. Go to your team dashboard
2. Click **"Team Settings"**
3. Find the **"Member Permissions"** section
4. Toggle settings on/off
5. Changes apply immediately



When to Enable Member Creation

Enable member chatbot creation when you want team members to build and experiment with chatbots. Remember that member-created chatbots are billed to the member until [shared with the team](/teams/share-requests.md).

## Team Dashboard

After creating a team, you'll see:

* **Members** - Who's in the team
* **Chatbots** - Shared chatbots
* **Settings** - Team configuration
* **Billing** - Team owner's billing info



## Personal vs Team Chatbots

| Personal Chatbots      | Team Chatbots               |
| ---------------------- | --------------------------- |
| Only you can access    | All team members can access |
| Billed to your account | Billed to team owner        |
| Full control           | Based on permissions        |

## Switching Between Teams

If you're on multiple teams:

1. Click your profile in the sidebar
2. Click **"Switch Team"**
3. Select the team



## Next Steps

After creating a team:

* [Invite members](/teams/invitations.md)
* [Set up roles](/teams/roles-permissions.md)
* [Configure team settings](#team-settings)
* [Share chatbots](/teams/sharing.md)

## Related

* [Inviting Members](/teams/invitations.md)
* [Roles & Permissions](/teams/roles-permissions.md)
* [Team Ownership Transfer](/teams/team-ownership-transfer.md)


---

# Inviting Members

Add team members by sending email invitations.

## Sending Invitations

1. Go to **"Teams" > Your Team**
2. Click **"Members"**
3. Click **"Invite Member"**
4. Enter their email address
5. Select a role (Admin or Member)
6. Click **"Send Invitation"**



## Invitation Status

| Status       | Description                           |
| ------------ | ------------------------------------- |
| **Pending**  | Invitation sent, waiting for response |
| **Accepted** | User joined the team                  |
| **Expired**  | Invitation not accepted in time       |
| **Declined** | User declined the invitation          |

## Invitation Expiration

* Invitations expire after **7 days**
* You can resend expired invitations
* Users can accept from the email link

## Managing Pending Invitations

### View Pending Invitations

1. Go to **"Teams" > Your Team > "Members"**
2. Click **"Pending"** tab
3. See all outstanding invitations

### Resend Invitation

1. Find the pending invitation
2. Click **"Resend"**
3. A new email is sent

### Cancel Invitation

1. Find the pending invitation
2. Click **"Cancel"**
3. Confirm cancellation



## Bulk Invitations

Invite multiple people at once:

1. Click **"Invite Member"**
2. Click **"Bulk Invite"**
3. Enter multiple emails (one per line)
4. Select a role for all
5. Click **"Send Invitations"**

## What Invitees See

When someone receives an invitation:

1. Email with team name and inviter
2. Link to accept the invitation
3. Option to create an account if needed

## Accepting an Invitation

For the invitee:

1. Click the link in the invitation email
2. Log in or create an account
3. You're added to the team

## Best Practices

* Use work email addresses
* Assign appropriate roles
* Follow up on pending invitations
* Keep your team member list current

## Troubleshooting

### Invitation Not Received

* Check spam/junk folder
* Verify email address is correct
* Resend the invitation
* Ask them to add wizchat.com to allowed senders

### Can't Accept Invitation

* Verify the invitation hasn't expired
* Ensure they're using the correct email
* Have them try a different browser

## Related

* [Roles & Permissions](/teams/roles-permissions.md)
* [Creating a Team](/teams/creating.md)


---

# Roles & Permissions

Teams have three roles with different permissions.

## Role Overview

| Role       | Description                                      |
| ---------- | ------------------------------------------------ |
| **Owner**  | Full control, manages billing                    |
| **Admin**  | Can manage members and chatbots                  |
| **Member** | Can use shared chatbots, limited creation rights |

## Permission Matrix

| Permission           | Owner | Admin | Member            |
| -------------------- | ----- | ----- | ----------------- |
| View team chatbots   | Yes   | Yes   | Yes               |
| Use shared chatbots  | Yes   | Yes   | Yes               |
| Edit shared chatbots | Yes   | Yes   | If granted Admin† |
| Create chatbots      | Yes   | Yes   | Settings\*        |
| Upload documents     | Yes   | Yes   | Settings\*        |
| Delete own chatbots  | Yes   | Yes   | Yes               |
| Delete team chatbots | Yes   | Yes   | No                |
| Invite members       | Yes   | Yes   | No                |
| Remove members       | Yes   | Yes   | No                |
| Change member roles  | Yes   | Yes   | No                |
| Manage team settings | Yes   | Yes   | No                |
| Manage billing       | Yes   | No    | No                |
| Delete team          | Yes   | No    | No                |
| Transfer ownership   | Yes   | No    | No                |

**\*Settings** = Controlled by team settings. See [Team Settings](#team-settings) below.

**†Edit shared chatbots** = A team member can edit a chatbot shared with them only if they're granted **Admin** access to that chatbot (or they created it). The per-chatbot access level is set when [sharing the chatbot](/teams/sharing.md#access-levels).

## Team Settings

Team owners can configure what members are allowed to do. These settings are found in **Team Settings**.

### Member Permissions

| Setting                           | Description                              | Default |
| --------------------------------- | ---------------------------------------- | ------- |
| **Allow member chatbot creation** | Members can create their own chatbots    | On      |
| **Allow member document uploads** | Members can upload documents to chatbots | On      |

How to Configure

1. Go to **"Team Settings"**
2. Find the **"Member Permissions"** section
3. Toggle settings on/off
4. Changes apply immediately

When these settings are **enabled**:

* Members can create chatbots (owned by them personally)
* Members can upload documents to chatbots they have access to
* Members can request to share their chatbots with the team

When these settings are **disabled**:

* Members cannot create new chatbots
* Members cannot upload documents
* Members can only use chatbots shared with them

Upload permission vs. a chatbot's access level

**"Allow member document uploads"** governs whether a **plain member** can **add content** (documents and YouTube videos) to chatbots they can access. Chatbot owners, anyone with per-chatbot **Admin**, and team owners/admins can always upload regardless of this setting.

This setting is **separate** from a chatbot's per-member access level (**View Only** / **Admin**), which only controls chatbot *management*. A member set to **View Only** on a chatbot can still upload to it when this team permission is granted. See [Sharing Chatbots → Access Levels](/teams/sharing.md#access-levels).

## Owner Role

The **Owner** has complete control over the team:

* All admin permissions
* Manages team billing
* Can transfer team ownership
* Can delete the team
* Controls member permission settings

note

Each team has exactly one owner. To change owners, see [Team Ownership Transfer](/teams/team-ownership-transfer.md).

## Admin Role

**Admins** can manage day-to-day operations:

* Invite and remove members
* Create and manage chatbots
* Share chatbots with the team
* Delete any team chatbot
* Cannot access billing
* Cannot delete the team

## Member Role

**Members** have access based on team settings:

* View and use shared chatbots
* Edit a shared chatbot only when granted **Admin** access to it (or they created it)
* Delete their **own** chatbots (if they created any)
* Cannot delete other team chatbots
* Cannot invite others
* Can create chatbots **if team settings allow**
* Can upload documents **if team settings allow**

Member-Created Chatbots

When a member creates a chatbot, they own it personally. To share it with the team, they must submit a [share request](/teams/share-requests.md) for owner approval.

## Changing Roles

To change a member's role:

1. Go to **"Teams" > Your Team > "Members"**
2. Find the member
3. Click the role dropdown
4. Select the new role
5. Confirm the change



note

Only Owners and Admins can change roles.

## Removing Members

1. Go to **"Teams" > Your Team > "Members"**
2. Find the member
3. Click **"Remove"**
4. Confirm removal

warning

Removed members lose access to all team chatbots immediately.

## Best Practices

### Assigning Roles

* Use **Admin** for trusted collaborators who need management access
* Use **Member** for those who only need chatbot access
* Limit the number of Admins

### Team Settings

* Enable member chatbot creation if you want distributed ownership
* Keep it disabled if you prefer centralized control
* Remember: member-created chatbots are billed to the member, not the team

### Security

* Regularly review team members
* Remove inactive members
* Audit role assignments
* Review team settings periodically

## Related

* [Creating a Team](/teams/creating.md)
* [Inviting Members](/teams/invitations.md)
* [Team Ownership Transfer](/teams/team-ownership-transfer.md)
* [Chatbot Ownership Transfer](/teams/chatbot-transfer.md)


---

# Share Request Workflow

When team members create their own chatbots, they can request to share them with the team for wider access.

## Overview

This workflow is specifically for:

* **Team members** who have created their own chatbots
* Requesting to share those chatbots **with the team**
* Getting **owner approval** before sharing

Billing Changes on Approval

When a share request is approved, the **team owner becomes responsible for all usage costs** of that chatbot. Owners should consider this before approving.

## How It Works

1. **Member creates chatbot** - Member builds a chatbot (billed to them)
2. **Request to share** - Member requests to share with team
3. **Owner reviews** - Owner receives and reviews the request
4. **Decision** - Owner approves or denies
5. **Billing shifts** - On approval, billing moves to team owner

## Submitting a Share Request

If you're a team member with your own chatbot:

1. Open your chatbot
2. Go to **"Settings" > "Sharing"**
3. Click **"Request to Share with Team"**
4. Add a reason (optional but recommended)
5. Click **"Submit Request"**



Why Include a Reason?

A clear reason helps the team owner understand why this chatbot would benefit the team and makes approval more likely.

## Request Status

| Status       | Description                |
| ------------ | -------------------------- |
| **Pending**  | Waiting for owner review   |
| **Approved** | Owner granted the request  |
| **Denied**   | Owner rejected the request |
| **Expired**  | No response within 7 days  |

## Viewing Your Requests

1. Go to **"Teams" > "Share Requests"**
2. View all your pending and past requests
3. See status and responses



## For Owners: Reviewing Requests

### Understanding the Billing Impact

Before reviewing requests, understand that **approving a share request means you take on billing for that chatbot**:

| Before Approval         | After Approval              |
| ----------------------- | --------------------------- |
| Member pays for chatbot | You (owner) pay for chatbot |
| Usage billed to member  | Usage billed to team        |
| Member's plan limits    | Your team plan limits       |

### View Pending Requests

1. Go to **"Teams" > "Share Requests"**
2. Or check the notification bell
3. See all pending requests

### Approve a Request

1. Click on the request
2. Review the chatbot details
3. **Consider the billing implications**
4. Click **"Approve"**
5. Chatbot is shared with team automatically
6. Billing responsibility transfers to you

### Deny a Request

1. Click on the request
2. Review the details
3. Click **"Deny"**
4. Optionally add a reason
5. Chatbot remains with the member



## Notifications

* Requesters receive email when request is reviewed
* Owners receive email when new request is submitted
* In-app notifications also appear

## What Happens After Approval

### For the Member (Original Creator)

* Chatbot is now shared with the entire team
* You retain co-ownership and full edit access
* **You are no longer billed** for this chatbot
* Usage now counts against team limits, not yours

### For the Team Owner

* Chatbot appears in team's shared chatbots
* **You are now responsible for all billing**
* Usage counts against your team plan
* You can manage access and settings

### For Other Team Members

* Chatbot appears in their shared chatbots
* Access based on sharing permissions
* Can use the chatbot per their role

## Best Practices

### For Requesters

* Provide clear reasons for sharing
* Explain the value to the team
* Ensure the chatbot is ready (tested, documented)
* Consider timing of the request

### For Owners

* Review requests promptly
* Consider business need and value
* **Factor in billing impact** when deciding
* Communicate decisions to requesters
* Document approval reasoning

## Billing Summary

| Scenario                           | Who Pays   |
| ---------------------------------- | ---------- |
| Member's chatbot (not shared)      | Member     |
| Member requests to share (pending) | Member     |
| Request approved                   | Team Owner |
| Request denied                     | Member     |

## Related

* [Sharing Chatbots](/teams/sharing.md)
* [Roles & Permissions](/teams/roles-permissions.md)
* [Billing & Plans](/billing/plans.md)


---

# Sharing Chatbots

Share chatbots with team members or grant individual access.

## Share with Team

Share a chatbot with all team members:

1. Open the chatbot
2. Open **Manage Access** (the chatbot's sharing/access dialog)
3. Enable **"Share with Team"** — all team members can then use the chatbot
4. Choose whether to **Include Knowledge Base access** for team members
5. Click **"Save"**



Billing Implications

When you share a chatbot with your team, the **team owner becomes responsible for all usage costs** of that chatbot. The original creator retains co-ownership but billing shifts to the team owner.

## Who Pays for Shared Chatbots?

Understanding billing is critical when sharing chatbots:

| Chatbot Type             | Who Pays   |
| ------------------------ | ---------- |
| Personal (not shared)    | Creator    |
| Shared with team         | Team Owner |
| After ownership transfer | New Owner  |

### What's Included in Usage Costs

When the team owner takes on billing responsibility, they pay for:

* **AI queries** - All chat interactions
* **Document processing** - Parsing and indexing
* **Storage** - Knowledge base storage
* **Embeddings** - Vector embeddings for search

For Members

If you're a team member and create a chatbot, it's billed to **you** until you share it with the team. Once shared and approved, the team owner pays.

## Access Levels

When you grant a team member **individual** access to a chatbot, you choose a per-chatbot access level:

| Level         | What it controls                                                                                                        |
| ------------- | ----------------------------------------------------------------------------------------------------------------------- |
| **View Only** | Use the chatbot (and, if Knowledge Base access is included, view its documents). Cannot edit settings or manage access. |
| **Admin**     | Everything in View Only, **plus** edit settings, manage access, and redeploy.                                           |

These per-chatbot levels apply to **team members** you grant individual access. People added by **email or domain** (see [Share with Individuals](#share-with-individuals)) get plain view-and-use access to the chatbot, not these management levels.

Access level is *not* the same as upload permission

The access level controls **chatbot management**. By itself it does **not** decide who can **add content** — uploading documents and importing YouTube videos is also governed by the team-level **"Allow member document uploads"** setting (see [Roles & Permissions](/teams/roles-permissions.md#member-permissions)).

Who can upload documents or import YouTube videos:

* The chatbot **owner**, anyone with per-chatbot **Admin** access, and team **owners/admins** — always.
* **View Only** members (and other plain team members) — only when the team has granted **"Allow member document uploads"**.

So a **View Only** member *can* still upload once that team permission is granted, and *can't* upload without it. (Granting someone **Admin** on the chatbot also lets them upload, because Admin can manage everything about the chatbot.)

## Share with Individuals

Share with specific people (even non-team members):

1. Open the chatbot
2. Open **Manage Access**
3. Click **"Add People"**
4. Enter email addresses (or a domain)
5. Click **"Share"**



External (non-team) recipients added this way get **view-and-use** access to the chatbot. The **View Only / Admin** management levels above apply to **teammates** you grant [individual access](#access-levels) from the same dialog.

Individual Sharing and Billing

When sharing with individuals outside your team, **you remain responsible for billing**. Individual sharing does not transfer billing responsibility.

## Knowledge Base Access

When sharing a chatbot, you can control knowledge base access:

* **Include KB** - Can view the chatbot's knowledge base and its documents
* **Exclude KB** - Can use the chatbot but not view its knowledge base

Toggle this in the chatbot's **Manage Access** dialog. Adding, editing, or deleting documents is controlled separately by upload/delete permissions (see the callout above), not by this toggle.

## YouTube Channel Access

If a chatbot has a **connected YouTube channel**, you can let specific members **browse and load videos from that channel** under the connection of the owner/admin who linked it — without sharing the Google login.

In the chatbot's **Manage Access** dialog, each member row has a **YouTube channel access** checkbox (alongside *Include Knowledge Base access*):

* Owners, per-chatbot **Admins**, and team owners/admins can already browse a linked channel. The checkbox is **off by default** for everyone else — grant it per member explicitly.
* It becomes available **only once a channel is linked** to the chatbot. To link one, an owner or admin connects YouTube and browses the channel once on this chatbot's **Add Content → YouTube** screen. The first such browse links the channel to the chatbot.
* A granted member can then browse the channel and **load** its videos — but **loading still requires document-upload permission** (see [who can upload](#access-levels) above). Videos are fetched under the linking admin's connection; the member never sees the Google credentials.

### Private videos

By default, granted members see only **public and unlisted** videos. To also expose **private** videos, enable **"Let granted members see private videos"** in the same dialog — a per-chatbot, channel-level toggle that is **off by default**. The member who connected the channel always sees its private videos; everyone else sees them only when this toggle is on.

For the full channel-linking walkthrough, see [YouTube Integration → Sharing a connected channel with your team](/integrations/youtube.md#sharing-a-connected-channel-with-your-team).

## Non-Owner Sharing

If you're not the chatbot owner:

1. You can request to share
2. A share request is sent to the owner
3. Owner approves or denies
4. See [Share Request Workflow](/teams/share-requests.md)

## Viewing Shared Chatbots

### Chatbots Shared with You

1. Go to **"Chatbots"**
2. Click **"Shared with Me"** tab
3. View all chatbots others have shared

### Your Shared Chatbots

1. Go to **"Chatbots"**
2. Open a chatbot
3. Go to **"Settings" > "Sharing"**
4. See who has access

## Removing Access

1. Go to **"Settings" > "Sharing"**
2. Find the person or team
3. Click **"Remove"**
4. Confirm removal



## Best Practices

* Only share with those who need access
* Use appropriate access levels
* Regularly review who has access
* Remove access when no longer needed
* **Understand billing implications** before sharing with team

## Related

* [Share Request Workflow](/teams/share-requests.md)
* [Roles & Permissions](/teams/roles-permissions.md)
* [Chatbot Ownership Transfer](/teams/chatbot-transfer.md)
* [Billing & Plans](/billing/plans.md)


---

# Team Ownership Transfer

Transfer ownership of your entire team to another team member.

note

This page covers transferring **team ownership**. For transferring individual **chatbot ownership**, see [Chatbot Ownership Transfer](/teams/chatbot-transfer.md).

## Why Transfer Team Ownership?

* Leaving the organization
* Changing roles within the company
* Handing over responsibility to another leader
* Organizational restructuring

## Requirements

To transfer team ownership:

* You must be the current team owner
* The recipient must be an existing team member
* The recipient must have an active account

## How to Transfer

### Step 1: Initiate Transfer

1. Go to **"Team Settings"**
2. Scroll to the **"Danger Zone"** section
3. Click **"Transfer Ownership"**



### Step 2: Select New Owner

1. A modal appears with a dropdown of team members
2. Select the member you want to transfer to
3. Type "confirm" in the confirmation field
4. Click **"Send Transfer Request"**

### Step 3: Recipient Action

The selected member will receive:

* An **email notification** with Accept/Decline links
* A **banner** in their dashboard showing the pending request

The recipient can:

* **Accept** - Takes ownership immediately
* **Decline** - Rejects the transfer, nothing changes



## Transfer Flow

```
Owner initiates → Email sent to recipient → Recipient reviews
                                                    ↓
                              Accept ← → Decline
                                 ↓              ↓
                      Ownership transfers    No change
                      Old owner → Admin
```

## What Happens on Accept

When the recipient accepts:

| Before                    | After                     |
| ------------------------- | ------------------------- |
| You are Owner             | You become Admin          |
| Recipient is Member/Admin | Recipient becomes Owner   |
| You manage billing        | Recipient manages billing |

info

**You're not removed!** After transferring ownership, you remain in the team as an Admin. You'll still have access to team chatbots and member management—just not billing or the ability to delete the team.

## What Gets Transferred

| Transferred            | Not Transferred        |
| ---------------------- | ---------------------- |
| Team ownership         | Personal chatbots      |
| Billing responsibility | Your subscription      |
| Team settings control  | Individual settings    |
| All team chatbots      | Non-team chatbots      |
| Team member list       | Other team memberships |

## Request Expiration

* Transfer requests **expire after 7 days** if not acted upon
* After expiration, you can initiate a new transfer request
* Expired requests are automatically cleaned up

## Canceling a Transfer

Before the recipient accepts or declines:

1. Go to **"Team Settings"**
2. Find the **"Pending Transfer"** section
3. Click **"Cancel Transfer Request"**
4. The recipient will be notified



## Billing Implications

Important

When team ownership transfers, **billing responsibility transfers too**. The new owner will be responsible for:

* Team subscription payments
* All team chatbot usage costs
* Any overages or additional charges

Make sure the new owner:

* Understands billing responsibilities
* Has payment methods set up
* Has sufficient plan limits

## Best Practices

### Before Transferring

* Communicate with the recipient beforehand
* Ensure they understand billing responsibilities
* Review team settings together
* Document any important information

### After Transferring

* Update any external documentation
* Notify team members of the change
* Review your Admin permissions
* Consider if you need to remain on the team

## Troubleshooting

### Recipient Didn't Receive Email

1. Check spam/junk folders
2. Verify email address is correct
3. Cancel and resend the transfer request
4. Contact support if issues persist

### Transfer Request Expired

Simply initiate a new transfer request. There's no limit to how many times you can try.

### Recipient Can't Accept

Ensure the recipient:

* Has a verified email address
* Is logged into their account
* Has an active subscription (if required)

## Related

* [Chatbot Ownership Transfer](/teams/chatbot-transfer.md)
* [Roles & Permissions](/teams/roles-permissions.md)
* [Billing & Plans](/billing/plans.md)


---

# Common Issues

Solutions to problems you might encounter with WizChat.

## Document Upload Issues

### Upload Fails

**Symptoms:** File upload fails or times out

**Solutions:**

1. Check file size against your plan and file-type limits (see [Subscription Plans](/billing/plans.md#file-upload-size-limits))
2. Verify file format is supported
3. Try a different browser
4. Clear browser cache
5. Check internet connection

### Processing Stuck

**Symptoms:** Document shows "Processing" for too long

**Solutions:**

1. Large files can take several minutes (sometimes longer)
2. Check document isn't password-protected
3. Try re-uploading the file
4. Contact support if persists

### Poor Text Extraction

**Symptoms:** Chatbot doesn't find content from uploaded docs

**Solutions:**

1. Ensure PDF has selectable text (not scanned)
2. Enable OCR for scanned documents
3. Check document isn't corrupted
4. Try converting to a different format

## Chatbot Response Issues

### No Answer / Hallucination

**Symptoms:** Chatbot says it doesn't know or gives wrong info

**Solutions:**

1. Verify relevant documents are uploaded
2. Check documents are processed (status: Ready)
3. Review system prompt for clarity
4. Adjust retrieval settings (more chunks)
5. Try rephrasing the question

### Slow Responses

**Symptoms:** Responses take a long time

**Solutions:**

1. Check internet connection
2. Try a faster model (GPT-4o vs GPT-4)
3. Reduce context window size
4. Check WizChat status page

### Inconsistent Answers

**Symptoms:** Same question gets different answers

**Solutions:**

1. Lower temperature setting (0.2-0.4)
2. Improve system prompt clarity
3. Add more specific context
4. Review document quality

## Deployment Issues

### Deployment Failed

**Symptoms:** Chatbot won't deploy

**Solutions:**

1. Check all required settings are filled
2. Verify custom domain configuration
3. Wait and retry
4. Check error message for specifics

### Changes Not Appearing

**Symptoms:** Updates don't show on deployed chatbot

**Solutions:**

1. Clear browser cache
2. Use incognito/private window
3. Redeploy the chatbot
4. Check CDN propagation (wait 5-10 min)

### Custom Domain Not Working

**Symptoms:** Custom domain shows error

**Solutions:**

1. Verify DNS records are correct
2. Wait for DNS propagation (up to 48 hours)
3. Check SSL certificate status
4. Ensure domain is verified

## Authentication Issues

### Can't Log In

**Symptoms:** Login fails or loops

**Solutions:**

1. Clear browser cookies
2. Try incognito mode
3. Check email/password
4. Reset password
5. Try a different browser

### OAuth Connection Failed

**Symptoms:** Can't connect Google/Salesforce/etc.

**Solutions:**

1. Check popup blocker
2. Verify OAuth credentials in WizChat
3. Ensure correct permissions granted
4. Re-authorize the connection

### Session Expired

**Symptoms:** Unexpectedly logged out

**Solutions:**

1. Log in again
2. Check session timeout settings
3. Clear cookies if repeated

## Team & Sharing Issues

### Invitation Not Received

**Symptoms:** Team invite email not arriving

**Solutions:**

1. Check spam/junk folder
2. Verify email address is correct
3. Add wizchat.com to allowed senders
4. Resend invitation

### Can't Access Shared Chatbot

**Symptoms:** Shared chatbot not visible

**Solutions:**

1. Accept invitation if pending
2. Verify you're in the correct team
3. Check sharing permissions
4. Contact chatbot owner

## API Issues

### API Calls Failing

**Symptoms:** API returns errors

**Solutions:**

1. Verify API key is valid
2. Check authorization header format
3. Verify endpoint URL
4. Check rate limits
5. See [Error Codes](/api/errors.md)

### Rate Limited

**Symptoms:** 429 errors

**Solutions:**

1. Implement request throttling
2. Wait for rate limit reset
3. Upgrade plan for higher limits
4. Cache responses where possible

## Performance Issues

### Dashboard Slow

**Symptoms:** WizChat interface is sluggish

**Solutions:**

1. Check internet connection
2. Try a different browser
3. Clear browser cache
4. Disable browser extensions

### Analytics Not Loading

**Symptoms:** Charts/stats won't display

**Solutions:**

1. Refresh the page
2. Check date range selection
3. Wait if chatbot is new (data takes time)
4. Try a different browser

## Still Having Issues?

If these solutions don't help:

1. Check the [FAQ](/troubleshooting/faq.md)

2. Review [Error Messages](/troubleshooting/errors.md)

3. Contact support at 

4. Include:

   

   * Chatbot ID
   * Steps to reproduce
   * Screenshots if applicable
   * Browser and OS

## Related

* [Error Messages](/troubleshooting/errors.md)
* [FAQ](/troubleshooting/faq.md)
* [API Errors](/api/errors.md)


---

# Error Messages

Reference guide for WizChat error messages.

## Document Errors

### "Document processing failed"

**Cause:** The document couldn't be processed.

**Solutions:**

* Verify the file isn't corrupted
* Check file isn't password-protected
* Ensure file format is supported
* Try re-uploading

### "File too large"

**Cause:** File exceeds plan limits.

**Solutions:**

* Compress the file
* Split into smaller documents
* Upgrade your plan

### "Unsupported file type"

**Cause:** File format not supported.

**Supported formats:**

* PDF, DOCX, TXT, MD, CHM
* XLSX, CSV
* PNG, JPG, WEBP
* MP4, AVI, MOV, MKV, WebM, WMV (videos)

### "Storage limit reached"

**Cause:** You've used all available storage.

**Solutions:**

* Delete unused documents
* Upgrade your plan
* Check storage usage in Settings

## Chatbot Errors

### "Chatbot not found"

**Cause:** The chatbot doesn't exist or you don't have access.

**Solutions:**

* Check the chatbot ID
* Verify you have access
* Contact the owner if shared

### "Deployment failed"

**Cause:** Chatbot couldn't be deployed.

**Solutions:**

* Check all required settings
* Verify domain configuration
* Review error details
* Try again after a few minutes

### "Model unavailable"

**Cause:** Selected AI model is temporarily unavailable.

**Solutions:**

* Try a different model
* Wait and retry
* Check WizChat status page

## Authentication Errors

### "Invalid credentials"

**Cause:** Email or password is incorrect.

**Solutions:**

* Double-check your email
* Reset your password
* Try social login if available

### "Session expired"

**Cause:** Your login session has ended.

**Solutions:**

* Log in again
* Check session timeout settings
* Clear cookies if repeated

### "OAuth authorization failed"

**Cause:** OAuth connection couldn't be established.

**Solutions:**

* Check popup blocker
* Verify OAuth app credentials
* Re-authorize the connection
* Check third-party service status

## Team Errors

### "Invitation expired"

**Cause:** Team invitation has expired (7 days).

**Solutions:**

* Request a new invitation
* Accept invitations promptly

### "Permission denied"

**Cause:** You don't have permission for this action.

**Solutions:**

* Contact team admin
* Check your team role
* Request elevated permissions

### "Member limit reached"

**Cause:** Team has maximum members for plan.

**Solutions:**

* Remove inactive members
* Upgrade your plan

## API Errors

### "Rate limit exceeded"

**Cause:** Too many API requests.

**Solutions:**

* Wait for rate limit reset
* Implement request throttling
* Upgrade for higher limits

### "Invalid API key"

**Cause:** API key is wrong or revoked.

**Solutions:**

* Check API key is correct
* Generate a new key
* Verify key permissions

### "Quota exceeded"

**Cause:** Monthly query limit reached.

**Solutions:**

* Wait for billing cycle reset
* Purchase credits
* Upgrade your plan

## Integration Errors

### "Connection failed"

**Cause:** Can't connect to external service.

**Solutions:**

* Check credentials
* Verify service is accessible
* Re-authenticate
* Check firewall settings

### "Database connection error"

**Cause:** PostgreSQL connection failed.

**Solutions:**

* Verify host and port
* Check credentials
* Ensure database is accessible
* Check SSL settings

### "MCP server error"

**Cause:** MCP server returned an error.

**Solutions:**

* Check server is running
* Verify server URL
* Review server logs
* Test server manually

## Billing Errors

### "Payment failed"

**Cause:** Payment couldn't be processed.

**Solutions:**

* Update payment method
* Check card details
* Ensure sufficient funds
* Contact your bank

### "Subscription update failed"

**Cause:** Plan change couldn't be processed.

**Solutions:**

* Retry the change
* Check payment method
* Contact support

## Network Errors

### "Network error"

**Cause:** Connection to WizChat failed.

**Solutions:**

* Check internet connection
* Try a different network
* Disable VPN if active
* Check firewall settings

### "Request timeout"

**Cause:** Request took too long.

**Solutions:**

* Try again
* Check internet speed
* Try a simpler request
* Contact support if persistent

## Getting Help

If you can't resolve an error:

1. Note the exact error message
2. Capture the steps to reproduce
3. Check [Common Issues](/troubleshooting/common-issues.md)
4. Contact  with details

## Related

* [Common Issues](/troubleshooting/common-issues.md)
* [FAQ](/troubleshooting/faq.md)
* [API Errors](/api/errors.md)


---

# Frequently Asked Questions

Answers to common questions about WizChat.

## General

### What is WizChat?

WizChat is a platform for creating AI-powered chatbots that answer questions from your own documents and data. Upload PDFs, crawl websites, or connect databases, and your chatbot provides accurate answers grounded in your content.

### How is WizChat different from ChatGPT?

ChatGPT uses general knowledge. WizChat uses **your** knowledge base. Your chatbot only answers from documents you provide, ensuring accurate, relevant responses specific to your business.

### Do I need technical skills to use WizChat?

No. WizChat is designed for non-technical users. You can create, configure, and deploy chatbots without any coding. API access is available for developers who want deeper integration.

### What AI models does WizChat support?

WizChat supports multiple models:

* OpenAI: GPT-4o, GPT-4 Turbo, GPT-3.5
* Anthropic: Claude 3.5 Sonnet, Claude 3 Opus
* And more depending on your plan

## Documents & Knowledge Base

### What file types can I upload?

* **Documents:** PDF, DOCX, TXT, MD
* **Spreadsheets:** XLSX, CSV
* **Images:** PNG, JPG, WEBP (with OCR)
* **Videos:** MP4, AVI, MOV, MKV, WebM, WMV, YouTube links

### How large can my files be?

File limits depend on both your plan and file type.

**Effective per-file limit = min(plan limit, file-type hard limit)**

Plan base per-file limits:

* Free: 25 MB
* Starter: 200 MB
* Pro: 500 MB
* Pro+: 1 GB
* Business: 2 GB
* Enterprise: 5 GB

File-type hard limits:

* PDF: 500 MB
* CHM: 350 MB
* Excel/CSV: 200 MB
* Video: 1 GB
* Image: 50 MB
* Other documents: 500 MB

See [Subscription Plans](/billing/plans.md#file-upload-size-limits) for the full matrix.

### How does the chatbot find answers in my documents?

WizChat uses **Retrieval-Augmented Generation (RAG)**. Your documents are processed into searchable chunks. When a user asks a question, relevant chunks are retrieved and sent to the AI model, which generates an answer based on that content.

### Can I update documents after uploading?

Yes. You can replace documents with new versions. The old content is replaced with the new, and your chatbot immediately uses the updated information.

## Pricing & Billing

### What plans are available?

| Plan       | Price   | AI Budget   | Chatbots  |
| ---------- | ------- | ----------- | --------- |
| Free       | $0      | $5 lifetime | 1         |
| Starter    | $20/mo  | $20/mo      | 5         |
| Pro        | $50/mo  | $50/mo      | Unlimited |
| Pro+       | $100/mo | $100/mo     | Unlimited |
| Business   | $200/mo | $200/mo     | Unlimited |
| Enterprise | Custom  | Unlimited   | Unlimited |

### Is there a free plan?

Yes. The free plan includes:

* 1 chatbot (can delete and redeploy)
* **$5 lifetime AI budget** (never resets)
* 100 MB storage

The free plan budget is a lifetime grant to help you try WizChat. When your budget runs out, upgrade to a paid plan to continue.

### How does billing work?

WizChat uses **cost-based billing**. Instead of counting queries, we track actual AI costs:

* Different AI models have different costs per token
* Complex queries with more context cost more
* Simple queries cost less
* You pay for what you actually use

This is fairer because a simple greeting doesn't cost the same as a detailed analysis.

### Does the free plan budget reset monthly?

**No.** The free plan has a **lifetime $5 budget** that never resets. Once depleted, you must upgrade to continue.

### When does my paid plan budget reset?

Your budget resets on your **personal billing date** — the same day of the month you subscribed. For example, if you signed up on the 15th, your budget resets on the 15th of every month. This is not tied to the 1st of the month.

You can see your exact reset date on your Dashboard.

### What happens if I run out of budget?

**Free Plan:** Your chatbots are paused. Upgrade to a paid plan to continue.

**Starter/Pro/Pro+/Business:**

* Your budget resets automatically on your next billing date
* You can purchase [top-ups](/billing/top-up.md) anytime to add budget immediately
* Chatbots are paused until budget is available

**Enterprise:**

* Budget behavior is contract-based (typically uncapped)

### Can I change plans anytime?

Yes. Upgrades take effect immediately. Downgrades take effect at the end of your billing period.

### What are top-ups?

Top-ups let you purchase additional AI budget if you run out before your monthly reset. Available on Starter, Pro, Pro+, and Business plans.

## Teams & Sharing

### How do I collaborate with my team?

1. Create a team
2. Invite members via email
3. Share chatbots with the team
4. Team members can view/edit based on their role

### What are the team roles?

* **Owner:** Full control, manages billing
* **Admin:** Manages team and chatbots
* **Member:** Uses shared chatbots

### Can I share a chatbot without creating a team?

Yes. You can share chatbots with individual users by email without requiring a formal team.

### How many team members can I have?

| Plan       | Team Seats |
| ---------- | ---------- |
| Free       | -          |
| Starter    | -          |
| Pro        | -          |
| Pro+       | 5          |
| Business   | 20         |
| Enterprise | Unlimited  |

## Security & Privacy

### Is my data secure?

Yes. WizChat uses:

* AES-256 encryption at rest
* TLS 1.3 encryption in transit
* SOC 2 Type II certified infrastructure
* Regular security audits

### Where is my data stored?

You can choose between US and EU data regions. All data (documents, embeddings, conversations) stays in your selected region.

### Is WizChat GDPR compliant?

Yes. WizChat is GDPR compliant. For EU data subjects, use the EU data region. You can also enable Zero Data Retention mode for maximum privacy.

### Does the AI learn from my data?

By default, your data may be used by AI providers per their policies. Enable **Zero Data Retention (ZDR)** mode to ensure your data is not retained or used for training.

## Deployment

### How do I embed my chatbot on a website?

Add the provided JavaScript snippet to your website:

```


```

Or use an iframe embed for more control.

### Can I use my own domain?

* **Subdomains:** Available on all plans (yourbot.wizchat.app)
* **Custom domains:** Available on Pro and above (chat.yourcompany.com)

### Can I customize the appearance?

Yes. You can customize:

* Logo and colors
* Chat bubble style
* Welcome message
* Suggested questions

### Can I remove the "Powered by ChatFactory" branding?

Yes, on Pro plans and above. Free and Starter plans display the branding.

## Integrations

### What is MCP?

MCP (Model Context Protocol) is a standard that lets your chatbot connect to external tools like databases, CRMs, and APIs. Your chatbot can query Salesforce, run SQL queries, or use custom integrations.

### Which integrations are available?

Built-in integrations include:

* Salesforce
* Atlassian (Jira, Confluence)
* PostgreSQL
* Weather
* Calculator

You can also add custom MCP servers.

## Support

### How do I get help?

* Browse this documentation
* Check [Common Issues](/troubleshooting/common-issues.md)
* Email 
* Business plans include dedicated support

### Is there a status page?

Yes. Check [status.wizchat.com](https://status.wizchat.com) for service status and incident updates.

## Related

* [Common Issues](/troubleshooting/common-issues.md)
* [Error Messages](/troubleshooting/errors.md)
* [Getting Started](/getting-started/quick-start.md)


---