Skip to main content
PATCH
/
v3
/
workflows
/
{workflow_id}
/
curl -X PATCH 'https://api.anyformat.ai/v3/workflows/0686bb97-8c30-70f0-8000-97669e000eb8/' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Invoice Processing",
    "description": "Extract data from invoice documents",
    "nodes": [
      { "id": "parse_1", "type": "parse" },
      {
        "id": "extract_1",
        "type": "extract",
        "extraction_schema": {
          "fields": [
            {
              "name": "invoice_reference",
              "description": "The unique invoice identifier",
              "data_type": "string",
              "persistent_id": "8f14e45f-ceea-467f-a34e-9b6e2f7d3c1a"
            }
          ]
        }
      }
    ],
    "edges": [ { "source": "parse_1", "target": "extract_1" } ]
  }'
import requests

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

# GET → mutate → PATCH: rename a field, keep its persistent_id.
workflow = requests.get(url, headers=headers).json()
field = workflow["nodes"][1]["extraction_schema"]["fields"][0]
field["name"] = "invoice_reference"  # persistent_id stays — identity survives the rename

body = {k: workflow[k] for k in ("name", "description", "nodes", "edges")}
updated = requests.patch(url, headers=headers, json=body).json()
print(updated["updated_at"])
{
  "id": "0686bb97-8c30-70f0-8000-97669e000eb8",
  "name": "Invoice Processing",
  "description": "Extract data from invoice documents",
  "created_at": "2026-07-01T12:00:00.000Z",
  "updated_at": "2026-07-05T09:30:00.000Z",
  "nodes": [
    {
      "id": "parse_1",
      "type": "parse",
      "mode": "standard",
      "prompt_hint": null,
      "figure_enhancement": false,
      "cache": true,
      "effort": "mid",
      "ocr_effort": "high",
      "region": "eu",
      "skip_routing_review": true,
      "figures": false,
      "text_formatting": false,
      "routing_effort": null
    },
    {
      "id": "extract_1",
      "type": "extract",
      "mode": "standard",
      "extraction_schema": {
        "fields": [
          {
            "name": "invoice_reference",
            "description": "The unique invoice identifier",
            "data_type": "string",
            "persistent_id": "8f14e45f-ceea-467f-a34e-9b6e2f7d3c1a"
          }
        ]
      },
      "lookup_files": [],
      "lookup_suggestion": null,
      "lookup_reasoning_effort": null,
      "lookup_file_uploads": [],
      "lookup_schema": [],
      "use_images": false,
      "row_extractor_enabled": false,
      "page_sum_verification_enabled": false
    }
  ],
  "edges": [ { "source": "parse_1", "target": "extract_1" } ]
}
Rate limit tier: general (600 req/min) — see Rate limits. Replaces a workflow’s typed graph, atomically. The body is the {name, description, nodes, edges} sub-shape of GET /v3/workflows/{workflow_id}/ — the intended loop is GET → mutate → PATCH. Each update mints a new workflow version; previous versions remain available for historical runs. There is no PUT in v3.

Field identity: persistent_id

Every field in the GET response carries a server-assigned persistent_id. When you PATCH:
  • Echo persistent_id unchanged — including when you rename the field — and the field keeps its identity: analytics history, ground truth, and quality metrics stay attached.
  • Omit it only for brand-new fields; the server assigns one. A field without persistent_id is always treated as new — name coincidence with a prior field does not confer identity, so omitting it on an existing field replaces that field with a fresh one and detaches its history.
  • An echoed persistent_id that doesn’t match any field in the current version is rejected with 400.
  • Sending back an unchanged graph cuts no new version.
The response is the updated workflow in the exact GET shape — including the persistent_ids just assigned to new fields — so the result can be edited and PATCHed again. The echoed graph is this request’s own write result, never the state left by a concurrent update.
An invalid graph is rejected with 400 TOPOLOGY_INVALID (same contract as Create workflow); the stored workflow is untouched.
curl -X PATCH 'https://api.anyformat.ai/v3/workflows/0686bb97-8c30-70f0-8000-97669e000eb8/' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Invoice Processing",
    "description": "Extract data from invoice documents",
    "nodes": [
      { "id": "parse_1", "type": "parse" },
      {
        "id": "extract_1",
        "type": "extract",
        "extraction_schema": {
          "fields": [
            {
              "name": "invoice_reference",
              "description": "The unique invoice identifier",
              "data_type": "string",
              "persistent_id": "8f14e45f-ceea-467f-a34e-9b6e2f7d3c1a"
            }
          ]
        }
      }
    ],
    "edges": [ { "source": "parse_1", "target": "extract_1" } ]
  }'
import requests

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

# GET → mutate → PATCH: rename a field, keep its persistent_id.
workflow = requests.get(url, headers=headers).json()
field = workflow["nodes"][1]["extraction_schema"]["fields"][0]
field["name"] = "invoice_reference"  # persistent_id stays — identity survives the rename

body = {k: workflow[k] for k in ("name", "description", "nodes", "edges")}
updated = requests.patch(url, headers=headers, json=body).json()
print(updated["updated_at"])
{
  "id": "0686bb97-8c30-70f0-8000-97669e000eb8",
  "name": "Invoice Processing",
  "description": "Extract data from invoice documents",
  "created_at": "2026-07-01T12:00:00.000Z",
  "updated_at": "2026-07-05T09:30:00.000Z",
  "nodes": [
    {
      "id": "parse_1",
      "type": "parse",
      "mode": "standard",
      "prompt_hint": null,
      "figure_enhancement": false,
      "cache": true,
      "effort": "mid",
      "ocr_effort": "high",
      "region": "eu",
      "skip_routing_review": true,
      "figures": false,
      "text_formatting": false,
      "routing_effort": null
    },
    {
      "id": "extract_1",
      "type": "extract",
      "mode": "standard",
      "extraction_schema": {
        "fields": [
          {
            "name": "invoice_reference",
            "description": "The unique invoice identifier",
            "data_type": "string",
            "persistent_id": "8f14e45f-ceea-467f-a34e-9b6e2f7d3c1a"
          }
        ]
      },
      "lookup_files": [],
      "lookup_suggestion": null,
      "lookup_reasoning_effort": null,
      "lookup_file_uploads": [],
      "lookup_schema": [],
      "use_images": false,
      "row_extractor_enabled": false,
      "page_sum_verification_enabled": false
    }
  ],
  "edges": [ { "source": "parse_1", "target": "extract_1" } ]
}

Authorizations

Authorization
string
header
required

API key issued from app.anyformat.ai/api-key. Send as Authorization: Bearer <key>.

Path Parameters

workflow_id
string
required

Body

application/json

Public-surface workflow update body — full replacement of the typed graph.

Echo each existing field's persistent_id (from GET) unchanged — including across renames — to keep the field's identity; omit it for new fields. Thin subclass for OpenAPI naming (WorkflowUpdateRequest). Behaviour is fully inherited from WorkflowDefinition in anyformat.workflow.

name
string
required
Minimum string length: 1
Example:

"Invoice or receipt"

nodes
(ParseNode · object | ClassifyNode · object | SplitterNode · object | ExtractNode · object | ValidateNode · object)[]
required
Minimum array length: 1
description
string | null
default:""
edges
Edge · object[]

Response

Successful Response

A workflow with its complete typed graph inline.

{name, description, nodes, edges} is the exact shape POST /v3/workflows/ accepts — mutate it and feed it back to edit.

id
string
required

Unique identifier of the workflow (hyphenated UUID).

Example:

"0686bb97-8c30-70f0-8000-97669e000eb8"

name
string
required

Human-readable name of the workflow.

Example:

"Invoice Processing"

nodes
(ParseNode · object | ClassifyNode · object | SplitterNode · object | ExtractNode · object | ValidateNode · object)[]
required

Typed graph nodes (parse / classify / splitter / extract / validate).

description
string | null

Optional description of what this workflow extracts.

Example:

"A workflow for processing invoices and retrieving invoice details."

created_at
string<date-time> | null

Timestamp when the workflow was created (ISO 8601).

updated_at
string<date-time> | null

Timestamp when the workflow was last modified (ISO 8601).

edges
Edge · object[]

Directed edges between the graph nodes.