Skip to main content

Traces

GET /v1/traces returns a record of the requests your organization has made through the API — model, timing, token counts, and whether the request succeeded. GET /v1/traces/{trace_id} returns one of those records in full, with its span waterfall and payloads.

This is health and debugging data, not billing. Token counts appear as request metadata; spend lives in your billing dashboard.

Traces are available where your organization has them enabled. Everywhere else both endpoints answer 404.

Endpoint

GET https://api.mindshub.ai/v1/traces

import os

import httpx

headers = {"Authorization": f"Bearer {os.environ['MINDSHUB_API_KEY']}"}
page = httpx.get(
"https://api.mindshub.ai/v1/traces",
params={"page": 1, "limit": 25, "model": "sonnet"},
headers=headers,
).json()
for trace in page["traces"]:
print(trace["id"], trace["model"])

The generated reference pages are GET /v1/traces and GET /v1/traces/{trace_id}.

Who sees what

Every response is scoped to your organization. Within it, what you see depends on your role:

  • Members see their own requests.
  • Organization administrators see the whole organization's requests, and can narrow to one person with user_id.

Request and response content is always your own, for every role. An administrator can see that a colleague made a request, with its model, timing and outcome, but opening it returns 404. There is no setting that changes this today.

Request parameters

All optional.

ParameterMeaning
page, limit1-based page number and page size. limit defaults to 25, maximum 100.
from, toISO-8601 instants bounding the request time. A value without an offset is read as UTC.
hoursLegacy relative window. Combines with from/to when both are given; prefer the absolute pair.
session_idOnly requests belonging to this session.
model, exclude_modelModel aliases. Repeatable.
provider, exclude_providerUpstream providers. Repeatable.
level, exclude_levelDEFAULT (succeeded), ERROR (failed), UNKNOWN (no outcome recorded). Repeatable, OR-ed.
streamtrue for streamed requests, false for non-streamed.
include_probestrue to include connectivity health-check requests, which are hidden by default.
sort, ordertimestamp or latency_ms, asc or desc. Defaults to newest first.
user_idAdministrators only: narrow to one person. Ignored for members.

Every filter runs server-side over your whole history, not over one page. The exclusions are null-permissive: excluding a model never hides requests whose model was not recorded.

Response

{
"traces": [
{
"id": "3f1c8a90d4e24b7f9a6c5e2d",
"name": "cowork:turn-3",
"timestamp": "2026-09-16T09:41:22.118Z",
"user_id": "0f2b5c71-9e3a-4d18-bb44-7c6a1d2e5f30",
"session_id": "b7d1e4a2-5c88-4f30-9a61-2e7c4b9d8f15",
"model": "sonnet",
"provider": "anthropic",
"input_tokens": 1840,
"output_tokens": 302,
"cached_input_tokens": 1536,
"latency_ms": 4120,
"stream": true,
"level": "DEFAULT",
"http_status": 200,
"error_class": null,
"span_count": 0,
"kind": null,
"preview": null,
"tags": []
}
],
"page": 1,
"limit": 25,
"total": 412,
"total_capped": false,
"has_more": true,
"langfuse_available": true
}
FieldMeaning
idThe trace id. Pass it to GET /v1/traces/{trace_id}. A request recorded while tracing was off carries an internal id instead. That id opens only for a stored Responses turn, whose payload we hold ourselves, and only while the turn is live; every other untraced request returns 404.
nameWhat the request was, when we can say: the calling client and turn (cowork:turn-3), otherwise the operation (chat.completion, response, embedding).
timestampWhen the request started.
model, providerThe alias you called, and the upstream that served it.
input_tokens, output_tokens, cached_input_tokensToken counts. cached_input_tokens are the discounted prompt-cache reads; they are not included in input_tokens.
latency_msEnd to end, in milliseconds. For a streamed request this is time to the last token and includes your own read time. stream tells the two apart, so compare like with like.
levelDEFAULT succeeded, ERROR failed, null when no outcome was recorded.
http_status, error_classThe status we returned and the failure category, when recorded.
session_idGroups a multi-turn conversation. null for a request that carried no session header, which is most direct API traffic.
kindprobe for a connectivity health check, otherwise null.
span_countAlways 0 on the list. The real count comes with the detail.
preview, tagsReserved. Always null and [] today.
totalMatching requests, or null when it could not be counted cheaply — see below.
total_cappedtrue when counting stopped at the cap, so total is null rather than approximate.
has_moreWhether another page is reachable. Page on this, not on total.
langfuse_availableWhether the tracing backend is configured in this environment. The list never depends on it, and a stored Responses turn still opens when it is false — from our own payload, so without its span waterfall.

Counts and paging

total is exact or null, never an estimate. It is null in two cases: when more than 10,000 requests match, and when the query filters on anything other than time, because counting those cannot be done cheaply. has_more is always correct, so page on that.

Paging stops at an offset of 10,000. Beyond it the endpoint returns 400; narrow with from/to or user_id instead of paging deeper.

Getting one trace

GET https://api.mindshub.ai/v1/traces/{trace_id}

import os

import httpx

headers = {"Authorization": f"Bearer {os.environ['MINDSHUB_API_KEY']}"}
trace = httpx.get("https://api.mindshub.ai/v1/traces/tr_1a2b3c", headers=headers).json()
print(trace["level"], len(trace["spans"]))

The response is a list row plus input, output, metadata, and spans — the nested operations the request ran, each with its own timing, model, level and payloads, ordered by start time.

Lane-specific behaviour

Health checks are hidden. Some MindsHub clients send a small connectivity probe on the normal completion path to verify your key. Those are excluded from the list by default so it reflects real activity. Pass include_probes=true to see them; they drop out of the counts while hidden.

Detail can lag the list. Trace ingestion is asynchronous, so a request that appears in the list immediately may not be retrievable by id for a few seconds.

Detail can expire before the list does. The list is served from our own records and keeps its history. The span waterfall is held by the tracing backend under whatever retention it is configured with, and a stored Responses turn's payload is held by us for 30 days. Neither is tied to how long the list keeps a request, so an old request can list correctly and still return 404 when opened.

Errors you can hit

StatusWhen
400Paging past the offset limit. Narrow the window instead.
401Missing or invalid key.
404Traces are not enabled for your organization; or the trace does not exist; or it is not yours to see. All three answer 404 rather than 403, so a disabled surface is invisible rather than visibly gated. The last two are indistinguishable by design, down to the response body: we never confirm that someone else's trace exists.
503The trace is yours, but the detail backend is temporarily unavailable. The list keeps working. Retry the drill-down.

See Errors for the response shape.