Automating employee expense approvals with AI is rapidly becoming a standard for modern organizations looking to streamline operations, reduce manual errors, and maintain compliance. As we explored in The Ultimate Guide to Automating Approval Workflows with AI in 2026, expense management is a prime candidate for AI-driven automation. This deep-dive tutorial will walk you through designing, building, and deploying an automated expense approval workflow using AI, complete with hands-on code, configuration, and best practices.
Whether you're an IT leader, workflow automation specialist, or developer, this guide will help you implement a robust, auditable, and scalable solution. We'll focus on practical, testable steps using open-source tools and cloud AI services, and point to related topics such as Best Practices for Automating Employee Expense Management Workflows with AI and Security & Compliance Risks in Automated Approval Workflows: How to Mitigate in 2026.
Prerequisites
-
Technical Knowledge:
- Basic understanding of REST APIs and webhooks
- Python programming (intermediate level)
- Familiarity with workflow automation concepts
-
Tools & Versions:
- Python 3.10+
- FastAPI 0.95+ or Flask 2.2+
- Pydantic 1.10+
- PostgreSQL 14+ (or SQLite for demo/testing)
- OpenAI API (or Azure OpenAI, or HuggingFace Transformers)
- Ngrok (for local webhook testing)
- Slack or Microsoft Teams (for notifications)
- Optional: Docker 24+ for containerization
-
Accounts:
- OpenAI or HuggingFace account with API access
- Slack/Microsoft Teams workspace for notifications
1. Define Your Expense Approval Workflow
-
Map out your approval logic:
- What triggers an approval? (e.g., submission via app or email)
- What are the routing criteria? (e.g., amount, category, department)
- Who are the approvers? (e.g., manager, finance, AI-only for small amounts)
- What are the compliance and audit requirements?
Example: All expenses < $500 are auto-approved by AI; $500–$2000 require manager review; > $2000 require finance approval.
For more on mapping AI-driven workflows, see The Ultimate Guide to Automating AI-Driven Compliance Workflows in 2026.
2. Set Up Your Development Environment
-
Clone the Starter Repository and Install Dependencies:
git clone https://github.com/your-org/expense-approval-ai.git cd expense-approval-ai python3 -m venv venv source venv/bin/activate pip install -r requirements.txtrequirements.txt should include:
fastapi uvicorn pydantic sqlalchemy openai slack_sdk -
Configure Environment Variables:
- Create a
.envfile with your API keys and database URL:
OPENAI_API_KEY=sk-... DATABASE_URL=postgresql://user:password@localhost:5432/expenses SLACK_BOT_TOKEN=xoxb-... - Create a
3. Design the Expense Submission API
-
Create a FastAPI endpoint for expense submissions:
from fastapi import FastAPI, HTTPException from pydantic import BaseModel, Field from typing import Optional app = FastAPI() class ExpenseSubmission(BaseModel): employee_id: int amount: float = Field(gt=0) category: str description: Optional[str] receipt_url: Optional[str] @app.post("/expenses/submit") async def submit_expense(expense: ExpenseSubmission): # Save to database (pseudo-code) # db.save(expense.dict()) return {"status": "received", "expense": expense}Test your endpoint:
uvicorn main:app --reload curl -X POST http://127.0.0.1:8000/expenses/submit \ -H "Content-Type: application/json" \ -d '{"employee_id": 123, "amount": 450, "category": "Travel", "description": "Conference", "receipt_url": "http://imgur.com/receipt.jpg"}'Screenshot Description: API response in terminal showing
{"status": "received", ...}.
4. Integrate AI for Automated Decision-Making
-
Connect to the OpenAI API for expense evaluation:
import openai import os openai.api_key = os.getenv("OPENAI_API_KEY") def ai_expense_approval(expense): prompt = ( f"Review the following employee expense:\n" f"Amount: ${expense['amount']}\n" f"Category: {expense['category']}\n" f"Description: {expense['description']}\n" f"Should this be approved? Reply 'APPROVE' or 'REJECT' and provide a reason." ) response = openai.Completion.create( engine="text-davinci-003", prompt=prompt, max_tokens=64, temperature=0.1, stop=None, ) decision = response.choices[0].text.strip() return decisionIntegrate the AI call into your API endpoint:
@app.post("/expenses/submit") async def submit_expense(expense: ExpenseSubmission): # Save to database # db.save(expense.dict()) ai_decision = ai_expense_approval(expense.dict()) return {"status": "AI_decision", "decision": ai_decision}Screenshot Description: JSON response showing AI's decision:
{"status": "AI_decision", "decision": "APPROVE: Expense is within policy."} -
Set up routing logic:
- Auto-approve low-value expenses; escalate higher-value ones.
@app.post("/expenses/submit") async def submit_expense(expense: ExpenseSubmission): # Save to database # db.save(expense.dict()) if expense.amount <= 500: ai_decision = ai_expense_approval(expense.dict()) if "APPROVE" in ai_decision: status = "approved" else: status = "rejected" # Notify employee via Slack or email (see next section) elif expense.amount <= 2000: status = "pending_manager" # Notify manager for manual review else: status = "pending_finance" # Notify finance team return {"status": status}
5. Add Notifications and Approver Actions
-
Send notifications via Slack:
from slack_sdk import WebClient slack_token = os.getenv("SLACK_BOT_TOKEN") client = WebClient(token=slack_token) def notify_user(user_id, message): client.chat_postMessage(channel=user_id, text=message)Example: Notify a manager for approval:
def notify_manager(expense): manager_slack_id = "U123456" message = ( f"Expense approval needed:\n" f"Employee: {expense['employee_id']}\n" f"Amount: ${expense['amount']}\n" f"Category: {expense['category']}\n" f"Description: {expense['description']}\n" f"Approve or reject in the app." ) notify_user(manager_slack_id, message)Screenshot Description: Slack message in manager's workspace showing expense details and action prompt.
-
Enable Approvers to Act:
- Provide a link or button in the Slack message to approve/reject.
- Set up an endpoint to receive approver actions:
@app.post("/expenses/approve") async def approve_expense(expense_id: int, action: str): # Update database status # db.update(expense_id, status=action) return {"status": f"Expense {expense_id} {action}d"}
6. Store and Audit Expense Decisions
-
Use an auditable database schema:
CREATE TABLE expenses ( id SERIAL PRIMARY KEY, employee_id INT NOT NULL, amount NUMERIC(10,2) NOT NULL, category VARCHAR(50), description TEXT, receipt_url TEXT, status VARCHAR(20), ai_decision TEXT, approver_id INT, approved_at TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );Screenshot Description: Table view in database GUI showing expense records, statuses, and AI decisions.
-
Log all AI decisions and human overrides:
- Every decision (AI or human) should be recorded with a timestamp and reason.
def log_decision(expense_id, decision, actor, reason): # Insert into audit_log table (pseudo-code) # db.insert('audit_log', { # "expense_id": expense_id, # "decision": decision, # "actor": actor, # "reason": reason, # "timestamp": datetime.utcnow() # }) pass
7. Test Workflow End-to-End
-
Simulate an expense submission:
curl -X POST http://127.0.0.1:8000/expenses/submit \ -H "Content-Type: application/json" \ -d '{"employee_id": 234, "amount": 1200, "category": "Meals", "description": "Team offsite", "receipt_url": "http://imgur.com/receipt2.jpg"}'- Check that notifications are sent to the right approver.
- Approve or reject via the Slack link or API.
- Verify database and audit logs for correct status and traceability.
For a comparison of how leading AI approval bots handle these steps, see The Rise of Approval Bots: Comparing Top AI Tools for Streamlining Business Sign-Offs in 2026.
Common Issues & Troubleshooting
-
API Key Errors: Ensure your
OPENAI_API_KEYandSLACK_BOT_TOKENare set in your environment and not expired. - Webhooks Not Firing: If using ngrok, verify the public URL is correctly configured in Slack or Teams and that your FastAPI server is accessible.
-
AI Decision Quality: If the AI is making poor decisions, review your prompt and consider adding more context or rules. Experiment with
temperatureandmax_tokensin the OpenAI API call. -
Database Issues: Check your
DATABASE_URLand ensure the schema is migrated before running the app. - Notification Failures: Confirm the Slack user/channel IDs are correct and that your bot has permission to post.
- Audit Trail Gaps: Make sure all decision points (AI and human) are logged with timestamps and reasons.
- For compliance and security troubleshooting, refer to Security & Compliance Risks in Automated Approval Workflows: How to Mitigate in 2026.
Next Steps
- Expand AI Capabilities: Add document/receipt OCR validation, anomaly detection, or integrate with ERP systems.
- Scale Up: Containerize the app with Docker and deploy to your preferred cloud platform.
- Improve Accessibility: For guidance on inclusive workflow automation, see Designing AI Workflow Automation for Accessibility and Inclusion: Best Practices 2026.
- Explore Related Workflow Automations: Consider adapting this framework for HR onboarding (Automating HR Onboarding Approvals with AI: Blueprint and Best Practices for 2026) or procurement approvals (How LLMs Are Streamlining Procurement Approvals: Practical Use Cases for 2026).
- Dive Deeper: For a holistic view of AI-powered approval automation, revisit The Ultimate Guide to Automating Approval Workflows with AI in 2026.