Last Updated: 2026-04-03 Status: Draft
1. Service Overview
| Property | Value |
|---|---|
| Service Owner | apps/brain-service |
| Base URL | https://api.logicspike.com/brain (via Gateway) |
| Internal Microservice | brain-service.logicspike.workers.dev |
| Gateway Key Header | x-gateway-key |
| Auth | RS256 JWT via Gateway |
2. Authentication Requirements
| Domain | Auth Type | Header |
|---|---|---|
| Chat (Copilot) | JWT (user session) | Authorization: Bearer <token> |
| Insights | JWT (user session) | Authorization: Bearer <token> |
| Memory (admin) | JWT + admin permission | Authorization: Bearer <token> |
| Usage | JWT (user session) | Authorization: Bearer <token> |
| Internal (Cron, Queues) | Gateway key only | x-gateway-key: <key> |
3. Endpoints by Domain
3.1 Copilot Chat (Core)
💬 Send Message (Streaming)
The primary endpoint. Accepts a user message and returns a streaming response via SSE.
POST /brain/chat
Content-Type: application/json
Accept: text/event-streamRequest Body:
{
"conversation_id": "conv_abc123",
"message": "Why did my blog traffic drop this week?",
"attachments": []
}| Field | Type | Required | Description |
|---|---|---|---|
conversation_id |
UUID | ❌ | Existing conversation to continue. If omitted, creates a new conversation. |
message |
String | ✅ | User's natural language input. Max 4000 characters. |
attachments |
Array | ❌ | Future: images, files. Currently unused. |
Response (SSE Stream):
event: token
data: {"text": "Based on "}
event: token
data: {"text": "your blog analytics, "}
event: tool_call
data: {"name": "blog.get_analytics", "params": {"range": "7d"}}
event: tool_result
data: {"name": "blog.get_analytics", "result": {"views": 45, "previous": 120}}
event: token
data: {"text": "your traffic dropped from 120 to 45 views this week. "}
event: done
data: {"conversation_id": "conv_abc123", "message_id": "msg_xyz789", "usage": {"input_tokens": 2500, "output_tokens": 180, "cost_usd": 0.0042}, "decision_id": "dec_456"}SSE Event Types:
| Event | Payload | Description |
|---|---|---|
token |
{ text: string } |
A streamed text token |
tool_call |
{ name: string, params: object } |
Agent is calling a service tool |
tool_result |
{ name: string, result: object } |
Tool execution result |
thinking |
{ text: string } |
Agent's reasoning (optional, configurable) |
done |
{ conversation_id, message_id, usage, decision_id } |
Stream complete |
error |
{ code: string, message: string } |
Error during processing |
Error Codes:
| Code | HTTP | Description |
|---|---|---|
RATE_LIMITED |
429 | Tenant exceeded plan's AI interaction limit |
CONVERSATION_NOT_FOUND |
404 | Invalid conversation_id |
MESSAGE_TOO_LONG |
400 | Message exceeds 4000 character limit |
PROVIDER_UNAVAILABLE |
503 | All LLM providers are down |
PERMISSION_DENIED |
403 | User lacks required permission |
🔄 Confirm Action
When an agent requests user confirmation for a destructive action, the client sends approval/denial.
POST /brain/chat/confirm
Content-Type: application/jsonRequest Body:
{
"conversation_id": "conv_abc123",
"decision_id": "dec_456",
"confirmed": true
}| Field | Type | Required | Description |
|---|---|---|---|
conversation_id |
UUID | ✅ | Active conversation |
decision_id |
UUID | ✅ | The pending decision to confirm/deny |
confirmed |
Boolean | ✅ | true to execute, false to cancel |
Response:
{
"status": "executed",
"tool_result": {
"name": "blog.delete_posts",
"result": { "deleted_count": 3 }
}
}3.2 Conversations
📋 List Conversations
GET /brain/conversations?status=active&limit=20&offset=0Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
status |
Enum | all |
Filter: active, idle, closed, all |
limit |
Integer | 20 | Max results (1–100) |
offset |
Integer | 0 | Pagination offset |
Response:
{
"conversations": [
{
"id": "conv_abc123",
"title": "Blog traffic analysis",
"status": "active",
"message_count": 12,
"last_message_at": "2026-04-03T10:30:00Z",
"started_at": "2026-04-03T10:15:00Z"
}
],
"total": 45,
"limit": 20,
"offset": 0
}📜 Get Conversation History
GET /brain/conversations/:id/messages?limit=50&before=<message_id>Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
limit |
Integer | 50 | Max messages (1–100) |
before |
UUID | ❌ | Cursor-based pagination — messages before this ID |
Response:
{
"messages": [
{
"id": "msg_001",
"role": "user",
"content": "Why did my traffic drop?",
"created_at": "2026-04-03T10:15:00Z"
},
{
"id": "msg_002",
"role": "assistant",
"content": "Based on your analytics...",
"agent_type": "analytics",
"model": "claude-sonnet-4-6",
"tool_calls": [
{ "name": "blog.get_analytics", "params": { "range": "7d" } }
],
"created_at": "2026-04-03T10:15:03Z"
}
],
"has_more": true
}🗑️ Close Conversation
POST /brain/conversations/:id/closeResponse:
{
"status": "closed",
"memories_extracted": 3,
"total_tokens": 15420,
"total_cost_usd": 0.089
}3.3 Insights (Proactive)
💡 List Insights
GET /brain/insights?status=unseen&priority=high&limit=10Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
status |
Enum | unseen |
Filter: unseen, seen, acted, dismissed, all |
priority |
Enum | all |
Filter: high, medium, low, all |
limit |
Integer | 10 | Max results (1–50) |
Response:
{
"insights": [
{
"id": "ins_789",
"type": "opportunity",
"priority": "high",
"title": "Your audience wants eggless cake recipes",
"body": "40% of chatbot questions this week were about eggless cakes. You don't have a blog post on this yet.",
"suggested_action": "blog.create_draft",
"action_params": { "topic": "eggless cake recipes", "format": "recipe" },
"created_at": "2026-04-03T06:00:00Z",
"expires_at": "2026-04-10T06:00:00Z"
}
],
"unseen_count": 3
}👁️ Mark Insight as Seen
POST /brain/insights/:id/seenResponse:
{
"status": "seen",
"seen_at": "2026-04-03T10:45:00Z"
}✅ Act on Insight
Executes the suggested action for an insight.
POST /brain/insights/:id/actResponse (SSE Stream):
Same SSE format as chat — the action is executed by the relevant specialist agent, and the response is streamed back. The conversation is auto-created if one isn't active.
❌ Dismiss Insight
POST /brain/insights/:id/dismissRequest Body:
{
"reason": "not_relevant"
}| Field | Type | Required | Description |
|---|---|---|---|
reason |
Enum | ❌ | not_relevant, already_done, later, other. Used to improve future insight quality. |
3.4 Memory (Admin)
These endpoints are for debugging and advanced users. Not exposed in the standard dashboard UI.
🧠 List Memories
GET /brain/memory?type=preference&entity=blog&limit=20Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
type |
Enum | all |
Filter: fact, preference, episode, pattern, entity, all |
entity |
String | ❌ | Filter by linked entity ID |
min_importance |
Float | 0.0 | Minimum importance score |
limit |
Integer | 20 | Max results (1–100) |
Response:
{
"memories": [
{
"id": "mem_123",
"type": "preference",
"content": "Focus on blog only, not interested in social media currently",
"importance": 0.82,
"entity_ids": ["blog", "content-engine"],
"access_count": 7,
"source_type": "conversation",
"created_at": "2026-03-15T10:00:00Z",
"accessed_at": "2026-04-02T14:30:00Z"
}
],
"total": 45
}🗑️ Delete Memory
Allows a user to explicitly tell the AI to forget something.
DELETE /brain/memory/:idResponse:
{
"status": "deleted",
"content": "Focus on blog only, not interested in social media currently"
}3.5 Usage & Analytics
📊 Get AI Usage
GET /brain/usage?period=2026-04Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
period |
String | Current month | YYYY-MM format |
Response:
{
"period": "2026-04",
"plan": "pro",
"limits": {
"max_interactions": 5000,
"used_interactions": 342,
"remaining": 4658
},
"tokens": {
"input": 856000,
"output": 68400,
"total": 924400
},
"cost_usd": 4.72,
"model_breakdown": {
"claude-haiku-4-5-20251001": { "calls": 342, "tokens": 120000, "cost": 0.12 },
"claude-sonnet-4-6": { "calls": 280, "tokens": 780000, "cost": 4.20 },
"claude-opus-4-6": { "calls": 12, "tokens": 24400, "cost": 0.40 }
},
"daily": [
{ "date": "2026-04-01", "interactions": 45, "cost_usd": 0.62 },
{ "date": "2026-04-02", "interactions": 67, "cost_usd": 0.89 },
{ "date": "2026-04-03", "interactions": 230, "cost_usd": 3.21 }
]
}📈 Get AI Performance Metrics
GET /brain/usage/metrics?period=2026-04Response:
{
"period": "2026-04",
"metrics": {
"task_completion_rate": 0.78,
"action_acceptance_rate": 0.65,
"avg_latency_ms": 234,
"memory_hit_rate": 0.72,
"escalation_rate": 0.12,
"insight_click_through_rate": 0.28,
"total_conversations": 89,
"total_messages": 1240,
"total_tool_calls": 456,
"total_insights_generated": 34,
"total_insights_acted_on": 12
}
}3.6 Internal Endpoints (Service-to-Service)
These endpoints are called by CF Cron Triggers and CF Queues. Not exposed via Gateway.
⏰ Run Insight Generation (Cron)
POST /internal/insights/generate
x-gateway-key: <internal_key>Triggers the insight engine for all active tenants. Called by Cron Trigger every 6 hours.
🔄 Process Memory Consolidation (Queue Consumer)
POST /internal/memory/consolidate
x-gateway-key: <internal_key>Request Body (from CF Queue):
{
"tenant_id": "tnt_123",
"conversation_id": "conv_abc123",
"tasks": ["merge_duplicates", "extract_entities", "compute_importance"]
}📉 Run Memory Decay (Cron)
POST /internal/memory/decay
x-gateway-key: <internal_key>Triggers periodic memory decay and pruning for all tenants. Called by Cron Trigger every 6 hours.
4. Generic Error Response Format
All error responses follow this structure:
{
"error": {
"code": "RATE_LIMITED",
"message": "You've used 5000 of 5000 AI interactions this month. Upgrade your plan for more.",
"details": {
"plan": "pro",
"limit": 5000,
"used": 5000,
"resets_at": "2026-05-01T00:00:00Z"
}
}
}Standard Error Codes:
| Code | HTTP Status | Description |
|---|---|---|
RATE_LIMITED |
429 | AI interaction limit exceeded for current plan |
INVALID_INPUT |
400 | Malformed request body |
CONVERSATION_NOT_FOUND |
404 | Conversation ID does not exist or belongs to another tenant |
INSIGHT_NOT_FOUND |
404 | Insight ID does not exist or belongs to another tenant |
MEMORY_NOT_FOUND |
404 | Memory ID does not exist or belongs to another tenant |
PERMISSION_DENIED |
403 | User lacks required PBAC permission |
PROVIDER_UNAVAILABLE |
503 | All LLM providers failed (circuit breaker open) |
CONFIRMATION_REQUIRED |
202 | Action requires user confirmation before execution |
CONVERSATION_LIMIT |
409 | User already has an active conversation (close it first) |
PLAN_FEATURE_UNAVAILABLE |
403 | Feature not available on current plan (e.g., opus model on Free) |