What if your business could turn every invoice and receipt into structured financial data without manually entering every detail?
Businesses process hundreds or thousands of invoices and receipts every month. Finance teams spend valuable time extracting vendor names, invoice numbers, dates, tax amounts, line items, and payment totals.
Manual processing is slow, repetitive, and vulnerable to human error. Duplicate invoices can be processed more than once, important fields can be missed, and outdated document versions can overwrite newer information.
In this article, we'll explore how to build a Smart Invoice & Receipt Scanner on AWS using Amazon S3, AWS Lambda, Amazon EventBridge, Amazon DynamoDB, AWS Step Functions, Amazon Textract, and Amazon Bedrock.
The goal is not simply to extract text from documents. It is to build a reliable financial document workflow that can detect duplicate events, handle out-of-order processing, validate extracted information, and route uncertain results to a human for review.
1. The Business Problem
Imagine a company receiving invoices and receipts through email, customer portals, mobile uploads, and shared folders.
A finance employee typically needs to:
- Open each invoice or receipt.
- Identify the vendor and invoice number.
- Extract invoice dates and due dates.
- Read line items and quantities.
- Identify subtotal, tax, and total amounts.
- Enter the information into an accounting system.
- Check whether the invoice has already been processed.
- Forward exceptions for approval.
This creates several challenges:
- Slow processing: Employees spend hours entering information manually.
- Human errors: Incorrect invoice numbers, dates, and totals can cause accounting problems.
- Duplicate processing: The same invoice may be uploaded more than once.
- Document updates: A corrected invoice may arrive after an earlier version has been processed.
- Limited visibility: Finance teams may not know whether a document is waiting, processing, rejected, or ready for approval.
A smart invoice scanner can automate much of this workflow.
2. Solution Architecture on AWS
The proposed solution uses an event-driven architecture to process documents as they arrive.
The workflow looks like this:
- A user uploads an invoice or receipt.
- Amazon S3 stores the original document.
- Amazon EventBridge receives the relevant S3 event.
- AWS Lambda validates the event and checks processing state.
- Amazon DynamoDB tracks event identity and document-processing status.
- AWS Step Functions coordinates the processing workflow.
- Amazon Textract extracts invoice and receipt information.
- Lambda functions validate and normalize the extracted data.
- Amazon Bedrock optionally provides AI-assisted classification and explanations.
- DynamoDB stores structured business records.
- Amazon S3 stores processed artifacts.
- Amazon SNS notifies the finance team when action is required.
Architecture overview
Finance User | v Web Application | v Amazon S3 Bucket (Original Files) | v Amazon EventBridge | v AWS Lambda Event Validation | v Amazon DynamoDB Event State / Idempotency | v AWS Step Functions | v Amazon Textract Invoice / Receipt OCR | v AWS Lambda Normalize and Validate Data | +--------+--------+ | | v v Amazon Bedrock Business Rules Optional AI and Validation | | +--------+--------+ | v Amazon DynamoDB Structured Records | +--------+--------+ | | v v Amazon S3 Amazon SNS Processed Files Notifications This is a reference architecture. Each service requires the appropriate event rules, IAM permissions, integrations, and application logic.
3. Upload Documents to Amazon S3
Amazon S3 provides durable object storage for original invoices and receipts.
A business can organize documents using separate prefixes:
invoice-scanner/ │ ├── incoming/ │ ├── invoices/ │ └── receipts/ │ ├── processing/ │ ├── processed/ │ ├── failed/ │ └── reports/ For example:
s3://invoice-scanner/incoming/invoices/invoice-1001.pdf Keeping original files separate from processed outputs makes the system easier to manage.
For production deployments, consider enabling:
- S3 Versioning to preserve document versions.
- Server-side encryption to protect stored documents.
- Bucket policies to restrict access.
- Lifecycle policies to manage document retention.
- Separate permissions for upload, processing, and review operations.
A useful design principle is to preserve the original document. Extracted data and generated reports should not replace the source file.
4. Handle S3 Events Reliably
This is one of the most important parts of the architecture.
Amazon S3 event notifications provide at-least-once delivery. Events may be delivered more than once and are not guaranteed to arrive in the order in which changes occurred.
This creates two problems:
Duplicate events: The same event may be delivered multiple times.
Out-of-order events: An older document event may be processed after a newer document event.
For a financial workflow, these issues matter. Processing the same event twice could create duplicate work, while processing an older version last could leave the system with outdated information.
AWS has published a pattern for managing event ordering and duplicate events using S3 event information, Lambda, EventBridge, and DynamoDB.
The key is to design the workflow so that receiving an event more than once does not cause the business operation to happen more than once.
5. Use S3 Sequencers and DynamoDB for Event Coordination
S3 event notifications can include a sequencer value for supported object events.
The sequencer helps determine the relative order of events for the same object key.
A higher hexadecimal sequencer represents a later event for that object key. However, sequencer values from different object keys cannot be compared to determine which event happened later.
When comparing sequencers, shorter values must be left-padded with zeros before lexicographical comparison.
For example:
Object key: incoming/invoices/invoice-1001.pdf Event A sequencer: 00A1 Event B sequencer: 00B5 Event B is later than Event A for this object key.
DynamoDB can maintain the latest accepted event state for each object.
A simplified record might look like:
{ "documentKey": "incoming/invoices/invoice-1001.pdf", "latestSequencer": "00B5", "status": "PROCESSING", "versionId": "example-version-id", "lastUpdated": "2026-10-21T10:30:00Z" } The application should use conditional writes or other atomic state transitions to prevent concurrent workers from incorrectly accepting stale events.
A simple read-then-write operation is not sufficient by itself. Two workers might read the same previous state and race to update it.
The comparison and update need to be protected by an appropriate atomic condition.
Why idempotency matters
An idempotent workflow can receive the same event multiple times without creating multiple business outcomes.
For example:
- The first event creates a processing record.
- A repeated event is recognized as already handled.
- The workflow avoids creating a second invoice record.
- A newer valid event can update the document's processing state.
- An older event cannot overwrite the newer accepted state.
This event-level protection is different from detecting two separate uploaded files that contain the same invoice.
6. Extract Invoice Data with Amazon Textract
Once the document event has been accepted, the workflow can use Amazon Textract to analyze the invoice or receipt.
Amazon Textract provides the AnalyzeExpense operation for extracting information from invoices and receipts.
It can identify summary fields such as:
- Vendor name.
- Invoice or receipt number.
- Invoice date.
- Due date, where available.
- Subtotal.
- Tax.
- Total.
- Payment-related information.
It can also return line-item information, including descriptions, quantities, prices, and other available fields.
Here's a simple Python example using Boto3:
import boto3 textract = boto3.client("textract") response = textract.analyze_expense( Document={ "S3Object": { "Bucket": "invoice-scanner", "Name": "incoming/invoices/invoice-1001.pdf" } } ) for expense_document in response.get("ExpenseDocuments", []): for field in expense_document.get("SummaryFields", []): field_type = field.get("Type", {}).get("Text") field_value = field.get("ValueDetection", {}).get("Text") print(field_type, field_value) This example illustrates the basic API call. A production implementation should handle permissions, document constraints, API errors, retries, and the full response structure.
For longer-running processing, Textract also provides asynchronous expense-analysis operations, including StartExpenseAnalysis and GetExpenseAnalysis.
The workflow can store the extracted response and pass it to the next processing stage.
Extraction is not validation
Textract extracts information from a document. It does not automatically establish that the invoice is legitimate, approved, or financially correct.
Consider this example:
Subtotal: $1,000 Tax: $100 Total: $1,250 A validation step should flag that the displayed total does not match the subtotal plus tax.
The application should also check whether required fields are missing, whether values have valid formats, and whether confidence levels are sufficient for automatic processing.
7. Add AI-Assisted Intelligence with Amazon Bedrock
Document extraction provides structured information. Amazon Bedrock can add an optional intelligence layer.
A Bedrock-powered component could help:
- Categorize expenses.
- Summarize invoice contents.
- Explain unusual charges.
- Suggest an expense category.
- Identify missing information.
- Generate natural-language summaries for finance staff.
- Prepare review notes when extracted information appears inconsistent.
Imagine an invoice containing several unfamiliar product descriptions.
An AI-generated summary might say:
This invoice appears to cover monthly IT infrastructure services. The document includes hosting, storage, and support charges. The total should be reviewed because the extracted tax amount does not reconcile with the displayed subtotal and total.
AI-generated explanations should be treated as assistance, not authoritative financial records.
Use deterministic application logic for arithmetic, currency normalization, tax calculations, required-field checks, and accounting rules.
For example:
def validate_invoice(subtotal, tax, total, tolerance=0.01): expected_total = subtotal + tax difference = abs(expected_total - total) return { "expected_total": expected_total, "difference": difference, "is_valid": difference <= tolerance } This example assumes that values have already been parsed into compatible numeric types and that no additional discounts, fees, or rounding rules apply.
Keep a human in the loop
An invoice scanner should not automatically approve or pay every invoice it reads.
A safer workflow is:
- High-confidence extraction and successful validation: mark the record as ready for review or downstream processing.
- Missing fields or low-confidence extraction: send the document for manual review.
- Financial inconsistencies: flag the record.
- Possible duplicate invoices: request verification.
- Payment approval: require the organization's authorized approval process.
AI should help people make decisions, not silently make high-impact financial decisions on their behalf.
8. Detect Business-Level Duplicate Invoices
There are two different types of duplication to consider.
Event duplication occurs when the same S3 event is delivered more than once. Sequencer tracking and idempotent processing help address this.
Business duplication occurs when the same invoice is uploaded as two separate objects, perhaps with different filenames or through different channels.
For example:
incoming/invoices/invoice-1001.pdf incoming/email/vendor-invoice-october.pdf Both documents might represent the same invoice.
To detect potential business duplicates, the application can compare extracted attributes such as:
- Vendor identifier or normalized vendor name.
- Invoice number.
- Invoice date.
- Currency.
- Total amount.
A possible duplicate key could be based on a normalized combination of vendor identity, invoice number, and currency.
However, duplicate detection should account for vendors that reuse invoice numbers, inconsistent formatting, credit notes, and corrected invoices.
A matching record should usually be flagged for review rather than automatically rejected.
Preventing duplicate event processing does not solve duplicate financial documents. These are separate problems and need separate checks.
9. Orchestrate the Workflow with AWS Step Functions
A document-processing system has multiple stages, and each stage can fail independently.
AWS Step Functions can coordinate these operations and make the workflow easier to observe.
A typical state machine could contain:
- Receive accepted document event.
- Retrieve the required S3 object version.
- Start Textract analysis.
- Wait for or retrieve the analysis result.
- Normalize extracted fields.
- Validate required fields and financial values.
- Check for potential business duplicates.
- Optionally request AI-assisted classification.
- Store the structured result.
- Route exceptions for human review.
- Notify the finance team.
A simplified workflow:
Document Event | v Validate Event | v Check Idempotency | v Start Document Analysis | v Retrieve Textract Results | v Normalize and Validate | v Duplicate Check | v AI-Assisted Classification | v Store Structured Record | v Review / Approval | v Notify Finance Team The workflow should define retry behavior, timeout handling, and failure paths.
For example, a temporary service error may be retried, while an invalid document or failed validation should be routed to an exception path.
Step Functions also provides execution history, which helps engineers investigate where a document failed.
10. Store Structured Records and Notify Users
After extraction and validation, the application can store structured records in DynamoDB.
A simplified record might look like:
{ "documentId": "INV-1001", "vendor": "Example Technologies", "invoiceNumber": "ET-2026-1001", "invoiceDate": "2026-10-20", "currency": "USD", "subtotal": 1000.00, "tax": 100.00, "total": 1100.00, "processingStatus": "READY_FOR_REVIEW", "duplicateStatus": "NOT_FLAGGED" } This is an illustrative application data model, not a fixed Textract response schema.
The application should preserve source-document references and relevant processing metadata so finance staff can trace extracted values back to the original document.
Amazon SNS can notify the relevant team when:
- A document has been processed.
- A document needs manual review.
- A possible duplicate has been detected.
- Processing has failed.
- An invoice is ready for an approval workflow.
A notification might say:
Invoice ET-2026-1001 has been processed. The extracted total is $1,100.00. The document is ready for finance review.
Notifications should avoid exposing unnecessary sensitive financial or personal information.
11. Security and Reliability Considerations
Invoices and receipts can contain confidential business information, customer details, addresses, and payment-related data.
Security must be part of the architecture from the beginning.
Protect documents
Use encryption at rest and in transit. Restrict access to source documents and processed artifacts through IAM policies and S3 bucket policies.
Apply least privilege
Each Lambda function and workflow component should receive only the permissions it needs.
For example, a document-processing function may need permission to read from a specific S3 prefix and write to a particular DynamoDB table. It should not automatically receive broad access to every bucket or table.
Avoid recursive event loops
If a Lambda function writes its output to the same bucket and prefix that triggers the function, it can create an unintended processing loop.
Use separate buckets or carefully configured event filters for incoming documents and generated outputs.
Handle document versions
When documents can be updated, enable S3 Versioning and preserve the relevant version information.
If the workflow needs to process the exact version that generated an event, use the version identifier from the event when retrieving the object.
This helps prevent a delayed event from causing the application to read a different version of the document.
Monitor failures
Use CloudWatch logs, metrics, and alarms to monitor:
- Failed document processing.
- Textract errors.
- Lambda failures.
- Step Functions execution failures.
- Unusually high processing volume.
- Documents waiting too long for review.
Protect sensitive data in AI workflows
Only send the information needed for the AI task. Apply appropriate access controls, data-retention policies, and model-service configuration for the organization's requirements.
Do not allow untrusted document text to issue instructions to an AI agent or bypass application authorization. Treat invoice contents as data to analyze, not as trusted instructions.
12. A Practical Implementation Roadmap
You do not need to build the entire platform in one step.
Phase 1: Document ingestion
Create an S3 bucket, configure upload access, and store incoming invoices and receipts.
Phase 2: Event processing
Configure S3 event delivery through EventBridge, create a Lambda event handler, and implement idempotency using DynamoDB.
Phase 3: Document extraction
Integrate Amazon Textract and store the extracted fields and source references.
Phase 4: Validation
Add deterministic checks for required fields, totals, currencies, and potential duplicates.
Phase 5: Workflow orchestration
Use Step Functions to manage processing, retries, exceptions, and review states.
Phase 6: AI assistance
Add Amazon Bedrock for optional categorization, summarization, and explanations.
Phase 7: Finance dashboard
Build a dashboard showing document status, extracted information, possible duplicates, and pending approvals.
Start with a small set of representative invoices and receipts. Test poor-quality scans, rotated pages, missing fields, multiple currencies, corrected invoices, and duplicate uploads before expanding the system.
13. What Business Value Can This Deliver?
A well-designed invoice scanner can help organizations:
- Reduce repetitive manual data entry.
- Improve visibility into document-processing status.
- Identify potential duplicate invoices earlier.
- Standardize extracted financial information.
- Route exceptions to the right people.
- Preserve document history and processing evidence.
- Scale document processing as business volume grows.
Actual time and cost savings depend on document quality, processing volume, integration complexity, AWS service usage, and the percentage of documents that still require manual review.
Measure results using real business metrics such as average processing time, extraction accuracy, exception rate, duplicate detection rate, and cost per processed document.
Conclusion: From Scanned Documents to Intelligent Financial Workflows
A smart invoice and receipt scanner is more than an OCR application.
It is an event-driven financial document workflow that combines reliable storage, event coordination, document extraction, deterministic validation, AI-assisted interpretation, and human approval.
Amazon S3 provides document storage. EventBridge and Lambda help process incoming events. DynamoDB supports idempotency and processing state. Step Functions coordinates the workflow. Amazon Textract extracts invoice information, while Amazon Bedrock can help interpret and summarize it.
The most important engineering lesson is that intelligence alone does not make a system reliable.
A production-ready solution must also handle duplicate events, out-of-order notifications, document versioning, failed processing, financial validation, security, and human approval.
The real opportunity is to turn unstructured financial documents into reliable, traceable, and actionable business data—using AWS services in a workflow designed for both intelligence and control.
Further Reading
- AWS Storage Blog: Manage Event Ordering and Duplicate Events with Amazon S3 Event Notifications
- Amazon S3 Event Notifications
- Amazon S3 Event Message Structure
- Amazon Textract Documentation
- Amazon Textract AnalyzeExpense API
- AWS Step Functions
- Amazon DynamoDB
- Amazon Bedrock
- Amazon EventBridge


