Data extracted from documents in integrator.io passes through three layers of checks before it reaches a destination: Celigo validates the AI agent's response against your schema, the agent flags values it couldn't read, and your flow checks the values against your business rules and systems of record. Records that fail a check wait in error management, where a person reviews the extracted data, corrects it, and retries it. Everything else continues without anyone touching it.
Use this pattern for any document that creates a financial or operational record — a vendor bill, a sales order, a payment — so that uncertain data never posts silently. It's the same error management your team already uses for every other flow, so reviewers work in a familiar place.
How the checks work together
| Layer | What it catches | Where it runs |
|---|---|---|
| Schema validation | A response with missing required fields, wrong types, or an invalid structure | Celigo, automatically, on every agent response |
| Review flags | Values the agent couldn't find, couldn't read, or found more than one candidate for | The agent, through review fields in your schema |
| Business rules | A purchase order that doesn't exist, totals that don't add up, an unknown vendor, a duplicate invoice, a price outside your tolerance | Your flow: lookups, branch conditions, and hooks |
Use checks in the flow for every value that affects money, inventory, or a customer: they're exact, and they use data in your other systems that the agent can't see.
Add review flags to the agent's output
Add needs_review (boolean) and review_reasons (array of strings) to the extraction schema, list both as required, and tell the agent in its instructions to set them — instead of guessing — when a required value is missing, unreadable, or ambiguous, or when the document isn't the type you expect. The invoice schema and instructions in Extract data from documents include both fields.
Check extracted values in the flow
Common checks for documents that create transactions:
- The referenced record exists — A lookup finds the purchase order, customer, vendor, or item by the extracted identifier. No match is an exception.
- The amounts agree — Line amounts add up to the subtotal, and the subtotal plus tax and shipping equals the total due.
- The values are within tolerance — Extracted prices and quantities match the purchase order within the percentage or amount you accept.
- It's not a duplicate — A lookup searches for an existing record with the same vendor and invoice number, or the same customer and PO number.
- Required business values are present — For example, a PO number on every invoice from vendors who require one.
Run lookups right after the agent, and bring their results into the record with response mapping so the checks that follow can use them.
Send exceptions to error management
Put the checks in a preMap hook on the destination import. For each record, the hook either passes the record through or returns an error with a message that explains what to check. A record with an error stops at that step and appears on the step's Errors page; the other records on the page continue.
This hook assumes the agent's output was mapped to extracted and the purchase order lookup's result to purchaseOrder:
function preMap (options) {
return options.data.map((record) => {
const doc = record.extracted || {}
const approved = record.review && record.review.approved === true
const problems = []
if (doc.needs_review) problems.push(...(doc.review_reasons || ['The agent flagged this document']))
if (!record.purchaseOrder) problems.push(`No open purchase order found for PO number ${doc.po_number}`)
const lineTotal = (doc.line_items || []).reduce((sum, line) => sum + (line.amount || 0), 0)
if (typeof doc.subtotal === 'number' && Math.abs(lineTotal - doc.subtotal) > 0.01) {
problems.push(`Line items add up to ${lineTotal.toFixed(2)}, but the subtotal is ${doc.subtotal}`)
}
if (problems.length > 0 && !approved) {
return {
errors: [{
code: 'needs_review',
message: `Review this invoice: ${problems.join('; ')}. Correct the values in the retry data, or add "review": { "approved": true } to accept them as they are, and then retry.`,
source: 'document_review'
}]
}
}
return { data: record }
})
}
Tips for the hook:
- Write messages for the reviewer — Say what's wrong and exactly how to clear it. The message is what the reviewer reads first.
-
Honor an approval — The hook runs again on every retry. An override field, such as
review.approved, lets a reviewer accept a record that's correct as it is. - Return errors; don't throw — Throwing an exception fails every record on the page, not only the one with the problem.
You can ask Celigo Ora to write and test this hook from a description of your checks. See integrator.io extension frameworks for the preMap contract.
Review and approve exceptions
Reviewers work on the Errors page of the step where the record stopped:
- Open the flow, and select the error count on the destination step.
- Select an error, and read the message.
- In Retry data, correct the extracted values, or add the approval field the message names.
- Select Retry. The hook runs again with the corrected data. A record that passes continues to the destination.
To resolve a record without posting it — for example, a document that isn't an invoice — resolve the error instead of retrying it. The Errors page keeps a history of resolved errors. Monitor users need permission from an administrator to edit retry data. See Errors page – troubleshoot and retry open errors.
Set up error notifications for the integration, and use tags and assignments on the Errors page to route work to the right reviewer. See Configure error notification email for other users.
Protect personal data in documents
Invoices, onboarding forms, and claims often contain personal data. Add a guardrail after the agent to detect or mask personally identifiable information (PII) in the extracted data before it's written to another system. See Understand Celigo guardrails and Create a guardrail.
Start from a Marketplace template
The AI AP Invoice Ingestion Agent (Email/PDF to NetSuite Vendor Bill) and AI based Email Remittance for Cash Application Management templates implement this pattern end to end: records that pass every check post automatically, and everything else waits in error management with a message that names the override that clears it. See Intelligent document processing overview.
Related articles
- Intelligent document processing overview
- Extract data from documents
- Classify documents and route them by type
- Troubleshoot intelligent document processing
- Errors page – troubleshoot and retry open errors
- Resolve errors – automatically or manually
- Enhancing AI enablement with TRiSM: Trust, risk, and security in action