Runs
A run executes an app: you supply the app's input fields, the API queues the work, and a worker fills in the response. Runs are asynchronous — creating one returns immediately with a new status, and you read the result back once it has finished. A run started through the API shows API as its origin in the workspace history.
Endpoints
| Method | Path | Scope |
|---|---|---|
| POST | /v1/run/create | reasoning:write |
| GET | /v1/run/list | reasoning:read |
| GET | /v1/run/detail/<run_id> | reasoning:read |
<run_id> is a run identifier, prefixed runi_.
Note — The path segment is
runbut the scope isreasoning:readandreasoning:write, and the object is areasoning. A key scopedrun:*cannot call these endpoints. Usereasoning:*, or*.
The reasoning object
| Field | Type | Description |
|---|---|---|
id | string | The run identifier, prefixed runi_. |
object | string | Always reasoning. |
app_id | string | The app that was run. |
model | object | The model that was resolved for the run, or null. |
data | object | The inputs the run was launched with, keyed by field name. |
instruction | object | The instructions that were sent, keyed by instruction identifier. |
response | object | The model's answer, keyed by instruction identifier. Empty until the run finishes. |
tokens | object | Token counts as input, output and total, or null when not yet metered. |
status | string | See the statuses below. |
duration | number | How long the run took, in seconds to two decimals, or null. |
started_at | integer | When the worker picked the run up, or null. |
finished_at | integer | When the run completed, or null. |
created_at | integer | When the run was queued, in Unix seconds. |
updated_at | integer | Last change, in Unix seconds. |
The model object carries the resolved build:
| Field | Type | Description |
|---|---|---|
id | string | The model. |
model_library | string | The exact model build the run used. |
name | string | The build's name. |
parameter | string | The build's parameter size. |
Statuses
| Status | Meaning |
|---|---|
new | Queued, not yet picked up. |
pull | Being prepared by a worker. |
processing | Running against the model. |
finished | Complete. response is filled in. |
failed | Ended in an error. |
Poll GET /v1/run/detail/<run_id> until the status is finished or failed. Both are final; every other status will change on its own.
Launch a run
POST /v1/run/create names an app and supplies its inputs.
| Parameter | Type | Required | Description |
|---|---|---|---|
app_id | string | yes | The app to run. Also accepted as app or app_ident. |
data | object | yes | One entry per input field. Key each entry by the field's name, as returned by Apps or Catalog. |
curl -X POST https://api.thinkhx.com/v1/run/create \
-H "Authorization: Bearer sk-project-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"app_id": "mapp_0ceacb46e5b3a99e91b6",
"data": { "message": "The checkout page has been down since this morning." }
}' {
"code": 200,
"title": "OK",
"response": {
"id": "runi_1b7f4e0c96a2d8531fca",
"object": "reasoning",
"data": { "message": "The checkout page has been down since this morning." },
"instruction": { "1": "Classify the message as low, normal or urgent." },
"status": "new",
"created_at": 1754209200
}
} Keep the returned id and poll it. The creation response deliberately carries no response field: nothing has run yet.
Sending a document or an image
A field whose type is document or image (see Apps) does not take text: it takes a file your project has already uploaded to its own library. Send the file's identifier, prefixed file_, or its delivery URL — both are accepted and both are stored as the URL:
curl -X POST https://api.thinkhx.com/v1/run/create \
-H "Authorization: Bearer sk-project-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"app_id": "mapp_0ceacb46e5b3a99e91b6",
"data": { "invoice": "file_9c1d4a70e58b23f6ad02" }
}' The engine reads the file before the model runs: a document becomes the text it contains, an image is handed to the model as a picture. Accepted document formats are PDF, DOCX, XLSX, CSV and TXT; images are PNG, JPG and WebP.
| Code | Message | Cause |
|---|---|---|
| 422 | Field '<name>' expects an uploaded file: send its cdn file id (file_<20 hex>) or its delivery URL. | The value was ordinary text. |
| 422 | The file sent for '<name>' is not in this project's reasoning image / reasoning document library. | The file belongs to another project, was deleted, or was uploaded into another library. |
| 422 | The file sent for '<name>' cannot be read: accepted document formats are pdf, docx, xlsx, csv, txt. | The document is in a format the engine cannot read. |
| 422 | The model resolved for this app cannot read images. Choose a model that accepts image input. | The app has an image field but its model has no image input. |
You can run your own apps and any published app of any project. An app that is not activated, or has no usable model, is refused with 422 and the general message.
| Code | Message | Cause |
|---|---|---|
| 400 | Missing required field: app_id. | No app was named. |
| 404 | App not found. | The app does not exist, or is deleted, or is private to another project. |
| 422 | Missing required field: <name>. | A required input field was absent or empty. |
| 402 | Your reasoning quota is exhausted. Please wait until it resets or upgrade your plan. | The allowance for the cycle is used up. |
The quota is checked before anything else, so an exhausted project cannot queue work. Read the remaining allowance from Quota and token usage.
Tip — A field can also be keyed by its
madi_identifier or by its position, counting from1. Keying bynameis the clearest and is what the app's schema gives you.
Read one run
GET /v1/run/detail/<run_id> returns the whole run, including the response once it exists.
curl https://api.thinkhx.com/v1/run/detail/runi_1b7f4e0c96a2d8531fca \
-H "Authorization: Bearer sk-project-YOUR_KEY" {
"code": 200,
"title": "OK",
"response": {
"id": "runi_1b7f4e0c96a2d8531fca",
"object": "reasoning",
"app_id": "mapp_0ceacb46e5b3a99e91b6",
"model": {
"id": "modi_7b1e4c2a9d05f3618ea4",
"model_library": "mlyi_2c9a7f45b8e1d06a3427",
"name": "thinkhx-reason",
"parameter": "8B"
},
"data": { "message": "The checkout page has been down since this morning." },
"instruction": {
"miid_9a4c07e5b312df8641ca": "Classify the message as low, normal or urgent."
},
"response": {
"miid_9a4c07e5b312df8641ca": "urgent"
},
"tokens": { "input": 412, "output": 3, "total": 415 },
"status": "finished",
"duration": 1.84,
"started_at": 1754209202,
"finished_at": 1754209204,
"created_at": 1754209200,
"updated_at": 1754209204
}
} instruction and response share their keys, so you can pair each answer with the instruction that produced it. A run of another project gives 404 and Reasoning not found.
List runs
GET /v1/run/list returns the project's runs, newest first.
| Parameter | Type | Description |
|---|---|---|
app_id | string | Return only the runs of one app. Also accepted as app or app_ident. |
limit | integer | Rows to return, 1 to 100. Defaults to 50. |
offset | integer | Rows to skip. Defaults to 0. |
curl "https://api.thinkhx.com/v1/run/list?app_id=mapp_0ceacb46e5b3a99e91b6&limit=2" \
-H "Authorization: Bearer sk-project-YOUR_KEY" {
"code": 200,
"title": "OK",
"response": {
"object": "list",
"data": [
{
"id": "runi_1b7f4e0c96a2d8531fca",
"object": "reasoning",
"app_id": "mapp_0ceacb46e5b3a99e91b6",
"status": "finished",
"duration": 1.84,
"started_at": 1754209202,
"finished_at": 1754209204,
"created_at": 1754209200,
"updated_at": 1754209204,
"tokens": { "input": 412, "output": 3, "total": 415 }
}
],
"total": 1
}
} The list omits data, instruction, response and model. Read a run to get them. Listing never touches the quota, so you can poll a history freely.