Sogni: Learn logo

Workflow Templates

Workflow templates are saved, parameterized creative-agent recipes. Use them when your builder UI or agent wants to create reusable workflows with typed inputs, then start durable /v1/creative-agent/workflows runs from those saved definitions.

compose_workflow_template in /v1/chat/completions can draft a template from a natural-language brief. The same tool also accepts an existing_template argument carrying the prior template JSON — pass it when the user asks to edit a saved template ("change my saved storyboard to 16:9", "add a music step to wf_X", "swap the model in my saved template") and the planner will preserve stage ids and bump only the requested change. The REST template endpoints below persist, list, edit, fork, and delete those drafts.

#Template Endpoints

Endpoint Method Use
/v1/creative-agent/workflows/templates POST Create a workflow template.
/v1/creative-agent/workflows/templates GET List accessible templates.
/v1/creative-agent/workflows/templates/:id GET Read one template.
/v1/creative-agent/workflows/templates/:id PATCH Update an owned template.
/v1/creative-agent/workflows/templates/:id DELETE Delete an owned template.
/v1/creative-agent/workflows/templates/:id/fork POST Copy an accessible template into the caller's private templates.

All template routes require authentication. Private templates are only visible to their owner. Public templates are readable and forkable by any authenticated caller. Update and delete treat "not owned" the same as "not found" so private template IDs cannot be probed.

#Template Shape

Field Use
id Optional caller-supplied template ID. If omitted, the API mints one from the template name.
version Optional semantic version. Defaults to 0.0.1; updates bump the patch version.
name Required display name.
description Optional description.
brief Optional source brief or authoring prompt.
category Optional category: portrait, video-social, makeover, cinematic, music, analysis, custom, or other. Defaults to custom.
stability Optional production, beta, or experimental. Defaults to experimental.
author Optional system or { "userId": "...", "displayName": "..." }.
visibility Optional private or public. Defaults to private.
inputs Typed input declarations used when compiling the template.
stages Fixed, interactive, or batch stages that compile into workflow steps.
graph Optional visual builder layout.
previewArtifacts Optional image/video preview metadata for galleries.
estimatedCapacityUnits Optional { "min": number, "max": number } estimate.
exposeToLLM Optional boolean for template discovery surfaces. Defaults to false.
llmPriority Optional ranking hint for LLM-facing template selection.
tags, metadata Optional app-specific metadata.

Templates are validated by the shared creative-agent validator. Invalid create or update requests return 422 with data.validation.issues.

#Binding Syntax In Stage Args

Stage args values use binding placeholders to pull from the run context. Two forms are supported:

  • Pure binding — the entire string is $root.path (e.g. "$inputs.duration", "$artifacts.script.items[0].selectedVersion.content"). The resolver returns the value at its original type: a number stays a number, an array stays an array, a selected ArtifactVersion stays the object.
  • Embedded binding$root.path patterns inside a longer string (e.g. "Render in $inputs.aspect_ratio for $inputs.duration seconds.") are interpolated inline. Each match is stringified and substituted. Embedded paths that resolve to undefined throw a BindingError so typos surface during validation rather than shipping $inputs.foo text to a model.
  • Wildcard expansionitems[*] returns the full list. Example: "$artifacts.angles.items[*].selectedVersion.url" returns string[].

Roots: $inputs, $artifacts, $item (batch stage), $runtime, $run.

Convenience accessors on artifacts: .items[N].selectedVersion resolves to the currently-selected version of an ArtifactItem (the canonical way to pull a generated URL from a prior stage).

#Workflow Primitives

@sogni-ai/sogni-intelligence-client/workflows exposes a primitives namespace of pure helpers (prompt builders, parsers, predicate evaluators) that runtimes use to implement wf:*-prefixed workflow stage tools. Primitives are NOT chat tools — they are stage-only utilities that compose with the condition field on a stage to enable automated validate-and-regenerate loops.

Primitive Purpose
wf:validate_with_rubric LLM judge with strict __PASS__ / __FAIL__: <reason> token protocol. Returns ToolErr with WORKFLOW_VALIDATION_FAILED on fail so a downstream stage with condition: { type: 'if_error_in', stageId: 'validate_X' } fires a retry. Supports text and image artifacts. The artifactUrl argument is checked against an allow-list before any HTTP fetch — loopback, private, and link-local addresses are rejected.
wf:retry_until_condition Wraps another tool with a bounded retry loop until a predicate passes. Predicate kinds: metadata_field_truthy, metadata_field_equals, metadata_field_gte, metadata_field_lte over a dot-path into the wrapped tool's result. Preserves the wrapped tool's output_assets so downstream bindings continue to resolve.
wf:expand_storyboard_script LLM expands a brief into a numbered TITLE / TOTAL_DURATION / BEATS script with structural validation (sum-of-seconds drift within 20%, every beat has VISUAL and ACTION fields, sequential numbering).
wf:fit_dialogue_to_duration LLM rewrites dialogue to fit a target spoken duration at a configurable words-per-minute rate. Enforces mustKeep verbatim phrases.

All four wf:* primitives now run durably on the hosted backend (POST /v1/creative-agent/workflows) as well as in client-side runtimes — the executor short-circuits wf:* steps to a server-side primitive service (pure compute for wf:fit_dialogue_to_duration, server-side LLM for wf:expand_storyboard_script / wf:validate_with_rubric, and a durable loop marker for wf:retry_until_condition). wf:validate_with_rubric enforces an SSRF allow-list on artifactUrl (loopback / private / link-local rejected) and maps a blocked input to WORKFLOW_VALIDATION_FAILED without echoing the raw URL.

#Create A Template

curl https://api.sogni.ai/v1/creative-agent/workflows/templates \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Two-shot product teaser",
    "description": "Generate a product keyframe and animate it.",
    "category": "video-social",
    "visibility": "private",
    "inputs": [
      {
        "name": "brief",
        "type": "text",
        "required": true,
        "description": "Product and visual direction"
      }
    ],
    "stages": [
      {
        "id": "keyframe",
        "type": "fixed",
        "tool": "generate_image",
        "args": {
          "prompt": "$inputs.brief",
          "model": "flux2",
          "width": 1024,
          "height": 576
        }
      },
      {
        "id": "clip",
        "type": "fixed",
        "tool": "generate_video",
        "args": {
          "prompt": "Slow cinematic product push-in",
          "duration": 5
        }
      }
    ],
    "exposeToLLM": false
  }'

Representative response:

{
  "status": "success",
  "data": {
    "template": {
      "id": "wf_two-shot-product-teaser_a1b2c3d4",
      "version": "0.0.1",
      "name": "Two-shot product teaser",
      "visibility": "private",
      "inputs": [],
      "stages": []
    }
  }
}

#List And Read

curl "https://api.sogni.ai/v1/creative-agent/workflows/templates?visibility=all&limit=20&offset=0" \
  -H "Authorization: Bearer YOUR_API_KEY"

visibility can be:

Value Result
all Caller-owned templates plus public templates. Default.
own Only caller-owned templates.
public Only public templates.

Pagination uses offset and limit; limit is capped at 100. Responses return data.templates and data.next, where next is the next offset or null.

Read one template:

curl https://api.sogni.ai/v1/creative-agent/workflows/templates/wf_two-shot-product-teaser_a1b2c3d4 \
  -H "Authorization: Bearer YOUR_API_KEY"

#Update, Delete, Fork

Patch an owned template:

curl -X PATCH https://api.sogni.ai/v1/creative-agent/workflows/templates/wf_two-shot-product-teaser_a1b2c3d4 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "visibility": "public", "tags": ["product", "video"] }'

Delete an owned template:

curl -X DELETE https://api.sogni.ai/v1/creative-agent/workflows/templates/wf_two-shot-product-teaser_a1b2c3d4 \
  -H "Authorization: Bearer YOUR_API_KEY"

Fork a public or owned template into a new private template:

curl -X POST https://api.sogni.ai/v1/creative-agent/workflows/templates/wf_source_template/fork \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "My product teaser variant" }'

Forked templates reset to version 0.0.1, are private by default, and include clonedFromTemplateId.

#Run From A Template

Start a durable workflow from a saved template by sending workflow_id and inputs to /v1/creative-agent/workflows. Do not send input.steps in the same request.

curl https://api.sogni.ai/v1/creative-agent/workflows \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: template-run-001" \
  -d '{
    "workflow_id": "wf_two-shot-product-teaser_a1b2c3d4",
    "inputs": {
      "brief": "A translucent speaker on a glossy black table, neon rim light"
    },
    "token_type": "spark",
    "confirm_cost": true
  }'

The API compiles the template with the provided inputs. Compile failures return 422 with compileErrors and compileWarnings. A successful template start authorizes cost first: it persists the compiled workflow and returns HTTP 202 with { workflow, waitingForCostApproval: true, preview } in a cost_approval_required pause — release it with POST /:id/confirm-cost before any step dispatches. See Creative-Agent Workflows → Run From A Template.