Planhat Logo

Developers

Planhat Logo

Developers

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": []
 }'