Most small teams handle expenses one of two ways. The first is a dedicated expense platform, often priced per seat per month, which is a reasonable deal if you've got dozens of people submitting dozens of expenses weekly and need corporate card feeds. For a five-person team where two people submit a coffee-run receipt and a conference ticket once a month, you're paying a recurring per-seat fee for software that mostly sits idle. The second default is worse: an email thread, a Slack DM to whoever's around, and a shared spreadsheet someone updates when they remember. Receipts get lost in inboxes, approvals happen verbally and get forgotten, and the inevitable question — "did this get approved?" — shows up in Slack every single month. Neither of these fits the actual shape of the problem, which is narrow: submit, approve, reimburse, done.
Strip away everything a general-purpose expense platform bundles in — mileage tracking, multi-currency conversion, card reconciliation — and what's left for a small team is genuinely simple: a form, a status, a routing rule, and a notification. That's it. A submission form needs five fields: amount, category, date, a short description, and a file upload for the receipt. No more. Each submission needs a status that moves through a defined path — submitted, approved, reimbursed, or submitted, rejected with a reason — so the state of any request is answered by looking at a record, not by asking a person. Approval needs to route by amount rather than dumping everything on one manager: something under $50 can auto-route to a team lead, anything over $200 needs a second approver, and everything in between follows whatever threshold makes sense for your team. And whoever cuts the reimbursement check needs one view: everything currently sitting in "approved" status, so they're not scrolling through old emails on the last day of the month trying to remember who's owed what.
The single-approver bottleneck is the most common failure mode in ad-hoc expense handling, and it's also the easiest thing to fix once you're building the workflow yourself instead of accepting whatever a template gives you. If every expense — a $12 parking receipt and a $450 client dinner — goes to the same person, that person either becomes a rubber stamp (defeating the point of approval) or a genuine bottleneck (delaying reimbursement for trivial amounts). Amount-based routing fixes both: small stuff clears fast through a team lead, larger stuff gets the scrutiny of a second approver. This is the kind of business logic that's trivial to describe and mildly annoying to configure in most off-the-shelf tools, but it's exactly the kind of conditional rule that's straightforward to set up when you're defining the workflow from scratch — see workflow automation for how that routing logic works in practice.
A status field is only useful if someone acts on it, and someone only acts on it if they know it changed. This is where the ad-hoc spreadsheet approach quietly fails even when someone is diligent about updating it: nobody's pinged when it's their turn to act, so requests sit for days until someone happens to check. The fix isn't complicated — a notification fires when a submission moves to "pending approval" (the approver gets pinged), and another fires when it moves to "approved" or "rejected" (the submitter gets pinged, with a reason attached if it's a rejection). That's two notification rules, not a messaging platform. It's enough to keep the workflow moving without anyone needing to remember to check a queue.
Run the numbers honestly. A per-seat expense tool charges for every person who might ever submit a request, whether they submit once a year or once a week — the billing model is built for high-volume teams, and it doesn't scale down gracefully. If you've only got five people filing occasional expenses, you're paying for capacity you're not using, every single month, indefinitely. Building the scope described above — one form, one status field, two threshold rules, two notification triggers — is realistic in a single afternoon precisely because the scope is this narrow. It's not a full accounting system. It's not handling multi-currency. It's not reconciling corporate card feeds. It's one table with a status column and some conditional routing, which is a fundamentally different (and much smaller) build than what dedicated expense software is solving for. If you want a sense of how that build-vs-buy tradeoff plays out more generally, the buy vs. build vs. ViibeStack comparison walks through where each option actually wins.
Be honest about the line here. If your team has actual corporate cards that need transaction-level feeds, if you're dealing with multiple currencies and exchange-rate handling, or if you're in a regulated industry that requires a formal audit trail with specific compliance controls, a dedicated expense platform earns its fee — that's genuinely hard to replicate well, and it's not what this workflow is for. This approach is for the much more common case: a small team that needs visibility into who's owed what and a reliable paper trail, without paying a recurring per-seat fee for a system that's mostly idle. If your internal process needs grow past this scope later — multiple departments, more complex approval chains, integration with payroll — you can extend the same app rather than starting over, which is a pattern worth comparing against how internal tools get built more broadly.
Realistically, this is a Tuesday-afternoon build with Thursday for testing and Friday for rollout. Day one: build the submission form with the five fields and the receipt upload, and set the status field with its four states. Day two: add the two routing rules based on amount and wire up the approver and submitter notifications. Day three: have two or three people on your team submit real expenses through it, fix whatever's awkward, and show the approved-items view to whoever handles reimbursement. By Friday, you've replaced the email thread and the spreadsheet with something nobody has to ask about in Slack — and you didn't pay a per-seat fee to get there.