Time Entry
The Time Entry model represents single time log, used for tracking time. Theoretically, Time Entries can be associated with many models in Planhat (all except User, Metric), and can be restricted to certain models in tenant settings. For now Time Entries created via API can only be associated to the Company model, by setting the CompanyId.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
companyId | objectId | Company id (planhat identifier). If time entry is tracked on model that is not company, this field is autofilled if model is related to company. | |
date | Yes | string | Date when time was logged in ISO format. |
hours | Yes | number | The total hours logged, must be positive, can be a decimal number, and between 0.1 and 24. |
isTimeOff | boolean | Indicates if the time entry is a time off (vacation, sick leave, etc). | |
description | string | Description of the time entry. | |
isBillable | boolean | Indicates if the time entry is billable. | |
billingCode | string | Billing code for the time entry if it is billable. | |
currency | string | The currency code, for example "USD". There is a "soft" mapping to the id’s in your list of currencies. Technically we accept any string but we recommend using standard currency codes as Ids. Since the mapping is soft you can add time entries with a currency code not yet available in your list of currencies. | |
billableRate | number | Billable rate for the time entry. | |
totalBilled | number | The total amount billed for the time entry (hours * billableRate). Calculated automatically. | |
costRate | number | Cost rate for the time entry. | |
totalCost | number | The total cost for the time entry (hours * costRate). Calculated automatically. | |
timesheetStatus | string | Status of the time entry in the timesheet. Possible values are: "draft", "submitted", "approved", "returned". Default is "draft". It's readonly field. (Autogenerated). | |
timesheetId | objectId | Related timesheet id (planhat identifier), exists only if the time entry belongs to timesheet. It's readonly field. (Autogenerated). | |
assignedModel | string | Model which the Time Entry is assigned to. Current supported value is "User". | |
assignedId | objectId | Id of which the Time Entry is assigned to. Currently only supports User Ids. |
The Time Entry model represents single time log, used for tracking time. Theoretically, Time Entries can be associated with many models in Planhat (all except User, Metric), and can be restricted to certain models in tenant settings. For now Time Entries created via API can only be associated to the Company model, by setting the CompanyId.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
companyId | objectId | Company id (planhat identifier). If time entry is tracked on model that is not company, this field is autofilled if model is related to company. | |
date | Yes | string | Date when time was logged in ISO format. |
hours | Yes | number | The total hours logged, must be positive, can be a decimal number, and between 0.1 and 24. |
isTimeOff | boolean | Indicates if the time entry is a time off (vacation, sick leave, etc). | |
description | string | Description of the time entry. | |
isBillable | boolean | Indicates if the time entry is billable. | |
billingCode | string | Billing code for the time entry if it is billable. | |
currency | string | The currency code, for example "USD". There is a "soft" mapping to the id’s in your list of currencies. Technically we accept any string but we recommend using standard currency codes as Ids. Since the mapping is soft you can add time entries with a currency code not yet available in your list of currencies. | |
billableRate | number | Billable rate for the time entry. | |
totalBilled | number | The total amount billed for the time entry (hours * billableRate). Calculated automatically. | |
costRate | number | Cost rate for the time entry. | |
totalCost | number | The total cost for the time entry (hours * costRate). Calculated automatically. | |
timesheetStatus | string | Status of the time entry in the timesheet. Possible values are: "draft", "submitted", "approved", "returned". Default is "draft". It's readonly field. (Autogenerated). | |
timesheetId | objectId | Related timesheet id (planhat identifier), exists only if the time entry belongs to timesheet. It's readonly field. (Autogenerated). | |
assignedModel | string | Model which the Time Entry is assigned to. Current supported value is "User". | |
assignedId | objectId | Id of which the Time Entry is assigned to. Currently only supports User Ids. |
The Time Entry model represents single time log, used for tracking time. Theoretically, Time Entries can be associated with many models in Planhat (all except User, Metric), and can be restricted to certain models in tenant settings. For now Time Entries created via API can only be associated to the Company model, by setting the CompanyId.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
companyId | objectId | Company id (planhat identifier). If time entry is tracked on model that is not company, this field is autofilled if model is related to company. | |
date | Yes | string | Date when time was logged in ISO format. |
hours | Yes | number | The total hours logged, must be positive, can be a decimal number, and between 0.1 and 24. |
isTimeOff | boolean | Indicates if the time entry is a time off (vacation, sick leave, etc). | |
description | string | Description of the time entry. | |
isBillable | boolean | Indicates if the time entry is billable. | |
billingCode | string | Billing code for the time entry if it is billable. | |
currency | string | The currency code, for example "USD". There is a "soft" mapping to the id’s in your list of currencies. Technically we accept any string but we recommend using standard currency codes as Ids. Since the mapping is soft you can add time entries with a currency code not yet available in your list of currencies. | |
billableRate | number | Billable rate for the time entry. | |
totalBilled | number | The total amount billed for the time entry (hours * billableRate). Calculated automatically. | |
costRate | number | Cost rate for the time entry. | |
totalCost | number | The total cost for the time entry (hours * costRate). Calculated automatically. | |
timesheetStatus | string | Status of the time entry in the timesheet. Possible values are: "draft", "submitted", "approved", "returned". Default is "draft". It's readonly field. (Autogenerated). | |
timesheetId | objectId | Related timesheet id (planhat identifier), exists only if the time entry belongs to timesheet. It's readonly field. (Autogenerated). | |
assignedModel | string | Model which the Time Entry is assigned to. Current supported value is "User". | |
assignedId | objectId | Id of which the Time Entry is assigned to. Currently only supports User Ids. |
Create Time Entry
To create a time entry the required fields are date and hours. Keep in mind that the hours must be positive, can be a decimal number, and between 0.1 and 24.
Example Request
curl --location -g --request POST 'https://api.planhat.com/timeentries' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"hours": 5,
"date": "2025-01-30T14:51:01.691Z",
"description": "Worked on the integration issue"
}'
Example Response
'{
"timesheetStatus": "draft",
"assignedModel": "User",
"_id": "67d04352557181002fd16424",
"hours": 5,
"date": "2025-01-30T00:00:00.000Z",
"description": "Worked on the integration issue",
"path": [],
"totalBilled": 0,
"totalCost": 0,
"createdAt": "2025-03-11T14:06:10.722Z",
"updatedAt": "2025-03-11T14:06:10.722Z",
"__v": 0
}'
Create Time Entry
To create a time entry the required fields are date and hours. Keep in mind that the hours must be positive, can be a decimal number, and between 0.1 and 24.
Example Request
curl --location -g --request POST 'https://api.planhat.com/timeentries' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"hours": 5,
"date": "2025-01-30T14:51:01.691Z",
"description": "Worked on the integration issue"
}'
Example Response
'{
"timesheetStatus": "draft",
"assignedModel": "User",
"_id": "67d04352557181002fd16424",
"hours": 5,
"date": "2025-01-30T00:00:00.000Z",
"description": "Worked on the integration issue",
"path": [],
"totalBilled": 0,
"totalCost": 0,
"createdAt": "2025-03-11T14:06:10.722Z",
"updatedAt": "2025-03-11T14:06:10.722Z",
"__v": 0
}'
Create Time Entry
To create a time entry the required fields are date and hours. Keep in mind that the hours must be positive, can be a decimal number, and between 0.1 and 24.
Example Request
curl --location -g --request POST 'https://api.planhat.com/timeentries' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"hours": 5,
"date": "2025-01-30T14:51:01.691Z",
"description": "Worked on the integration issue"
}'
Example Response
'{
"timesheetStatus": "draft",
"assignedModel": "User",
"_id": "67d04352557181002fd16424",
"hours": 5,
"date": "2025-01-30T00:00:00.000Z",
"description": "Worked on the integration issue",
"path": [],
"totalBilled": 0,
"totalCost": 0,
"createdAt": "2025-03-11T14:06:10.722Z",
"updatedAt": "2025-03-11T14:06:10.722Z",
"__v": 0
}'
Update Time Entry
To update a time entry it's required to pass the time entry _id in the request URL as a parameter.
Example Request
curl --location -g --request PUT 'https://api.planhat.com/timeentries/610411d5b046afb2109df12c' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"hours": 7
}'
Example Response
'{
"_id": "67d04352557181002fd16424",
"timesheetStatus": "draft",
"assignedModel": "User",
"hours": 7,
"date": "2025-01-30T00:00:00.000Z",
"description": "Worked on the integration issue",
"path": [],
"totalBilled": 0,
"totalCost": 0,
"createdAt": "2025-03-11T14:06:10.722Z",
"updatedAt": "2025-03-11T16:50:26.953Z",
"__v": 0
}'
Update Time Entry
To update a time entry it's required to pass the time entry _id in the request URL as a parameter.
Example Request
curl --location -g --request PUT 'https://api.planhat.com/timeentries/610411d5b046afb2109df12c' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"hours": 7
}'
Example Response
'{
"_id": "67d04352557181002fd16424",
"timesheetStatus": "draft",
"assignedModel": "User",
"hours": 7,
"date": "2025-01-30T00:00:00.000Z",
"description": "Worked on the integration issue",
"path": [],
"totalBilled": 0,
"totalCost": 0,
"createdAt": "2025-03-11T14:06:10.722Z",
"updatedAt": "2025-03-11T16:50:26.953Z",
"__v": 0
}'
Update Time Entry
To update a time entry it's required to pass the time entry _id in the request URL as a parameter.
Example Request
curl --location -g --request PUT 'https://api.planhat.com/timeentries/610411d5b046afb2109df12c' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"hours": 7
}'
Example Response
'{
"_id": "67d04352557181002fd16424",
"timesheetStatus": "draft",
"assignedModel": "User",
"hours": 7,
"date": "2025-01-30T00:00:00.000Z",
"description": "Worked on the integration issue",
"path": [],
"totalBilled": 0,
"totalCost": 0,
"createdAt": "2025-03-11T14:06:10.722Z",
"updatedAt": "2025-03-11T16:50:26.953Z",
"__v": 0
}'
get Time Entries by ID
To get a specific time entry it's required to pass the _id in the request URL as a parameter.
Example Request
curl --location -g --request GET 'https://api.planhat.com/timeentries/67d04352557181002fd16424' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
Example Response
'{
"_id": "67d04352557181002fd16424",
"timesheetStatus": "draft",
"assignedModel": "User",
"hours": 7,
"date": "2025-01-30T00:00:00.000Z",
"description": "Worked on the integration issue",
"path": [],
"totalBilled": 0,
"totalCost": 0,
"createdAt": "2025-03-11T14:06:10.722Z",
"updatedAt": "2025-03-11T16:50:26.953Z",
"__v": 0
}'
get Time Entries by ID
To get a specific time entry it's required to pass the _id in the request URL as a parameter.
Example Request
curl --location -g --request GET 'https://api.planhat.com/timeentries/67d04352557181002fd16424' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
Example Response
'{
"_id": "67d04352557181002fd16424",
"timesheetStatus": "draft",
"assignedModel": "User",
"hours": 7,
"date": "2025-01-30T00:00:00.000Z",
"description": "Worked on the integration issue",
"path": [],
"totalBilled": 0,
"totalCost": 0,
"createdAt": "2025-03-11T14:06:10.722Z",
"updatedAt": "2025-03-11T16:50:26.953Z",
"__v": 0
}'
get Time Entries by ID
To get a specific time entry it's required to pass the _id in the request URL as a parameter.
Example Request
curl --location -g --request GET 'https://api.planhat.com/timeentries/67d04352557181002fd16424' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
Example Response
'{
"_id": "67d04352557181002fd16424",
"timesheetStatus": "draft",
"assignedModel": "User",
"hours": 7,
"date": "2025-01-30T00:00:00.000Z",
"description": "Worked on the integration issue",
"path": [],
"totalBilled": 0,
"totalCost": 0,
"createdAt": "2025-03-11T14:06:10.722Z",
"updatedAt": "2025-03-11T16:50:26.953Z",
"__v": 0
}'
get Time Entries List
When fetching multiple time entries there are some options that can be used via query params:
companyId: Filter using company id.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
Example Request
curl --location -g --request GET 'https://api.planhat.com/timeentries?limit=2&offset=0&sort=-createdAt&select=_id,hours,date' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
Example Response
'[
{
"_id": "67d04352557181002fd16424",
"hours": 7,
"date": "2025-01-30T00:00:00.000Z"
},
{
"_id": "67c98759b874ce002f97cb48",
"date": "2025-03-06T00:00:00.000Z",
"hours": 12
}
]'
get Time Entries List
When fetching multiple time entries there are some options that can be used via query params:
companyId: Filter using company id.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
Example Request
curl --location -g --request GET 'https://api.planhat.com/timeentries?limit=2&offset=0&sort=-createdAt&select=_id,hours,date' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
Example Response
'[
{
"_id": "67d04352557181002fd16424",
"hours": 7,
"date": "2025-01-30T00:00:00.000Z"
},
{
"_id": "67c98759b874ce002f97cb48",
"date": "2025-03-06T00:00:00.000Z",
"hours": 12
}
]'
get Time Entries List
When fetching multiple time entries there are some options that can be used via query params:
companyId: Filter using company id.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
Example Request
curl --location -g --request GET 'https://api.planhat.com/timeentries?limit=2&offset=0&sort=-createdAt&select=_id,hours,date' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
Example Response
'[
{
"_id": "67d04352557181002fd16424",
"hours": 7,
"date": "2025-01-30T00:00:00.000Z"
},
{
"_id": "67c98759b874ce002f97cb48",
"date": "2025-03-06T00:00:00.000Z",
"hours": 12
}
]'
delete Time Entries
To delete a time entry it's required to pass the _id in the request URL as a parameter.
Example Request
curl --location -g --request DELETE 'https://api.planhat.com/timeentries/67d04352557181002fd16424' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
Example Response
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
delete Time Entries
To delete a time entry it's required to pass the _id in the request URL as a parameter.
Example Request
curl --location -g --request DELETE 'https://api.planhat.com/timeentries/67d04352557181002fd16424' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
Example Response
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
delete Time Entries
To delete a time entry it's required to pass the _id in the request URL as a parameter.
Example Request
curl --location -g --request DELETE 'https://api.planhat.com/timeentries/67d04352557181002fd16424' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
Example Response
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
Bulk Upsert Time Entries
To create a time entry it's required to define a hours and date.
To update a time entry it is required to specify _id in the payload.
Since this is a bulk upsert operation it's possible to create and/or update multiple time entries with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
Example Request
curl --location -g --request PUT 'https://api.planhat.com/timeentries' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"_id": "677427729c28f8015843e87d",
"hours": 6
},
{
"_id": "677427729c28f8015843e87e",
"description": "There is a problem with our integration settings that is affecting some users."
},
{
"hours": 10,
"date": "2025-01-30T14:51:01.691Z",
"description": "Creating time entry using bulk operations"
}
]'
Example Response
'{
"created": 1,
"createdErrors": [],
"insertsKeys": [
{
"_id": "67d070dc557181002fd16c9d"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 2,
"modified": [],
"upsertedIds": [
"67d070dc557181002fd16c9d"
],
"permissionErrors": [],
"validationErrors": []
}'
Bulk Upsert Time Entries
To create a time entry it's required to define a hours and date.
To update a time entry it is required to specify _id in the payload.
Since this is a bulk upsert operation it's possible to create and/or update multiple time entries with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
Example Request
curl --location -g --request PUT 'https://api.planhat.com/timeentries' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"_id": "677427729c28f8015843e87d",
"hours": 6
},
{
"_id": "677427729c28f8015843e87e",
"description": "There is a problem with our integration settings that is affecting some users."
},
{
"hours": 10,
"date": "2025-01-30T14:51:01.691Z",
"description": "Creating time entry using bulk operations"
}
]'
Example Response
'{
"created": 1,
"createdErrors": [],
"insertsKeys": [
{
"_id": "67d070dc557181002fd16c9d"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 2,
"modified": [],
"upsertedIds": [
"67d070dc557181002fd16c9d"
],
"permissionErrors": [],
"validationErrors": []
}'
Bulk Upsert Time Entries
To create a time entry it's required to define a hours and date.
To update a time entry it is required to specify _id in the payload.
Since this is a bulk upsert operation it's possible to create and/or update multiple time entries with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
Example Request
curl --location -g --request PUT 'https://api.planhat.com/timeentries' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"_id": "677427729c28f8015843e87d",
"hours": 6
},
{
"_id": "677427729c28f8015843e87e",
"description": "There is a problem with our integration settings that is affecting some users."
},
{
"hours": 10,
"date": "2025-01-30T14:51:01.691Z",
"description": "Creating time entry using bulk operations"
}
]'
Example Response
'{
"created": 1,
"createdErrors": [],
"insertsKeys": [
{
"_id": "67d070dc557181002fd16c9d"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 2,
"modified": [],
"upsertedIds": [
"67d070dc557181002fd16c9d"
],
"permissionErrors": [],
"validationErrors": []
}'
Duplicate Time Entry
To duplicate time entries it's required to pass the ids array in the payload. Bulk upsert will be performed on the time entries with the specified ids if ids exist.
Example Request
curl --location -g --request POST 'https://api.planhat.com/timeentries/duplicate' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"ids": ["67d07487557181002fd16d50", "677427729c28f8015843e87d", "677427729c28f8015843e87e"]
}'
Example Response
'{
"count": 3,
"errors": []
}'
Duplicate Time Entry
To duplicate time entries it's required to pass the ids array in the payload. Bulk upsert will be performed on the time entries with the specified ids if ids exist.
Example Request
curl --location -g --request POST 'https://api.planhat.com/timeentries/duplicate' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"ids": ["67d07487557181002fd16d50", "677427729c28f8015843e87d", "677427729c28f8015843e87e"]
}'
Example Response
'{
"count": 3,
"errors": []
}'
Duplicate Time Entry
To duplicate time entries it's required to pass the ids array in the payload. Bulk upsert will be performed on the time entries with the specified ids if ids exist.
Example Request
curl --location -g --request POST 'https://api.planhat.com/timeentries/duplicate' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"ids": ["67d07487557181002fd16d50", "677427729c28f8015843e87d", "677427729c28f8015843e87e"]
}'
Example Response
'{
"count": 3,
"errors": []
}'