API: Chat

Base URL: /projects/{projectId}/chat

The chat API provides AI-assisted co-design coaching with streaming support and form trigger generation.

Endpoints

Create Thread

POST /projects/{projectId}/chat

Request Body:

{
  "project_context": {
    "projectId": "uuid",
    "projectName": "Climate Resilience Service"
  },
  "phase": 1
}

Response (201):

{
  "thread_id": "uuid",
  "projectId": "project-uuid",
  "phase": 1,
  "intro_message": "Welcome to Phase 1! Let's start by identifying...",
  "createdAt": "2026-01-15T10:30:00Z"
}

List Threads

GET /projects/{projectId}/chat

Returns all threads for the authenticated user in this project.

Response (200):

[
  {
    "thread_id": "uuid",
    "phase": 1,
    "lastMessage": "Help me identify stakeholders",
    "messageCount": 12,
    "createdAt": "2026-01-15T10:30:00Z"
  }
]

Get Thread

GET /projects/{projectId}/chat/{thread_id}

Send Message

POST /projects/{projectId}/chat/{thread_id}/messages

Request Body:

{
  "content": "Help me create a stakeholder card for the local municipality",
  "stream": false
}

Response (200) — Non-streaming:

{
  "message_id": "uuid",
  "role": "assistant",
  "content": "I'll help you create a stakeholder card for the local municipality...",
  "status": "completed",
  "follow_up_options": [
    "Add assessment scores",
    "Create another stakeholder",
    "Generate ecosystem matrix"
  ],
  "form_trigger": {
    "templateCode": "1.0.1",
    "action": "create",
    "fields": {
      "formalInfo_name": "Local Municipality",
      "formalInfo_type": "Public administration",
      "formalInfo_location": "City, Country"
    }
  },
  "token_usage": {
    "prompt_tokens": 1200,
    "completion_tokens": 350
  }
}

Streaming Response:

When stream=true, the response uses Server-Sent Events (SSE):

data: {"type": "token", "content": "I'll"}
data: {"type": "token", "content": " help"}
data: {"type": "token", "content": " you"}
...
data: {"type": "follow_up", "options": ["Add assessment", "Create another"]}
data: {"type": "form_trigger", "data": {...}}
data: {"type": "done"}

Get Thread Messages

GET /projects/{projectId}/chat/{thread_id}/messages

Response (200):

[
  {
    "message_id": "uuid",
    "role": "user",
    "content": "Help me identify stakeholders",
    "timestamp": "2026-01-15T10:30:00Z"
  },
  {
    "message_id": "uuid",
    "role": "assistant",
    "content": "Based on your project...",
    "follow_up_options": [...],
    "timestamp": "2026-01-15T10:30:05Z"
  }
]

Delete Thread

DELETE /projects/{projectId}/chat/{thread_id}

Response (204): No content.

Frontend Integration

Streaming example (JavaScript):

async function sendMessage(projectId, threadId, content) {
  const response = await fetch(
    `/projects/${projectId}/chat/${threadId}/messages`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      },
      body: JSON.stringify({ content, stream: true })
    }
  );

  const reader = response.body.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    const chunk = decoder.decode(value);
    const lines = chunk.split('\n').filter(l => l.startsWith('data: '));

    for (const line of lines) {
      const data = JSON.parse(line.slice(6));
      switch (data.type) {
        case 'token':
          appendToMessage(data.content);
          break;
        case 'follow_up':
          showFollowUpButtons(data.options);
          break;
        case 'form_trigger':
          openTemplateForm(data.data);
          break;
      }
    }
  }
}