How to Sync Deputy Timesheets to a MongoDB HR Warehouse
Build a Spojit workflow that runs on a weekly schedule, pulls approved Deputy timesheets, normalizes each one into a clean document, writes them to a MongoDB collection, and posts a completion summary to Slack.
What This Integration Does
Workforce data in Deputy is shaped for shift management, not for analytics. This workflow gives your HR and finance teams a tidy, query-ready copy of every approved timesheet inside a MongoDB warehouse so they can run reports on hours, cost, and location without touching the live Deputy account. Each run gathers the latest approved timesheets, reshapes them into a consistent document layout, and appends them to your warehouse collection, then drops a short summary into a Slack channel so the team knows the sync ran and how many records landed.
The workflow is driven by a Schedule trigger, so nobody has to remember to run it. On the cadence you set (for example, every Monday morning), Spojit lists timesheets from the Deputy connector, loops over the approved ones, and inserts a normalized document per timesheet using the MongoDB connector. The warehouse collection grows over time as an append-only history. Because each document carries a stable timesheet identifier, you can switch the final write from a plain insert to an upsert later if you want re-runs to refresh existing records instead of adding duplicates. After the loop, a single Slack message reports the count and timestamp.
Prerequisites
- A Deputy connection in Connections, authorized against the Deputy account that holds your timesheets.
- A MongoDB connection pointed at your warehouse database, with write access to the target collection (for example,
hr_timesheets). - A Slack connection authorized for the workspace, and the channel ID (or name) where the summary should post.
- The Deputy timesheet fields you care about (such as hours worked, employee, date, and location) decided up front so your normalized document shape stays consistent across runs.
Step 1: Start with a Schedule trigger
Add a Trigger node and set its type to Schedule. A Schedule trigger uses a 5-field Unix cron expression plus an IANA timezone. For a weekly Monday 7am run in Sydney, use:
0 7 * * 1
Australia/Sydney
The trigger output is {{ scheduledAt }}, the timestamp the run was launched. You will reuse this later in the warehouse document and the Slack summary. A single trigger can hold more than one schedule if you later want, say, a Monday and a Thursday run.
Step 2: List approved timesheets from Deputy
Add a Connector node in Direct mode, choose the Deputy connector, and select the list-timesheets tool. Direct mode is the right choice here because you want a deterministic, no-AI-cost fetch of the same dataset every week. Map its output to a variable such as timesheets.
This returns the timesheet records from your Deputy account. In the next step you will filter the list down to approved entries before writing anything, so the warehouse only ever holds finalized hours.
Step 3: Keep only approved timesheets
Most weeks the list contains drafts and pending entries you do not want in the warehouse. Add a Connector node in Direct mode using the built-in array connector and the filter tool against {{ timesheets }}, keeping only records whose approval flag indicates the timesheet is approved. Save the filtered result to a variable such as approved.
If you prefer to express the filter as code, you can instead use the code connector with execute-javascript to return only approved rows. Either way, the goal is a clean array of approved timesheets that the loop in the next step can iterate.
Step 4: Loop over each approved timesheet
Add a Loop node set to ForEach and point it at {{ approved }}. The loop runs its body once per timesheet, exposing the current item (for example as {{ item }}). Everything in Steps 5 and 6 lives inside this loop body so each timesheet is normalized and written individually.
Keeping the normalize-and-write pair inside the loop also makes failures easy to reason about: if one record is malformed, you can see exactly which timesheet stopped the run in the execution history.
Step 5: Normalize the timesheet into a warehouse document
Inside the loop, add a Transform node to reshape the raw Deputy item into the flat, predictable document your warehouse expects. Pull only the fields you decided on in the prerequisites, and stamp each document with the run time so you can trace which sync produced it. A normalized document looks like:
{
"timesheetId": "{{ item.Id }}",
"employeeId": "{{ item.Employee }}",
"locationId": "{{ item.OperationalUnit }}",
"date": "{{ item.Date }}",
"totalHours": "{{ item.TotalTime }}",
"approved": true,
"syncedAt": "{{ scheduledAt }}"
}
Save the result to a variable such as doc. Confirm the exact Deputy field names against a sample run, since they drive every downstream value.
Step 6: Insert the document into MongoDB
Still inside the loop, add a Connector node in Direct mode, choose the MongoDB connector, and select the insert-documents tool. Set collection to your warehouse collection (for example hr_timesheets) and pass the normalized document in the documents array:
{
"collection": "hr_timesheets",
"documents": [ {{ doc }} ]
}
The tool returns insertedCount and the generated identifiers. If you later want re-runs to update existing records instead of appending, swap this step for the update-documents tool with a filter of { "timesheetId": "{{ item.Id }}" }, the same fields under $set, and upsert set to true.
Step 7: Post a completion summary to Slack
After the Loop node (not inside it), add a Connector node in Direct mode, choose the Slack connector, and select the send-message tool. Set the channel to your target channel and write a templated text summary:
{
"channel": "C0123456789",
"text": "Deputy timesheet sync complete. {{ approved.length }} approved timesheets written to the HR warehouse at {{ scheduledAt }}."
}
This single message confirms the run succeeded and reports the volume, so the team has a lightweight audit trail in Slack without opening Spojit.
Tips
- Use Direct mode for every connector step here. The dataset and tools are predictable, so you avoid AI credit costs and get repeatable runs.
- If you want a richer Slack summary (for example, total hours across all timesheets), add a Transform or a math connector step after the loop to compute the total before the
send-messagestep. - Ask Miraxa, the intelligent layer across your automation, to scaffold the skeleton for you ("Build a workflow on a weekly schedule that lists Deputy timesheets, loops over them to insert documents into MongoDB, and posts a Slack summary"), then fine-tune each node in the properties panel.
- Keep your normalized document shape stable across runs so MongoDB queries and reports stay simple. Add new fields rather than renaming existing ones.
Common Pitfalls
- Timezone drift. The cron expression runs in the IANA timezone you set on the trigger, not the viewer's local time. Confirm
Australia/Sydney(or your region) so a "Monday 7am" run actually fires Monday morning where your team works. - Writing unapproved hours. If you skip the filter in Step 3, drafts and pending entries land in the warehouse. Always reduce to approved timesheets before the insert.
- Duplicate records on re-run. A plain
insert-documentsappends every time, so a re-run will add the same week twice. Switch toupdate-documentswithupsertkeyed ontimesheetIdif you need idempotent re-runs. - Field name assumptions. Deputy field names differ from the friendly labels in its UI. Verify the actual keys from a sample
list-timesheetsoutput before wiring up your Transform node.
Testing
Before turning the schedule on, validate the path end to end on a tiny scope. Use the Run button to fire the workflow manually, or temporarily point the MongoDB step at a throwaway collection such as hr_timesheets_test. Slice the approved list down to one or two records (a Transform or the array connector slice tool works well) so the loop runs quickly, then confirm the document shape in MongoDB matches what your reports expect and that the Slack summary posts with the right count. Once a single document looks correct, remove the slice, restore the real collection, and let the Schedule trigger take over.