Thread endpoints
In shortReference for the 10xGraph REST endpoints that read and write thread state and messages, with request fields, responses, and auth requirements.
- 4 min read
- 12 sections
- Updated
- v0.9.2
- Markdown
Thread endpoints let you read and manage conversation state stored in the checkpointer. A thread is identified by its thread_id.
Base path: /v1/threads
Route summary
| Method | Path | Permission |
|---|---|---|
GET |
/v1/threads |
checkpointer:read |
GET |
/v1/threads/{thread_id} |
checkpointer:read |
DELETE |
/v1/threads/{thread_id} |
checkpointer:delete |
GET |
/v1/threads/{thread_id}/state |
checkpointer:read |
PUT |
/v1/threads/{thread_id}/state |
checkpointer:write |
DELETE |
/v1/threads/{thread_id}/state |
checkpointer:delete |
GET |
/v1/threads/{thread_id}/messages |
checkpointer:read |
POST |
/v1/threads/{thread_id}/messages |
checkpointer:write |
GET |
/v1/threads/{thread_id}/messages/{message_id} |
checkpointer:read |
DELETE |
/v1/threads/{thread_id}/messages/{message_id} |
checkpointer:delete |
There is no create-thread endpoint. A thread is created implicitly by the first POST /v1/graph/invoke or POST /v1/graph/stream that uses its thread_id, or by the server generating one when the request omits it.
GET /v1/threads
List threads stored in the checkpointer. With ownership authorization active, only threads owned by the caller are returned.
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
search |
string | — | Free-text filter over thread records |
offset |
integer | — | Number of threads to skip. Must be >= 0. |
limit |
integer | 100 |
Page size. Clamped server-side to a maximum of 1000 regardless of what the client asks for. Must be > 0. |
Response:
{
"success": true,
"data": {
"threads": [
{"thread_id": "t1", "created_at": "2026-04-01T10:00:00Z"},
{"thread_id": "t2", "created_at": "2026-04-02T09:30:00Z"}
]
}
}GET /v1/threads/{thread_id}
Get a single thread record (metadata, not messages or state).
Path parameters:
| Parameter | Type | Description |
|---|---|---|
thread_id |
string or integer | Thread identifier. An empty or whitespace-only string, or an integer below 1, returns 422. |
Response:
{
"success": true,
"data": {
"thread_data": {
"thread_id": "t1",
"thread_name": "Weather in Paris",
"user_id": "user-123"
}
}
}DELETE /v1/threads/{thread_id}
Delete a thread and its checkpointed data.
Request body:
{
"config": {}
}The body is required; send {} or {"config": {}} when you have no extra config to pass. Keys in config are merged into the checkpointer config alongside thread_id.
Response:
{
"success": true,
"data": {"success": true, "message": "Thread deleted successfully"}
}Deleting a thread also evicts its cached ownership entry, so the thread_id can be reused by a different user afterwards.
GET /v1/threads/{thread_id}/state
Get the saved state for a thread.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
thread_id |
string or integer | Thread identifier |
Response:
{
"success": true,
"data": {
"state": {
"context": [
{"role": "user", "content": "Hello"},
{"role": "assistant", "content": "Hi there!"}
]
}
}
}PUT /v1/threads/{thread_id}/state
Replace or update state fields for a thread.
Request body:
{
"state": {
"user_id": "user-456"
},
"config": {}
}| Field | Type | Description |
|---|---|---|
state |
object | State fields to merge into the current state |
config |
object | Optional extra config |
Response:
{
"success": true,
"data": {"updated": true}
}Use this endpoint to inject custom state fields (like user_id) before the first invoke call or to repair inconsistent state.
DELETE /v1/threads/{thread_id}/state
Clear the saved state for a thread. The next invoke call with this thread_id will start fresh.
Response:
{
"success": true,
"data": {"deleted": true}
}GET /v1/threads/{thread_id}/messages
Get the conversation messages for a thread.
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
search |
string | — | Free-text filter over message content |
offset |
integer | — | Number of messages to skip. Must be >= 0. |
limit |
integer | 100 |
Page size. Clamped server-side to a maximum of 1000. Must be > 0. |
Response:
{
"success": true,
"data": {
"messages": [
{"role": "user", "content": "Hello"},
{"role": "assistant", "content": "Hi there!"}
]
}
}POST /v1/threads/{thread_id}/messages
Store messages on a thread.
Request body:
{
"messages": [
{"role": "user", "content": "Injected message"}
],
"metadata": {"source": "import"},
"config": {}
}| Field | Type | Required | Description |
|---|---|---|---|
messages |
array | yes | Messages to store. An empty array returns 422. |
metadata |
object | no | Arbitrary metadata stored with the write |
config |
object | no | Extra keys merged into the checkpointer config |
Response:
{
"success": true,
"data": {"success": true, "message": "Messages stored"}
}GET /v1/threads/{thread_id}/messages/{message_id}
Get a single message from a thread.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
thread_id |
string or integer | Thread identifier |
message_id |
string or integer | Message identifier. Empty or whitespace-only returns 422. |
Response: the Message object.
DELETE /v1/threads/{thread_id}/messages/{message_id}
Delete a single message from a thread.
Request body:
{
"config": {}
}Response:
{
"success": true,
"data": {"success": true, "message": "Message deleted successfully"}
}Authentication and ownership
When auth is configured, all endpoints require a bearer token. Each route declares its own permission, listed in Route summary; the required scope is the "<resource>:<action>" string, for example checkpointer:read.
With the ownership authorization backend active (the default in MODE=production), thread_id is also checked against the thread’s owner. A request for a thread owned by another user is rejected with 403 before it reaches the checkpointer. A thread_id that does not exist yet is allowed through, since it represents a new session.
See Authentication.