# Delete a workflow

Deletes one workflow together with its trigger, its steps and its run history.

- Endpoint: `DELETE https://api.returning.ai/v1/workflow-builder/data-workflows/{workflowId}`
- Section: Workflow Builder / Workflows
- Authentication: `Authorization: Bearer <API_KEY>` (Community API key)
- Permission: `workflowBuilder`
- Retries: A retry after an ambiguous failure is safe in the sense that a second delete of a missing workflow answers `404` rather than deleting something else.
- Guide: generated from the published specification
- Last updated: 28 Oct 2026
- Web page: https://docs.returning.ai/api-reference/workflow-builder/delete-a-workflow

## 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 and a stale value is refused with `409 VERSION_CONFLICT` instead of deleting a workflow someone else has changed since; omit it and the delete applies as the last write. Deleting a deployed workflow needs no extra header: the delete applies immediately.

Deleting is a client-visible, irreversible change. Take an export first if the workflow should be recoverable.

| Failure | Meaning | Recovery |
| --- | --- | --- |
| `409 VERSION_CONFLICT` | Someone changed or already deleted it since your read | Re-read; if it is gone, the delete is effectively done. |

## Behaviour

It is irreversible: there is no restore route and no recycle bin.

A deployed workflow can be deleted like any other, in one call, with its trigger, steps and run history. Because that takes a live workflow out of service and leaves nothing to read back, `POST /{workflowId}/undeploy` first when the intent is to stop it rather than remove it.

## Request

### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `workflowId` | `string` | Yes | Workflow identifier: 24 hexadecimal characters, as returned in `_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 step, a branch or a whole workflow cannot be undone. Export first.
- A delete does not need an undeploy first, and it does not need a confirmation header. A deployed workflow is removed in one call, so the export and the second read in this page are the only protection there is.
- Run history goes with the workflow. Export anything you need to keep from `GET /{workflowId}/runs` before deleting.
- Deleting does not revoke a webhook key that was stored elsewhere. The key becomes useless once the trigger is gone, but stop senders as well.
- A delete is logged as one audit line with the workflow id, the operation and the revision before it. The body is never logged.

### Example request

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

### More examples

Export first when the definition matters:

```bash
curl --request GET \
  --url "https://api.returning.ai/v1/workflow-builder/data-workflows/65f1a2b3c4d5e6f708192a3b/export" \
  --header "Authorization: Bearer <API_KEY>" \
  --output vip-bonus.workflow.json
```

Then delete:

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

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

## Response

HTTP `200` with `data.deleted: true`. There is nothing left to read back on the workflow itself, so prove the delete with the list: `GET /` must no longer contain that `_id`, and `GET /{workflowId}` must answer `404 WORKFLOW_NOT_FOUND`. Runs of the workflow are removed with it, so `GET /{workflowId}/runs` also answers `404`.

The response carries no revision: a deleted workflow has none.

### 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": "65f1a2b3c4d5e6f708192a3b",
    "deleted": true
  }
}
```

## Errors

### Fix the request

| Status | Code | What to do |
| --- | --- | --- |
| 400 | `VALIDATION_FAILED` | The id is not 24 hexadecimal characters. Use the id 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 | `WORKFLOW_NOT_FOUND` | Unknown id, or another community's workflow. Nothing to delete; confirm with the list. |
| 409 | `VERSION_CONFLICT` | You sent an `If-Match` that is not the current revision. Re-read; retry only if the workflow still exists. |
| 409 | `WORKFLOW_LOCKED` | Another write to this workflow is in progress. Re-read; retry only if the workflow still exists. |

### 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 before retrying: a partial cascade is possible on a database failure, and the workflow may already be gone. |
| 503 | `LOCK_UNAVAILABLE` | The write lock store did not answer, so nothing was written. Retry shortly. |

**Retries:** A retry after an ambiguous failure is safe in the sense that a second delete of a missing workflow answers `404` rather than deleting something else. Do not switch to a new id to "make the delete work": confirm with `GET /` which id still exists. The cascade is not transactional. A failure part way through can leave the workflow row removed while a run record briefly remains; the records are scoped to the deleted id and are not reachable through any read.

## Next step

- [Duplicate a workflow](https://docs.returning.ai/api-reference/workflow-builder/duplicate-a-workflow.md): `POST /v1/workflow-builder/data-workflows/{workflowId}/duplicate`.
