> 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/workflows/manage/manage-workflows.md).

# Manage Workflows

## About

[Roboflow Workflows](/workflows/build/create-a-workflow.md) are visual computer-vision pipelines you build in the web app and deploy as a hosted endpoint. This page covers the management surface - listing, retrieving, creating, and updating the Workflows in a workspace - through the REST API and Python SDK. To run a Workflow against an image or video stream, see the [Workflows runtime docs](/workflows/deploy/deploy-a-workflow.md).

## HTTP API

[Roboflow Workflows](/workflows/build/create-a-workflow.md) are visual computer-vision pipelines you can build in the web app and deploy as a hosted endpoint. The REST API exposes the management surface; for executing a workflow against an image or video stream, see [Run a Model on an Image](https://docs.roboflow.com/deployment/roboflow-cloud/serverless-api#http-api) and the [Workflows runtime docs](/workflows/deploy/deploy-a-workflow.md).

`api_key` may be passed as a query parameter or in the request body. Required scopes are noted on each endpoint.

### Project Base Workflows

Each Project has a base Workflow that backs its hosted model endpoint. Use these Project-scoped operations to read that Workflow or select the model used by its model step.

#### Get a Project Base Workflow

<mark style="color:green;">`GET`</mark> `/:workspace/:project/deploy`

Required scope: `project:read`

```bash
curl "https://api.roboflow.com/my-workspace/my-project/deploy?api_key=$ROBOFLOW_API_KEY"
```

If the Project does not have a base Workflow, this request creates one. The response identifies the Project, its base Workflow, the selected model, its deployability, and its Active Learning state:

```json
{
  "project": {
    "id": "abc123",
    "url": "my-project",
    "name": "My Project",
    "owner": "my-workspace-id",
    "type": "object-detection",
    "classes": ["cat", "dog"],
    "multilabel": false
  },
  "workflow": {
    "id": "wf_xyz",
    "name": "My Project Base Workflow",
    "url": "my-project-base-workflow",
    "workspaceUrl": "my-workspace",
    "inferencePath": "/infer/workflows/my-workspace/my-project-base-workflow"
  },
  "model": {
    "id": "rfdetr-medium",
    "kind": "pretrained",
    "displayName": "RF-DETR Medium",
    "modelId": "rfdetr-medium"
  },
  "deployability": {
    "status": "deployable",
    "modelWasConfigured": false,
    "selectedModelId": null,
    "selectionReason": null
  },
  "activeLearning": {
    "enabled": false,
    "collectionLimits": {
      "dataPercentage": 100,
      "minutelyUsageLimit": 10,
      "hourlyUsageLimit": 100,
      "dailyUsageLimit": 1000,
      "labelingBatchesRecreationFrequency": "daily",
      "usageQuotaName": "upload_quota_active_learning",
      "imageCompressionLevel": 95,
      "maxImageHeight": 1080,
      "maxImageWidth": 1920,
      "persistPredictions": true
    },
    "filters": []
  },
  "baseWorkflowWasCreated": false
}
```

`model` is `null` when no model is configured. `deployability.status` is `"not_deployable"` when the Workflow cannot serve inference. `baseWorkflowWasCreated` tells you whether this request created the base Workflow.

#### Select a Project Base Workflow Model

<mark style="color:green;">`POST`</mark> `/:workspace/:project/deploy/model`

Required scope: `project:update`

Set `model.type` to `"model_id"`, `"sam3"`, or `"clip"`:

```bash
curl -X POST "https://api.roboflow.com/my-workspace/my-project/deploy/model" \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "'$ROBOFLOW_API_KEY'",
    "model": {
      "type": "model_id",
      "modelId": "rfdetr-medium"
    }
  }'
```

For `"model_id"`, `modelId` is required. `displayName` and `taskType` are optional. For `"sam3"` and `"clip"`, provide a non-empty `classes` array instead of `modelId`:

```json
{
  "api_key": "YOUR_API_KEY",
  "model": {
    "type": "sam3",
    "classes": ["cat", "dog"]
  }
}
```

The response has the same shape as [Get a Project Base Workflow](#get-a-project-base-workflow). A `400` response means the `model` value is missing or invalid.

To enable data collection, set collection limits, or list images in the review queue, use the [Active Learning HTTP API](https://docs.roboflow.com/deployment/monitoring-and-analytics/active-learning#http-api).

### List Workflows

<mark style="color:green;">`GET`</mark> `/:workspace/workflows`

Lists all workflows in the workspace.

**Query**

<table data-search="false"><thead><tr><th>Name</th><th>Type</th><th>Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td><code>api_key</code></td><td>string</td><td>API key for the workspace.</td><td>true</td></tr></tbody></table>

**Example Request**

```bash
curl "https://api.roboflow.com/my-workspace/workflows?api_key=$ROBOFLOW_API_KEY"
```

**Response**

```json
{
  "workflows": [
    {
      "id": "wf_abc123",
      "name": "Slow webhooks",
      "url": "slow-webhooks",
      "createdAt": "2026-04-12T17:05:33.000Z"
    }
  ],
  "status": "ok"
}
```

Required scope: `workflow:read`.

### Get a Workflow

<mark style="color:green;">`GET`</mark> `/:workspace/workflows/:workflowUrl`

Returns the workflow's specification, metadata, and (for non-public workflows) authorization status.

```bash
curl "https://api.roboflow.com/my-workspace/workflows/slow-webhooks?api_key=$ROBOFLOW_API_KEY"
```

Public workflows can be accessed without an `api_key`. Private workflows require the `workflow:read` scope.

### List Workflow Versions

<mark style="color:green;">`GET`</mark> `/:workspace/workflows/:workflowUrl/versions`

```bash
curl "https://api.roboflow.com/my-workspace/workflows/slow-webhooks/versions?api_key=$ROBOFLOW_API_KEY"
```

Returns the versioned snapshots of the workflow specification.

### Create a Workflow

<mark style="color:green;">`POST`</mark> `/:workspace/createWorkflow`

**Headers**

| Name         | Value              |
| ------------ | ------------------ |
| Content-Type | `application/json` |

**Body**

<table data-search="false"><thead><tr><th width="180">Name</th><th width="140">Type</th><th>Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td><code>api_key</code></td><td>string</td><td>Workspace API key.</td><td>true</td></tr><tr><td><code>name</code></td><td>string</td><td>Display name.</td><td>true</td></tr><tr><td><code>url</code></td><td>string</td><td>URL slug for the workflow.</td><td>true</td></tr><tr><td><code>config</code></td><td>string</td><td>JSON-encoded workflow specification (see note below).</td><td>true</td></tr><tr><td><code>template</code></td><td>string</td><td>JSON-encoded template metadata. Pass <code>"{}"</code> if you don't have one.</td><td>false</td></tr></tbody></table>

**Note on `config`**: the API expects the stored shape `{"specification": {...}}`. Passing a bare specification works through the SDK adapter, which auto-wraps it; for direct REST calls, wrap it yourself.

**Example Request**

```bash
curl -X POST "https://api.roboflow.com/my-workspace/createWorkflow" \
  -H 'Content-Type: application/json' \
  -d '{"api_key":"'$ROBOFLOW_API_KEY'","name":"My Workflow","url":"my-workflow","config":"{\"specification\":{\"version\":\"1.0\",\"inputs\":[],\"steps\":[],\"outputs\":[]}}"}'
```

You can also send the same fields as query parameters, but then `template` is required. Use the body for large specifications, since long URLs get cut off.

```bash
curl -X POST "https://api.roboflow.com/my-workspace/createWorkflow" \
  --get \
  --data-urlencode "api_key=$ROBOFLOW_API_KEY" \
  --data-urlencode "name=My Workflow" \
  --data-urlencode "url=my-workflow" \
  --data-urlencode 'config={"specification":{"version":"1.0","inputs":[],"steps":[],"outputs":[]}}' \
  --data-urlencode 'template={}'
```

**Response**

```json
{
  "workflows": { "id": "wf_xyz789", "url": "my-workflow" },
  "status": "ok"
}
```

Required scope: `workflow:create`.

### Update a Workflow

<mark style="color:green;">`POST`</mark> `/:workspace/updateWorkflow`

**Headers**

| Name         | Value              |
| ------------ | ------------------ |
| Content-Type | `application/json` |

**Body**

<table data-search="false"><thead><tr><th>Name</th><th>Type</th><th>Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td><code>id</code></td><td>string</td><td>Workflow's internal ID.</td><td>true</td></tr><tr><td><code>name</code></td><td>string</td><td>Display name.</td><td>true</td></tr><tr><td><code>url</code></td><td>string</td><td>URL slug.</td><td>true</td></tr><tr><td><code>config</code></td><td>string</td><td>JSON-encoded workflow specification (see note on Create).</td><td>true</td></tr></tbody></table>

```bash
curl -X POST "https://api.roboflow.com/my-workspace/updateWorkflow?api_key=$ROBOFLOW_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"id":"wf_xyz789","name":"My Workflow","url":"my-workflow","config":"{\"specification\":{\"version\":\"1.0\",\"steps\":[]}}"}'
```

Required scope: `workflow:update`.

### Fork a Workflow

<mark style="color:green;">`POST`</mark> `/:workspace/forkWorkflow`

Copy a workflow from another workspace into this one.

**Body**

<table data-search="false"><thead><tr><th>Name</th><th>Type</th><th>Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td><code>source_workspace</code></td><td>string</td><td>Slug of the workspace that owns the source workflow.</td><td>true</td></tr><tr><td><code>source_workflow</code></td><td>string</td><td>URL slug of the source workflow.</td><td>true</td></tr><tr><td><code>name</code></td><td>string</td><td>Display name for the fork. Defaults to source name.</td><td>false</td></tr><tr><td><code>url</code></td><td>string</td><td>URL slug for the fork. Auto-generated if omitted.</td><td>false</td></tr></tbody></table>

```bash
curl -X POST "https://api.roboflow.com/my-workspace/forkWorkflow?api_key=$ROBOFLOW_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"source_workspace":"other-workspace","source_workflow":"their-workflow","name":"My Fork","url":"my-fork"}'
```

Required scope: `workflow:create`.

### Generate a Workflow Token

<mark style="color:green;">`POST`</mark> `/:workspace/workflowToken`

Generate a short-lived token suitable for executing a workflow from a public client (e.g. a browser).

```bash
curl -X POST "https://api.roboflow.com/my-workspace/workflowToken?api_key=$ROBOFLOW_API_KEY"
```

### Delete (soft-delete) a Workflow

<mark style="color:red;">`DELETE`</mark> `/:workspace/workflows/:workflowUrl`

Moves the workflow to Trash. See [Manage Trash](https://docs.roboflow.com/platform/workspaces/trash#delete-a-workflow) for the response shape and restore flow.

### Run a Workflow

Workflow execution lives at `https://serverless.roboflow.com`, not the management API. See [Run a Model on an Image](https://docs.roboflow.com/deployment/roboflow-cloud/serverless-api#http-api) and the product docs on [deploying a workflow](/workflows/deploy/deploy-a-workflow.md).

## Python SDK

[Roboflow Workflows](/workflows/build/create-a-workflow.md) 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](https://docs.roboflow.com/platform/workspaces/trash#python-sdk) where it remains for 30 days before permanent cleanup. Restore via `Workspace.restore_from_trash("workflow", id)` - see [Delete and Restore](https://docs.roboflow.com/platform/workspaces/trash#workflows).

### Run a workflow

Workflow execution lives in the [Inference SDK](https://inference.roboflow.com) and the [Workflows runtime](/workflows/deploy/deploy-a-workflow.md), 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"},
)
```

## CLI

You can list, create, update, fork, and version workflows from the command line.

### List Workflows

```bash
roboflow workflow list
```

```bash
roboflow workflow list --json
```

### Get Workflow Details

```bash
roboflow workflow get my-workflow
```

```bash
roboflow workflow get my-workflow --json
```

### Create a Workflow

```bash
roboflow workflow create --name "My Workflow"
```

With a JSON definition file:

```bash
roboflow workflow create --name "My Workflow" --definition workflow.json
```

#### Options

| Flag            | Description                  |
| --------------- | ---------------------------- |
| `--name`        | Workflow name (required)     |
| `--definition`  | Path to JSON definition file |
| `--description` | Workflow description         |

### Update a Workflow

Update a workflow's definition:

```bash
roboflow workflow update my-workflow --definition updated.json
```

### List Workflow Versions

```bash
roboflow workflow version list my-workflow
```

```bash
roboflow workflow version list my-workflow --json
```

### Fork a Workflow

Fork a workflow from the current workspace:

```bash
roboflow workflow fork my-workflow
```

Fork from another workspace:

```bash
roboflow workflow fork other-workspace/their-workflow
```

### JSON Output

All workflow commands support `--json` for structured output:

```bash
roboflow workflow list --json | jq '.[].name'
roboflow workflow create --name "Test" --json
```

Exit codes: 0 = success, 1 = error, 2 = auth error, 3 = not found.

## MCP Server

Connect your AI agent to the [MCP Server](https://docs.roboflow.com/agents/mcp-server) and it can build and run Workflows with these tools:

<table data-search="false"><thead><tr><th width="290">Tool</th><th>Description</th></tr></thead><tbody><tr><td><code>workflows_list</code></td><td>List saved Workflows in the workspace.</td></tr><tr><td><code>workflows_get</code></td><td>Get details for a saved Workflow.</td></tr><tr><td><code>workflows_create</code></td><td>Create and save a new Workflow.</td></tr><tr><td><code>workflows_update</code></td><td>Update a saved Workflow's name and definition.</td></tr><tr><td><code>workflows_run</code></td><td>Execute a saved Workflow on one or more images.</td></tr><tr><td><code>workflows_delete</code></td><td>Delete a saved Workflow, moving it to the workspace Trash.</td></tr></tbody></table>
