Querying Child Workflows
When a workflow uses forEach nodes, each iteration spawns a child workflow. The children API lets you discover, drill into, and retrieve the full execution tree β all without knowing Temporal internals.
This guide covers usage patterns and examples. For the canonical request/response schemas, see the Workflow API Reference.
Overview
When you call GET /workflows/{id}, the response now includes a children array: a lightweight manifest listing every direct child workflow with its status, iteration data, and an href link for drill-down.
For deeper nesting (a forEach inside a forEach), each child's response includes its own children manifest β same shape, all the way down.
Three endpoints cover every use case:
| Use case | Endpoint |
|---|---|
| "What happened? What children exist?" | GET /workflows/{id} |
| "Drill into Spanish (index 0)" | GET /workflows/{id}/forEach/{nodeId}/{index} |
| "Give me everything in one call" | GET /workflows/{id}/tree |
API endpoints
All endpoints are relative to https://api.graphcompose.io/api/v1.
| Endpoint | Method | Description |
|---|---|---|
/workflows/{id} | GET | Parent state + children[] manifest |
/workflows/{id}/forEach/{nodeId}/{index} | GET | Specific child by forEach node ID and index |
/workflows/{id}/tree | GET | Full recursive execution tree |
The first two endpoints return the exact same response shape (state, status, children[]). The tree endpoint has its own recursive shape. See the Workflow API Reference for complete request/response schemas.
Children manifest
The children array on the parent response is a manifest β lightweight metadata with links. It never includes child state inline.
curl https://api.graphcompose.io/api/v1/workflows/abc123 \
-H "Authorization: Bearer $GRAPH_COMPOSE_TOKEN"
Each manifest entry includes:
| Field | Description |
|---|---|
forEachNodeId | The forEach node that spawned this child |
index | Iteration index (0-based) |
status | Current status (RUNNING, COMPLETED, FAILED, etc.) |
data | The forEach item data for this iteration |
href | API link to fetch the child's full state |
childCount | Number of grandchildren (0 = leaf, no deeper nesting) |
View full ChildManifestEntry schema in API Reference β
children is an empty array [] for workflows without forEach nodes. The response shape is always the same.
Get a forEach child by index
Use the href from the manifest, or construct the path yourself using the forEach node ID and iteration index:
curl https://api.graphcompose.io/api/v1/workflows/abc123/forEach/dub_langs/0 \
-H "Authorization: Bearer $GRAPH_COMPOSE_TOKEN"
The response has the same shape as the parent endpoint β executionState, status, and children[].
View full response schema in API Reference β
Deep nesting
For nested forEach loops (forEach inside forEach), chain the path segments:
curl https://api.graphcompose.io/api/v1/workflows/abc123/forEach/dub_langs/0/forEach/dub_chunks/1 \
-H "Authorization: Bearer $GRAPH_COMPOSE_TOKEN"
The path pattern is /forEach/{nodeId}/{index} repeated for each level of nesting. The API constructs the internal Temporal workflow ID from the path β you never need to know compound IDs.
Full execution tree
For workflows with many children, use the tree endpoint to fetch everything in a single call:
curl https://api.graphcompose.io/api/v1/workflows/abc123/tree \
-H "Authorization: Bearer $GRAPH_COMPOSE_TOKEN"
The tree is keyed by forEach node ID at each level. Use ?maxDepth=N to limit recursion depth for large workflows.
View full WorkflowTree response schema in API Reference β
For a 2-language x 50-chunk workflow, the tree response contains 103 states (1 parent + 2 children + 100 grandchildren). Consider using maxDepth or the per-child endpoint for very large workflows.
Programmatic traversal
Use the href links in the children manifest to crawl the tree programmatically:
const parent = await fetch(`/api/v1/workflows/${id}`, {
headers: { Authorization: `Bearer ${token}` }
}).then(r => r.json())
const failedChild = parent.data.children.find(
(c: any) => c.status === 'FAILED'
)
if (failedChild) {
const child = await fetch(failedChild.href, {
headers: { Authorization: `Bearer ${token}` }
}).then(r => r.json())
console.log('Failed child state:', child.data.executionState)
// Check grandchildren too β same shape
const failedGrandchild = child.data.children.find(
(c: any) => c.status === 'FAILED'
)
}
Response shape consistency
A key design principle: the parent endpoint and the forEach child endpoint return the exact same response type. This means:
- The same TypeScript interface works for both
- Recursive traversal code doesn't need special cases per depth level
- The
childrenfield is always present (empty array[]for leaf nodes)
The tree endpoint (/tree) uses a different recursive shape since it includes all states inline, but it's a dedicated endpoint β no shape-shifting within a single URL.
The complete response schemas β including all fields, types, and examples β are defined in the Workflow API Reference. The API reference is auto-generated from the Zod schemas and is always the canonical source of truth.