Agents Autonomous
Worked example / Synthetic data

Duplicate invoice checks.
Before approval.

A repeated invoice is easy to miss. Here is a small, runnable check that shows what to compare, when to stop, and what to put in front of a reviewer.

What should a duplicate check do?

Compare an incoming invoice with the records already available for the same supplier. Keep the matching references, flag conflicting fields, and give a reviewer enough evidence to decide. A clean comparison alone does not authorize approval or payment.

This example starts after document extraction. It checks structured fields with deterministic rules: supplier ID, invoice number, amount, and currency. There is no language model, OCR, or client data in the runner.

Two rules. The same inputs.

The literal rule compares the supplier ID and invoice number exactly. The normalized rule also ignores ASCII letter case, spaces, and hyphens in the invoice number. Supplier IDs remain exact in both rules.

Both rules compare against a supplied ledger and earlier records in the same batch. They validate the input and flag amount or currency conflicts. The normalized rule preserves leading zeros; a number that matches only after removing them goes to review. Normalization can connect different numbers by mistake, so its matches remain possible duplicates.

  1. Needs review: incomplete data, conflicting records, or ambiguous numbers.
  2. Possible duplicate: a reference matches under the selected rule.
  3. No match: no matching reference in the supplied comparison set. The normal approval process still applies.

What the run produced.

Literal comparison
12/16 expectations matched
Normalized comparison
16/16 expectations matched

Counts show agreement with manually assigned expectations on 16 deliberately chosen synthetic scenarios, not accuracy on real invoices or evidence of savings.

The difference comes from four deliberately included cases: spacing, letter case, a leading-zero ambiguity, and conflicting references. These cases explain the rule change; they do not establish which rule will work best on your documents.

Open a case. Inspect the decision.

Each case is independent. The target is the incoming invoice; ledger and priorBatch contain its reference records. Expand a case to compare both decisions and their explanations.

01Exact copy of a ledger invoice

Expected: Possible duplicate

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "invoice_number": "INV-1042",
    "amount": "120.00",
    "currency": "USD"
  },
  "ledger": [
    {
      "id": "ledger-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    }
  ],
  "priorBatch": []
}

Literal rule

Possible duplicate

The supplier, compared invoice number, amount and currency match a supplied reference. A person must decide whether this is a duplicate.

Matching references: ledger: ledger-1

Normalized rule

Possible duplicate

The supplier, compared invoice number, amount and currency match a supplied reference. A person must decide whether this is a duplicate.

Matching references: ledger: ledger-1

02Spaces replace the invoice-number hyphen

Expected: Possible duplicate

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "invoice_number": " INV 1042 ",
    "amount": "120.00",
    "currency": "USD"
  },
  "ledger": [
    {
      "id": "ledger-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    }
  ],
  "priorBatch": []
}

Literal rule

No match

No reference matches within the supplied ledger and earlier batch under this rule. This is not permission to approve or pay.

Matching references: None

Normalized rule

Possible duplicate

The supplier, compared invoice number, amount and currency match a supplied reference. A person must decide whether this is a duplicate.

Matching references: ledger: ledger-1

03Invoice-number letters change case

Expected: Possible duplicate

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "invoice_number": "inv-1042",
    "amount": "120.00",
    "currency": "USD"
  },
  "ledger": [
    {
      "id": "ledger-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    }
  ],
  "priorBatch": []
}

Literal rule

No match

No reference matches within the supplied ledger and earlier batch under this rule. This is not permission to approve or pay.

Matching references: None

Normalized rule

Possible duplicate

The supplier, compared invoice number, amount and currency match a supplied reference. A person must decide whether this is a duplicate.

Matching references: ledger: ledger-1

04The same invoice number belongs to another supplier

Expected: No match

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-002",
    "invoice_number": "INV-1042",
    "amount": "120.00",
    "currency": "USD"
  },
  "ledger": [
    {
      "id": "ledger-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    }
  ],
  "priorBatch": []
}

Literal rule

No match

No reference matches within the supplied ledger and earlier batch under this rule. This is not permission to approve or pay.

Matching references: None

Normalized rule

No match

No reference matches within the supplied ledger and earlier batch under this rule. This is not permission to approve or pay.

Matching references: None

05The invoice number matches but the amount changes

Expected: Needs review

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "invoice_number": "INV-1042",
    "amount": "125.00",
    "currency": "USD"
  },
  "ledger": [
    {
      "id": "ledger-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    }
  ],
  "priorBatch": []
}

Literal rule

Needs review

At least one matching supplier/number reference has a different amount or currency; inspect the source records.

Matching references: ledger: ledger-1

Normalized rule

Needs review

At least one matching supplier/number reference has a different amount or currency; inspect the source records.

Matching references: ledger: ledger-1

06The invoice number matches but the currency changes

Expected: Needs review

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "invoice_number": "INV-1042",
    "amount": "120.00",
    "currency": "EUR"
  },
  "ledger": [
    {
      "id": "ledger-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    }
  ],
  "priorBatch": []
}

Literal rule

Needs review

At least one matching supplier/number reference has a different amount or currency; inspect the source records.

Matching references: ledger: ledger-1

Normalized rule

Needs review

At least one matching supplier/number reference has a different amount or currency; inspect the source records.

Matching references: ledger: ledger-1

07The extracted invoice number is missing

Expected: Needs review

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "amount": "120.00",
    "currency": "USD"
  },
  "ledger": [
    {
      "id": "ledger-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    }
  ],
  "priorBatch": []
}

Literal rule

Needs review

The target or supplied reference data is incomplete, invalid or outside this example's supported format.

Matching references: None

Input issues: target: missing invoice_number; target: invoice_number must contain ASCII letters/digits, spaces or hyphens, 1–64 characters

Normalized rule

Needs review

The target or supplied reference data is incomplete, invalid or outside this example's supported format.

Matching references: None

Input issues: target: missing invoice_number; target: invoice_number must contain ASCII letters/digits, spaces or hyphens, 1–64 characters

08The amount uses an unsupported decimal separator

Expected: Needs review

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "invoice_number": "INV-1042",
    "amount": "120,00",
    "currency": "USD"
  },
  "ledger": [
    {
      "id": "ledger-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    }
  ],
  "priorBatch": []
}

Literal rule

Needs review

The target or supplied reference data is incomplete, invalid or outside this example's supported format.

Matching references: None

Input issues: target: amount must be a positive decimal string, at most 999999999.99 and two decimal places

Normalized rule

Needs review

The target or supplied reference data is incomplete, invalid or outside this example's supported format.

Matching references: None

Input issues: target: amount must be a positive decimal string, at most 999999999.99 and two decimal places

09Removing leading zeros would create a match

Expected: Needs review

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "invoice_number": "INV-001042",
    "amount": "120.00",
    "currency": "USD"
  },
  "ledger": [
    {
      "id": "ledger-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    }
  ],
  "priorBatch": []
}

Literal rule

No match

No reference matches within the supplied ledger and earlier batch under this rule. This is not permission to approve or pay.

Matching references: None

Normalized rule

Needs review

A number matches only after removing leading zeros from digit groups. The example does not assume these numbers are equivalent.

Matching references: ledger: ledger-1

10A duplicate is present earlier in the current batch

Expected: Possible duplicate

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "invoice_number": "INV-1042",
    "amount": "120.00",
    "currency": "USD"
  },
  "ledger": [],
  "priorBatch": [
    {
      "id": "batch-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    }
  ]
}

Literal rule

Possible duplicate

The supplier, compared invoice number, amount and currency match a supplied reference. A person must decide whether this is a duplicate.

Matching references: batch: batch-1

Normalized rule

Possible duplicate

The supplier, compared invoice number, amount and currency match a supplied reference. A person must decide whether this is a duplicate.

Matching references: batch: batch-1

11No matching invoice number exists in the supplied context

Expected: No match

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "invoice_number": "INV-1043",
    "amount": "120.00",
    "currency": "USD"
  },
  "ledger": [
    {
      "id": "ledger-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    }
  ],
  "priorBatch": []
}

Literal rule

No match

No reference matches within the supplied ledger and earlier batch under this rule. This is not permission to approve or pay.

Matching references: None

Normalized rule

No match

No reference matches within the supplied ledger and earlier batch under this rule. This is not permission to approve or pay.

Matching references: None

12The same input record ID appears twice

Expected: Needs review

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "invoice_number": "INV-1042",
    "amount": "120.00",
    "currency": "USD"
  },
  "ledger": [],
  "priorBatch": [
    {
      "id": "incoming-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    }
  ]
}

Literal rule

Needs review

A record ID occurs more than once in the supplied context; check the import before interpreting matches.

Matching references: None

Input issues: repeated id: incoming-1

Normalized rule

Needs review

A record ID occurs more than once in the supplied context; check the import before interpreting matches.

Matching references: None

Input issues: repeated id: incoming-1

13An exact match and a formatted match disagree on amount

Expected: Needs review

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "invoice_number": "INV-1042",
    "amount": "120.00",
    "currency": "USD"
  },
  "ledger": [
    {
      "id": "ledger-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    },
    {
      "id": "ledger-2",
      "supplier_id": "SUP-001",
      "invoice_number": "inv 1042",
      "amount": "125.00",
      "currency": "USD"
    }
  ],
  "priorBatch": []
}

Literal rule

Possible duplicate

The supplier, compared invoice number, amount and currency match a supplied reference. A person must decide whether this is a duplicate.

Matching references: ledger: ledger-1

Normalized rule

Needs review

At least one matching supplier/number reference has a different amount or currency; inspect the source records.

Matching references: ledger: ledger-1, ledger: ledger-2

14An earlier reference invoice has incomplete data

Expected: Needs review

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "invoice_number": "INV-1042",
    "amount": "120.00",
    "currency": "USD"
  },
  "ledger": [
    {
      "id": "ledger-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "currency": "USD"
    }
  ],
  "priorBatch": []
}

Literal rule

Needs review

The target or supplied reference data is incomplete, invalid or outside this example's supported format.

Matching references: None

Input issues: ledger[0]: missing amount; ledger[0]: amount must be a positive decimal string, at most 999999999.99 and two decimal places

Normalized rule

Needs review

The target or supplied reference data is incomplete, invalid or outside this example's supported format.

Matching references: None

Input issues: ledger[0]: missing amount; ledger[0]: amount must be a positive decimal string, at most 999999999.99 and two decimal places

15Leading zeros are kept on a genuinely different number

Expected: No match

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "invoice_number": "INV-001043",
    "amount": "120.00",
    "currency": "USD"
  },
  "ledger": [
    {
      "id": "ledger-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    }
  ],
  "priorBatch": []
}

Literal rule

No match

No reference matches within the supplied ledger and earlier batch under this rule. This is not permission to approve or pay.

Matching references: None

Normalized rule

No match

No reference matches within the supplied ledger and earlier batch under this rule. This is not permission to approve or pay.

Matching references: None

16The invoice currency is outside this example

Expected: Needs review

Input and reference records

{
  "target": {
    "id": "incoming-1",
    "supplier_id": "SUP-001",
    "invoice_number": "INV-1042",
    "amount": "120.00",
    "currency": "JPY"
  },
  "ledger": [
    {
      "id": "ledger-1",
      "supplier_id": "SUP-001",
      "invoice_number": "INV-1042",
      "amount": "120.00",
      "currency": "USD"
    }
  ],
  "priorBatch": []
}

Literal rule

Needs review

The target or supplied reference data is incomplete, invalid or outside this example's supported format.

Matching references: None

Input issues: target: currency must be USD, EUR or GBP in this example

Normalized rule

Needs review

The target or supplied reference data is incomplete, invalid or outside this example's supported format.

Matching references: None

Input issues: target: currency must be USD, EUR or GBP in this example

Run the same check yourself.

Download these five files into one folder. With Python 3.9 or later, run the command below from that folder. It recalculates the results and checks that they match the published report. No packages or network access are needed.

python3 run.py --check

To test your own synthetic cases, edit the inputs and their expected decisions, then run python3 run.py --output results.json. Read the instructions before changing the supported input format.

What a real workflow still needs.

This is one check inside an invoice workflow. A production implementation also needs reliable extraction, supplier identity rules, access controls, a complete comparison set, audit records, and an approval owner. The example does not demonstrate concurrent processing, persistent duplicate prevention, or integration with a finance system.

The demo accepts positive decimal amounts in USD, EUR, or GBP only. It does not support credit notes, other currency formats, or arbitrary invoice-number scripts. Test broader conditions against representative documents before deciding how any match should affect the workflow.

We use a worked example like this to make the next project conversation concrete: which inputs matter, which failures to test, what evidence to retain, and who accepts the result.

A useful conversation starts here

Where does the work
get stuck?

Bring one document workflow. We can define the checks, evidence, and review path together.

Discuss your project