Chat & conversations
Run Theo turns from your backend, streaming or JSON, with persistent conversations.
Modes
POST /chat runs a Theo turn with tools: Theo can create flowcharts, whiteboards, notes, presentations, sheets, boards, documents, images, video, and music from a plain-English prompt, each surfacing as an artifact on the response. Two launch modes ship in v1:
fastdefaultthinkdeeper reasoningmessagestringmessagesarray (max 40)conversationIdstringmodefast | thinkstreamboolean (default true)Streaming (default)
The endpoint streams the Vercel AI SDK UI-message SSE protocol (the same wire format the OpenCharts app consumes), so useChatcan render it directly. The request body is the API's own shape (see above), so map it in the transport:
import { useChat } from "@ai-sdk/react";
import { DefaultChatTransport } from "ai";
const { messages, sendMessage } = useChat({
transport: new DefaultChatTransport({
// Your server proxy: forwards to opencharts.com and attaches the key.
api: "/api/theo-chat",
prepareSendMessagesRequest: ({ messages }) => ({
body: {
messages: messages
.filter((m) => m.role === "user" || m.role === "assistant")
.map((m) => ({
role: m.role,
content: m.parts
.filter((p) => p.type === "text")
.map((p) => p.text)
.join(""),
})),
},
}),
}),
});Or read the SSE stream directly: the exact event vocabulary is documented in the next section.
Keys stay server-side
Never expose your API key in a browser. Proxy the stream through your own backend and attach the key there.
SSE events
The stream is standard Server-Sent Events: Content-Type: text/event-stream plus the protocol marker header x-vercel-ai-ui-message-stream: v1. Each event is data: <json> with a type discriminator, and the stream ends with the terminator data: [DONE].
startlifecyclestart-step / finish-steplifecycletext-start / text-delta / text-endtextreasoning-start / reasoning-delta / reasoning-endtexttool-input-start / tool-input-delta / tool-input-availabletoolstool-output-availabletoolsfinishlifecycleerrorlifecycledata: {"type":"start","messageId":"msg_0"}
data: {"type":"start-step"}
data: {"type":"text-start","id":"txt_0"}
data: {"type":"text-delta","id":"txt_0","delta":"Here is your onboarding funnel"}
data: {"type":"tool-input-available","toolCallId":"call_1","toolName":"create_flowchart","input":{"title":"SaaS onboarding funnel"}}
data: {"type":"tool-output-available","toolCallId":"call_1","output":{"type":"flowchart","title":"SaaS onboarding funnel","projectId":"6870f3...","projectType":"chart","openUrl":"https://www.opencharts.com/editor/6870f3..."}}
data: {"type":"text-end","id":"txt_0"}
data: {"type":"finish-step"}
data: {"type":"finish","finishReason":"stop"}
data: [DONE]Non-streaming
Pass stream: false for a single assembled JSON response with the message, its artifacts, and token usage:
curl https://www.opencharts.com/api/v1/chat \
-H "Authorization: Bearer $OPENCHARTS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Create a flowchart of a SaaS onboarding funnel",
"mode": "fast",
"stream": false
}'Conversations
Turns persist as real OpenCharts conversations and appear in the account's in-app sidebar. Manage threads with the Conversations resource:
Artifacts & async jobs
Every tool result surfaces as an artifact: on JSON responses under message.artifacts, on streams as the output of a tool-output-availableevent. Project-backed artifacts carry the created project's id plus an absolute openUrl deep link into the OpenCharts editor:
{
"type": "flowchart",
"title": "SaaS onboarding funnel",
"projectId": "6870f3...",
"projectType": "chart",
"openUrl": "https://www.opencharts.com/editor/6870f3..."
}flowchart / whiteboard/editor/{projectId}notes/notes/{projectId}presentation/presentations/{projectId}sheet/sheets/{projectId}code build/code-editor/{codeProjectId}social_board/boards/{boardId}conversation/chat/{conversationId}When Theo dispatches long-running work mid-chat (video, music), the artifact instead carries an apiJobId (type-prefixed) and pollUrl on its data. Poll it at GET /jobs/{id} or register a webhook and skip polling entirely. The full artifact schema ships in the API reference and the OpenAPI document (ChatArtifact).
Tools & credits
The API surface runs a curated tool set focused on creation and research; account-sensitive tools (email sending, project deletion, database access) are excluded by design. Chat consumes AI credits with the same metering Theo uses in-app; check the balance with GET /account/credits.