Skip to main content

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 no conversationId 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-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

Context Routing

The route 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, 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

Request Body

Analysis Types

Response — Confirmation Required

When the dataset exceeds 5,000 rows and confirmed 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, editor

GET /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, 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. Settings are persisted to the TenantSettings table and take effect on the next /recommend call (no server restart required).

Request Body

Partial object matching the response structure of GET /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

When lagrangianEnabled 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 from offer.budget.dailyCapCents and currentDailySpentCents. Remaining budget = cap − spent (resets each calendar day). An offer with no remaining budget yields no constraint and is not penalized.
  • inventory:<offerId> — built from offer.inventory.remainingStock.
When no binding constraint exists across all candidates (no offer has 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 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

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 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

Response

Heuristic Fallback Patterns

When the LLM is unavailable, the parser handles these regex patterns:

Example

Roles

admin, editor

GET /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, viewer

POST /api/v1/ai/recommendations

Create a new AI recommendation manually.

Request Body

Response

201 Created with the created recommendation object.

Roles

admin, editor

GET /api/v1/ai/recommendations/

Get a single recommendation by ID.

Path Parameters

Response

Roles

admin, editor, viewer

PATCH /api/v1/ai/recommendations/

Update the status of a recommendation.

Path Parameters

Request Body

Response

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

Entity Creation by Type

Response

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, 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 only

POST /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, editor

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

Response — Not Connected

Roles

admin, editor, viewer

GET /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 reports configured: 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, viewer

Example


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 returns failedProposalId 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.
Rollback response:

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, editor

POST /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 parameter id 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, editor

Role Summary

See also: AI Assistant | AI Insights | AI Configuration | AI Document Import | MCP Server