---
title: "Create workflow"
method: POST
path: "/workflows"
tags: ["Workflows"]
---

# Create workflow

`POST /workflows`

Create a new workflow in draft status. You can provide a minimal definition (just a start node) and build out the workflow later, or provide a complete workflow definition with all nodes and edges.

After creating a workflow, you can:
1. Update the definition to add more nodes/edges
2. Create triggers to specify when the workflow should execute
3. Activate the workflow by changing status to 'active'

## Request body

- WorkflowCreateRequest
  - `workflow` object, required
    - `name` string, required — Workflow name (must be unique within project)
    - `slug` string — Optional URL-safe identifier. Auto-generated from `name` if omitted. Lowercase alphanumeric with hyphens. Unique within the project.
    - `description` string, nullable — Optional workflow description
    - `definition` WorkflowDefinitionInput — Workflow graph write payload. Field names are snake_case. The expanded definition response includes persisted IDs such as edge IDs and condition IDs; those IDs are optional in write payloads.
      - `nodes` WorkflowDefinitionInputNode[] — Desired node set for the workflow. When `nodes` is present on create or update, it is treated as the complete node set: nodes omitted from the array are removed. Omit `nodes` to leave existing nodes unchanged on update.
        - `id` string, required — Stable step identifier used by edges. Use a readable identifier such as `send_intro`.
        - `type` string — Canvas renderer type. Use `flow-node`.
        - `position` WorkflowDefinitionNodePosition, required — Canvas position of the node.
          - `x` number, required — Horizontal canvas position.
          - `y` number, required — Vertical canvas position.
        - `data` WorkflowDefinitionInputNodeData, required — Node data write payload.
          - `node_type` 'start' | 'send_text' | 'send_template' | 'send_interactive' | 'wait_for_response' | 'decide' | 'function' | 'webhook' | 'agent' | 'call' | 'handoff' | 'set_variable' | 'emit_event', required — Canonical backend node type.
          - `config` union, required — Node configuration. Shape depends on `node_type`.
            - WorkflowNodeStartConfig — Empty config for the `start` node.
            - WorkflowNodeSendTextConfig — Config for `send_text` nodes.
              - …
            - WorkflowNodeSendTemplateConfig — Config for `send_template` nodes.
              - …
            - WorkflowNodeSendInteractiveConfig — Config for `send_interactive` nodes.
              - …
            - WorkflowNodeWaitForResponseConfig — Config returned for `wait_for_response` nodes.
              - …
            - WorkflowNodeDecideConfig — Config returned for `decide` nodes.
              - …
            - WorkflowNodeFunctionConfig — Config for `function` nodes.
              - …
            - WorkflowNodeWebhookConfig — Config for `webhook` nodes.
              - …
            - WorkflowNodeAgentConfig — Config returned for `agent` nodes.
              - …
            - WorkflowNodeCallConfig — Config returned for `call` nodes.
              - …
            - WorkflowNodeHandoffConfig — Config for `handoff` nodes.
              - …
            - WorkflowNodeSetVariableConfig — Config for `set_variable` nodes.
              - …
            - WorkflowNodeEmitEventConfig — Config for `emit_event` nodes.
              - …
          - `display_name` string — Optional human-friendly label shown in the visual editor.
      - `edges` WorkflowDefinitionInputEdge[] — Desired edge set for the workflow. When `edges` is present on create or update, it is treated as the complete edge set: edges omitted from the array are removed. Omit `edges` to leave existing edges unchanged on update.
        - `id` string, uuid — Optional existing edge ID. Usually omitted for new edges.
        - `source` string, required — Source node identifier.
        - `target` string, required — Target node identifier.
        - `label` string — Transition label. Use `next` for non-decision nodes. For decide nodes, this must match a condition label.
        - `type` string — Optional canvas edge renderer type. The API returns `default`.
        - `flow_condition_id` string, uuid, nullable — Optional persisted condition ID for decide-step edges. If omitted, the API resolves decide edges by `label`.

## Response `201`

Workflow created successfully

- WorkflowResponse — Single workflow response
  - `data` Workflow, required
    - `id` string, uuid, required — Unique workflow identifier
    - `name` string, required — Workflow name (unique per project)
    - `slug` string, required — URL-safe workflow identifier (lowercase alphanumeric with hyphens). Stable across renames — useful as an external sync key. Auto-generated from `name` on create if not provided. Unique within the project.
    - `description` string, nullable — Optional workflow description
    - `status` 'draft' | 'active' | 'archived', required — Workflow lifecycle status: - `draft`: Under development, not executable - `active`: Published and executable - `archived`: Inactive, no longer in use
    - `lock_version` integer, nullable — Optimistic locking version. Increment on each update to prevent concurrent modification conflicts. Include this value when updating to ensure you're working with the latest version.
    - `message_debounce_seconds` integer, nullable — Debounce window for incoming messages in seconds (default: 1). When a user sends multiple messages rapidly, the workflow waits this duration before processing to batch messages together. Prevents workflow from reacting to every keystroke.
    - `agent_default_tools_version` integer, nullable — Version used to decide which built-in agent tools are required by default for this workflow.
    - `inbound_message_read_mode` 'disabled' | 'read_only' | 'read_with_typing' — Controls how inbound WhatsApp messages are marked as read before the workflow responds (default: read_with_typing). - `disabled`: Do nothing — messages are not marked as read - `read_only`: Mark messages as read without showing a typing indicator - `read_with_typing`: Mark as read and show a typing indicator before responding
    - `created_at` string, date-time, required — Workflow creation timestamp
    - `updated_at` string, date-time, required — Last modification timestamp
    - `project_id` string, uuid — Project this workflow belongs to
    - `execution_count` integer — Total number of times this workflow has been executed
    - `last_executed_at` string, date-time, nullable — Timestamp of most recent execution, null if never executed

## Other responses

- `401` — Missing or invalid API key
- `422` — Request validation failed

---

[API](https://skmtc.net/kapso/apis/kapso-platform-api.md) · [All operations](https://skmtc.net/kapso/apis/kapso-platform-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/kapso/kapso-platform-api/revisions/18ff5548a33f/schema)
