Traces API
Read your agents' execution traces programmatically.
On this page
The Traces API lets you read your agents' execution traces programmatically — list recent runs and fetch a single run in detail, including the model, latency, input/output, intermediate steps, and user reactions. Use it to debug agent behavior or to feed traces into your own analysis and improvement pipelines.
Authenticate with a bearer API key, created under Settings → API keys (where available). If your organization doesn't show that item, open Settings → Members, which opens your organization's account page, and manage keys in its API Keys section; see API keys. Full request/response schemas live in the OpenAPI reference; MCP clients can read the same data through the MCP server's list_recent_agent_traces and get_agent_trace tools.
Endpoints#
| Endpoint | Purpose |
|---|---|
GET /v1/agents/{agentId}/traces | List recent traces for an agent |
GET /v1/agents/{agentId}/traces/{traceId} | Read a single trace in detail |
GET /v1/agents/{agentId}/messages/{messageId}/trace | Resolve the trace behind a specific message |
GET /v1/agents/{agentId}/traces/export | Bulk-export whole traces over a long window |
Traces are retained for 90 days. They cover Classic, Anthropic and OpenAI Responses agents, and every channel the agent answers on, not only the API. An agent that uses HIPAA data handling is covered too, read from its separate protected tracing path.
Rate limits#
| Endpoints | Limit |
|---|---|
| The list endpoint and the message-trace endpoint, together | 30 requests per minute per organization |
| The export endpoint | 20 requests per minute per organization |
GET /v1/agents/{agentId}/traces/{traceId} | No limit |
The limits are counted on each API server separately, so the budget you observe can be higher than the number above. Every response from a limited endpoint carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds until the window resets), and a 429 includes Retry-After. Pace yourself by the headers rather than by a fixed count. See Errors and limits.
Listing traces#
GET /v1/agents/{agentId}/traces returns trace summaries, newest first, with meta holding page, limit, totalItems and totalPages.
| Query parameter | Meaning |
|---|---|
page | Page number, starting at 1 |
limit | Traces per page, up to 100. Defaults to 50 |
sessionId | Only traces from one conversation (the channel's thread id) |
fromTimestamp | ISO 8601 start of the window. Defaults to 90 days ago |
toTimestamp | ISO 8601 end of the window. Defaults to now |
A page can hold slightly fewer traces than limit. For large pulls, use the export endpoint instead.
Reading one trace#
GET /v1/agents/{agentId}/traces/{traceId} returns the trace in detail: the model, latency, input and output, each step with its tool calls, and user reactions. When the caller passed config.userContext for the turn, the trace includes it as userContext.
GET /v1/agents/{agentId}/messages/{messageId}/trace returns the same detail for a message, given the message id from GET /v1/threads/{threadId}/messages. It answers 404 when no trace can be found for the message: the trace is older than the 90-day retention, the message belongs to a different agent than the one in the path, or the message wasn't produced by an agent run. A messageId that isn't a UUID is refused with 400.
Exporting traces#
GET /v1/agents/{agentId}/traces/export returns whole traces, newest first, for loading into a warehouse or analytics pipeline.
- Set the window with
fromTimestampandtoTimestamp(ISO 8601;toTimestampis exclusive).fromTimestampdefaults to, and is clamped at, 90 days ago.toTimestampdefaults to now. - Follow
meta.cursor: pass it back ascursoruntil it isnull. Once you pass a cursor,toTimestampis ignored, so keep the window fixed for the whole export. - A page holds whole traces only, never part of one, so page sizes vary.
- A trace becomes exportable about 2 to 3 minutes after its turn ends. For a reproducible extract, set
toTimestampat least 15 minutes in the past. - Exported traces don't include
reactions,threadIdorsessionStartHook. Read a single trace for those.
Session-start hook outcome#
For organizations with the session-start hook feature enabled, the trace detail response includes a sessionStartHook field with the outcome of the hook for the trace's thread. The hook runs at most once per thread, so every trace in the same thread reports the same object; the field is null when the agent has no hook or the hook never ran for the thread.
{
"sessionStartHook": {
"fetchedAt": "2026-07-22T19:03:58.412Z",
"status": "ok",
"contexts": [
{ "name": "Session Context", "context": "tier: enterprise" }
]
}
}| Field | Meaning |
|---|---|
fetchedAt | ISO 8601 timestamp of when the hook was attempted |
status | ok — the hook completed successfully. degraded — the hook failed (timeout, error, or invalid response) and the session proceeded without injected context |
contexts | Context entries injected into the system prompt, one per result the hook returned |
Note that ok does not guarantee context was injected: a hook tool that returns no content is a successful no-op, reported as ok with an empty contexts array. When status is degraded, contexts is always empty.
Related#
- Credits API — group credit usage by
traceId - Chat — the threads and messages traces belong to
- Errors and limits