Construction Operations · ERP Automation Case study
AI-Assisted Sage Intacct Automation
Reis Contracting / Agent.Press
AI-assisted automation for construction operations running through Sage Intacct.
Reis Contracting / Agent.Press
AI-Assisted Sage Intacct Automation AI-Assisted ERP Automation
Senior Full-Stack AI Engineer · Architecture & Delivery
System map · Workflow
Verified proof
- ~1 hour → minutes Project-level processing
- Nearly 99% Successful transaction processing
Automation flow
Input
- Estimates
- Subcontracts
- Change orders
- Change requests
- Subcontract invoices
Validation
ERP lookup before extraction
Orchestration
Declared tools, then a human approval gate
Sage Intacct
External system · one write path
Result
A posted record, attributable to a document
Retry · fallback · rejection reported per field
Engineering
AI-assisted workflows · Tool calling · Validation · Sage Intacct · Load testing
Named with approval · Proprietary implementation omitted
- Role
- Senior Full-Stack AI Engineer · Architecture & Delivery
- Delivery
- Agent.Press engagement
- Disclosure
- Named with approval · Proprietary implementation omitted
- Links
- Product website
The problem
What the system had to solve.
Manual construction and accounting workflows around Sage Intacct required significant project-level processing time across connected operational records.
What I owned
The responsibility behind the work.
Architected and delivered the AI-assisted automation platform covering Estimates, Subcontracts, Change Orders, Change Requests and Subcontract Invoices, from the Sage Intacct integration through extraction, validation and the production failure paths.
Built on the Agent.Press platform: the extraction and lookup tools that confirm a record against the ERP before anything is written, the validation ahead of every write, and the retry and fallback behaviour behind them.
Engineering approach
How it was built.
Built the workflow automation, external-system integration, validation and production error handling, with lookup tools that confirm a record against the ERP before anything is extracted or written, and a load-testing suite to check the paths under concurrency.
Automation flow
- Input
- Validation
- Orchestration
- ERP
- Result
Why ERP automation is different
The write is the whole problem.
Most AI features fail softly. A summary is a bit off, a suggestion is ignored, and a user moves on. Writing into an accounting system is not that. A wrong subcontract, a duplicated invoice or an estimate posted against the wrong project is a financial record that someone has to find, understand and reverse.
So the interesting engineering here is not extraction. It is everything arranged around the extraction to make sure a write is correct, expected, and traceable to a document a human approved.
Record types handled
- Estimates
- Subcontracts
- Change requests
- Subcontract invoices
Every one of these has downstream financial consequences. None of them is a good candidate for a model writing directly into an ERP.
From document to posted record
The order of operations is the safety model.
A document does not go straight to extraction. It is classified, the records it refers to are confirmed to exist in the ERP, and only then is anything extracted from it. Extraction produces structured data, which is checked and mapped, and which a person approves before any write is attempted.
Processing pipeline
- Document received
- Classification Which kind of record is this
- ERP lookup Confirm project, vendor or estimate exists
- Structured extraction Per document type
- Validation and field mapping
- Human approval
- Write to the ERP
Confirming the record first means extraction is anchored to something real. A document referring to a project that does not exist fails at lookup, cheaply, instead of producing a confident extraction that cannot be posted.
Tools, not prompts
What the agent is actually allowed to do.
The agent has no direct access to the ERP. It has a set of declared tools, each with a schema and a single job, executed by the runtime. Reading and writing are separate tools, and the difference between them is enforced by which tools exist rather than by instruction.
The tool surface
Read and confirm
- Classify document
- Look up project
- Look up vendor
- Look up estimate
- Resolve file reference
Extract
- Estimate
- Subcontract
- Subcontract invoice
- Change request
Write
- Approve and submit extracted data
One write tool, reached only after the read and extract tools have done their work.
A separate extraction tool per record type is more code than one general extractor, and worth it: each document type has its own shape, its own required fields and its own failure modes.
The approval gate
Nothing reaches the ERP unreviewed.
Extraction produces a structured result held against an identifier. It is not posted. A person reviews what was extracted and approves it, and only that approval triggers submission. The gate is a step in the pipeline rather than a convention someone might skip.
Two submission modes
All or nothing
The default.
- Every line must resolve in the ERP
- One unresolvable line fails the submission
- Nothing partial is posted
- Used when the record must be complete to be meaningful
Partial submission
Explicitly requested.
- Valid lines are posted
- Unresolvable lines are reported, not posted
- Used when most of a document is actionable
- The remainder is handled separately
The default is the strict one. Partial submission is available because real documents are sometimes partly wrong, but it has to be asked for.
Talking to the ERP
An integration layer, not a client call.
Sage Intacct is reached through a dedicated integration layer rather than from the tools directly. That layer owns the transport, the per-record-type request construction, the mapping between extracted fields and ERP fields, and the interpretation of what comes back.
What the integration layer owns
- Transport and session handling
- A module per record type
- Field mapping between extraction and ERP
- Error response parsing
- Shared types across the boundary
Error parsing earns its own module. An ERP does not fail with a clean status code; it returns structured errors describing which field on which line was rejected and why. Turning that into something a user can act on — rather than a stack trace or a generic failure — is most of the difference between an automation people trust and one they stop using.
Failure paths
What happens when it does not work.
Every stage has a way of going wrong that a person eventually has to understand: an unreadable document, a project that does not exist, an extraction missing a required field, a line item that does not resolve, an ERP that rejects a write. Each fails at its own stage with the reason attached rather than surfacing as a generic error at the end.
Where a document can stop
- Document in progress
- Classification fails Unrecognised document type
- Lookup fails Referenced record not in the ERP
- Extraction incomplete Required fields missing
- Mapping fails Line items do not resolve
- ERP rejects the write Parsed and reported per field
Retry and fallback sit behind these paths, but the first requirement is that a failure is attributable. An automation that fails without saying where is worse than no automation, because someone still has to check the work.
Built on the platform, not beside it
Why this is not a standalone application.
The automation is delivered on the Agent.Press platform: it depends on the published runtime, tool contract and console rather than carrying a private copy of them. The client-specific work is the tools, the ERP integration and the document handling. The agent loop, conversation state, retrieval and observability come from the platform.
What belongs where
From the platform
- Agent runtime and model loop
- Tool execution and validation
- Conversation state
- Console and surfaces
- Tracing
Client-specific
- ERP integration layer
- Per-record extraction tools
- Lookup and approval tools
- Field mappings
- Document classification
Behaviour under concurrency
Testing the paths that write.
The transaction paths were exercised under concurrency with a dedicated load-testing suite. The question being asked is not throughput. It is whether the same document processed twice produces one record, whether concurrent submissions against the same project stay correct, and whether failures under load stay attributable.
What load testing was for
- Duplicate submission behaviour
- Concurrent writes against one project
- Failure attribution under load
- Integration behaviour at rate
Engineering scope
What I worked on.
- Workflow automation across connected operational records
- Sage Intacct integration and record lookup
- Extraction tools that confirm a record before writing to it
- Validation ahead of downstream writes
- Production error handling, retry and fallback
- Load testing of the transaction paths under concurrency
Why these decisions mattered
The trade-offs behind the automation.
Lookup before extraction
A human approval gate
Strict submission by default
One extraction tool per record type
A dedicated integration layer
Delivered on the shared platform
Impact
The verified result.
Reduced project-level processing from approximately one hour to a few minutes, with nearly 99% successful transaction processing.
Technology
The technical surface.
- AI-assisted workflows
- Sage Intacct
- Tool calling
- Validation
- Integrations
- Load testing