Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt

Use this file to discover all available pages before exploring further.

POST /api/v1/ai/chat

Stream a conversation with the AI assistant. Uses the Vercel AI SDK streamText() to stream responses with multi-step tool calling support (up to 5 tool steps per message). Messages are persisted to the database after the stream completes. Conversations are auto-created if no conversationId is provided. Rate limited to 30 requests per 60 seconds per user. Request timeout: 60 seconds.

Headers

HeaderRequiredDescription
Content-TypeYesapplication/json
X-Tenant-IdYesTenant identifier
X-User-IdNoUser identifier for conversation ownership

Request Body

FieldTypeRequiredDescription
messagesarrayYesAI SDK message array. Each message has role (user, assistant, tool) and content (string or parts array). Must not be empty.
routestringNoCurrent page route for context routing (e.g., "/studio/decision-flows"). Determines which tools and system prompt are used. Defaults to "/" (general context with all tools).
conversationIdstringNoExisting conversation ID to continue. If omitted, a new conversation is auto-created. When provided, persisted message history is prepended to the messages array.

Response

Returns a streaming UIMessageStreamResponse (Server-Sent Events). The response includes:
  • X-Conversation-Id header with the conversation ID for follow-up messages
  • Streamed text chunks and tool call results in AI SDK wire format

Roles

admin, editor, viewer

Example

curl -N -X POST https://playground.kaireonai.com/api/v1/ai/chat \
  -H "Content-Type: application/json" \
  -H "X-Tenant-Id: my-tenant" \
  -d '{
    "messages": [{ "role": "user", "content": "What are my top performing offers?" }],
    "route": "/dashboards"
  }'

Context Routing

The route parameter determines which tools are available:
Route PatternModuleTools Available
/data/schemasData18 read-only + addSchemaField, getSchemaFields, createSchema
/data/flow-pipelinesData18 read-only + getSchemaFields, createFlowPipeline, updateFlowPipeline
/data/*Data18 read-only + createConnector, testConnector
/studio/decision-flowsStudio18 read-only + 30+ creation, mutation, V2 pipeline, and intelligence tools
/studio/treatmentsStudio18 read-only + creation tools + content generation + 8 CMS tools
/algorithms/*Algorithms18 read-only + model management + 4 model intelligence tools
/dashboards/*Dashboards18 read-only + runHealthCheck, analyzeOfferPerformance, analyzePolicyConflicts
Any otherGeneralAll 105+ tools

GET /api/v1/ai/conversations

List recent conversations for the tenant (up to 50, newest first). Requires session authentication.

Response

[
  {
    "id": "conv_abc123",
    "title": "What are my top performing offers?",
    "userId": "user_001",
    "createdAt": "2026-03-18T10:30:00Z",
    "updatedAt": "2026-03-18T10:35:00Z",
    "user": { "name": "Admin User", "image": null }
  }
]

Roles

Requires session authentication (any authenticated user).

POST /api/v1/ai/conversations

Create a new conversation.

Request Body

FieldTypeRequiredDescription
titlestringNoConversation title. Default: "New conversation"
Response: 201 Created with the created conversation object.

Roles

Requires session authentication.

GET /api/v1/ai/conversations/

Get a single conversation with its full message history, ordered by creation time ascending.

Path Parameters

ParameterTypeDescription
idstringConversation ID

Response

{
  "id": "conv_abc123",
  "title": "What are my top performing offers?",
  "tenantId": "my-tenant",
  "userId": "user_001",
  "createdAt": "2026-03-18T10:30:00Z",
  "updatedAt": "2026-03-18T10:35:00Z",
  "messages": [
    { "role": "user", "content": "What are my top performing offers?", "createdAt": "2026-03-18T10:30:00Z" },
    { "role": "assistant", "content": "Based on the data...", "toolInvocations": [...], "createdAt": "2026-03-18T10:30:05Z" }
  ]
}

Roles

Requires session authentication. Only conversations belonging to the user’s tenant are accessible.

DELETE /api/v1/ai/conversations/

Delete a conversation and all its messages. Only deletes conversations belonging to the authenticated user’s tenant.

Path Parameters

ParameterTypeDescription
idstringConversation ID

Response

{ "ok": true }

Roles

admin, editor

POST /api/v1/ai/analyze/

Run AI-powered analysis on tenant data. Supports three analysis types with automatic LLM/ML Worker routing based on data volume. The ML row threshold is 5,000 rows.

Path Parameters

ParameterValuesDescription
type"policies", "segments", "content"Type of analysis to perform

Request Body

FieldTypeRequiredDescription
schemaIdstringRequired for segmentsID of the data schema to analyze
confirmedbooleanNoSet true to bypass the large-dataset confirmation dialog
preferredTier"llm" or "ml_worker"NoOverride automatic tier routing

Analysis Types

TypeData SourceLLM MethodML Worker Method
segmentsDataSchema rows and field statisticsgenerateObject() with field summaries to propose segment definitionsK-Means clustering with silhouette scoring on full dataset
policiesInteractionHistory tablegenerateObject() with channel breakdown and frequency bandsStatistical frequency binning and correlation analysis
contentTreatment (Creative) records (max 200)generateObject() with creative metadata and performance metricsTF-IDF and statistical content pattern analysis

Response — Confirmation Required

When the dataset exceeds 5,000 rows and confirmed is not true:
{
  "requiresConfirmation": true,
  "tier": "ml_worker",
  "warning": "Dataset has 50,000 rows. For datasets over 5,000 rows, enable the ML Worker for faster and cheaper analysis.",
  "confirmationMeta": {
    "rowCount": 50000,
    "accuracy": "ML Worker uses K-Means clustering, logistic regression, and TF-IDF -- more accurate than LLM pattern matching for large datasets.",
    "costEstimate": "Proceeding with LLM will use approximately 3,750,500 tokens (~$0.56).",
    "speedComparison": "ML Worker processes locally in seconds vs LLM round-trip latency."
  }
}

Response — Analysis Complete

{
  "results": [
    { "name": "High-Value Loyalists", "description": "...", "size": 2340, "percentage": 18, "filterRules": [...], "characteristics": [...], "suggestedUse": "..." }
  ],
  "source": "llm",
  "analysisType": "segments"
}

Response — ML Worker Job Submitted

{
  "jobId": "job_abc123",
  "source": "ml_worker",
  "analysisType": "segments"
}

Heuristic Fallbacks

Each analyzer falls back to deterministic heuristics if the LLM call fails:
  • Segments: Splits the most variable numeric field into Low/Mid/High at the 33rd and 67th percentiles
  • Policies: Finds the frequency band with the highest conversion rate and recommends a cap one step below the drop-off point
  • Content: Computes CTR/CVR per creative, flags underperformers below 50% of average, highlights top performers above 150% of average

Roles

admin, editor

GET /api/v1/ai/analyzer-settings

Get current AI analyzer settings for the tenant with defaults filled in. Returns four sections: segmentation, policy, content, and ruleBuilder.

Response

{
  "segmentation": {
    "minClusters": 2,
    "maxClusters": 8,
    "algorithm": "kmeans",
    "includedFeatures": null
  },
  "policy": {
    "dailyCap": 3,
    "weeklyCap": 10,
    "monthlyCap": 30,
    "lookbackDays": 90,
    "minSampleSize": 100
  },
  "content": {
    "minImpressions": 100,
    "metricWeights": { "ctr": 0.33, "cvr": 0.34, "revenue": 0.33 },
    "confidenceLevel": 0.95
  },
  "ruleBuilder": {
    "maxConditions": 5,
    "allowedOperators": ["equals", "gt", "lt", "gte", "lte", "contains", "in"],
    "fieldTypeConstraints": null
  }
}

Roles

admin, editor, viewer

PUT /api/v1/ai/analyzer-settings

Update AI analyzer settings. Each sub-schema is validated independently using Zod. Invalid values in one section do not affect valid values in other sections.

Request Body

Partial object matching the response structure of GET /api/v1/ai/analyzer-settings. Only include sections you want to update.
{
  "segmentation": { "maxClusters": 12 },
  "policy": { "lookbackDays": 180 }
}

Response

Returns the full merged settings object (same format as GET).

Roles

admin only

POST /api/v1/ai/intelligence

Dispatch to intelligence backend tools. This is a bridge endpoint used by the MCP server (which runs as a separate stdio process and cannot import Next.js server modules directly).

Request Body

FieldTypeRequiredDescription
toolstringYesTool name (see table below)
paramsobjectYesTool-specific parameters. tenantId is auto-injected.

Available Tools

ToolParametersDescription
explainDecisioncustomerId, offerId?, decisionFlowKey?Explain why a customer received or did not receive an offer. Full funnel walkthrough.
compareOfferEligibilitycustomerId, offerIds (2-5)Side-by-side offer eligibility comparison.
listCustomerSuppressionscustomerIdActive contact policy suppressions for a customer.
traceCustomerJourneycustomerId, limit? (default 20)Customer activity timeline: interactions, journeys, experiments.
analyzeQualificationFunneldecisionFlowKey?Funnel analysis identifying bottleneck rules.
analyzeContactPolicySuppressionchannel?, period? (day/week/month)Suppression rate analysis by rule type and channel.
analyzePolicyConflicts(none)Detect conflicts across offers, rules, policies, experiments.
analyzeOfferPerformanceperiod? (day/week/month), limit? (default 20)Offer performance with trends and actionable insights.
simulateRuleChangeruleId, proposedChange: { field, oldValue, newValue }Before/after reach estimation for rule changes.
simulateFrequencyCapChangechannel, currentCap, newCap, periodImpact of frequency cap change: customers unlocked/suppressed, fatigue risk.
analyzeModelHealthmodelIdModel metrics, performance trend, feature importance, data freshness, health verdict.
explainModelScoringmodelId, customerIdScore breakdown: raw score, percentile, contributing features with direction.
suggestModelImprovementsmodelIdMissing predictors, model type advice, unused features, hyperparameter suggestions.
detectModelDriftmodelIdDistribution shift detection, calibration check, action recommendation.
runHealthCheck(none)Comprehensive tenant health check (cached 5 minutes).
analyzeCrossModule(none)Cross-module correlation analysis (see below).

analyzeCrossModule Response

Returns insights that connect dots across modules — the platform’s most valuable intelligence layer.
{
  "tenantId": "tenant_001",
  "analyzedAt": "2026-03-26T15:34:24.991Z",
  "insights": [
    {
      "id": "policy-blocks-offer_001",
      "type": "policy_blocks_top_offer",
      "severity": "warning",
      "title": "Category suppression may limit \"Win-Back Lapsed Policy\"",
      "description": "\"Win-Back Lapsed Policy\" has a 9.8% CVR (top performer) but category suppression may be blocking repeat impressions.",
      "impact": "Potential revenue loss: relaxing this policy for high-value customers could increase conversions by 10-20%.",
      "action": {
        "label": "Review Policy",
        "type": "navigate",
        "href": "/studio/contact-policies"
      },
      "entities": [
        { "type": "offer", "id": "offer_001", "name": "Win-Back Lapsed Policy" },
        { "type": "contactPolicy", "id": "cp_001", "name": "Category Suppression After Dismiss" }
      ]
    }
  ],
  "summary": { "total": 4, "critical": 0, "warning": 4 }
}
Correlation TypeSeverityWhat It Detects
policy_blocks_top_offerwarningContact policy suppressing a high-CVR offer
low_auc_model_in_active_flowcriticalNear-random model active while decision flow is published
zero_cvr_high_spendwarningOffer with many impressions but zero conversions
Each insight includes an action object that the UI renders as a one-click button (either navigation or direct API call).

Response

Returns the tool’s result directly as JSON. Errors return 500 with { "error": { "message": "..." } }.

Roles

admin, editor, viewer

POST /api/v1/ai/parse-rule

Parse a natural language rule description into structured entity definitions. Uses LLM-powered parsing with regex-based heuristic fallback if the LLM call fails. The parser loads the tenant’s data schemas to provide field context to the LLM. It produces three entity types: qualification_rule, contact_policy, and behavioral_metric.

Request Body

FieldTypeRequiredDescription
textstringYesNatural language rule description

Response

{
  "entities": [
    {
      "type": "qualification_rule",
      "name": "Age >= 25",
      "payload": {
        "conditions": [{ "field": "customer.age", "operator": "gte", "value": 25 }],
        "ruleType": "hard"
      }
    },
    {
      "type": "behavioral_metric",
      "name": "total_spend_90d",
      "payload": {
        "aggregation": "sum",
        "field": "revenue",
        "windowDays": 90,
        "description": "Sum of revenue from conversions over the last 90 days"
      }
    },
    {
      "type": "qualification_rule",
      "name": "Spend >= $500 (90d)",
      "payload": {
        "conditions": [{ "field": "total_spend_90d", "operator": "gte", "value": 500 }],
        "ruleType": "hard"
      }
    }
  ],
  "warnings": [
    "No 'age' field found in available schemas. The rule may not work until the field is added."
  ]
}

Heuristic Fallback Patterns

When the LLM is unavailable, the parser handles these regex patterns:
PatternExample InputParsed Entity
Age comparison”over 25”, “aged 18 or older”qualification_rule with customer.age >= N
Spend threshold”spent more than $500”qualification_rule with customer.total_spend >= N
Time-windowed spend”spent $500 in the last 90 days”behavioral_metric (sum revenue, 90d) + qualification_rule
Negation”haven’t converted on credit card”contact_policy with outcome-based suppression
Category detection”credit card offers”, “loan offers”Scope applied to contact policy

Example

curl -X POST https://playground.kaireonai.com/api/v1/ai/parse-rule \
  -H "Content-Type: application/json" \
  -H "X-Tenant-Id: my-tenant" \
  -d '{ "text": "Only show to customers over 25 who spent more than $500 in the last 90 days and haven'\''t converted on credit card offers" }'

Roles

admin, editor

GET /api/v1/ai/recommendations

List AI-generated recommendations for the tenant, ordered by creation date descending.

Query Parameters

ParameterTypeValuesDescription
typestringpolicy, rule, segment, contentFilter by recommendation type
statusstringnew, reviewed, applied, dismissedFilter by status

Response

{
  "recommendations": [
    {
      "id": "rec_001",
      "tenantId": "my-tenant",
      "type": "policy",
      "title": "Set frequency cap to 3/week",
      "description": "Analysis of 12,500 interactions shows conversion rate peaks at 3 contacts/week (8.2%). Rate drops 65% at 7 contacts/week.",
      "payload": {
        "ruleType": "frequency_cap",
        "scope": "global",
        "maxContactsPerWeek": 3
      },
      "confidence": "high",
      "source": "llm",
      "status": "new",
      "metadata": {
        "frequencyBands": [
          { "contactsPerWeek": 1, "conversionRate": 0.05 },
          { "contactsPerWeek": 3, "conversionRate": 0.082 }
        ],
        "estimatedImpact": "Applying this cap would optimize contact frequency for better conversion."
      },
      "createdAt": "2026-03-18T10:00:00Z"
    }
  ]
}

Roles

admin, editor, viewer

POST /api/v1/ai/recommendations

Create a new AI recommendation manually.

Request Body

FieldTypeRequiredDescription
typestringYespolicy, rule, segment, content
titlestringYesShort summary
descriptionstringYesDetailed explanation
payloadobjectNoMachine-readable entity definition
confidencestringNohigh, medium, low. Default: medium
sourcestringNollm, ml_worker. Default: llm
metadataobjectNoAdditional context data

Response

201 Created with the created recommendation object.

Roles

admin, editor

GET /api/v1/ai/recommendations/

Get a single recommendation by ID.

Path Parameters

ParameterTypeDescription
idstringRecommendation ID

Response

{
  "recommendation": { "id": "rec_001", "type": "policy", "title": "...", "status": "new", ... }
}

Roles

admin, editor, viewer

PATCH /api/v1/ai/recommendations/

Update the status of a recommendation.

Path Parameters

ParameterTypeDescription
idstringRecommendation ID

Request Body

FieldTypeRequiredValues
statusstringYesreviewed, applied, dismissed

Response

{
  "recommendation": { "id": "rec_001", "status": "reviewed", ... }
}

Roles

admin, editor

POST /api/v1/ai/recommendations//apply

Apply an AI recommendation by creating the corresponding entity in draft status. The created entity type depends on the recommendation type.

Path Parameters

ParameterTypeDescription
idstringRecommendation ID

Entity Creation by Type

Recommendation TypeEntity CreatedModule
policyContact Policy (draft)Studio > Contact Policies
ruleQualification Rule (draft)Studio > Qualification Rules
segmentCustomer Segment (draft)AI > Segments
contentTreatment / Creative (draft)Studio > Treatments

Response

{
  "entityId": "cp_001",
  "entityType": "policy"
}
The recommendation status is updated to applied with the appliedEntityId set to the created entity’s ID. Returns 400 if the recommendation has already been applied.

Roles

admin only

GET /api/v1/ai/ml-worker/status

Check ML Worker connectivity status. Checks the tenant’s ML Worker configuration from settings, with an environment variable fallback (ML_WORKER_URL). The health check endpoint (/health) uses a 30-second cache TTL and 3-second timeout.

Response — Connected

{
  "connected": true,
  "url": "https://ml-worker.internal:8080"
}

Response — Not Connected

{
  "connected": false
}

Roles

admin, editor, viewer

GET /api/v1/ai/config-status

Returns whether the configured AI provider has the credentials it needs to run. The route at src/app/api/v1/ai/config-status/route.ts:9-21 reads the merged tenant + environment config via getAiConfigAsync(), then reports configured: true when the provider does not need an API key (ollama, lm_studio) or when an API key is present.

Response

{
  "configured": true,
  "provider": "openai"
}
configured
boolean
true when the provider does not need a key (ollama or lm_studio) or a key is configured. false only when a key-required provider has no key set.
provider
string
The active provider id from getAiConfigAsync(). Examples: "openai", "anthropic", "ollama", "lm_studio".

Roles

admin, editor, viewer

Example

curl https://playground.kaireonai.com/api/v1/ai/config-status \
  -H "X-API-Key: krn_your_api_key" \
  -H "X-Tenant-Id: 5a9904b9-..."

POST /api/v1/ai/imports//apply

Atomic apply of operator verdicts on AI-extracted import proposals. The route at src/app/api/v1/ai/imports/[id]/apply/route.ts wraps every verdict in a single prisma.$transaction (timeout 30s per lib/ai/import/apply.ts:55) — any per-verdict failure rolls back the entire batch and returns failedProposalId so the UI can highlight the offending row inline. The path parameter id is the attachmentId (the chat attachment that produced the proposals), not the apply id.

Path Parameters

ParameterTypeDescription
idstringAiAttachment.id — the document the proposals were extracted from.

Request Body

Validated by Schema at apply/route.ts:20-30.
conversationId
string
required
AI conversation id the proposals were generated in. Used for audit linkage.
verdicts
array
required
Non-empty array of { proposalId, verdict } items. verdict is one of "create-new", "merge-into-existing", or "skip".

Verdict semantics

VerdictBehavior
create-newInsert a new entity row from the proposal payload. The new row id is recorded in AiImportApply.createdEntityIds so revert can delete it.
merge-into-existingUpdate an existing entity. The field-level diff is recorded in AuditLog; revert does NOT undo merges (apply.ts:636).
skipNo entity write. A SkipDigest row is recorded so the same proposal does not reappear in future extracts.

Response

Returns the ApplyOk shape declared at lib/ai/import/apply.ts:39-45 on success and ApplyFail at lib/ai/import/apply.ts:47-53 on rollback.
{
  "ok": true,
  "applyId": "apl_abc123",
  "createdEntityIds": [
    { "entityType": "offer", "entityId": "off_xyz" }
  ],
  "mergedEntityIds": [
    { "entityType": "creative", "entityId": "crv_def" }
  ],
  "skippedProposalIds": ["prop_111", "prop_222"]
}
Rollback response:
{
  "ok": false,
  "status": "rolled_back",
  "failedProposalId": "prop_888",
  "errorMessage": "creative.templateType is required",
  "errorField": "templateType"
}

Status codes

CodeWhen
201Apply succeeded
400Invalid JSON body or schema validation failure
401Caller is not authenticated
403Caller is not admin or editor
422Per-verdict failure rolled back the whole transaction
500Unexpected error in runApply

Honest limit

Apply itself does not call the LLM — the customer cost was already incurred at extract time. See AI Document Import.

Roles

admin, editor

POST /api/v1/ai/imports//revert

Soft-revert an apply: deletes the rows in AiImportApply.createdEntityIds, leaves merges as-is, and refuses to cascade-delete a created entity that now has child references. The route at src/app/api/v1/ai/imports/[id]/revert/route.ts calls runRevert from lib/ai/import/apply.ts:564 and surfaces orphaned refusals in the response so the operator can resolve them manually. The path parameter id is the applyId returned from the apply call — NOT the attachment id.

Path Parameters

ParameterTypeDescription
idstringAiImportApply.id from the prior apply response.

Request Body

None — revert is a single transactional sweep keyed by applyId.

Response

{
  "ok": true,
  "applyId": "apl_abc123",
  "deletedEntityIds": [
    { "entityType": "offer", "entityId": "off_xyz" }
  ],
  "skippedMerges": [
    { "entityType": "creative", "entityId": "crv_def" }
  ],
  "orphanedRefusals": [
    {
      "entityType": "offer",
      "entityId": "off_old",
      "reason": "Foreign key constraint: 14 child interactionHistory rows reference this offer"
    }
  ]
}
deletedEntityIds
array
Entities that were created by the apply and successfully deleted. Each entry is { entityType, entityId }.
skippedMerges
array
Entities that were merge-updated by the apply. Revert does NOT undo these — operators do field-level undo manually against the AuditLog field-diff trail (apply.ts:636).
orphanedRefusals
array
Created entities that now have child references and cannot be cascade-deleted. The reason field contains the truncated FK error message.

Status codes

CodeWhenSource
200Revert succeededroute.ts:34
401 / 403Caller is not admin or editorrequireAuth at lib/require-auth.ts
404applyId does not match a row for the tenantrevert/route.ts:29-30
409Apply was already revertedrevert/route.ts:31
500Unexpected error in runRevertrevert/route.ts:32

Roles

admin, editor

Role Summary

EndpointMethodAllowed Roles
/api/v1/ai/chatPOSTadmin, editor, viewer
/api/v1/ai/conversationsGETsession auth
/api/v1/ai/conversationsPOSTsession auth
/api/v1/ai/conversations/{id}GETsession auth
/api/v1/ai/conversations/{id}DELETEadmin, editor
/api/v1/ai/analyze/{type}POSTadmin, editor
/api/v1/ai/analyzer-settingsGETadmin, editor, viewer
/api/v1/ai/analyzer-settingsPUTadmin
/api/v1/ai/intelligencePOSTadmin, editor, viewer
/api/v1/ai/parse-rulePOSTadmin, editor
/api/v1/ai/recommendationsGETadmin, editor, viewer
/api/v1/ai/recommendationsPOSTadmin, editor
/api/v1/ai/recommendations/{id}GETadmin, editor, viewer
/api/v1/ai/recommendations/{id}PATCHadmin, editor
/api/v1/ai/recommendations/{id}/applyPOSTadmin
/api/v1/ai/ml-worker/statusGETadmin, editor, viewer
/api/v1/ai/config-statusGETadmin, editor, viewer
/api/v1/ai/imports/{id}/applyPOSTadmin, editor
/api/v1/ai/imports/{id}/revertPOSTadmin, editor
See also: AI Assistant | AI Insights | AI Configuration | AI Document Import | MCP Server