Reviews · approval workflow

Sign-off on every high-value entry — without slowing your team down.

Reviews routes invoices, bills, payments, payroll, journals, and more through a multi-step approval chain you control. Smart mode catches only the entries that matter; strict mode catches everything. Reject an entry and the books auto-reverse — net-zero impact, full audit trail.

Three modes
Off · Smart · Strict
🔁
On reject
Auto-reverse — books stay balanced
🔔
Notifications
Bell + email + WhatsApp + mobile
📜
Audit trail
Companies Act 2013 compliant
The submit flow

What happens when staff creates an entry

Submitters do not change a single keystroke when Reviews is on. The routing decision is invisible to them — they fill the form, click Save, and Reviews decides what to do.

1

Staff creates the entry as usual

Sales invoice, purchase bill, payment, receipt, journal voucher, payroll run, credit note, debit note, stock adjustment, vendor advance — Reviews is wired into 12 entry surfaces.

Nothing about creating the entry changes for the submitter. They fill the form, click Save, and the entry posts as normal.

2

Reviews decides whether this needs a review

In "Off" mode: no routing — everything posts immediately. Existing behaviour, no change.

In "Smart" mode: an entry routes only if its amount crosses a configured threshold, OR AI detects an anomaly (3× the baseline for this vendor, duplicate likely, first transaction with a new party), OR a strict chain is configured for that trigger.

In "Strict" mode: every entry from non-owner staff routes — regardless of amount.

3

The entry is "held" while the review runs

The underlying journal entry stays in the books but is marked as "Awaiting review." List pages render a yellow pill so anyone looking at the invoice / bill / voucher knows it has not been blessed yet.

If the review is approved, the hold flag is cleared and the entry behaves like any other posted item. If rejected, a counter-JE is posted that nets the original to zero — your books stay balanced and both rows survive in the audit trail.

4

Approvers get notified, four ways

In-app bell — the OnGravy notification bell shows a high-priority entry with a tap-through to the audit detail.

Email — Resend-powered transactional email goes to every current-step approver (for amounts ≥ ₹50,000 by default, configurable).

WhatsApp — for businesses with Meta credentials configured, an interactive message with the link.

Mobile push — Expo app surfaces the entry in the Reviews queue with pull-to-refresh.

The reviewer flow

What approvers do — the three decisions

Every review can be approved, sent back for changes, or rejected outright. Each has a different downstream effect. Keyboard shortcuts (J/K to navigate, A to approve, R to request changes, X to reject) make a busy queue tractable.

A

Approve

One click (or one J/K/A keyboard tap from the queue). Approve advances the review to the next step in the chain. If there is no next step, the held flag is cleared and the entry posts to the GL.

For chains with `all_must_approve = true`, the review only advances when every required approver at the step has approved. Until then it stays at the current step.

B

Request changes

A reviewer who needs the submitter to fix something clicks "Request changes." A required comment field opens — explain what needs to change, then submit.

The submitter gets a high-priority notification with the comment and the entry sits in "Changes requested" status. They edit the underlying entry on the original form, then come back to /dashboard/reviews/mine and click "Resubmit" — which sends the review back to step 1 for a fresh look.

C

Reject

Terminal NO. Reviewer clicks Reject, fills in the required comment, and submits. The review is closed.

The system automatically posts a counter-JE that reverses the original — net effect on books is zero. The original JE stays in the audit trail with the rejection reason; the parent entity (invoice / bill / etc.) flips to status = cancelled.

The submitter gets a high-priority "rejected" notification with the reviewer's reason.

The submitter flow

What submitters can do while a review is in-flight

Submitters are not locked out while a review runs. They can chase up stuck items, withdraw before approval, or respond to a changes-requested decision.

i

See your in-flight submissions

/dashboard/reviews/mine lists every entry you have submitted in the last 90 days. Each row shows the trigger type, amount, current status pill, and (for in-flight items) which approver is holding it up.

On mobile, the same view is at the "My submissions" Home shortcut.

ii

Withdraw your own submission

Changed your mind before the reviewer got to it? Click "Withdraw." A confirm dialog asks for an optional reason; the review closes, the underlying entry is reversed, and your reviewers get a notification telling them the row is gone (so it does not just ghost-disappear from their queue).

Withdrawal works only while the review is still "Pending" or "Changes requested." Once a reviewer has decided, the audit log is final.

iii

Resubmit after changes requested

If a reviewer requested changes, edit the underlying entry (invoice / bill / voucher) on its original form. Then return to /dashboard/reviews/mine or the audit detail page and click "Resubmit."

You can attach a note explaining what you changed — it shows on the audit timeline so the reviewer sees your response. The review resets to step 1 and notifications re-fire to the original approvers.

Configuration

Owner / CA setup

Owners and admins configure modes, chains, and delegations per business. A CA firm running 30 clients can run different modes for different clients — no shared global config.

Configure the approval mode

/dashboard/settings/reviews — three cards for Off / Smart / Strict. Toggle is owner/admin only and applies per-business (so a CA firm can run different modes for different clients).

Define approval chains

/dashboard/settings/approval-chains — define one or more chains per trigger (invoice / bill / payment / journal / payroll) with a threshold amount and an ordered list of steps. Each step can target a specific user OR a role (e.g. "any user with accountant role"). Mark all_must_approve when you want every approver at the step to vote.

Chain edits never affect in-flight reviews. Each review snapshots the chain at the moment it was created, so a chain change today does not retroactively rewire reviews submitted yesterday.

Set up delegations for vacations

Same screen, "Delegations" tab. An approver going on leave can route their approvals to a colleague for a date window. The delegate sees the original's queue items + can act on them; both get the bell when something arrives. The audit trail records "acting for X" on every delegated decision.

Monitor with Insights

/dashboard/reviews/insights — overall approval rate, decision latency, oldest-pending age, and bucketed totals by business / submitter / trigger / status. Window picker (7 / 30 / 90 / 180 days).

For CA firms: the page calls out the highest-rejection-rate client when sample size ≥ 5, so you spot a bookkeeper-training problem before the next audit.

Export for audit

Insights → "↓ Export CSV" produces an RFC-4180 CSV with every decision in the selected window. One row per review, with the full actor::decision::comment trail in a single cell so the audit pack survives a CSV transport.

Indian Companies Act 2013 (post-2023 amendments) requires a tamper-evident audit trail of approvals. The CSV satisfies the "produce the trail on demand" obligation; the underlying append-only `approval_step_actions` table is what makes it tamper-evident.

When you hear from Reviews

Five notification events

Every state transition fires a notification to the right person. Both submitters and reviewers stay in the loop without anyone having to chase status manually.

Goes to Approver
New entry submitted
"<Submitter> submitted INV-2026-0042 (₹1.2L) for approval."
Goes to Submitter
Reviewer requested changes
"INV-2026-0042 — changes requested. <Reviewer>: 'Wrong GST rate on line 2.'"
Goes to Submitter
Reviewer approved (mid-chain)
"INV-2026-0042 approved at step 1 — awaiting next reviewer."
Goes to Submitter
Final approval (posted)
"INV-2026-0042 approved. Posted to books."
Goes to Submitter
Reviewer rejected
"INV-2026-0042 — rejected. Reason: 'Duplicate of INV-2026-0040.' Books have been reversed."
Goes to Approvers
Submitter withdrew
"<Submitter> withdrew INV-2026-0042 before approval — the entry has been reversed."
Correctness guarantees

What Reviews guarantees — and why it matters

No double-approvals on a race

Optimistic-lock token on every state transition. Two reviewers clicking Approve at the same instant — only one wins; the other sees "this review was updated by someone else, refresh."

No double-clicks recording two actions

Unique (instance, step, user) constraint on the audit log. A double-click is silently de-duplicated rather than producing two duplicate audit entries.

No in-flight rewiring

Each review snapshots its chain at submit time. A chain edit today never retroactively changes the reviewers for a review submitted yesterday.

No books drift on reject

Auto-reverse posts a counter-JE that nets the original to zero. Reports compute correctly with both rows present; the audit trail preserves the rejection reason.

No notification spam on terminal states

When a review is approved / rejected / withdrawn, every unread "needs your review" notification pointing at it is marked read. The bell stops flagging items you no longer need to look at.

No role-change surprises

canActOnInstance re-checks the user's role at decision time. If you were demoted between getting the bell and clicking Approve, the action is rejected — you cannot approve as a role you no longer hold.

Common questions

FAQ

Will turning on Reviews slow down my staff?
No. Submitters fill the same form they always have — Reviews is invisible at submit time. The only slow-down is at decision time, and only for the reviewer (which is the point). In Smart mode, most entries skip routing entirely because they're below threshold AND show no anomaly.
What happens to a pending entry if my reviewer is on vacation?
Set up a delegation (Settings → Approval chains → Delegations tab). For the date range you specify, every entry routed to that user also routes to their delegate. Both get the bell + email; either can approve. The audit trail records "acting for X" so it's clear who did what.
My reviewer rejected something three days after we already invoiced the customer. What happens to the books?
The system automatically posts a counter-JE the moment the rejection is recorded. Books net to zero. The original entry stays in the audit trail with the rejection reason — that's the Tally/Xero "post-and-reverse" pattern, and it's what Companies Act 2013 audit trail rules effectively require.
What if the original period is closed when a rejection comes in?
The counter-JE can't post (period is locked), so the system fires an urgent bell to every owner/admin pointing at the JE that needs manual reversal. You either reopen the period briefly or post the reversal in the current period with a narration linking back.
Can two reviewers approve at the same instant?
They can try — only one wins. We use an optimistic-lock token (lock_version) on every state transition; if you read the instance at v=5 and try to update while another reviewer's update bumped it to v=6, your update returns "this review was updated by someone else, refresh." No double-approvals, no race.
Can a step require two specific people to both sign off?
Yes. Mark the step "all_must_approve = true" in the chain editor. The review stays at that step until every required approver has clicked Approve. Until then, your action is recorded in the audit log but the chain doesn't advance.
Does Reviews work for retail POS / in-person sales?
No — POS bills are intentionally NOT routed. A customer at the counter can't wait for an approval roundtrip. POS posts directly. Reviews is for back-office entries (invoices, bills, payments, payroll, journals).
How are reviewers notified?
Four channels in parallel: the in-app notification bell, email (via Resend), WhatsApp (when the user's phone is on file and Meta credentials are configured), and the mobile Reviews screen. High-value events (≥ ₹50k) trigger out-of-app channels; smaller entries are bell-only to reduce noise.
Can I export the audit trail for my CA / external auditor?
Yes. /dashboard/reviews/insights → Export CSV produces an RFC-4180 file with every decision in a date range. Each row has the full actor::decision::comment trail in one cell, so the trail survives transport between systems.
Can I bulk-approve a backlog?
Yes. Tick the checkboxes on the reviewer queue (or J/K through them with Space to toggle) and the sticky action bar lets you approve, reject, or request changes on all selected at once. Max 50 per call. Each goes through the full decision pipeline (lock check, all-must-approve, auto-reverse, notifications).
What about AI — does Reviews use it?
On every routed-entry check we run three lightweight signals: amount ≥ 3× the 6-month baseline for that party + entry type, first-entry-from-this-party in 12 months, and duplicate-likely (same party + amount within 1% in the last 7 days). Any signal trips Smart mode even when the amount alone wouldn't. The reviewer sees the AI flag inline in the audit detail.
Is Reviews included in every plan?
Yes. No paywall. Off by default for new businesses; toggle to Smart or Strict whenever you're ready.

Ready to turn Reviews on?

New businesses default to "Off" — Reviews is opt-in. Once enabled, the first review fires the moment an entry crosses your threshold.

Start free — set up Reviews in 2 minutes →