Chat Endpoint
POST /api/chat — Send a message to Casey and stream the response via SSE.
POST /api/chat
The main conversation endpoint. Sends a user message and streams Casey's response as Server-Sent Events.
Request Body
{
"message": "Tell me about this deal",
"conversation_id": "550e8400-e29b-41d4-a716-446655440000",
"create_new_conversation": false,
"context": {
"page": "deal",
"deal_id": 123,
"deal_name": "Acme Corp",
"deal_slug": "acme-corp"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
message | string | Yes | The user's message (1–4000 chars) |
conversation_id | string | No | UUID to continue an existing conversation |
create_new_conversation | boolean | No | Force a new conversation even if conversation_id is set |
context | object | No | Page context — tells Casey where the user is |
Page Context
Only 3 page types provide meaningful context. Everything else can be sent as "unknown" or omitted.
| Page | Fields | Example |
|---|---|---|
"deal" | deal_id, deal_name, deal_slug | User is viewing a deal page |
"portfolio" | (none) | User is viewing their portfolio |
"investment_detail" | investment_id | User is viewing a specific investment |
// On a deal page
context: { page: "deal", deal_id: 123, deal_name: "Acme Corp", deal_slug: "acme-corp" }
// On the portfolio page
context: { page: "portfolio" }
// On an investment detail page
context: { page: "investment_detail", investment_id: 456 }
// Anywhere else (chat still works, just no special context)
context: { page: "unknown" }
When a user continues an existing conversation from a different page, send the
new context with the conversation_id. Casey will automatically update the
conversation's context.
Response
Content-Type: text/event-stream
The response is an SSE stream. Each event is a data: line containing a JSON object with a type field.
SSE Event Types
metadata
Always the first event. Contains the conversation ID.
data: {"type": "metadata", "conversation_id": "550e8400-e29b-41d4-a716-446655440000"}
Save this ID to continue the conversation in future messages.
token
Streamed text chunks. Accumulate these into the assistant's message bubble.
data: {"type": "token", "content": "You"}
data: {"type": "token", "content": " have"}
data: {"type": "token", "content": " 3 active investments"}
tool_start
Casey is executing a tool. Show a loading indicator with the label text.
data: {"type": "tool_start", "tool": "query_database", "label": "Looking up your information..."}
tool | label |
|---|---|
find_deal | Finding the deal... |
query_database | Looking up your information... |
search_deal_documents | Researching the deal... |
search_platform_docs | Checking Play Money guides... |
web_search | Searching the web... |
submit_qa_question | Submitting your question... |
request_investment_increase | Submitting increase request... |
tool_end
Tool finished. Dismiss the loading indicator for that tool.
data: {"type": "tool_end", "tool": "query_database"}
Multiple tools can run concurrently. Track active tools by name and dismiss them individually.
widget
A hint telling the frontend to render a visual component. See the Widgets page for details.
data: {"type": "widget", "widget": {"type": "deal_card", "dealId": 123}}
sources
Emitted once before done when Casey's response includes citable sources from web search or platform documentation. Each source has an index that corresponds to [N] markers in the message text.
data: {"type": "sources", "sources": [{"index": 1, "title": "Play Money Fees", "url": "https://...", "source_type": "platform_docs"}]}
| Field | Type | Description |
|---|---|---|
sources[].index | number | Corresponds to [N] citation markers in the message text |
sources[].title | string | Human-readable source title |
sources[].url | string | URL to the source |
sources[].source_type | "web" | "platform_docs" | Where the source came from |
Frontend: Render [N] markers in the message text as small clickable links that open the source URL. When loading from conversation history, sources are in the citations array on assistant messages (see Conversations).
error
Something went wrong. Show the message to the user.
data: {"type": "error", "message": "Something went wrong. Please try again."}
done
Always the last event. Finalize the message UI.
data: {"type": "done"}
Event Ordering
A typical stream looks like:
metadata → tool_start → tool_end → token* → widget? → token* → sources? → done
metadatais always firsttool_start/tool_endpairs may interleave with tokenswidgetevents can appear at any pointsourcesis emitted once after all tokens, beforedone(only when citable sources exist)doneis always last
TypeScript Types
type CaseySSEEvent =
| { type: "metadata"; conversation_id: string }
| { type: "token"; content: string }
| { type: "tool_start"; tool: string; label: string }
| { type: "tool_end"; tool: string }
| { type: "widget"; widget: CaseyWidgetHint }
| { type: "sources"; sources: CaseySource[] }
| { type: "error"; message: string }
| { type: "done" };
interface CaseySource {
index: number;
title: string;
url: string;
source_type: "web" | "platform_docs";
}
Inline Markers
Casey embeds lightweight markers in its message text that the frontend should parse and render as interactive elements.
Deal Links — [deal:ID]
Every deal name in a response is followed by a [deal:ID] marker containing the deal's numeric ID.
**Bold Reuse** [deal:42] is a sustainable packaging company that...
Frontend: Use a regex like /\[deal:(\d+)\]/g to find markers, strip them from the visible text, and wrap the preceding deal name in a link to the deal page.
Source Citations — [N]
When Casey cites web search or platform documentation, it uses numbered [1], [2] markers. The matching source data arrives in the sources SSE event (see above).
Play Money charges a platform fee on all investments [1].
Frontend: Match \[(\d+)\] markers against the sources array by index and render them as small clickable links that open the source URL.
Last updated Mar 26, 2026
Built with Documentation.AI