Custom Software With Configurable Approval Workflows: Feasibility, Cost, and the Parts Nobody Quotes
A focused approval workflow build inside an existing product runs $15,000 to $60,000 and 4 to 8 weeks. As part of a first release it is $50,000 to $130,000 over 10 to 16 weeks, and a full multi-tenant, tenant-configurable platform with versioning and a regulated audit trail is $150,000 to $350,000 over 6 to 12 months. Anyone quoting two weeks is quoting a boolean flag, not an approval system.
What configurable approval workflows actually are once real users touch them
An approval looks like a boolean. A record gets status = pending, someone with the right role flips it to approved, the record moves on. Two days of work. That version ships, and it holds until the first time somebody edits an approved record.
Here is the scene. A purchase request for $9,400 routes to a department head, because the VP tier starts at $10,000. She approves it Tuesday. Thursday, the requester opens the same record, adds two line items, and the total becomes $26,400. The approved flag is still sitting on the row. Nothing re-routes, because nothing in the code connects the approval to the thing that was approved. The invoice pays. Nine months later an auditor pulls a sample of forty purchase orders, finds this one, and it is no longer a bug conversation. It is a control gap in the spend approval process, which is a different meeting with different people.
The fix is not a bigger if statement. Approvals do not attach to a record, they attach to a specific version of a payload. A competent build hashes the material fields (amount, vendor, cost center, currency, line items) at the moment each decision is recorded, stores that hash with the decision, and invalidates downstream approvals when the hash changes. Then you have to decide, per field, what counts as material: a typo in the description should not restart a three step chain, a vendor swap absolutely should. That per-field decision is the actual work. Nobody quotes for it. Everything below is like that.
The workflow definition is not the workflow instance
"Configurable" means an admin can change the rules. The instant that is true you have a versioning problem, and it is the most common reason these builds go sideways in month three.
If your engine reads the current definition every time it evaluates a step, an admin dropping the threshold from $10,000 to $5,000 on a Tuesday afternoon retroactively changes what 300 in-flight requests are supposed to do. Some sit at a step that no longer exists. Some skip a step they already passed. Some silently gain an approver who was never notified.
The rule: definitions are immutable and versioned, instances pin to the version they started under. An admin edit publishes v7 and leaves v6 alive until its last instance drains. That means you keep every historic definition forever, your UI renders steps from a definition nobody can open in the editor anymore, and you need a migration path for the times business genuinely must move in-flight requests to new rules (a compliance change, usually). "Migrate in-flight instances from v6 to v7 with a preview of what changes" is a two week feature on its own, and most teams discover they need it after go-live.
This is also where you pick an engine. Hand-roll and you own timers, retries, replay and versioning yourself. Temporal gives you durable execution, signals and native workflow versioning, at the cost of your team learning determinism constraints (no wall-clock reads, no random UUIDs, no direct database calls inside workflow code). Camunda 8 gives you BPMN 2.0 as the definition format and DMN decision tables for thresholds, which matters because DMN lets non-engineers edit the routing matrix as a spreadsheet without a deploy. AWS Step Functions is cheap for state but the one year maximum execution and callback token model make long-lived human approvals awkward. For a first build inside an existing product, a hand-rolled machine over a versioned definition table is usually right. For parallel branches, quorum and sub-processes, buy the engine.
Routing is an org chart problem, and every org chart is broken
The spec you get says "route to the requester's manager, then their manager if the amount exceeds the threshold." Every clause is a landmine.
Manager chains have gaps and cycles. The CEO has no manager. Contractors often have no manager record at all. Matrix orgs have dotted-line reporting that HR (Human Resources) never exports. Your resolver needs defined behavior for chain termination, cycles and missing managers, and throwing an exception is not it, because the request then vanishes into a queue nobody watches.
Approvers leave, which is where SCIM matters. If you provision from Okta or Entra ID over SCIM 2.0, a deprovision arrives as a PATCH setting active: false. Most builds handle that by disabling login, so the person's twelve pending tasks now belong to a user who cannot sign in. You need a reassignment policy that fires on deprovision (to the manager, a role queue, or a named backup) decided per workflow. Test it by actually deactivating a user in your IdP sandbox. Most teams never have.
Delegation is not reassignment. Out-of-office delegation must record "approved by B on behalf of A" as two identities in the log, because an auditor will ask whether A's authority was validly exercised, and "B approved it" is the wrong answer. Delegation needs a date range, a scope (all workflows or just expense), and a rule on sub-delegation. Say no to sub-delegation unless someone insists in writing.
Segregation of duties is a hard constraint. A requester cannot approve their own request, including through a delegate, including when they are the manager of the person who submitted on their behalf. That last case is the one that gets missed and the one SOX testers look for.
Currency thresholds surprise everyone. Your delegation-of-authority matrix says $10,000. The request is 9,600 EUR. Which rate, from which source, on which date? Submission date and approval date give different answers, and the difference decides whether the VP is even in the chain. Pick a rule (we default to the rate at submission, pinned onto the instance), write it down, and show it in the UI, so that when Finance disagrees you are having a policy discussion instead of a bug discussion.
Concurrency, idempotency, and the approve-by-email trap
Two approvers in an "any two of five" quorum click within the same 200ms. Without a lock both transactions read a count of 1, both write 2, and the step either completes on one recorded approval or fires its side effects twice. Fix it with SELECT ... FOR UPDATE on the instance row, or optimistic concurrency with a version column and a retry loop on Postgres serialization failures (SQLSTATE 40001). Basic, and still missing from most builds we inherit.
Idempotency is separate. A mobile client retries on a flaky network, a user double-clicks, a webhook redelivers. Every decision write needs an idempotency key and a unique constraint on (instance_id, step_id, actor_id), so the second write returns the first result instead of causing a second transition.
Now the trap that costs real money. The obvious design is an Approve button in the notification email pointing at a signed GET URL. Microsoft Defender for Office 365 Safe Links and comparable mail security products prefetch inbound links to scan them. Your approval fires before the human has opened the message. We have watched an entire batch auto-clear this way at a client who could not work out why every request was approved within seconds of being sent. The correct pattern: the email link is a GET to a confirmation page carrying a single-use signed token with a short expiry and a jti you burn on use, and the decision itself is a POST from that page. If you truly need reply-to-approve for field staff, parse inbound mail through a provider that surfaces DKIM and SPF results, and treat the message as an assertion of identity, not proof of it.
Timers, escalation, and the business calendar nobody scoped
"Escalate after two business days" is four systems. Business days in whose country. Which holiday calendar, updated by whom, across how many customer regions. The approver's IANA timezone or the requester's. And what escalate means: notify the next level, reassign to them, or auto-approve. Auto-approve on timeout is what business asks for and what auditors hate, so if you build it, log it as a distinct decision type that reports separately, never as a human approval.
Delivery matters too. A cron that scans for due timers every minute is fine into the low hundreds of thousands of rows, but only if it takes a lease on each row. Without one, a deploy that restarts workers mid-scan gives you two processes escalating the same batch. That is the 3am page: 900 duplicate escalations to every VP in the company, and the postmortem is one missing FOR UPDATE SKIP LOCKED.
The audit trail an auditor will actually accept
An updated_by column is not an audit trail. What holds up is an append-only event log, never updated, never deleted, one row per decision, recording actor, on-behalf-of actor, step id, definition version, payload hash, decision, comment, timestamp with timezone, source (web, email, API), and the resolved reason this actor was in the chain at all ("manager of requester per org snapshot 2026-03-04"). That last field is the one that saves you, because org charts change and in two years nobody can reconstruct why Priya was an approver.
In regulated territory the bar moves. Under 21 CFR Part 11 an electronic signature needs the printed name of the signer, the date and time, and the meaning of the signature (reviewed, approved) shown as part of the record, plus re-authentication at signing. That is a UX change and a compliance review cycle, not a schema change, and it typically adds three to five weeks. SOC 2 and ISO 27001 do not prescribe a format, but your assessor will ask for evidence the log cannot be edited by an application admin, which means no UPDATE or DELETE grant to the app role, or an append-only store with hash chaining.
What this costs and how long it takes
These are Digital Heroes delivery bands, not market averages.
Inside an existing product, where identity, org data and notifications already work: $15,000 to $60,000, typically 4 to 8 weeks. The low end is a linear chain, fixed steps, one threshold, admin edits via config. The high end is parallel branches, quorum, delegation and an audit export.
As part of a first release, where you are also building the records being approved: $50,000 to $130,000 over 10 to 16 weeks.
A full platform (multi-tenant, tenant-configurable definitions, versioning with in-flight migration, SCIM lifecycle, regulated audit trail): $150,000 to $350,000 over 6 to 12 months.
What pushes this specific capability's number up, in the order we see it:
- Parallel and conditional branching. A linear chain is a list. Branching plus join semantics plus quorum is a real state machine and roughly doubles the engine work.
- A visual builder for admins. Drag-and-drop editing with validation (no unreachable steps, no cycles, every branch joins) often costs more than the engine underneath. Budget $25,000 to $50,000 for it alone, and ask hard whether a decision table beats a canvas.
- Tenant-configurable rules in a multi-tenant product. Definitions, versions and migrations all become per-tenant, and support needs a way to debug tenant 412's stuck instance without shell access.
- Regulated e-signature. Weeks, not days.
- Org data quality. If manager relationships live in a spreadsheet instead of an IdP, the first six weeks are data cleanup wearing an engineering costume.
When you should NOT build this
If the approvals are internal operations (expenses, purchase requests, time off, access requests), the approvers are your own staff, and the headcount is under roughly 150, do not build. Take Power Automate approvals with Dataverse if you are already on Microsoft 365, or ServiceNow or Jira Service Management if you already pay for either. You get delegation, escalation, mobile approvals and an audit trail on day one, and three years of licensing costs less than the build's first quarter. If the approvals are spend-specific, Ramp, Coupa and Airbase have already solved thresholds, receipts and card controls better than a bespoke build will in year one. Take the tool and spend the money on something your competitors do not have.
Build when the approval workflow is a feature your customers configure inside your product. That is where off-the-shelf dies: you cannot expose Power Automate's designer to your tenants, per-user licensing on your customers' users destroys your margin, and the approval state has to be transactional with your own data rather than living in another vendor's cloud behind a webhook. Also build when routing depends on domain data the generic tools cannot see (loan grade, clinical acuity, load tender margin), because once routing needs a computation from inside your system, integration cost exceeds build cost.
How to brief and vet a developer for this
Brief with artifacts, not adjectives. Bring the delegation-of-authority matrix as it exists today (usually a spreadsheet), five real historical requests including one that went wrong, your org data source and whether it is authoritative, and a written answer to: what happens when an approved request is edited.
Then ask these. They separate people who have shipped it from people who have read about it.
- "An admin changes a threshold while 300 requests are in flight. What happens to them?" If they do not immediately say definitions are versioned and instances pin to a version, they have not shipped this.
- "Show me where the approval attaches to the payload, not the record." You want a hash or a snapshot. If the answer is "we store approver_id on the request," you have found the $9,400 bug in the interview.
- "Two approvers in a two-of-five quorum click at the same instant. Walk me through the transaction." You want row locks or a version column with a 40001 retry, not "the database handles it."
- "How do you stop mail security link scanners from approving requests?" A shipper answers this in one second.
- "A user is deprovisioned in Okta with eight pending tasks. What happens?" No answer means add four weeks.
- "How does the log distinguish an approval by a delegate from one by the principal?"
- "How do you test escalation timers?" The good answer is an injectable clock and time-travel tests, not "we waited two days on staging."
- "Where does the business calendar come from and who maintains it?"
- "Tell me about the worst thing you shipped in this area and how it got caught." Anyone with production time has a duplicate-notification story or an approval that routed to someone who had left. No story means no production time.
If a vendor quotes this at two weeks and a flat fee without asking about your org chart or what happens to edited records, they are quoting the boolean. You pay for the rest later, at a worse rate, under audit pressure.
The evidence behind this guide
Independent findings on why this investment pays off. Every link goes to the primary source.
- Almost half of all the activities people are paid almost $16 trillion in wages to do in the global economy have the potential to be automated by adapting currently demonstrated technologies. Source: McKinsey Global Institute (2017) →
- Median SaaS spend reached $9,455 per employee, and organizations leave an average of 36% of their SaaS licenses unused. Source: Zylo (2026) →
- A later Nucleus Research review of analytics software ROI case studies found customers received $9.01 in benefits for every dollar spent on analytics technology, showing returns vary with deployment factors but remain strongly positive. Source: Nucleus Research (2019) →
- The 2015 CHAOS data (based on the modern definition of success) reports that only about 29% of software projects succeed, 52% are challenged, and 19% fail, with the three most important success skills being executive sponsorship, emotional maturity, and user involvement. Source: The Standish Group (reported via InfoQ Q&A with Jennifer Lynch) (2015) →
Rohan advises mid-market and enterprise teams on ERP, CRM and custom software, and has led delivery on dozens of business-software builds.
Writes for Digital Heroes, shipping business software for 2,000+ brands across 55+ countries since 2017.