Update a workflow
PATCH
/api/v1/workflows/{id}
workflows:write
MCP:
cascades_update_workflow
Partial update: only the keys present in the body change. To edit the
graph, read it with getWorkflow, modify the array, and send the full
definition back. PUT /workflows/{id} is accepted as an alias with
identical (partial) semantics.
Setting active: true from an account without production access is
refused with 403 activation_forbidden rather than silently
dropped. Requires workflows:write.
Path parameters
| Name | Type | Description |
|---|---|---|
idrequired |
integer |
Workflow id. Only workflows owned by the token's account resolve; a foreign or deleted id returns |
Request body
The fields to change. Omitted fields keep their current value.
-
namestring -
definitionCascadeDefinition Replacement node graph (the full array, not a diff). Read the current one with `getWorkflow` first. -
use_casestring, nullable -
trigger_typestring Unknown values are ignored (the current value is kept). One ofmanualeventscheduled -
activeboolean `true` activates, `false` makes it a draft. Activating requires production access (`403 activation_forbidden` otherwise).
Rename only
{
"name": "Tenant Screening — Premium"
}Make it a draft
{
"active": false
}Replace the node graph
{
"definition": [
{
"id": "step_applicant",
"type": "ApplicantSource",
"name": "Applicant",
"next_step": [
"step_approve"
]
},
{
"id": "step_approve",
"type": "Action",
"name": "Approve",
"action_type": "Approve"
}
]
}Responses
-
200 Updated workflow with definition
application/json-
dataWorkflowSchema: WorkflowDetail
-
idinteger required -
objectstring required -
codestring, nullable Short human-readable code assigned by Cascades. -
namestring required -
activeboolean required `true` = activated and triggerable in live mode. Drafts (`false`) can still be triggered in test mode. -
trigger_typestring required One ofmanualeventscheduled -
use_casestring, nullable -
created_atstring (date-time) -
updated_atstring (date-time) -
definitionarray of CascadeNode A cascade's node graph: an ordered array of `CascadeNode` objects. Exactly one `ApplicantSource` node is the entry point; every other node is reached through the edge keys (`next_step`, `pass_steps`, `human_review_steps`, `fail_steps`), each of which is an array of node `id`s that must resolve within the same array. An empty array is accepted on create/update (an empty draft) but cannot be run.Schema: CascadeDefinition
-
idstring required Unique within the definition, e.g. `step_credit`. Edge keys reference nodes by this value. -
typestring required One ofApplicantSourceBillingProductProductIfElseConditionWaitGoToShowResultsAction -
namestring Human-readable label shown in the builder and in `step_outputs`. -
next_steparray of string Default forward edge — ids of the node(s) to run next. -
billing_product_codestring `BillingProduct` / `Product` only. The product to pull, e.g. `EQF1003` (Equifax credit), `TUC1001` (TransUnion credit), `CIC4002` (criminal), `CIC4003` (eviction). May also be nested as `config.billing_product_code`. -
configobject Optional per-node configuration. `store_result_as` names the key under which a product's output is stored.-
store_result_asstring -
billing_product_codestring Alternative location for `billing_product_code`.
-
-
branchesobject `IfElse` / `Condition` only. Conditions for the `pass` branch and (optionally) the `human_review` branch; anything that matches neither takes `fail_steps`.-
passCascadeBranch A branch of an `IfElse` node — one or more condition groups combined with `group_logic`.Schema: CascadeBranch
-
group_logicstring How the condition groups combine. Defaults to `and`. One ofandor -
condition_groupsarray of object-
logicstring How the conditions inside this group combine. Defaults to `and`. One ofandor -
conditionsarray of CascadeCondition required-
source_node_idstring required The `id` of the product node whose output is compared. -
fieldstring required Exact output field path from that product's schema, e.g. `creditScore.fico9`. -
operatorstring required One ofequalsnot_equalsgreater_thangreater_than_or_equalless_thanless_than_or_equalcontainsnot_containsstarts_withends_withis_emptyis_not_emptyis_trueis_false -
valueone of The comparison value. Required for every operator except the unary ones (`is_empty`, `is_not_empty`, `is_true`, `is_false`), which accept `null` or no `value` at all.
-
-
-
-
human_reviewCascadeBranch A branch of an `IfElse` node — one or more condition groups combined with `group_logic`.Schema: CascadeBranch
-
group_logicstring How the condition groups combine. Defaults to `and`. One ofandor -
condition_groupsarray of object-
logicstring How the conditions inside this group combine. Defaults to `and`. One ofandor -
conditionsarray of CascadeCondition required-
source_node_idstring required The `id` of the product node whose output is compared. -
fieldstring required Exact output field path from that product's schema, e.g. `creditScore.fico9`. -
operatorstring required One ofequalsnot_equalsgreater_thangreater_than_or_equalless_thanless_than_or_equalcontainsnot_containsstarts_withends_withis_emptyis_not_emptyis_trueis_false -
valueone of The comparison value. Required for every operator except the unary ones (`is_empty`, `is_not_empty`, `is_true`, `is_false`), which accept `null` or no `value` at all.
-
-
-
-
-
pass_stepsarray of string `IfElse` only. Node ids to run when the `pass` branch matches. -
human_review_stepsarray of string `IfElse` only. Node ids to run when the `human_review` branch matches; the execution pauses with `needs_human_review: true` until a review decision resumes it. -
fail_stepsarray of string `IfElse` only. Node ids to run when no branch matches. -
action_typestring `Action` only. One ofApproveSendEmailAdverseActionInternalNotification -
emailobject `Action` with `action_type: SendEmail`. Fields support `{{variable}}` interpolation from the execution context.-
tostring -
subjectstring -
bodystring
-
-
adverse_actionobject `Action` with `action_type: AdverseAction`. `send_strategy: draft_first` parks the notice for human review before sending.-
recipientstring -
action_takenstring The action box ticked on the notice: `denied` (application denied), `revoked` (credit revoked or terms changed unfavorably), `adverse_employment` (adverse employment action) or `other_action`. Cascades the AI designer generates always use `denied`. One ofdeniedrevokedadverse_employmentother_action -
send_strategystring One ofdraft_firstauto_send -
reasonstring
-
-
internal_notificationobject `Action` with `action_type: InternalNotification`. Operator-facing notification settings. -
waitobject `Wait` only. The delay before the next node runs.-
durationnumber -
unitstring One ofsecondsminuteshoursdaysweeks
-
-
target_stepstring `GoTo` only. The node id to jump to.
-
-
-
metaMetaSchema: Meta
-
request_idstring required Correlation id for this request. Also sent as the `X-Request-Id` response header; quote it when contacting support.
-
200 example{ "data": { "id": 27, "object": "workflow", "code": "TSS-27", "name": "Tenant Screening Standard", "active": true, "trigger_type": "manual", "use_case": "tenant_screening", "created_at": "2026-05-08T18:41:05Z", "updated_at": "2026-05-08T18:41:05Z", "definition": [ { "id": "step_applicant", "type": "ApplicantSource", "name": "Applicant", "next_step": [ "step_credit" ] }, { "id": "step_credit", "type": "BillingProduct", "name": "Credit report", "billing_product_code": "EQF1003", "next_step": [ "step_score_check" ] }, { "id": "step_score_check", "type": "IfElse", "name": "Score at least 650?", "branches": { "pass": { "group_logic": "and", "condition_groups": [ { "logic": "and", "conditions": [ { "source_node_id": "step_credit", "field": "creditScore.fico9", "operator": "greater_than_or_equal", "value": 650 } ] } ] } }, "pass_steps": [ "step_approve" ], "fail_steps": [ "step_adverse_action" ] }, { "id": "step_approve", "type": "Action", "name": "Approve", "action_type": "Approve" }, { "id": "step_adverse_action", "type": "Action", "name": "Adverse action", "action_type": "AdverseAction", "adverse_action": { "recipient": "{{applicant.email}}", "action_taken": "denied", "send_strategy": "draft_first", "reason": "Credit score below the minimum required for this property." } } ] }, "meta": { "request_id": "7d4c2f48-9a1b-4c3d-8e2f-1a2b3c4d5e6f" } } -
-
400
malformed_bodyapplication/json400 example{ "error": { "code": "validation_failed", "message": "The request could not be processed.", "details": [ { "field": "execution_mode", "message": "must be test or live" } ], "request_id": "7d4c2f48-9a1b-4c3d-8e2f-1a2b3c4d5e6f", "doc_url": "https://cascades.crscreditapi.com/docs/api/errors/validation_failed" } } -
401 Missing, malformed, expired or revoked bearer token. The
WWW-Authenticateheader carries the RFC 6750 challenge.application/json401 example{ "error": { "code": "unauthorized", "message": "A valid bearer token is required.", "details": [], "request_id": "7d4c2f48-9a1b-4c3d-8e2f-1a2b3c4d5e6f", "doc_url": "https://cascades.crscreditapi.com/docs/api/errors/unauthorized" } } -
403
insufficient_scopeoractivation_forbiddenapplication/json403 example{ "error": { "code": "activation_forbidden", "message": "Activating a cascade requires production access. It stays a draft, which runs in test mode.", "details": [ { "field": "active", "message": "requires production access" } ], "request_id": "7d4c2f48-9a1b-4c3d-8e2f-1a2b3c4d5e6f", "doc_url": "https://cascades.crscreditapi.com/docs/api/errors/activation_forbidden" } } -
404 Resource does not exist or belongs to another tenant / api_client
application/json404 example{ "error": { "code": "not_found", "message": "The requested resource was not found.", "details": [], "request_id": "7d4c2f48-9a1b-4c3d-8e2f-1a2b3c4d5e6f", "doc_url": "https://cascades.crscreditapi.com/docs/api/errors/not_found" } } -
422
validation_failedapplication/json422 example{ "error": { "code": "validation_failed", "message": "The workflow could not be updated.", "details": [ { "field": "definition", "message": "can only have one Applicant Source node" } ], "request_id": "7d4c2f48-9a1b-4c3d-8e2f-1a2b3c4d5e6f", "doc_url": "https://cascades.crscreditapi.com/docs/api/errors/validation_failed" } } -
429 Rate limit exceeded (60 req/min per IP on
/api/v1, 600 req/hour per token prefix, or 300 req/5 min per IP globally). The body is the standard error envelope andRetry-Aftergives the seconds until the window resets.application/json429 example{ "error": { "code": "rate_limited", "message": "Rate limit exceeded. Retry later.", "details": [], "request_id": "7d4c2f48-9a1b-4c3d-8e2f-1a2b3c4d5e6f", "doc_url": "https://cascades.crscreditapi.com/docs/api/errors/rate_limited" } }