> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anyformat.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# List Workflow Versions

> List a workflow's versions, newest first, for comparison and audit

*Rate limit tier: **general** (600 req/min) — see [Rate limits](/api-reference-v3/introduction#rate-limits).*

Returns one keyset page of a workflow's versions, newest first. Follow `next_cursor` until it is `null` — there are no totals or page numbers (see [Pagination](/api-reference-v3/introduction#pagination)). Every save that changes the graph mints a new version; item 0 of the first page is the version runs use.

Each item carries the `version_id` and the display number `major.minor.patch`. To read a version's graph, pass its `version_id` as `?version=` on [`GET /v3/workflows/{workflow_id}/`](/api-reference-v3/workflows/get).

<Note>
  **Versions are read-only.** They exist for comparison and audit. A run always uses the latest version, and a [`PATCH`](/api-reference-v3/workflows/update) always builds on the latest version — there is no way to run or restore an older version through the API.
</Note>

An unknown workflow, or one that belongs to another organization, answers `404` with `error_code: NOT_FOUND`.

## Compare two versions

List the versions, read two of them, and diff the field descriptions of the extract node:

```python Python (requests) theme={null}
import requests

workflow_id = "0686bb97-8c30-70f0-8000-97669e000eb8"
base = f"https://api.anyformat.ai/v3/workflows/{workflow_id}/"
headers = {"Authorization": "Bearer YOUR_API_KEY"}

versions = requests.get(f"{base}versions/", headers=headers).json()["items"]
latest, previous = versions[0], versions[1]


def field_descriptions(version_id):
    workflow = requests.get(base, headers=headers, params={"version": version_id}).json()
    extract = next(node for node in workflow["nodes"] if node["type"] == "extract")
    return {f["name"]: f["description"] for f in extract["extraction_schema"]["fields"]}


before = field_descriptions(previous["version_id"])
after = field_descriptions(latest["version_id"])
for name in sorted(before.keys() | after.keys()):
    if before.get(name) != after.get(name):
        print(f"{name}: {before.get(name)!r} -> {after.get(name)!r}")
```

<RequestExample>
  ```bash curl theme={null}
  curl -X GET 'https://api.anyformat.ai/v3/workflows/0686bb97-8c30-70f0-8000-97669e000eb8/versions/?limit=20' \
    -H 'Authorization: Bearer YOUR_API_KEY'
  ```

  ```python Python (requests) theme={null}
  import requests

  workflow_id = "0686bb97-8c30-70f0-8000-97669e000eb8"
  url = f"https://api.anyformat.ai/v3/workflows/{workflow_id}/versions/"
  headers = {"Authorization": "Bearer YOUR_API_KEY"}

  cursor = None
  while True:
      params = {"limit": 20, **({"cursor": cursor} if cursor else {})}
      page = requests.get(url, headers=headers, params=params).json()
      for version in page["items"]:
          print(version["version_id"], version["version"], version["created_at"])
      cursor = page["next_cursor"]
      if cursor is None:
          break
  ```
</RequestExample>

<ResponseExample>
  ```json Response (200 OK) theme={null}
  {
    "items": [
      {
        "version_id": "FGaV4I2JAA",
        "version": "1.2.0",
        "created_at": "2026-07-03T09:00:00.000Z"
      },
      {
        "version_id": "AbCdEfGhIj",
        "version": "1.1.0",
        "created_at": "2026-07-02T09:00:00.000Z"
      }
    ],
    "next_cursor": null
  }
  ```

  ```json Response (404 Not Found) theme={null}
  {
    "error": "Resource not found",
    "detail": "Workflow not found",
    "error_code": "NOT_FOUND",
    "retryable": false,
    "request_id": "a1b2c3d4e5f67890abcdef1234567890"
  }
  ```
</ResponseExample>
