How to Build an AI-Powered Invoice Processing Pipeline
Extract data from PDF invoices, validate it, and push it to your accounting system.
What This Integration Does
Vendor invoices arrive in dozens of formats: scanned PDFs, system-generated PDFs with embedded text, image-only attachments, and occasionally inline HTML. Hand-keying these into your accounting system is slow and error prone. This workflow ingests each invoice email, pulls structured fields out of the PDF with AI, validates them, and creates a vendor bill ready for approval.
The workflow runs every time an invoice email arrives at a dedicated Spojit mailhook address. It fetches the bytes of each PDF attachment, extracts the text, uses a Connector node in Agent mode to produce a structured invoice record, validates the result against business rules, optionally pauses for a human approver, and then writes the record into NetSuite. Each processed invoice is also embedded into a Knowledge collection so future runs and your team can search past vendor activity.
Prerequisites
- A Trigger node set to Mailhook, with the generated address pointed at by your invoice forwarding rules.
- A NetSuite connection with permission to create records and read vendor records.
- A persistent Knowledge collection for archiving processed invoices (optional, only if you want a searchable archive).
Step 1: Mailhook Trigger
Add a Trigger node and set Trigger Type to Mailhook. Give it an address prefix such as invoices, then click Generate email address and forward your accounts-payable mail to the generated ...@mailhook.spojit.com address. Add an optional From allowlist or Subject regex filter if the address also receives non-invoice traffic. The trigger output is available downstream as {{ input }}, including {{ input.subject }}, {{ input.from }}, and the attachment references in {{ input.attachments }}.
Step 2: Fetch the PDF and Extract Text
Add an Attachment node (this node is only available in Mailhook workflows) to pull the actual bytes of the invoice PDF. Set Mode to Single, set the Content type filter to application/pdf, and optionally a Filename pattern like *.pdf. The node outputs { filename, contentType, size, content }, where content is base64.
Next add a Connector node pointing at the pdf connector with the extract-text tool, feeding it {{ attachment.content }}. The output is plain text the extraction step can consume. If an invoice can carry several PDFs, set the Attachment node to Multiple instead and wrap the extract step in a Loop over {{ attachment.attachments }}.
Step 3: AI Extraction with Structured Output
Add a Connector node in Agent mode. Feed it the extracted text and use a Response Schema to force structured JSON output:
{
"vendor": "string",
"invoiceNumber": "string",
"date": "string",
"dueDate": "string",
"currency": "string",
"total": "number",
"lineItems": [
{ "description": "string", "quantity": "number", "unitAmount": "number", "amount": "number" }
]
}
Include a short prompt that tells the Agent-mode step how to handle missing fields (use null), how to parse dates (ISO 8601), and how to normalize amounts (no thousands separators). If you prefer not to spend AI credits on each invoice, you can instead use a Knowledge node: embed the extracted text into a Transient collection, then query that collection in the same run with a Response Schema matching the shape above.
Step 4: Validate
Add a Transform followed by a Condition to check that required fields are present, the line items sum to the total within one cent, and the vendor matches a record in NetSuite. Use a Connector node on netsuite with the run-suiteql tool to query the vendor table and confirm the vendor exists. If validation fails, route to a Connector node on slack with the send-message tool to alert your accounts-payable channel, and stop.
Step 5: Human Approval Above Threshold
Add a Condition on {{ invoice.total }}. For invoices over your threshold (say USD 5,000), route through a Human approval node. Set its Message and Notification body to surface the parsed fields with {{ variables }}, and add an Approval slot for your finance approver (a User, Role, or Team atom). Approvers respond in the Approvals inbox. If they reject, the workflow halts, so there is no separate rejection branch to wire up. Lower-value invoices skip straight to creation.
Step 6: Create the Vendor Bill and Archive
Add a Connector node pointing at netsuite with the create-record tool, record type vendorbill. Map the parsed fields onto the NetSuite record, including each line item. After the create succeeds, add a Knowledge node in Embed mode and write a copy of the parsed invoice into your persistent collection so future workflows and search can find it by vendor or invoice number.
Tips
- Image-only PDFs return little or no text from
extract-text. Branch on empty text with a Condition and route those runs to a slacksend-messagealert for manual handling, or embed the attachment into a Knowledge collection using the Images (via OCR) document type. - Keep a short list of "known vendors" in the Agent-mode prompt context. Accuracy on vendor name normalization jumps when it has a list to choose from.
- Stamp the source
{{ input.messageId }}on the NetSuite record. It makes audits and dedup checks much easier.
Common Pitfalls
- Duplicate invoices. The same vendor sometimes emails a reminder copy a week later. Check NetSuite for an existing bill with the same vendor and invoice number before creating.
- Multi-currency rounding. Trust the invoice's stated currency rather than guessing from a symbol, and let NetSuite handle the FX conversion at post time.
- Tax lines treated as line items. Add a rule to the prompt that taxes go into the bill's tax field, not a separate item line.
Testing
Forward five real invoices from different vendors to your generated mailhook address, one at a time. Watch the execution history in Spojit for each run, confirm the parsed fields, and check that the NetSuite vendor bill matches the PDF. Only widen the From allowlist and turn on full-volume forwarding after the parsed output looks consistent across at least a dozen samples.
Learn More
- Connector node documentation
- Knowledge base documentation
- NetSuite connector documentation
- PDF Tools documentation
- Mailhook trigger documentation
- Attachment node documentation
- Setting Up a Mailhook Trigger
- Using Knowledge Nodes
- Using Human Approval Nodes
- Create NetSuite Sales Orders from Emailed PO PDFs