Project read API

Read project runs, usage, threads and scores from a backend with an API key.

The project read API answers project wide observability and conversation reads for a backend service. Send an API key to https://backend.assistant-api.com with the Aui-User-Id and Aui-Workspace-Id headers like every API key request; the workspace header is required but does not scope these reads, which cover the whole project. The cloud never returns system runs such as thread title runs. See Conventions for the shared hosts, credentials and error shapes.

The project run object

FieldTypeMeaning
idstringThe run identifier.
thread_id, message_idstring or nullThe thread and message associated with the run.
created_bystring or nullThe identity that created the run.
status, outcome_type, error_codestored valuesThe run status, outcome classification and error code.
provider, model_idstring or nullThe provider and model used by the run.
environment, releasestring or nullThe environment and release recorded for the run.
tagsarrayTags recorded on the run. The tag query filters for a matching tag.
metadata, attributesobjectThe same object under both names. metadata remains for SDK backward compatibility.
root_span_idstring or nullThe root span identifier.
service_name, agent_namestring or nullService and agent names recorded for the run.
usage_details, cost_detailsobject or nullDetailed usage and cost values recorded for the run.
input_tokens, cached_input_tokens, output_tokens, reasoning_tokensnumber or nullToken counts recorded for the run.
duration_ms, first_token_msnumber or nullRun duration and time to the first token in milliseconds.
cost_usdnumber or nullThe run cost in US dollars.
total_stepsnumber or nullThe total number of recorded steps.
assistant_idstring or nullThe assistant associated with the run.
created_atISO 8601When the run was created.

The project span object

FieldTypeMeaning
id, run_id, parent_span_idstring or nullSpan, run and parent span identifiers.
created_at, started_at, ended_atISO 8601 or nullSpan creation, start and end times.
trace_id, span_idstring or nullW3C trace and span identifiers when exported from your server.
name, operationstring or nullSpan name and operation.
provider, tool_call_idstring or nullProvider and tool call associated with the span.
status_code, error_typestored valuesSpan status code and error type.
attributesobject or nullAttributes recorded for the span.
span_indexnumberThe span index used to order spans with the same start time.
type, step_typestored valuestype is generation or tool_call; step_type is initial, tool-result, continue or sampling.
model_id, tool_name, tool_sourcestring or nullModel and tool details recorded for the span.
input_tokens, cached_input_tokens, output_tokens, reasoning_tokensnumber or nullToken counts recorded for the span.
start_ms, end_msnumber or nullStart and end times relative to the run.
finish_reason, status, errorstored valuesCompletion and error values recorded for the span.
cost_usdnumber or nullThe span cost in US dollars.
usage_details, cost_detailsobject or nullDetailed usage and cost values recorded for the span.
input, outputstored valuesThe span input and output.

List project runs

GET /v1/projects/runs
QueryTypeDefaultRules
statusenumOne of the API run status values.
outcome_typeenumOne of the API run outcome values.
model_idstring1 to 255 characters.
providerstring1 to 255 characters.
created_bystring1 to 255 characters.
thread_idstring1 to 48 characters.
environmentstring1 to 64 characters.
releasestring1 to 255 characters.
tagstring1 to 64 characters. Matches a tag on the run.
fromISO 8601 datetimeInclude runs from this time.
toISO 8601 datetimeInclude runs through this time.
limitinteger501 to 100.
cursorstringAn opaque cursor, 1 to 512 characters.
Request
GET /v1/projects/runs?limit=50&from=2026-09-01T00%3A00%3A00.000Z&to=2026-09-17T00%3A00%3A00.000Z
curl
curl "https://backend.assistant-api.com/v1/projects/runs?limit=50&from=2026-09-01T00%3A00%3A00.000Z&to=2026-09-17T00%3A00%3A00.000Z" \
  -H "Authorization: Bearer $ASSISTANT_API_KEY" \
  -H "Aui-User-Id: user_123" \
  -H "Aui-Workspace-Id: workspace_123"
Response
{
  "runs": [],
  "next_cursor": null
}

The cursor is a strict base64url encoding of JSON shaped like { "created_at": ISO, "id": string }. It is opaque, so pass next_cursor unchanged as the next cursor value. Results are ordered by created_at DESC, id DESC, and the response contains limit rows at most.

StatusBodyWhen
200A runs array and a next_cursor value.The read completed. The array is empty when no runs match.
400A schema validation error object.A query value failed validation.
400{ "error": "Invalid run cursor" }cursor is not a valid project run cursor.
401An authentication error object.The authorization header is missing, malformed or expired.
403{ "error": "This endpoint requires an API key" }The credential is not an API key, or the API key cannot use this route.

This route is read only and has no side effects. Repeating the same request is idempotent. The query always stays within the authenticated project and excludes runs whose source is system.

Get a project run

GET /v1/projects/runs/{run_id}
ParameterTypeRequiredRules
runIdstringyes1 to 48 characters.
Request
GET /v1/projects/runs/run_000000000000000000000000
curl
curl https://backend.assistant-api.com/v1/projects/runs/run_000000000000000000000000 \
  -H "Authorization: Bearer $ASSISTANT_API_KEY" \
  -H "Aui-User-Id: user_123" \
  -H "Aui-Workspace-Id: workspace_123"
Response
{
  "id": "run_000000000000000000000000",
  "thread_id": "thread_0qzof3jPoDwr7K3agyJN3D4U",
  "message_id": null,
  "created_by": null,
  "status": null,
  "outcome_type": null,
  "error_code": null,
  "provider": null,
  "model_id": null,
  "environment": null,
  "release": null,
  "tags": [],
  "metadata": {},
  "attributes": {},
  "root_span_id": null,
  "service_name": null,
  "agent_name": null,
  "usage_details": null,
  "cost_details": null,
  "input_tokens": 0,
  "cached_input_tokens": 0,
  "output_tokens": 0,
  "reasoning_tokens": 0,
  "duration_ms": 0,
  "first_token_ms": null,
  "cost_usd": 0,
  "total_steps": 0,
  "assistant_id": null,
  "created_at": "2026-09-17T00:00:00.000Z",
  "spans": []
}

The response is the project run object plus spans. Spans are ordered by start_ms ASC, span_index ASC. Only spans belonging to a non system run are returned.

StatusBodyWhen
200The run object with spans.The run is visible in the authenticated project.
400A schema validation error object.runId failed validation, including a value longer than 48 characters.
401An authentication error object.The authorization header is missing, malformed or expired.
403{ "error": "This endpoint requires an API key" }The request does not use an API key.
404{ "error": "Run not found" }No matching non system run is visible in the project.

This route is read only and has no side effects. Repeating it is idempotent. The span order is part of the response contract, so clients can render a stable sequence without sorting the returned array.

Get daily project usage

GET /v1/projects/usage/daily
QueryTypeDefaultRules
fromYYYY-MM-DD30 day windowA real UTC calendar day. If omitted, it is 29 days before to.
toYYYY-MM-DDToday in UTCA real UTC calendar day.
group_byenummodel, which groups rows by day, provider and model.

The default range ends today in UTC and starts 29 days earlier. A requested range cannot have a negative span or a span greater than 366 days. Invalid calendar dates are also rejected. Without group_by, every day in the range appears, including days with zero values. With group_by=model, the response contains one row for each stored day, provider and model combination, with no zero fill; provider and model_id can be null.

Request
GET /v1/projects/usage/daily?from=2026-09-01&to=2026-09-17&group_by=model
curl
curl "https://backend.assistant-api.com/v1/projects/usage/daily?from=2026-09-01&to=2026-09-17&group_by=model" \
  -H "Authorization: Bearer $ASSISTANT_API_KEY" \
  -H "Aui-User-Id: user_123" \
  -H "Aui-Workspace-Id: workspace_123"
Response
{
  "days": [
    {
      "day": "2026-09-17",
      "provider": null,
      "model_id": null,
      "runs": 0,
      "errors": 0,
      "input_tokens": 0,
      "output_tokens": 0,
      "total_tokens": 0,
      "cost_usd": 0
    }
  ]
}

runs counts rows whose kind is run. errors counts rows whose kind is run and whose status is error. Token and cost sums also include rows whose kind is sampling.

StatusBodyWhen
200A days array.The usage range was read.
400A schema validation error object.A query value failed validation.
400{ "error": "Usage day range must span at most 366 days" }The range is negative, greater than 366 days or contains a date that is not a real UTC day.
401An authentication error object.The authorization header is missing, malformed or expired.
403{ "error": "This endpoint requires an API key" }The request does not use an API key.

This route is read only and has no side effects. Repeating it is idempotent. The grouping choice changes the rows returned but does not change the stored usage.

Get the current usage period

GET /v1/projects/usage/period

This route has no query parameters and no request body. The period is the UTC calendar month from the first day at 00:00 through the first day of the next month at 00:00.

Request
GET /v1/projects/usage/period
curl
curl https://backend.assistant-api.com/v1/projects/usage/period \
  -H "Authorization: Bearer $ASSISTANT_API_KEY" \
  -H "Aui-User-Id: user_123" \
  -H "Aui-Workspace-Id: workspace_123"
Response
{
  "plan": "free",
  "period_start": "2026-09-01T00:00:00.000Z",
  "period_end": "2026-10-01T00:00:00.000Z",
  "active_users": 0,
  "included": 200,
  "cap": 200,
  "capped_at": null,
  "thread_titles": {
    "used": 0,
    "completed": 0,
    "included": 500,
    "cap": 500,
    "capped_at": null
  }
}
FieldMeaning
planThe plan identifier for the project.
period_start, period_endThe UTC start and exclusive end of the current calendar month.
active_usersThe active user count for the period. It is the greater of the stored period count and the sum of period users by day.
included, capThe active user allowance and cap resolved for the project.
capped_atThe time the active user cap was reached, or null.
thread_titlesThe title usage counters, allowance, cap and cap time for the period.
StatusBodyWhen
200The full usage period object.The project exists and the period was read.
401An authentication error object.The authorization header is missing, malformed or expired.
403{ "error": "This endpoint requires an API key" }The request does not use an API key.
404{ "error": "Project not found" }The project row does not exist.

This route is read only and has no side effects. Repeating it is idempotent. The response reports the current UTC period and does not reserve or consume allowance.

List project threads

GET /v1/projects/threads
QueryTypeDefaultRules
is_archivedtrue or falsefalseList archived or unarchived threads. A response does not mix both.
external_idstringReturn only threads with this external id.
limitinteger201 to 100.
afterthread idContinue after this thread in the list order.

The query is the same as the thread list. The route searches every workspace in the project. It returns raw thread table rows, not the workspace scoped ThreadDTO mapping.

Request
GET /v1/projects/threads?is_archived=false&limit=20
curl
curl "https://backend.assistant-api.com/v1/projects/threads?is_archived=false&limit=20" \
  -H "Authorization: Bearer $ASSISTANT_API_KEY" \
  -H "Aui-User-Id: user_123" \
  -H "Aui-Workspace-Id: workspace_123"
Response
{
  "threads": [
    {
      "id": "thread_0qzof3jPoDwr7K3agyJN3D4U",
      "project_id": "proj_0ltyjcuaxpv1",
      "workspace_id": "usr_anon_0ouwwTGaKr9lBxsYD5mPSWga",
      "created_at": "2026-09-17T02:40:30.497Z",
      "updated_at": "2026-09-17T02:40:32.478Z",
      "title": "Capital of Portugal and a pastry",
      "last_message_at": "2026-09-17T02:40:31.932Z",
      "is_archived": false,
      "external_id": null,
      "metadata": null
    }
  ]
}

Threads use the thread list ordering and after cursor rules. A successful response always has threads, including an empty array when nothing matches.

StatusBodyWhen
200A threads array.The project wide read completed.
400A schema validation error object.A query value failed validation.
401An authentication error object.The authorization header is missing, malformed or expired.
403{ "error": "Project-wide thread listing requires API key authentication" }The credential is not an API key, or API key access failed.

This route is read only and has no side effects. Repeating it is idempotent. Because it spans every workspace, the result can contain threads belonging to different workspace ids.

List messages in a project thread

GET /v1/projects/threads/{thread_id}/messages
Parameter or queryTypeRequiredDefaultRules
threadIdstringyes1 to 255 characters.
formatstringnoStored formatRequests a supported conversion of message content.
limitintegerno2001 to 200.
aftermessage idnoContinue after this message.

The route applies the same format conversion as the user message list. Stored aui/v0 rows can convert to ai-sdk/v5 or ai-sdk/v6, and stored ai-sdk/v5 rows can convert to ai-sdk/v6. Other formats are returned as stored. A conversion that cannot parse a row skips that row rather than failing the whole list. When R2 is configured, attachment URLs in the content are replaced with signed reads.

Request
GET /v1/projects/threads/thread_0qzof3jPoDwr7K3agyJN3D4U/messages?format=ai-sdk%2Fv6&limit=200
curl
curl "https://backend.assistant-api.com/v1/projects/threads/thread_0qzof3jPoDwr7K3agyJN3D4U/messages?format=ai-sdk%2Fv6&limit=200" \
  -H "Authorization: Bearer $ASSISTANT_API_KEY" \
  -H "Aui-User-Id: user_123" \
  -H "Aui-Workspace-Id: workspace_123"
Response
{
  "messages": [
    {
      "id": "msg_000000000000000000000000",
      "parent_id": null,
      "created_at": "2026-09-17T02:40:31.000Z",
      "updated_at": "2026-09-17T02:40:31.000Z",
      "format": "ai-sdk/v6",
      "content": {
        "role": "user",
        "parts": [{ "type": "text", "text": "Where is order 1042?" }]
      },
      "height": 0
    }
  ]
}

The response contains raw message rows with the requested format and converted content, not ThreadMessageDTO objects.

StatusBodyWhen
200A messages array.The project wide message read completed.
400A schema validation error object.A parameter or query value failed validation.
401An authentication error object.The authorization header is missing, malformed or expired.
403{ "error": "Project-wide message listing requires API key authentication" }The request does not use an API key, or API key access failed.

This route is read only and has no side effects. Repeating it is idempotent. Format conversion and attachment signing affect the returned representation only; they do not rewrite stored messages.

List project scores

GET /v1/projects/scores
QueryTypeDefaultRules
namestring1 to 64 characters.
thread_idstring1 to 48 characters.
run_idstring1 to 48 characters.
sinceISO 8601 datetimeInclude scores from this time.
limitinteger501 to 200.
afterscore id1 to 48 characters. Resolves the score cursor.

There is no source query filter on this route. Scores are ordered by created_at DESC, id DESC. after resolves the referenced score and continues after its (created_at, id) position in that same order.

Request
GET /v1/projects/scores?name=quality&limit=50
curl
curl "https://backend.assistant-api.com/v1/projects/scores?name=quality&limit=50" \
  -H "Authorization: Bearer $ASSISTANT_API_KEY" \
  -H "Aui-User-Id: user_123" \
  -H "Aui-Workspace-Id: workspace_123"
Response
{
  "scores": [
    {
      "id": "score_000000000000000000000000",
      "thread_id": "thread_0qzof3jPoDwr7K3agyJN3D4U",
      "message_id": null,
      "run_id": null,
      "name": "quality",
      "data_type": "numeric",
      "value": 0,
      "string_value": null,
      "source": "api",
      "author_id": null,
      "comment": null,
      "created_at": "2026-09-17T00:00:00.000Z",
      "updated_at": "2026-09-17T00:00:00.000Z"
    }
  ]
}

Each score contains id, thread_id, message_id, run_id, name, data_type, value, string_value, source, author_id, comment, created_at and updated_at. value is returned as a number or null.

StatusBodyWhen
200A scores array.The score read completed. There is no next_cursor field.
400A schema validation error object.A query value failed validation.
401An authentication error object.The authorization header is missing, malformed or expired.
403{ "error": "Project-wide score listing requires API key authentication" }The request does not use an API key, or API key access failed.

This route is read only and has no side effects. Repeating it is idempotent. The after value is a score id cursor, and the response body never includes a cursor for the next page.