Platform Pipelines Agents Human review Self-improvement Observability Deployment Security Use cases Compare Docs Pricing Roadmap Get early access

Document intake

Invoices and contracts arrive as PDFs and scans. Millstream fetches each document, has an agent extract its fields, checks them in plain code, and sends only the exceptions to an accounts team, with every correction recorded against the step that made the mistake.


The pipeline

flowchart LR
  W(["webhook: upload"]) --> F[fetch document] --> X["extract (agent)"] --> V[validate]
  V -->|no issues| S[/spot check/]
  V -->|issues| E[/exception review/]
  S & E --> P[post to ERP]
pipeline: invoice-intake
description: Extract, validate and post supplier invoices

vars: { minConfidence: 0.9, autoApproveMaxEur: 5000 }

triggers:
  upload: { webhook: { rate: 120/min } }

streams:
  docs.extracted: { retention: 400d }

steps:
  fetch:
    action: ./actions/fetch-document
    in: trigger.upload
    out: docs.fetched
  extract:
    action: lab/extract-invoice@1
    in: docs.fetched
    out: docs.extracted
    concurrency: 6
  validate:
    action: ./actions/validate-invoice
    in: docs.extracted
    out:
      - { when: "size(item.issues) == 0 && item.confidence >= vars.minConfidence", out: docs.clean }
      - { when: "true", out: docs.exceptions }
  spot-check:
    action: review
    in: docs.clean
    out: docs.approved
    config:
      inbox: accounts
      timeout: 72h
      onTimeout: { escalate: accounts-leads }
      autoApprove: "item.totalEur <= vars.autoApproveMaxEur"
      sampleRate: 0.05
  exception-review:
    action: review
    in: docs.exceptions
    out: docs.approved
    config:
      inbox: accounts
      timeout: 48h
      onTimeout: { escalate: accounts-leads }
      editable: [/supplier, /poNumber, /totalEur, /lines]
      reasons: [duplicate, wrongSupplier, missingPo, unreadable]
  post:
    action: lab/erp-post@1
    in: docs.approved

budget: { dayUsd: 40 }

What Millstream does for it

Documents as artifacts

Extraction and validation

People on the exceptions

Failures


How it learns

A correction to /totalEur is attributed by walking the item's lineage to the nearest step whose output changed that field. That step is extract; validate passed the value through unchanged, so it is not blamed. Three or more such edits on one field become a lessons proposal for extract, with a rule and the corrected examples. When sampled rule approvals start disagreeing with people, the reviewPattern insight raises a warning below 90% agreement.


Figures to watch

Figure What it tells you
Intervention rate per review step The share of invoices that still need a person
Exceptions by reason code Whether the problem is the documents or the extraction
Sampled-rule agreement on spot-check Whether the auto-approval rule still holds
Most edited pointers on exception-review Which fields the agent gets wrong
Cost per approved item Extraction cost per posted invoice

Next

Human review · Observability · Security