POST /api/v1/ai/chat
Stream a conversation with the AI assistant. Responses are streamed token-by-token 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 noconversationId is provided.
Rate limited to 30 requests per 60 seconds per user. Request timeout: 60 seconds.
Headers
Request Body
Response
Returns a streaming response in the AI SDK UI message format (Server-Sent Events). The response includes:X-Conversation-Idheader with the conversation ID for follow-up messages- Streamed text chunks and tool call results in AI SDK wire format
Roles
admin, editor, viewerExample
Context Routing
Theroute parameter determines which tools are available:
GET /api/v1/ai/conversations
List recent conversations for the tenant (up to 50, newest first). Requires session authentication.Response
Roles
Requires session authentication (any authenticated user).POST /api/v1/ai/conversations
Create a new conversation.Request Body
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
Response
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
Response
Roles
admin, editorPOST /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
Request Body
Analysis Types
Response — Confirmation Required
When the dataset exceeds 5,000 rows andconfirmed is not true:
Response — Analysis Complete
Actionable findings are also persisted as AI recommendations (dedupe skips ones already in the inbox), so the response echoes what was written:Response — ML Worker Job Submitted
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, editorGET /api/v1/ai/analyzer-settings
Get current AI analyzer settings for the tenant with defaults filled in. Returns five sections: segmentation, policy, content, ruleBuilder, and ranking.Response
Roles
admin, editor, viewerPUT /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. Settings are persisted to theTenantSettings table and take effect on the next /recommend call (no server restart required).
Request Body
Partial object matching the response structure ofGET /api/v1/ai/analyzer-settings. Only include sections you want to update.
ranking object
Controls realtime ranking features that run inside the /recommend hot path. All flags default to false (opt-in).
Lagrangian constraint solver
WhenlagrangianEnabled is true, the /recommend hot path calls applyRealtimeRanking (per src/lib/ranking/realtime-wire.ts) after the score node and before the final sort. The solver models two types of per-offer constraints:
budget_daily:<offerId>— built fromoffer.budget.dailyCapCentsandcurrentDailySpentCents. Remaining budget =cap − spent(resets each calendar day). An offer with no remaining budget yields no constraint and is not penalized.inventory:<offerId>— built fromoffer.inventory.remainingStock.
budget or inventory configured, or all remaining values are zero), the solver detects this and returns noOp: true — base scores are returned untouched and the solver overhead is skipped. A solver failure (rare) returns solverFailed: true and falls back to base scores; the failure is logged at error level for operator alerting.
The solver does not drop offers below zero score — it applies a continuous shadow-price penalty that rotates traffic, not a hard filter. Hard filters (offers that have already exhausted their cap) run earlier in the pipeline via src/lib/ranking/constraints.ts regardless of this flag.
Response
Returns the full merged settings object (same format as GET).Roles
admin onlyPOST /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
Available Tools
analyzeCrossModule Response
Returns insights that connect dots across modules — the platform’s most valuable intelligence layer.
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 return500 with { "error": { "message": "..." } }.
Roles
admin, editor, viewerPOST /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
Response
Heuristic Fallback Patterns
When the LLM is unavailable, the parser handles these regex patterns:Example
Roles
admin, editorGET /api/v1/ai/recommendations
List AI-generated recommendations for the tenant, ordered by creation date descending.Query Parameters
The
experiment, model, and weights types are Autopilot proposals (champion promotion, model retrain/pause, ranking-weight change).
Response
Roles
admin, editor, viewerPOST /api/v1/ai/recommendations
Create a new AI recommendation manually.Request Body
Response
201 Created with the created recommendation object.
Roles
admin, editorGET /api/v1/ai/recommendations/
Get a single recommendation by ID.Path Parameters
Response
Roles
admin, editor, viewerPATCH /api/v1/ai/recommendations/
Update the status of a recommendation.Path Parameters
Request Body
Response
Roles
admin, editorPOST /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
Entity Creation by Type
Response
applied with the appliedEntityId set to the created entity’s ID. Returns 400 if the recommendation has already been applied, or if the recommendation type is not one the applier handles (Unknown recommendation type: ...). Autopilot-sourced types (experiment, model, weights) are normally actioned through the Autopilot cron / approval flow rather than this endpoint.
Roles
admin onlyPOST /api/v1/ai/mutations/confirm
Explicitly approve a pending AI mutation preview. When the chat assistant proposes a change, it stages a preview instead of writing; the AI panel’s Approve button calls this endpoint directly (no LLM round-trip), so approval is deterministic and audit-logged against the actor’s tenant.Request Body
Response 200
Errors
Roles
admin, editorGET /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
Response — Not Connected
Roles
admin, editor, viewerGET /api/v1/ai/config-status
Returns whether the configured AI provider has the credentials it needs to run. The endpoint reads the merged tenant + environment AI configuration and reportsconfigured: true when the provider does not need an API key (ollama, lm_studio) or when an API key is present.
Response
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.string
The active AI provider id resolved from the merged tenant + environment configuration. Examples:
"openai", "anthropic", "ollama", "lm_studio".Roles
admin, editor, viewerExample
POST /api/v1/ai/imports//apply
Atomic apply of operator verdicts on AI-extracted import proposals. Every verdict in the request is wrapped in a single database transaction (30 second timeout) — any per-verdict failure rolls back the entire batch and returnsfailedProposalId so the UI can highlight the offending row inline.
The path parameter id is the attachment ID (the chat attachment that produced the proposals), not the apply ID.
Path Parameters
Request Body
string
required
AI conversation id the proposals were generated in. Used for audit linkage.
array
required
Non-empty array of
{ proposalId, verdict } items. verdict is one of "create-new", "merge-into-existing", or "skip".Verdict semantics
Response
Returns one of two response shapes — a success body when the apply commits, and a rollback body when any per-verdict failure aborts the transaction.Status codes
Honest limit
Apply itself does not call the LLM — the customer cost was already incurred at extract time. See AI Document Import.Roles
admin, editorPOST /api/v1/ai/imports//revert
Soft-revert an apply: deletes the entities that were created by the apply, leaves merges as-is, and refuses to cascade-delete a created entity that now has child references. Orphaned refusals are surfaced in the response so the operator can resolve them manually. The path parameterid is the apply ID returned from the apply call — NOT the attachment ID.
Path Parameters
Request Body
None — revert is a single transactional sweep keyed by the apply ID in the path.Response
array
Entities that were created by the apply and successfully deleted. Each entry is
{ entityType, entityId }.array
Entities that were merge-updated by the apply. Revert does NOT undo these — operators do field-level undo manually against the audit log field-diff trail.
array
Created entities that now have child references and cannot be cascade-deleted. The
reason field contains the truncated FK error message.Status codes
Roles
admin, editorRole Summary
See also: AI Assistant | AI Insights | AI Configuration | AI Document Import | MCP Server