> For the complete documentation index, see [llms.txt](https://docs.roboflow.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.roboflow.com/developer/python-sdk/manage-workflows.md).

# Manage Workflows

[Roboflow Workflows](https://docs.roboflow.com/workflows/create-a-workflow) are visual computer-vision pipelines. The SDK exposes list / get / create directly on `Workspace`; update, fork, and delete live in the low-level `rfapi` adapter.

## List workflows

```python
import roboflow

rf = roboflow.Roboflow(api_key="YOUR_API_KEY")
workspace = rf.workspace()

workflows = workspace.list_workflows()
for w in workflows:
    print(w["id"], w["name"], w["url"])
```

## Get a workflow

```python
workflow = workspace.get_workflow("slow-webhooks")
print(workflow["specification"])
```

The `url` argument is the workflow's slug (visible in the web app's URL bar) - not its Firestore id.

## Create a workflow

```python
workflow = workspace.create_workflow(
    name="My Workflow",
    definition={
        "version": "1.0",
        "inputs": [...],
        "steps": [...],
        "outputs": [...],
    },
)
print(workflow["id"], workflow["url"])
```

Pass `definition=None` to create an empty workflow shell that you'll edit in the web app afterwards.

The SDK accepts either a bare specification dict (`{"version": ..., "steps": ...}`) or a wrapped one (`{"specification": {...}}`); it normalizes the wrapping for you and strips a UTF-8 BOM if present.

## Update a workflow

`Workspace` doesn't expose update directly - use the low-level adapter:

```python
from roboflow.adapters import rfapi

rfapi.update_workflow(
    api_key="YOUR_API_KEY",
    workspace_url=workspace.url,
    workflow_id=workflow["id"],
    workflow_name="My Workflow",
    workflow_url="my-workflow",
    config={"version": "1.0", "steps": [...]},
)
```

## Fork a workflow

Copy a workflow from another workspace into your own. Useful for adopting a public template:

```python
from roboflow.adapters import rfapi

forked = rfapi.fork_workflow(
    api_key="YOUR_API_KEY",
    workspace_url=workspace.url,
    source_workspace="other-workspace",
    source_workflow="their-workflow",
    name="My Fork",       # optional; defaults to the source name
    url="my-fork",        # optional; defaults to a generated slug
)
```

## List workflow versions

```python
versions = rfapi.list_workflow_versions(
    api_key="YOUR_API_KEY",
    workspace_url=workspace.url,
    workflow_url="my-workflow",
)
```

## Delete (soft-delete) a workflow

```python
rfapi.delete_workflow(api_key="YOUR_API_KEY", workspace_url=workspace.url, workflow_url="my-workflow")
```

This moves the workflow to the workspace [Trash](/developer/python-sdk/delete-and-restore.md) where it remains for 30 days before permanent cleanup. Restore via `Workspace.restore_from_trash("workflow", id)` - see [Delete and Restore](/developer/python-sdk/delete-and-restore.md#workflows).

## Run a workflow

Workflow execution lives in the [Inference SDK](https://inference.roboflow.com) and the [Workflows runtime](https://docs.roboflow.com/workflows/deploy-a-workflow), not the `roboflow` package. From Python:

```python
from inference_sdk import InferenceHTTPClient

client = InferenceHTTPClient(
    api_url="https://serverless.roboflow.com",
    api_key="YOUR_API_KEY",
)
result = client.run_workflow(
    workspace_name="my-workspace",
    workflow_id="my-workflow",
    images={"image": "photo.jpg"},
)
```

## REST and CLI equivalents

* REST: see [Manage Workflows](/developer/rest-api/manage-workflows.md).
* CLI: see [Manage Workflows (CLI)](/developer/command-line-interface/manage-workflows.md).
