Endpoint
PUT https://api.eachlabs.ai/v1/workflows/{workflowID}/versions/{versionID}
- Create the version if it doesn’t exist, or patch the stored one
- Set this version as the latest version
Once a version is locked, it cannot be modified.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
workflowID | string | Yes | Workflow UUID or slug |
versionID | string | Yes | Version identifier (e.g., v1, v2) |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
definition | object | To create | Complete workflow definition. Required for a new version; omit (or send null) to keep the stored definition when updating |
output_mapping | object | No | Final output keys mapped to step output refs, e.g. {"image": "$.generate_image.output"}. Omit to leave unchanged, send {} to clear, send entries to replace the whole map |
published | boolean | No | Publish state for this version |
locked | boolean | No | Lock this version against further edits |
production | boolean | No | Mark as production |
allowed_to_share | boolean | No | Make unlisted (true) or private (false) |
version_id | string | No | Overrides the version in the path when present |
Code Examples
This adds versionv2 to the quickstart workflow: the image shape becomes an
optional input, and the image is returned as workflow_output.image.
curl -X PUT https://api.eachlabs.ai/v1/workflows/WF_ID/versions/v2 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"definition": {
"input_schema": {
"properties": {
"prompt": { "type": "string", "required": true },
"aspect_ratio": { "type": "string", "required": false, "default_value": "16:9" }
}
},
"steps": [
{
"id": "write_prompt",
"type": "model",
"model": "eachlabs-llm-router",
"params": {
"model": "google/gemini-3.6-flash",
"messages": [
{ "role": "system", "content": "Rewrite the idea as one vivid, detailed image prompt. Reply with the prompt only." },
{ "role": "user", "content": "$.inputs.prompt" }
]
}
},
{
"id": "generate_image",
"type": "model",
"model": "nano-banana-2-text-to-image",
"params": {
"prompt": "$.write_prompt.primary.choices[0].message.content",
"aspect_ratio": "$.inputs.aspect_ratio"
}
}
]
},
"output_mapping": { "image": "$.generate_image.primary" }
}'
import requests
definition = {
"input_schema": {
"properties": {
"prompt": {"type": "string", "required": True},
"aspect_ratio": {"type": "string", "required": False, "default_value": "16:9"},
}
},
"steps": [
{
"id": "write_prompt",
"type": "model",
"model": "eachlabs-llm-router",
"params": {
"model": "google/gemini-3.6-flash",
"messages": [
{"role": "system", "content": "Rewrite the idea as one vivid, detailed image prompt. Reply with the prompt only."},
{"role": "user", "content": "$.inputs.prompt"},
],
},
},
{
"id": "generate_image",
"type": "model",
"model": "nano-banana-2-text-to-image",
"params": {
"prompt": "$.write_prompt.primary.choices[0].message.content",
"aspect_ratio": "$.inputs.aspect_ratio",
},
},
],
}
response = requests.put(
"https://api.eachlabs.ai/v1/workflows/WF_ID/versions/v2",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"definition": definition, "output_mapping": {"image": "$.generate_image.primary"}},
)
print(response.json()["version_id"])
const definition = {
input_schema: {
properties: {
prompt: { type: "string", required: true },
aspect_ratio: { type: "string", required: false, default_value: "16:9" },
},
},
steps: [
{
id: "write_prompt",
type: "model",
model: "eachlabs-llm-router",
params: {
model: "google/gemini-3.6-flash",
messages: [
{ role: "system", content: "Rewrite the idea as one vivid, detailed image prompt. Reply with the prompt only." },
{ role: "user", content: "$.inputs.prompt" },
],
},
},
{
id: "generate_image",
type: "model",
model: "nano-banana-2-text-to-image",
params: {
prompt: "$.write_prompt.primary.choices[0].message.content",
aspect_ratio: "$.inputs.aspect_ratio",
},
},
],
};
const response = await fetch("https://api.eachlabs.ai/v1/workflows/WF_ID/versions/v2", {
method: "PUT",
headers: { "Content-Type": "application/json", "Authorization": "Bearer YOUR_API_KEY" },
body: JSON.stringify({ definition, output_mapping: { image: "$.generate_image.primary" } }),
});
console.log((await response.json()).version_id);
POST /v1/workflows/trigger/WF_ID/v2 and {"inputs": {"prompt": "A lighthouse on a cliff at sunset", "aspect_ratio": "9:16"}};
the finished run has workflow_output.image.
Response
{
"version_id": "v2",
"slug": "text-to-image-generator",
"published": false,
"locked": false,
"production": true,
"allowed_to_share": false,
"trigger_count": 0,
"status": "active",
"visibility": "private",
"is_popular": false,
"updated_by": "[email protected]",
"created_at": "2025-12-05T14:20:00Z",
"updated_at": "2025-12-05T14:20:00Z",
"definition": { ... }
}
Error Responses
| Status | Body | Description |
|---|---|---|
400 | {"error": "invalid JSON body"} | Malformed body — validation failures return the specific reason |
401 | {"error": "Invalid or missing API key"} | Auth failure |
403 | {"error": "version is locked"} | Cannot modify a locked version |
404 | {"error": "workflow not found"} | Invalid workflow ID |