Skip to content

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

  1. System Coupa
  2. Step Check the budget
  3. Step Route on the matrix
  4. Step Three-way match
  5. System NetSuite
Also Slack

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. 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. 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. 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. 4

    An approved requisition becomes a purchase order

    And the commitment is recorded at that moment, not when the invoice arrives.

  5. 5

    Receipt, order and invoice are matched three ways

    Within tolerance on price and quantity. Anything outside stops for a person.

  6. 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. 1

    First, read the procurement and finance models

    Approval and budget both live in places the requester never sees.

    Headless skills build-workflow

    Use 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. 2

    Check the budget before anybody approves

    So the answer arrives while it can still change the decision.

    Headless skills build-workflow

    Use 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. 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. 4

    Match three ways, with tolerances

    Two-way matching pays for things that never arrived.

    Headless skills tray-gotchas

    Use 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. 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. 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)

Last reviewed September 2026.