curl --request PATCH \
--url https://app.formbricks.com/api/v3/workflows/{workflowId} \
--header 'Content-Type: application/json' \
--cookie next-auth.session-token= \
--data '
{
"name": "<string>",
"description": "<string>"
}
'import requests
url = "https://app.formbricks.com/api/v3/workflows/{workflowId}"
payload = {
"name": "<string>",
"description": "<string>"
}
headers = {
"cookie": "next-auth.session-token=",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {cookie: 'next-auth.session-token=', 'Content-Type': 'application/json'},
body: JSON.stringify({name: '<string>', description: '<string>'})
};
fetch('https://app.formbricks.com/api/v3/workflows/{workflowId}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.formbricks.com/api/v3/workflows/{workflowId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'description' => '<string>'
]),
CURLOPT_COOKIE => "next-auth.session-token=",
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.formbricks.com/api/v3/workflows/{workflowId}"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"description\": \"<string>\"\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("cookie", "next-auth.session-token=")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://app.formbricks.com/api/v3/workflows/{workflowId}")
.header("cookie", "next-auth.session-token=")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"description\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.formbricks.com/api/v3/workflows/{workflowId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["cookie"] = 'next-auth.session-token='
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"description\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "<string>",
"workspaceId": "<string>",
"name": "<string>",
"description": "<string>",
"status": "draft",
"triggerType": "response.completed",
"surveyId": "<string>",
"createdBy": "<string>",
"creator": {
"name": "<string>"
},
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"lastRun": {
"id": "<string>",
"workflowId": "<string>",
"workspaceId": "<string>",
"workflowVersionId": "<string>",
"status": "queued",
"isDryRun": true,
"triggerType": "response.completed",
"surveyId": "<string>",
"responseId": "<string>",
"error": "<string>",
"attempt": 1,
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"startedAt": "2023-11-07T05:31:56Z",
"finishedAt": "2023-11-07T05:31:56Z"
},
"runCount": 1,
"definition": {
"trigger": {
"id": "<string>",
"type": "trigger",
"triggerType": "response.completed",
"config": {
"surveyId": "<string>",
"endingCardIds": []
},
"label": "<string>",
"ui": {
"position": {
"x": 123,
"y": 123
},
"collapsed": true
}
},
"entryNodeId": "<string>",
"schemaVersion": 1,
"nodes": [],
"edges": []
}
}
}{
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"type": "<string>",
"instance": "<string>",
"code": "ai_features_not_enabled",
"details": {},
"invalid_params": [
{
"name": "<string>",
"reason": "<string>",
"code": "dangling_reference",
"identifier": "<string>",
"referenceType": "block",
"missingId": "<string>",
"firstUsedAt": "<string>",
"conflictsWith": "<string>"
}
]
}{
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"type": "<string>",
"instance": "<string>",
"code": "ai_features_not_enabled",
"details": {},
"invalid_params": [
{
"name": "<string>",
"reason": "<string>",
"code": "dangling_reference",
"identifier": "<string>",
"referenceType": "block",
"missingId": "<string>",
"firstUsedAt": "<string>",
"conflictsWith": "<string>"
}
]
}{
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"type": "<string>",
"instance": "<string>",
"code": "ai_features_not_enabled",
"details": {},
"invalid_params": [
{
"name": "<string>",
"reason": "<string>",
"code": "dangling_reference",
"identifier": "<string>",
"referenceType": "block",
"missingId": "<string>",
"firstUsedAt": "<string>",
"conflictsWith": "<string>"
}
]
}{
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"type": "<string>",
"instance": "<string>",
"code": "ai_features_not_enabled",
"details": {},
"invalid_params": [
{
"name": "<string>",
"reason": "<string>",
"code": "dangling_reference",
"identifier": "<string>",
"referenceType": "block",
"missingId": "<string>",
"firstUsedAt": "<string>",
"conflictsWith": "<string>"
}
]
}{
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"type": "<string>",
"instance": "<string>",
"code": "ai_features_not_enabled",
"details": {},
"invalid_params": [
{
"name": "<string>",
"reason": "<string>",
"code": "dangling_reference",
"identifier": "<string>",
"referenceType": "block",
"missingId": "<string>",
"firstUsedAt": "<string>",
"conflictsWith": "<string>"
}
]
}{
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"type": "<string>",
"instance": "<string>",
"code": "ai_features_not_enabled",
"details": {},
"invalid_params": [
{
"name": "<string>",
"reason": "<string>",
"code": "dangling_reference",
"identifier": "<string>",
"referenceType": "block",
"missingId": "<string>",
"firstUsedAt": "<string>",
"conflictsWith": "<string>"
}
]
}Update a workflow
Updates human-facing workflow metadata and/or the workflow definition. Status changes are
handled by lifecycle endpoints (enable, disable, archive, unarchive) so the state
machine remains explicit. Provided fields replace the corresponding stored fields; this
endpoint does not implement JSON Patch.
name and description can be updated in any state except archived. The definition
can only be updated while the workflow is draft or disabled: the live version of an
enabled workflow is an immutable snapshot, so definition changes require disabling (or
moving to draft) first and re-enabling afterwards. Violations return 422 with code
invalid_workflow_state. A structurally invalid definition returns 400 with structured invalid_params; the referenced survey and ending cards are not verified here — that existence check runs when the workflow is enabled.
curl --request PATCH \
--url https://app.formbricks.com/api/v3/workflows/{workflowId} \
--header 'Content-Type: application/json' \
--cookie next-auth.session-token= \
--data '
{
"name": "<string>",
"description": "<string>"
}
'import requests
url = "https://app.formbricks.com/api/v3/workflows/{workflowId}"
payload = {
"name": "<string>",
"description": "<string>"
}
headers = {
"cookie": "next-auth.session-token=",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {cookie: 'next-auth.session-token=', 'Content-Type': 'application/json'},
body: JSON.stringify({name: '<string>', description: '<string>'})
};
fetch('https://app.formbricks.com/api/v3/workflows/{workflowId}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.formbricks.com/api/v3/workflows/{workflowId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'description' => '<string>'
]),
CURLOPT_COOKIE => "next-auth.session-token=",
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.formbricks.com/api/v3/workflows/{workflowId}"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"description\": \"<string>\"\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("cookie", "next-auth.session-token=")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://app.formbricks.com/api/v3/workflows/{workflowId}")
.header("cookie", "next-auth.session-token=")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"description\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.formbricks.com/api/v3/workflows/{workflowId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["cookie"] = 'next-auth.session-token='
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"description\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "<string>",
"workspaceId": "<string>",
"name": "<string>",
"description": "<string>",
"status": "draft",
"triggerType": "response.completed",
"surveyId": "<string>",
"createdBy": "<string>",
"creator": {
"name": "<string>"
},
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"lastRun": {
"id": "<string>",
"workflowId": "<string>",
"workspaceId": "<string>",
"workflowVersionId": "<string>",
"status": "queued",
"isDryRun": true,
"triggerType": "response.completed",
"surveyId": "<string>",
"responseId": "<string>",
"error": "<string>",
"attempt": 1,
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"startedAt": "2023-11-07T05:31:56Z",
"finishedAt": "2023-11-07T05:31:56Z"
},
"runCount": 1,
"definition": {
"trigger": {
"id": "<string>",
"type": "trigger",
"triggerType": "response.completed",
"config": {
"surveyId": "<string>",
"endingCardIds": []
},
"label": "<string>",
"ui": {
"position": {
"x": 123,
"y": 123
},
"collapsed": true
}
},
"entryNodeId": "<string>",
"schemaVersion": 1,
"nodes": [],
"edges": []
}
}
}{
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"type": "<string>",
"instance": "<string>",
"code": "ai_features_not_enabled",
"details": {},
"invalid_params": [
{
"name": "<string>",
"reason": "<string>",
"code": "dangling_reference",
"identifier": "<string>",
"referenceType": "block",
"missingId": "<string>",
"firstUsedAt": "<string>",
"conflictsWith": "<string>"
}
]
}{
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"type": "<string>",
"instance": "<string>",
"code": "ai_features_not_enabled",
"details": {},
"invalid_params": [
{
"name": "<string>",
"reason": "<string>",
"code": "dangling_reference",
"identifier": "<string>",
"referenceType": "block",
"missingId": "<string>",
"firstUsedAt": "<string>",
"conflictsWith": "<string>"
}
]
}{
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"type": "<string>",
"instance": "<string>",
"code": "ai_features_not_enabled",
"details": {},
"invalid_params": [
{
"name": "<string>",
"reason": "<string>",
"code": "dangling_reference",
"identifier": "<string>",
"referenceType": "block",
"missingId": "<string>",
"firstUsedAt": "<string>",
"conflictsWith": "<string>"
}
]
}{
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"type": "<string>",
"instance": "<string>",
"code": "ai_features_not_enabled",
"details": {},
"invalid_params": [
{
"name": "<string>",
"reason": "<string>",
"code": "dangling_reference",
"identifier": "<string>",
"referenceType": "block",
"missingId": "<string>",
"firstUsedAt": "<string>",
"conflictsWith": "<string>"
}
]
}{
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"type": "<string>",
"instance": "<string>",
"code": "ai_features_not_enabled",
"details": {},
"invalid_params": [
{
"name": "<string>",
"reason": "<string>",
"code": "dangling_reference",
"identifier": "<string>",
"referenceType": "block",
"missingId": "<string>",
"firstUsedAt": "<string>",
"conflictsWith": "<string>"
}
]
}{
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"type": "<string>",
"instance": "<string>",
"code": "ai_features_not_enabled",
"details": {},
"invalid_params": [
{
"name": "<string>",
"reason": "<string>",
"code": "dangling_reference",
"identifier": "<string>",
"referenceType": "block",
"missingId": "<string>",
"firstUsedAt": "<string>",
"conflictsWith": "<string>"
}
]
}Authorizations
NextAuth session JWT cookie. Development: often next-auth.session-token.
Production (HTTPS): often __Secure-next-auth.session-token. Send the cookie your browser receives after sign-in.
Path Parameters
Workflow identifier.
Body
Partial workflow update. name and description are accepted in any state except
archived; definition is only accepted while the workflow is draft or disabled.
status is intentionally not patchable — use the lifecycle endpoints.
1 - 120500Scope 1 workflow JSON document, mirroring ZWorkflowDefinition in packages/workflows. The
definition is the public source of truth for the builder and API clients. Scope 1
intentionally excludes user-authored if/else branches, webhook actions, schedules, delays,
loops, and AI/MCP-assisted creation; future node types extend nodes additively.
Graph rules enforced on every write (400 with invalid_params on violation):
node ids are unique across trigger and nodes; every edge references existing node ids;
the trigger has at most one outgoing edge; entryNodeId equals trigger.id. Trigger-only
drafts (no nodes, no edges) are valid persisted documents. Executability rules (exactly
one outgoing trigger edge, acyclic graph, every node reachable from the trigger) are
additionally enforced by enable and test with 422 workflow_not_executable.
Show child attributes
Show child attributes
Response
Workflow updated successfully
Full workflow shape returned by detail, create, update, duplicate, and lifecycle endpoints:
the list-item fields plus the complete definition document.
Show child attributes
Show child attributes
Was this page helpful?