Inspiration
Small businesses and freelancers regularly verify incoming supplier invoices by hand before sending money: Does the supplier match our purchase order? Do net + VAT add up to the billed gross total? Did someone already pay this invoice reference? Letting an autonomous LLM trigger payments directly creates unacceptable accounting and security risk—so we designed a strict separation between probabilistic AI assistance and deterministic payment authorization.
What it does
SyntraVariga Invoice & Payment Guard runs a six-stage auditable workflow under branch feature/invoice-guard-public (ai-studio/):
- Structured Field Proposal (
POST /api/ai/extract): Extractsvendor,invoice_number,net_amount,tax_amount,gross_amount, andamountfrom fictitious English or German invoice text. Missing placeholders (---,N/A) and ambiguous conflicting totals are surfaced with explicit manual-review warnings rather than guessed. Runs 100% locally via a transparent deterministic regex parser (non-AI fallback) by default and calls Google Gemini (configuredgemini-3.8-flashprimary with resilient Flash failover—verified live ongemini-3.5-flash-lite) only with explicit user opt-in (allow_external_ai: true). - Human Inspection & Confirmation: A reviewer inspects, edits, or selects ambiguous candidates manually. Any field edit immediately invalidates any prior sealed verification receipt.
- Deterministic Integer-Cent Verification (
invoiceGuard.ts): Evaluates confirmed fields strictly in integer cents (Net + Tax === Gross === Payable Amount), applies UnicodeNFKCsupplier comparison against the expected purchase order, and supports optional SHA-256 duplicate-invoice checks (DUPLICATE_INVOICE). Only deterministic rules decideFIELDS_CONSISTENTvs.REVIEW_REQUIRED. - Tamper-Evident Audit Ledger & Zero-PII Explainer (
POST /api/ai/explain): Seals each review inside an append-only RFC 8785 canonical JSON + FIPS 180-4 SHA-256 chain stored in ACID SQLite. By default it uses a deterministic local rule dictionary (non-AI); when explaining findings with explicit Gemini opt-in, only{ status, finding_codes }leave the server—zero invoice vendor names, numbers, or amounts. - Server-Bound PayPal Sandbox Checkout & Crash Recovery: Reserves the verified one-time receipt in SQLite (
BEGIN IMMEDIATE) with deterministicPayPal-Request-Ididempotency keys before callinghttps://api-m.sandbox.paypal.com/v2/checkout/orders, bindsEURcurrency,verified_amount_eur, andcustom_idto the server-side receipt, enforces explicit buyer approval before capture, validates rawPOST /captureresponses before queryingGET /v2/checkout/orders/{id}whencustom_idis omitted (rejecting any amount/status/capture-ID contradictions fail-closed), and transitions gateway timeouts or interrupted operations intoUNKNOWN_RECONCILIATION_REQUIREDfor manual reconciliation rather than blind retries. - Batch Sample Triage & Isolated Negative Self-Tests: Demonstrates deterministic triage across 5 synthetic invoices and executes 4 isolated negative checks (receipt forgery guard, post-review amount mismatch, atomic replay block, and Zero-PII payload guard) in a temporary SQLite store without touching the main audit ledger.
How we built it
- Frontend (
ai-studio/src/): React 19, TypeScript, Tailwind CSS, Lucide icons, WCAG contrast & keyboard-accessible Audit Ledger explorer, mobile-responsive layout, and persistent SQLite payment resume/reconciliation views. - Backend & Persistence (
ai-studio/server.ts,persistentStore.ts): Node 24 (node:sqliteWAL + nativenode:cryptoSHA-256), Express with exactscheme://host:portvalidation and single-instance PID locking (acquireSingleInstanceServerLock), strict PayPal response verification (paypalSandbox.ts), and bounded request timeouts with resilient Flash model failover on external Gemini requests.
Challenges we ran into & Honest Boundaries
- No magic AI claims: LLMs can misread numbers or hallucinate missing VAT fields. Blocking placeholders and keeping payment locks purely deterministic prevented prompt or model quirks from unlocking checkout.
- Database recovery vs. multi-process safety: Startup crash recovery locks transient
RESERVED_ORDERandCAPTURE_PENDINGrows intoUNKNOWN_RECONCILIATION_REQUIRED, so supporting two Express processes on one database file would falsely lock sibling requests. We enforce a per-database.server.pidlock instartServer()and clearly scope supported deployment to one server process per database. - Explicit non-claims: Passing deterministic rules confirms internal arithmetic and purchase-order consistency on user-confirmed fields—it is not proof of legal invoice authenticity, supplier identity verification, or absolute prevention of out-of-band double payments.
Accomplishments & Verification
- Automated Test Matrix: 51 TypeScript tests (
npm test—including multi-process child crash recovery, concurrent SQLite lock race checks,AIza*/AQ.*key & Flash failover checks, strict PayPal capture contradiction & POST-before-GET reconciliation checks, exact host/origin checks, and isolated HTTP end-to-end lifecycle) + 7 reference Python tests (npm run test:python), passingtsc --noEmitand Vite production build (0 warnings). - Performance Optimization: Replaced repeated pure-JS full-ledger passes with single-transaction native
node:cryptoverification (600events:GET /api/ledger87.51 ms -> 34.78 ms,POST /api/review173.50 ms -> 51.34 ms). - Live External APIs Verified (Fictitious Data Only, Clearly Separated from Local Non-AI Fallback):
- Google Gemini (
LIVE_GEMINI_API): Verified authenticated live/api/ai/extract(Beispieltechnik GmbH/119.00 EUR,HTTP 200, SQLite ledger event12) and Zero-PII/api/ai/explain(REVIEW_REQUIRED+["EXPECTED_AMOUNT_MISMATCH"],HTTP 200, SQLite ledger event13) viaAQ.*auth key; automatic capacity failover executed cleanly ongemini-3.5-flash-litewhengemini-3.8-flashhit transient503/504limits and recorded the activemodel_idin SQLite. Default unchecked mode remains deterministic local parsing/lookup (non-AI). - PayPal Sandbox REST (
LIVE_PAYPAL_SANDBOX_REST,https://api-m.sandbox.paypal.com): Verified live Sandbox order8DH65564PK409905U(119.00 EUR, bound to verified receipt viacustom_id), real DE Sandbox Personal test-buyer approval, captured settlement (3ND85370G4181781M,COMPLETED,119.00 EUR), reconciliation handling, and SQLite state persistence across full server restart (LEDGER: PASS).
- Google Gemini (
What we learned & What's next
Separating probabilistic AI extraction from deterministic financial state machines makes AI workflows auditable. Next steps include external head-hash anchoring, multi-currency invoice rules, and webhook reconciliation with merchant accounting ledgers.
Built With
- express.js
- google-gemini
- node.js
- paypal
- python
- react
- sqlite
- tailwindcss
- typescript
- vite