Save a workflow as a template
POST/
Saves a copy of a workflow’s draft as a template.
Needs an API token with the Write permission for workflows (workflow:write).
Parameters
Body
workflowIdRequired · UUIDThe workflow to copy, in this workspace. Its draft is copied as it is now.
nameOptional · stringUp to 255 characters, trimmed. Blank: the workflow’s name.
descriptionOptional · stringTrimmed. Blank stays blank: the template then describes itself by its trigger and first steps.
categoryOptional · stringAny label, trimmed.
What is copied
The steps and their settings, plain variables and notes. Not sensitive variables, which a template can’t hold, and not a secret typed into a step: those are listed in blanked. Preview saving says which first.
Connections travel by ID and are matched when the template is used. The copy never changes when the workflow does; update its steps to copy again.
In an organization it belongs to the organization; in a customer account, to this workspace. It takes no Idempotency-Key: a retry saves a second one.
Responses
- 201Created
The template, with its copy of the steps and
blanked: each value the copy left out. The body isn’t JSON,
workflowIdis missing or not a UUID, or the name is over 255 characters.- 403
FORBIDDENThe token lacks the Write permission for workflows.
- 404
NOT_FOUNDNo workflow with this ID in the workspace.
The template wasn’t saved. Try again.
Any call can also answer: 401 UNAUTHORIZED · 401 TOKEN_ENDED · 403 TOKEN_SURFACE_OFF · 403 FEATURE_OFF · 403 EMBED_NOT_ALLOWED · 403 EMBED_NOT_AVAILABLE · 403 ACCOUNT_SUSPENDED · 413 PAYLOAD_TOO_LARGE · 415 INVALID_CONTENT_TYPE · 429 RATE_LIMITED · 503 BUSY · 503 PAUSED · 503 SERVICE_UNAVAILABLE. See Errors.
Request
GORUNNER="https://api.gorunner.io"
GORUNNER_TOKEN="grt_…" # needs Write for workflows
curl -X POST "$GORUNNER/api/templates" \
-H "Authorization: Bearer $GORUNNER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"workflowId": "3b1e5c2a-7d4f-4e8b-a1c6-5f2d9b0e7a31",
"name": "Order intake",
"category": "Sales"
}'const GORUNNER = "https://api.gorunner.io";
const TOKEN = process.env.GORUNNER_TOKEN;
const res = await fetch(`${GORUNNER}/api/templates`, {
method: "POST",
headers: {
Authorization: `Bearer ${TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
workflowId: "3b1e5c2a-7d4f-4e8b-a1c6-5f2d9b0e7a31",
name: "Order intake",
category: "Sales",
}),
});
const { data } = await res.json();import os, requests
GORUNNER = "https://api.gorunner.io"
TOKEN = os.environ["GORUNNER_TOKEN"]
res = requests.post(
f"{GORUNNER}/api/templates",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"workflowId": "3b1e5c2a-7d4f-4e8b-a1c6-5f2d9b0e7a31",
"name": "Order intake",
"category": "Sales",
},
)
data = res.json()["data"]Response · 201 Created, shortened
{
"data": {
"id": "9c4e2a17-3d5b-4f86-b0e2-8a1c7d3f5e29",
"scope": "org",
"name": "Order intake",
"description": "Webhook to fulfilment, with a VIP branch.",
"category": "Sales",
"triggerType": "webhook",
"createdAt": "2026-10-20T08:00:00Z",
"definition": {
"schemaVersion": 2,
"trigger": {
"name": "trigger",
"displayName": "Order received",
"type": "webhook",
"pieceId": "webhook",
"pieceVersion": "1.0.0",
"actionId": "catch_webhook",
"config": {
"methods": [
"POST"
]
},
"valid": true,
"nextAction": {
"name": "forward",
"displayName": "Forward to fulfilment",
"type": "PIECE",
"pieceId": "http",
"pieceVersion": "1.0.0",
"actionId": "send_request",
"config": {
"method": "POST",
"url": "https://example.com/fulfilment",
"body_type": "json",
"body_json": "{{trigger.body}}"
},
"valid": true
}
},
"settings": {}
},
"blanked": [
{
"step": "forward",
"stepLabel": "Forward to fulfilment",
"field": "auth_token",
"fieldLabel": "Bearer Token"
}
]
}
}Every field
Body
workflowIdRequired · UUIDThe workflow whose CURRENT DRAFT definition is snapshotted. Must be in the caller’s workspace. You never submit a definition yourself.
nameOptional · stringOptional; trimmed. Blank falls back to the source workflow’s name. Max 255 characters.
descriptionOptional · stringOptional; trimmed. Blank stays blank (the template then shows a generated
whenLine).categoryOptional · stringOptional free-text grouping label; trimmed. No server-side vocabulary.
Response · 201 Created
dataobjectA template with its definition: an immutable snapshot of a workflow’s draft taken when it was saved (or its steps last updated). A copy, never a live link: workflows made from it are not affected by changing or deleting it.
idUUIDscopestringWho sees it:
org— an organization’s, every workspace of it;workspace— a customer account’s, the workspace it was saved in only;installation— shared by the installation with its customer accounts (listed only in a customer account, and only while the license has embedding), read-only here.One of
org,workspace,installation.keystringAn installation template’s stable handle. Absent on every other template.
namestringdescriptionstringWhat it does, as saved. May be empty:
whenLinethen describes it.categorystringFree-text grouping label; empty when none.
triggerTypestringcreatedAttimeupdatedAttimepublishedAttimeWhen an installation template was first offered. Absent on every other template.
readablebooleanfalse: its definition cannot be read. Such a row is listed only to someone who may delete it (
canManage), with everything derived from the definition empty.authorobject or nullWho saved it; null for an installation template.
idUUID or nullnamestring or nullTheir name, else their email; null once the account is deleted.
leftbooleanThey are no longer a member of this organization.
sourceobject or nullAn installation template’s origin; null otherwise.
organizationstringThe organization it was shared from; empty once that organization is gone.
savedHerebooleanIt was saved in this workspace. Otherwise its bound values arrive blank (see
TemplateFillField).savedInstring or nullThe workspace it was saved in (an installation template: the organization it was shared from); null when not recorded.
sourceWorkflowobject or nullThe workflow it was saved (or last updated) from, while that workflow exists and is in this workspace.
idUUIDnamestringtriggerobject or nullnamestringdisplayNamestringpieceIdstringactionIdstringmarksarray of stringsApp ids in run order: the trigger’s, then one per step (branch steps
branch, loopsloop, a Code stepcode), never de-duplicated.stepsarray of objectsEvery step, in the order of
marksafter the trigger.namestringdisplayNamestringpieceIdstringactionIdstringtypestringOne of
PIECE,CODE,BRANCH,LOOP.depthinteger0 at the top level; one more inside a branch arm, a loop body or an error path.
whenLinestringA generated line for a template without a description: how it starts, then its first three steps’ names.
slotsarray of objectsThe connections a workflow made from it needs, one per service account.
keystringpieceIdstringThe connection’s app (what
GET /api/connectionsrows carry).pieceNamestringstepsarray of stringsstepLabelsarray of stringsconnectionIdstring or nullThe connection the template’s own steps name; null for an installation template or none.
toFillintegerHow many values using it here will ask for: required fields left blank and bound values blanked here.
availablebooleanunavailableobject or nullWhy it cannot be used on this installation.
codestringOne of
PIECE_UNAVAILABLE,STEP_INCOMPLETE,ACTION_UNAVAILABLE,UNREADABLE.messagestringstepstringThe step it is about, by name.
usesobject or nullWorkflows of this organization made from it, and how many are live. Sent only to its author, an organization admin or a platform admin.
workflowsintegerliveintegercanManagebooleanThe caller may rename, update the steps of and delete it: its creator, an organization admin, or for a
workspacetemplate that workspace’s admin.createdByUUIDWho saved it, as before the Templates redesign (
authornames them). Absent on an installation template and when the account is gone.definitionobjectA workflow definition — the same document the workflow API uses (
schemaVersionis 2). It is a TREE, not a list:triggeris the root and each node chains onward throughnextAction;branches[].firstActionandfirstLoopActionhold nested sub-chains, andonErrorActionholds a step’s error arm. A step’s settings live inconfig, neversettings. The trigger names its trigger in a field calledactionId, and triggertypeis lowercase while actiontypeis UPPERCASE (PIECE,BRANCH,LOOP,CODE). A step that uses credentials carriesconnectionId— a bare connection id, workspace-scoped, which is why it may be cleared when the template is used in another workspace.A workflow definition: its fields are in Workflow definition.
blankedarray of objectsOnly on a save’s and an update of the steps’ answers: each value the copy left out (a credential typed into a step).
stepstringThe step’s name (the trigger’s own name for the trigger).
stepLabelstringThe step as the canvas names it.
fieldstringThe top-level input key.
fieldLabelstringThe app’s title for the input.