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, so 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",
"scanned_pages": "ocr"
},
{
"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_file_ids": [],
"lookup_suggestion": null,
"lookup_reasoning_effort": null,
"lookup_file_uploads": [],
"use_images": false
}
],
"edges": [ { "source": "parse_1", "target": "extract_1", "branch": null } ]
}
Update Workflow
Replace a workflow’s typed graph atomically, echoing persistent_id to keep field identity across renames
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, so 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",
"scanned_pages": "ocr"
},
{
"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_file_ids": [],
"lookup_suggestion": null,
"lookup_reasoning_effort": null,
"lookup_file_uploads": [],
"use_images": false
}
],
"edges": [ { "source": "parse_1", "target": "extract_1", "branch": null } ]
}
{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. Earlier versions stay available for historical runs. v3 has no PUT.
Field identity: persistent_id
Every field in the GET response carries a server-assigned persistent_id. When you PATCH:
- Echo
persistent_idunchanged, including when you rename the field. The field then keeps its identity: analytics history, ground truth and quality metrics stay attached. - Omit it only for a brand-new field, and the server assigns one. A field without
persistent_idis always new. A name that matches a prior field confers no identity, so omitting it on an existing field replaces that field and detaches its history. - An echoed
persistent_idthat matches no field in the current version is rejected with400. - Sending back an unchanged graph cuts no new version.
persistent_ids just assigned to new fields. Edit that response and PATCH 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, on the same contract as Create workflow. The stored workflow stays 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, so 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",
"scanned_pages": "ocr"
},
{
"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_file_ids": [],
"lookup_suggestion": null,
"lookup_reasoning_effort": null,
"lookup_file_uploads": [],
"use_images": false
}
],
"edges": [ { "source": "parse_1", "target": "extract_1", "branch": null } ]
}
Authorizations
API key issued from app.anyformat.ai/api-key. Send as Authorization: Bearer <key>.
Path Parameters
Body
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. Restricts the node union to the public types (see
WorkflowCreateRequest). Call :meth:to_domain before forwarding to
the backend.
1"Invoice or receipt"
1- PublicParseNode
- ClassifyNode
- SplitterNode
- PublicExtractNode
- PublicValidateNode
- PublicIfElseNode
- PublicSlackAlertNode
- PublicEditNode
- KnowledgeNode
Show child attributes
Show child attributes
Show child attributes
Show child attributes
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.
Unique identifier of the workflow (hyphenated UUID).
"0686bb97-8c30-70f0-8000-97669e000eb8"
Human-readable name of the workflow.
"Invoice Processing"
Typed graph nodes (parse / classify / splitter / extract / validate / if_else).
- PublicParseNode
- ClassifyNode
- SplitterNode
- PublicExtractNode
- PublicValidateNode
- PublicIfElseNode
- PublicSlackAlertNode
- PublicEditNode
- KnowledgeNode
Show child attributes
Show child attributes
Optional description of what this workflow extracts.
"A workflow for processing invoices and retrieving invoice details."
Timestamp when the workflow was created (ISO 8601).
Timestamp when the workflow was last modified (ISO 8601).
Directed edges between the graph nodes.
Show child attributes
Show child attributes

