Expense approver
A serverless system that takes each staff expense claim and its receipt, reads the receipt, checks the claim against your written expense policy, auto-clears the small in-policy ones for a manager’s one-tap confirm, and sends anything over a limit or out of policy to the right person with the reason. A human approves every payment — nothing is reimbursed automatically. Seven posts on the same system — one diagram at a time — with an engineering reference at the end.
-
01
An expense approver on AWS for a few dollars a month
The whole system on one page — a claim intake, a policy checker, and a routing piece, plus the one rule they all share: a human approves every payment.
-
02
How an expense claim gets submitted
Three ways a claim gets in — a short web form, a forwarded receipt email, and a chat upload — all landing as one claim record with the receipt read by Textract into amount, date, and vendor.
-
03
How an expense claim gets checked against policy
A checker reads the claim, sorts it into a category, compares the amount against the per-category limit in the policy doc, and picks one of four outcomes: clear, confirm, review, reject. No model on the limit check.
-
04
How an expense claim finds its approver
Approver resolution per claim, the reason line that travels with it, the one-tap confirm for in-policy claims, full review for the rest, and the four guardrails before any approval request lands.
-
05
How an expense claim gets paid
Three actions on the approval card: approve (write to the payable sheet), reject (with a reason back to the claimant), and ask (request a missing receipt or note). Every action is logged. The system never moves money itself.
-
06
What the expense approver costs
A couple of dollars a month at SMB volume. The policy check calls no model; Textract reads each receipt and a small Bedrock call sorts the category. Where the dollars go and how it scales.
-
07
Engineering reference: the expense approver architecture
Same system, drawn purely for engineers. Service names, resource identifiers, region, Bedrock model IDs, Lambda inventory, IAM scopes, the Textract flow, EventBridge config, and the DynamoDB schemas.
Frequently asked questions
- What is an expense approver?
- A small serverless system that takes each staff expense claim and its receipt, reads the receipt, checks the claim against your written expense policy (per-category limits, allowed categories, whether a receipt is required), auto-clears the small in-policy ones for a manager’s one-tap confirm, and sends anything over a limit or out of policy to the right approver with a plain-English reason. A human approves every payment; nothing is reimbursed automatically.
- How much does it cost to run?
- About $2.40/month at typical small-business volume (around 200 claims a month). The fixed cost is essentially zero. The variable cost is dominated by Textract reading each receipt and a small Bedrock call to sort the category; the policy check itself is plain Python and costs almost nothing. At 1,000 claims a month the bill lands around $11.
- Which AWS services does it use?
- Lambda (Python 3.14, arm64) with Function URLs for the submit form and the approve buttons, EventBridge for routing claim events, DynamoDB on-demand, S3 (with versioning) for receipts, SES outbound for emails, Secrets Manager, CloudWatch Logs (7-day retention), AWS Budgets, Textract for reading receipts, and Bedrock (Claude Haiku 4.5 via Global cross-Region inference) for category sorting and the monthly summary. No API Gateway, no NAT Gateway, no always-on compute.
- Where does the policy live?
- In a short Google Doc in a Drive folder. Plain prose: the per-category limits (meals $40/day, taxis $30/trip, software needs a manager’s sign-off), which categories are allowed, when a receipt is required, and who approves what. A small
drive-syncLambda mirrors the doc to S3 every 15 minutes; the checker reads from S3 so a policy edit needs no deploy. - Does it use AI?
- Sparingly. The policy check itself uses no AI — it’s plain Python comparing an amount against a limit and a category against an allow-list. Bedrock Haiku 4.5 fires only to sort a receipt into a category (is this “meals” or “client entertainment”?) and once a month for a board-summary narrative. Textract reads the receipt image. Every approval decision is made by a human, never the model.
- Does it ever pay anyone automatically?
- No. The system never moves money. It reads, checks, and routes; a person taps Approve before any claim is marked payable. Even an auto-cleared in-policy claim still needs the manager’s one-tap confirm. The system’s job is to make the approve-or-reject decision fast and well-grounded, not to remove the human from it.
- What happens after a claim is approved?
- The approved claim is written to a payable sheet in Drive that your bookkeeper or payroll run reads from — one row per claim with employee, amount, category, approver, and a link to the receipt. The system doesn’t push money; it hands a clean, approved, audit-trailed list to whoever runs the payment. Every action is recorded in the
ea-auditDynamoDB table with timestamp, claim, action, by-user, and a before-and-after snapshot.