Skip to content

AI

Requires a license with the ai feature. See pricing. The support desk also needs the support capability, and it is beta.

AI puts the model providers you choose, with your own keys, behind the admin console, the API and your flows. Editors draft, rewrite and translate entries, images get alt text, and flows classify, extract and generate. Each tenant can switch AI off, write the instructions every call runs under, and read a transcript of what was asked and answered. Nothing goes anywhere except to the provider endpoint you configure.

PartWhat it isWho sets it
ProviderAn endpoint and its key: OpenAI, Anthropic, or any server that speaks one of their APIs, such as Ollama or OpenRouterA super admin
Tenant switchTurns AI, and storing transcripts, on or off for one tenantA tenant admin
PromptThe instructions a kind of call runs under, kept as numbered versionsA tenant admin
TranscriptThe record of one conversation: what was asked, what came back, the model, tokens and estimated costWritten by every call
Price tableWhat a model costs per 1,000 tokens or per image, so each call carries an estimateA super admin

A call goes to the tenant's enabled providers in priority order, highest priority first, and the first one that can do the job answers. An operation no provider can do answers 409 rather than going somewhere unexpected.

You need an admin token in TOKEN from a super admin, and a key from your provider. The quickstart shows how to get the token.

  1. Check that AI is on for your tenant:

    Terminal window
    curl http://localhost:3001/api/admin/ai/settings \
    -H "Authorization: Bearer $TOKEN"
    { "tenant_id": "default", "enabled": true, "transcripts_enabled": true, "updated_at": "0001-01-01T00:00:00Z" }
  2. Add a provider. enabled is false unless you send it:

    Terminal window
    curl -X POST http://localhost:3001/api/admin/ai/providers \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"name": "openai", "kind": "openai", "api_key": "sk-your-key", "default_model": "gpt-4o-mini", "enabled": true, "priority": 10}'

    The answer is 201 with the provider. The key is never returned: "has_key": true says one is stored.

  3. Summarize a text:

    Terminal window
    curl -X POST http://localhost:3001/api/admin/ai/summarize \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"content": "LyEve now ships eighteen starter flows, from a sitemap to a nightly sheet export.", "style": "concise"}'
    {
    "summary": "LyEve adds eighteen ready-made flows.",
    "model": "gpt-4o-mini",
    "tokens_used": 74,
    "tokens_in": 61,
    "tokens_out": 13,
    "cost_estimate": "0.000017",
    "transcript_id": "1e7c9a40-3b2d-4f58-8a61-0d9e2c4b7f35"
    }

    A key the provider refuses answers 503 with ai summarization failed.

  4. Read the transcript of that call:

    Terminal window
    curl "http://localhost:3001/api/admin/ai/transcripts?kind=route&limit=1" \
    -H "Authorization: Bearer $TOKEN"

    The newest transcript is first, with its model, prompt version and number of messages. GET /api/admin/ai/transcripts/{id} adds the messages.

  5. In the admin console, open Operations > AI > Transcripts to read it, download it as JSON or Markdown, or ask for a recap.

A super admin adds providers under Operations > AI > Providers, or with POST /api/admin/ai/providers. Keys are encrypted with ENCRYPTION_KEY, one derived key per tenant.

FieldMeaning
name, kindRequired. The kind is one of the four below
api_keyRequired for openai and anthropic. Optional for a compatible server
base_urlRequired for a compatible kind, unless a preset fills it
default_modelThe model used when a call names none
enabledfalse unless you send true
priority-1000 to 1000. The highest goes first
modalitiesWhich of text, embed and image it may serve. All three when left out
max_budget_usdA monthly cap on estimated spend. 0 means no cap
KindTextEmbeddingsImagesDescribe an image
openaiyeswith an embedding modelwith an image modelwith a vision model
anthropicyesnonoyes
openai_compatibleyeswhen the server has an embedding model, named in the callwhen the server has an image modelwhen the model can see
anthropic_compatibleyesnonowhen the model can see

GET /api/admin/ai/providers/{id}/models lists the provider's models, and .../capabilities?model= says what one model can do.

openai_compatible speaks the OpenAI API and anthropic_compatible the Anthropic one, to a gateway, another vendor or a server on your network. Besides base_url they take key_header, the header the key travels in (empty means Authorization: Bearer for the OpenAI shape and x-api-key for the Anthropic one), and query_string, appended to every request, which Azure OpenAI needs for its api-version.

With "kind": "openai_compatible", a preset fills in what you left empty:

PresetFills in
ollamahttp://localhost:11434/v1
vllmhttp://localhost:8000/v1
lm_studiohttp://localhost:1234/v1
openrouterhttps://openrouter.ai/api/v1
groqhttps://api.groq.com/openai/v1
deepseekhttps://api.deepseek.com/v1
geminihttps://generativelanguage.googleapis.com/v1beta/openai, with your Gemini API key
azurekey_header: api-key. You supply your deployment's URL

A provider URL that resolves to a private, loopback or link-local address is refused unless the provider sets allow_private: true, which a local Ollama, vLLM or LM Studio needs. The address is checked when the provider is saved and again on every call, and the instance's own database address is always refused.

If ENCRYPTION_KEY changes, stored keys can no longer be read, and calls skip those providers. With no other provider left, a call answers 503. Enter each key again.

A tenant admin sets two switches under Operations > AI > AI settings: AI for this tenant and Store transcripts. Over the API:

Terminal window
curl -X PUT http://localhost:3001/api/admin/ai/settings \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": false}'

A field you leave out keeps its value. Off means off everywhere: every AI and support desk route except the settings pair answers 404 with AI is switched off for this tenant, the flow nodes refuse to run, and both editor assistants refuse.

Every call runs under the prompt for its use case: default, assistant (the content editor and generate), flow_assistant (the flow editor), translate, summarize, suggest (search suggestions), alt_text, classify, extract, recap and support. Edit them under Operations > AI > Prompts, or save a new version:

Terminal window
curl -X POST http://localhost:3001/api/admin/ai/prompts/summarize \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"body": "Summarize for a product newsletter. Use plain words."}'

The answer is 201 with the new version, which becomes active. Versions are never edited, the shipped default is version 0, and each transcript records the version it ran under, so you can always read what a call was told. GET /api/admin/ai/prompts lists every use case with its default, its active version and its history.

The instructions a call sends are, in order:

  1. The tenant's prompt for the use case.
  2. Text the caller added for this call: system on a flow node, or system_prompt on generate.
  3. A fixed guardrail, which you cannot change. It tells the model to treat anything between <user_content> or <user_query> tags as data, never as instructions, and never to reveal its instructions.

These routes need an admin. Most take an optional provider_id, model, max_tokens (up to 200,000) and temperature (0 to 2, where 0 leaves the provider's default).

RouteSendGet back
POST /api/admin/ai/generateprompt, optional system_promptcontent with title and body
POST /api/admin/ai/summarizecontent, optional style (concise, bullet, paragraph, tl;dr) and max_length in wordssummary
POST /api/admin/ai/suggestionsquery, optional context and count (1 to 20, and 5 for anything else)suggestions, a list of strings
POST /api/admin/ai/translatetext (up to 20,000 characters), to, optional from, glossary (up to 100 terms), tone, format (html, rich_text, markdown or url)text, from, to, machine: true, model, tokens
POST /api/admin/ai/media/{id}/describeoptional prompttext, a suggested alt text that is not saved on the image, and cost_estimate_usd. Needs a model that can see

The answers also carry model, tokens_in, tokens_out, cost_estimate and transcript_id, except where the table says otherwise. translate takes none of the optional provider fields, and its answer carries no transcript_id or cost_estimate, although the call is still recorded in a transcript. translate saves nothing, so write the result into the entry's translation yourself. A glossary entry that maps a term to itself keeps a product name untranslated.

The content editor's assistant is POST /api/admin/content/ai-assist, and GET /api/admin/content/ai-usage returns the tenant's token totals. The flow editor's assistant is covered in Build a flow with the assistant.

Four node types appear in the flow editor's AI category. They need flow-pro as well as ai, run in the flow's tenant, and refuse with the reason when AI is switched off or the tenant has no enabled provider. Every node takes an optional provider (a provider's name or id) and model.

NodeWhat it doesKey settingsAdds to the output
ai.completeSends a prompt and returns the textprompt (required), use_case (custom, translate, summarize), system, max_tokens, temperature, json_schemajson when json_schema is set
ai.classifyPicks which of your labels applyinput, labels (both required), multilabel, the first match or "", and labels
ai.extractReturns a JSON object that matches a schema, with one retryinput, schema (both required)data, the object
ai.imagegenerate, variation or inpaint an image into the media library, or describe onekind (required), prompt, source, mask, sizemedia_ids, or text for describe

The text nodes also output text, provider, model, tokens_in, tokens_out, cost_estimate and transcript_id.

A test run checks the switch and calls no provider: ai.complete answers example answer, ai.classify the first label, ai.extract an empty object and ai.image an example. A test with live: true calls the provider. The flow definition format covers expressions and the other nodes.

A transcript has a kind: assistant (the content editor), flow_assistant, node, route or support. It records the provider, model, prompt use case and version, who started it and when, and each message's role, text, tokens, latency and cost. A content editor transcript names its entry, and a node transcript its node.

List them with GET /api/admin/ai/transcripts, filtered by kind, subject_kind and subject_id. .../{id}/export?format=json or format=markdown downloads one, and POST .../{id}/recap asks the same provider for a short recap and stores it on the transcript.

Transcripts are kept for AI_TRANSCRIPT_RETENTION after they start, 30 days by default, and older ones are removed every hour. When the instance setting AI_TRANSCRIPTS_ENABLED or the tenant's switch is off, no text is stored and answers carry no transcript_id. Cost and latency are still recorded.

Each call's cost_estimate is a USD amount computed from the price table at GET /api/admin/ai/prices: one row per kind and model, priced per 1,000 input tokens, per 1,000 output tokens and per generated image, with a * row per kind for models the table does not name. Vendors change their prices, so a super admin keeps the rows current with PUT /api/admin/ai/prices/{kind}/{model} (input_per_1k, output_per_1k, image_per_call) and removes them with DELETE. The estimate is what the table says, not what the vendor bills.

When a provider has max_budget_usd and the tenant's estimated spend on it in the current calendar month (UTC) reaches the cap, calls to it answer 402 with ai budget exhausted for this billing period before anything is sent. The call does not move on to another provider.

GET /api/admin/ai/dashboard shows calls, cost and latency per provider and model since the start, and GET /api/admin/ai/cost-log lists the newest 50 calls, filtered by provider_id, model, and from and to as RFC 3339 times.

The support desk answers questions from a knowledge base you write, with the same providers, prompts and transcripts. It is for admins: there is no public chat route. Each conversation is a transcript of kind support, under the tenant's support prompt.

Terminal window
curl -X POST http://localhost:3001/api/admin/support/chat \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"message": "How do I reset my password?"}'

The answer carries reply, confidence, sources, escalated, tokens_used and conversation_id. Send the conversation_id back to continue.

  • When the whole knowledge base fits the limits below, it goes to the model in one block, which lets a provider cache it, and confidence is 0.9. Otherwise the question is embedded, the top_k nearest articles go instead, and confidence reflects how close they were.
  • A turn below min_confidence escalates the conversation. Escalating only sets its status: it reaches no person by itself.
  • An escalated or resolved conversation takes no more turns.
  • Chat answers 409 while the tenant does not store transcripts.

Every desk route needs the support capability and answers 402 naming support without it. It also needs ai.

Support desk settings
VariableWhat it doesDefault
PLUGINS_SUPPORT_RAG_TOP_KArticles retrieved per question when the base is not sent whole5
PLUGINS_SUPPORT_RAG_MIN_CONFIDENCEBelow this, a turn escalates0.6
PLUGINS_SUPPORT_RAG_MAX_TOKENSLongest answer1024
PLUGINS_SUPPORT_RAG_CAG_MODESend the whole base when it fitstrue
PLUGINS_SUPPORT_RAG_CAG_MAX_ENTRIESMost articles sent whole. 0 is no limit0
PLUGINS_SUPPORT_RAG_CAG_MAX_CHARSMost characters sent whole. 0 is no limit32000
PLUGINS_SUPPORT_RAG_REINDEX_BATCH_SIZEArticles per embedding call on reindex50
PLUGINS_SUPPORT_RAG_REINDEX_TIMEOUT_SECSLongest a reindex may run600
PLUGINS_SUPPORT_RAG_REINDEX_RATE_LIMIT_MSPause between reindex batches0
Support desk routes
MethodPathPurposeRole
POST/api/admin/support/chatOne turn: message, optional conversation_idadmin
GET/api/admin/support/conversationsConversations, newest first (limit, offset)admin
GET/api/admin/support/conversations/{id}One conversation with its turnsadmin
POST/api/admin/support/conversations/{id}/escalateHand it to a person. Repeating it answers 409admin
POST/api/admin/support/conversations/{id}/resolveClose it. Repeating it answers 409admin
GET/api/admin/support/knowledgeList articlesadmin
POST/api/admin/support/knowledgeCreate an article: title, content, optional source, metadata (a string) and embedsuper admin
GET, PUT, DELETE/api/admin/support/knowledge/{id}One article. Changes need a super adminadmin
POST/api/admin/support/knowledge/reindexEmbed every article again. Answers total, embedded, errorssuper admin
POST/api/admin/support/feedbackRate an answer: conversation_id, message_id, rating 1 to 5, comment, resolved, kb_entry_idadmin
GET/api/admin/support/analyticsConversations, deflection rate, average confidence, article count and recent daily countsadmin
VariableWhat it doesDefault
ENCRYPTION_KEYEncrypts provider keys. At least 32 characters and different from JWT_SECRET. See configurationrequired
AI_TRANSCRIPT_RETENTIONHow long transcripts are kept. A value under 1h is ignored720h
AI_TRANSCRIPTS_ENABLEDInstance switch for storing transcripts. false, 0, off or no turns it offtrue
AI_PROVIDER_TIMEOUTLongest one provider call may take, held between 5s and 300s60s

The last three can also be set on the AI configuration form in the admin console, where a change applies without a restart. An environment variable wins over the form. Providers live in the database, not in the environment. If you set LYEVE_PLUGINS to choose which features start, include ai in it. See licensing and tiers.

Every route is on the Admin API. Provider and price changes need a super admin, everything else an admin.

AI routes
MethodPathPurpose
GET, PUT/api/admin/ai/settingsThe tenant switch
GET, POST/api/admin/ai/providersList or create providers
GET, PUT, DELETE/api/admin/ai/providers/{id}One provider
GET/api/admin/ai/providers/{id}/modelsThe models the provider offers
GET/api/admin/ai/providers/{id}/capabilities?model=What a model can do
GET/api/admin/ai/promptsEvery use case
GET, POST/api/admin/ai/prompts/{use_case}One use case, or save a new version with body
GET/api/admin/ai/pricesThe price table
PUT, DELETE/api/admin/ai/prices/{kind}/{model}Change or remove a price
GET/api/admin/ai/transcriptsList transcripts
GET/api/admin/ai/transcripts/{id}One transcript
GET/api/admin/ai/transcripts/{id}/exportDownload a transcript
POST/api/admin/ai/transcripts/{id}/recapRecap a transcript
POST/api/admin/ai/generateGenerate a title and body
POST/api/admin/ai/translateTranslate one field
POST/api/admin/ai/summarizeSummarize
POST/api/admin/ai/suggestionsSearch suggestions
POST/api/admin/ai/media/{id}/describeAlt text for an image
GET/api/admin/ai/dashboardSpend and latency
GET/api/admin/ai/cost-logThe newest calls
POST/api/admin/content/ai-assistThe content editor's assistant
GET/api/admin/content/ai-usageToken totals
POST/api/admin/ai/assist/flowThe flow assistant drafts a definition
POST/api/admin/ai/assist/flow/explainThe flow assistant explains a node or a problem

The ones you are most likely to meet:

  • 404 AI is switched off for this tenant: the tenant switch is off.
  • 503 no enabled AI provider configured: add or enable a provider, or fix the provider_id you sent.
  • 409 no configured provider supports this operation: no enabled provider can do it, such as images on Anthropic.
  • 402 ai budget exhausted for this billing period: the provider's monthly cap is spent.
Other errors
StatusMessageCause
400body must be a JSON object with text and toA translate body that is not JSON or has a field translate does not take.
400api_key is required for this kindA new openai or anthropic provider without a key.
400base_url does not resolve to a public address; allow_private is required for a private oneA local server without allow_private.
402payment_requiredThe license lapsed while the instance ran, or a desk route without support.
409conversation is closedA desk turn on an escalated or resolved conversation.
422validation error: the source and the target are the same localeTranslate with from equal to to.
503the operation's message, such as ai summarization failedThe provider failed. The reason is in the server log, never in the response.

On a self-hosted install, the only bytes that leave are the request to the endpoint you configured, when a call is made and not before. That request carries the instructions, the conversation so far, and for an image operation the picture or the prompt for one. For the flow assistant it carries the node catalog, the definition on the canvas and your prompt. For the support desk it carries the knowledge base articles it chose. It goes to the vendor behind that endpoint and to nobody else.

Never sent anywhere: content other than what a call puts in the request, provider keys (except to their own endpoint), other tenants' data, transcripts, and any signal that the feature is in use. The product ships no default provider, no hosted proxy and no telemetry of prompts. The cost log keeps tokens, latency and cost, never text. A signed license token contacts nothing. An opaque license key is exchanged with the license server once, and again to renew, and that request carries the key and an instance id, never anything this feature handles. LyEve Labs never sees your prompts, answers, keys, transcripts, which vendor you use, or whether you use the feature at all.

A model server on your own network, such as Ollama or vLLM with allow_private, sends nothing to a third party.

When a provider call fails, the server log records the vendor's error answer, up to 2 KiB, and some vendors repeat part of the request in it. Treat the server log with the same care as transcripts.

Under the GDPR and similar laws, the roles on a self-hosted install are these.

You are the controller of every prompt, answer and transcript your instance produces. You decide whether the feature is on, which endpoint answers, what the prompts say, and whether and for how long transcripts are stored.

The vendor behind your endpoint is your processor. OpenAI, Anthropic, Google, OpenRouter or whichever endpoint you configured processes what you send under the data processing agreement you hold with that vendor. That agreement, and the vendor's terms on whether your prompts may be used for training, are yours to read and sign. This page does not summarize them. A model server on your own network has no third-party processor.

LyEve Labs is not a party to that agreement and is not a processor of prompt data, because no prompt reaches us. Our processor role covers the sales and license records for your subscription, which carry no prompt.

What the product gives you to build on:

  • Storage limitation. Transcripts expire after the retention you set, 30 days by default. Deleting a tenant removes its transcripts, providers, prompts, settings, cost history and support desk data.
  • Access and erasure. A privacy export returns the transcripts a person started and every message whose text contains the identifier you name, matched without regard to case. Erasure replaces those messages, and any recap that contains the identifier, with {"redacted":true}, and keeps the tokens and cost so usage totals stay whole. A transcript is matched to the person who started it by the identifier it was recorded under, which is usually the user id, so name the user id in the request.
  • Off switches. A tenant admin can switch the feature and transcript storage off.

What to write in your records of processing:

  • The purpose you use the feature for.
  • The vendor and endpoint as the recipient, with the country it processes in as the vendor states it.
  • That the data sent is the prompt, the conversation and any picture, at the moment of a call.
  • That transcripts are kept for the window you set.
  • That privacy export and erasure reach transcripts, matched by the account that started one and by the identifier appearing in its text.

Nothing on this page makes the product compliant on its own. Compliance is a property of your deployment and your agreements, and this section lists what the product gives you to build it.