Workflows
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)
Section titled “workflow.findNode(nodeId)”Available on response.workflow after calling client.workflows.retrieve().
Signature
response.workflow.findNode(nodeId: string): Flow | undefinedParameters
| 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)
Section titled “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()
Section titled “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(): voidParameters
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);}workflow.run(params)
Section titled “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 for the full .wait() reference.
Signature
response.workflow.run( params: WorkflowRunParams, options?: RequestOptions,): APIPromise<WithJob<WorkflowRunResponse>>Parameters
| Name | Type | Description |
|---|---|---|
params.body | object | Workflow input values (keys defined by the workflow’s inputs). |
Returns
APIPromise<WithJob<WorkflowRunResponse>> — 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
Section titled “run() — enhanced response”client.workflows.run() returns a response where response.job has .wait(). See Jobs 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
Section titled “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();validateWorkflowFlow(flow) — standalone utility
Section titled “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 are identical.
Signature
validateWorkflowFlow(flow: unknown[]): voidParameters
| 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
Section titled “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): WorkflowExportDataParameters
| 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', 'aspectRatio', 'model', 'llm', 'transformText', 'splitText', 'ifElse', 'groupItems', 'sliceAssets', 'forEach', 'forEachEnd', 'stickyNote', 'approval'. |
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
Section titled “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' | 'aspectRatio' | 'model' | 'llm' | 'transformText' | 'splitText' | 'ifElse' | 'groupItems' | 'sliceAssets' | 'forEach' | 'forEachEnd' | 'stickyNote' | 'approval';The runtime constant VALID_EDITOR_NODE_TYPES (also exported) contains the same values as a readonly array and is used internally by validateEditorInfo.
WorkflowImportError
Section titled “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; }}convertWorkflowEditorToFlow(params) — editor-to-API converter
Section titled “convertWorkflowEditorToFlow(params) — editor-to-API converter”Named export from @scenario-labs/sdk. Converts a workflow editor state (nodes, edges, input key order) into a flow array ready to be passed to client.workflows.update({ flow: ... }).
Signature
convertWorkflowEditorToFlow( params: ConvertWorkflowEditorToFlowParams,): WorkflowEditorFlowItem[]Parameters
| Name | Type | Description |
|---|---|---|
params.nodes | WorkflowEditorNode[] | Editor nodes. See WorkflowEditorNode. |
params.edges | WorkflowEditorEdge[] | Edge connections between nodes. |
params.inputKeys | string[] | Ordered list of input node IDs; determines sort order of workflow inputs. |
params.getModel? | (modelId: string) => WorkflowEditorModel | 'unknown' | undefined | Optional model resolver. Called with a node’s modelId; return the model object, 'unknown', or undefined. Used to resolve aspect-ratio presets and input-type hints. |
Returns
WorkflowEditorFlowItem[] — the compiled flow array, suitable for client.workflows.update().
Example
import Scenario, { convertWorkflowEditorToFlow } from '@scenario-labs/sdk';import type { WorkflowUpdateParams } from '@scenario-labs/sdk/resources/workflows';
const client = new Scenario({ apiKey: '...' });
const flow = convertWorkflowEditorToFlow({ nodes, edges, inputKeys, getModel });
// `convertWorkflowEditorToFlow` returns `WorkflowEditorFlowItem[]`, whose `type`// is a plain `string`. `update()` expects the API's `Flow` type, whose `type` is// a narrower string-literal union — so cast to it when passing the compiled flow.await client.workflows.update('wflow_...', { flow: flow as WorkflowUpdateParams.Flow[] });WorkflowEditorNode
Section titled “WorkflowEditorNode”Union type for workflow editor nodes. Each member has id, type, and a data object specific to that type.
type WorkflowEditorNode = | { id: string; type: 'model'; data: NodeCommonData & { modelId?: string; type?: string; form?: Record<string, unknown> } } | { id: string; type: 'llm'; data: NodeCommonData & { modelId?: string; form?: Record<string, unknown> } } | { id: string; type: 'text'; data: NodeCommonData & { value?: string } } | { id: string; type: 'asset'; data: NodeCommonData & { type?: string; value?: string | string[]; isMultiple?: boolean; isRequired?: boolean; valueFirstFrame?: string; valueLastFrame?: string } } | { id: string; type: 'transformText'; data: NodeCommonData & { value?: string } } | { id: string; type: 'splitText'; data: NodeCommonData & { splitDelimiter?: string } } | { id: string; type: 'aspectRatio'; data: NodeCommonData & { output?: string; quality?: string } } | { id: string; type: 'groupItems'; data: NodeCommonData & { value?: string } } | { id: string; type: 'sliceAssets'; data: NodeCommonData & { from?: number | string; count?: number | string } } | { id: string; type: 'forEach'; data: NodeCommonData } | { id: string; type: 'forEachEnd'; data: NodeCommonData & { parentNodeId?: string } } | { id: string; type: 'ifElse'; data: NodeCommonData & { conditionBlocks?: WorkflowEditorConditionBlock[] } } | { id: string; type: 'approval'; data: NodeCommonData & { message?: string } };where NodeCommonData is:
type NodeCommonData = { isInput?: boolean; isOutput?: boolean; inputHandles?: WorkflowEditorHandleInput[]; outputHandles?: WorkflowEditorHandleOutput[];};WorkflowEditorEdge
Section titled “WorkflowEditorEdge”type WorkflowEditorEdge = { source: string; target: string; sourceHandle?: string | null; targetHandle?: string | null; data?: { isForEachEndEdge?: boolean } | undefined;};WorkflowEditorFlowItem
Section titled “WorkflowEditorFlowItem”Shape of a single item in the compiled flow array returned by convertWorkflowEditorToFlow. This is the format accepted by client.workflows.update().
type WorkflowEditorFlowItem = { id: string; type: string; modelId?: string | undefined; inputs?: WorkflowEditorFlowInput[] | undefined; logic?: { transform?: string | undefined; cases?: { condition: string; value: string }[] | undefined; default?: string | undefined; } | undefined; logicType?: 'if-else' | undefined; loopBodyNodeIds?: string[] | undefined; includeOutputsInWorkflowJob?: true | undefined; dependsOn?: string[] | undefined; label?: string | undefined;};WorkflowEditorModel
Section titled “WorkflowEditorModel”Model definition used by the optional getModel resolver in convertWorkflowEditorToFlow. Provides input-type and aspect-ratio resolution hints; return 'unknown' when the model exists but its definition isn’t available.
type WorkflowEditorModel = { id?: string; inputs?: WorkflowEditorModelInput[]; tags?: string[]; uiConfig?: { resolutionComponent?: { widthInput?: string; heightInput?: string; presets?: WorkflowEditorResolutionPreset[]; }; };};
type WorkflowEditorModelInput = { name: string; type: string; inputs?: Array<{ name: string; type: string }>; min?: number; max?: number; step?: number; allowedValues?: string[];};
type WorkflowEditorResolutionPreset = { width?: number; height?: number;};WorkflowEditorConditionBlock
Section titled “WorkflowEditorConditionBlock”Used in ifElse node data. Describes one branch of an if-else condition.
type WorkflowEditorConditionBlock = { conditions: WorkflowEditorCondition[]; logic: 'and' | 'or';};
type WorkflowEditorCondition = { field: string | undefined; operator: string; value?: string | string[];};WorkflowEditorHandleInput / WorkflowEditorHandleOutput
Section titled “WorkflowEditorHandleInput / WorkflowEditorHandleOutput”Handle descriptors attached to node data.inputHandles and data.outputHandles.
type WorkflowEditorHandleInput = { id: string; label?: string; name?: string; type?: string | string[]; subHandles?: WorkflowEditorHandleInput[];};
type WorkflowEditorHandleOutput = { id: string; name?: string; type?: string; isArray?: boolean;};WorkflowEditorFlowInput / WorkflowEditorFlowInputRef
Section titled “WorkflowEditorFlowInput / WorkflowEditorFlowInputRef”Input descriptor inside a WorkflowEditorFlowItem.
type WorkflowEditorFlowInput = { name: string; type: string; ref?: WorkflowEditorFlowInputRef | undefined; value?: string | number | string[] | boolean | undefined; items?: WorkflowEditorFlowInput[][] | undefined;};
type WorkflowEditorFlowInputRef = { equal?: string | undefined; node?: string | undefined; conditional?: string[] | undefined; name?: string | undefined;};normalizeAspectRatio(aspectRatio)
Section titled “normalizeAspectRatio(aspectRatio)”Normalizes an aspect ratio string to the canonical form used by the SDK (reduces by GCD, then maps aliases: '3:7' → '9:21', '7:3' → '21:9').
Signature
normalizeAspectRatio(aspectRatio: string | undefined): string | undefinedReturns the normalized ratio string, or undefined if the input is missing or contains non-positive / non-integer components.
getAspectRatioModelInputNames(model)
Section titled “getAspectRatioModelInputNames(model)”Extracts the width, height, and aspect-ratio input names from a model’s uiConfig or inputs array.
Signature
getAspectRatioModelInputNames( model: WorkflowEditorModel | undefined,): AspectRatioModelInputNamesReturns AspectRatioModelInputNames — { widthInputName?, heightInputName?, aspectRatioInputName? }.
getAspectRatioBounds(model, inputNames)
Section titled “getAspectRatioBounds(model, inputNames)”Returns the min/max width and height bounds for a model, derived from its inputs min/max and uiConfig.resolutionComponent.presets. Falls back to reasonable defaults when those fields are absent.
Signature
getAspectRatioBounds( model: WorkflowEditorModel | undefined, inputNames: Pick<AspectRatioModelInputNames, 'widthInputName' | 'heightInputName'>,): AspectRatioBounds | undefinedReturns AspectRatioBounds | undefined — undefined if model, widthInputName, or heightInputName is absent.
getDimensionsFromAspectRatio(args)
Section titled “getDimensionsFromAspectRatio(args)”Computes pixel dimensions for a given aspect ratio and model bounds. Snaps to the model’s multipleOf step and clamps to min/max.
Signature
getDimensionsFromAspectRatio(args: { aspectRatio: string; bounds: AspectRatioBounds;}): { width: number; height: number } | undefinedReturns { width, height }, or undefined if the aspect ratio string is invalid.
ASPECT_RATIO_PRESETS
Section titled “ASPECT_RATIO_PRESETS”Readonly array of the supported aspect ratio strings, from widest to tallest.
const ASPECT_RATIO_PRESETS = [ '21:9', '16:9', '3:2', '4:3', '5:4', '1:1', '4:5', '3:4', '2:3', '9:16', '9:21',] as const;AspectRatioBounds
Section titled “AspectRatioBounds”type AspectRatioBounds = { minWidth: number; maxWidth: number; minHeight: number; maxHeight: number; multipleOf: number;};AspectRatioModelInputNames
Section titled “AspectRatioModelInputNames”type AspectRatioModelInputNames = { widthInputName?: string | undefined; heightInputName?: string | undefined; aspectRatioInputName?: string | undefined;};