--- title: Workflows | Scenario Docs description: API reference for enhanced workflow methods. --- The `workflows` resource is enhanced with helper methods on response objects. All original methods (`retrieve`, `create`, `update`, `list`, `delete`, `run`, `userApproval`, `getTags`) are inherited. --- ## `workflow.findNode(nodeId)` Available on `response.workflow` after calling `client.workflows.retrieve()`. **Signature** ``` response.workflow.findNode(nodeId: string): Flow | undefined ``` **Parameters** | Name | Type | Description | | -------- | -------- | --------------------------- | | `nodeId` | `string` | The ID of the node to find. | **Returns** `Flow | undefined` — The node definition, or `undefined` if not found. | Property | Type | Description | | ------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | `string` | Node identifier. | | `type` | `string` | Node type: `'custom-model'`, `'for-each'`, `'generate-prompt'`, `'list'`, `'logic'`, `'model'`, `'remove-background'`, `'transform'`, `'user-approval'`, `'workflow'`. | | `modelId?` | `string` | Model ID (for `custom-model` nodes). | | `workflowId?` | `string` | Sub-workflow ID (for `workflow` nodes). | | `inputs?` | `Input[]` | Node input configuration. | | `dependsOn?` | `string[]` | IDs of nodes this node depends on. | | `logic?` | `Logic` | Logic configuration (for `logic` nodes). | **Example** ``` const response = await client.workflows.retrieve('wflow_...'); const node = response.workflow.findNode('final_image'); if (node) { console.log(node.type); // 'custom-model' console.log(node.modelId); // 'model_...' } ``` --- ## `workflow.getNodesByType(type)` Available on `response.workflow` after calling `client.workflows.retrieve()`. **Signature** ``` response.workflow.getNodesByType(type: NodeType): Flow[] ``` **Parameters** | Name | Type | Description | | ------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `type` | `NodeType` | One of: `'custom-model'`, `'for-each'`, `'generate-prompt'`, `'list'`, `'logic'`, `'model'`, `'remove-background'`, `'transform'`, `'user-approval'`, `'workflow'`. | **Returns** `Flow[]` — Array of matching node definitions. Empty array if none match. **Example** ``` const response = await client.workflows.retrieve('wflow_...'); const modelNodes = response.workflow.getNodesByType('custom-model'); modelNodes.forEach((node) => { console.log(`${node.id}: model=${node.modelId}`); }); ``` --- ## `workflow.validate()` Available on `response.workflow` after calling `client.workflows.retrieve()`. Validates the structural integrity of the workflow’s `flow` definition. Throws an `Error` with a human-readable message on the first violation found. **Signature** ``` response.workflow.validate(): void ``` **Parameters** None. **Returns** `void` — returns nothing on success. **Errors** Throws `Error` on the first violation. Checks performed: | # | Check | | - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 1 | Every node has a non-empty string `id`. | | 2 | Node IDs are unique within the flow. | | 3 | Every node `type` is one of: `'custom-model'`, `'for-each'`, `'generate-prompt'`, `'list'`, `'logic'`, `'model'`, `'remove-background'`, `'transform'`, `'user-approval'`, `'workflow'`. | | 4 | Per-type required fields: `custom-model` → `modelId`, `workflow` → `workflowId`, `logic` → `logicType`, `for-each` → non-empty `loopBodyNodeIds` or positive `count`. | | 5 | All cross-references point to existing node IDs: `dependsOn`, input `ref.node`, input `ref.conditional`, and `loopBodyNodeIds`. | **Example** ``` const response = await client.workflows.retrieve('wflow_...'); try { response.workflow.validate(); console.log('Workflow is valid'); } catch (err) { // e.g. 'Node "final_image" (custom-model) is missing required field "modelId"' console.error((err as Error).message); } ``` Note The string `"workflow"` is reserved inside an input `ref.node` — it means “take the value from the parent workflow’s inputs” and is not checked against node IDs. --- ## `workflow.run(params)` Available on `response.workflow` after calling `client.workflows.retrieve()`. Runs this workflow. Shortcut for `client.workflows.run(workflow.id, params)` — no need to repeat the workflow ID. Returns an enhanced response where `response.job` has `.wait()`. See [Jobs](/sdk-helpers/jobs/index.md) for the full `.wait()` reference. **Signature** ``` response.workflow.run( params: WorkflowRunParams, options?: RequestOptions, ): APIPromise> ``` **Parameters** | Name | Type | Description | | ------------- | -------- | -------------------------------------------------------------- | | `params.body` | `object` | Workflow input values (keys defined by the workflow’s inputs). | **Returns** `APIPromise>` — a run response where `response.job` has `.wait()`. **Example** ``` const { workflow } = await client.workflows.retrieve('wflow_...'); const response = await workflow.run({ body: { prompt: 'a medieval landscape' }, }); const completed = await response.job.wait(); console.log(completed.status); // 'success' console.log(completed.metadata?.assetIds); ``` --- ## `run()` — enhanced response `client.workflows.run()` returns a response where `response.job` has `.wait()`. See [Jobs](/sdk-helpers/jobs/index.md) for the full `.wait()` reference. **Example** ``` const response = await client.workflows.run('wflow_...', { body: { prompt: 'a sleek platinum bob with bangs', image: 'asset_...', }, }); // response.job has all original fields + .wait() const completed = await response.job.wait(); // Access completed job metadata (flow with runtime status + assets) completed.metadata?.flow?.forEach((node) => { console.log(`${node.id} [${node.status}]`); node.assets?.forEach((asset) => { console.log(` ${asset.assetId} -> ${asset.url}`); }); }); ``` --- ## `userApproval()` — enhanced response `client.workflows.userApproval()` also returns a response where `response.job` has `.wait()`. ``` const response = await client.workflows.userApproval('wflow_...', { nodeId: 'approval_node', status: 'approved', }); const completed = await response.job.wait(); ``` Tip `response.workflow` from `retrieve()` keeps all original fields (`name`, `status`, `flow`, `inputs`, etc.). The helper methods are added on top. --- ## `validateWorkflowFlow(flow)` — standalone utility Named export from `@scenario-labs/sdk`. Use it to validate a raw flow array (e.g. one you’ve built locally or loaded from JSON) without going through `retrieve()`. This is the same function `workflow.validate()` calls internally, so the [checks and error messages](#workflowvalidate) are identical. **Signature** ``` validateWorkflowFlow(flow: unknown[]): void ``` **Parameters** | Name | Type | Description | | ------ | ----------- | ---------------------------------------------------------- | | `flow` | `unknown[]` | The workflow flow (array of node definitions) to validate. | **Returns** `void` — returns nothing on success. Throws `Error` on the first violation. **Example** ``` import { validateWorkflowFlow } from '@scenario-labs/sdk'; const flow = [ { id: 'start', type: 'generate-prompt', inputs: [] }, { id: 'final_image', type: 'custom-model', modelId: 'model_...', dependsOn: ['start'] }, ]; try { validateWorkflowFlow(flow); } catch (err) { console.error((err as Error).message); } ``` --- ## `validateEditorInfo(data)` — import validator Named export from `@scenario-labs/sdk`. Validates a workflow export payload (e.g. from a JSON file import). Throws a `WorkflowImportError` with a human-readable message on the first violation found. Returns the validated data typed as `WorkflowExportData`. **Signature** ``` validateEditorInfo(data: unknown): WorkflowExportData ``` **Parameters** | Name | Type | Description | | ------ | --------- | ------------------------------------ | | `data` | `unknown` | The parsed JSON payload to validate. | **Returns** `WorkflowExportData` — the validated export payload. | Property | Type | Description | | ---------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `version` | `'1.0'` | Payload version; only `'1.0'` is accepted. | | `name` | `string` | Workflow name. | | `description` | `string` | Workflow description. | | `editorInfo.nodes` | `Array<{ type: WorkflowEditorNodeType; ... }>` | Editor nodes. Valid `type` values: `'text'`, `'asset'`, `'model'`, `'llm'`, `'transformText'`, `'splitText'`, `'ifElse'`, `'groupItems'`, `'sliceAssets'`, `'forEach'`, `'forEachEnd'`, `'stickyNote'`. | | `editorInfo.edges` | `object[]` | Edge connections between nodes. | | `editorInfo.inputKeys` | `string[]` | Input key names. | | `inputs` | `unknown[]` | Input definitions. | | `tagSet` | `string[]` | Tags associated with the workflow. | | `uiConfig?` | `object` | Optional UI configuration. | | `exportedAt` | `string` | ISO 8601 export timestamp. | | `exportedBy` | `string` | Identifier of the exporting entity. | **Errors** Throws `WorkflowImportError` on the first violation. Checks performed: | # | Check | | - | ---------------------------------------------------------- | | 1 | `data` is a non-null object. | | 2 | `version` is present and equals `'1.0'`. | | 3 | `editorInfo` has non-empty `nodes` and `edges` arrays. | | 4 | Each node `type` is a recognized `WorkflowEditorNodeType`. | | 5 | `inputs` is an array. | **Example** ``` import { validateEditorInfo, WorkflowImportError } from '@scenario-labs/sdk'; import fs from 'node:fs'; const raw = JSON.parse(fs.readFileSync('my-workflow-export.json', 'utf8')); try { const data = validateEditorInfo(raw); console.log(data.name); // 'My workflow' console.log(data.version); // '1.0' } catch (err) { if (err instanceof WorkflowImportError) { // e.g. 'Unsupported version: 2.0' console.error(err.message); } } ``` --- ## `WorkflowEditorNodeType` String-literal union of valid editor node type values. Used by `validateEditorInfo()` to check each node’s `type` in `editorInfo.nodes`. ``` type WorkflowEditorNodeType = | 'text' | 'asset' | 'model' | 'llm' | 'transformText' | 'splitText' | 'ifElse' | 'groupItems' | 'sliceAssets' | 'forEach' | 'forEachEnd' | 'stickyNote'; ``` The runtime constant `VALID_EDITOR_NODE_TYPES` (also exported) contains the same values as a readonly array and is used internally by `validateEditorInfo`. --- ## `WorkflowImportError` Error subclass thrown by `validateEditorInfo()` when validation fails. Extends the standard `Error`; its `name` property is always `'WorkflowImportError'`, which lets you distinguish import validation errors from other runtime errors. **Example** ``` import { WorkflowImportError, validateEditorInfo } from '@scenario-labs/sdk'; try { validateEditorInfo(raw); } catch (err) { if (err instanceof WorkflowImportError) { console.error('Import validation failed:', err.message); } else { throw err; } } ```