curl --request POST \
--url https://app.formbricks.com/api/v3/workflows \
--header 'Content-Type: application/json' \
--cookie next-auth.session-token= \
--data '
{
"workspaceId": "clworkspace000000000000000",
"name": "Notify team after CSAT completion",
"description": "Sends an internal email when a respondent reaches the negative CSAT ending.",
"status": "draft",
"definition": {
"schemaVersion": 1,
"trigger": {
"id": "trigger",
"type": "trigger",
"triggerType": "response.completed",
"label": "CSAT survey completed",
"config": {
"surveyId": "clsurvey000000000000000000",
"endingCardIds": [
"clending000000000000000000"
]
}
},
"nodes": [
{
"id": "send-email",
"type": "action",
"actionType": "send_email",
"label": "Notify support team",
"config": {
"to": "[email protected]",
"from": "[email protected]",
"replyTo": [
"[email protected]"
],
"subject": "Thanks for your feedback",
"body": "We saw your feedback and will follow up soon.",
"attachResponseData": true,
"includeVariables": true,
"includeHiddenFields": false
},
"ui": {
"position": {
"x": 260,
"y": 120
}
}
}
],
"edges": [
{
"id": "edge-trigger-email",
"source": "trigger",
"target": "send-email"
}
],
"entryNodeId": "trigger"
}
}
'import requests
url = "https://app.formbricks.com/api/v3/workflows"
payload = {
"workspaceId": "clworkspace000000000000000",
"name": "Notify team after CSAT completion",
"description": "Sends an internal email when a respondent reaches the negative CSAT ending.",
"status": "draft",
"definition": {
"schemaVersion": 1,
"trigger": {
"id": "trigger",
"type": "trigger",
"triggerType": "response.completed",
"label": "CSAT survey completed",
"config": {
"surveyId": "clsurvey000000000000000000",
"endingCardIds": ["clending000000000000000000"]
}
},
"nodes": [
{
"id": "send-email",
"type": "action",
"actionType": "send_email",
"label": "Notify support team",
"config": {
"to": "[email protected]",
"from": "[email protected]",
"replyTo": ["[email protected]"],
"subject": "Thanks for your feedback",
"body": "We saw your feedback and will follow up soon.",
"attachResponseData": True,
"includeVariables": True,
"includeHiddenFields": False
},
"ui": { "position": {
"x": 260,
"y": 120
} }
}
],
"edges": [
{
"id": "edge-trigger-email",
"source": "trigger",
"target": "send-email"
}
],
"entryNodeId": "trigger"
}
}
headers = {
"cookie": "next-auth.session-token=",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {cookie: 'next-auth.session-token=', 'Content-Type': 'application/json'},
body: JSON.stringify({
workspaceId: 'clworkspace000000000000000',
name: 'Notify team after CSAT completion',
description: 'Sends an internal email when a respondent reaches the negative CSAT ending.',
status: 'draft',
definition: {
schemaVersion: 1,
trigger: {
id: 'trigger',
type: 'trigger',
triggerType: 'response.completed',
label: 'CSAT survey completed',
config: {
surveyId: 'clsurvey000000000000000000',
endingCardIds: ['clending000000000000000000']
}
},
nodes: [
{
id: 'send-email',
type: 'action',
actionType: 'send_email',
label: 'Notify support team',
config: {
to: '[email protected]',
from: '[email protected]',
replyTo: ['[email protected]'],
subject: 'Thanks for your feedback',
body: JSON.stringify('We saw your feedback and will follow up soon.'),
attachResponseData: true,
includeVariables: true,
includeHiddenFields: false
},
ui: {position: {x: 260, y: 120}}
}
],
edges: [{id: 'edge-trigger-email', source: 'trigger', target: 'send-email'}],
entryNodeId: 'trigger'
}
})
};
fetch('https://app.formbricks.com/api/v3/workflows', 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",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'workspaceId' => 'clworkspace000000000000000',
'name' => 'Notify team after CSAT completion',
'description' => 'Sends an internal email when a respondent reaches the negative CSAT ending.',
'status' => 'draft',
'definition' => [
'schemaVersion' => 1,
'trigger' => [
'id' => 'trigger',
'type' => 'trigger',
'triggerType' => 'response.completed',
'label' => 'CSAT survey completed',
'config' => [
'surveyId' => 'clsurvey000000000000000000',
'endingCardIds' => [
'clending000000000000000000'
]
]
],
'nodes' => [
[
'id' => 'send-email',
'type' => 'action',
'actionType' => 'send_email',
'label' => 'Notify support team',
'config' => [
'to' => '[email protected]',
'from' => '[email protected]',
'replyTo' => [
'[email protected]'
],
'subject' => 'Thanks for your feedback',
'body' => 'We saw your feedback and will follow up soon.',
'attachResponseData' => true,
'includeVariables' => true,
'includeHiddenFields' => false
],
'ui' => [
'position' => [
'x' => 260,
'y' => 120
]
]
]
],
'edges' => [
[
'id' => 'edge-trigger-email',
'source' => 'trigger',
'target' => 'send-email'
]
],
'entryNodeId' => 'trigger'
]
]),
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"
payload := strings.NewReader("{\n \"workspaceId\": \"clworkspace000000000000000\",\n \"name\": \"Notify team after CSAT completion\",\n \"description\": \"Sends an internal email when a respondent reaches the negative CSAT ending.\",\n \"status\": \"draft\",\n \"definition\": {\n \"schemaVersion\": 1,\n \"trigger\": {\n \"id\": \"trigger\",\n \"type\": \"trigger\",\n \"triggerType\": \"response.completed\",\n \"label\": \"CSAT survey completed\",\n \"config\": {\n \"surveyId\": \"clsurvey000000000000000000\",\n \"endingCardIds\": [\n \"clending000000000000000000\"\n ]\n }\n },\n \"nodes\": [\n {\n \"id\": \"send-email\",\n \"type\": \"action\",\n \"actionType\": \"send_email\",\n \"label\": \"Notify support team\",\n \"config\": {\n \"to\": \"[email protected]\",\n \"from\": \"[email protected]\",\n \"replyTo\": [\n \"[email protected]\"\n ],\n \"subject\": \"Thanks for your feedback\",\n \"body\": \"We saw your feedback and will follow up soon.\",\n \"attachResponseData\": true,\n \"includeVariables\": true,\n \"includeHiddenFields\": false\n },\n \"ui\": {\n \"position\": {\n \"x\": 260,\n \"y\": 120\n }\n }\n }\n ],\n \"edges\": [\n {\n \"id\": \"edge-trigger-email\",\n \"source\": \"trigger\",\n \"target\": \"send-email\"\n }\n ],\n \"entryNodeId\": \"trigger\"\n }\n}")
req, _ := http.NewRequest("POST", 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.post("https://app.formbricks.com/api/v3/workflows")
.header("cookie", "next-auth.session-token=")
.header("Content-Type", "application/json")
.body("{\n \"workspaceId\": \"clworkspace000000000000000\",\n \"name\": \"Notify team after CSAT completion\",\n \"description\": \"Sends an internal email when a respondent reaches the negative CSAT ending.\",\n \"status\": \"draft\",\n \"definition\": {\n \"schemaVersion\": 1,\n \"trigger\": {\n \"id\": \"trigger\",\n \"type\": \"trigger\",\n \"triggerType\": \"response.completed\",\n \"label\": \"CSAT survey completed\",\n \"config\": {\n \"surveyId\": \"clsurvey000000000000000000\",\n \"endingCardIds\": [\n \"clending000000000000000000\"\n ]\n }\n },\n \"nodes\": [\n {\n \"id\": \"send-email\",\n \"type\": \"action\",\n \"actionType\": \"send_email\",\n \"label\": \"Notify support team\",\n \"config\": {\n \"to\": \"[email protected]\",\n \"from\": \"[email protected]\",\n \"replyTo\": [\n \"[email protected]\"\n ],\n \"subject\": \"Thanks for your feedback\",\n \"body\": \"We saw your feedback and will follow up soon.\",\n \"attachResponseData\": true,\n \"includeVariables\": true,\n \"includeHiddenFields\": false\n },\n \"ui\": {\n \"position\": {\n \"x\": 260,\n \"y\": 120\n }\n }\n }\n ],\n \"edges\": [\n {\n \"id\": \"edge-trigger-email\",\n \"source\": \"trigger\",\n \"target\": \"send-email\"\n }\n ],\n \"entryNodeId\": \"trigger\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.formbricks.com/api/v3/workflows")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["cookie"] = 'next-auth.session-token='
request["Content-Type"] = 'application/json'
request.body = "{\n \"workspaceId\": \"clworkspace000000000000000\",\n \"name\": \"Notify team after CSAT completion\",\n \"description\": \"Sends an internal email when a respondent reaches the negative CSAT ending.\",\n \"status\": \"draft\",\n \"definition\": {\n \"schemaVersion\": 1,\n \"trigger\": {\n \"id\": \"trigger\",\n \"type\": \"trigger\",\n \"triggerType\": \"response.completed\",\n \"label\": \"CSAT survey completed\",\n \"config\": {\n \"surveyId\": \"clsurvey000000000000000000\",\n \"endingCardIds\": [\n \"clending000000000000000000\"\n ]\n }\n },\n \"nodes\": [\n {\n \"id\": \"send-email\",\n \"type\": \"action\",\n \"actionType\": \"send_email\",\n \"label\": \"Notify support team\",\n \"config\": {\n \"to\": \"[email protected]\",\n \"from\": \"[email protected]\",\n \"replyTo\": [\n \"[email protected]\"\n ],\n \"subject\": \"Thanks for your feedback\",\n \"body\": \"We saw your feedback and will follow up soon.\",\n \"attachResponseData\": true,\n \"includeVariables\": true,\n \"includeHiddenFields\": false\n },\n \"ui\": {\n \"position\": {\n \"x\": 260,\n \"y\": 120\n }\n }\n }\n ],\n \"edges\": [\n {\n \"id\": \"edge-trigger-email\",\n \"source\": \"trigger\",\n \"target\": \"send-email\"\n }\n ],\n \"entryNodeId\": \"trigger\"\n }\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>"
}
]
}Create a workflow
Creates a draft workflow. The workflow definition is the public source of truth used by
the dashboard and external clients, following the document-first pattern established by the
v3 Survey API. Runtime persistence, revision creation, and version snapshotting are
implementation details behind this contract.
Workflows are always created as drafts; use POST /api/v3/workflows/{workflowId}/enable to
make them respond to trigger events. Graph reference failures (duplicate node ids, edges
pointing at missing nodes, entryNodeId not referencing the trigger, unknown surveyId or
endingCardIds in the workspace) are rejected with 400 and structured invalid_params.
curl --request POST \
--url https://app.formbricks.com/api/v3/workflows \
--header 'Content-Type: application/json' \
--cookie next-auth.session-token= \
--data '
{
"workspaceId": "clworkspace000000000000000",
"name": "Notify team after CSAT completion",
"description": "Sends an internal email when a respondent reaches the negative CSAT ending.",
"status": "draft",
"definition": {
"schemaVersion": 1,
"trigger": {
"id": "trigger",
"type": "trigger",
"triggerType": "response.completed",
"label": "CSAT survey completed",
"config": {
"surveyId": "clsurvey000000000000000000",
"endingCardIds": [
"clending000000000000000000"
]
}
},
"nodes": [
{
"id": "send-email",
"type": "action",
"actionType": "send_email",
"label": "Notify support team",
"config": {
"to": "[email protected]",
"from": "[email protected]",
"replyTo": [
"[email protected]"
],
"subject": "Thanks for your feedback",
"body": "We saw your feedback and will follow up soon.",
"attachResponseData": true,
"includeVariables": true,
"includeHiddenFields": false
},
"ui": {
"position": {
"x": 260,
"y": 120
}
}
}
],
"edges": [
{
"id": "edge-trigger-email",
"source": "trigger",
"target": "send-email"
}
],
"entryNodeId": "trigger"
}
}
'import requests
url = "https://app.formbricks.com/api/v3/workflows"
payload = {
"workspaceId": "clworkspace000000000000000",
"name": "Notify team after CSAT completion",
"description": "Sends an internal email when a respondent reaches the negative CSAT ending.",
"status": "draft",
"definition": {
"schemaVersion": 1,
"trigger": {
"id": "trigger",
"type": "trigger",
"triggerType": "response.completed",
"label": "CSAT survey completed",
"config": {
"surveyId": "clsurvey000000000000000000",
"endingCardIds": ["clending000000000000000000"]
}
},
"nodes": [
{
"id": "send-email",
"type": "action",
"actionType": "send_email",
"label": "Notify support team",
"config": {
"to": "[email protected]",
"from": "[email protected]",
"replyTo": ["[email protected]"],
"subject": "Thanks for your feedback",
"body": "We saw your feedback and will follow up soon.",
"attachResponseData": True,
"includeVariables": True,
"includeHiddenFields": False
},
"ui": { "position": {
"x": 260,
"y": 120
} }
}
],
"edges": [
{
"id": "edge-trigger-email",
"source": "trigger",
"target": "send-email"
}
],
"entryNodeId": "trigger"
}
}
headers = {
"cookie": "next-auth.session-token=",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {cookie: 'next-auth.session-token=', 'Content-Type': 'application/json'},
body: JSON.stringify({
workspaceId: 'clworkspace000000000000000',
name: 'Notify team after CSAT completion',
description: 'Sends an internal email when a respondent reaches the negative CSAT ending.',
status: 'draft',
definition: {
schemaVersion: 1,
trigger: {
id: 'trigger',
type: 'trigger',
triggerType: 'response.completed',
label: 'CSAT survey completed',
config: {
surveyId: 'clsurvey000000000000000000',
endingCardIds: ['clending000000000000000000']
}
},
nodes: [
{
id: 'send-email',
type: 'action',
actionType: 'send_email',
label: 'Notify support team',
config: {
to: '[email protected]',
from: '[email protected]',
replyTo: ['[email protected]'],
subject: 'Thanks for your feedback',
body: JSON.stringify('We saw your feedback and will follow up soon.'),
attachResponseData: true,
includeVariables: true,
includeHiddenFields: false
},
ui: {position: {x: 260, y: 120}}
}
],
edges: [{id: 'edge-trigger-email', source: 'trigger', target: 'send-email'}],
entryNodeId: 'trigger'
}
})
};
fetch('https://app.formbricks.com/api/v3/workflows', 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",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'workspaceId' => 'clworkspace000000000000000',
'name' => 'Notify team after CSAT completion',
'description' => 'Sends an internal email when a respondent reaches the negative CSAT ending.',
'status' => 'draft',
'definition' => [
'schemaVersion' => 1,
'trigger' => [
'id' => 'trigger',
'type' => 'trigger',
'triggerType' => 'response.completed',
'label' => 'CSAT survey completed',
'config' => [
'surveyId' => 'clsurvey000000000000000000',
'endingCardIds' => [
'clending000000000000000000'
]
]
],
'nodes' => [
[
'id' => 'send-email',
'type' => 'action',
'actionType' => 'send_email',
'label' => 'Notify support team',
'config' => [
'to' => '[email protected]',
'from' => '[email protected]',
'replyTo' => [
'[email protected]'
],
'subject' => 'Thanks for your feedback',
'body' => 'We saw your feedback and will follow up soon.',
'attachResponseData' => true,
'includeVariables' => true,
'includeHiddenFields' => false
],
'ui' => [
'position' => [
'x' => 260,
'y' => 120
]
]
]
],
'edges' => [
[
'id' => 'edge-trigger-email',
'source' => 'trigger',
'target' => 'send-email'
]
],
'entryNodeId' => 'trigger'
]
]),
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"
payload := strings.NewReader("{\n \"workspaceId\": \"clworkspace000000000000000\",\n \"name\": \"Notify team after CSAT completion\",\n \"description\": \"Sends an internal email when a respondent reaches the negative CSAT ending.\",\n \"status\": \"draft\",\n \"definition\": {\n \"schemaVersion\": 1,\n \"trigger\": {\n \"id\": \"trigger\",\n \"type\": \"trigger\",\n \"triggerType\": \"response.completed\",\n \"label\": \"CSAT survey completed\",\n \"config\": {\n \"surveyId\": \"clsurvey000000000000000000\",\n \"endingCardIds\": [\n \"clending000000000000000000\"\n ]\n }\n },\n \"nodes\": [\n {\n \"id\": \"send-email\",\n \"type\": \"action\",\n \"actionType\": \"send_email\",\n \"label\": \"Notify support team\",\n \"config\": {\n \"to\": \"[email protected]\",\n \"from\": \"[email protected]\",\n \"replyTo\": [\n \"[email protected]\"\n ],\n \"subject\": \"Thanks for your feedback\",\n \"body\": \"We saw your feedback and will follow up soon.\",\n \"attachResponseData\": true,\n \"includeVariables\": true,\n \"includeHiddenFields\": false\n },\n \"ui\": {\n \"position\": {\n \"x\": 260,\n \"y\": 120\n }\n }\n }\n ],\n \"edges\": [\n {\n \"id\": \"edge-trigger-email\",\n \"source\": \"trigger\",\n \"target\": \"send-email\"\n }\n ],\n \"entryNodeId\": \"trigger\"\n }\n}")
req, _ := http.NewRequest("POST", 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.post("https://app.formbricks.com/api/v3/workflows")
.header("cookie", "next-auth.session-token=")
.header("Content-Type", "application/json")
.body("{\n \"workspaceId\": \"clworkspace000000000000000\",\n \"name\": \"Notify team after CSAT completion\",\n \"description\": \"Sends an internal email when a respondent reaches the negative CSAT ending.\",\n \"status\": \"draft\",\n \"definition\": {\n \"schemaVersion\": 1,\n \"trigger\": {\n \"id\": \"trigger\",\n \"type\": \"trigger\",\n \"triggerType\": \"response.completed\",\n \"label\": \"CSAT survey completed\",\n \"config\": {\n \"surveyId\": \"clsurvey000000000000000000\",\n \"endingCardIds\": [\n \"clending000000000000000000\"\n ]\n }\n },\n \"nodes\": [\n {\n \"id\": \"send-email\",\n \"type\": \"action\",\n \"actionType\": \"send_email\",\n \"label\": \"Notify support team\",\n \"config\": {\n \"to\": \"[email protected]\",\n \"from\": \"[email protected]\",\n \"replyTo\": [\n \"[email protected]\"\n ],\n \"subject\": \"Thanks for your feedback\",\n \"body\": \"We saw your feedback and will follow up soon.\",\n \"attachResponseData\": true,\n \"includeVariables\": true,\n \"includeHiddenFields\": false\n },\n \"ui\": {\n \"position\": {\n \"x\": 260,\n \"y\": 120\n }\n }\n }\n ],\n \"edges\": [\n {\n \"id\": \"edge-trigger-email\",\n \"source\": \"trigger\",\n \"target\": \"send-email\"\n }\n ],\n \"entryNodeId\": \"trigger\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.formbricks.com/api/v3/workflows")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["cookie"] = 'next-auth.session-token='
request["Content-Type"] = 'application/json'
request.body = "{\n \"workspaceId\": \"clworkspace000000000000000\",\n \"name\": \"Notify team after CSAT completion\",\n \"description\": \"Sends an internal email when a respondent reaches the negative CSAT ending.\",\n \"status\": \"draft\",\n \"definition\": {\n \"schemaVersion\": 1,\n \"trigger\": {\n \"id\": \"trigger\",\n \"type\": \"trigger\",\n \"triggerType\": \"response.completed\",\n \"label\": \"CSAT survey completed\",\n \"config\": {\n \"surveyId\": \"clsurvey000000000000000000\",\n \"endingCardIds\": [\n \"clending000000000000000000\"\n ]\n }\n },\n \"nodes\": [\n {\n \"id\": \"send-email\",\n \"type\": \"action\",\n \"actionType\": \"send_email\",\n \"label\": \"Notify support team\",\n \"config\": {\n \"to\": \"[email protected]\",\n \"from\": \"[email protected]\",\n \"replyTo\": [\n \"[email protected]\"\n ],\n \"subject\": \"Thanks for your feedback\",\n \"body\": \"We saw your feedback and will follow up soon.\",\n \"attachResponseData\": true,\n \"includeVariables\": true,\n \"includeHiddenFields\": false\n },\n \"ui\": {\n \"position\": {\n \"x\": 260,\n \"y\": 120\n }\n }\n }\n ],\n \"edges\": [\n {\n \"id\": \"edge-trigger-email\",\n \"source\": \"trigger\",\n \"target\": \"send-email\"\n }\n ],\n \"entryNodeId\": \"trigger\"\n }\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.
Body
1 - 120Scope 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
500New workflows are created as drafts in Scope 1.
draft Response
Workflow created 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?