Skip to main content
This page is transcribed from the API’s request schema. It lists the fields a public caller may set on each node of a workflow, with their type, whether they are required, and their default. The machine-readable form is the OpenAPI document at https://api.anyformat.ai/schema/. Each node’s guide page explains what the fields do and when to use them. A workflow body is { name, description, nodes, edges }. Every node carries an id (unique within the graph) and a type (the discriminator). The API rejects unknown keys on any node with 400 VALIDATION_ERROR, so a field that is not on this page is not accepted, even if the app shows it. Write only the fields you want to set. A GET echoes every node with every default filled in (for example "cache": true on a Parse node you created with only id and type), and every edge with "branch": null where you set none. That echoed shape is what PATCH accepts back.

parse

Reads the document and turns it into text, tables and layout. Every workflow has exactly one. Guide: Parse. A field that belongs to another tier is accepted and ignored. A GET also echoes "ocr_effort": "high": a retired lite-tier knob, accepted and ignored, kept on the wire for compatibility. Do not set it.
Echoed by GET:

extract

Pulls the fields of a schema out of the parsed document, each with a value, a confidence and evidence. Guide: Extract.
Echoed by GET. Every field carries the server-assigned persistent_id and its source; echo both back on PATCH:

classify

Labels the document as one of your categories and routes it down that category’s branch. Guide: Classify.

splitter

Breaks one file that holds several documents into pieces, one rule per piece, and routes each rule down its own branch. The wire type is splitter; the app calls it Split. Guide: Split.

validate

Checks the values an Extract node produced against your rules and records a verdict per rule. Guide: Validate.

if_else

Evaluates one check against the upstream extraction and routes the run down a true or a false branch. Guide: If/Else. The outgoing edges carry "branch": "true" and "branch": "false". The true edge is required; the false edge may be left unwired.

slack_alert

Posts a rendered message to a Slack channel at the end of a branch. It emits nothing downstream. Guide: Slack alert.

edit

Detects the fillable fields on the parsed PDF, fills them, and returns the filled PDF. Terminal: nothing accepts an edge from it. Guide: Edit.

knowledge

Indexes every document the workflow parses into a per-workflow knowledge base. Its presence is the switch; it has no options. At most one per workflow. Guide: Knowledge.

Shared types

ExtractionSchema and fields

extraction_schema is { "fields": [ ... ] } with at least one field. Every field carries these keys, plus the ones its data_type adds. See Field types for what each type extracts.

EnumOption

ClassifyCategory

SplitterRule

ValidationRule

A rule is either AI-evaluated (kind: "ai", a natural-language description) or deterministic (kind: "deterministic", a structured check). An ai rule must not carry a check; a deterministic rule must carry one.

Check

A check is a JSON object discriminated on type. Field operands are persistent_ids, except in expression, which addresses fields by name. Combinators nest.

LookupFileUpload

Edges

edges is a list of directed connections between node ids. A workflow with only a Parse node needs no edges. branch must equal a category id on a Classify node, a rule id on a Split node, or "true" / "false" on an If/Else node. It is the id, not the name. A GET echoes an edge you wrote as { "source", "target" } as { "source": "parse_1", "target": "extract_1", "branch": null }.

Topology rules

The API validates the whole graph on create and on update. A graph that breaks a rule is rejected with 400 and error_code: "TOPOLOGY_INVALID"; detail.violations[] names every rule broken and the node ids involved, so one round trip shows every problem. Which node may feed which: The graph-level rules:
  • Exactly one parse node.
  • Node ids are unique. Every edge names existing nodes. Every node except parse has an inbound edge. No cycles.
  • Only classify, splitter and if_else fan out. Every other node has at most one outgoing edge.
  • validate, if_else and slack_alert read one upstream extraction, so each accepts exactly one incoming edge. extract may receive several branches of one Classify node.
  • Each Split rule routes to its own target node. Two rules cannot share a target.
  • Within one node, category or rule ids are unique and names are unique. Two edges leaving the same node cannot carry the same branch.
  • Every if_else has a true outgoing edge.
  • An extract cannot sit downstream of an if_else today. That fan-out shape is not yet supported.
  • Every extract has at least one field.
  • At most one knowledge node.
  • Every rule_id in an if_else condition, and every ${validation.<rule_id>...} token in a slack_alert template, names a rule on a Validate node reachable upstream of that node.
  • edit is terminal: no node accepts an edge from it.