Replace the entire workflow
Only use this when you are authoring the whole graph. For an ordinary edit reach for PATCH .../workflow, POST .../outcomes/{outcome}/nodes or DELETE .../nodes/{nodeId} — they carry no graph, so they cannot overwrite one.
Whole-graph upsert (create-or-update). Replaces nodes, edges and dispositionEntries in one write. The graph is your additions on top of the built-in per-agent-type base pass (auto outcome-tagging, power-dialer, alerts) that runs on every call regardless of what you save here. Structure is validated (node types, edges, branch handles, acyclicity); per-node config is not required so partial drafts are accepted, and anything incomplete comes back in warnings. Pass expectedVersion for optimistic concurrency.
Omitting a field does not clear it. campaignConfig and a node’s coordinates are kept as stored when the request leaves them out, so a read-modify-write never silently discards settings you did not send. Send "campaignConfig": null to clear it on purpose.
Omitting a node does not delete it. A request that drops a node or an outcome entry that currently exists is rejected with 400, naming exactly what would be destroyed, unless you pass "allowRemovals": true.
This replaces the whole graph, so prefer a narrower endpoint when one fits. Whatever you send here overwrites nodes, edges and dispositionEntries outright, including any change someone else made after you read them. The narrower writes never carry a graph, so they cannot destroy one:
- add steps →
POST /outcomes/{outcome}/nodes(also derives the node ids, edge ids and branch handles this endpoint expects you to invent correctly) - change a step’s config, a setting, or both together →
PATCH /workflow(one write, so the pair cannot half-apply) - remove one step and re-link the chain →
DELETE /nodes/{nodeId}
Use this endpoint when you genuinely are authoring the whole graph, or for the things only it can do: saving an unconfigured draft node, repositioning, or editing an if/switch config.
Concurrency. Send expectedVersion and a write that lost the race is rejected with 409 instead of overwriting the winner — this is the only thing that protects you against your own read being stale, so send it. Without it, an API key is still guarded against the narrower window inside this request, but that will not save you from a graph that changed while you were editing.
Required API key scope: campaign_workflows:write.
Authorizations
Send your API key as Authorization: Bearer YOUR_API_KEY.
Path Parameters
Agent id.
1Query Parameters
Pair with campaignId; omit both for primary campaign.
1Pair with locationId; omit both for primary campaign.
1Body
Workflow nodes keyed by node id.
Directed connections between workflow nodes.
Maps each call outcome to the id of the node that starts its action chain. Keys are uppercase outcome constants: SUCCESS/BOOKED (booked), CONFIRMED (appointment confirmed), RESCHEDULE (rebooked), TRANSFER (live-transferred), TAG_APPLIED (tag objective met), CALLBACK (asked for a callback), INFO_ONLY/FOLLOWUP_REQUESTED (asked for information), HUMAN_NEEDED (asked for a person), VOICEMAIL/NO_ACTION (no outcome), KILL_SWITCH (opted out), FAILED_TRANSFER (transfer did not connect). Which outcomes an agent can emit depends on its type; the legal set per agent type is returned as dispositions by GET /api/v2/projects/systems. The value is the id of a node in nodes — the first node of your action chain for that outcome. The platform composes the canonical handler for each outcome automatically, so just attach your actions here; do not build your own trigger/detector nodes to re-detect a standard outcome.
INFO_ONLY and FOLLOWUP_REQUESTED are two spellings of the same outcome ("asked for information") and are treated as interchangeable at run time: outbound agent types emit INFO_ONLY and the inbound receptionist emits FOLLOWUP_REQUESTED, and a chain wired under either spelling fires for both. Use whichever the systems endpoint lists for your agent type.
A key no agent type can emit is accepted but never fires — the response reports it as an unknown_outcome warning rather than rejecting the write, because graphs predating a rename rely on being readable.
Campaign-level settings saved with the workflow. Documented fields cover supported campaign controls; additional keys (including canvas-only presentation state) are preserved for forward-compatible options.
Optimistic-concurrency guard: the write is rejected with 409 if the stored version has moved on.
x >= 03
Confirms that nodes and outcome entries missing from this request should be deleted. Without it, a request that would destroy existing nodes or outcome lanes is rejected with 400 listing them by id. Set it only when you have read the current graph and mean to drop those parts.
false
Response
The saved workflow.
