# Delete a step

Removes one step from a workflow.

- Endpoint: `DELETE https://api.returning.ai/v1/workflow-builder/data-workflows/{workflowId}/nodes/{nodeId}`
- Section: Workflow Builder / Steps
- Authentication: `Authorization: Bearer <API_KEY>` (Community API key)
- Permission: `workflowBuilder`
- Retries: A second delete of the same step answers `404 NODE_NOT_FOUND`, which is the same end state.
- Guide: generated from the published specification
- Last updated: 28 Oct 2026
- Web page: https://docs.returning.ai/api-reference/workflow-builder/delete-a-step

## Authentication

- Header: `Authorization: Bearer <API_KEY>`
- Permission: `workflowBuilder`

`Authorization: Bearer <API_KEY>` with `workflowBuilder`, on a workflow of the key's community. `If-Match` is optional. Send the `revision` you read to avoid overwriting a concurrent change (a stale value is refused with `409 VERSION_CONFLICT`); omit it and your write wins as the last one. A deployed workflow is edited with the same call: the change applies immediately.

| Failure | Meaning | Recovery |
| --- | --- | --- |
| `404 NODE_NOT_FOUND` | The step is not part of this workflow | Read the workflow for its step ids. |

## Behaviour

Deleting a router removes its branches and the steps inside them, and clears the branch pointers in one operation.

The delete is permanent, and references from later steps to the deleted step become unresolved until they are changed.

## Request

### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `workflowId` | `string` | Yes | Workflow identifier: 24 hexadecimal characters, as returned in `_id`. (`^[0-9a-fA-F]{24}$`) |
| `nodeId` | `string` | Yes | Step identifier: 24 hexadecimal characters, as returned in the step's `_id`. (`^[0-9a-fA-F]{24}$`) |

### Headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | `string` | Yes | Community API key: `Bearer <API_KEY>`. |
| `If-Match` | `string` | No | Optional. Send the `revision` the change is based on, bare or quoted, to avoid overwriting a concurrent change: a stale value is refused with `409 VERSION_CONFLICT`. Omit it for last-write-wins. |

### Watch for

- Deleting a router deletes every step in its branches. Those steps are not reattached anywhere.
- Deleting a step does not rewrite references in other steps. `POST /{workflowId}/validate` reports the dangling references as warnings and deploy still proceeds, so fix them before the next run.
- Run history is not rewritten. An old run still shows the deleted step's result under its old id.
- A delete cannot be undone. Export the workflow first if the step is worth recovering.

### Example request

```bash
curl --request DELETE \
  --url 'https://api.returning.ai/v1/workflow-builder/data-workflows/<workflowId>/nodes/<nodeId>' \
  --header 'Authorization: Bearer <API_KEY>'
```

### More examples

Delete a step, then check what now refers to nothing:

```bash
curl --request DELETE \
  --url "https://api.returning.ai/v1/workflow-builder/data-workflows/65f1a2b3c4d5e6f708192a3b/nodes/65f1a2b3c4d5e6f708192a3c" \
  --header "Authorization: Bearer <API_KEY>" \
  --header "If-Match: 162af81f5de4ff2b557a4087de9a9a73a0ed4e621f737787e35a93614cb50d1c"
```

```json
{
  "data": {
    "id": "65f1a2b3c4d5e6f708192a3c",
    "deleted": true
  }
}
```

## Response

HTTP `200` with `data.deleted: true`. There is no revision in this response, so the readback is a `GET /{workflowId}`: it returns the new revision, shows the step is absent, and shows its branch membership is gone from any router that listed it.

Run `POST /{workflowId}/validate` after the delete: a step that read the deleted step now reports `REFERENCE_UNRESOLVED`, and a router branch that listed it reports `NODE_NOT_IN_WORKFLOW`.

### Response fields

| Field | Type | Presence | Description |
| --- | --- | --- | --- |
| `data` | `object` | - | Deletion result. |
| `data.id` | `string` | - | Identifier of the deleted object. |
| `data.deleted` | `boolean` | - | Always `true` on a successful delete. |

### Example response (200)

```json
{
  "data": {
    "id": "65f1a2b3c4d5e6f708192a3c",
    "deleted": true
  }
}
```

## Errors

### Fix the request

| Status | Code | What to do |
| --- | --- | --- |
| 400 | `VALIDATION_FAILED` | An id is not 24 hexadecimal characters. Use the ids exactly as returned. |
| 401 | `AUTHENTICATION_REQUIRED` | No key, or an unknown key. Send a valid key. |
| 401 | `API_KEY_REQUIRED` | A valid admin session was used, because this API accepts community API keys only. Use a community API key. |
| 403 | `API_KEY_PERMISSION_DENIED` | No `workflowBuilder`. Grant the permission. |

### Fix the data

| Status | Code | What to do |
| --- | --- | --- |
| 404 | `NODE_NOT_FOUND` | The step is not part of this workflow. Confirm with `GET /{workflowId}`. |
| 409 | `VERSION_CONFLICT` | You sent an `If-Match` that is not the current revision. `meta.currentRevision` carries the live value. Re-read and resend. |
| 409 | `WORKFLOW_LOCKED` | Another write to this workflow held the lock for too long, and this write was not applied. Re-read and retry. |

### Retry with backoff

| Status | Code | What to do |
| --- | --- | --- |
| 429 | `RATE_LIMITED` | The community's API rate limit was reached. Wait for the window to reset, then retry. |
| 500 | `INTERNAL_ERROR` | Unexpected failure. Re-read the workflow: the step may already be gone. |
| 503 | `LOCK_UNAVAILABLE` | The write lock store did not answer, so nothing was written. Retry shortly. |

**Retries:** A second delete of the same step answers `404 NODE_NOT_FOUND`, which is the same end state. Do not create a replacement step to "make the retry work"; read the workflow instead.

## Next step

- [Reorder a main-line step](https://docs.returning.ai/api-reference/workflow-builder/reorder-a-main-line-step.md): `POST /v1/workflow-builder/data-workflows/{workflowId}/nodes/{nodeId}/move`.
