Inspiration
Most AP teams take 17.4 days to process a single invoice; the best take 3.1 (Ardent Partners, State of ePayables 2024). That's not slow typing. AP meets every bill cold. By the time an invoice arrives, the agreed price is buried in an email thread, the PO is in the ERP, the receipt is in a spreadsheet, and what shipped is in a chat. Someone rebuilds that context by hand for every bill, while the expensive mistakes slip through:
- a "new bank account" from a look-alike domain, the day before a $3.3M payment;
- a paid invoice resent as
INV-2291-A; - a vendor billing the quoted price instead of the agreed one.
We asked: what if AP started at the first quote instead of the invoice?
What it does
ReconAI fills two seats at a fabless chip company, the AP specialist and the vendor-master clerk. It runs the whole bill lifecycle in one Slack channel with the vendor and produces the three documents a 3-way match needs on the way.
- Negotiate. While the vendor quotes, ReconAI privately shows only your side the numbers: counter, aim and walk-away from your PO history and market percentiles, plus cash-flow terms to ask for.
- Contract and onboarding. It drafts the supply agreement. When the vendor accepts, onboarding runs automatically: sanctions, bank, domain, tax form and CRS identity checks. Low-risk vendors are approved by policy and start on probation.
- ๐ Document 1, the purchase order: the contract becomes a PO in the ERP (Odoo).
- ๐ฆ Document 2, the goods receipt: the vendor runs
/reconai shipped PO-7001 SKU=50, which counts only as a claim. ReconAI then DMs the buyer to confirm the count, and that confirmation creates the receipt. - ๐งพ Document 3, the invoice: the vendor drops it in the chat (PDF, CSV, XLSX or photo), and ReconAI runs the 3-way match immediately:
$$ Q_{PO} = Q_{GRN} = Q_{INV} \qquad\text{and}\qquad p_{INV} \le p_{\text{contract}}\,(1+\tau_p),\quad \tau_p = 0.5\% $$
Tiny differences are accepted and logged instead of escalated:
$$ \text{auto-accept} \iff |\Delta|{USD} < \$50 \;\;\lor\;\; |\Delta| < 0.001 \cdot T{\text{invoice}} $$
A real mismatch is flagged in the same chat, and a corrected invoice is linked to the original and re-matched.
- Pay. When all three agree, ReconAI DMs the approver "Ready to approve" with every check listed, and one click releases payment.
It never pays, approves its own work or edits bank details. The agent proposes, a different person approves, code posts.
The coach's math (all in code, never in the LLM)
The coach's numbers come from your PO and contract history ($p_{best}$, the lowest price you've paid) and the market percentiles $P_{25}, P_{50}, P_{75}$:
$$ \text{counter} = \min(p_{best},\, P_{25}), \qquad \text{aim} = \min(P_{50},\, p_{best}), \qquad \text{walk away above } P_{75} $$
For 50 HBM3E stacks quoted at \$1,520 against an aim of \$1,300:
$$ \text{savings at aim} = (q - a)\cdot n = (1520 - 1300)\times 50 = \$11{,}000 $$
It also pushes for better cash flow. Terms of 2/15 net 30 on a \$72,500 bill pay $72{,}500\times(1-0.02) = \$71{,}050$ when released in time, an annualized return of
$$ \frac{d}{1-d}\cdot\frac{365}{N-D} \;=\; \frac{0.02}{0.98}\cdot\frac{365}{30-15} \;\approx\; 49.7\% $$
How we built it
- Pipeline: Python + FastAPI with Pydantic contracts. Every stage is deterministic code except three bounded AI roles.
- Claude Opus 5.5:
- reads invoices with no tools, so a poisoned PDF can't trigger anything;
- plays the AP lead and controller under separate identities;
- phrases supplier emails and the coach's notes.
- Factory Droid: investigates exceptions in a read-only, per-case sandbox. It proposes skill changes on a copy of the skills repo, which only apply after a replay test passes and the controller signs off.
- Claude Sonnet 5.5: an independent LLM judge for explanation quality.
- Ledger: Beancount double entry. After every post, two invariants are checked:
$$ \sum \text{debits} = \sum \text{credits}, \qquad \sum_{v \in \text{vendors}} \text{open balance}v = \text{GL}{\text{AP control}} $$
- State: SpacetimeDB for live cases, traces and approvals.
- Integrations: Odoo 17 (POs and goods receipts), Slack Bolt, the CRS sandbox (know-your-business checks), Coinbase CDP (testnet payouts), Resend (supplier email).
- UI: React + Mantine + Vite for the AP workspace. Video: Remotion.
- Evals: 48 hand-built cases with an answer key. The headline score is deterministic:
$$ \text{catch rate} = \frac{\text{problems caught}}{\text{problems planted}}, \qquad \text{false alarm rate} = \frac{\text{clean bills flagged}}{\text{clean bills}} $$
Challenges we ran into
- Keeping the LLM away from money. We moved all math into
Decimalcode, and validators recompute every number the model cites. The model can only make an outcome stricter, never softer. - Prompt injection. Invoices and supplier messages are untrusted, so that text never reaches a model that has tools. The Droid sandbox only sees extracted JSON.
- Sandboxing Factory Droid. It runs with read-only mounts and a tool allowlist, and its only exit (a proposal file) is validated by code.
- Live model variability. Our final live run scored 46/48 because a reviewer re-plan changed which skill a clean invoice was tagged with. We fixed it, and we report live and replayed scores separately.
- Real third-party sandboxes.
- CRS locks the account after failed logins, so we log in once per process and never retry.
- Coinbase testnet amounts had to be scaled down.
- Odoo receipts had to stay in sync with our store.
Accomplishments that we're proud of
| Passed | Catch rate | False alarms | Control invariants | Onboarding |
|---|---|---|---|---|
| 48/48 | 100% | 0% | 100% | 6/6 |
- $857k in bad payments caught before they went out.
- A full quote-to-paid cycle in real Slack. In our live run, the invoice reached a release-ready prompt in about 7 minutes, against the industry's 17.4 days.
- Controls a finance team would trust:
- the requester can never approve;
- approval limits by amount;
- locked periods;
- pay only the undisputed part;
- a kill switch;
- every decision traced to a document line, a rule, a skill version, a memory version and an approver.
- A skill-evolution loop that learns from controller rejections but can't loosen controls on its own: loosening needs two signers.
What we learned
- The hardest part of AP isn't matching numbers. It's having the context when the bill arrives, which is why moving upstream to the quote changes everything.
- Agents are most useful when they are bounded: AI for reading, judgement and language; code for math, posting and permissions.
- Deterministic evals with an answer key made us faster. Every fix showed up as a number, and every regression was caught before merging.
What's next for ReconAI
- Adapter evolution: quarantine a vendor's new API or CSV format, propose a versioned adapter, and roll it out after human approval.
- Real payment rails and ERP sync, replacing the simulated settlement.
- A containerized Droid sandbox instead of a deny list.
- Auditor evidence packs: "what it knew then" for any past decision.
- Pilots with AP teams at semiconductor and hardware companies, where one wrong wafer or memory bill costs six figures.
Log in or sign up for Devpost to join the conversation.