Files
sim/apps/docs/openapi-v2-logs.json
T
Waleed 366829b6b0 fix(v2): derive the log and run status enums from the persisted status list (#6612)
* fix(v2): derive the log and run status enums from the persisted status list

`GET /api/v2/logs` and `GET /api/v2/logs/{runId}` parse the raw
`workflow_execution_logs.status` column against a six-value enum that omits
`paused`, so a run holding that value returns 500. The list response is
validated whole-page, so one such row 500s every page it lands on, and the
row is durable until the run is resumed, cancelled, or failed.

`paused` is not written by an ordinary human-in-the-loop pause — that path
persists `pending` (logging-session.ts:1180). It is written by
`PauseResumeManager.markResumeAttemptFailed`, which fires on any
`ResumeAdmissionError`: a workspace over its usage limit, an archived or
undeployed workflow, or a concurrent resume losing the claim race. That is a
routine business path.

The enum was supposed to be protected by an `AssertNever` exhaustiveness gate,
but the gate was vacuous: it compared against `PersistedWorkflowExecutionStatus`,
a hand-written union that was itself missing `paused`, because the write goes
through a raw `sql` CASE fragment Drizzle cannot type-check. Adding `paused` to
both lists would leave the same vacuous gate in place for the next status.

Instead, `PERSISTED_WORKFLOW_EXECUTION_STATUSES` becomes the single runtime
source of truth, `PersistedWorkflowExecutionStatus` is derived from it, and both
v2 contracts derive their enums from the const rather than re-declaring them.
Both surfaces pass the column through verbatim, so their reported set is the
persisted set by definition — there is no editorial choice for a gate to force,
only the question of whether a newly persisted status should be public, which
the option-list tests now pin. The `[...V2_PERSISTED_RUN_STATUSES, 'paused']`
append on the runs contract is deleted rather than adjusted; it would otherwise
be a duplicate.

Alternatives rejected:
- A `.catch()` or `safeParse` in the presenters is dead code:
  `v2-json-route.ts:271` re-parses the whole body with the same schema.
- Normalizing `markResumeAttemptFailed` to write `pending` would remove the
  distinction the resume claim query at human-in-the-loop-manager.ts:973 relies
  on, and leaves the contract wrong for any other future status.
- Typing the Drizzle column does not help: the offending write is a raw `sql`
  fragment, and `packages/db` cannot import the app's status list.

The v2 workflows spec changes are reordering and description only — the value
set there already contained `paused`. The v2 logs spec gains `paused`, which is
additive and safe while the whole `/api/v2` surface is behind the off-by-default
`v2-api` flag; it must land before v2 GA, after which it would be breaking.

* fix(v2): document both provenances of a reported paused run status

* fix(v2): stop promising a paused discriminator the response cannot always provide

* fix(v2): describe the paused discriminator as the code actually records it
2026-08-12 01:51:55 -07:00

1349 lines
46 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"openapi": "3.1.0",
"info": {
"title": "Sim API v2 — Logs",
"description": "Version 2 of the Sim REST API for listing workflow execution logs and retrieving complete diagnostic run snapshots.",
"version": "2.0.0",
"contact": {
"name": "Sim Support",
"email": "help@sim.ai",
"url": "https://www.sim.ai"
},
"license": {
"name": "Apache 2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
}
},
"servers": [
{
"url": "https://www.sim.ai",
"description": "Production"
}
],
"tags": [
{
"name": "Logs",
"description": "Query workflow execution logs and retrieve complete run diagnostics."
}
],
"security": [
{
"apiKey": []
}
],
"paths": {
"/api/v2/logs": {
"get": {
"operationId": "listLogs",
"summary": "List Logs",
"description": "List workflow execution logs for a workspace with filters, selectable detail, and opaque cursor pagination. This list predates the shared sort convention: it has no `sortBy` (the sort column is fixed to execution start time) and spells the direction `order` rather than `sortOrder`. Trace spans are stored separately from the log row and are pruned on their own retention schedule: `includeTraceSpans=true` on a run whose stored spans have aged out returns `traceSpans: []` rather than an error, so an empty array does not mean the run recorded no spans.",
"tags": ["Logs"],
"parameters": [
{
"name": "workspaceId",
"in": "query",
"required": true,
"description": "Workspace whose execution logs should be returned.",
"schema": {
"type": "string",
"minLength": 1,
"description": "Workspace whose execution logs should be returned."
}
},
{
"name": "workflowIds",
"in": "query",
"required": false,
"description": "Comma-separated workflow identifiers to include.",
"schema": {
"type": "string",
"description": "Comma-separated workflow identifiers to include."
}
},
{
"name": "triggers",
"in": "query",
"required": false,
"description": "Comma-separated trigger types to include.",
"schema": {
"type": "string",
"description": "Comma-separated trigger types to include."
}
},
{
"name": "level",
"in": "query",
"required": false,
"description": "Severity level to include.",
"schema": {
"type": "string",
"enum": ["info", "error"],
"description": "Severity level to include."
}
},
{
"name": "startDate",
"in": "query",
"required": false,
"description": "Only include runs started at or after this ISO 8601 timestamp.",
"schema": {
"type": "string",
"description": "Only include runs started at or after this ISO 8601 timestamp."
}
},
{
"name": "endDate",
"in": "query",
"required": false,
"description": "Only include runs started at or before this ISO 8601 timestamp.",
"schema": {
"type": "string",
"description": "Only include runs started at or before this ISO 8601 timestamp."
}
},
{
"name": "minDurationMs",
"in": "query",
"required": false,
"description": "Minimum total execution duration in milliseconds.",
"schema": {
"type": "number",
"description": "Minimum total execution duration in milliseconds."
}
},
{
"name": "maxDurationMs",
"in": "query",
"required": false,
"description": "Maximum total execution duration in milliseconds.",
"schema": {
"type": "number",
"description": "Maximum total execution duration in milliseconds."
}
},
{
"name": "minCost",
"in": "query",
"required": false,
"description": "Minimum execution cost in USD.",
"schema": {
"type": "number",
"description": "Minimum execution cost in USD."
}
},
{
"name": "maxCost",
"in": "query",
"required": false,
"description": "Maximum execution cost in USD.",
"schema": {
"type": "number",
"description": "Maximum execution cost in USD."
}
},
{
"name": "model",
"in": "query",
"required": false,
"description": "AI model used during execution.",
"schema": {
"type": "string",
"description": "AI model used during execution."
}
},
{
"name": "details",
"in": "query",
"required": false,
"description": "Response detail level.",
"schema": {
"default": "basic",
"type": "string",
"enum": ["basic", "full"],
"description": "Response detail level."
}
},
{
"name": "includeTraceSpans",
"in": "query",
"required": false,
"description": "Whether to include block-level trace spans.",
"schema": {
"description": "Whether to include block-level trace spans.",
"type": "boolean"
}
},
{
"name": "includeFinalOutput",
"in": "query",
"required": false,
"description": "Whether to include the final workflow output.",
"schema": {
"description": "Whether to include the final workflow output.",
"type": "boolean"
}
},
{
"name": "limit",
"in": "query",
"required": false,
"description": "Maximum log entries per page, clamped to 11000.",
"schema": {
"description": "Maximum log entries per page, clamped to 11000.",
"default": 100,
"type": "number"
}
},
{
"name": "cursor",
"in": "query",
"required": false,
"description": "Opaque cursor returned by a previous page.",
"schema": {
"type": "string",
"description": "Opaque cursor returned by a previous page."
}
},
{
"name": "order",
"in": "query",
"required": false,
"description": "Sort order by execution start time.",
"schema": {
"default": "desc",
"type": "string",
"enum": ["desc", "asc"],
"description": "Sort order by execution start time."
}
},
{
"name": "runId",
"in": "query",
"required": false,
"description": "Exact run identifier to match.",
"schema": {
"type": "string",
"minLength": 1,
"description": "Exact run identifier to match."
}
},
{
"name": "folderPaths",
"in": "query",
"required": false,
"description": "Comma-separated workflow folder paths to include.",
"schema": {
"type": "string",
"description": "Comma-separated workflow folder paths to include."
}
}
],
"responses": {
"200": {
"description": "A page of execution logs matching the filters.",
"headers": {
"X-RateLimit-Limit": {
"$ref": "#/components/headers/X-RateLimit-Limit"
},
"X-RateLimit-Remaining": {
"$ref": "#/components/headers/X-RateLimit-Remaining"
},
"X-RateLimit-Reset": {
"$ref": "#/components/headers/X-RateLimit-Reset"
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2LogListResponse"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
},
"500": {
"$ref": "#/components/responses/InternalError"
},
"503": {
"$ref": "#/components/responses/ServiceUnavailable"
}
}
}
},
"/api/v2/logs/{runId}": {
"get": {
"operationId": "getLog",
"summary": "Get Log",
"description": "Retrieve the diagnostic representation of a run, including its workflow snapshot, trace spans, final output, and cost. The returned `workflowState` snapshot has credential values redacted: OAuth credential references and secret (`password`) sub-block values are null, while `{{VAR}}` environment-variable references are preserved so consecutive snapshots stay diffable. Trace spans are stored separately from the log row and are pruned on their own retention schedule: a run whose stored spans have aged out returns `traceSpans: []` rather than an error, so an empty array does not mean the run recorded no spans.",
"tags": ["Logs"],
"parameters": [
{
"name": "runId",
"in": "path",
"required": true,
"description": "The unique run identifier shared by lifecycle and diagnostic resources.",
"schema": {
"type": "string",
"minLength": 1,
"description": "The unique run identifier shared by lifecycle and diagnostic resources."
}
}
],
"responses": {
"200": {
"description": "The requested diagnostic log representation.",
"headers": {
"X-RateLimit-Limit": {
"$ref": "#/components/headers/X-RateLimit-Limit"
},
"X-RateLimit-Remaining": {
"$ref": "#/components/headers/X-RateLimit-Remaining"
},
"X-RateLimit-Reset": {
"$ref": "#/components/headers/X-RateLimit-Reset"
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2LogDetailResponse"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
},
"500": {
"$ref": "#/components/responses/InternalError"
},
"503": {
"$ref": "#/components/responses/ServiceUnavailable"
}
}
}
}
},
"components": {
"securitySchemes": {
"apiKey": {
"type": "apiKey",
"in": "header",
"name": "X-API-Key",
"description": "Your Sim API key, personal or workspace-scoped. Generate one from the Sim dashboard under Settings > API Keys. A workspace API key is not accepted everywhere: operations that act on behalf of a specific human — administrative reads, secret access, and irreversible or governance-affecting writes — always reject it, whatever role the key carries. Each such operation says so in its own description, and the rejection surfaces as `403` unless the operation conceals unauthorized resources, in which case it is reported as `404`. Use a personal API key for those."
}
},
"headers": {
"X-RateLimit-Limit": {
"description": "Maximum requests allowed in the current window.",
"schema": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"title": "Rate limit",
"description": "Maximum requests allowed in the current window."
}
},
"X-RateLimit-Remaining": {
"description": "Requests remaining in the current window.",
"schema": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"title": "Rate limit remaining",
"description": "Requests remaining in the current window."
}
},
"X-RateLimit-Reset": {
"description": "ISO 8601 timestamp when the current rate-limit window resets.",
"schema": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"title": "Rate limit reset",
"description": "ISO 8601 timestamp when the current rate-limit window resets."
}
},
"Retry-After": {
"description": "Seconds to wait before retrying a rate-limited request.",
"schema": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"title": "Retry after",
"description": "Seconds to wait before retrying a rate-limited request."
}
},
"X-Run-Id": {
"description": "Identifier assigned to the workflow run.",
"schema": {
"type": "string",
"minLength": 1,
"title": "Run identifier",
"description": "Identifier assigned to the workflow run."
}
}
},
"responses": {
"BadRequest": {
"description": "The request is invalid.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
},
"Unauthorized": {
"description": "The API key is missing or invalid.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
},
"UsageLimitExceeded": {
"description": "The workspace has exceeded its usage or billing limits.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
},
"Forbidden": {
"description": "The caller lacks access to the resource.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
},
"NotFound": {
"description": "The requested resource was not found.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
},
"Conflict": {
"description": "The request conflicts with current resource state.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
},
"RunIdConflict": {
"description": "The run cannot be started. Two causes share this status, distinguished by `error.details.code`: `RUN_ID_CONFLICT` when the supplied `X-Run-Id` is already associated with a different request, and `CALL_CHAIN_DEPTH_EXCEEDED` when the incoming `X-Sim-Via` chain has already reached the maximum workflow-to-workflow call depth.",
"headers": {
"X-Run-Id": {
"$ref": "#/components/headers/X-Run-Id"
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
},
"Gone": {
"description": "The requested generated resource has expired.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
},
"PayloadTooLarge": {
"description": "The request, or a resource collection it must materialize, exceeds the allowed size. Besides an oversized request body, this covers a generated artifact that renders past the download ceiling and a workspace folder tree too large to load in full.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
},
"UnsupportedMediaType": {
"description": "The request uses an unsupported media type.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
},
"Locked": {
"description": "The resource is locked and cannot be modified.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
},
"RateLimited": {
"description": "The caller exceeded the request rate limit.",
"headers": {
"Retry-After": {
"$ref": "#/components/headers/Retry-After"
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
},
"ClientClosedRequest": {
"description": "The client closed the connection before the response was produced.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
},
"InternalError": {
"description": "An unexpected server error occurred.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
},
"ServiceUnavailable": {
"description": "A required service is temporarily unavailable.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V2Error"
}
}
}
}
},
"schemas": {
"V2Error": {
"type": "object",
"properties": {
"error": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "Stable machine-readable error code."
},
"message": {
"type": "string",
"description": "Human-readable explanation of the error."
},
"details": {
"description": "Optional structured error details."
}
},
"required": ["code", "message"],
"additionalProperties": false,
"description": "Canonical error details."
}
},
"required": ["error"],
"additionalProperties": false,
"title": "v2 error response",
"description": "Canonical error envelope returned by the public v2 API.",
"examples": [
{
"error": {
"code": "BAD_REQUEST",
"message": "The request is invalid."
}
}
]
},
"V2LogListItem": {
"type": "object",
"properties": {
"runId": {
"type": "string",
"description": "Unique run identifier."
},
"workflowId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Workflow identifier, or null when unavailable."
},
"deploymentVersionId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Deployment version identifier, or null when unavailable."
},
"status": {
"type": "string",
"enum": [
"pending",
"running",
"paused",
"redacting",
"completed",
"failed",
"cancelled"
],
"description": "Current execution status. `redacting` is transient while run output is scrubbed. `paused` is reported when a resume attempt did not run to completion and the run is waiting to be resumed again."
},
"level": {
"type": "string",
"description": "Log severity level."
},
"trigger": {
"type": "string",
"description": "Trigger that started the run."
},
"startedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "ISO 8601 execution start timestamp."
},
"endedAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "ISO 8601 execution end timestamp, or null while the run is active."
},
"totalDurationMs": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "Total execution duration in milliseconds, or null while unavailable."
},
"cost": {
"anyOf": [
{
"type": "object",
"properties": {
"total": {
"type": "number",
"description": "Total execution cost in USD."
}
},
"required": ["total"],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Cost charged for the run, or null when unavailable."
},
"files": {
"anyOf": [
{
"type": "array",
"items": {
"description": "Attachment metadata captured for the execution."
}
},
{
"type": "null"
}
],
"description": "Files attached to the run, or null when none are recorded."
},
"workflow": {
"type": "object",
"properties": {
"id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Workflow identifier, or null when unavailable."
},
"name": {
"type": "string",
"description": "Workflow name."
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Workflow description, or null when unset."
},
"deleted": {
"type": "boolean",
"description": "Whether the workflow has been deleted."
}
},
"required": ["id", "name", "description", "deleted"],
"additionalProperties": false,
"description": "Workflow summary for a full-detail result."
},
"finalOutput": {
"description": "Final workflow output."
},
"traceSpans": {
"type": "array",
"items": {
"$ref": "#/components/schemas/LogTraceSpan"
},
"description": "Block-level execution trace spans."
}
},
"required": [
"runId",
"workflowId",
"deploymentVersionId",
"status",
"level",
"trigger",
"startedAt",
"endedAt",
"totalDurationMs",
"cost",
"files"
],
"additionalProperties": false,
"title": "Execution log summary",
"description": "Summary information for one workflow execution log."
},
"LogTraceSpan": {
"title": "Log trace span",
"description": "One recursive operation span in a workflow execution trace.",
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Trace-span identifier."
},
"name": {
"type": "string",
"description": "Trace-span name."
},
"type": {
"type": "string",
"description": "Trace-span category."
},
"duration": {
"type": "number",
"description": "Legacy span duration in milliseconds."
},
"durationMs": {
"type": "number",
"description": "Span duration in milliseconds."
},
"startTime": {
"type": "string",
"description": "ISO 8601 span start timestamp."
},
"endTime": {
"type": "string",
"description": "ISO 8601 span end timestamp."
},
"status": {
"type": "string",
"description": "Trace-span status."
},
"errorHandled": {
"type": "boolean",
"description": "Whether the recorded error was handled."
},
"errorType": {
"type": "string",
"description": "Recorded error type."
},
"errorMessage": {
"type": "string",
"description": "Recorded error message."
},
"blockId": {
"type": "string",
"description": "Workflow block associated with the span."
},
"input": {
"description": "Input captured for the traced operation."
},
"output": {
"description": "Output captured for the traced operation."
},
"tokens": {
"anyOf": [
{
"type": "number",
"description": "Total tokens attributed to the span."
},
{
"type": "object",
"properties": {
"total": {
"type": "number",
"description": "Total tokens."
},
"input": {
"type": "number",
"description": "Input tokens."
},
"output": {
"type": "number",
"description": "Output tokens."
}
},
"additionalProperties": false
}
],
"description": "Token usage attributed to the span."
},
"cost": {
"type": "object",
"properties": {
"total": {
"type": "number",
"description": "Total span cost in USD."
},
"input": {
"type": "number",
"description": "Input-token cost in USD."
},
"output": {
"type": "number",
"description": "Output-token cost in USD."
},
"toolCost": {
"type": "number",
"description": "Tool cost in USD."
}
},
"additionalProperties": false,
"description": "Cost attributed to the span."
},
"relativeStartMs": {
"type": "number",
"description": "Offset from the root span in milliseconds."
},
"toolCalls": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Tool-call identifier."
},
"name": {
"type": "string",
"description": "Invoked tool name."
},
"arguments": {
"description": "Arguments supplied to the tool call."
},
"result": {
"description": "Value returned by the tool call."
},
"error": {
"type": "string",
"description": "Tool-call error message."
},
"startTime": {
"type": "string",
"description": "ISO 8601 tool-call start timestamp."
},
"endTime": {
"type": "string",
"description": "ISO 8601 tool-call end timestamp."
},
"duration": {
"type": "number",
"description": "Tool-call duration in milliseconds."
}
},
"additionalProperties": {
"description": "Additional provider-specific tool-call metadata."
}
},
"description": "Tool calls recorded by the span."
},
"children": {
"type": "array",
"items": {
"$ref": "#/components/schemas/LogTraceSpan"
},
"description": "Nested child trace spans."
}
},
"required": ["id", "name", "type"],
"additionalProperties": {
"description": "Additional provider-specific trace-span metadata."
}
},
"V2LogListResponse": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/V2LogListItem"
},
"description": "Items in the current page."
},
"nextCursor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Opaque cursor for the next page: send it back as `cursor` to continue, and stop when it is null. Most v2 lists page, so null means the last page was reached. A few are full-set lists that return their whole bounded result in one response and therefore always report null; those say so in the operation description. Either way, null means there is nothing further to fetch — never construct a cursor yourself."
}
},
"required": ["data", "nextCursor"],
"additionalProperties": false,
"title": "Log list response",
"description": "A cursor-paginated page of workflow execution logs.",
"examples": [
{
"data": [
{
"runId": "e4f8d2b6-9a1c-4e3d-8b7f-5c0a2d9e6f13",
"workflowId": "3b1f7c92-8d4e-4a6b-9c0d-5e2f8a714b36",
"deploymentVersionId": "dep_2c4e6a8b0d1f",
"status": "completed",
"level": "info",
"trigger": "api",
"startedAt": "2026-01-15T10:30:00.000Z",
"endedAt": "2026-01-15T10:30:01.250Z",
"totalDurationMs": 1250,
"cost": {
"total": 0.0032
},
"files": null
}
],
"nextCursor": "eyJzdGFydGVkQXQiOiIyMDI2LTAxLTE1VDEwOjMwOjAwMFoifQ=="
}
]
},
"V2LogDetail": {
"type": "object",
"properties": {
"runId": {
"type": "string",
"description": "Unique run identifier."
},
"workflowId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Workflow identifier, or null when unavailable."
},
"deploymentVersionId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Deployment version identifier, or null when unavailable."
},
"status": {
"type": "string",
"enum": [
"pending",
"running",
"paused",
"redacting",
"completed",
"failed",
"cancelled"
],
"description": "Current execution status. `redacting` is transient while run output is scrubbed. `paused` is reported when a resume attempt did not run to completion and the run is waiting to be resumed again."
},
"level": {
"type": "string",
"description": "Log severity level."
},
"trigger": {
"type": "string",
"description": "Trigger that started the run."
},
"startedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "ISO 8601 execution start timestamp."
},
"endedAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "ISO 8601 execution end timestamp, or null while the run is active."
},
"totalDurationMs": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "Total execution duration in milliseconds, or null while unavailable."
},
"files": {
"anyOf": [
{
"type": "array",
"items": {
"description": "Attachment metadata captured for the execution."
}
},
{
"type": "null"
}
],
"description": "Files attached to the run, or null when none are recorded."
},
"workflow": {
"type": "object",
"properties": {
"id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Workflow identifier, or null when unavailable."
},
"name": {
"type": "string",
"description": "Workflow name."
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Workflow description, or null when unset."
},
"folderPath": {
"anyOf": [
{
"type": "string",
"description": "Canonical slash-prefixed folder path. `/` is the workspace root."
},
{
"type": "null"
}
],
"description": "Workflow folder path, or null when unavailable."
},
"ownerEmail": {
"anyOf": [
{
"type": "string",
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
},
{
"type": "null"
}
],
"description": "Workflow owner email, or null when unavailable."
},
"workspaceId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Owning workspace identifier, or null when unavailable."
},
"createdAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "ISO 8601 workflow creation timestamp, or null when unavailable."
},
"updatedAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "ISO 8601 workflow update timestamp, or null when unavailable."
},
"deleted": {
"type": "boolean",
"description": "Whether the workflow has been deleted."
}
},
"required": [
"id",
"name",
"description",
"folderPath",
"ownerEmail",
"workspaceId",
"createdAt",
"updatedAt",
"deleted"
],
"additionalProperties": false,
"description": "Workflow snapshot associated with the execution."
},
"workflowState": {
"anyOf": [
{
"type": "object",
"properties": {},
"additionalProperties": {
"description": "One top-level snapshot section — `blocks`, `edges`, `loops`, `parallels`, or `variables` — passed through as stored."
}
},
{
"type": "null"
}
],
"description": "Workflow graph snapshot captured for the run, with credential values redacted: `oauth-input`, `password: true`, and table sub-block values are null; sensitive nested tool parameters and every parameter without authoritative codec metadata are null; and `{{VAR}}` references in non-opaque fields are preserved. Null when no snapshot is retained."
},
"traceSpans": {
"type": "array",
"items": {
"$ref": "#/components/schemas/LogTraceSpan"
},
"description": "Materialized block-level execution trace spans."
},
"finalOutput": {
"anyOf": [
{
"description": "Materialized final workflow output value."
},
{
"type": "null"
}
],
"description": "Materialized final workflow output, or null when none was produced."
},
"cost": {
"anyOf": [
{
"type": "object",
"properties": {
"total": {
"type": "number",
"description": "Total execution cost in USD."
}
},
"required": ["total"],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Cost charged for the run, or null when unavailable."
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "ISO 8601 log creation timestamp."
}
},
"required": [
"runId",
"workflowId",
"deploymentVersionId",
"status",
"level",
"trigger",
"startedAt",
"endedAt",
"totalDurationMs",
"files",
"workflow",
"workflowState",
"traceSpans",
"finalOutput",
"cost",
"createdAt"
],
"additionalProperties": false,
"title": "Execution log detail",
"description": "Detailed workflow execution log including state, trace, output, and cost."
},
"V2LogDetailResponse": {
"type": "object",
"properties": {
"data": {
"description": "Response data.",
"$ref": "#/components/schemas/V2LogDetail"
}
},
"required": ["data"],
"additionalProperties": false,
"title": "Log detail response",
"description": "The complete diagnostic representation of a workflow run.",
"examples": [
{
"data": {
"runId": "e4f8d2b6-9a1c-4e3d-8b7f-5c0a2d9e6f13",
"workflowId": "3b1f7c92-8d4e-4a6b-9c0d-5e2f8a714b36",
"deploymentVersionId": "dep_2c4e6a8b0d1f",
"status": "completed",
"level": "info",
"trigger": "api",
"startedAt": "2026-01-15T10:30:00.000Z",
"endedAt": "2026-01-15T10:30:01.250Z",
"totalDurationMs": 1250,
"files": null,
"workflow": {
"id": "3b1f7c92-8d4e-4a6b-9c0d-5e2f8a714b36",
"name": "Customer Support Agent",
"description": "Routes incoming support tickets and drafts responses",
"folderPath": "/",
"ownerEmail": "jane@example.com",
"workspaceId": "a91c4b2e-6d3f-4e8a-b5c7-0d9e2f1a8c64",
"createdAt": "2025-01-10T09:00:00.000Z",
"updatedAt": "2025-06-18T16:45:00.000Z",
"deleted": false
},
"workflowState": {
"blocks": {},
"edges": []
},
"traceSpans": [],
"finalOutput": {
"result": "Hello, world!"
},
"cost": {
"total": 0.0032
},
"createdAt": "2026-01-15T10:30:00.000Z"
}
}
]
}
}
},
"x-generated-by": "scripts/generate-openapi.ts"
}