# Edit a workflow draft (/docs/api-reference/workflows/editWorkflow)

> Change the draft with a list of `ops`: add, update, move or delete nodes, and connect or disconnect them. The ops apply all together or not at all. You must send the `revision` from your last read. If you get `409 revision_conflict`, read the workflow again and retry. Secrets read back as `********`. Send them back unchanged to keep the stored value. This edits the draft only. Use `publishWorkflow` to make it live.


> **Workflow builder.** Included from the Jump Starter plan. [See plans](https://omnidim.io/pricing).

**PATCH** `/workflows/{workflow_id}`

Change the draft with a list of `ops`: add, update, move or delete nodes, and connect or disconnect them. The ops apply all together or not at all. You must send the `revision` from your last read. If you get `409 revision_conflict`, read the workflow again and retry. Secrets read back as `********`. Send them back unchanged to keep the stored value. This edits the draft only. Use `publishWorkflow` to make it live.

```yaml
operationId: editWorkflow
parameters:
  - in: path
    name: workflow_id
    required: true
    schema:
      type: integer
    description: Id of the workflow.
  - in: query
    name: user_id
    required: false
    description: |
      Reseller keys only: the id of one of your direct client users. The
      call then acts as that client, on that client's agents, numbers,
      campaigns and balance. Calls, sessions and bulk campaigns spend that
      client's balance and concurrency. Omit it to act on your own account.
      An empty value, `0`, `false` or your own user id also means your own
      account. Any other value that is not a positive integer id is
      refused with `400 invalid_request`. A key that is not a reseller's
      gets `403` when it names someone else. A user who is not your
      direct client gets `404`.
    schema:
      type: integer
      description: |
        Reseller keys only: the id of one of your direct client users. The
        call then acts as that client, on that client's agents, numbers,
        campaigns and balance. Calls, sessions and bulk campaigns spend that
        client's balance and concurrency. Omit it to act on your own account.
        Send it as a JSON integer in the body. `null`, `0`, `false` or your
        own user id also means your own account. Any other value that is not
        a positive integer id is refused with `400 invalid_request`. A key
        that is not a reseller's gets `403` when it names someone else. A
        user who is not your direct client gets `404`.
      example: 1234
requestBody:
  required: true
  content:
    application/json:
      schema:
        type: object
        required:
          - revision
          - ops
        properties:
          revision:
            type: string
            description: The `draft.revision` from your last `getWorkflow` or edit.
          ops:
            type: array
            items:
              type: object
              description: >
                One edit to the draft. Set `op` and the fields that op uses.

                | `op` | Fields | Effect |

                |---|---|---|

                | `add_node` | `id`, `type`, `label?`, `config?`, `after?`, `handle?`, `position?` |
                Adds a node. With `after`, it also connects it to that node (on output `handle`). |

                | `update_node` | `id`, `config?`, `label?` | Merges `config` keys into the node. A
                `null` value removes a key. |

                | `move_node` | `id`, `position` | Moves a node on the canvas. |

                | `delete_node` | `id` | Deletes a node and its edges. |

                | `connect` | `from`, `to`, `handle?` | Adds an edge. |

                | `disconnect` | `from`, `to`, `handle?` | Removes an edge. |
              required:
                - op
              properties:
                op:
                  type: string
                  enum:
                    - add_node
                    - update_node
                    - move_node
                    - delete_node
                    - connect
                    - disconnect
                id:
                  type: string
                  description: >-
                    Node id. For `add_node`, lowercase letters, digits and underscores, starting
                    with a letter. It must be new.
                type:
                  type: string
                  description: '`add_node`: a node type from `listWorkflowNodeTypes`.'
                label:
                  type: string
                  description: '`add_node`, `update_node`: the name shown on the canvas.'
                config:
                  type: object
                  additionalProperties: true
                  description: |
                    `add_node`, `update_node`: the node's settings. The fields come from
                    `getWorkflowNodeType`. Send a secret back as `********` to keep the
                    stored value.
                after:
                  type: string
                  description: '`add_node`: id of the node to connect the new node to.'
                handle:
                  type: string
                  description: >-
                    `add_node`, `connect`, `disconnect`: the output of the source node. Omit for the
                    default output.
                position:
                  type: object
                  description: >-
                    `add_node`, `move_node`: canvas position. `add_node` places the node for you if
                    you omit it.
                  properties:
                    x:
                      type: number
                    'y':
                      type: number
                from:
                  type: string
                  description: '`connect`, `disconnect`: id of the node the edge starts at.'
                to:
                  type: string
                  description: '`connect`, `disconnect`: id of the node the edge ends at.'
          name:
            type: string
            description: Rename the workflow.
responses:
  '200':
    description: The ops were applied.
    content:
      application/json:
        schema:
          type: object
          properties:
            revision:
              type: string
              description: The new revision. Use it for your next edit.
            issues:
              type: object
              description: |
                What validation found. Errors block publish. Warnings do not.
              properties:
                errors:
                  type: array
                  items:
                    type: object
                    description: One problem found in a draft.
                    properties:
                      code:
                        type: string
                        description: >
                          Stable issue code. `not_found`: an id is not in this workspace, pick one
                          with

                          `listWorkflowFieldOptions`. `templated_ref`: an id field holds a `{{ }}`
                          template; ids

                          must be literal. Others include `missing_field`, `bad_option`,
                          `bad_handle`,

                          `unreachable`, `trigger_count`, `unknown_type`, `unknown_reference` and
                          `malformed`.
                      message:
                        type: string
                      node:
                        type: string
                        nullable: true
                        description: Id of the node the issue is about, if any.
                      field:
                        type: string
                        nullable: true
                        description: Config field the issue is about, if any.
                      hint:
                        type: string
                        nullable: true
                        description: What to do to fix it.
                warnings:
                  type: array
                  items:
                    type: object
                    description: One problem found in a draft.
                    properties:
                      code:
                        type: string
                        description: >
                          Stable issue code. `not_found`: an id is not in this workspace, pick one
                          with

                          `listWorkflowFieldOptions`. `templated_ref`: an id field holds a `{{ }}`
                          template; ids

                          must be literal. Others include `missing_field`, `bad_option`,
                          `bad_handle`,

                          `unreachable`, `trigger_count`, `unknown_type`, `unknown_reference` and
                          `malformed`.
                      message:
                        type: string
                      node:
                        type: string
                        nullable: true
                        description: Id of the node the issue is about, if any.
                      field:
                        type: string
                        nullable: true
                        description: Config field the issue is about, if any.
                      hint:
                        type: string
                        nullable: true
                        description: What to do to fix it.
  '400':
    description: >-
      A bad parameter or body. `code` says which, such as `invalid_json`, `invalid_parameter`,
      `missing_fields` or `no_options`.
    content:
      application/json:
        schema:
          type: object
          description: |
            The v1 error envelope. Some errors add keys: `errors` (validation
            issues), `op_index` and `hint` (a refused op), `revision` (the current
            revision after a conflict).
          properties:
            error:
              type: string
              description: Machine-readable error code, such as `revision_conflict`.
            error_description:
              type: string
              description: Human-readable explanation.
            code:
              type: string
              description: Stable, specific reason. Present on 400 errors and auth errors.
            request_id:
              type: string
              description: >-
                Correlates this response with the server log. Also sent as the `X-Request-Id`
                header.
            errors:
              type: array
              description: On `validation_failed`, the issues that blocked the request.
              items:
                type: object
                description: One problem found in a draft.
                properties:
                  code:
                    type: string
                    description: >
                      Stable issue code. `not_found`: an id is not in this workspace, pick one with

                      `listWorkflowFieldOptions`. `templated_ref`: an id field holds a `{{ }}`
                      template; ids

                      must be literal. Others include `missing_field`, `bad_option`, `bad_handle`,

                      `unreachable`, `trigger_count`, `unknown_type`, `unknown_reference` and
                      `malformed`.
                  message:
                    type: string
                  node:
                    type: string
                    nullable: true
                    description: Id of the node the issue is about, if any.
                  field:
                    type: string
                    nullable: true
                    description: Config field the issue is about, if any.
                  hint:
                    type: string
                    nullable: true
                    description: What to do to fix it.
            op_index:
              type: integer
              description: On `invalid_op`, the zero-based position of the op that failed.
            hint:
              type: string
              description: On `invalid_op`, what to do next.
            revision:
              type: string
              description: On `revision_conflict`, the current revision of the draft.
        example:
          error: invalid_request
          error_description: revision is required. Read the workflow to get it.
          code: missing_fields
          request_id: req_5d9a1f3e8b02
  '401':
    description: Missing or invalid API key.
    content:
      application/json:
        schema:
          type: object
          description: |
            The v1 error envelope. Some errors add keys: `errors` (validation
            issues), `op_index` and `hint` (a refused op), `revision` (the current
            revision after a conflict).
          properties:
            error:
              type: string
              description: Machine-readable error code, such as `revision_conflict`.
            error_description:
              type: string
              description: Human-readable explanation.
            code:
              type: string
              description: Stable, specific reason. Present on 400 errors and auth errors.
            request_id:
              type: string
              description: >-
                Correlates this response with the server log. Also sent as the `X-Request-Id`
                header.
            errors:
              type: array
              description: On `validation_failed`, the issues that blocked the request.
              items:
                type: object
                description: One problem found in a draft.
                properties:
                  code:
                    type: string
                    description: >
                      Stable issue code. `not_found`: an id is not in this workspace, pick one with

                      `listWorkflowFieldOptions`. `templated_ref`: an id field holds a `{{ }}`
                      template; ids

                      must be literal. Others include `missing_field`, `bad_option`, `bad_handle`,

                      `unreachable`, `trigger_count`, `unknown_type`, `unknown_reference` and
                      `malformed`.
                  message:
                    type: string
                  node:
                    type: string
                    nullable: true
                    description: Id of the node the issue is about, if any.
                  field:
                    type: string
                    nullable: true
                    description: Config field the issue is about, if any.
                  hint:
                    type: string
                    nullable: true
                    description: What to do to fix it.
            op_index:
              type: integer
              description: On `invalid_op`, the zero-based position of the op that failed.
            hint:
              type: string
              description: On `invalid_op`, what to do next.
            revision:
              type: string
              description: On `revision_conflict`, the current revision of the draft.
        example:
          error: unauthorized
          error_description: Missing or invalid API key
          code: invalid_api_key
          request_id: req_6e2b9d4f1a38
  '403':
    description: |
      The Workflow Builder is not enabled for this account
      (`feature_not_enabled`), or your API key's user cannot make this
      change (`permission_denied`). The Workflow Builder must be included in
      your plan.
    content:
      application/json:
        schema:
          type: object
          description: |
            The v1 error envelope. Some errors add keys: `errors` (validation
            issues), `op_index` and `hint` (a refused op), `revision` (the current
            revision after a conflict).
          properties:
            error:
              type: string
              description: Machine-readable error code, such as `revision_conflict`.
            error_description:
              type: string
              description: Human-readable explanation.
            code:
              type: string
              description: Stable, specific reason. Present on 400 errors and auth errors.
            request_id:
              type: string
              description: >-
                Correlates this response with the server log. Also sent as the `X-Request-Id`
                header.
            errors:
              type: array
              description: On `validation_failed`, the issues that blocked the request.
              items:
                type: object
                description: One problem found in a draft.
                properties:
                  code:
                    type: string
                    description: >
                      Stable issue code. `not_found`: an id is not in this workspace, pick one with

                      `listWorkflowFieldOptions`. `templated_ref`: an id field holds a `{{ }}`
                      template; ids

                      must be literal. Others include `missing_field`, `bad_option`, `bad_handle`,

                      `unreachable`, `trigger_count`, `unknown_type`, `unknown_reference` and
                      `malformed`.
                  message:
                    type: string
                  node:
                    type: string
                    nullable: true
                    description: Id of the node the issue is about, if any.
                  field:
                    type: string
                    nullable: true
                    description: Config field the issue is about, if any.
                  hint:
                    type: string
                    nullable: true
                    description: What to do to fix it.
            op_index:
              type: integer
              description: On `invalid_op`, the zero-based position of the op that failed.
            hint:
              type: string
              description: On `invalid_op`, what to do next.
            revision:
              type: string
              description: On `revision_conflict`, the current revision of the draft.
        example:
          error: forbidden
          error_description: You do not have permission to use Workflows.
          code: feature_not_enabled
          request_id: req_9f2c1a4b7d3e
  '404':
    description: No workflow, node type or run with that id in your account.
    content:
      application/json:
        schema:
          type: object
          description: |
            The v1 error envelope. Some errors add keys: `errors` (validation
            issues), `op_index` and `hint` (a refused op), `revision` (the current
            revision after a conflict).
          properties:
            error:
              type: string
              description: Machine-readable error code, such as `revision_conflict`.
            error_description:
              type: string
              description: Human-readable explanation.
            code:
              type: string
              description: Stable, specific reason. Present on 400 errors and auth errors.
            request_id:
              type: string
              description: >-
                Correlates this response with the server log. Also sent as the `X-Request-Id`
                header.
            errors:
              type: array
              description: On `validation_failed`, the issues that blocked the request.
              items:
                type: object
                description: One problem found in a draft.
                properties:
                  code:
                    type: string
                    description: >
                      Stable issue code. `not_found`: an id is not in this workspace, pick one with

                      `listWorkflowFieldOptions`. `templated_ref`: an id field holds a `{{ }}`
                      template; ids

                      must be literal. Others include `missing_field`, `bad_option`, `bad_handle`,

                      `unreachable`, `trigger_count`, `unknown_type`, `unknown_reference` and
                      `malformed`.
                  message:
                    type: string
                  node:
                    type: string
                    nullable: true
                    description: Id of the node the issue is about, if any.
                  field:
                    type: string
                    nullable: true
                    description: Config field the issue is about, if any.
                  hint:
                    type: string
                    nullable: true
                    description: What to do to fix it.
            op_index:
              type: integer
              description: On `invalid_op`, the zero-based position of the op that failed.
            hint:
              type: string
              description: On `invalid_op`, what to do next.
            revision:
              type: string
              description: On `revision_conflict`, the current revision of the draft.
        example:
          error: not_found
          error_description: No workflow with that id.
          request_id: req_2c8e7a1d9b40
  '409':
    description: |
      `revision_conflict`: the draft changed since you read it. The body
      has the current `revision`. Read the workflow again, then retry.
      `no_draft` or `not_draft`: there is no draft to edit.
    content:
      application/json:
        schema:
          type: object
          description: |
            The v1 error envelope. Some errors add keys: `errors` (validation
            issues), `op_index` and `hint` (a refused op), `revision` (the current
            revision after a conflict).
          properties:
            error:
              type: string
              description: Machine-readable error code, such as `revision_conflict`.
            error_description:
              type: string
              description: Human-readable explanation.
            code:
              type: string
              description: Stable, specific reason. Present on 400 errors and auth errors.
            request_id:
              type: string
              description: >-
                Correlates this response with the server log. Also sent as the `X-Request-Id`
                header.
            errors:
              type: array
              description: On `validation_failed`, the issues that blocked the request.
              items:
                type: object
                description: One problem found in a draft.
                properties:
                  code:
                    type: string
                    description: >
                      Stable issue code. `not_found`: an id is not in this workspace, pick one with

                      `listWorkflowFieldOptions`. `templated_ref`: an id field holds a `{{ }}`
                      template; ids

                      must be literal. Others include `missing_field`, `bad_option`, `bad_handle`,

                      `unreachable`, `trigger_count`, `unknown_type`, `unknown_reference` and
                      `malformed`.
                  message:
                    type: string
                  node:
                    type: string
                    nullable: true
                    description: Id of the node the issue is about, if any.
                  field:
                    type: string
                    nullable: true
                    description: Config field the issue is about, if any.
                  hint:
                    type: string
                    nullable: true
                    description: What to do to fix it.
            op_index:
              type: integer
              description: On `invalid_op`, the zero-based position of the op that failed.
            hint:
              type: string
              description: On `invalid_op`, what to do next.
            revision:
              type: string
              description: On `revision_conflict`, the current revision of the draft.
        example:
          error: revision_conflict
          error_description: The workflow changed since you read it. Read it again, then retry.
          revision: 8c1d4e7a92f0
          request_id: req_7a3d9c2e5b18
  '422':
    description: |
      `invalid_op`: an op was refused. `op_index` and `hint` say which
      and why. `validation_failed`: the result would be unsafe to save,
      such as an unknown node type or an edge to a missing node. The
      problems are in `errors`. Nothing was saved.
    content:
      application/json:
        schema:
          type: object
          description: |
            The v1 error envelope. Some errors add keys: `errors` (validation
            issues), `op_index` and `hint` (a refused op), `revision` (the current
            revision after a conflict).
          properties:
            error:
              type: string
              description: Machine-readable error code, such as `revision_conflict`.
            error_description:
              type: string
              description: Human-readable explanation.
            code:
              type: string
              description: Stable, specific reason. Present on 400 errors and auth errors.
            request_id:
              type: string
              description: >-
                Correlates this response with the server log. Also sent as the `X-Request-Id`
                header.
            errors:
              type: array
              description: On `validation_failed`, the issues that blocked the request.
              items:
                type: object
                description: One problem found in a draft.
                properties:
                  code:
                    type: string
                    description: >
                      Stable issue code. `not_found`: an id is not in this workspace, pick one with

                      `listWorkflowFieldOptions`. `templated_ref`: an id field holds a `{{ }}`
                      template; ids

                      must be literal. Others include `missing_field`, `bad_option`, `bad_handle`,

                      `unreachable`, `trigger_count`, `unknown_type`, `unknown_reference` and
                      `malformed`.
                  message:
                    type: string
                  node:
                    type: string
                    nullable: true
                    description: Id of the node the issue is about, if any.
                  field:
                    type: string
                    nullable: true
                    description: Config field the issue is about, if any.
                  hint:
                    type: string
                    nullable: true
                    description: What to do to fix it.
            op_index:
              type: integer
              description: On `invalid_op`, the zero-based position of the op that failed.
            hint:
              type: string
              description: On `invalid_op`, what to do next.
            revision:
              type: string
              description: On `revision_conflict`, the current revision of the draft.
        example:
          error: invalid_op
          error_description: No node 'send_helo' in this workflow.
          op_index: 0
          hint: Read the workflow for its node ids.
          request_id: req_4b8f1e6a3c27
```

**cURL**

```bash
curl -X PATCH "https://backend.omnidim.io/api/v1/workflows/42" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "revision": "3f9a1c07be2d",
    "ops": [
      {"op": "add_node", "id": "send_hello", "type": "whatsapp", "after": "trigger",
       "config": {"message": "Hi {{ context.trigger.customer_number }}"}}
    ]
  }'
```

**curl**

```bash
curl -X PATCH "https://backend.omnidim.io/api/v1/workflows/{workflow_id}?user_id=1234" \
  -H "Authorization: Bearer $OMNIDIM_API_KEY"
```