Connect Thread History
Configure threadApiUrl and load thread lists and message history.
This page explains how to connect thread lists and previous messages from a backend.
To connect thread history, either:
- pass
threadApiUrland implement the default endpoint contract used by OpenUI - provide custom thread functions if your API shape is different
This config only affects thread history. Your live chat request still comes from apiUrl or processMessage.
Default threadApiUrl contract
When you pass threadApiUrl="/api/threads", OpenUI appends its own path segments. The default requests look like this:
| Action | Method | URL | Request body | Expected response |
|---|---|---|---|---|
| List threads | GET | /api/threads/get | — | { threads: Thread[], nextCursor?: any } |
| Create thread | POST | /api/threads/create | { messages } | Thread |
| Update thread | PATCH | /api/threads/update/:id | Thread | Thread |
| Delete thread | DELETE | /api/threads/delete/:id | — | empty response is fine |
| Load messages | GET | /api/threads/get/:id | — | message array in your backend format |
import { FullScreen } from "@openuidev/react-ui";
<FullScreen apiUrl="/api/chat" threadApiUrl="/api/threads" agentName="Assistant" />;createThread sends the first user message as messages, already converted through your current messageFormat. loadThread expects the response body to be something messageFormat.fromApi() can read.
When to add messageFormat
If your thread API stores messages in OpenUI's default shape, you do not need any extra config.
If your thread API stores messages in OpenAI chat format, add messageFormat={openAIMessageFormat} so both chat requests and thread loading stay aligned.
In other words:
apiUrlorprocessMessagehandles sending new chat requeststhreadApiUrlhandles listing threads and loading saved messagesmessageFormatkeeps both paths aligned when your backend does not use the default AG-UI message shape
import { openAIMessageFormat, openAIReadableStreamAdapter } from "@openuidev/react-headless";
import { FullScreen } from "@openuidev/react-ui";
<FullScreen
apiUrl="/api/chat"
threadApiUrl="/api/threads"
streamProtocol={openAIReadableStreamAdapter()}
messageFormat={openAIMessageFormat}
agentName="Assistant"
/>;Use custom thread functions when your API differs
If your backend already uses a different shape, such as:
- REST routes like
/api/threads/:id/messages - GraphQL
- auth-protected endpoints with custom headers
- a different request body for creating threads
then provide the individual thread functions instead of relying on the default threadApiUrl behavior.
<FullScreen
apiUrl="/api/chat"
fetchThreadList={async (cursor) => {
const res = await fetch(`/api/conversations?cursor=${cursor ?? ""}`);
return res.json();
}}
createThread={async (firstMessage) => {
const res = await fetch("/api/conversations", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ firstMessage }),
});
return res.json();
}}
updateThread={async (thread) => {
const res = await fetch(`/api/conversations/${thread.id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(thread),
});
return res.json();
}}
deleteThread={async (id) => {
await fetch(`/api/conversations/${id}`, { method: "DELETE" });
}}
loadThread={async (threadId) => {
const res = await fetch(`/api/conversations/${threadId}/messages`);
return res.json();
}}
agentName="Assistant"
/>