Developer Documentation

Everything you need to integrate Citai into your website or application.

1 Quick Start

1. Create an API Key

Go to Settings > API Keys in your dashboard and create a new key. Save it securely, it's only shown once.

2. Copy the snippet

Paste this code before the closing </body> tag in your HTML. Replace YOUR_API_KEY with your actual key.

<script
  src="https://citai.ai/widget.js"
  data-api-key="sk-YOUR_API_KEY"
  data-base-url="https://citai.ai"
  data-lang="EN">
</script>

3. Done

The widget will appear as a floating bubble on your site. Visitors can chat with your knowledge base instantly.

2 Widget Configuration

All options are configured from Dashboard > API Keys > Edit. The widget loads them automatically from the server.

Snippet Attributes (HTML)

FieldTypeDefaultDescription
data-api-keystringYour API key (required). Identifies the tenant and widget configuration
data-base-urlstringBase URL of your Citai instance (required)
data-langstring(auto)Forces the widget language (ES, EN, PT, DE, FR, IT). If omitted, detects from HTML lang attribute, localStorage or browser
data-themestring(server)Widget visual theme (light / dark). If omitted, uses server configuration
data-positionstring"bottom-right"Bubble position (bottom-right / bottom-left)

Appearance

FieldTypeDefaultDescription
themestring"light"Widget theme (light / dark)
positionstring"bottom-right"Screen position (bottom-right / bottom-left)
primary_colorstring"#2563eb"Widget primary color (hex)
logo_urlstring | nullnullLogo URL shown in the header
powered_bybooleantrueShow 'Powered by Citai' in the footer

Messages

FieldTypeDefaultDescription
agent_namestring | nullnullAgent name displayed in the header
avatar_urlstring | nullnullAgent avatar URL
welcome_messagestring"Hola! ..."Initial welcome message
welcome_messages_i18nobject | nullnullWelcome messages by language (e.g. ES, EN, PT as keys)
farewell_messagestring | null"Gracias..."Farewell message when conversation ends
out_of_scope_messagestring | nullnullResponse when the question is out of scope

Interaction

FieldTypeDefaultDescription
conversation_startersstring[][]Initial suggestions as clickable chips
conversation_starters_i18nobject | nullnullInitial suggestions by language
quick_replies_templatesstring[][]Quick reply templates
pre_chat_fieldsPreChatField[][]Pre-chat form fields (name, email, etc.)
proactive_triggersProactiveTrigger[][]Proactive triggers: by time, scroll or URL
show_sourcesbooleantrueShow sources and citations in responses
rating_enabledbooleantrueAllow visitors to rate responses
inactivity_timeout_secondsinteger300Seconds of inactivity before timeout

Escalation

FieldTypeDefaultDescription
escalation_config.enabledbooleanfalseEnable escalation to human agent
escalation_config.webhook_urlstring | nullnullWebhook URL for receiving escalations
escalation_config.emailstring | nullnullEmail for escalation notifications
escalation_config.confidence_thresholdfloat0.3Minimum confidence for auto-escalation (0.0 - 1.0)
escalation_config.messagestring""Message shown to user on escalation

Business Hours

FieldTypeDefaultDescription
business_hours.enabledbooleanfalseEnable business hours
business_hours.timezonestring"UTC"Timezone (e.g., America/New_York)
business_hours.scheduleSchedule[][]Schedule by day (array with day, start, end)
business_hours.out_of_hours_messagestring""Out of hours message
business_hours.ooh_capture_enabledbooleanfalseAllow data capture outside business hours

3 Webhooks

Receive real-time notifications when events occur in your conversations. Configure them in Dashboard > Webhooks.

Headers on each request

Content-Type: application/json
X-Citai-Event: {event_type}
X-Citai-Signature: sha256={hmac}

Retries: 3 additional attempts on failure (1s, 5s, 30s).

Example: Node.js receiver

// Node.js / Express
const express = require('express');
const crypto = require('crypto');
const app = express();

app.use(express.json());

app.post('/citai-webhook', (req, res) => {
  // Verify signature (optional, if secret configured)
  const signature = req.headers['x-citai-signature'];
  if (signature) {
    const expected = 'sha256=' + crypto
      .createHmac('sha256', process.env.WEBHOOK_SECRET)
      .update(JSON.stringify(req.body))
      .digest('hex');
    if (signature !== expected) {
      return res.status(401).send('Invalid signature');
    }
  }

  const { event } = req.body;
  switch (event) {
    case 'escalation.triggered':
      // Create ticket in your CRM
      break;
    case 'low_confidence':
      // Alert your team
      break;
    case 'feedback.negative':
      // Log for review
      break;
  }

  res.status(200).send('OK');
});

app.listen(3000);

4 Plans & Limits

Usage limits per plan. FAQ matches are always unlimited on all plans.

FeatureFreeStarterPro
AI Queries / month50/mo500/mo5,000/mo
FAQ Matches
Knowledge Bases1520
Documents per KB1050200
API Keys1310
Storage100 MB500 MB2 GB
Team Members1520
Webhooks
Smart Routing

FAQ matches do not consume AI queries. They are always free and unlimited.

5 Knowledge Bases & Documents

Create knowledge bases, upload documents and configure access control for your organization.

Create & upload documents

Each Knowledge Base (KB) is a document container with its own RAG configuration.

  • Go to Knowledge Bases in the sidebar and click 'New KB'
  • Upload documents by dragging files or pasting a URL (HTML, PDF, DOCX)
  • Processing (chunking + embeddings) happens in the background with progress tracking

Access control

Each KB has a visibility level that determines who can query it.

Public

All tenant members can query it.

Private

Only the creator and admins can access it.

Group-based

Only members of the assigned groups have access.

Document processing

When you upload a document, Citai processes it automatically in multiple stages.

  • Chunking: splits the document into semantic fragments of configurable size
  • Embeddings: generates 384-dimension vectors with a multilingual model (ES/EN/PT/DE/FR/IT)
  • Contextual Retrieval: optionally enriches each chunk with full document context via LLM
FormatExtensionMax sizeDescription
PDF.pdf50 MBPDF documents with text and page extraction
DOCX.docx50 MBWord documents with preserved formatting
Excel.xlsx / .xls50 MBExcel spreadsheets (.xlsx and .xls). Use descriptive headers in row 1 for best results. All sheets are extracted as tabular text.
TXT.txt10 MBPlain text files
Markdown.md10 MBMarkdown files with formatting
URLN/AN/AURL ingestion: auto-detects HTML, PDF or DOCX

6 RAG Configuration

Each Knowledge Base has its own RAG configuration. Adjust these parameters from the KB settings or the Playground to optimize results.

ParameterTypeDefaultDescription
temperaturefloat0.3LLM creativity. Lower values produce more deterministic answers.
top_kint5Number of chunks to retrieve in hybrid search.
similarity_thresholdfloat0.3Minimum vector similarity threshold to include a chunk.
use_rerankingbooltrueEnable cross-encoder reranking to reorder by real relevance.
use_mmrbooltrueEnable MMR (Maximal Marginal Relevance) for result diversity.
mmr_diversityfloat0.3MMR diversity factor. Higher values reduce redundancy.
max_search_roundsint3Maximum autonomous search rounds (Agentic RAG). Up to 3.
cache_enabledbooltrueEnable semantic cache for repeated responses.
cache_ttl_hoursint168Cache time-to-live in hours (default: 7 days).
language_auto_detectbooltrueAutomatically detect query language (ES/EN/PT/DE/FR/IT).
language_overridestring | nullnullForce a specific language for all responses.
faq_thresholdfloat0.75Confidence threshold for a valid FAQ match.

These parameters can be adjusted per KB from Settings > RAG or from the Playground with real-time preview.

7 FAQ Management

FAQs provide instant answers without consuming AI queries. They are evaluated before the RAG pipeline.

Manual creation

Create FAQs one by one from the FAQ section of each Knowledge Base. Define question, answer and optionally multimedia attachments (images, videos, links).

Bulk import (CSV)

Import hundreds of FAQs from a CSV file with columns: question, answer, category. Ideal for migrations or existing knowledge bases.

Multimedia & attachments

Each FAQ can include images (with crop editor), videos and links. Image limits depend on the plan: Starter 3/FAQ, Pro 5/FAQ, Enterprise 10/FAQ.

Auto-suggested FAQs

Citai detects recurring unanswered queries and automatically generates suggested FAQs using AI. Admins can approve or reject them from the suggested FAQs panel.

Matching flow

When a user asks a question, the system searches for similar FAQs before querying the LLM.

Query embeddingSimilarity >= thresholdFAQ response (no LLM)

FAQ matches are always free and do not consume the AI query budget on any plan.

8 API Keys & Rate Limiting

Manage access keys for the embeddable widget and REST API. Each key has configurable permissions and limits.

Creating API Keys

Generate keys with the sk- prefix from Dashboard > API Keys. Each key is associated with specific Knowledge Bases and can be configured with allowed CORS origins.

Security

API keys are shown only once upon creation. They are stored hashed with SHA-256 in the database. If you lose a key, you must regenerate it.

Rate Limiting

Each API key has a per-minute request limit implemented with Redis sliding window (sorted sets). If the limit is exceeded, HTTP 429 is returned. If Redis is unavailable, rate limiting fails open.

Dynamic CORS

Each API key can have configured allowed origins. The CORS middleware validates the origin of each request against the key's list. This ensures the widget only works on authorized domains.

PlanMax API KeysRate Limit
Free110 req/min
Starter330 req/min
Pro10100 req/min

9 Live Chat & Human Handoff

Allows human agents to take over widget conversations when AI is not enough.

How it works

When a widget visitor needs human help (due to low confidence or manual escalation), the session enters a waiting queue. A team agent can claim the session from the Live Chat panel and respond in real time via SSE.

Session states

WaitingWaiting for an agent to claim the session
ActiveAn agent is responding in real time
ResolvedThe session was closed by the agent

Agent panel

Agents access the panel from the sidebar to manage live chat sessions.

  • Waiting queue: sessions pending to be claimed
  • Active sessions: ongoing conversations with the agent
  • History: resolved sessions with complete records

When it triggers

Handoff triggers automatically when response confidence is below the configured threshold, or manually when the visitor clicks the escalation button. Concurrency is handled with SELECT FOR UPDATE to prevent two agents from claiming the same session.

10 Smart Routing

Automatic Knowledge Base selection based on the semantics of the user's query.

How it works

Smart Routing computes centroids (average embeddings) of each KB and compares the user's query against these centroids using cosine similarity. It selects the top-3 most relevant KBs.

User querySimilarity vs centroidsTop-3 KBs selected

Minimum threshold

Only KBs with cosine similarity >= 0.15 are included. If no KB exceeds the threshold, all available tenant KBs are used.

Centroid cache

Centroids are cached in Redis for 24 hours. They are automatically invalidated when new documents are uploaded, reprocessed or FAQs are created.

Usage in Chat & Widget

In chat, enable the 'Auto' toggle to use Smart Routing. It disables automatically when you manually select a KB. In the widget, auto-routing applies when the API key has access to multiple KBs.

11 Analytics & Export

Comprehensive dashboard with real-time metrics, interactive charts and data export.

📊

Total queries

Resolution rate

💰

Cost per query

Cache hit rate

🎯

FAQ savings

🏷️

Tag distribution

Interactive charts

Visualize your assistant's performance with Chart.js charts.

  • Time series: queries per day/week/month with range filters
  • Resolution doughnut: resolved, escalated and negative
  • Horizontal bars: tag distribution with per-conversation detail

Knowledge gap detection

The system identifies queries that didn't get good answers and groups them by frequency. You can mark them as resolved, filter by KB or generate suggested FAQs directly.

AI auto-tagging

Each conversation is automatically tagged with one of 15 canonical categories using a background LLM call (fire-and-forget). Tags are used for analytics and filtering.

Data export

Export all analytics metrics in CSV or JSON format from the export button on the dashboard. Includes queries, resolution, costs, tags and knowledge gaps.

Revenue vs Cost (super admin)

Super admin exclusive view showing revenue, costs, profit and margin per tenant. Includes global totals cards and a detailed per-organization table.

12 GDPR & Data Privacy

Citai complies with GDPR principles. Here are the tools and policies available to manage personal data.

Art. 20

Data export

Download a ZIP file with all your organization's data: conversations, FAQs, documents, configurations and usage logs. Available from Settings > Account.

Art. 17

Account deletion

Request account deletion with password confirmation. A soft delete is performed, marking data for permanent deletion according to the retention policy.

Art. 5(1)(e)

Retention policies

Retention policies are configurable by the administrator. Define how long conversations, audit logs and widget session data are kept.

Art. 30

Audit log

Records over 15 event types (login, creation, deletion, config changes). Configurable retention with date-based purge. Accessible from the admin panel.

Stored data

Citai stores the following data, all isolated per tenant:

  • Conversations and messages (with confidence metadata and sources)
  • Original documents and their processed chunks
  • Vector embeddings (384 dimensions) associated with chunks and FAQs
  • Usage logs (queries, tokens, provider, query type) and audit logs

How to request export or deletion

From the app: go to Settings > Account to export data or request deletion. By email: contact [email protected] with your registered email address.

13 Tools & Auto-Inject

Connect external APIs so the agent can access real-time data. Two modes: the LLM decides when to call (flexible) or Auto-Inject from widget filters (deterministic).

LLM

LLM Mode

The AI model analyzes the user's question and decides if it needs external data. Flexible, ideal for optional tools.

E.g.: weather, exchange rates, news — the LLM calls only when relevant.

Auto

Auto-Inject Mode

The tool runs automatically with widget intake filter data. 100% deterministic, no LLM dependency.

E.g.: CRM, ERP, ticketing — customer data available from the first message.

Auto-Inject Flow

Widget opensIntake: customer codeAuto-inject: API callKB + real dataPersonalized response

The system maps widget filters directly to API parameters. The result is injected as context before the LLM generates the response, combined with the KB.

How to configure (4 steps)

  1. 1Set up an intake filter in your API Key (Settings > API Keys) with a key like 'customer_code'.
  2. 2Create a tool in Tools > New. Configure endpoint, auth, and parameters.
  3. 3Select 'Auto-inject from filters' and map each tool parameter to a widget filter.
  4. 4Test: open the widget, complete the intake, send a message. You'll see 'Loading your data...' before the response.

Widget SSE Events

EventStatusDescription
tool_callcallingThe LLM decided to call a tool (LLM mode).
tool_callauto_injectAuto-Inject tool executing with intake data.
tool_callsuccessTool executed successfully, result available.
tool_callerrorError executing the tool (timeout, HTTP error, etc).
👤

Test Template: CRM Demo

Demo

Use the 'CRM Demo (test)' template when creating a tool. Connects to DummyJSON (free public API) to simulate a customer lookup. Set up an intake filter with key 'nombre_cliente' in your API key.

// Endpoint: GET https://dummyjson.com/users/search
// trigger_mode: "auto_inject"
// filter_param_mapping: { "q": "nombre_cliente" }
intake_filter: nombre_cliente = "Emily"
→ GET /users/search?q=Emily&limit=1&select=firstName,lastName,email,phone
{ firstName: 'Emily', lastName: 'Johnson', email: '[email protected]', phone: '+81 965-431-3024' }

Per-widget tool filtering

Each API key can select which tools it uses. If tool_ids is null, it uses all tools. If it has IDs, only those tools. Configurable in Settings > API Keys > Enabled tools.

FieldValueDescription
tool_idsnullUses all tenant tools (default, backward compatible).
tool_ids[uuid, ...]Uses only the tools with those IDs.

Visual RAG: Document Images

Automatically extracts images from PDFs and DOCX and displays them in chat responses alongside relevant sources.

How it works

1. Upload PDF/DOCX2. Extract text + images3. Filter & dedup4. Associate to chunks5. Display in responses

Images are extracted during document processing, filtered (min 50x50px, dedup by hash, max 50/doc), and associated with chunks by page proximity. At runtime, images are included in the SSE sources event with zero latency impact.

SSE format: sources with images

The 'sources' event now includes an 'images' array in each source that has associated images:

{
  "sources": [{
    "document_name": "manual.pdf",
    "page": 21,
    "score": 0.73,
    "images": [
      { "url": "/api/v1/doc-images/.../img.jpg", "caption": null, "width": 800, "height": 600 }
    ]
  }]
}

RAG Configuration

Extraction is controlled via processing.extract_images (default: true). Can be toggled per-KB from the RAG Configuration dialog.

{
  "processing": {
    "extract_images": true
  }
}

Image Manager Endpoints

EndpointMethodDescription
/documents/{id}/imagesGETList document images with associations
/documents/{id}/images/uploadPOSTUpload manual image to document
/documents/{id}/images/{img}/associatePATCHAssociate image with a chunk
/documents/{id}/images/{img}/dissociatePATCHDissociate image from a chunk
/documents/{id}/images/chunksGETList document chunks (for association UI)

Semantic Cache

Vector-similarity response cache. If a new query has an embedding with cosine >= 0.95 against a cached entry from the same KB and same rag_config hash, the cached response is served without invoking the LLM.

When it runs

FAQ matchCache lookup (cosine ≥ 0.95)RAG pipelineLLM

After FAQ matching and before the RAG pipeline. Cache hits emit 'cached: true' in the SSE done event and are counted as query_type='cached' in usage_logs. Automatic invalidations happen on document reprocessing, FAQ create/update, and new doc upload.

RAGConfig parameters

Configurable per KB inside the retrieval block. Default: cache enabled with a 7-day TTL (168 hours). Valid range: 1 to 720 hours.

{
  "retrieval": {
    "cache_enabled": true,
    "cache_ttl_hours": 168
  }
}

Endpoints

EndpointMethodDescription
/admin/cache/statsGETStats: total entries, total hits, cached_queries, hit_rate
/admin/cache/flushPOSTFlush per tenant or per KB (body: [kb_id?: UUID])
/admin/cache/entriesGETPaginated list with filters (search, origin, sort)
/admin/cache/entries/{'{'}entry_id{'}'}GETEntry detail (full text, sources, embedding)
/admin/cache/entries/{'{'}entry_id{'}'}DELETEDelete a single entry or bulk

KB Health Score

0-100 score that measures the operational quality of each Knowledge Base, based on 5 weighted components. Cached in Redis for 1 hour; invalidated on doc upload/reprocess and FAQ create/update.

Components

Each component returns a 0-100 score with detailed breakdown (counts and averages). The final score is the weighted average.

25%Documents — based on total doc_count and chunk_count
15%FAQ Coverage — ratio between faq_count and queries from the last 30 days
30%RAG Quality — average confidence and percentage of low-confidence answers
15%Knowledge Gaps — total gaps vs unresolved gaps
15%Freshness — days since the last document update

Endpoints

EndpointMethodDescription
/knowledge-bases/health-summaryGETHealth score summary across all tenant KBs
/knowledge-bases/{'{'}kb_id{'}'}/healthGETPer-component breakdown + prioritized recommendations

Smart Routing

When an API key has multiple KBs or the user enables 'Auto' in chat, route_query() compares the query embedding against each KB centroid (AVG of chunk embeddings) using cosine similarity. Returns up to top 3 KBs with score >= 0.15. Centroids cached in Redis for 24h.

Auto-FAQ / Suggested FAQs

Automatically generates FAQ answers from the KB context for unanswered queries (knowledge gaps). Suggestions remain pending until an admin approves them (creates a real FAQ) or rejects them.

Flow

1) A query is logged as a knowledge gap. 2) Admin invokes suggest-faq (single or batch top 5). 3) The service skips queries with an existing similar FAQ (>= 0.85) or pending suggestion. 4) Calls the LLM to generate an answer from the KB context. 5) Stores in suggested_faqs with embedding. 6) Admin approves or rejects from the UI.

Endpoints

EndpointMethodDescription
/admin/analytics/unanswered/{'{'}id{'}'}/suggest-faqPOSTGenerate suggestion for one unanswered query (body: [kb_id])
/admin/analytics/unanswered/batch-suggestPOSTBatch generate top N unanswered for a KB (body: [kb_id, limit=5])
/admin/suggested-faqsGETPaginated list (filters: status, kb_id)
/admin/suggested-faqs/{'{'}id{'}'}/approvePOSTApprove — creates the real FAQ and invalidates cache
/admin/suggested-faqs/{'{'}id{'}'}/rejectPOSTReject — marks the suggestion as rejected

Content Rules

Per-KB declarative rules to block, redirect or filter sensitive content. Stored in the content_rules block of each KB's rag_config JSONB.

Rule types

  • BLOCKBLOCK — cuts the flow and emits SSE content_blocked with the custom response. Evaluated after FAQ + cache, before RAG.
  • REDIRECTREDIRECT — same as block but with type='redirect' (e.g. handoff to human support).
  • FILTERFILTER — does not cut the flow. Applied to retrieved chunks before passing them to the LLM, removing those that contain the triggers.

Schema in rag_config

Each rule has type, list of triggers (keywords that fire it), optional response (max 500 chars, only for block/redirect) and enabled.

{
  "content_rules": [
    {
      "type": "block",
      "triggers": ["password", "credit card"],
      "response": "I can't help with that.",
      "enabled": true
    },
    {
      "type": "filter",
      "triggers": ["internal-only"],
      "enabled": true
    }
  ]
}

SSE event content_blocked

Emitted when a query matches a BLOCK or REDIRECT rule. The widget and chat have native handlers to display the response without invoking the LLM.

event: content_blocked
data: {"type": "block", "response": "I can't help with that."}

Audit Log

Per-tenant log of critical events: login, configuration changes, KB/FAQ/API key create and delete, etc. Filterable by user, action, resource type and date range.

Endpoints

EndpointMethodDescription
/admin/audit-logGETPaginated list with filters: user_id, action, resource_type, date_from, date_to, search
/admin/audit-log/exportGETExport results as CSV
/admin/audit-log/retentionGETRead retention config in days (super_admin)
/admin/audit-log/retentionPUTUpdate retention days (super_admin)
/admin/audit-log/purgePOSTPurge logs older than retention (super_admin)

Tracked actions

The backend emits these action keys via audit_service. You can filter by any of them.

user.loginuser.logoutuser.password_changekb.createkb.deletedocument.uploaddocument.deletefaq.createfaq.deleteapi_key.createapi_key.deleteapi_key.regeneratetool.createtool.deleteplan.changetenant.inviteconfig.change

Full REST API

For advanced integrations, check the OpenAPI reference with all available endpoints.

Open Swagger UI