Review pay changes before you approve your Gusto payroll
One screen compares this period's gross pay to last period, flags anyone moving more than 5 percent, and lets you approve and submit the run from there.
Build me a pre-payroll review desk my finance lead opens before every payroll run. It is a single interactive app over Gusto, Google Sheets, and Slack Bot. Nothing in it is ever calculated, submitted, logged, or posted unless a person clicks a button: no schedule, no auto-run on page load, no chaining one action into the next.
The main view is one table covering the current draft payroll. Use Gusto List Payrolls to find the open unprocessed payroll for the company's regular pay schedule, then Gusto Get Payroll to pull its full detail including per-employee compensations, hours, and totals. Use List Payrolls again to find the previous comparable pay period, meaning the most recent processed payroll on the same pay schedule with off-cycle runs excluded, and Get Payroll on that one too. Each row shows the employee name, this period's gross pay, that same person's gross pay from the prior period, the dollar change, and the percent change. Match employees between the two runs by employee UUID, never by name.
Any row moving more than the variance threshold in either direction gets an outlier flag and sorts to the top. The threshold is a stored app setting that defaults to 5 percent and is editable on a settings screen; do not hardcode 5 anywhere in handler logic. Add a companion setting for a minimum dollar change so tiny paychecks do not flood the list. Alongside the variance rows, render two distinct groups with their own headers and their own counts: new hires who appear in this payroll with no prior period at all, and anyone who dropped to zero hours or zero gross this period after being paid last period. Both groups always show regardless of the percent threshold, since a missing paycheck never produces a percentage worth sorting on.
Gusto returns money and hours as decimal strings such as '1234.56' and '8.0'. Do every comparison and every piece of arithmetic with exact decimal math on those strings rather than parsing to floats, and render values back as strings so nothing drifts by a cent. Percent change on a prior gross of zero is not a number, it is the new hire case, so route it to that group instead of dividing.
When a reviewer expands a row, fetch that employee's rate history on demand with Gusto Get Employee Jobs and Gusto List Job Compensations, and show job title, effective dates, rate, and payment unit so the reviewer can see whether a rate changed mid period. Only fetch this when the row is actually expanded, not for the whole table up front.
Every flagged row gets an Explain this swing button that kicks off a background agent embedded in the app. The agent receives that one employee plus both payrolls, inspects their jobs with Get Employee Jobs, their compensation history with List Job Compensations, and their recent payrolls with List Payrolls and Get Payroll, and writes a short plain English explanation back onto the row. The reviewer should read something like 'switched to a new hourly rate mid period, 18 hours at the old rate and 22 at the new one' or 'logged 12 fewer hours than last period' instead of just seeing a red number. Show the explanation state on the row (not started, running, done, failed), persist the explanation so it survives a refresh, and let the reviewer rerun it.
Each flagged row can be cleared or acknowledged by the reviewer with an optional note, and the app records who did it and when. Keep a live count of open flags at the top of the screen.
The Calculate Payroll button stays disabled until every flag is cleared or acknowledged. On click it calls Gusto Calculate Payroll, then polls Gusto Get Payroll and reads processing_request.status through calculating to calculate_success, plus the top level calculated_at field, rather than assuming the call succeeded. Show a calculating state while polling, surface processing_failed with Gusto's own error message, and refresh the on-screen totals and taxes when it lands. The reviewer then clicks Submit Payroll, which calls Gusto Submit Payroll and polls the same way through submitting to submit_success. Both buttons need an explicit click and a confirmation step, and calculate never chains into submit.
Once a run reaches submit_success, append exactly one signed off audit row per run to Google Sheets with Append Values: pay period start and end, payroll id, employee count, total gross, total employer taxes, total net, the variance threshold in effect, how many rows were flagged, how many were cleared versus acknowledged, the reviewer name, and the timestamp. Then post the final totals to the finance channel with Slack Bot Send a Message, including a short list of the flagged employees with their explanations. Write the audit row and the Slack post exactly once per submitted run and guard against duplicates if the reviewer reloads the page.
A settings screen holds the variance threshold percent, the minimum dollar change, the Google Sheets spreadsheet and tab for the audit log, and the Slack channel for the summary.
What does this prompt do?
- Loads your current draft payroll and lists every employee with this period's gross pay next to the same person's gross pay last period, plus the dollar and percent change
- Flags anyone whose pay moved more than your threshold, and gives new hires with no prior period and anyone who dropped to zero hours their own separate groups
- Puts an Explain this swing button on every flagged row, which sends an assistant to read that person's job and pay history and write a plain English reason back onto the row
- Once every flag is cleared or acknowledged, lets the reviewer calculate the run, check refreshed totals and taxes, and submit payroll without leaving the screen
- Logs one signed off row per run to a Google Sheets audit sheet and posts the final totals to your finance channel in Slack
What do I need to use this?
- A Gusto account with payroll admin access, including permission to run payroll
- At least one completed pay period in Gusto so there is a prior period to compare against
- A Google account and a spreadsheet to hold the sign off log
- A Slack workspace and a finance channel where the final totals should be posted
How can I customize it?
- Change the variance threshold from the default 5 percent, and set a minimum dollar change so small paychecks do not clutter the list
- Point the audit log at a different spreadsheet or tab, and send the summary to a different Slack channel
- Decide which groups a reviewer has to acknowledge before the approve button unlocks, and what the assistant should mention in its explanations
FAQs
Does this run payroll automatically?
Can I change the 5 percent threshold?
What happens with someone who just joined and has no prior pay period?
What does the Explain this swing button actually do?
Do I need to be a payroll admin in Gusto?
Where does the audit trail go?
Related templates
Stage a batch of filings overnight, then approve each completed form from a screenshot before anything is ever submitted.
Pick a client and a date range to see sent, replies, meetings booked and the real deal value your cold email produced, campaign by campaign.
Review every conversation Fin closed as resolved, judge which ones actually stuck, and see what the gap is worth against your bill.
Merge your IT, HR and Facilities queues into one list ranked by SLA time left, then reply, change status and escalate without ever opening Jira.
Work every return, damage and warranty claim in one queue, with the order, the delivery date and a policy-backed recommendation already on screen.
See every page's translation status at a glance, edit translations side by side with the English, and publish only what your team has actually approved.
Stop hunting for payroll surprises in a spreadsheet.
Open one review screen, clear every flag with a reason attached, and approve the run with a record of who signed off.