POST
/v1/threads/{thread_id}/runsRuns
Execute an Assistant against a Thread: the model reads the thread, optionally calls tools, and writes its reply back as a new message. Stream the events over SSE or poll the run until it reaches a terminal status. When the assistant calls one of your function tools the run pauses at requires_action and waits for you to submit_tool_outputs.
Request
- HTTP
- POST
- URL
- /v1/threads/{thread_id}/runs
- Auth
- api_key
Try it
# start a run (polling style)
curl https://api.fightclub.pro/v1/threads/thread_abc/runs \
-H "Authorization: Bearer $FC_API_KEY" -H "Content-Type: application/json" \
-d '{"assistant_id":"asst_xyz"}'
# => { "id":"run_...", "status":"queued", ... } then poll GET the run
# if status=requires_action, answer the tool calls
curl https://api.fightclub.pro/v1/threads/thread_abc/runs/run_123/submit_tool_outputs \
-H "Authorization: Bearer $FC_API_KEY" -H "Content-Type: application/json" \
-d '{"tool_outputs":[{"tool_call_id":"call_1","output":"{\"ok\":true}"}]}'Example response
{
"id": "run_6Aa9",
"object": "thread.run",
"created_at": 1782300000,
"thread_id": "thread_5Yz8",
"assistant_id": "asst_4Tn7",
"status": "completed",
"model": "openai/gpt-4o-mini",
"tools": [ { "type": "file_search" } ],
"usage": { "prompt_tokens": 820, "completion_tokens": 96, "total_tokens": 916 }
}A representative 200 body. Ids and timestamps are illustrative.
Body parameters
| Name | Type | Default | Description |
|---|---|---|---|
| assistant_id* | string | — | The assistant (asst_*) to run against this thread. |
| model | string | optional | Override the assistant model for this run. |
| instructions | string | optional | Replace the assistant instructions for this run only. |
| additional_instructions | string | optional | Append to the assistant instructions for this run only. |
| additional_messages | array | optional | Extra messages appended to the thread before the run starts. |
| tools | array | optional | Override the assistant tools for this run. Attach stores here: [{ type:"file_search", file_search:{ vector_store_ids:["vs_..."] } }]. |
| tool_choice | string | object | optional | auto | none | required, or force a specific tool. |
| temperature | number | optional | Sampling temperature for this run, 0-2. |
| top_p | number | optional | Nucleus sampling for this run, 0-1. |
| response_format | string | object | optional | auto or a json_schema to force structured output for this run. |
| metadata | object | optional | Free-form metadata on the run. |
| stream | boolean | false | Stream run + message-delta events as SSE instead of polling. |
* required.
Response fields
| Name | Type | Description |
|---|---|---|
| id | string | Run id (run_*). |
| object | string | "thread.run". |
| created_at | integer | Unix timestamp. |
| thread_id | string | The thread this run executes on. |
| assistant_id | string | The assistant being run. |
| status | string | queued | in_progress | requires_action | cancelling | cancelled | completed | failed | expired. |
| required_action | object | null | When status=requires_action: { type:"submit_tool_outputs", submit_tool_outputs:{ tool_calls:[...] } }. |
| last_error | object | null | On failure: { code, message }. |
| usage | object | null | { prompt_tokens, completion_tokens, total_tokens }, set on completion. |
| model | string | The model that ran. |
| started_at / expires_at / completed_at / cancelled_at / failed_at | integer | null | Lifecycle timestamps as they occur. |
Errors
- 401
missing_tokenNo Authorization header was sent. - 401
invalid_auth_schemeThe scheme was neither Bearer nor Client. - 401
invalid_token_formatA Bearer token not prefixed ko_. - 401
invalid_tokenThe API key is unknown, revoked or expired. - 403
insufficient_scopeThe key is valid but lacks the required scope. - 400
invalid_assistant_idassistant_id is missing or malformed. - 400
invalid_additional_messagesadditional_messages is malformed. - 400
invalid_modelmodel override is not a valid ref. - 400
invalid_tool_call_idsubmit_tool_outputs referenced an unknown tool_call_id. - 409
thread_lockedA run is already active on this thread. - 409
run_not_in_requires_actionsubmit_tool_outputs called when the run is not waiting for tools. - 409
run_already_completedcancel called on a run that already reached a terminal status. - 404
not_foundNo such thread, assistant or run (also cross-tenant).
See the full error reference.
Related routes
| GET | /v1/threads/{thread_id}/runs | List runs on a thread. |
| GET | /v1/threads/{thread_id}/runs/{run_id} | Retrieve a run (poll its status). |
| POST | /v1/threads/{thread_id}/runs/{run_id} | Modify run metadata. |
| POST | /v1/threads/{thread_id}/runs/{run_id}/cancel | Cancel a queued/in-progress run (409 run_already_completed if terminal). |
| POST | /v1/threads/{thread_id}/runs/{run_id}/submit_tool_outputs | Answer the tool calls: { tool_outputs:[{ tool_call_id, output }] }. Supports stream:true. |
Notes
- ·The run loop: create a run -> if status=requires_action, read required_action.submit_tool_outputs.tool_calls, execute them, POST submit_tool_outputs -> repeat until status=completed.
- ·Only one run can be active on a thread at a time (the thread is locked while it runs).
- ·Stream:true emits run lifecycle + message-delta events over SSE; otherwise poll GET the run.
- ·Spend lands on the customer named in the thread metadata, if any.