logo
Casey AIChat Endpoint

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"
  }
}
FieldTypeRequiredDescription
messagestringYesThe user's message (1–4000 chars)
conversation_idstringNoUUID to continue an existing conversation
create_new_conversationbooleanNoForce a new conversation even if conversation_id is set
contextobjectNoPage 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.

PageFieldsExample
"deal"deal_id, deal_name, deal_slugUser is viewing a deal page
"portfolio"(none)User is viewing their portfolio
"investment_detail"investment_idUser 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..."}
toollabel
find_dealFinding the deal...
query_databaseLooking up your information...
search_deal_documentsResearching the deal...
search_platform_docsChecking Play Money guides...
web_searchSearching the web...
submit_qa_questionSubmitting your question...
request_investment_increaseSubmitting 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"}]}
FieldTypeDescription
sources[].indexnumberCorresponds to [N] citation markers in the message text
sources[].titlestringHuman-readable source title
sources[].urlstringURL 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
  • metadata is always first
  • tool_start / tool_end pairs may interleave with tokens
  • widget events can appear at any point
  • sources is emitted once after all tokens, before done (only when citable sources exist)
  • done is 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.

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.