Review pay changes before you approve your Gusto payroll

By General Input

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.

Integrations

  • Gusto
  • Google Sheets
  • Slack Bot

Type

App

Categories

  • Finance
  • Operations

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.

Related prompts

Explore more prompts
Call overdue Xero customers with an AI collections agentLocal listing health board for every location you manageLet support send one-off Loops emails without an engineerA brand asset library your marketing team actually searchesTurn Mailjet email clicks into ranked HubSpot follow-upsClean out the Looker dashboards and Looks nobody opensStop cold emails to anyone with a live deal in PipedriveLiveKit live operations console for room moderationWake up dormant Keap leads with a researched reasoniMessage campaign console with pre-flight checks and delivery board