> ## 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.

# Create Workflow

> Create a workflow from a typed graph of parse / classify / splitter / extract / validate nodes in a single atomic transaction

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

<Tip>
  We recommend creating workflows in the [anyformat platform](https://app.anyformat.ai), where you can visually configure fields, test with sample documents, and iterate faster. Once your workflow is ready, copy its ID and use it with the API to run documents programmatically.
</Tip>

Creates a workflow from a strongly-typed graph, atomically. The body is the same `{name, description, nodes, edges}` shape `POST /v2/workflows/` accepts — node types, field types, and validation rules are documented in depth on the [v2 create page](/api-reference/workflows/create) and in [Field types](/concepts/field-types); the graph model itself did not change in v3.

A body that violates graph topology (e.g. no parse node, an orphaned extract node) is rejected with `400 TOPOLOGY_INVALID`; `detail.violations` lists each broken rule with the offending node ids.

Fetch the stored graph back — with server-assigned `persistent_id`s on every field — via [`GET /v3/workflows/{workflow_id}/`](/api-reference-v3/workflows/get).

<RequestExample>
  ```bash curl theme={null}
  curl -X POST 'https://api.anyformat.ai/v3/workflows/' \
    -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_number", "description": "The unique invoice identifier", "data_type": "string" },
              { "name": "total_amount", "description": "Total invoice amount including tax", "data_type": "float" }
            ]
          }
        }
      ],
      "edges": [ { "source": "parse_1", "target": "extract_1" } ]
    }'
  ```

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

  url = "https://api.anyformat.ai/v3/workflows/"
  headers = {"Authorization": "Bearer YOUR_API_KEY"}

  body = {
      "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_number", "description": "The unique invoice identifier", "data_type": "string"},
                      {"name": "total_amount", "description": "Total invoice amount including tax", "data_type": "float"},
                  ]
              },
          },
      ],
      "edges": [{"source": "parse_1", "target": "extract_1"}],
  }

  workflow = requests.post(url, headers=headers, json=body).json()
  print(workflow["id"])
  ```
</RequestExample>

<ResponseExample>
  ```json Response (201 Created) theme={null}
  {
    "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-01T12:00:00.000Z"
  }
  ```

  ```json Response (400 — invalid topology) theme={null}
  {
    "error": "Validation failed",
    "detail": {
      "message": "Workflow graph has 1 violation",
      "violations": [
        {
          "rule": "single_parse_entrypoint",
          "message": "Exactly one parse node is required",
          "node_ids": []
        }
      ]
    },
    "error_code": "TOPOLOGY_INVALID",
    "retryable": false,
    "request_id": "a1b2c3d4e5f67890abcdef1234567890"
  }
  ```
</ResponseExample>


## OpenAPI

````yaml POST /v3/workflows/
openapi: 3.1.0
info:
  title: anyformat API
  description: >
    Document extraction and workflow automation API.


    AnyFormat lets you define extraction workflows that pull structured data
    from any document — PDFs, images, scanned files, or plain text. Upload a
    file, run it through a workflow, and get back structured fields with
    confidence scores and source evidence.


    ## Quick start


    See the [Quick start
    guide](https://docs.anyformat.ai/api-reference/introduction) for a
    walkthrough.


    ## Authentication


    All endpoints (except `/health/`) require a Bearer token in the
    `Authorization` header:


    ```

    Authorization: Bearer <your-api-key>

    ```


    Get your API key from
    [app.anyformat.ai/api-key](https://app.anyformat.ai/api-key).


    ## Versioning


    Endpoints are versioned by path prefix (`/v2/`, `/v3/`). Every response
    under

    a versioned prefix includes `X-API-Version`.
  version: 2.0.0
servers:
  - url: https://api.anyformat.ai
    description: API server
security: []
tags:
  - name: workflows
    description: >-
      Workflows define extraction templates — what fields to extract from
      documents. Create workflows, upload files, run extractions, and fetch
      results.
  - name: files
    description: >-
      File collections group uploaded documents and track their extraction
      progress. Upload files, check status, and retrieve extraction results.
  - name: suggestions
    description: >-
      AI-powered schema and workflow suggestion endpoints for the AnyFormat
      webapp. Authenticated with a Cognito JWT rather than an API key.
  - name: document-packets
    description: >-
      Document packets group uploaded documents for a workflow (v3). Address a
      packet directly to (re-)run its workflow.
  - name: runs
    description: >-
      Extraction runs — the v3 first-class result entity. Each run is a single
      execution of a workflow against a document packet; fetch its status and
      results flat by run id.
  - name: health
    description: Health check endpoints to verify API availability.
paths:
  /v3/workflows/:
    post:
      tags:
        - workflows
      summary: Create workflow
      description: |-
        Create a workflow from a strongly-typed graph (atomic).

        Provide an explicit list of typed `nodes` (parse / classify / splitter /
        extract / validate) and `edges` between them — the same body shape
        `POST /v2/workflows/` accepts. Fetch the stored graph back via
        `GET /v3/workflows/{workflow_id}/`.
      operationId: v3_create_workflow
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WorkflowCreateRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowSummaryV3'
          headers:
            X-RateLimit-Limit:
              description: Requests allowed per window (60s).
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
        '401':
          description: Authentication failed — missing, invalid, or expired API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              examples:
                AUTH_FAILED:
                  value:
                    error: Authentication failed.
                    detail: Authentication failed.
                    error_code: AUTH_FAILED
                    retryable: false
                    request_id: req_abc123
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          description: >-
            Rate limited — retry after the `Retry-After` header. Default
            windows: 60 requests/minute for extraction submission, 600
            requests/minute for general endpoints.
          headers:
            Retry-After:
              description: Seconds until the next request is allowed.
              schema:
                type: integer
            X-RateLimit-Limit:
              description: Requests allowed per window (60s).
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              examples:
                RATE_LIMITED:
                  value:
                    error: Rate limit exceeded — retry after backoff.
                    detail: Rate limit exceeded — retry after backoff.
                    error_code: RATE_LIMITED
                    retryable: true
                    request_id: req_abc123
      security:
        - ApiKeyAuth: []
components:
  schemas:
    WorkflowCreateRequest:
      properties:
        name:
          type: string
          minLength: 1
          title: Name
          examples:
            - Invoice or receipt
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
          default: ''
        nodes:
          items:
            oneOf:
              - $ref: '#/components/schemas/ParseNode'
              - $ref: '#/components/schemas/ClassifyNode'
              - $ref: '#/components/schemas/SplitterNode'
              - $ref: '#/components/schemas/ExtractNode'
              - $ref: '#/components/schemas/ValidateNode'
            discriminator:
              propertyName: type
              mapping:
                classify:
                  $ref: '#/components/schemas/ClassifyNode'
                extract:
                  $ref: '#/components/schemas/ExtractNode'
                parse:
                  $ref: '#/components/schemas/ParseNode'
                splitter:
                  $ref: '#/components/schemas/SplitterNode'
                validate:
                  $ref: '#/components/schemas/ValidateNode'
          type: array
          minItems: 1
          title: Nodes
        edges:
          items:
            $ref: '#/components/schemas/Edge'
          type: array
          title: Edges
      additionalProperties: false
      type: object
      required:
        - name
        - nodes
      title: WorkflowCreateRequest
      description: >-
        Public-surface workflow create body — typed graph of parse / classify /
        splitter / extract / validate nodes.


        A ``validate`` node carries ``rules``; each rule is either AI-evaluated

        (``kind="ai"`` + a natural-language ``description``) or deterministic

        (``kind="deterministic"`` + a structured ``check``, evaluated in pure

        Python with no model call).


        Defined as a thin subclass so the FastAPI-generated OpenAPI components

        entry is named ``WorkflowCreateRequest`` (FastAPI uses the model's

        ``__name__``). Behaviour is fully inherited from

        ``WorkflowDefinition`` in ``anyformat.workflow``.
      examples:
        - description: Pull the invoice number and total from each document.
          edges:
            - source: parse
              target: extract
          name: Invoice totals
          nodes:
            - id: parse
              mode: standard
              type: parse
            - extraction_schema:
                fields:
                  - data_type: string
                    description: Invoice number as printed on the document.
                    name: invoice_number
                  - data_type: float
                    description: Invoice total in the document's currency.
                    name: total_amount
              id: extract
              mode: standard
              type: extract
    WorkflowSummaryV3:
      properties:
        id:
          type: string
          title: Id
          description: Unique identifier of the workflow (hyphenated UUID).
          examples:
            - 0686bb97-8c30-70f0-8000-97669e000eb8
        name:
          type: string
          title: Name
          description: Human-readable name of the workflow.
          examples:
            - Invoice Processing
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
          description: Optional description of what this workflow extracts.
          examples:
            - A workflow for processing invoices and retrieving invoice details.
        created_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Created At
          description: Timestamp when the workflow was created (ISO 8601).
        updated_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Updated At
          description: Timestamp when the workflow was last modified (ISO 8601).
      type: object
      required:
        - id
        - name
      title: WorkflowSummaryV3
      description: Slim workflow projection returned by create and list.
    ErrorEnvelope:
      type: object
      title: ErrorEnvelope
      description: >-
        Uniform error response. `retryable=true` means the same request may
        succeed on retry (with backoff); `retryable=false` means the caller must
        change the request before retrying.
      required:
        - error
        - detail
        - error_code
        - retryable
        - request_id
      properties:
        error:
          type: string
          description: Short human-readable summary.
        detail:
          description: >-
            Machine-readable detail. String for most errors; list of field
            errors for validation failures.
          oneOf:
            - type: string
            - type: array
              items:
                type: object
        error_code:
          type: string
          description: Stable identifier for programmatic handling.
          examples:
            - VALIDATION_ERROR
            - AUTH_FAILED
            - NOT_FOUND
            - PRECONDITION_FAILED
            - RATE_LIMITED
            - INTERNAL_ERROR
            - GATEWAY_TIMEOUT
        retryable:
          type: boolean
          description: True when the caller should retry (with backoff for 429/412/5xx).
        request_id:
          type: string
          description: Correlates this response with server logs.
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    ParseNode:
      properties:
        id:
          type: string
          minLength: 1
          title: Id
          description: Stable identifier for this node within the graph.
        type:
          type: string
          const: parse
          title: Type
        mode:
          type: string
          enum:
            - standard
            - agentic
            - lite
          title: Mode
          description: >-
            Parse tier. 'standard' (default): page-by-page parsing with
            reading-order correction — the best quality/speed balance for most
            documents and tables. 'agentic': adaptive parsing that works hardest
            on dense tables (50+ rows, many columns) — highest fidelity on
            complex documents; extra cost per page. 'lite' (shown as 'Fast' in
            the app): OCR-first tier, fastest and cheapest — accurate OCR by
            default; set skip_routing_review=False to add a correction pass when
            reading order, figures, or text formatting matter.
          default: standard
        prompt_hint:
          anyOf:
            - type: string
            - type: 'null'
          title: Prompt Hint
          description: >-
            Free-form hint that biases the parse output. In lite mode it guides
            the correction pass, so it requires skip_routing_review=False.
        figure_enhancement:
          type: boolean
          title: Figure Enhancement
          description: >-
            Standard mode: extract structured data from charts and images —
            extra processing per figure. Ignored in agentic (figures are already
            handled) and in lite (use `figures` instead).
          default: false
        cache:
          type: boolean
          title: Cache
          description: >-
            Reuse parsed output when the same file was already parsed with the
            same mode and settings — a hit skips the whole parse. Disable to
            force a fresh parse.
          default: true
        effort:
          type: string
          enum:
            - low
            - mid
            - accurate
          title: Effort
          description: >-
            Agentic mode: quality/cost preset. 'low' = several times cheaper but
            more errors on dense or low-contrast tables, 'mid' (default) =
            balanced, 'accurate' = highest fidelity. (Distinct from lite
            `ocr_effort`.)
          default: mid
        ocr_effort:
          type: string
          enum:
            - medium
            - high
          title: Ocr Effort
          description: >-
            Lite mode: 'high' (default) = the strongest OCR — best accuracy on
            complex layouts, tables, and handwriting, and usually all a document
            needs. 'medium' = faster and cheaper, for clean digital documents.
            (Distinct from agentic `effort`.)
          default: high
        region:
          type: string
          enum:
            - eu
            - global
          title: Region
          description: >-
            Lite mode: OCR data-residency. 'eu' keeps processing in-region;
            'global' uses the hosted endpoint. Feature-flagged.
          default: eu
        skip_routing_review:
          type: boolean
          title: Skip Routing Review
          description: >-
            Lite mode: emit the OCR output as-is (the default — fastest and
            cheapest). Set False to add a correction pass that fixes reading
            order and OCR errors and rebuilds broken tables; while True,
            figures/text_formatting/routing_effort/prompt_hint are inert.
          default: true
        figures:
          type: boolean
          title: Figures
          description: >-
            Lite mode: the correction pass reads data points off charts/figures
            and reconstructs them as HTML tables (extra work on figure pages;
            needs skip_routing_review=False).
          default: false
        text_formatting:
          type: boolean
          title: Text Formatting
          description: >-
            Lite mode: the correction pass restores inline styling
            (bold/italic/superscript), code, and LaTeX math in text blocks
            (needs skip_routing_review=False).
          default: false
        routing_effort:
          anyOf:
            - type: string
              enum:
                - minimal
                - low
                - medium
                - high
            - type: 'null'
          title: Routing Effort
          description: >-
            Lite mode: effort of the correction pass's reading-order analysis —
            its dominant latency knob (None = the highest). Lower it to cut
            latency on simple layouts.
      additionalProperties: false
      type: object
      required:
        - id
        - type
      title: ParseNode
    ClassifyNode:
      properties:
        id:
          type: string
          minLength: 1
          title: Id
          description: Stable identifier for this node within the graph.
        type:
          type: string
          const: classify
          title: Type
        user_prompt:
          anyOf:
            - type: string
            - type: 'null'
          title: User Prompt
          description: >-
            Optional extra instructions inserted between the classifier's system
            prompt and the document text.
        categories:
          items:
            $ref: '#/components/schemas/ClassifyCategory'
          type: array
          minItems: 1
          title: Categories
      additionalProperties: false
      type: object
      required:
        - id
        - type
        - categories
      title: ClassifyNode
    SplitterNode:
      properties:
        id:
          type: string
          minLength: 1
          title: Id
          description: Stable identifier for this node within the graph.
        type:
          type: string
          const: splitter
          title: Type
        rules:
          items:
            $ref: '#/components/schemas/SplitterRule'
          type: array
          minItems: 1
          title: Rules
      additionalProperties: false
      type: object
      required:
        - id
        - type
        - rules
      title: SplitterNode
    ExtractNode:
      properties:
        id:
          type: string
          minLength: 1
          title: Id
          description: Stable identifier for this node within the graph.
        type:
          type: string
          const: extract
          title: Type
        mode:
          type: string
          enum:
            - standard
            - agentic
            - max
            - lite
          title: Mode
          description: >-
            Extraction tier. 'standard' (default): single-pass extraction — the
            best balance for simple documents and layouts. 'agentic': multi-step
            extraction that maps every table to the schema and reasons across
            sections — for dense or cross-page tables; extra cost per page.
            'max' (feature-gated): extracts table rows page by page with
            cross-page context tracking, then independently verifies row sums
            against document totals and re-extracts pages that don't reconcile —
            for multi-page invoices with complex row grouping. 'lite' (shown as
            'Fast' in the app): standard extraction, faster and cheaper; quality
            may vary on complex layouts.
          default: standard
        extraction_schema:
          $ref: '#/components/schemas/ExtractionSchema'
          description: Schema for the fields this node extracts. Required.
        lookup_files:
          items:
            type: string
          type: array
          title: Lookup Files
          description: Smart-lookup reference document URIs persisted on the extract node.
        lookup_suggestion:
          anyOf:
            - type: string
            - type: 'null'
          title: Lookup Suggestion
          description: Free-form hint shown to the smart-lookup matcher.
        lookup_reasoning_effort:
          anyOf:
            - type: string
              enum:
                - minimal
                - low
                - medium
                - high
            - type: 'null'
          title: Lookup Reasoning Effort
          description: >-
            Reasoning effort for the smart-lookup matcher (gpt-5 family):
            minimal | low | medium | high. None = model default. Higher effort
            improves match reliability on noisy join keys at higher
            latency/cost.
        lookup_file_uploads:
          items:
            $ref: '#/components/schemas/LookupFileUpload'
          type: array
          title: Lookup File Uploads
          description: >-
            Inline lookup-file content for the typed create call. Each entry is
            uploaded and the resulting URI is appended to ``lookup_files``; this
            field is create-input only.
        lookup_schema:
          items:
            oneOf:
              - $ref: '#/components/schemas/StringField'
              - $ref: '#/components/schemas/IntegerField'
              - $ref: '#/components/schemas/FloatField'
              - $ref: '#/components/schemas/BooleanField'
              - $ref: '#/components/schemas/DateField'
              - $ref: '#/components/schemas/DatetimeField'
              - $ref: '#/components/schemas/EnumField'
              - $ref: '#/components/schemas/MultiSelectField'
              - $ref: '#/components/schemas/ObjectField'
            discriminator:
              propertyName: data_type
              mapping:
                boolean:
                  $ref: '#/components/schemas/BooleanField'
                date:
                  $ref: '#/components/schemas/DateField'
                datetime:
                  $ref: '#/components/schemas/DatetimeField'
                enum:
                  $ref: '#/components/schemas/EnumField'
                float:
                  $ref: '#/components/schemas/FloatField'
                integer:
                  $ref: '#/components/schemas/IntegerField'
                multi_select:
                  $ref: '#/components/schemas/MultiSelectField'
                object:
                  $ref: '#/components/schemas/ObjectField'
                string:
                  $ref: '#/components/schemas/StringField'
          type: array
          title: Lookup Schema
          description: >-
            Typed schema of fields the smart-lookup pass should produce. Derived
            server-side from the workflow's smart-lookup fields; default empty
            for nodes without any.
        use_images:
          type: boolean
          title: Use Images
          description: >-
            Standard/lite modes: send each PDF page's rendered image alongside
            its parsed text so the model can read layout the text missed — adds
            vision cost on every page. No effect in agentic/max modes or on
            non-PDF sources.
          default: false
        row_extractor_enabled:
          type: boolean
          title: Row Extractor Enabled
          description: >-
            Extract table rows page by page, carrying context across page breaks
            so rows stay in their group ('max' mode implies this).
          default: false
        page_sum_verification_enabled:
          type: boolean
          title: Page Sum Verification Enabled
          description: >-
            After row extraction, independently re-check each page's rows
            against document totals and re-extract pages that don't reconcile
            ('max' mode implies this).
          default: false
      additionalProperties: false
      type: object
      required:
        - id
        - type
        - extraction_schema
      title: ExtractNode
    ValidateNode:
      properties:
        id:
          type: string
          minLength: 1
          title: Id
          description: Stable identifier for this node within the graph.
        type:
          type: string
          const: validate
          title: Type
        rules:
          items:
            $ref: '#/components/schemas/ValidationRule'
          type: array
          minItems: 1
          title: Rules
        field_index:
          anyOf:
            - additionalProperties:
                type: string
              type: object
            - type: 'null'
          title: Field Index
          description: >-
            Executor-injected at run time (persistent_id → field name); never
            set by callers or persisted.
      additionalProperties: false
      type: object
      required:
        - id
        - type
        - rules
      title: ValidateNode
    Edge:
      properties:
        source:
          type: string
          minLength: 1
          title: Source
        target:
          type: string
          minLength: 1
          title: Target
        branch:
          anyOf:
            - type: string
            - type: 'null'
          title: Branch
          description: >-
            Source-port label for branch routing. Required when leaving a
            classify or splitter node by category/rule.
      additionalProperties: false
      type: object
      required:
        - source
        - target
      title: Edge
      description: >-
        A directed edge between two nodes. ``branch`` carries the source-port
        label

        used for routing out of ``classify`` (category id) or ``splitter`` (rule
        id) nodes.
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
    ClassifyCategory:
      properties:
        id:
          type: string
          minLength: 1
          title: Id
          description: Stable category id used as the edge `branch` value when routing.
        name:
          type: string
          minLength: 1
          title: Name
          description: >-
            Display name shown to the LLM; classification and routing key off
            it, so it must be unique across categories.
        description:
          type: string
          minLength: 1
          title: Description
          description: Free-form description shown to the LLM.
      additionalProperties: false
      type: object
      required:
        - id
        - name
        - description
      title: ClassifyCategory
    SplitterRule:
      properties:
        id:
          type: string
          minLength: 1
          title: Id
        name:
          type: string
          minLength: 1
          title: Name
        description:
          type: string
          minLength: 1
          title: Description
        partition_key:
          type: string
          title: Partition Key
          description: >-
            Field that further partitions this category into separate
            sub-documents (e.g. invoice_number): each distinct value becomes its
            own split, extracted independently. Empty = routing-only, the whole
            category flows on as one document.
          default: ''
      additionalProperties: false
      type: object
      required:
        - id
        - name
        - description
      title: SplitterRule
    ExtractionSchema:
      properties:
        fields:
          items:
            oneOf:
              - $ref: '#/components/schemas/StringField'
              - $ref: '#/components/schemas/IntegerField'
              - $ref: '#/components/schemas/FloatField'
              - $ref: '#/components/schemas/BooleanField'
              - $ref: '#/components/schemas/DateField'
              - $ref: '#/components/schemas/DatetimeField'
              - $ref: '#/components/schemas/EnumField'
              - $ref: '#/components/schemas/MultiSelectField'
              - $ref: '#/components/schemas/ObjectField'
            discriminator:
              propertyName: data_type
              mapping:
                boolean:
                  $ref: '#/components/schemas/BooleanField'
                date:
                  $ref: '#/components/schemas/DateField'
                datetime:
                  $ref: '#/components/schemas/DatetimeField'
                enum:
                  $ref: '#/components/schemas/EnumField'
                float:
                  $ref: '#/components/schemas/FloatField'
                integer:
                  $ref: '#/components/schemas/IntegerField'
                multi_select:
                  $ref: '#/components/schemas/MultiSelectField'
                object:
                  $ref: '#/components/schemas/ObjectField'
                string:
                  $ref: '#/components/schemas/StringField'
          type: array
          minItems: 1
          title: Fields
          description: Field definitions making up this extract's output.
      additionalProperties: false
      type: object
      required:
        - fields
      title: ExtractionSchema
      description: |-
        Schema describing what an extract node produces.

        Modeled as a typed object (not a bare ``list[AnyField]``) so metadata
        can be added later (versioning, derived flags, output-shape hints)
        without another wire-format break. At least one field is required.
    LookupFileUpload:
      properties:
        filename:
          type: string
          minLength: 1
          title: Filename
        content:
          type: string
          minLength: 1
          title: Content
          description: Base64-encoded file bytes.
      additionalProperties: false
      type: object
      required:
        - filename
        - content
      title: LookupFileUpload
      description: |-
        Inline lookup-file content carried on the typed create call.

        The backend reads ``filename`` + ``content`` (base64-encoded bytes),
        uploads the file, and stores the resulting URI in
        ``ExtractNode.lookup_files``. Create-input only — not persisted on
        the node after upload.
    StringField:
      properties:
        persistent_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Persistent Id
          description: >-
            Server-assigned stable field identity (UUID), emitted by GET
            /definition/. Echo it back on updates — including across renames —
            to keep quality metrics, ground-truth links and analytics attached
            to the field. Matching is scoped to the field's nesting level in the
            immediately-prior version; an id that matches nothing at its level,
            appears on more than one field, or is sent at workflow creation is
            rejected with 400. Omit for new fields; when omitted on an update,
            the server matches the field to the prior version by name.
        name:
          type: string
          minLength: 1
          title: Name
          description: Field name. Used as the key in the extraction response.
        description:
          type: string
          title: Description
          description: Free-form description shown to the extraction model.
          default: ''
        lookup:
          type: boolean
          title: Lookup
          default: false
        data_type:
          type: string
          const: string
          title: Data Type
      additionalProperties: false
      type: object
      required:
        - name
        - data_type
      title: StringField
    IntegerField:
      properties:
        persistent_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Persistent Id
          description: >-
            Server-assigned stable field identity (UUID), emitted by GET
            /definition/. Echo it back on updates — including across renames —
            to keep quality metrics, ground-truth links and analytics attached
            to the field. Matching is scoped to the field's nesting level in the
            immediately-prior version; an id that matches nothing at its level,
            appears on more than one field, or is sent at workflow creation is
            rejected with 400. Omit for new fields; when omitted on an update,
            the server matches the field to the prior version by name.
        name:
          type: string
          minLength: 1
          title: Name
          description: Field name. Used as the key in the extraction response.
        description:
          type: string
          title: Description
          description: Free-form description shown to the extraction model.
          default: ''
        lookup:
          type: boolean
          title: Lookup
          default: false
        data_type:
          type: string
          const: integer
          title: Data Type
      additionalProperties: false
      type: object
      required:
        - name
        - data_type
      title: IntegerField
    FloatField:
      properties:
        persistent_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Persistent Id
          description: >-
            Server-assigned stable field identity (UUID), emitted by GET
            /definition/. Echo it back on updates — including across renames —
            to keep quality metrics, ground-truth links and analytics attached
            to the field. Matching is scoped to the field's nesting level in the
            immediately-prior version; an id that matches nothing at its level,
            appears on more than one field, or is sent at workflow creation is
            rejected with 400. Omit for new fields; when omitted on an update,
            the server matches the field to the prior version by name.
        name:
          type: string
          minLength: 1
          title: Name
          description: Field name. Used as the key in the extraction response.
        description:
          type: string
          title: Description
          description: Free-form description shown to the extraction model.
          default: ''
        lookup:
          type: boolean
          title: Lookup
          default: false
        data_type:
          type: string
          const: float
          title: Data Type
      additionalProperties: false
      type: object
      required:
        - name
        - data_type
      title: FloatField
    BooleanField:
      properties:
        persistent_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Persistent Id
          description: >-
            Server-assigned stable field identity (UUID), emitted by GET
            /definition/. Echo it back on updates — including across renames —
            to keep quality metrics, ground-truth links and analytics attached
            to the field. Matching is scoped to the field's nesting level in the
            immediately-prior version; an id that matches nothing at its level,
            appears on more than one field, or is sent at workflow creation is
            rejected with 400. Omit for new fields; when omitted on an update,
            the server matches the field to the prior version by name.
        name:
          type: string
          minLength: 1
          title: Name
          description: Field name. Used as the key in the extraction response.
        description:
          type: string
          title: Description
          description: Free-form description shown to the extraction model.
          default: ''
        lookup:
          type: boolean
          title: Lookup
          default: false
        data_type:
          type: string
          const: boolean
          title: Data Type
      additionalProperties: false
      type: object
      required:
        - name
        - data_type
      title: BooleanField
    DateField:
      properties:
        persistent_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Persistent Id
          description: >-
            Server-assigned stable field identity (UUID), emitted by GET
            /definition/. Echo it back on updates — including across renames —
            to keep quality metrics, ground-truth links and analytics attached
            to the field. Matching is scoped to the field's nesting level in the
            immediately-prior version; an id that matches nothing at its level,
            appears on more than one field, or is sent at workflow creation is
            rejected with 400. Omit for new fields; when omitted on an update,
            the server matches the field to the prior version by name.
        name:
          type: string
          minLength: 1
          title: Name
          description: Field name. Used as the key in the extraction response.
        description:
          type: string
          title: Description
          description: Free-form description shown to the extraction model.
          default: ''
        lookup:
          type: boolean
          title: Lookup
          default: false
        data_type:
          type: string
          const: date
          title: Data Type
      additionalProperties: false
      type: object
      required:
        - name
        - data_type
      title: DateField
    DatetimeField:
      properties:
        persistent_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Persistent Id
          description: >-
            Server-assigned stable field identity (UUID), emitted by GET
            /definition/. Echo it back on updates — including across renames —
            to keep quality metrics, ground-truth links and analytics attached
            to the field. Matching is scoped to the field's nesting level in the
            immediately-prior version; an id that matches nothing at its level,
            appears on more than one field, or is sent at workflow creation is
            rejected with 400. Omit for new fields; when omitted on an update,
            the server matches the field to the prior version by name.
        name:
          type: string
          minLength: 1
          title: Name
          description: Field name. Used as the key in the extraction response.
        description:
          type: string
          title: Description
          description: Free-form description shown to the extraction model.
          default: ''
        lookup:
          type: boolean
          title: Lookup
          default: false
        data_type:
          type: string
          const: datetime
          title: Data Type
      additionalProperties: false
      type: object
      required:
        - name
        - data_type
      title: DatetimeField
    EnumField:
      properties:
        persistent_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Persistent Id
          description: >-
            Server-assigned stable field identity (UUID), emitted by GET
            /definition/. Echo it back on updates — including across renames —
            to keep quality metrics, ground-truth links and analytics attached
            to the field. Matching is scoped to the field's nesting level in the
            immediately-prior version; an id that matches nothing at its level,
            appears on more than one field, or is sent at workflow creation is
            rejected with 400. Omit for new fields; when omitted on an update,
            the server matches the field to the prior version by name.
        name:
          type: string
          minLength: 1
          title: Name
          description: Field name. Used as the key in the extraction response.
        description:
          type: string
          title: Description
          description: Free-form description shown to the extraction model.
          default: ''
        lookup:
          type: boolean
          title: Lookup
          default: false
        data_type:
          type: string
          const: enum
          title: Data Type
        enum_options:
          items:
            $ref: '#/components/schemas/EnumOption'
          type: array
          minItems: 1
          title: Enum Options
      additionalProperties: false
      type: object
      required:
        - name
        - data_type
        - enum_options
      title: EnumField
    MultiSelectField:
      properties:
        persistent_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Persistent Id
          description: >-
            Server-assigned stable field identity (UUID), emitted by GET
            /definition/. Echo it back on updates — including across renames —
            to keep quality metrics, ground-truth links and analytics attached
            to the field. Matching is scoped to the field's nesting level in the
            immediately-prior version; an id that matches nothing at its level,
            appears on more than one field, or is sent at workflow creation is
            rejected with 400. Omit for new fields; when omitted on an update,
            the server matches the field to the prior version by name.
        name:
          type: string
          minLength: 1
          title: Name
          description: Field name. Used as the key in the extraction response.
        description:
          type: string
          title: Description
          description: Free-form description shown to the extraction model.
          default: ''
        lookup:
          type: boolean
          title: Lookup
          default: false
        data_type:
          type: string
          const: multi_select
          title: Data Type
        enum_options:
          items:
            $ref: '#/components/schemas/EnumOption'
          type: array
          minItems: 1
          title: Enum Options
      additionalProperties: false
      type: object
      required:
        - name
        - data_type
        - enum_options
      title: MultiSelectField
    ObjectField:
      properties:
        persistent_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Persistent Id
          description: >-
            Server-assigned stable field identity (UUID), emitted by GET
            /definition/. Echo it back on updates — including across renames —
            to keep quality metrics, ground-truth links and analytics attached
            to the field. Matching is scoped to the field's nesting level in the
            immediately-prior version; an id that matches nothing at its level,
            appears on more than one field, or is sent at workflow creation is
            rejected with 400. Omit for new fields; when omitted on an update,
            the server matches the field to the prior version by name.
        name:
          type: string
          minLength: 1
          title: Name
          description: Field name. Used as the key in the extraction response.
        description:
          type: string
          title: Description
          description: Free-form description shown to the extraction model.
          default: ''
        lookup:
          type: boolean
          title: Lookup
          default: false
        data_type:
          type: string
          const: object
          title: Data Type
        nested_fields:
          items:
            oneOf:
              - $ref: '#/components/schemas/StringField'
              - $ref: '#/components/schemas/IntegerField'
              - $ref: '#/components/schemas/FloatField'
              - $ref: '#/components/schemas/BooleanField'
              - $ref: '#/components/schemas/DateField'
              - $ref: '#/components/schemas/DatetimeField'
              - $ref: '#/components/schemas/EnumField'
              - $ref: '#/components/schemas/MultiSelectField'
            discriminator:
              propertyName: data_type
              mapping:
                boolean:
                  $ref: '#/components/schemas/BooleanField'
                date:
                  $ref: '#/components/schemas/DateField'
                datetime:
                  $ref: '#/components/schemas/DatetimeField'
                enum:
                  $ref: '#/components/schemas/EnumField'
                float:
                  $ref: '#/components/schemas/FloatField'
                integer:
                  $ref: '#/components/schemas/IntegerField'
                multi_select:
                  $ref: '#/components/schemas/MultiSelectField'
                string:
                  $ref: '#/components/schemas/StringField'
          type: array
          minItems: 1
          title: Nested Fields
          description: >-
            Child fields of this object. Only one level of nesting is supported
            — an object field's children must be non-object types.
      additionalProperties: false
      type: object
      required:
        - name
        - data_type
        - nested_fields
      title: ObjectField
    ValidationRule:
      properties:
        id:
          type: string
          minLength: 1
          title: Id
          description: Stable rule id; round-trips through validation results.
        name:
          anyOf:
            - type: string
            - type: 'null'
          title: Name
          description: >-
            Optional human-readable rule name. Round-trips through the config
            endpoint so renames are preserved.
        kind:
          type: string
          enum:
            - ai
            - deterministic
          title: Kind
          description: >-
            'deterministic' = a structured check run in code — instant, free,
            reproducible; 'ai' = a model judges the rule description against the
            extraction. Prefer deterministic whenever the condition is exact and
            testable.
          default: ai
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
          description: >-
            Natural-language description sent to the LLM. Required when kind ==
            'ai'.
        check:
          anyOf:
            - oneOf:
                - $ref: '#/components/schemas/RangeCheck'
                - $ref: '#/components/schemas/DateCheck'
                - $ref: '#/components/schemas/ArithmeticCheck'
                - $ref: '#/components/schemas/ComparisonCheck'
                - $ref: '#/components/schemas/OneOfCheck'
                - $ref: '#/components/schemas/RegexCheck'
                - $ref: '#/components/schemas/RequiredCheck'
              discriminator:
                propertyName: type
                mapping:
                  arithmetic:
                    $ref: '#/components/schemas/ArithmeticCheck'
                  comparison:
                    $ref: '#/components/schemas/ComparisonCheck'
                  date:
                    $ref: '#/components/schemas/DateCheck'
                  one_of:
                    $ref: '#/components/schemas/OneOfCheck'
                  range:
                    $ref: '#/components/schemas/RangeCheck'
                  regex:
                    $ref: '#/components/schemas/RegexCheck'
                  required:
                    $ref: '#/components/schemas/RequiredCheck'
            - type: 'null'
          title: Check
          description: >-
            Structured deterministic check. Required when kind ==
            'deterministic'.
        severity:
          type: string
          enum:
            - error
            - warning
          title: Severity
          description: >-
            How a failed rule is labelled in results. Display-level only — it
            never blocks the run.
          default: error
        source_fields:
          items:
            type: string
          type: array
          title: Source Fields
          description: Persistent ids of fields this rule references.
      additionalProperties: false
      type: object
      required:
        - id
      title: ValidationRule
    EnumOption:
      properties:
        name:
          type: string
          minLength: 1
          title: Name
        description:
          type: string
          minLength: 1
          title: Description
          description: Free-form description shown to the model.
      additionalProperties: false
      type: object
      required:
        - name
        - description
      title: EnumOption
    RangeCheck:
      properties:
        type:
          type: string
          const: range
          title: Type
        field:
          type: string
          minLength: 1
          title: Field
          description: persistent_id of the bounded numeric field.
        min:
          anyOf:
            - type: number
            - type: 'null'
          title: Min
        max:
          anyOf:
            - type: number
            - type: 'null'
          title: Max
      additionalProperties: false
      type: object
      required:
        - type
        - field
      title: RangeCheck
    DateCheck:
      properties:
        type:
          type: string
          const: date
          title: Type
        field:
          type: string
          minLength: 1
          title: Field
          description: persistent_id of the date field.
        earliest:
          anyOf:
            - type: string
            - type: 'null'
          title: Earliest
        latest:
          anyOf:
            - type: string
            - type: 'null'
          title: Latest
      additionalProperties: false
      type: object
      required:
        - type
        - field
      title: DateCheck
    ArithmeticCheck:
      properties:
        type:
          type: string
          const: arithmetic
          title: Type
        operands:
          items:
            type: string
          type: array
          minItems: 1
          title: Operands
          description: persistent_ids combined by `operator`.
        operator:
          type: string
          enum:
            - sum
            - subtract
            - product
          title: Operator
          default: sum
        equals:
          type: string
          minLength: 1
          title: Equals
          description: persistent_id whose value the result must equal.
        tolerance:
          type: number
          minimum: 0
          title: Tolerance
          description: Absolute slack allowed around `equals`.
          default: 0
      additionalProperties: false
      type: object
      required:
        - type
        - operands
        - equals
      title: ArithmeticCheck
    ComparisonCheck:
      properties:
        type:
          type: string
          const: comparison
          title: Type
        left:
          type: string
          minLength: 1
          title: Left
          description: persistent_id of the left-hand field.
        op:
          type: string
          enum:
            - '=='
            - '!='
            - '>'
            - '>='
            - <
            - <=
          title: Op
        right:
          oneOf:
            - $ref: '#/components/schemas/_FieldOperand'
            - $ref: '#/components/schemas/_LiteralOperand'
          title: Right
          discriminator:
            propertyName: source
            mapping:
              field:
                $ref: '#/components/schemas/_FieldOperand'
              literal:
                $ref: '#/components/schemas/_LiteralOperand'
      additionalProperties: false
      type: object
      required:
        - type
        - left
        - op
        - right
      title: ComparisonCheck
    OneOfCheck:
      properties:
        type:
          type: string
          const: one_of
          title: Type
        field:
          type: string
          minLength: 1
          title: Field
        allowed:
          items:
            type: string
          type: array
          minItems: 1
          title: Allowed
        case_sensitive:
          type: boolean
          title: Case Sensitive
          default: false
      additionalProperties: false
      type: object
      required:
        - type
        - field
        - allowed
      title: OneOfCheck
    RegexCheck:
      properties:
        type:
          type: string
          const: regex
          title: Type
        field:
          type: string
          minLength: 1
          title: Field
        pattern:
          type: string
          minLength: 1
          title: Pattern
          description: Evaluated with google-re2 (linear time); never stdlib re.
      additionalProperties: false
      type: object
      required:
        - type
        - field
        - pattern
      title: RegexCheck
    RequiredCheck:
      properties:
        type:
          type: string
          const: required
          title: Type
        field:
          type: string
          minLength: 1
          title: Field
      additionalProperties: false
      type: object
      required:
        - type
        - field
      title: RequiredCheck
    _FieldOperand:
      properties:
        source:
          type: string
          const: field
          title: Source
        field:
          type: string
          minLength: 1
          title: Field
          description: persistent_id of the compared field.
      additionalProperties: false
      type: object
      required:
        - source
        - field
      title: _FieldOperand
    _LiteralOperand:
      properties:
        source:
          type: string
          const: literal
          title: Source
        value:
          anyOf:
            - type: number
            - type: string
            - type: boolean
          title: Value
      additionalProperties: false
      type: object
      required:
        - source
        - value
      title: _LiteralOperand
  securitySchemes:
    ApiKeyAuth:
      type: http
      description: >-
        API key issued from app.anyformat.ai/api-key. Send as `Authorization:
        Bearer <key>`.
      scheme: bearer

````