Time tracking
Learn how to use the time tracking API to keep the time sheets of your Global Payroll employees under control
With the time tracking API, you can manage the time worked by employees, and add, update, retrieve and delete their shifts.
The time tracking API only works for Global Payroll
Independent contractors use timesheets to track their time. For more information, see Timesheets.
Manage shifts
Here's a few things to keep in mind before starting to manage shifts:
- Shifts are linked contracts. To manage shifts, you need the contract ID that you can retrieve from the GET list of contracts endpoint.
- Shifts are processed and compensated at the end of each payroll cycle.
- If you submit a shift for a past payroll cycle, it will be compensated at the end of the current cycle without validating if the date of the shift falls within the current cycle.
- (Remove if redundant?) Shifts will be compensated according to the shift_rate attached to each shift and combination of per hour base salary of the employee.
Add shifts for an employee
You can add multiple shifts for a single contract by providing an array of shifts. Before creating a shift, you need to create a shift rate that you will link to the shift.
To add shifts, make a POST request to the Create a time tracking shift endpoint.
curl --location --request POST 'https://api.letsdeel.com/rest/v2/time_tracking/shifts' \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json' \
--data '{
"data": {
"contract_id": "123456",
"shifts": [
{
"external_id": "shift_123456",
"description": "This is a sample shift description.",
"date_of_work": "2023-10-01",
"meta": {
"start": {
"date": "2023-10-01",
"time": "08:00",
"is_rest_day": false,
"is_public_holiday": false
},
"end": {
"date": "2023-10-01",
"time": "17:00",
"is_rest_day": false,
"is_public_holiday": false
},
"breaks": [
{
"start": {
"date": "2023-10-01",
"time": "12:00"
},
"end": {
"date": "2023-10-01",
"time": "12:30"
},
"is_paid": true
}
],
"approval_date": "2023-10-02"
},
"summary": {
"shift_rate_external_id": "rate1234",
"shift_duration_hours": 8,
"total_break_hours": 1,
"payable_break_hours": 0.5,
"total_payable_hours": 7.5
}
}
]
}
}'
In the body:
Name | Required | Type | Format | Description | Example |
---|---|---|---|---|---|
contract_id | true | string | - | Unique identifier of the contract for which shifts are being submitted | 123456 |
description | true | string | - | Description of shift. Use it to describe what kind of work is done during the shift. | This is a sample shift description. |
external_id | true | string | - | User-defined ID of the shift | shift_123456 |
date_of_work | true | string | date | Date on which shift is performed. It is used to identify the payroll cycle of the shift | 2023-10-01 |
meta | false | object | - | Object containing metadata about the shift. This data is used for descriptive purposes and doesn't affect how the payroll is calculated. | - |
meta.start.date | true | string | date | Start date of the shift | 2023-10-01 |
meta.start.time | true | string | - | Start time of the shift | 08:00 |
meta.start.is_rest_day | true | boolean | - | Is there a rest day or weekend on the start date of the shift | false |
meta.start.is_public_holiday | true | boolean | - | Is public holiday on the start of the shift | false |
meta.end.date | true | string | date | End date of the shift | 2023-10-01 |
meta.end.time | true | string | - | End time of the shift. The format is HH:MM. | 17:00 |
meta.end.is_rest_day | true | boolean | - | Is there a rest day or weekend on the end date of the shift | false |
meta.end.is_public_holiday | true | boolean | - | Is public holiday on the end of the shift | false |
meta.breaks | false | array | - | List of breaks during the shift. Multiple breaks are allowed. | - |
meta.breaks.start.date | true | string | date | Start date of the break | 2023-10-01 |
meta.breaks.start.time | true | string | - | Start time of the break. The format is HH:MM. | 12:00 |
meta.breaks.[0].end.date | true | string | date | End date of the break | 2023-10-01 |
meta.breaks.[0].end.time | true | string | - | End time of the break. The format is HH:MM. | 12:30 |
meta.breaks.[0].is_paid | true | boolean | - | Defines if break is paid or not | true |
meta.approval_date | true | string | date | Date on which shift is approved | 2023-10-02 |
summary | true | object | - | Object containing numerical data about the shift. This data is used to calculate the amount to be paid for the shift. | - |
summary.shift_rate_external_id | true | string | - | ID of the shift rate. Use it to link the shift to a shift rate you created. | rate1234 |
summary.shift_duration_hours | false | number | - | Total time of the shift in hours | 8 |
summary.total_break_hours | false | number | - | Total break time in hours | 1 |
summary.payable_break_hours | false | number | - | Total breaks hours that must be paid | 0.5 |
summary.total_payable_hours | true | number | - | Total hours that need be paid using the shift rate provided above | 7.5 |
A successful response (200
) returns the details of the shift created.
{
"data": [
{
"external_id": "95c35493-41aa-44f8-9154-5a25cbbc1865",
"organization_id": 0,
"description": "string",
"date_of_work": "2019-08-24T14:15:22Z",
"contract_id": "string",
"meta": {
"start": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd$",
"is_rest_day": true,
"is_public_holiday": true
},
"end": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd$",
"is_rest_day": true,
"is_public_holiday": true
},
"breaks": [
{
"start": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd:$"
},
"end": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd$"
},
"is_paid": true
}
],
"approval_date": "^\\dddd-\\dd-\\dd$"
},
"summary": {
"shift_duration_hours": 0,
"total_break_hours": 0,
"payable_break_hours": 0,
"total_payable_hours": 0
},
"created_at": "2022-05-24T09:38:46.235Z",
"updated_at": "2022-05-24T09:38:46.235Z"
}
]
}
Where:
Name | Required | Type | Format | Description | Example |
---|---|---|---|---|---|
external_id | true | string | - | User-defined ID of the shift | shift_123456 |
organization_id | true | number | - | The ID of your organization | 123456 |
description | false | string | - | Description of shift | This is a sample shift description. |
date_of_work | true | string | date-time | Date of the shift | 2019-08-24T14:15:22Z |
contract_id | false | string | - | Unique identifier of the contract that shifts were submitted for | 123456 |
meta | false | object | - | Object containing metadata about the shift. This data is used for descriptive purposes and doesn't affect how the payroll is calculated. | - |
summary | true | object | - | Object containing numerical data about the shift. This data is used to calculate the amount to be paid for the shift. | - |
created_at | true | string | date-time | Date on which the shift is created | 2022-05-24T09:38:46.235Z |
updated_at | true | string | date-time | Date on which the shift is updated | 2022-05-24T09:38:46.235Z |
List shifts in your organization
You can list the shifts in your organization and sort them by the time of creation.
To list shifts, make a GET request to the List time tracking shifts endpoint.
curl --location --request GET 'https://api.letsdeel.com/rest/v2/time_tracking/shifts?limit=10&offset=20' \
--header 'Authorization: Bearer {{token}}'
In the query:
Name | Required | Type | Format | Description | Example |
---|---|---|---|---|---|
limit | false | number | Number of rows that must be returned in one API call | 100 | |
offset | false | number | Number of rows that must be skipped when returning the results | 10 |
A successful response (200
) returns the list of shifts available in your organization and matching any filters applied. For example:
{
"data": [
{
"external_id": "d3m0d3m0-d3m0-d3m0-d3m0-d3m0d3m0d3m0",
"organization_id": 0,
"description": "string",
"date_of_work": "2019-08-24T14:15:22Z",
"contract_id": "string",
"meta": {
"start": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd$",
"is_rest_day": true,
"is_public_holiday": true
},
"end": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd$",
"is_rest_day": true,
"is_public_holiday": true
},
"breaks": [
{
"start": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd:$"
},
"end": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd$"
},
"is_paid": true
}
],
"approval_date": "^\\dddd-\\dd-\\dd$"
},
"summary": {
"shift_duration_hours": 0,
"total_break_hours": 0,
"payable_break_hours": 0,
"total_payable_hours": 0
},
"created_at": "2022-05-24T09:38:46.235Z",
"updated_at": "2022-05-24T09:38:46.235Z"
}
],
"page": {
"total_rows": 0,
"items_per_page": 1,
"offset": 999999999
}
}
Where:
Name | Required | Type | Format | Description | Example |
---|---|---|---|---|---|
data | true | array | - | The list of shifts available | - |
page | true | object | - | Contains information to navigate to the next set of results, if applicable | - |
Retrieve a single shift
You can retrieve the information of a single shift starting from the external_id
of the shift.
To retrieve a shift, make a GET request to the Retrieve a single time tracking shift endpoint.
curl --location --request GET 'https://api.letsdeel.com/rest/v2/time_tracking/shifts/{{external_id}}' \
--header 'Authorization: Bearer {{token}}'
A successful response (200
) returns the information of the requested shift.
{
"external_id": "d3m0d3m0-d3m0-d3m0-d3m0-d3m0d3m0d3m0",
"organization_id": 0,
"description": "string",
"date_of_work": "2019-08-24T14:15:22Z",
"contract_id": "string",
"meta": {
"start": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd$",
"is_rest_day": true,
"is_public_holiday": true
},
"end": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd$",
"is_rest_day": true,
"is_public_holiday": true
},
"breaks": [
{
"start": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd:$"
},
"end": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd$"
},
"is_paid": true
}
],
"approval_date": "^\\dddd-\\dd-\\dd$"
},
"summary": {
"shift_duration_hours": 0,
"total_break_hours": 0,
"payable_break_hours": 0,
"total_payable_hours": 0
},
"created_at": "2022-05-24T09:38:46.235Z",
"updated_at": "2022-05-24T09:38:46.235Z"
}
Update shifts for an employee
If you need it, you can update the information of a shift.
You can only update shifts that haven't been processed for payroll
Shifts are processed for payroll at the cutoff date. You can configure the cutoff date in the Deel app.
To update a shift, make a PATCH request to the Update a time tracking shift endpoint.
curl --location --request PATCH 'https://api.letsdeel.com/rest/v2/time_tracking/shifts/{{external_id}}' \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json' \
--data '{
"data": {
"description": "This is a sample shift description.",
"date_of_work": "2023-10-01",
"meta": {
"start": {
"date": "2023-10-01",
"time": "08:00",
"is_rest_day": false,
"is_public_holiday": false
},
"end": {
"date": "2023-10-01",
"time": "17:00",
"is_rest_day": false,
"is_public_holiday": false
},
"breaks": [
{
"start": {
"date": "2023-10-01",
"time": "12:00"
},
"end": {
"date": "2023-10-01",
"time": "13:00"
},
"is_paid": false
}
],
"approval_date": "2023-10-01"
},
"summary": {
"shift_duration_hours": 8,
"total_break_hours": 1,
"payable_break_hours": 0.5,
"total_payable_hours": 7.5
}
}
}'
In the path:
Name | Required | Type | Format | Description | Example |
---|---|---|---|---|---|
external_id | true | string | - | User-defined ID of the shift | shift_123456 |
In the body:
Name | Required | Type | Format | Description | Example |
---|---|---|---|---|---|
data | true | object | - | Contains the information of the shift that must be updated. | - |
A successful response (200
) returns the updated shift. For example:
{
"external_id": "95c35493-41aa-44f8-9154-5a25cbbc1865",
"organization_id": 0,
"description": "string",
"date_of_work": "2019-08-24T14:15:22Z",
"contract_id": "string",
"meta": {
"start": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd$",
"is_rest_day": true,
"is_public_holiday": true
},
"end": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd$",
"is_rest_day": true,
"is_public_holiday": true
},
"breaks": [
{
"start": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd:$"
},
"end": {
"date": "^\\dddd-\\dd-\\dd$",
"time": "^\\dd:\\dd$"
},
"is_paid": true
}
],
"approval_date": "^\\dddd-\\dd-\\dd$"
},
"summary": {
"shift_duration_hours": 0,
"total_break_hours": 0,
"payable_break_hours": 0,
"total_payable_hours": 0
},
"created_at": "2022-05-24T09:38:46.235Z",
"updated_at": "2022-05-24T09:38:46.235Z"
}
Delete shift for a contract
You can delete a shift for a contract by using the external_id
of the shift.
To delete a shift, make a DELETE request to the Delete a time tracking shift endpoint.
You can only delete shifts that haven't been processed for payroll
Shifts are processed for payroll at the cutoff date. You can configure the cutoff date in the Deel app.
curl --location --request DELETE 'https://api.letsdeel.com/rest/v2/time_tracking/shifts/{{external_id}}' \
--header 'Authorization: Bearer {{token}}'
Where:
Name | Required | Type | Format | Description | Example |
---|---|---|---|---|---|
external_id | true | string | - | User-defined ID of the shift | shift_123456 |
A successful response (204
) returns an empty body.
Manage shift rates
Shift rates are used in payroll calculations to define the amount of the salary to be paid for a specific shift. There shift rate types are:
Name | Description | Formula | Example |
---|---|---|---|
MULTIPLIER_PERCENTAGE | Defines the rate of a shift as a percentage of the salary, using the employee's hourly salary (if it's a hourly contract) or equivalent hourly salary (for non-hourly contracts). | Total amount for shift = (MULTIPLIER_PERCENTAGE/100) * Per_hour_salary * Total_payable_hours | 10$/hour is the base salary, user submitted shift with total of 5 payable hours and according to the shift rate attached to the shift MULTIPLIERPERCENTAGE is set to 200% so Total amount paid for the shift = 2 10 _ 5 = 100$ |
PER_HOUR_FLAT_RATE | Define the rate of a shift as a flat rate per hour. | Total amount for shift = PER_HOUR_FLAT_RATE * Total_payable_hours | PER_HOUR_FLAT_RATE set to 100$ and total_payable_hours for the shift are 5 hours Total amount paid for the shift = 100 * 5 = 500$ |
Create a shift rate
You can create shift rates for your organization, which you can then map to individual shifts when creating them.
To create a shift rate, make a POST request to the time_tracking/shift_rates endpoint.
curl --location --request POST 'https://api.letsdeel.com/rest/v2/time_tracking/shift_rates' \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json' \
--data '{
"data": {
"external_id": "regular_rate_1",
"name": "Regular Shift rate 1",
"type": "PER_HOUR_FLAT_RATE",
"value": 150
}
}'
Where:
Name | Required | Type | Format | Description | Example |
---|---|---|---|---|---|
external_id | true | string | - | User defined unique identifier for the shift rate | regular_rate_1 |
Step 1: Fill the below details related to the shift rate
Name | Required | Type | Format | Description | Example |
---|---|---|---|---|---|
external_id | true | string | - | User defined unique identifier for the shift rate | regular_rate_1 |
name | true | string | - | A human readable string to identify the purpose of the shift rate | Regular Shift rate 1 |
type | true | string | ENUM | Defines the type of rate that must be used. Use any of the available shift rate types | PER_HOUR_FLAT_RATE |
value | true | number | - | Value of the shift rate, to use in combination with the type parameter | 150 |
Retrieve the shift rate
You can also retrieve the shift rates starting from the external_id
of the shift rate.
To retrieve a shift rate, make a GET request to the Retrieve a single time tracking shift rate endpoint.
curl --location --request GET 'https://api.letsdeel.com/rest/v2/time_tracking/shift_rates/{{external_id}}' \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json'
Where:
Name | Required | Type | Format | Description | Example |
---|---|---|---|---|---|
external_id | true | string | - | User-defined unique identifier for the shift rate | shift_123456 |
A successful response (200
) returns the shift rate of the requested shift. For example:
{
"data": {
"organization_id": "string",
"external_id": "string",
"name": "string",
"rate_type": "MULTIPLIER_PERCENTAGE",
"value": 0,
"created_at": "2022-05-24T09:38:46.235Z",
"updated_at": "2022-05-24T09:38:46.235Z"
}
}
Retrieve shift rates
You can also retrieve the list of shift rates for your organization.
To retrieve a list of shift rates, make a GET request to the List time tracking shift rates endpoint.
curl --location --request GET 'https://api.letsdeel.com/rest/v2/time_tracking/shift_rates?limit=10&offset=5' \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json'
Name | Required | Type | Format | Description | Example |
---|---|---|---|---|---|
limit | false | number | Number of rows that must be returned in one API call | 100 | |
offset | false | number | Number of rows that must be skipped when returning the results | 10 |
A successful response (200
) returns the list of shift rates available in your organization and matching any filters applied. For example:
{
"data": [
{
"organization_id": "string",
"external_id": "string",
"name": "string",
"rate_type": "MULTIPLIER_PERCENTAGE",
"value": 0,
"created_at": "2022-05-24T09:38:46.235Z",
"updated_at": "2022-05-24T09:38:46.235Z"
}
],
"page": {
"total_rows": 0,
"items_per_page": 1,
"offset": 999999999
}
}
Where:
Name | Required | Type | Format | Description | Example |
---|---|---|---|---|---|
data | true | array | - | An array of shift rates | [shift_rate_1, shift_rate_2, shift_rate_3] |
organization_id | true | number | - | The ID of your organization | 123456 |
external_id | true | string | - | User defined unique identifier for the shift rate | regular_rate_1 |
name | true | string | - | A human readable string to identify the purpose of the shift rate | Regular Shift rate 1 |
rate_type | true | string | ENUM | Defines the type of rate that must be used. Use any of the available shift rate types | PER_HOUR_FLAT_RATE |
value | true | number | - | Value of the shift rate, to use in combination with the type parameter | 150 |
created_at | true | string | date-time | Date on which the shift rate is created | 2022-05-24T09:38:46.235Z |
updated_at | true | string | date-time | Date on which the shift rate is updated | 2022-05-24T09:38:46.235Z |
page | true | object | - | An object containing pagination information. Use it to navigate through sets of | - |
Update a shift rate
You can also update a shift rate if it's not being used in any shift, by using the external_id
of the shift rate.
To update a shift rate, make a PATCH request to the Update a time tracking shift rate endpoint.
Only shift rates that are not used in any shift can be updated.
curl --location --request PATCH 'https://api.letsdeel.com/rest/v2/time_tracking/shift_rates/{{external_id}}' \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json' \
--data '{
"data": {
"name": "On-call shift rate",
"type": "PER_HOUR_FLAT_RATE",
"value": 150
}
}'
In the path:
Name | Required | Type | Format | Description | Example |
---|---|---|---|---|---|
external_id | true | string | - | User defined unique identifier for the shift rate | regular_rate_1 |
In the body:
Name | Required | Type | Format | Description | Example |
---|---|---|---|---|---|
name | true | string | - | A human readable string to identify the purpose of the shift rate | Regular Shift rate 1 |
type | true | string | ENUM | Defines the type of rate that must be used. Use any of the available shift rate types | PER_HOUR_FLAT_RATE |
value | true | number | - | Value of the shift rate, to use in combination with the type parameter | 150 |
A successful response (200
) returns the updated shift rate. For example:
{
"data": {
"organization_id": "string",
"external_id": "string",
"name": "string",
"rate_type": "MULTIPLIER_PERCENTAGE",
"value": 0,
"created_at": "2022-05-24T09:38:46.235Z",
"updated_at": "2022-05-24T09:38:46.235Z"
}
}
Delete a shift rate
You can also delete a shift rate if it's not being used in any shift, by using the external_id
of the shift rate.
To delete a shift rate, make a DELETE request to the Delete a time tracking shift rate endpoint.
Only shift rates that are not used in any shift can be deleted.
curl --location --request DELETE 'https://api.letsdeel.com/rest/v2/time_tracking/shift_rates/{{external_id}}' \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json'
A successful response (204
) returns an empty body.
Updated 5 months ago