Approvals
Tiered approval for large opportunities — what triggers it, who approves at each tier, and what happens on approve/reject.
Approvals
HotCRM ships with one built-in approval: the Opportunity Approval flow. It enforces a tiered "extra pairs of eyes" rule on large deals so no rep can commit a big-ticket opportunity without the right level of sign-off.
Since ObjectStack 7.4 this is modeled as a flow with
approvalnodes (ADR-0019), not a standalone approval-process object. The flow chains the approval steps, locks the record while a step is pending, and mirrors the live decision onto the opportunity'sapproval_statusfield. Auto-launch requires thetriggerscapability (see Administration › Automation).
What triggers an approval
The flow runs automatically when an opportunity is saved and its amount reaches a threshold — no manual "submit" step:
- Amount $100K or more → Sales Manager review.
- Amount > $500K → Sales Manager review and Sales Director sign-off.
Under $100K, no approval is needed — the rep can progress the deal directly. The manager line is inclusive: a deal at exactly $100,000 does route for approval. The entry guard (approval_status = not_required) means the flow's own status writes don't re-trigger it.
The tiered process
| Tier | Approver | Applies when | Why |
|---|---|---|---|
| 1. Sales Manager | The sales_manager role | Amount $100K or more | First line of defense — sanity-check the deal |
| 2. Sales Director | The sales_director role | Amount > $500K | Final sign-off — protect company margin on the largest deals |
A > $500K deal goes Manager → (decision gate) → Director. A $100K–$500K deal needs only the Manager. Rejection at either tier ends the run as rejected and notifies the owner.
What submitters see
When a rep saves an opportunity whose amount reaches the threshold, the flow submits it automatically:
- The opportunity is locked — the approval node holds the record until the step resolves.
approval_statusflips to pending (shown as In Approval).- The first approver gets an in-app notification and email.
There's no separate "Submit for Approval" click — reaching the amount threshold on save is the trigger.
What approvers see
Each approver receives:
- An email with the opportunity summary, amount, account, stage, and the submitter's comment.
- An in-app task in their Approval Inbox.
- A one-click Approve / Reject with a comment box.
Approvers can also delegate during PTO (configured in their profile).
First-response behavior
The process uses first-response behavior — the first approver to respond at each step (in case of delegates or multiple eligible approvers) decides the outcome. No "wait for all" voting.
What happens on each outcome
✅ Approved (all required tiers)
- The opportunity is unlocked.
approval_statusis stamped approved andapproved_dateis set to today.- The owner is notified ("Deal approved").
❌ Rejected (at any tier)
- The run ends immediately as rejected — a reject at the Manager tier never reaches the Director.
approval_statusis stamped rejected and the owner is notified to revise and resubmit.- The rejection is captured in the approval request's history.
Record locking
Each approval node sets lockRecord: true, so while a step is pending the opportunity is locked by the approval engine — edits are blocked until the step resolves. The lock is released automatically on the final approve/reject.
The approval audit trail
Every action is recorded on the approval request (sys_approval_request) created by the flow:
| Date | Tier | Actor | Action | Comment |
|---|---|---|---|---|
| 2024-03-12 09:14 | — | system | Submitted | Auto-submitted (amount $620K > $500K) |
| 2024-03-12 11:30 | Manager | Sam Lee | Approved | "OK given strategic logo" |
| 2024-03-12 14:02 | Director | Pat Wong | Approved | "Approved — book it" |
This history is permanent and surfaces in deal-review reports.
Where to find pending approvals
In the HotCRM app there is one approvals entry, and it sits under My Work — an approval waiting on you is your work, so it lives beside your tasks, deals and cases rather than in a group of its own. My Work is open when the app loads, so you do not have to click a group open to see it.
- Inbox — opens the platform's approval centre, the screen where the approvals waiting on you are actually approved or rejected. Inbox is the label on the sidebar item; Approval Requests is not a navigation entry anywhere in this app. The name is not invented — it is what the approvals plugin calls the object (Approval Request / Approval Requests) — but this page had it standing where a sidebar item should be.
That item pins no view of its own. It used to land on the sys_approval_request object's list, which is read-only — you could read a request there but not act on it — so it now opens the approval centre instead, the surface that carries the Approve / Reject buttons. The object name is still on the entry, as the guard that hides the whole item on an install without the approvals plugin, but it is no longer where the item lands.
The approval centre has three tabs of its own:
| Tab | What it shows |
|---|---|
| My Pending | Requests waiting on your decision, with a count badge |
| Submitted by me | Requests you raised, in any state |
| All | Every request you are allowed to see |
Inside whichever tab you are on, a separate Status filter narrows further: All statuses, Pending, Approved, Rejected, Recalled or Returned for revision.
The object's own list views are a different screen
The approvals plugin also ships four built-in list views on the sys_approval_request object. They are real and still shipped — they are simply not what clicking Inbox opens, and no sidebar item in this app opens them:
| Built-in view on the object | What it shows |
|---|---|
| My Pending | Requests still pending where you are one of the approvers |
| I Submitted | Everything you submitted, in any state |
| Completed | Requests that ended — approved, rejected or recalled |
| All | Every request, most recently updated first |
Read those as a second screen, not as the tabs above. Two names sit on both sides unchanged, and one pair differs by a single word:
| Built-in view on the object | Approval centre tab |
|---|---|
| My Pending | My Pending — same words, different screen |
| I Submitted | Submitted by me |
| Completed | no tab — use the Status filter instead |
| All | All — same words, different screen |
The three names this page used to list — Pending My Approval, Submitted by Me and Recently Approved — exist nowhere: neither src/ nor the installed approvals plugin carries any of them, under any spelling. My Pending, I Submitted and Completed are the views they were describing. One caveat arrived with the re-point: the approval centre's Submitted by me tab differs from the phantom Submitted by Me only in capitalisation. That tab is a real screen in the centre — it is not, and never was, a view of the object.
Action History is not in the group either, and no sidebar item anywhere in this app carries that name. The audit trail is real data — the approvals plugin stores every action as sys_approval_action, ships Recent / By Actor / All views for it, and each action points back at its request through a request_id lookup. What is missing is only the way in: no navigation entry in this app opens that object.
Tips for sales reps
- ✅ Mind the thresholds — an amount of $100K or more (and especially over $500K) will auto-launch approval the moment you save. A deal priced at exactly $100,000 is on the approval side of the line. Plan for the review window before promising a close date.
- ✅ Get the deal right before saving at or above the threshold — the record locks while a tier is pending; you can't tweak it mid-review.
- ✅ Watch for the rejection notification — a reject ends the run; revise and save again to re-submit.
Tips for managers
- ✅ Respond within 24 hours — sales velocity matters; a stuck approval kills deal momentum.
- ✅ Use the comment field even on approvals — "Approved; please attach signed NDA before booking".
- ✅ Reject with specifics — "Need exec sponsor letter from customer" is far more useful than "Not yet".
Tips for admins
- The thresholds ($100K / $500K), the tiers (manager → director), and
lockRecordare all defined in the Opportunity Approval flow — edit the approval nodes and the decision gate to change them. - Add more approvals by dropping
approvalnodes into any flow (contract approval, expense approval, etc.) — see Administration › Automation. - The flow lives alongside other automation in the codebase (
src/flows/opportunity-approval.flow.ts). - Delegated approvers are set in user profile preferences. See Administration › Profiles.