The public API is what the widget and the SDKs call. You can call it too, from a browser or a server. Every request needs a client key.

Base URL

https://app.kelu.dev
All paths below start with /api/v1/public. Self-hosted? Use your own server’s address. The paths are the same.

Endpoints

MethodPathWhat it does
POST/knowledge-bases/:knowledgeBaseId/chatStream an answer (SSE)
POST/threads/:threadId/chatAsk a follow-up
GET/knowledge-bases/:knowledgeBaseId/wsChat over WebSocket
POST/knowledge-bases/:knowledgeBaseId/searchSearch
POST/knowledge-bases/:knowledgeBaseId/form-deflectAnswer a support form
POST/deflections/:id/outcomeReport that the ticket was filed anyway
POST/feedbackRate an answer
DELETE/feedback/:messageIdWithdraw a rating
GET/knowledge-bases/:knowledgeBaseId/widget-configSettings the widget reads on load
GET/widget-integrations/:widgetId/configA saved widget’s settings
GET/form-deflectors/:deflectorId/configA saved form deflector’s settings
GET/knowledge-bases/:knowledgeBaseId/suggested-questionsStarter questions
POST/knowledge-bases/:knowledgeBaseId/relatedRelated articles
POST/knowledge-bases/:knowledgeBaseId/eventsRecord that the widget was opened: {"event": "opened", "end_user_id": "..."}. Returns 202
:knowledgeBaseId must be the knowledge base your key belongs to. Any other id returns 403.

Conventions

  • Request and response bodies are JSON. Chat streams Server-Sent Events.
  • Bodies are capped at 4 MB.
  • Questions on chat, search and WebSocket are capped at 4,000 characters.
  • Restricted documents are never returned.
  • group_ids (chat, search, form-deflect, WebSocket) limits answers to some source groups. Each id must be a source group of this knowledge base, or you get 403.

Errors

Errors are JSON with a matching HTTP status:
{
  "error": "client key is not authorized for this knowledge base",
  "code": "FORBIDDEN",
  "error_code": "forbidden",
  "retryable": false,
  "request_id": "5f0c..."
}
  • code is what to branch on. error is a sentence you can log or show.
  • error_code is the same class in lower case. Most errors carry it.
  • retryable says whether the same request can work later.
  • request_id is also sent as the X-Request-ID header. Quote it when you contact support.
StatusWhen
400Bad body, missing field, question too long
401Missing or wrong credentials (UNAUTHORIZED)
403Origin not allowed, key for another knowledge base, CAPTCHA missing or failed (CAPTCHA_REQUIRED, CAPTCHA_FAILED), an internal knowledge base (KNOWLEDGE_BASE_INTERNAL), or a source group outside this knowledge base
404Thread, message or deflector not found
413Body over 4 MB
429Rate limit reached (RATE_LIMITED). See rate limits
Chat and WebSocket report failures that happen mid-answer inside the stream. See chat errors and WebSocket errors.