Integration · Finance
How to build a procure-to-pay integration
A team commits to a twelve month contract and finance finds out when the invoice arrives. The thinking behind procure-to-pay that catches it earlier, the prompts that build it, and what it takes to keep it running.
Built with Tray Headless
- System Coupa
- Step Check the budget
- Step Route on the matrix
- Step Three-way match
- System NetSuite
The budget check runs before the commitment, and the approval matrix is data the finance team can change without a deployment.
The short answer
What is a procure-to-pay integration?
A procure-to-pay integration breaks into four parts: an approval matrix held as data instead of hardcoded, a budget check that runs before the commitment rather than after the invoice, three-way matching between order, receipt and invoice, and exceptions routed to a person instead of a queue. Where this usually goes wrong is the budget check. Approving a purchase and then discovering the cost centre is exhausted is a conversation nobody wants, and it happens after the supplier has already been told yes.
What matters here
- Check the budget before the approval, not after the invoice. A commitment made against an exhausted cost centre is already a problem.
- Hold the approval matrix as data. Thresholds and delegations change with every reorganisation and should not be a deployment.
- Match on three documents, not two. Order against invoice misses the goods that never arrived.
- Route exceptions to a named person with the discrepancy attached. A queue of unmatched invoices is where early payment discounts die.
- Record the commitment at PO, not at invoice. Committed spend is the number that makes a budget report honest.
Who this is for
You run finance systems or procurement operations. Purchase requests arrive by email, approvals happen in threads, and the first time finance sees a commitment is when the invoice lands.
How it works in practice
What has to happen between somebody needing something and a supplier being paid.
- 1
A requisition is raised with a cost centre and a category
Not a free text description. Both drive the approval path and the budget check.
- 2
The budget is checked before anybody approves
Committed plus actual against the line. An exhausted cost centre is a conversation now, not in six weeks.
- 3
The approval matrix routes on amount, category and cost centre
Held as data, with delegation for anybody away, because a purchase waiting on somebody on leave is a stalled purchase.
- 4
An approved requisition becomes a purchase order
And the commitment is recorded at that moment, not when the invoice arrives.
- 5
Receipt, order and invoice are matched three ways
Within tolerance on price and quantity. Anything outside stops for a person.
- 6
Matched invoices clear for payment automatically
The ones that did not match are the only ones anybody looks at, which is the point.
What procure-to-pay is made of
Four pieces, and the second is what stops finance being surprised.
An approval matrix as data
Amount bands, category rules, cost centre owners and delegations in a table finance maintains, not logic somebody deploys.
A budget check before commitment
Committed plus actual against the line, evaluated at requisition instead of at invoice, so the answer arrives while it can still change the decision.
Three-way matching
Purchase order, goods receipt and invoice, with tolerances. Two-way matching pays for things that never arrived.
Routed exceptions
Every mismatch to a named person with the discrepancy shown. An unmatched invoice queue is where early payment discounts are lost.
The Tray Headless prompts
Paste these into Claude Code or Codex with the Tray Headless plugin installed. Each stage runs on its own. The systems named in them are the worked example rather than a requirement, and every prompt says so.
Once per project, run
/tray-workflows:set-workspace
to pick the workspace these build in. Point it at a sandbox first.
- 1
First, read the procurement and finance models
Approval and budget both live in places the requester never sees.
Headless skills
build-workflowUse build-workflow. The systems in play are Coupa and NetSuite, or whatever we run in those seats. I need the requisition, purchase order, receipt and invoice objects, plus the chart of accounts, cost centres and how budget is held per period. Specifically: where does committed spend live, and is it a real field or something everybody calculates in a spreadsheet. That answer decides most of this build.
- 2
Check the budget before anybody approves
So the answer arrives while it can still change the decision.
Headless skills
build-workflowUse build-workflow. On requisition submit, before routing for approval: Resolve the cost centre and the budget line from the category Sum posted actuals for the period Add open commitments from approved purchase orders not yet invoiced Compare against the budget for that line Show the requester the remaining budget before they submit, not after somebody approves. If the request would exceed the line, route it to the budget owner first regardless of amount. A commitment made against an exhausted cost centre is a problem that gets discovered in six weeks by somebody who cannot fix it.
- 3
Route on a matrix finance can edit
Because thresholds change with every reorganisation.
Build the approval matrix as a table, not as logic: amount band, category, cost centre, approver role, and whether the approval is sequential or parallel Resolve approvers to real people through the directory at run time. Never hardcode a name, because the person who approved capital expenditure last year has changed role. Handle delegation: anybody marked away routes to their deputy automatically. A purchase request waiting five days on somebody on leave is a purchase that gets made on a personal card instead. Above a threshold I set, require two approvers and record both.
- 4
Match three ways, with tolerances
Two-way matching pays for things that never arrived.
Headless skills
tray-gotchasUse tray-gotchas, then build three-way matching between the purchase order, the goods receipt and the supplier invoice. Tolerances I can set: a small percentage or absolute on price, a percentage on quantity, and a window on date. Within tolerance clears automatically. Outside stops. Handle these explicitly: Partial delivery. Match what arrived, keep the remainder open, do not clear the whole invoice. Invoice before receipt. Hold rather than reject, because the goods are usually two days behind the paperwork. Price change between order and invoice. Always an exception, never a tolerance, because that is a supplier changing terms. Duplicate invoice number from the same supplier. Block it outright.
- 5
Route exceptions to a person, and report the commitment
Because an unmatched queue nobody owns costs real money.
Every exception goes to a named person with the discrepancy shown side by side: what was ordered, what arrived, what was invoiced, and the difference highlighted. Do not build a queue that a team collectively owns. Assign each one. Then report: committed versus actual by cost centre, exceptions by reason and by age, early payment discounts available and how many were missed, and average days from requisition to purchase order. That last number is the one procurement is judged on and the one nobody measures.
- 6
Validate, then hand the matrix to finance
Because approval thresholds are a finance policy.
Run the per-step schema checks and the whole-workflow audit before this touches production. Then open the same workflow in Tray Build so finance can maintain the approval matrix, the tolerances and the delegation rules in the visual canvas. Every reorganisation changes them.
What it connects to
Procurement holds the process, finance holds the money, and people need telling.
Coupa
Read requisitions, purchase orders and receipts, and write the approval outcome back where procurement works.
Reads and writes
NetSuite
Read budget, actuals and the chart of accounts. Write the commitment at purchase order and clear matched invoices for payment.
Reads and writes
Okta
Resolve an approver group to the people currently in it, so the matrix names a group instead of an individual who may have moved on.
Reads
Slack
Send the approval request where approvers already are, and chase before a discount deadline passes.
Writes
Google Drive
Attach the quote and the supplier contract to the requisition, which is what an auditor asks for first.
Reads and writes
Snowflake
Land commitments and exceptions, so committed spend by cost centre is a query instead of a month-end assembly.
Writes
Same build, other stacks
The design does not change if you run something else in one of these seats. The same prompts build it against SAP S/4HANA, Google BigQuery, Microsoft Teams, Azure Active Directory, SharePoint or Oracle.
Named systems are the ones most teams run, not the only ones that work. Each is an authentication in your Tray workspace, referenced by name, so the workflow never holds a credential. Where we have a connector page, the name links to it.
Running it in production
This commits company money and clears invoices for payment. It is audited.
It runs on the platform, not on your laptop
Budget checks at submit and matching at invoice both run on the same engine, at whatever volume month end produces.
Every approval is evidence
Who approved, at what amount, against which matrix version. That is the first thing an auditor asks for and the hardest thing to reconstruct.
Credentials are managed, never written into the build
The credential here can approve a commitment against a budget. It lives in your workspace, scoped to procurement, and nowhere near the matching logic.
Finance owns the matrix
Approval bands, tolerances and delegation open in Tray Build, maintained by the team that sets the policy.
Exceptions are assigned, never pooled
An unmatched invoice with no owner is an early payment discount already lost. Each one gets a name and an age.
Questions people ask
Why check budget before approval?
Because approving a purchase and then discovering the cost centre is exhausted is a conversation nobody wants, and by then the supplier has been told yes. Checking at requisition puts the answer where it can still change the decision.
What is three-way matching?
Comparing the purchase order, the goods receipt and the supplier invoice before paying. Two-way matching, order against invoice, pays for goods that never arrived.
Does procure-to-pay need EDI?
Not for the API-connected path this covers. Some manufacturing and distribution estates exchange orders with suppliers over EDI, and where that is the case it sits upstream and this picks up from the purchase order onward.
Why record the commitment at purchase order?
Because a budget report showing only invoiced spend is wrong by however much has been ordered and not yet billed. Committed plus actual is the only honest view.
Can finance maintain the approval matrix themselves?
Yes. Bands, categories, tolerances and delegation open in Tray Build, so a reorganisation is a table edit instead of an engineering ticket.
Vibe-coding app guides
Vibe-code an entire app with Helix
This moves the data between systems. It does not give anybody a screen to work in. Build that app in Claude Code, Codex or Cursor, then deploy and run it governed on Tray Helix. Same kind of guide, same kind of prompts.
How to build a purchase approval workflow (opens helix.tray.ai in a new tab)
Related guides
Finance
How to build AP invoice processing
Take invoices from wherever they arrive, extract and verify instead of trust, match against the order, and never pay the same one twice. The prompts that build it.
Revenue operations
How to build an order-to-cash integration
Closed-won to sales order to invoice to cash applied, as a CRM to ERP integration. Idempotent writes, a reconciliation loop, and the Headless prompts that build it.
Finance
How to build a vendor master sync
Onboard a supplier once, verify bank details out of band, keep one record per legal entity, and make a change to payment details an event. The prompts.
Platform engineering
How to migrate an SFTP batch feed to an API
Recover the semantics nobody wrote down, run both in parallel and diff, and cut over only after a month end. The Headless prompts that build it.
Last reviewed September 2026.