Skip to content

Automation  ·  Finance

How to build AP invoice processing

Invoices arrive as PDFs in a shared mailbox and somebody retypes them into the ledger. Here is the model behind processing that does not need retyping, the prompts that build it, and what it takes to run in production.

Built with Tray Headless

  1. System Gmail
  2. Step Extract with scores
  3. Step Human check below threshold
  4. Step Match to the PO
  5. System NetSuite
Also Coupa

Extraction produces a confidence score per field, and anything below the threshold stops at a person before it can reach the ledger.

The short answer

What is AP invoice processing?

AP invoice processing has four moving parts: intake from wherever invoices actually arrive instead of one channel you mandated, extraction with a confidence score and a human check on anything uncertain, duplicate detection before anything is posted, and matching against the purchase order with a clear exception path. The mistake that costs most is trusting extraction. A model reading a PDF is right most of the time, and posting the times it is wrong straight to the ledger is how a supplier gets paid a decimal place too much.

What matters here

  • Take invoices from where they already arrive. Mandating a portal means half of them still come by email and nobody watches that inbox.
  • Score the extraction and check the uncertain ones. A confident wrong number posted to the ledger is worse than a slow one.
  • Detect duplicates before posting, on supplier plus invoice number plus amount. The same invoice arrives twice more often than anybody expects.
  • Never post an unmatched invoice to clear payment. Hold it, name an owner and show the discrepancy.
  • Track early payment discounts by deadline. They are free money and they expire in a queue.

Who this is for

You run accounts payable or finance systems. Invoices arrive by email, portal and post, somebody keys them in, and the month end backlog is a known quantity everybody plans around.

How it works in practice

What has to happen between an invoice arriving and a supplier being paid.

  1. 1

    Invoices are taken from every channel they arrive on

    A shared mailbox, a supplier portal, and a folder somebody drops scans into. Not one mandated route.

  2. 2

    Extraction produces values with confidence scores

    Supplier, invoice number, date, line items, tax and total, each scored instead of asserted.

  3. 3

    Anything uncertain goes to a person before posting

    High confidence posts, the middle band is checked, and low confidence is keyed by hand with the image alongside.

  4. 4

    Duplicates are caught before anything reaches the ledger

    Supplier plus invoice number, then a fuzzy pass on amount and date for the ones that were re-sent slightly differently.

  5. 5

    The invoice is matched against its purchase order

    Within tolerance clears, outside it stops with the discrepancy shown.

  6. 6

    Payment is scheduled against terms and discounts

    Early payment discounts surfaced before the deadline, not reported after it.

What AP processing is made of

Four parts, and the second is the difference between automation and a liability.

Multi-channel intake

Mailbox, portal and folder, normalised into one queue. Suppliers send how they send, and a mandated channel captures only the compliant half.

Scored extraction

Every field with a confidence, and a threshold that sends the uncertain ones to a person with the original image beside the form.

Duplicate detection

Before posting, not after. Exact on supplier and invoice number, then fuzzy on amount and date for the re-sends.

Matching with exceptions

Against the purchase order and receipt, with tolerances, and every mismatch assigned to a person instead of pooled.

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

    Start here: take invoices from every channel

    Because a mandated portal captures the compliant suppliers only.

    Headless skills build-workflow

    Use build-workflow. The systems in play are Gmail, NetSuite, Coupa,
    Google Drive, Slack and Snowflake, or whatever we run in those seats.
    Before you plan anything, tell me which of them are already
    authenticated in the workspace, because I do not want a connector
    stubbed that I have not authenticated.
    
    Build intake from all of these into one queue, landing each as a
    NetSuite VendorBill draft matched against its PurchaseOrder and
    ItemReceipt:
    
      The shared AP mailbox, attachments only, ignoring the reply chains
      The supplier portal, where suppliers who use it upload
      A watched folder for scans and anything forwarded on
    
    Normalise them into one record with the source, the original file, and
    the arrival timestamp. Keep the original file forever. It is the evidence
    and it will be asked for.
  2. 2

    Extract with confidence, and check the uncertain ones

    The step where trusting a model too far becomes an overpayment.

    Headless skills build-workflow

    Use build-workflow. Extract supplier, invoice number, invoice date, due
    date, currency, line items, tax and total, and give each field a
    confidence.
    
    Then band the result:
    
      every field above the high threshold   post straight through
      anything in the middle band            queue for a quick human check
      anything low, or a total that does not equal the sum of lines plus tax
                                             key it by hand
    
    Always show the original image beside the extracted values in the review
    screen. A reviewer checking numbers against a form they cannot see is not
    checking anything.
    
    Never post a field the model was unsure about. A confident wrong total
    becomes a payment.

    The arithmetic check is the cheapest control here. If lines plus tax does not equal the total, extraction has misread something regardless of how confident it was.

  3. 3

    Catch duplicates before anything posts

    The same invoice arrives twice more often than anybody expects.

    Before posting, check for duplicates in this order:
    
      Exact: same supplier and same invoice number, ever
      Near: same supplier, same amount, within a few days, different number
      Fuzzy: same amount and date across two supplier records that may
      themselves be duplicates in the vendor master
    
    Block the exact ones outright. Flag the near ones for review with both
    invoices shown side by side.
    
    Suppliers re-send. A chased invoice arrives again with a new reference,
    and a statement re-sends everything outstanding. Both of those look like
    new invoices to anything checking only the number.
  4. 4

    Match, and route what does not

    So the only invoices anybody touches are the ones that need touching.

    Headless skills tray-gotchas

    Use tray-gotchas, then match against the purchase order and receipt with
    tolerances I can set.
    
    Within tolerance clears for payment. Outside it stops and routes to a
    named person with the order, the receipt and the invoice side by side and
    the difference highlighted.
    
    Handle these:
    
      No purchase order at all. Route to the cost centre owner to confirm and
      attach one, do not reject and do not pay.
      Partial delivery. Pay for what arrived, keep the balance open.
      Credit note. Match it to the original invoice rather than treating it
      as a negative invoice floating on its own.
      Supplier not in the vendor master. Stop. A new supplier is an onboarding
      process, not an invoice field.
  5. 5

    Schedule payment against terms, and chase the discounts

    Early payment discounts are free money that expires in a queue.

    Schedule payment from the supplier terms rather than the invoice date,
    and surface early payment discounts before their deadline, not after.
    
    Report weekly: invoices processed by channel, straight-through rate,
    average days to process, exceptions by reason, duplicates caught, and
    discounts available against discounts taken.
    
    That last pair is the number that pays for this. A discount missed
    because an invoice sat in a queue is a cost with nobody attached to it.
  6. 6

    Validate, then hand the thresholds to AP

    Because tolerances and confidence bands are finance judgement.

    Run the per-step schema checks and the whole-workflow audit before this
    touches production. Run in review-everything mode for a fortnight first,
    so the confidence thresholds are set from real invoices, not 
    guessed.
    
    Then open the same workflow in Tray Build so accounts payable can move
    the confidence bands and the matching tolerances in the visual canvas.

What it connects to

Invoices arrive in several places and end up in one ledger.

Gmail

Take invoices from the shared AP mailbox, attachments only, and keep the original message as evidence.

Reads

NetSuite

Read purchase orders, receipts and the vendor master. Post the invoice and clear it for payment.

Reads and writes

Coupa

Read the purchase order and receipt where procurement runs there instead of in the ERP.

Reads

Google Drive

Store the original document against the posted invoice, because the ledger entry is not the evidence.

Reads and writes

Slack

Route an exception to the named owner with the discrepancy, and warn before a discount deadline.

Writes

Snowflake

Land processing history, so straight-through rate and discount capture are measurable by supplier.

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, SharePoint, Microsoft Outlook 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 posts to the ledger and schedules payments. Both are audited and both are irreversible in practice.

It runs where production runs, not on a laptop

Intake from three channels, extraction and matching run continuously on the same engine, including through the month end spike.

The original document is kept, always

Posted values are traceable back to the image they came from, with the extraction confidence recorded. That pairing is what an audit needs.

Credentials are managed, never in code

A credential that can clear an invoice for payment is among the most sensitive you hold. It lives in your workspace, scoped and separately rotatable.

AP owns the thresholds

Confidence bands and matching tolerances open in Tray Build, tuned by the team reviewing the exceptions.

Nothing uncertain posts silently

Below the threshold it waits for a person. A wrong number posted confidently becomes a payment, and recovering an overpayment is a supplier conversation.

Questions people ask

Should extraction post straight to the ledger?

Only above a high confidence threshold, and only when the arithmetic checks out. A confidently wrong total becomes a payment, and recovering an overpayment is a conversation with a supplier.

Why take invoices from multiple channels?

Because mandating a portal captures the suppliers who comply and leaves the rest arriving by email into an inbox nobody watches. Take them where they already come.

How do duplicates get through?

Suppliers re-send. A chased invoice returns with a new reference and a statement re-sends everything outstanding, so checking the invoice number alone misses both. Match on supplier, amount and date as well.

What happens to an invoice with no purchase order?

It stops and routes to the cost centre owner to confirm and attach one. Rejecting it annoys a supplier who did nothing wrong, and paying it defeats the control.

What is the number that justifies this?

Early payment discounts available against discounts taken. They are free money, they expire in a queue, and almost nobody measures the gap.

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 an invoice approval queue (opens helix.tray.ai in a new tab)

Last reviewed September 2026.