Skip to main content

What is each::workflows?

A workflow is a saved recipe of AI steps that runs with one API call. You choose the models, prompts and post-processing once. Your app sends the inputs (usually a photo or a short text) and gets the finished result back.

Why use a workflow?

Workflows are free. You pay only for the model steps that run.
If you call one model with a prompt your user writes, a direct prediction is simpler. Use a workflow once the prompt is fixed, you want a fallback, or there is a second step.

Authoring rules

Follow these and a workflow runs on the first try.
  1. Reference values with $. paths: $.inputs.<name> for inputs, $.<step_id>.primary or $.<step_id>.output for earlier steps, brackets for arrays ($.step.output[0]). {{inputs.prompt}} is not a reference; it is sent to the model as literal text.
  2. A value that is exactly one reference keeps its type (URL, number, object). A reference inside a longer string is inserted as text: "A portrait of $.inputs.name in neon light".
  3. primary is the main result. For image and video models it is the file URL. For eachlabs-llm-router it is the chat completion, so the text is at $.<step_id>.primary.choices[0].message.content. For eachlabs-http-step it is the response, so JSON fields are at $.<step_id>.primary.output.<field>.
  4. Prompt fields quote whole references. If a prompt-like field (prompt, text, content, message, caption, title, description) is exactly $.step.primary or $.step.output, the value arrives wrapped in quotes. Reference a deeper field or embed it in a sentence.
  5. Step types are model, parallel, choice and pass. HTTP requests and Python code are not step types; they run as model steps through eachlabs-http-step and eachlabs-python-step (private beta). See HTTP steps.
  6. Every step needs a unique id, including steps inside branches. A step can only reference inputs and steps that ran before it.
  7. Inputs live in input_schema.properties. Each field takes type (string, number, boolean, image, video, voice for audio, file), required (true/false) and an optional default_value. Files are passed as public URLs. Give every optional input a default_value, because a run fails if a step references an omitted input with no default.
  8. Parallel: each branch is a list of steps. Later steps reference branch steps by their own id.
  9. Choice: a condition, a condition_met_branch and a default_branch, both non-empty. Afterwards, $.<choice_id>.primary is the result of whichever branch ran. Operators: equals, not_equals, greater_than, greater_than_or_equal, less_than, less_than_or_equal, string_equals, string_matches (a * wildcard pattern such as "*.mp4"), exists, is_not_null, combined with and, or and not.
  10. Fallback is set per model step and has its own params, because the second model may take different parameters.
  11. The result of a run is the output of its last step. To return named values, add "metadata": {"output_mapping": {"video": "$.final.primary"}} to the definition.
  12. Models are checked when a step runs, not when you save. Read a model’s inputs with GET /v1/models/{slug} and test the workflow once before shipping it.

Create, run and read

A completed run has output (the last step’s result), workflow_output (your named outputs) and step_outputs.<step_id> for every step. Add "webhook_url" to the run request to be notified instead of polling. If creating returns 400 invalid argument, send the definition to PUT /v1/workflows/{workflowID}/versions/v1 as {"definition": {...}} to see the exact error.

Examples

Each example is a complete workflow.json for the create call. Replace the input URLs with your own files, uploaded with each::storage if they are not public yet.

1. One-photo effect

Turn one photo into a finished clip. The prompt stays on Eachlabs, and a second model takes over if the first one fails.
Inputs: {"photo": "https://example.com/selfie.jpg"}

2. Restyle a photo, then animate it

Chain two models: edit the image, then pass the result to a video model.
Inputs: {"photo": "https://example.com/portrait.jpg", "style": "a watercolor illustration"} $.restyle.primary is the edited image, from the fallback model if it ran. style is optional because it has a default.

3. An LLM writes the prompt

A vision LLM looks at the product and writes the scene. The image and video models follow it.
Inputs: {"person": "https://example.com/creator.jpg", "product": "https://example.com/honey.png"}

4. Two photos, one clip, with music

Prepare both photos at the same time, put both people in one video, then resize it and add music.
Inputs: {"photo_a": "https://example.com/a.jpg", "photo_b": "https://example.com/b.jpg", "music": "https://example.com/track.mp3"} Both edits run at the same time. To use the same music every time, replace $.inputs.music with a fixed URL.

5. A reliable vision call

Write alt text for a product photo. If the first provider fails, a second one answers.
Inputs: {"image": "https://cdn.dummyjson.com/product-images/groceries/honey-jar/1.webp"} The run’s workflow_output.alt_text holds the sentence, whichever provider answered.

6. Call an API, then use its data

Fetch a product from an API and turn it into an ad image. This example calls the public DummyJSON test API; point url at your own API.
Inputs: {"product_id": "27"}
  • eachlabs-http-step takes url, method, headers, query_params, body (a JSON object for POST, PUT or PATCH), timeout_seconds (up to 30 recommended) and fail_on_status.
  • Set fail_on_status to "non_2xx" so an error response stops the run.
  • To run your own code, deploy it as an HTTPS endpoint (a serverless function is enough), POST the inputs to it, and read its JSON reply in the next step. Organizations in the private beta can use the eachlabs-python-step model instead.
  • Only public URLs are reachable. Definitions are stored, so use scoped, read-only tokens in headers.

7. Let AI choose the path

Ask a vision model what the photo shows, then pick the matching recipe. The next step continues from whichever branch ran.
Inputs: {"photo": "https://example.com/dog.jpg"} string_matches uses * wildcards, so *PET* also matches PET.. Use and, or and not to combine conditions.

8. Several scenes in parallel, joined with music

Each branch builds one scene (image, then video). All scenes render at the same time, then the clips are joined and music is added.
Inputs: {"product": "https://cdn.dummyjson.com/product-images/groceries/honey-jar/1.webp", "product_name": "honey jar", "music": "https://example.com/track.mp3"} Steps inside a branch run in order; the branches run at the same time, so three scenes take about as long as one. merge-videos joins the clips in the listed order.

Checklist for agents

  • Every step has a unique id; every $. reference points to an input or an earlier step.
  • References use $., never {{...}}.
  • Every optional input has a default_value.
  • Model slugs and parameters come from GET /v1/models/{slug}.
  • LLM text is read from primary.choices[0].message.content; HTTP JSON from primary.output.<field>.
  • The last step produces the final result, or metadata.output_mapping names it.
  • You ran it once and checked step_outputs before giving it to users.

Endpoints

All paths are relative to https://api.eachlabs.ai.

Pricing

Workflows are free to create, manage and run. You pay only for the models inside your steps, billed through each::api.
Last modified on October 6, 2026