- Threads
- Submit Tool Outputs
Threads
Submit Tool Outputs
curl --request POST \
--url https://app.backboard.io/api/threads/tool-outputs \
--header 'X-API-Key: <api-key>' \
--header 'authorization: <authorization>' \
--header 'x_session_token: <x_session_token>' \
--header 'Content-Type: application/json' \
--data '{
"thread_id": "<uuid>",
"tool_outputs": [
{
"tool_call_id": "string",
"output": "string"
}
],
"stream": true,
"thinking": {
"effort": "string",
"budget_tokens": 0,
"max_tokens": 1,
"exclude_reasoning": true
}
}'Overview
The recommended way to submit tool call results. Unlike the original endpoint, you never need to track run_id — the server resolves it automatically from the latest REQUIRES_ACTION message on the thread.
Three fields, no escape hatches:
| Field | Type | Required | Description |
|---|---|---|---|
thread_id | uuid | Yes | Thread the outputs belong to |
tool_outputs | array | Yes | [{tool_call_id, output}, ...] |
stream | boolean | No | Stream the response (default false) |
Quick Start
import json
from backboard import BackboardClient
client = BackboardClient(api_key="YOUR_API_KEY")
# 1. Send a message that triggers a tool call
r = await client.send_message(
"What's the weather in SF?",
thread_id=thread_id,
tools=[weather_tool],
)
# 2. Execute the tool
if r.status == "REQUIRES_ACTION" and r.tool_calls:
outputs = []
for tc in r.tool_calls:
result = my_tool_handler(tc.function.name, tc.function.parsed_arguments)
outputs.append({"tool_call_id": tc.id, "output": json.dumps(result)})
# 3. Submit outputs — no run_id needed
final = await client.submit_tool_outputs_simple(
thread_id=r.thread_id,
tool_outputs=outputs,
)
print(final.content)
Streaming
async for chunk in await client.submit_tool_outputs_simple(
thread_id=thread_id,
tool_outputs=outputs,
stream=True,
):
if chunk.get("type") == "content_streaming":
print(chunk.get("content", ""), end="", flush=True)
Chained Tool Calls
The model may need multiple rounds. Loop until status is COMPLETED:
r = await client.send_message("Get weather + forecast for SF", thread_id=tid, tools=tools)
while r.status == "REQUIRES_ACTION" and r.tool_calls:
outputs = [
{"tool_call_id": tc.id, "output": json.dumps(dispatch(tc))}
for tc in r.tool_calls
]
r = await client.submit_tool_outputs_simple(
thread_id=r.thread_id,
tool_outputs=outputs,
)
print(r.content)
Comparison with Original Endpoint
| This endpoint | Original (/threads/{id}/runs/{run_id}/submit-tool-outputs) | |
|---|---|---|
run_id | Auto-resolved | Must be provided |
tools override | Not supported | Supported |
thinking (reasoning) | Not supported | Supported — per-step reasoning on continuation |
| Schema | Strict (extra="forbid") | Flexible |
| Best for | Most integrations | Advanced: pin a run, swap tools, or tune reasoning after tools |
For the original endpoint, see Submit Tool Outputs.
Error Codes
| Status | Cause |
|---|---|
| 404 | Thread not found, or no pending REQUIRES_ACTION on the thread |
| 422 | tool_outputs is empty or contains invalid entries |
| 400 | Extra fields in request body (strict schema) |
Authorizations
Query Parameters
Body
Thread UUID the outputs belong to.
Tool outputs to submit. Each item is {tool_call_id, output}.
Whether to stream the response.
Optional per-step reasoning override for this continuation. Omit to reuse the run's original thinking config; send null to disable thinking for this continuation; send {} for provider defaults.
Response
200
422
Successful Response
Message
Thread Id
Run Id
Timestamp
Content
Message Id
Tool Calls
Memory Operation Id
Retrieved Files
Retrieved Files Count
Reasoning
Model Provider
Model Name
Input Tokens
Output Tokens
Total Tokens
Created At
Context Usage
curl --request POST \
--url https://app.backboard.io/api/threads/tool-outputs \
--header 'X-API-Key: <api-key>' \
--header 'authorization: <authorization>' \
--header 'x_session_token: <x_session_token>' \
--header 'Content-Type: application/json' \
--data '{
"thread_id": "<uuid>",
"tool_outputs": [
{
"tool_call_id": "string",
"output": "string"
}
],
"stream": true,
"thinking": {
"effort": "string",
"budget_tokens": 0,
"max_tokens": 1,
"exclude_reasoning": true
}
}'