Skip to main content
Read-only, start to finish. This recipe loads historical exports into a fresh project. Nothing here connects to a production system, and nothing here writes anywhere. The worst outcome is a clean bill of health.

The job

Nobody knows exactly what’s leaking out of their AP process, because checking every transaction against every other one was never possible by hand. So it gets sampled, and sampling finds the errors that happen to be in the sample. This recipe runs the checks across the full population — 12 to 24 months of it — and reports what it finds with the evidence attached. It’s the first stage of audit to prevention: prove the checks work on data nobody can dispute before anything runs on live events.

What you’ll build

One reconcile table, one SOP, and each check runs as its own task in that table — all of them sharing the same data access and the same procedure. This is the month-close pattern: the process is one thing, and its steps are tasks rather than separate tables.

Ingredients

What to export. Ask whoever runs your ERP for 12–24 months of:
Column names don’t have to match these — the agent reads your schema. They do have to be legible: bank_last_changed works, dt_fld_09 doesn’t.

The starter SOP

Walkthrough

1

Create the project and load the exports

New project. Create each export as a Storage table and upload the CSV. If you have invoice PDFs, put them in Files — checks 1, 2, and 7 get sharper when the agent can open the document behind a row.
2

Create the Audit Findings table

A Reconcile table with Operating Procedures: Run the audit checks defined in the SOP. Read-only.Output Fields: check, finding, row_references, amount, currency, confidence, recommended_action, population_examined. Grant Data Access to every storage table you loaded. Model tier Powerful.
3

Add the SOP and sanity-check it against your data

Paste the starter SOP into SOP.md, then ask in chat:
Read SOP.md, then look at the storage tables. Which checks can run against this data as-is, which need a column I haven’t loaded, and what’s the row count and date range per table?
It tells you what’s runnable before you run anything. Load what’s missing, or drop the check.
4

Run one check first

Create a task for Check 1 alone. Duplicates are the easiest to verify by hand, so it’s the cheapest way to confirm the agent is reading your schema correctly. Check a few findings against the ERP yourself.
5

Run the rest

One task per check. They share the SOP and the data access, so nothing is configured twice.

What good looks like

A real finding, with its evidence:
Check 3 — Cross-entity duplicates. Invoice MV-4471 from Marloe Verpackung (tax ID DE••1882) was paid twice: once by entity DE01 as vendor 21044 on 2025-11-14 (payment run PR-2211, 8,940.00 EUR) and once by entity AT02 as vendor 30871 on 2025-12-02 (PR-2249, 8,940.00 EUR). Same invoice number, same amount, same tax ID, different vendor records — which is why the per-entity duplicate check did not catch it. Rows: ledger 118422, 121907; payment runs PR-2211, PR-2249. Amount at stake 8,940.00 EUR. Confidence: high. Recommended action: raise a recovery claim against Marloe Verpackung for the AT02 payment.
Every number points at a row. A controller can verify this in the ERP in two minutes. A check that correctly finds nothing:
Check 5 — Bank detail changes near a payment run. Examined 1,247 vendor records against 38 payment runs in the period. Nine vendors had a bank_iban change during the window; none fell within 30 days before a payment to that vendor — closest was 63 days (vendor 20115, change 2025-08-03, next payment 2025-10-05). No findings. Population examined: 1,247 vendors, 38 runs, 14,902 ledger rows.
This is a result, not a blank. It says what was checked, how much of it, and what the near-miss was — which is what makes “nothing found” believable. A finding the agent correctly refuses to call:
Check 6 — Split invoices. Three invoices from Kestrel Instrumente within 5 days (4,800.00, 4,950.00, 4,200.00 EUR; total 13,950.00). No approval thresholds are present in the loaded data, so I cannot say whether this total crosses one — the pattern is reported, the conclusion is not. The innocent explanation I considered: all three reference PO 4500219 with different delivery notes, which is consistent with a phased delivery. Confidence: low. Recommended action: confirm your approval threshold, then check whether phased delivery against one PO is expected for this vendor.
The agent did the arithmetic and then declined to allege something the data doesn’t support.

The findings report

When the checks are done, ask for the deliverable:
Produce an xlsx of the audit: a summary sheet with each check, rows examined, findings, and total amount at stake; then one sheet per check with the full findings and their row references.
It writes the file into the project’s Files. That’s the artifact you take to the meeting — and because every row reference is in it, it survives being questioned.

Iterating

Your first run will find things that aren’t findings. That’s normal, and it’s fixed in the SOP, not by hand:
Check 2 is flagging our monthly software subscriptions as near duplicates. Add a rule: identical amounts recurring at a monthly cadence from the same vendor are expected, not near duplicates — exclude them and report the count excluded.
Note the last clause. Excluding something silently is how an audit loses credibility; excluding it and saying how many were excluded is how it keeps it.

What to do with the findings

The audit is stage one. The checks that found money are the checks worth running continuously — before payment rather than after it:

From audit to prevention

The three-stage path: audit, recover, prevent. Read this next.

Vendor invoice audit

The continuous sibling of this lookback — the same checks, running on invoices as they arrive.

Integrations

What turns a batch run into a live trigger.

Governance

Grants, roles, and the audit trail behind every finding.
All vendor names, tax IDs, invoice numbers, amounts, and row ids in this cookbook are invented.