Working with Timesheets

Overview

The Timesheet API provides a set of endpoints that allow you to manage and track employee work hours, including detailed time entries and their statuses. Through this API, you can retrieve, create, update, and manage timesheets submitted by your employees.

Key features include:

  • Listing Timesheets: Retrieve all timesheets associated with your company.
  • Show Timesheet: Access detailed information about a specific timesheet by its ID.
  • Time Tracking: Breakdown shifts into various categories (e.g., regular hours, overtime, weekend, night hours).
  • Special Time Types: Automatically handle time-off and public holiday tracking.
  • Approve or Decline Timesheet: Manage timesheets by approving or sending them back for revisions.

Prerequisites

Before you get started, ensure that you have an active employment in your company with timesheets already created.

Timesheet.submitted webhook

Every time an employee submits a timesheet for review, the timesheet.submitted webhook is triggered notifying the company owners and admins that there are pending timesheets.

ℹ️ This webhook is not triggered in case a timesheet is automatically approved. See the section at the bottom to learn about automatically approved timesheets.

List timesheets

The API provides an endpoint to retrieve a list of all timesheets associated with your company. You can filter the results by their status:open, submitted, in_calibration, and processed, or sort the list in a specific order.

This allows you to view all relevant timesheets linked to your organization. Detailed descriptions of the fields returned by this endpoint are provided in the next section.

Show timesheet

The API provides an endpoint to retrieve a specific timesheet by its ID. Below is an example of the response:

{
   "data":{
      "timesheet":{
         "approval_required":true,
         "break_hours":{
            "hours":35,
            "minutes":13
         },
         "country_code":"PRT",
         "employment_id":"663e0b79-c893-45ff-a1b2-f6dcabc098b5",
         "end_date":"2021-07-01",
         "holiday_hours":{
            "hours":35,
            "minutes":13
         },
         "id":"663e0b79-c893-45ff-a1b2-f6dcabc098b5",
         "night_hours":{
            "hours":35,
            "minutes":13
         },
         "notes":"Some notes",
         "on_call_hours":{
            "hours":35,
            "minutes":13
         },
         "overtime_hours":{
            "hours":35,
            "minutes":13
         },
         "regular_hours":{
            "hours":35,
            "minutes":13
         },
         "start_date":"2021-07-01",
         "status":"submitted",
         "submitted_at":"2021-07-15T18:18:17Z",
         "time_tracking":[
            ...
         ],
         "total_hours":{
            "hours":35,
            "minutes":13
         },
         "weekend_hours":{
            "hours":35,
            "minutes":13
         }
      }
   }
}
  • approval_required: A boolean indicating whether employer approval is required for this timesheet.
  • break_hours: An object containing hours and minutes, representing the total break hours in the timesheet.
  • holiday_hours: An object containing hours and minutes, representing the total holiday hours in the timesheet.
  • night_hours: An object containing hours and minutes, representing the total night hours in the timesheet.
  • on_call_hours: An object containing hours and minutes, representing the total on-call hours in the timesheet.
  • overtime_hours: An object containing hours and minutes, representing the total overtime hours in the timesheet.
  • regular_hours: An object containing hours and minutes, representing the total regular hours in the timesheet.
  • weekend_hours: An object containing hours and minutes, representing the total weekend hours in the timesheet.
  • total_hours: An object containing hours and minutes, representing the total number of hours recorded in the timesheet.
  • country_code: The country code associated with the timesheet.
  • employment_id: The employment ID associated with the timesheet.
  • start_date: The start date of the timesheet period.
  • end_date: The end date of the timesheet period.
  • id: The unique identifier for the timesheet.
  • notes: Additional notes attached to the timesheet.
  • status: The current status of the timesheet. Possible values are: open, submitted, approved, in_calibration, or processed.
    • open: The initial status when employees can edit time tracking and all *_hours fields associated with the timesheet. If a timesheet is never submitted for review, it will remain in the open state.
    • submitted: Indicates that the employee has submitted the timesheet for review and the approval_required flag is set to true.
    • approved: Indicates that the timesheet has been approved.
    • in_calibration: This status means employees can edit time tracking but only if the timesheet was previously submitted and sent back for amendments. When the status changes to in_calibration, all automatic fields (submitted_at, submitted_by, approved_at, approved_by) are cleared and a new boolean flag calibrated is added which is set to true.
    • processed: Indicates that the timesheet has been included in the payroll run and is considered paid. At this point, the timesheet will be locked and can no longer be edited.
  • submitted_at: The timestamp indicating when the timesheet was submitted.
  • time_trackings: The following section explains this field in detail.

TimeTracking

This object represents the first level of breakdown within a timesheet. It provides detailed information about each shift recorded in the timesheet. For example, a single TimeTracking object might look like this:

"time_tracking":[
  {
    "clock_in":"2021-07-15T18:18:17Z",
    "clock_out":"2021-07-15T18:18:17Z",
    "has_holiday_hours":false,
    "has_night_hours":false,
    "has_weekend_hours":false,
    "holiday_hours":{
      "hours":35,
      "minutes":13
    },
    "night_hours":{
      "hours":35,
      "minutes":13
    },
    "notes":"Time tracking project.",
    "time_breakdown":{
      "day":{
        "holiday":{
          "hours":35,
          "minutes":13
        },
        "regular":{
          "hours":35,
          "minutes":13
        },
        "weekend":{
          "hours":35,
          "minutes":13
        }
      },
      "night":{
        "holiday":{
          "hours":35,
          "minutes":13
        },
        "regular":{
          "hours":35,
          "minutes":13
        },
        "weekend":{
          "hours":35,
          "minutes":13
        }
      }
    },
    "timezone":"Etc/UTC",
    "total_hours":{
      "hours":35,
      "minutes":13
    },
    "type":"regular_hours",
    "weekend_hours":{
      "hours":35,
      "minutes":13
    }
  }
],

This object has the following fields:

  • type: Specifies the type of time tracking. Possible values are: regular_hours, overtime, on_call, break, time_off, public_holiday.
  • timezone: The timezone associated with the time tracking entry.
  • notes: Additional notes related to the time tracking entry.
  • total_hours: An object containing hours and minutes, representing the total recorded hours in the time tracking entry.
  • weekend_hours: An object containing hours and minutes, representing the total weekend hours in the time tracking entry.
  • holiday_hours: An object containing hours and minutes, representing the total holiday hours in the time tracking entry.
  • night_hours: An object containing hours and minutes, representing the total night hours in the time tracking entry.
  • clock_in: The date and time when the shift started (clock-in time).
  • clock_out: The date and time when the shift ended (clock-out time).
  • has_holiday_hours: A boolean indicating whether the time tracking entry includes holiday hours.
  • has_night_hours: A boolean indicating whether the time tracking entry includes night hours.
  • has_weekend_hours: A boolean indicating whether the time tracking entry includes weekend hours.
  • time_breakdown: An object providing a detailed breakdown of the time tracking entry. It categorizes time into day and night segments and further subdivides these into holiday, regular, and weekend hours.

ℹ️ Time tracking varies depending on the country. For example, the definition of what counts as a holiday, night shift, and weekend hours is different for every country and is automatically processed by Remote.

In general, for a single time_tracking object, we would have three indicators: has_holiday_hours, has_night_hours, and has_weekend_hours. In addition to these indicators, the type could be one of the following break, on_call, overtime, regular_hours, time_off, and public_holiday.

An API user can leverage both the type and the fields hours and minutes of holiday_hours, weekend_hours and night_hours to determine all possible scenarios.

To further explain the logic that is used to determine how each entry is categorized, we can take a look at a more complex timeTracking scenario:

{
   "type":"overtime",
   "timezone":"Canada/Montreal",
   "notes":"Complex example",
   "total_hours":{
      "minutes":0,
      "hours":16
   },
   "holiday_hours":{
      "minutes":0,
      "hours":0
   },
   "weekend_hours":{
      "minutes":0,
      "hours":1
   },
   "night_hours":{
      "minutes":0,
      "hours":4
   },
   "clock_in":"2024-06-23T14:00:00Z",
   "clock_out":"2024-06-23T16:00:00Z",
   "has_holiday_hours":false,
   "has_night_hours":true,
   "has_weekend_hours":true,
   "time_breakdown":{
      "day":{
         "regular":{
            "minutes":0,
            "hours":11
         },
         "holiday":{
            "minutes":0,
            "hours":0
         },
         "weekend":{
            "minutes":0,
            "hours":0
         }
      },
      "night":{
         "regular":{
            "minutes":0,
            "hours":4
         },
         "holiday":{
            "minutes":0,
            "hours":0
         },
         "weekend":{
            "minutes":0,
            "hours":1
         }
      }
   }
}

In this example, the type is set to overtime, and the TimeTracking entry includes night hours and weekend hours, with a total of 16 hours recorded.

Looking deeper into the time_breakdown, the composition of these 16 hours is as follows:

  • 1 hour of overtime weekend night hours.
  • 4 hours of overtime night hours.
  • 11 hours of overtime regular hours.

Special cases

There are 2 special types of time tracking:

  • public_holiday: Used when the time off that generated the time tracking entry corresponds to a holiday (either automatic or manually recorded).
  • time_off: Used for all other types of time-off requests, such as PTO, sick leave, etc.

For these special types, it is possible for time tracking entries to overlap. For example, if there is a public holiday on December 25th and an employee works 2 hours of overtime on that day, the system will create:

  • One time tracking entry covering the entire day for the public holiday.
  • And another entry for the 2 hours overtime worked on the same day.

Special types cannot be manually tracked. They are automatically synced when being added, canceled, or declined.

Approve Timesheet

This endpoint is used to approve a submitted timesheet. It sends a simple response with all the details necessary to approve the entry.

{
   "data":{
      "timesheet":{
         "approval_required":true,
         "country_code":"PRT",
         "employment_id":"663e0b79-c893-45ff-a1b2-f6dcabc098b5",
         "end_date":"2021-07-01",
         "id":"663e0b79-c893-45ff-a1b2-f6dcabc098b5",
         "notes":"Some notes",
         "start_date":"2021-07-01",
         "status":"submitted",
         "submitted_at":"2021-07-15T18:18:17Z"
      }
   }
}

ℹ️ You can only use this endpoint to approve a timesheet if the approval_required flag is set to true.

Automatically approved timesheets

A timesheet is automatically approved if either of the following conditions are met:

  • The submitted week only includes regular hours - meaning there was no overtime, no night shifts, no weekend hours worked, etc.
  • The approval_required flag is not set while submitting the request.

Any timesheet that has been automatically approved will have the default user listed in the approved_by field.

Send back a Timesheet

This endpoint is used to send back a timesheet for review or modification to the employee.

Here is an example of the response:

{
   "data":{
      "timesheet":{
         "id":"663e0b79-c893-45ff-a1b2-f6dcabc098b5",
         "sent_back":true,
         "sent_back_reason":"Please review the timesheet.",
         "status":"submitted"
      }
   }
}
  • sent_back: A boolean indicating whether this timesheet was sent back by the reviewer.
  • sent_back_reason: A string providing the reason why the timesheet was sent back.

ℹ️ If the employer sends the timesheet back for amendments, its status changes to in_calibration, and the fields sent_back and sent_back_by will be flagged to indicate this action.