Documentation
Concepts

Threads and Messages

Threads are conversation sessions in Flapjack. Messages are individual turns streamed via SSE. Learn the conversation lifecycle.

A thread is a conversation session between a user and an agent. A message is a single turn within that thread.

Thread Lifecycle

Create Thread → Send Message → Receive Stream → Send Another → ...
  1. Create a thread for a specific agent
  2. Send messages to the thread — each triggers an agent response
  3. Receive responses as SSE streams with incremental tokens
  4. The thread maintains full conversation history automatically

Thread Fields

FieldTypeDescription
idstringUnique identifier (UUID)
org_idstringOrganization that owns this thread
agent_idstringThe agent this thread belongs to
titlestring | nullOptional thread title
active_profilestring | nullActive tool profile (null = use agent default)
created_atstringISO 8601 timestamp

TypeScript Type

type Thread = {
  id: string;
  org_id: string;
  agent_id: string;
  title: string | null;
  active_profile?: string | null;
  created_at: string;
};

Creating a Thread

SDK

const thread = await client.createThread('agent-id');
console.log(thread.id); // Use this to send messages
📋 Copy as prompt

Create a new Flapjack thread for my agent using client.createThread(agentId), then log the thread ID.

API

curl -X POST https://api.flapjack.dev/api/threads \
  -H "Authorization: Bearer fj_live_..." \
  -H "Content-Type: application/json" \
  -d '{"agentId": "your-agent-id"}'

Sending Messages

Messages are sent to a thread and the response is streamed back via SSE.

SDK

for await (const event of client.sendMessage(thread.id, 'What is Flapjack?')) {
  if (event.type === 'token') process.stdout.write(event.delta);
  if (event.type === 'done') console.log('\n', event.content);
}
📋 Copy as prompt

Send a message to a Flapjack thread using client.sendMessage(threadId, message) and stream the response, printing each token as it arrives.

API

curl -N -X POST https://api.flapjack.dev/api/threads/{threadId}/messages \
  -H "Authorization: Bearer fj_live_..." \
  -H "Content-Type: application/json" \
  -d '{"content": "What is Flapjack?"}'

Message Roles

Messages in a thread have one of these roles:

RoleDescription
userMessage sent by the user
assistantResponse from the agent
toolResult of a tool execution
systemSystem-level message

Message Type

The SDK exposes a simplified message type for the useChat hook:

// SDK simplified type (useChat hook)
type Message = {
  role: 'user' | 'assistant';
  content: string;
  systemMessage?: SystemMessageMeta;
};

type SystemMessageMeta = {
  icon: string;   // 'check' | 'tool' | 'info' | 'error' or any emoji/character
  label: string;  // Short text shown next to the icon
};

The full API/database message model includes additional roles (tool, system) and fields like tool_name, tool_call, and tool_result_ref.

System User Messages

Some user messages represent system activity rather than typed user input — for example, approving a plan, confirming a tool execution, or acknowledging an MCP event. These are regular role: 'user' messages with a systemMessage metadata field that tells the UI to render them as a compact, centered status indicator (icon + label pill) instead of a chat bubble.

Built-in icon keys:

KeyGlyphUse case
checkPlan approved, action confirmed
tool🔧Tool / MCP activity
infoGeneral information
errorError / rejection

Any other string is rendered as-is (e.g. "🚀" or "★").

// Inject a system message via the useChat hook
const { addSystemMessage } = useChat(agentId);

addSystemMessage(
  { icon: 'check', label: 'Plan approved' },
  { content: 'Approved. Please proceed with the plan.' },
);

See SDK: React Hooks for full addSystemMessage API.

Conversation History

Flapjack automatically maintains the full conversation history for each thread. When you send a new message, the agent receives all prior messages in the thread as context. You don't need to manage history yourself.

Listing Threads

Retrieve a user's past conversation threads for an agent:

const { threads, nextCursor } = await client.listThreads('agent-id');

Threads are returned newest-first with cursor-based pagination. For JWT auth, only the current user's threads are returned. For API key auth, all org threads are returned.

See SDK: Client — listThreads and API: Threads — List Threads.

Retrieving Messages

Fetch the message history for a specific thread:

const { messages, total } = await client.getMessages('thread-id');

Returns user and assistant messages in chronological order with offset-based pagination.

See SDK: Client — getMessages and API: Threads — Get Messages.

Resuming a Thread

In the React SDK, pass a threadId to the useChat hook to resume an existing conversation:

const { messages, sendMessage } = useChat(agentId, { threadId: 'existing-thread-id' });

Messages are loaded automatically on mount. Use loadThread(id) to switch threads at runtime.

See SDK: React — Resuming a Thread.

Stopping a Response

To stop an active response mid-stream:

curl -X POST https://api.flapjack.dev/api/threads/{threadId}/stop \
  -H "Authorization: Bearer fj_live_..."

Next Steps

  • Streaming — SSE event types in detail
  • Tools — what happens when an agent calls a tool
  • API: Threads — full endpoint reference
Docs last updated May 11, 2026