AP Invoice Reconciliation

Three-way match across purchase orders, invoices, and payments. The universal starting point — every company has this problem, most solve it with spreadsheets.

What Gets Automated

PO-to-invoice matching on PO number, amount tolerance, and date windows. Fuzzy vendor name matching catches data entry inconsistencies. Agent investigates discrepancies: wrong amounts, missing POs, duplicate invoices, partial payments.

What Humans Still Own

Write-off approvals above threshold. Vendor dispute resolution. New vendor onboarding decisions.

Pipeline

flowchart TD A[Input: Invoices + Payments + POs] --> B[Matcher] B -->|~80% matched| C[Auto-Reconcile] B -->|~20% exceptions| D{Exception Type} D -->|Amount discrepancy| E[ReAct Agent] D -->|Missing PO| E D -->|Duplicate suspected| E E -->|High confidence| F[Auto-Resolve + Log] E -->|Low confidence| G[Human Approval] G -->|Approved| H[Process + Log] G -->|Rejected| I[Flag for Review] C --> J[Custom Table: Reconciliation Log] F --> J H --> J I --> J style B fill:#e8a84c,color:#09090b,stroke:none style E fill:#4ade80,color:#09090b,stroke:none style G fill:#60a5fa,color:#09090b,stroke:none

Workflow Definition

json
{
  "name": "ap_invoice_reconciliation",
  "definition": {
    "actions": [
      {
        "type": "matcher",
        "properties": {
          "left": "@input.invoices",
          "right": "@input.payments",
          "matchOn": ["po_number", "vendor_id"],
          "tolerance": 0.02,
          "dateWindowDays": 5,
          "fuzzyThreshold": 85,
          "descriptionKey": "vendor_name",
          "outputMatched": "reconciled",
          "outputUnmatchedLeft": "unmatched_invoices",
          "outputUnmatchedRight": "unmatched_payments"
        }
      },
      {
        "type": "loop",
        "filter": {
          "condition": {
            "greaterThan": [{ "length": "@unmatched_invoices" }, 0]
          }
        },
        "properties": {
          "mode": "foreach",
          "items_path": "@unmatched_invoices",
          "item_variable_name": "exception",
          "actions_to_execute": [
            {
              "type": "loop",
              "properties": {
                "mode": "react",
                "objective": "Investigate this unmatched invoice: {{exception.invoice_id}} from {{exception.vendor_name}} for ${{exception.amount}}. Determine the root cause: timing delay (check payment terms), amount discrepancy (compare to PO), duplicate invoice, missing PO, or data entry error. Recommend: auto-resolve, follow up with vendor, or escalate for write-off review.",
                "tools": [
                  { "type": "action", "name": "lookup_purchase_order" },
                  { "type": "action", "name": "check_payment_history" },
                  { "type": "action", "name": "search_duplicate_invoices" }
                ],
                "max_iterations": 8,
                "on_stuck": {
                  "iterations": 3,
                  "action": "retry_with_hint",
                  "hint": "If you cannot determine the root cause, complete with your best assessment and low confidence."
                },
                "result_key": "investigation"
              }
            }
          ],
          "max_concurrency": 5,
          "failure_strategy": "continue_on_error",
          "collect_results": true,
          "result_key": "all_investigations"
        }
      },
      {
        "type": "PbotApproval",
        "filter": {
          "condition": {
            "greaterThan": [{ "length": "@unmatched_invoices" }, 0]
          }
        },
        "properties": {
          "comment": "{{unmatched_invoices.length}} exceptions investigated. Review AI findings and approve recommended actions.",
          "request_payload": {
            "reconciled_count": "@reconciled.length",
            "exception_count": "@unmatched_invoices.length",
            "investigations": "@all_investigations",
            "unmatched_payments": "@unmatched_payments"
          }
        }
      },
      {
        "type": "custom-table",
        "properties": {
          "table": "reconciliation_log",
          "operation": "write",
          "keys": ["run_id", "run_date"],
          "values": ["@__run_id", "@now"],
          "fields": {
            "total_invoices": "@input.invoices.length",
            "auto_reconciled": "@reconciled.length",
            "exceptions_investigated": "@unmatched_invoices.length",
            "unmatched_payments": "@unmatched_payments.length",
            "status": "completed"
          }
        }
      }
    ]
  }
}

Required Registered Actions

Action Kind Purpose
lookup_purchase_order http Query ERP for PO details by PO number
check_payment_history db Search payment records for a vendor within date range
search_duplicate_invoices db Check for invoices with matching amounts and close dates

Customization Notes

Tolerance. The default 2% (0.02) handles typical rounding differences. Lower to 0.5% for high-precision environments; raise to 5% if partial payments are common.

Date window. 5 days covers standard payment processing lag. Extend to 15–30 days for international vendors with longer settlement cycles.

Fuzzy threshold. 85 catches minor name variations ("Acme Corp" vs "ACME Corporation"). Lower to 75 if vendor names are highly inconsistent across systems.

Agent iterations. 8 iterations gives the agent room to check multiple data sources. Reduce to 5 for simpler investigations; increase to 12 if your exception patterns are complex.