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:

JSON
{
  "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:

JSON
{
  "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:

JSON
{
  "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:

JSON
{
  "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:

JSON
{
  "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:

JSON
{
  "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:

JSON
{
  "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:

JSON
{
  "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:

JSON
{
  "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:

JSON
{
  "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:

JSON
{
  "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:

JSON
{
  "config": {}
}

Response:

JSON
{
  "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.

Last updated for v0.9.2Edit this page on GitHubReport an issue