Skip to content
Get started

Workflows and Apps

Workflows are programmable pipelines that allow you to chain multiple AI models and tools together to automate complex creative tasks. A workflow can accept inputs, process them through multiple nodes (models/tools), and produce outputs.

Apps are workflows that can be discovered and used by anyone through the API. They provide pre-built creative pipelines that you can integrate into your applications.


  • Workflow: A pipeline definition containing nodes, inputs, and execution logic
  • Node: A step in the workflow (e.g., a model inference, transformation, or logic operation)
  • Inputs: Parameters that must be provided when running the workflow
  • Flow: The graph of nodes that defines the workflow execution order
  • Privacy: Controls who can access the workflow (public, private)
  • Status: Lifecycle state (draft, ready, deleted)
PrivacyDescription
publicDiscoverable by anyone, can be run by anyone (Apps)
privateOnly accessible by the owning project
StatusDescription
draftWork in progress, cannot be executed
readyComplete and executable
deletedSoft-deleted (not returned by API)

Retrieve a list of workflows. By default, returns private workflows for authenticated users.

Endpoint:

GET /v1/workflows

Query Parameters:

ParameterTypeRequiredDefaultDescription
projectIdstringYes*-Your project ID (*optional for public workflows)
privacystringNoprivateFilter by privacy: public, private
statusstringNo-Filter by status: draft, ready
tagsstringNo-Comma-separated list of tags to filter by
pageSizeintegerNo50Number of results per page (1-100)
paginationTokenstringNo-Token for fetching the next page

Example Request:

import Scenario from '@scenario-labs/sdk';
const client = new Scenario({
apiKey: 'YOUR_API_KEY',
apiSecret: 'YOUR_API_SECRET',
});
// List your private workflows
const privateWorkflows = await client.workflows.list({
projectId: 'proj_abc123',
privacy: 'private',
});
// List public workflows (Apps)
const apps = await client.workflows.list({ privacy: 'public' });
// Filter by tags
const filtered = await client.workflows.list({
projectId: 'proj_abc123',
tags: 'upscale,image-enhancement',
});
from scenario_sdk import Scenario
client = Scenario(
api_key="YOUR_API_KEY",
api_secret="YOUR_API_SECRET",
)
# List your private workflows
private_workflows = client.workflows.list(
project_id="proj_abc123",
privacy="private",
)
# List public workflows (Apps)
apps = client.workflows.list(privacy="public")
# Filter by tags
filtered = client.workflows.list(
project_id="proj_abc123",
tags="upscale,image-enhancement",
)
Terminal window
# List your private workflows
curl -X GET "https://api.cloud.scenario.com/v1/workflows?projectId=proj_abc123&privacy=private" \
-H "Authorization: Basic <base64(YOUR_API_KEY:YOUR_API_SECRET)>"
# List public workflows (Apps)
curl -X GET "https://api.cloud.scenario.com/v1/workflows?privacy=public" \
-H "Authorization: Basic <base64(YOUR_API_KEY:YOUR_API_SECRET)>"
# Filter by tags
curl -X GET "https://api.cloud.scenario.com/v1/workflows?projectId=proj_abc123&tags=upscale,image-enhancement" \
-H "Authorization: Basic <base64(YOUR_API_KEY:YOUR_API_SECRET)>"

Response:

{
"workflows": [
{
"id": "workflow_abc123",
"name": "Image Upscaler",
"description": "Upscale images to 4K resolution with AI enhancement",
"shortDescription": "AI-powered 4K image upscaling",
"status": "ready",
"privacy": "public",
"ownerId": "proj_xyz789",
"authorId": "user_123",
"createdAt": "2026-01-15T10:30:00Z",
"updatedAt": "2026-02-01T14:22:00Z",
"tagSet": ["upscale", "image-enhancement", "tool"],
"inputs": [
{
"name": "image",
"type": "file",
"kind": "image",
"description": "The image to upscale",
"required": { "always": true }
}
],
"thumbnail": {
"assetId": "asset_thumb123",
"url": "https://cdn.scenario.com/..."
},
"before": {
"assetId": "asset_before123",
"url": "https://cdn.scenario.com/..."
},
"after": {
"assetId": "asset_after123",
"url": "https://cdn.scenario.com/..."
},
"outputAssetKinds": ["image"],
"isLocked": false,
"flow": [...],
"editorInfo": {...}
}
],
"nextPaginationToken": "eyJsYXN0S2V5IjoiLi4uIn0="
}

Retrieve details of a specific workflow.

Endpoint:

GET /v1/workflows/{workflowId}

Path Parameters:

ParameterTypeRequiredDescription
workflowIdstringYesThe workflow ID

Query Parameters:

ParameterTypeRequiredDescription
projectIdstringNo*Your project ID (*required for private workflows)

Example Request:

const response = await client.workflows.retrieve('workflow_abc123');
console.log(response.workflow);
response = client.workflows.retrieve("workflow_abc123")
print(response.workflow)
Terminal window
curl -X GET "https://api.cloud.scenario.com/v1/workflows/workflow_abc123?projectId=proj_abc123" \
-H "Authorization: Basic <base64(YOUR_API_KEY:YOUR_API_SECRET)>"

Response:

{
"workflow": {
"id": "workflow_abc123",
"name": "Background Remover",
"description": "Remove backgrounds from images automatically",
"shortDescription": "AI background removal",
"status": "ready",
"privacy": "public",
"ownerId": "proj_xyz789",
"authorId": "user_123",
"createdAt": "2026-01-10T08:15:00Z",
"updatedAt": "2026-01-28T11:45:00Z",
"tagSet": ["remove-background", "editing", "tool"],
"inputs": [
{
"name": "image",
"type": "file",
"kind": "image",
"description": "Image to remove background from",
"required": { "always": true }
}
],
"flow": [
{
"id": "node_1",
"type": "remove-background",
"inputs": [
{
"name": "image",
"type": "file",
"kind": "image",
"ref": {
"node": "workflow",
"name": "image"
}
}
],
"status": "pending"
}
],
"thumbnail": {
"assetId": "asset_thumb456",
"url": "https://cdn.scenario.com/..."
},
"outputAssetKinds": ["image"],
"isLocked": false,
"editorInfo": {...}
}
}

Create a new workflow. New workflows start with draft status.

Endpoint:

POST /v1/workflows

Query Parameters:

ParameterTypeRequiredDescription
projectIdstringYesYour project ID

Request Body:

FieldTypeRequiredDescription
namestringYesWorkflow name
descriptionstringYesFull description

Example Request:

const response = await client.workflows.create({
projectId: 'proj_abc123',
name: 'My Custom Pipeline',
description: 'A custom workflow for image processing',
});
console.log(response.workflow.id);
response = client.workflows.create(
project_id="proj_abc123",
name="My Custom Pipeline",
description="A custom workflow for image processing",
)
print(response.workflow.id)
Terminal window
curl -X POST "https://api.cloud.scenario.com/v1/workflows?projectId=proj_abc123" \
-H "Authorization: Basic <base64(YOUR_API_KEY:YOUR_API_SECRET)>" \
-H "Content-Type: application/json" \
-d '{
"name": "My Custom Pipeline",
"description": "A custom workflow for image processing"
}'

Response:

{
"workflow": {
"id": "workflow_new123",
"name": "My Custom Pipeline",
"description": "A custom workflow for image processing",
"status": "draft",
"privacy": "private",
"ownerId": "proj_abc123",
"authorId": "user_123",
"createdAt": "2026-02-11T10:30:00Z",
"updatedAt": "2026-02-11T10:30:00Z",
"tagSet": [],
"inputs": [],
"flow": [],
"isLocked": false,
"editorInfo": {}
}
}

Update an existing workflow’s configuration, inputs, flow, or metadata.

Endpoint:

PUT /v1/workflows/{workflowId}

Path Parameters:

ParameterTypeRequiredDescription
workflowIdstringYesThe workflow ID

Query Parameters:

ParameterTypeRequiredDescription
projectIdstringYesYour project ID

Request Body: (all fields optional)

FieldTypeDescription
namestringWorkflow name
descriptionstringFull description
shortDescriptionstringShort description for UI display
statusstringSet to draft or ready
inputsarrayArray of input definitions (see Input Schema below)
flowarrayArray of workflow nodes (see Node Schema below)
tagSetarrayArray of tag strings
outputAssetKindsarrayExpected output types: ["image"], ["video"], etc.
beforestringAsset ID for “before” preview (or null to remove)
afterstringAsset ID for “after” preview (or null to remove)
thumbnailstringAsset ID for thumbnail (or null to remove)
isLockedbooleanLock/unlock the workflow
editorInfoobjectEditor-specific metadata

Example Request:

const response = await client.workflows.update('workflow_abc123', {
projectId: 'proj_abc123',
name: 'Enhanced Image Pipeline',
shortDescription: 'Quick image enhancement',
status: 'ready',
inputs: [
{
name: 'image',
type: 'file',
kind: 'image',
description: 'Input image',
required: { always: true },
},
{
name: 'strength',
type: 'number',
description: 'Enhancement strength',
default: 0.8,
min: 0,
max: 1,
required: { always: false },
},
],
flow: [
{
id: 'node_upscale',
type: 'custom-model',
modelId: 'model_upscaler',
inputs: [
{
name: 'image',
type: 'file',
kind: 'image',
ref: { node: 'workflow', name: 'image' },
},
],
},
],
tagSet: ['upscale', 'enhancement'],
});
response = client.workflows.update(
"workflow_abc123",
project_id="proj_abc123",
name="Enhanced Image Pipeline",
short_description="Quick image enhancement",
status="ready",
inputs=[
{
"name": "image",
"type": "file",
"kind": "image",
"description": "Input image",
"required": {"always": True},
},
{
"name": "strength",
"type": "number",
"description": "Enhancement strength",
"default": 0.8,
"min": 0,
"max": 1,
"required": {"always": False},
},
],
flow=[
{
"id": "node_upscale",
"type": "custom-model",
"modelId": "model_upscaler",
"inputs": [
{
"name": "image",
"type": "file",
"kind": "image",
"ref": {"node": "workflow", "name": "image"},
}
],
}
],
tag_set=["upscale", "enhancement"],
)
Terminal window
curl -X PUT "https://api.cloud.scenario.com/v1/workflows/workflow_abc123?projectId=proj_abc123" \
-H "Authorization: Basic <your-api-key>" \
-H "Content-Type: application/json" \
-d '{
"name": "Enhanced Image Pipeline",
"shortDescription": "Quick image enhancement",
"status": "ready",
"inputs": [
{
"name": "image",
"type": "file",
"kind": "image",
"description": "Input image",
"required": { "always": true }
},
{
"name": "strength",
"type": "number",
"description": "Enhancement strength",
"default": 0.8,
"min": 0,
"max": 1,
"required": { "always": false }
}
],
"flow": [
{
"id": "node_upscale",
"type": "custom-model",
"modelId": "model_upscaler",
"inputs": [
{
"name": "image",
"type": "file",
"kind": "image",
"ref": { "node": "workflow", "name": "image" }
}
]
}
],
"tagSet": ["upscale", "enhancement"]
}'

Response:

{
"workflow": {
"id": "workflow_abc123",
"name": "Enhanced Image Pipeline",
...
}
}

Delete a workflow. Locked workflows can only be deleted by their author.

Endpoint:

DELETE /v1/workflows/{workflowId}

Path Parameters:

ParameterTypeRequiredDescription
workflowIdstringYesThe workflow ID

Query Parameters:

ParameterTypeRequiredDescription
projectIdstringYesYour project ID

Example Request:

await client.workflows.delete('workflow_abc123');
client.workflows.delete("workflow_abc123")
Terminal window
curl -X DELETE "https://api.cloud.scenario.com/v1/workflows/workflow_abc123?projectId=proj_abc123" \
-H "Authorization: Basic <base64(YOUR_API_KEY:YOUR_API_SECRET)>"

Response:

{
"success": true
}

Execute a workflow with provided inputs. Returns a job that tracks the execution.

Endpoint:

PUT /v1/workflows/{workflowId}/run

Path Parameters:

ParameterTypeRequiredDescription
workflowIdstringYesThe workflow ID

Query Parameters:

ParameterTypeRequiredDescription
projectIdstringYesYour project ID
dryRunstringNoSet to "true" to estimate cost without executing

Request Body:

FieldTypeRequiredDescription
{inputName}variesDepends on workflow definitionKey-value pairs matching the workflow’s input parameters, placed directly in the request body

Example Request:

const response = await client.workflows.run('workflow_abc123', {
body: {
image: 'asset_input123',
strength: 0.85,
},
});
// SDK helper: wait for the job to finish
const completed = await response.job.wait();
console.log(completed.status);
response = client.workflows.run(
"workflow_abc123",
body={
"image": "asset_input123",
"strength": 0.85,
},
)
print(response.job.job_id)
Terminal window
curl -X PUT "https://api.cloud.scenario.com/v1/workflows/workflow_abc123/run?projectId=proj_abc123" \
-H "Authorization: Basic <base64(YOUR_API_KEY:YOUR_API_SECRET)>" \
-H "Content-Type: application/json" \
-d '{
"image": "asset_input123",
"strength": 0.85
}'

Response:

{
"job": {
"jobId": "job_wf_abc123xyz",
"jobType": "workflow",
"status": "in-progress",
"progress": 15,
"ownerId": "proj_abc123",
"authorId": "user_123",
"createdAt": "2026-02-11T10:35:00Z",
"updatedAt": "2026-02-11T10:35:05Z",
"metadata": {
"input": {
"image": "asset_input123",
"strength": 0.85
},
"flow": [
{
"id": "node_upscale",
"type": "custom-model",
"modelId": "model_upscaler",
"status": "processing",
"jobId": "job_node_123",
"inputs": [...]
}
],
"isApiKey": true
}
},
"workflow": {
"id": "workflow_abc123",
"name": "Enhanced Image Pipeline",
...
}
}

Dry Run Example:

// Estimate cost without executing
const dryRun = await client.workflows.run('workflow_abc123', {
body: { image: 'asset_input123' },
dryRun: 'true',
});
console.log(dryRun);
# Estimate cost without executing
dry_run = client.workflows.run(
"workflow_abc123",
body={"image": "asset_input123"},
dry_run="true",
)
print(dry_run)
Terminal window
# Estimate cost without executing
curl -X PUT "https://api.cloud.scenario.com/v1/workflows/workflow_abc123/run?projectId=proj_abc123&dryRun=true" \
-H "Authorization: Basic <base64(YOUR_API_KEY:YOUR_API_SECRET)>" \
-H "Content-Type: application/json" \
-d '{
"image": "asset_input123"
}'

Dry Run Response:

{
"statusCode": 402,
"message": "Dry run completed",
"estimatedCost": 12
}

Retrieve unique tags used in workflows for a project.

Endpoint:

GET /v1/workflows/tags

Query Parameters:

ParameterTypeRequiredDefaultDescription
projectIdstringYes-Your project ID
statusstringNoreadyFilter by workflow status

Example Request:

const tags = await client.workflows.getTags({ projectId: 'proj_abc123' });
console.log(tags);
tags = client.workflows.get_tags(project_id="proj_abc123")
print(tags)
Terminal window
curl -X GET "https://api.cloud.scenario.com/v1/workflows/tags?projectId=proj_abc123" \
-H "Authorization: Basic <base64(YOUR_API_KEY:YOUR_API_SECRET)>"

Response:

{
"tags": [
"upscale",
"remove-background",
"image-enhancement",
"video",
"tool",
"editing"
]
}

Apps are public workflows that anyone can discover and use. They’re pre-built creative pipelines optimized for specific tasks.

List all available apps by filtering for public workflows.

Example Request:

const apps = await client.workflows.list({ privacy: 'public', status: 'ready' });
apps = client.workflows.list(privacy="public", status="ready")
Terminal window
curl -X GET "https://api.cloud.scenario.com/v1/workflows?privacy=public&status=ready" \
-H "Authorization: Basic <base64(YOUR_API_KEY:YOUR_API_SECRET)>"

Use Case Examples:

// Find background removal apps
const bgRemovers = await client.workflows.list({ privacy: 'public', tags: 'remove-background' });
// Find upscaling apps
const upscalers = await client.workflows.list({ privacy: 'public', tags: 'upscale' });
// Find all tool-type apps
const tools = await client.workflows.list({ privacy: 'public', tags: 'tool' });
# Find background removal apps
bg_removers = client.workflows.list(privacy="public", tags="remove-background")
# Find upscaling apps
upscalers = client.workflows.list(privacy="public", tags="upscale")
# Find all tool-type apps
tools = client.workflows.list(privacy="public", tags="tool")
Terminal window
# Find background removal apps
curl -X GET "https://api.cloud.scenario.com/v1/workflows?privacy=public&tags=remove-background"
# Find upscaling apps
curl -X GET "https://api.cloud.scenario.com/v1/workflows?privacy=public&tags=upscale"
# Find all tool-type apps
curl -X GET "https://api.cloud.scenario.com/v1/workflows?privacy=public&tags=tool"

Running an app is identical to running a workflow:

Example Request:

// Run the Background Remover app
const response = await client.workflows.run('workflow_bg_remover', {
body: { image: 'asset_photo123' },
});
const completed = await response.job.wait();
# Run the Background Remover app
response = client.workflows.run(
"workflow_bg_remover",
body={"image": "asset_photo123"},
)
Terminal window
# Run the Background Remover app
curl -X PUT "https://api.cloud.scenario.com/v1/workflows/workflow_bg_remover/run?projectId=proj_abc123" \
-H "Authorization: Basic <base64(YOUR_API_KEY:YOUR_API_SECRET)>" \
-H "Content-Type: application/json" \
-d '{
"image": "asset_photo123"
}'

After running a workflow, monitor its progress using the Jobs API:

Get Job Status:

const response = await client.jobs.retrieve('job_wf_abc123xyz');
console.log(response.job.status);
response = client.jobs.retrieve("job_wf_abc123xyz")
print(response.job.status)
Terminal window
curl -X GET "https://api.cloud.scenario.com/v1/jobs/job_wf_abc123xyz?projectId=proj_abc123" \
-H "Authorization: Basic <base64(YOUR_API_KEY:YOUR_API_SECRET)>"

Job Status Values:

StatusDescription
queuedJob is queued for execution
in-progressJob is currently executing
succeededJob completed successfully
failedJob failed with an error
canceledJob was canceled

Completed Job Response:

{
"job": {
"jobId": "job_wf_abc123xyz",
"jobType": "workflow",
"status": "succeeded",
"progress": 100,
"createdAt": "2026-02-11T10:35:00Z",
"updatedAt": "2026-02-11T10:35:45Z",
"metadata": {
"flow": [
{
"id": "node_upscale",
"status": "success",
"assets": [
{
"assetId": "asset_output123",
"url": "https://cdn.scenario.com/output/..."
}
]
}
]
}
}
}

Workflow inputs define the parameters that must be provided when running the workflow.

Common Input Types:

{
"name": "image",
"type": "file",
"kind": "image",
"description": "Input image",
"required": { "always": true }
}
{
"name": "prompt",
"type": "string",
"description": "Text prompt for generation",
"default": "A beautiful landscape",
"required": { "always": true }
}
{
"name": "strength",
"type": "number",
"description": "Processing strength",
"default": 0.75,
"min": 0,
"max": 1,
"step": 0.05,
"required": { "always": false }
}
{
"name": "enable_feature",
"type": "boolean",
"description": "Enable advanced feature",
"default": false,
"required": { "always": false }
}
{
"name": "style",
"type": "select",
"description": "Output style",
"options": ["realistic", "artistic", "cartoon"],
"default": "realistic",
"required": { "always": true }
}

Nodes define the processing steps in a workflow’s flow.

TypeDescription
custom-modelRun a custom AI model
remove-backgroundRemove image background
logicConditional logic (if/else)
transformTransform data
user-approvalRequire user approval
workflowRun a sub-workflow
generate-promptGenerate/refine prompts
{
"id": "node_generation",
"type": "custom-model",
"modelId": "model_xyz123",
"inputs": [
{
"name": "prompt",
"type": "string",
"ref": {
"node": "workflow",
"name": "prompt"
}
},
{
"name": "image",
"type": "file",
"kind": "image",
"ref": {
"node": "workflow",
"name": "image"
}
}
]
}
{
"id": "node_condition",
"type": "logic",
"logicType": "if-else",
"inputs": [
{
"name": "condition",
"type": "string",
"ref": {
"node": "workflow",
"name": "mode"
}
}
],
"logic": {
"cases": [
{
"condition": "fast",
"value": "output_fast"
},
{
"condition": "quality",
"value": "output_quality"
}
],
"default": "output_balanced"
}
}
{
"id": "node_resize",
"type": "transform",
"inputs": [
{
"name": "width",
"type": "number",
"value": 1024
}
],
"logic": {
"transform": "resize(width, height)"
}
}

Nodes can reference outputs from other nodes or workflow inputs:

{
"ref": {
"node": "workflow", // or node ID like "node_1"
"name": "prompt" // input/output name
}
}

Reference previous node output:

{
"ref": {
"node": "node_upscale",
"name": "all" // get all outputs
}
}

Conditional references:

{
"ref": {
"conditional": ["node_check_1", "node_check_2"],
"equal": "success"
}
}

Locked workflows cannot be modified or deleted except by specific users.

Lock a Workflow:

await client.workflows.update('workflow_abc123', {
projectId: 'proj_abc123',
isLocked: true,
});
client.workflows.update(
"workflow_abc123",
project_id="proj_abc123",
is_locked=True,
)
Terminal window
curl -X PUT "https://api.cloud.scenario.com/v1/workflows/workflow_abc123?projectId=proj_abc123" \
-H "Authorization: Basic <your-api-key>" \
-H "Content-Type: application/json" \
-d '{ "isLocked": true }'

Lock Rules:

  • Only the workflow author or project editors can lock/unlock
  • Only the author can modify or delete a locked workflow
  • Locking prevents accidental changes to production workflows

Status CodeDescription
400Bad Request - Invalid parameters or body
401Unauthorized - Invalid or missing API key
403Forbidden - Insufficient permissions
404Not Found - Workflow doesn’t exist
402Payment Required - Returned for dry run billing estimates

Error Response Format:

{
"statusCode": 400,
"error": "Bad Request",
"message": "Invalid privacy. Must be one of: public, private, unlisted"
}

Create workflows with draft status while building them. Set to ready only when complete and tested.

Use consistent tags to categorize workflows:

  • tool - Utility workflows (upscale, remove-background)
  • editing - Image/video editing workflows
  • generation - Content generation workflows
  • Custom domain tags (e.g., gaming, marketing)

Help users understand what each input does with clear descriptions and appropriate defaults.

Before executing expensive workflows, use dryRun=true to estimate costs.

Workflows can take time to complete. Poll the Jobs API or use webhooks to monitor progress.

Lock workflows that are used in production to prevent accidental modifications.

Add visual examples to help users understand what the workflow does.


  • API Requests: 100 requests per minute per project
  • Concurrent Workflow Jobs: 10 concurrent executions per project
  • Workflow Size: Maximum 50 nodes per workflow