Accounts payable (AP) is a critical function in finance, often burdened by manual data entry, invoice matching, and compliance checks. With the rise of AI workflow automation, AP teams can dramatically reduce errors, accelerate processing, and improve compliance. In this hands-on tutorial, you’ll learn how to implement an AI-powered workflow automation for accounts payable—from invoice ingestion to approval routing—using modern open-source tools and cloud AI services.
For a broader context and strategic guidance, see our Ultimate Guide to AI Workflow Automation in Finance.
Prerequisites
- Python 3.10+ (tested with 3.11)
- PIP (Python package manager)
- Docker (for running supporting services, e.g., OCR, databases)
- Basic knowledge of REST APIs and JSON
- Cloud AI Service Account (e.g., Google Cloud Vision, Azure Form Recognizer, or AWS Textract)
- Sample invoices in
PDForimageformat - Text editor or IDE (e.g., VS Code)
- Optional: Familiarity with AI workflow automation platforms
Step 1: Set Up Your Project Environment
-
Create a new project folder:
mkdir ap-ai-automation && cd ap-ai-automation
-
Set up a virtual environment:
python3 -m venv venv source venv/bin/activate
-
Install required Python libraries:
pip install fastapi uvicorn pydantic requests python-dotenv pandas
fastapifor building the APIuvicornto run the serverrequestsfor calling AI servicespandasfor data manipulation
-
Set up a .env file for secrets:
touch .env
Add your API keys and endpoints (example for Google Cloud Vision):GCLOUD_VISION_API_KEY=your_google_cloud_vision_api_key
Screenshot description: Project folder structure with venv/, .env, and main.py visible in VS Code.
Step 2: Implement Invoice Ingestion and OCR
The first step in AP automation is extracting data from invoices. We'll use Google Cloud Vision API for OCR, but you can adapt to Azure or AWS. For a deeper dive into invoice automation, see this invoice matching tutorial.
-
Create an OCR utility in
ocr_utils.py:import requests import os def extract_text_from_image(image_path): api_key = os.getenv("GCLOUD_VISION_API_KEY") endpoint = f"https://vision.googleapis.com/v1/images:annotate?key={api_key}" with open(image_path, "rb") as img_file: img_base64 = img_file.read().encode("base64").decode() payload = { "requests": [{ "image": {"content": img_base64}, "features": [{"type": "TEXT_DETECTION"}] }] } response = requests.post(endpoint, json=payload) result = response.json() try: return result['responses'][0]['fullTextAnnotation']['text'] except (KeyError, IndexError): return ""- Replace with your cloud provider’s API if needed.
-
Test OCR locally:
python3 >>> from ocr_utils import extract_text_from_image >>> print(extract_text_from_image('sample_invoice.pdf'))Screenshot description: Terminal output showing extracted invoice text.
Step 3: Parse Invoice Data with AI
After extracting raw text, use an LLM (e.g., OpenAI GPT-4, Azure OpenAI) to parse structured fields: invoice number, date, amount, vendor, line items.
-
Install OpenAI SDK:
pip install openai
-
Add OpenAI key to
.env:OPENAI_API_KEY=your_openai_api_key -
Create
parse_invoice.py:import openai import os def extract_invoice_fields(invoice_text): openai.api_key = os.getenv("OPENAI_API_KEY") prompt = f""" Extract the following fields from this invoice text: - Invoice Number - Invoice Date - Vendor Name - Total Amount - Line Items (Description, Quantity, Unit Price, Line Total) Return as JSON. Invoice Text: {invoice_text} """ response = openai.ChatCompletion.create( model="gpt-4", messages=[{"role": "user", "content": prompt}] ) return response.choices[0].message.content -
Test the parser:
python3 >>> from ocr_utils import extract_text_from_image >>> from parse_invoice import extract_invoice_fields >>> text = extract_text_from_image('sample_invoice.pdf') >>> print(extract_invoice_fields(text))Screenshot description: JSON with parsed invoice fields in terminal.
Tip: For advanced prompt engineering, see how to use prompt chaining for multi-step workflows.
Step 4: Automate Approval Workflow with FastAPI
Now, let's build a simple API to handle invoice submission, parsing, and approval routing. We'll simulate basic business logic: if the amount < $5,000, auto-approve; else, flag for manual review.
-
Create
main.py:from fastapi import FastAPI, File, UploadFile from ocr_utils import extract_text_from_image from parse_invoice import extract_invoice_fields import json app = FastAPI() @app.post("/process-invoice/") async def process_invoice(file: UploadFile = File(...)): # Save uploaded file file_location = f"temp_{file.filename}" with open(file_location, "wb") as f: f.write(await file.read()) # OCR text = extract_text_from_image(file_location) # LLM Parsing fields_json = extract_invoice_fields(text) fields = json.loads(fields_json) # Approval logic amount = float(fields.get("Total Amount", 0)) status = "approved" if amount < 5000 else "pending_review" # Clean up os.remove(file_location) return {"fields": fields, "status": status} -
Run the API server:
uvicorn main:app --reload
-
Test with
curl:curl -X POST "http://127.0.0.1:8000/process-invoice/" \ -H "accept: application/json" \ -H "Content-Type: multipart/form-data" \ -F "file=@sample_invoice.pdf"Screenshot description: API response with extracted fields and approval status.
Step 5: Store Results in a Database
For production, persist results to a database. We'll use SQLite for simplicity, but you can upgrade to PostgreSQL or integrate with your ERP.
-
Install SQLAlchemy:
pip install sqlalchemy
-
Add
db.py:from sqlalchemy import create_engine, Column, Integer, String, Float, JSON from sqlalchemy.orm import declarative_base, sessionmaker engine = create_engine("sqlite:///ap_invoices.db") Base = declarative_base() Session = sessionmaker(bind=engine) class APInvoice(Base): __tablename__ = "ap_invoices" id = Column(Integer, primary_key=True) invoice_number = Column(String) vendor = Column(String) amount = Column(Float) status = Column(String) data = Column(JSON) Base.metadata.create_all(engine) -
Update
main.pyto save to DB:from db import Session, APInvoice session = Session() invoice = APInvoice( invoice_number=fields.get("Invoice Number"), vendor=fields.get("Vendor Name"), amount=amount, status=status, data=fields ) session.add(invoice) session.commit() session.close() -
Verify in SQLite:
sqlite3 ap_invoices.db sqlite> SELECT * FROM ap_invoices;
Screenshot description: Database table with invoice records and statuses.
Step 6: Add Email Notifications
-
Install email library:
pip install yagmail
-
Configure
.env:EMAIL_USER=your_email@gmail.com EMAIL_PASS=your_app_password -
Add email logic to
main.py:import yagmail import os def send_notification(recipient, subject, contents): yag = yagmail.SMTP(os.getenv("EMAIL_USER"), os.getenv("EMAIL_PASS")) yag.send(recipient, subject, contents) if status == "pending_review": send_notification( "ap_manager@company.com", "Invoice Requires Review", f"Invoice {fields.get('Invoice Number')} from {fields.get('Vendor Name')} requires manual review." ) -
Test notification flow:
curl ... # as above, with a high-value invoice
Screenshot description: Email inbox with "Invoice Requires Review" notification.
Step 7: Secure and Audit Your Workflow
Security and auditability are crucial in financial automation. For a real-world cautionary tale, see this analysis of AI workflow vulnerabilities.
- Use environment variables for all secrets.
-
Log all API requests and actions:
import logging logging.basicConfig(filename='ap_workflow.log', level=logging.INFO) logging.info(f"Processed invoice: {fields.get('Invoice Number')}, status: {status}") -
Restrict API access:
Addfrom fastapi.security import HTTPBasic, HTTPBasicCredentials from fastapi import Depends security = HTTPBasic() @app.post("/process-invoice/") async def process_invoice( file: UploadFile = File(...), credentials: HTTPBasicCredentials = Depends(security)): if credentials.username != "ap_user" or credentials.password != os.getenv("API_PASS"): raise HTTPException(status_code=401, detail="Unauthorized") # ...rest of logic...API_PASS=your_api_passwordto your.env. - Regularly review logs and database for anomalies.
Common Issues & Troubleshooting
- OCR returns empty text: Check image quality, file format, and API key validity. Try converting PDFs to images using
pdf2image. - LLM parsing errors: Adjust prompt, verify API key, and limit input size. For complex invoices, consider prompt chaining or few-shot examples.
- API server not starting: Ensure
uvicornis installed and you are running from the project root. Check for syntax errors. - Database not saving: Confirm SQLite file permissions and that
Base.metadata.create_all(engine)has run. - Email sending fails: Use an app password for Gmail, enable less secure apps, and check firewall rules.
- Security errors: Never hardcode secrets; always use
.envand environment variables.
Next Steps
You now have a working AI-powered workflow for accounts payable automation, including invoice ingestion, AI parsing, approval logic, notifications, and audit logging. To productionize:
- Integrate with your ERP or accounting software via REST APIs or RPA tools.
- Expand approval logic for multi-level routing or compliance checks.
- Scale with Docker Compose or Kubernetes for high-volume invoice processing.
- Explore feature-rich AI workflow platforms for advanced orchestration.
- Learn from AI-powered KYC workflow best practices to further reduce risk and manual effort.
As AI workflow automation continues to evolve, staying informed about new tools, security risks, and best practices is vital. For a comprehensive view of the landscape, see our Ultimate Guide to AI Workflow Automation in Finance.