Build an AI-powered document verification pipeline that classifies uploaded documents, extracts structured data, and reconciles it against application data.
In this tutorial, you build a document processing pipeline that verifies customer onboarding documents against application data. The pipeline receives uploaded files (ID card, proof of address, salary slip), classifies each document, extracts structured data, compares it to what the applicant declared, and routes discrepancies to a human reviewer.What you will build:
A file upload UI that accepts multiple documents
A document classification workflow that identifies each document type using AI
A fan-out extraction pipeline that routes each type to a specialized extractor
An AI reconciliation step that compares extracted data against application data
Business rules that flag mismatches (name, address, income)
A human review task for documents with discrepancies
A summary generation step that produces a verification report
Define the following data model keys in your process. These keys hold the application data submitted by the customer and the results produced by the AI pipeline.
Step 1: Build the classification and extraction workflow
Create a workflow named classifyAndExtract. This workflow receives a single document file path, classifies the document type, and then routes to the appropriate extraction branch.This implements the fan-out extraction pattern.
Add a Document Understanding node as the first node after the Start node. This node accepts the document file directly and classifies it.
Use Document Understanding here, not Text Understanding — the text nodes accept text input only, while the document nodes work on the uploaded file itself.
Instructions:
You are a document classifier for a bank's customer onboarding process.Analyze the provided document and determine its type.Respond with exactly one of the following values:- ID_CARD- PROOF_OF_ADDRESS- SALARY_SLIP- UNKNOWNClassification rules:- ID_CARD: Government-issued identification documents (passport, national ID, driver's license). Contains photo, name, date of birth, document number.- PROOF_OF_ADDRESS: Utility bills, bank statements, or government letters showing a name and residential address. Must be dated within the last 3 months.- SALARY_SLIP: Employment payslips or salary certificates showing employer name, employee name, gross/net salary, and pay period.- UNKNOWN: Document does not match any of the above categories.Base your classification on the document layout, headers, field labels,and content structure. If uncertain, return UNKNOWN.
Response schema:
{ "type": "object", "properties": { "document_type": { "type": "string", "enum": ["ID_CARD", "PROOF_OF_ADDRESS", "SALARY_SLIP", "UNKNOWN"] }, "confidence": { "type": "number", "description": "Classification confidence between 0 and 1" }, "reasoning": { "type": "string", "description": "Brief explanation of why this type was chosen" } }, "required": ["document_type", "confidence"]}
The Else branch handles UNKNOWN documents. Use a Script node to return a structured error so the parent process can flag the document for manual classification.
Each branch contains a Document Extraction node with a prompt and schema tailored to that document type.
Use Document Extraction for this step, not Extract Data from File. The two nodes are not interchangeable:
Document Extraction takes Instructions and a Response schema, and returns structured fields. It has no extraction-method setting.
Extract Data from File takes an Extraction Method (Automatic, LLM Model, OCR Engine, Text Parsing) plus image and signature options, and returns text. It accepts no instructions or response schema.
A single node cannot combine a prompt, a response schema, and an extraction method.
ID card
Proof of address
Salary slip
Instructions:
Extract all personal identification fields from this ID document.The document may be a passport, national ID card, or driver's license.If a field is not present or not legible, return null for that field.
Extract the resident's name, full address, document date, and issuingorganization from this proof of address document. The document may be autility bill, bank statement, or government letter.If a field is not present, return null for that field.
Extract salary and employment details from this payslip document.Capture the employee name, employer, pay period, and all salarycomponents (gross, deductions, net).If a field is not present, return null for that field.
If you also need the raw text of a document, its embedded images, or signature detection, add a separate Extract Data from File node. Set its Extraction Method to Automatic for a mixed document set like this one, where the format varies per upload and you do not want to pick a strategy per file. See Extract Data from File for a comparison of the methods.
Both Document Extraction and Extract Data from File support the Personal Information Guard, which detects and replaces personal data before it reaches the model. Consider turning it on for this pipeline: ID documents, addresses, and payslips all carry personal data. See Personal Information Guard.
Create a workflow named reconcileData. This workflow compares the extracted document data against the applicant’s declared data.This implements the AI comparison and reconciliation pattern.
Add a Text Understanding node that receives both the extracted data and the application data.
The Instructions field is static — the node rejects ${...} references inside it. Pass dynamic values through the Context section instead; the node receives them alongside the instructions.
Instructions:
You are a document verification agent for a bank's customer onboardingprocess. Compare the AI-extracted document data (provided in the context)against the applicant's declared data (also in the context) and producea structured exception report.Rules:1. Compare each field individually. Use fuzzy matching for names (e.g., "John Smith" vs "JOHN SMITH" is a MATCH, "Jon Smith" vs "John Smith" is a WARNING).2. For addresses, compare at the component level (street, city, postal code). Minor formatting differences are acceptable.3. For dates, normalize to YYYY-MM-DD before comparing.4. For income, flag if the extracted net salary differs from the declared monthly income by more than 10%.5. Compute an overall match rate as a percentage (0-100).6. Assign a confidence score (0-100) reflecting how certain you are in the comparison results.7. Flag each exception with a severity: - CRITICAL: Identity mismatch (different person), expired document - WARNING: Minor name variation, address component mismatch, income difference 10-25% - INFO: Formatting differences, abbreviations
Context: reference the following process data so the node receives it at runtime:
${extraction.classifiedDocs} — the extracted document data
Create a workflow named generateSummary with a single Text Generation node.Instructions:
You are a compliance documentation assistant. Generate a documentverification summary report based on the applicant, extraction,reconciliation, and reviewer data provided in the context.Structure the report as follows:1. VERIFICATION OVERVIEW - Applicant name - Number of documents processed - Overall match rate - Verification status (Approved / Review Required / Rejected)2. DOCUMENT DETAILS For each document: - Document type and classification confidence - Fields extracted - Match/mismatch status per field3. EXCEPTIONS - List all exceptions with severity and description - Highlight any CRITICAL issues4. RECOMMENDATION - Clear recommendation based on the findings - Specific follow-up actions if neededUse professional, concise language. Format the report in Markdown.
Create a process named documentVerify that orchestrates the full pipeline using the workflows you built.
1
Add a User Task for file upload
Add a User Task node after the Start Event. This task presents the file upload UI to the user.Configure the task with:
Task name:Upload documents
Assignment: Assigned to the initiating user
The upload UI is designed directly on this node - you build it in Step 5. A User Task cannot attach a standalone UI Flow; its UI lives on the node.
2
Loop through uploaded documents
For each uploaded document, trigger the classifyAndExtract workflow. Add a Send Message Task node with a Start Integration Workflow action.Input mapping:
Replace [index] with a concrete extraction step for each file: array-indexed ${...} expressions do not resolve in data mappings. Extract the current file into a named object with a business rule or Script node (for example output.currentFile = input.documents.uploadedFiles[0];), then map ${currentFile.filePath} and ${currentFile.fileId}. See Referencing workflow data in node configurations.
Add a Receive Message Task node to capture the extraction output. In the node’s Data Stream, set the Key Name to extraction.classifiedDocs[index].
For multiple documents, repeat the Send/Receive pattern for each file, or use a loop structure with an exclusive gateway that iterates until all files are processed.
3
Trigger the reconciliation workflow
Add another Send Message Task with a Start Integration Workflow action pointing to the reconcileData workflow.Input mapping:
Add a Receive Message Task node. In the node’s Data Stream, set the Key Name to reconciliation.
4
Add a business rule for validation
Add a Service Task with a Business Rule action (JavaScript) to perform deterministic validation checks that supplement the AI reconciliation. Business rules read process data through input. and write results through output..
// Check if any CRITICAL exceptions existvar hasCritical = input.reconciliation.exceptions.some(function(e) { return e.severity === "CRITICAL";});// Check if ID document is expiredvar idDoc = input.extraction.classifiedDocs.find(function(d) { return d.documentType === "ID_CARD";});var isExpired = false;if (idDoc && idDoc.extractedData.expiry_date) { var expiryDate = new Date(idDoc.extractedData.expiry_date); isExpired = expiryDate < new Date();}// Check income discrepancyvar salaryDoc = input.extraction.classifiedDocs.find(function(d) { return d.documentType === "SALARY_SLIP";});var incomeDiscrepancy = false;if (salaryDoc && salaryDoc.extractedData.net_salary) { var declared = input.applicant.monthlyIncome; var extracted = salaryDoc.extractedData.net_salary; var diff = Math.abs(declared - extracted) / declared; incomeDiscrepancy = diff > 0.1; // More than 10% difference}// Check all required document types are presentvar docTypes = input.extraction.classifiedDocs.map(function(d) { return d.documentType;});var missingId = docTypes.indexOf("ID_CARD") === -1;var missingAddress = docTypes.indexOf("PROOF_OF_ADDRESS") === -1;var missingSalary = docTypes.indexOf("SALARY_SLIP") === -1;// Set validation resultoutput.validation = { hasCriticalExceptions: hasCritical, isIdExpired: isExpired, incomeDiscrepancy: incomeDiscrepancy, missingDocuments: { idCard: missingId, proofOfAddress: missingAddress, salarySlip: missingSalary }, requiresReview: hasCritical || isExpired || incomeDiscrepancy || missingId || missingAddress || missingSalary};
Business rules provide deterministic, auditable checks. Use them alongside AI reconciliation to catch issues the LLM might miss, such as expired documents or missing required document types.
5
Add the routing gateway
Add an Exclusive Gateway after the business rule. Configure two branches:
A gateway needs its evaluation rule defined in addition to the outgoing branches - without one, the process fails at runtime with “No rules found for gateway node”. Gateway conditions read process data with the input. prefix.
6
Add the human review task
Add a User Task node for manual review. The reviewer sees:
Uploaded documents (viewable in a File Preview component)
Extracted data side-by-side with declared data
The exception report from reconciliation
Validation flags from the business rule
The reviewer submits a decision:
Approve — continue to summary
Reject — end process with rejection status
Request re-upload — loop back to the upload step
Store the decision in review.reviewerDecision and any notes in review.reviewerNotes.
7
Route on the reviewer's decision
Add a second Exclusive Gateway after the review task - the three reviewer outcomes each need a branch:
Branch
Condition
Target
Approve
input.review.reviewerDecision == 'APPROVE'
Summary generation
Request re-upload
input.review.reviewerDecision == 'REUPLOAD'
Upload documents User Task
Reject
(default)
End Event
8
Trigger the summary generation workflow
After both the auto-approve and human-review-approve paths converge, add a Send Message Task to trigger the generateSummary workflow.Input mapping:
Design the upload page directly on the Upload documents User Task: select the node and open its UI Designer. A User Task’s UI lives on the node - a standalone UI Flow cannot be attached to a BPMN task.
1
Add an upload component
Add a File Upload component to the node’s UI and restrict the accepted file types to PDF, JPG, and PNG.
2
Add the Upload file action
On a User Task, the File Upload component does not come with an action - create an Upload file action on the node and link the component to it. The action posts the file to the Documents Plugin over Kafka; configure the Address (the document-persist topic) and the Document Type. For the full parameter list and the multi-file behavior, see the Upload file action guide.The AI document nodes read uploaded files with Document Source set to Document Plugin, which resolves paths produced by this upload.
3
Add applicant data display
Add form fields (read-only) that display the applicant’s declared data from applicant. This gives context to the person uploading documents.
4
Add a submit button
Add a Button component labeled Submit documents. Configure it to save the data and advance the User Task.
In a standalone UI Flow (for example, a chat-driven app that triggers workflows directly), the File Upload component behaves differently: it arrives with an Upload action already attached, and the upload result lands under that action’s Response Key - not under the component’s data key. With the default key of response, a successful upload produces:
Pass response.filePath to the workflow in that setup.
For the human review step, design a second page the same way - on the Human review User Task node - displaying the extracted data, reconciliation results, and exception report alongside the original documents. Use a side-by-side layout so the reviewer can compare easily.
Design the review page on the Human review User Task node, the same way you built the upload page in Step 5.The review page should include:
Section
Data source
Component
Applicant info
applicant
Read-only form fields
Uploaded documents
documents.uploadedFiles
File Preview
Extraction results
extraction.classifiedDocs
Data table
Reconciliation report
reconciliation.fieldResults
Data table with status badges
Exceptions
reconciliation.exceptions
List with severity highlighting
Validation flags
validation
Alert components for each flag
Decision
review.reviewerDecision
Radio buttons (Approve / Reject / Request re-upload)
Notes
review.reviewerNotes
Text area
Use conditional visibility to highlight rows with MISMATCH or CRITICAL status in the reconciliation table. This draws the reviewer’s attention to the issues that need their judgment.
Open the classifyAndExtract workflow and use Run Workflow with a test file. Upload sample documents one at a time and verify the classification output.
Test document
Expected type
Expected confidence
Scanned passport
ID_CARD
> 0.9
Electricity bill PDF
PROOF_OF_ADDRESS
> 0.9
Monthly payslip
SALARY_SLIP
> 0.9
Random brochure
UNKNOWN
< 0.5
2
Test extraction accuracy
For each document type, compare the extracted fields against the actual document content. Check that:
Names are captured correctly (including accented characters)
Dates are in the expected YYYY-MM-DD format
Numeric values (salary, postal code) are accurate
Null is returned for missing fields (not hallucinated values)
In this tutorial, you built a document processing pipeline that demonstrates several key patterns:
Fan-out extraction — classifying documents by type and routing each to a specialized extraction node with tailored prompts and schemas
AI reconciliation — comparing AI-extracted data against application data with structured exception reports
Hybrid AI + business rules — combining AI-driven comparison with deterministic validation (expired documents, missing types, income thresholds)
Human-in-the-loop — routing edge cases to a reviewer while auto-approving clean results
Workflow composition — building modular workflows for classification, reconciliation, and summary generation, then orchestrating them from a BPMN process