How to Flag Unapproved Deputy Timesheets in Slack
Build a Spojit workflow that scans Deputy timesheets on a schedule, keeps only the ones still waiting for approval, groups them by manager, and posts a per-manager reminder into Slack.
What This Integration Does
Unapproved timesheets are the quiet reason payroll runs late. Managers forget to sign off, the timesheets sit in Deputy, and nobody notices until the cutoff. This workflow closes that gap: every weekday morning it pulls the current Deputy timesheets, filters down to the entries that have not been approved yet, and nudges the responsible manager directly in Slack with the exact list of names and shifts that need their attention. Instead of one global "please approve your timesheets" blast, each manager gets only their own outstanding items, which makes the reminder easy to act on.
The workflow runs on a Schedule trigger, so there is no inbound event to wait for. On each run it reads timesheets from Deputy in Direct mode, reshapes the data with Transform and Condition nodes, loops over the affected managers, and sends a Slack message per manager. It writes nothing back to Deputy and approves nothing on its own, so it is safe to run repeatedly. Because it is purely a read-and-notify pattern, a re-run simply re-reports whatever is still unapproved at that moment: once a manager approves the timesheets in Deputy, the next run stops mentioning them.
Prerequisites
- A Deputy connection in Spojit with permission to read timesheets, employees, and locations. See Adding a New Connection if you have not connected Deputy yet.
- A Slack connection authorized to look up users and post messages (channel and direct-message scopes).
- A way to map each Deputy manager to a Slack destination. The cleanest route is a manager's work email (the same address in Deputy and Slack), which Slack can resolve with
lookup-user-by-email. Alternatively, keep a fixed channel per location. - Knowledge of which Deputy field marks a timesheet as approved in your account (commonly an approval timestamp or approver field), so the filter targets the right value.
Step 1: Add a Schedule trigger
Create a new workflow and set the Trigger type to Schedule. A Schedule trigger uses a 5-field Unix cron expression plus an IANA timezone. For a weekday 9am reminder in Sydney, use:
0 9 * * 1-5
Australia/Sydney
The trigger output is simply {{ scheduledAt }}, which you can include in messages as the "as of" time. A single trigger can hold more than one schedule, so add a second cron line (for example a late-afternoon pass) if managers need a second nudge before cutoff.
Step 2: Read timesheets from Deputy
Add a Connector node, pick the Deputy connector, and choose Direct mode with the list-timesheets tool. Direct mode is deterministic and spends no AI credits, which is what you want for a predictable bulk read. This returns the current set of Deputy timesheet records. Name the output something clear, such as timesheets, so later steps can reference it.
Add a second Connector node using Deputy list-employees in Direct mode, named employees. You will use this to translate the employee reference on each timesheet into a name and to find the right manager or work email for the notification.
Step 3: Filter to the unapproved timesheets and group by manager
Add a Transform node to do the data shaping in one place. From {{ timesheets }}, keep only the records that are still unapproved (for example, where the approval field is empty or false in your Deputy account), join each surviving record to its person using {{ employees }}, and group the results by the manager who owns the approval. Produce a list shaped like this so the loop has everything it needs:
{
"managers": [
{
"managerEmail": "alex@acme.com",
"managerName": "Alex Lee",
"items": [
{ "employee": "Sam Carter", "date": "2026-06-19", "hours": 7.5 },
{ "employee": "Jordan Diaz", "date": "2026-06-19", "hours": 8 }
]
}
]
}
If your approval logic is more nuanced (different rules per location, or a grace period), you can ask Miraxa, the intelligent layer across your automation, to draft the Transform for you with a prompt such as "From {{ timesheets }} keep entries where the approval field is empty, attach each person's name from {{ employees }}, and group them by manager email." Miraxa knows the workflow you are editing and can scaffold the node, which you then fine-tune in the properties panel.
Step 4: Stop early when there is nothing to send
Add a Condition node that checks whether there are any managers to notify, for example whether the length of {{ transform.managers }} is greater than 0. Wire the false branch to nothing (the run ends quietly), and the true branch onward to the loop. This keeps Slack quiet on days when every timesheet is already approved, which matters because a daily schedule will otherwise post an empty or noisy message.
Step 5: Loop over managers and resolve each Slack user
Add a Loop node in ForEach mode over {{ transform.managers }}. Inside the loop body, add a Connector node using the Slack connector in Direct mode with the lookup-user-by-email tool, passing {{ manager.managerEmail }}. This returns the Slack user for that manager so you can message them directly. If you would rather post to a shared channel per location instead of direct messages, skip the lookup and map a channel ID in the next step.
Step 6: Post the per-manager reminder to Slack
Still inside the loop, add a Connector node using the Slack connector in Direct mode with the send-message tool. Set the channel to the Slack user resolved in Step 5 (or your fixed channel), and build the text from the current manager's items. A template such as the one below produces a clean, scannable reminder:
Hi {{ manager.managerName }}, you have {{ manager.items.length }} timesheet(s)
still awaiting approval in Deputy as of {{ scheduledAt }}:
{{#each manager.items}}
- {{ this.employee }} - {{ this.date }} - {{ this.hours }}h
{{/each}}
Please review and approve them in Deputy before payroll close.
If you also want a single summary line for an HR oversight channel, add one more Slack send-message node after the loop that posts the total count across all managers, built from {{ transform.managers }}.
Tips
- Set the schedule timezone to the payroll team's region so "9am" and the
{{ scheduledAt }}stamp read correctly for everyone. The date connector'sformattool can renderscheduledAtinto a friendlier label inside the message. - Keep the heavy logic in one Transform node rather than spreading filters across several Condition nodes. It is easier to test and easier to ask Miraxa to revise later.
- If a manager's email does not resolve in Slack, fall back to a default HR channel rather than dropping the reminder, so nothing silently disappears.
- For a softer rollout, point the loop's Slack
send-messageat a private test channel first, confirm the formatting, then switch to real managers.
Common Pitfalls
- Approval field assumptions. Deputy accounts differ in how "approved" is represented. Inspect a real
list-timesheetsresult in the execution logs and confirm exactly which field flips before you trust the filter, or you may notify on already-approved entries. - Timezone drift. A Schedule trigger fires on the IANA timezone you set, not the viewer's local time. A cron of
0 9 * * 1-5with the wrong timezone can post in the middle of the night. - Duplicate daily nudges. The workflow re-reports anything still unapproved on every run. That is intended, but if you add a second schedule, make the message wording reflect that it is a reminder so managers are not confused by repeats.
- Large accounts.
list-timesheetsreturns the current set in one call; on very large accounts, do the grouping in Transform rather than many nested Loop passes to keep the run fast and within your timesheet window.
Testing
Before turning the schedule on, run the workflow with the Run button to execute it once on demand. Open the execution logs and check three things: the list-timesheets output shows the records you expect, the Transform output groups only genuinely unapproved entries under the right manager, and the Condition node takes the correct branch. Point the loop's Slack send-message at a test channel for the first few runs so you can confirm the formatting and the per-manager split without alerting real managers. Once the message reads well and the counts match a known unapproved timesheet, repoint Slack at the real users or channels and enable the Schedule trigger.