1. Core Concepts
  2. Conversation threads

​
What this is

A thread is a single conversation: the full back-and-forth between the user and the model (including tool messages). It has a thread_id. When you send another message with the same thread_id, the model sees prior turns—that is how chat feels continuous.

Threads are not the same as assistants. Think:

  • Assistant = the AI profile (memory scope, docs, defaults).
  • Thread = one chat session under that profile.

Each thread belongs to exactly one assistant. You can open many threads per assistant (for example one thread per end user).

​
When you create or reuse a thread

SituationWhat happens
First send_message with no thread_idThe API creates a new thread (and ties it to an assistant). Save thread_id from the response to continue.
Next message with thread_idAppends to that thread—history is preserved.
New thread under the same assistantOmit thread_id but pass the same assistant_id—memory and docs from that assistant still apply.

​
Key properties

PropertyTypeDescription
thread_iduuidUnique identifier
assistant_iduuidThe assistant this thread belongs to
messagesarrayMessages in the conversation (included on GET)
metadata_objectOptional metadata object
created_atdatetimeCreation timestamp

​
Important behavior

  • Each thread is tied to one assistant.
  • You can have many threads per assistant (e.g. one per end-user).
  • Threads persist until you delete them.
  • Fetching a thread (GET /threads/{id}) returns messages for inspection or debugging.

​
Create a thread

import requests

headers = {"X-API-Key": "YOUR_API_KEY"}
assistant_id = "your-assistant-id"

thread = requests.post(
    f"https://app.backboard.io/api/assistants/{assistant_id}/threads",
    headers=headers,
    json={}
).json()
print(thread["thread_id"])

​
Get a thread (with messages)

thread = requests.get(
    f"https://app.backboard.io/api/threads/{thread_id}",
    headers=headers
).json()

for msg in thread["messages"]:
    print(f"{msg['role']}: {msg.get('content', '')}")

​
List threads

Both GET /threads (all threads) and GET /assistants/{id}/threads (scoped) support skip and limit pagination.

ParameterTypeDefaultRangeDescription
skipinteger00–10 000Number of records to skip
limitinteger1001–200Maximum number of records to return
# All threads
all_threads = requests.get(
    "https://app.backboard.io/api/threads",
    headers=headers,
    params={"skip": 0, "limit": 50}
).json()

# Threads for a specific assistant
asst_threads = requests.get(
    f"https://app.backboard.io/api/assistants/{assistant_id}/threads",
    headers=headers,
    params={"skip": 0, "limit": 50}
).json()

​
Delete a thread

Permanently removes the thread and all its messages.

Threads do not expire automatically. Delete threads you no longer need to keep your data clean.

requests.delete(
    f"https://app.backboard.io/api/threads/{thread_id}",
    headers=headers
)

​
Cancel a run

If a streaming response is no longer needed (e.g. user presses Ctrl+C), you can cancel the in-progress run. The server stops the LLM call on the next yield. Idempotent — cancelling a finished or already-cancelled run returns 200.

result = await client.cancel_run(thread_id, run_id)
print(result)  # {"thread_id": "...", "run_id": "...", "cancelled": true}