Resource: TimeEntry — CRUD and model-specific endpoints
The model serves three purposes distinguished by trackingType. The three are independent in reporting: WORK totals are not affected by WORKTIME or BREAK.
Required fields depend on both trackingType and the account-level AccountSetting.timerMode:
- WORK (project time) —
projectandtaskare required. FollowstimerMode: inDURATION, provideduration+sorting(no times); inSTART_TIME_END_TIME, providestartTime+endTimeand omitsorting(omitendTimewhilerunning). - WORKTIME (clock in/out) —
projectandtaskmust be omitted. Always usesstartTime+endTime, regardless oftimerMode. - BREAK —
projectandtaskmust be omitted. FollowstimerModeonly when the account does not use worktime. When worktime is enabled, BREAK always usesstartTime+endTime(like WORKTIME), but may still includesorting.
Net worktime over a period is sum(WORKTIME.duration) − sum(BREAK.duration).
List TimeEntry (find where)
Find a list of TimeEntry records that match the specified criteria.
Tip: All query parameters accept multiple values for array filtering — e.g. ?id=1&id=2 or ?id[]=1&id[]=2. This also works within the where parameter: ?where={"id":[1,2,3]}.
Note: The per-attribute filter parameters and the where parameter are mutually exclusive. If where is supplied, the per-attribute filters are ignored — put all filter criteria inside where instead. limit, skip, sort, and populate are unaffected.
query Parameters
dayFilter by day (YYYY-MM-DD). This is an exact match filter; for range queries (greater than, less than), use the where parameter instead
sortingDisplay order within the day. Required when the account-level AccountSetting.timerMode is DURATION (except for worktime entries that are not project time). Must be omitted when AccountSetting.timerMode is START_TIME_END_TIME unless the entry is a break.
durationActual tracked duration in seconds. In start/end time mode, computed from startTime and endTime.
estimateReserved for future use.
runningWhether the timer is currently running.
taskID of the associated Task record
projectFilter by project ID
timeEntryReferenceID of the associated TimeEntryReference record. Deprecated. Legacy v1 reference. Use reference instead.
referenceID of the associated Reference record
userFilter by user ID
billedAtTimestamp when this time entry was billed. Set when associated with an invoice, or can be set separately to mark an entry as locked. (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss.sssZ). This is an exact match filter; for range queries (greater than, less than), use the where parameter instead
billableWhether this time entry is billable. Computed from the task assignment and project billing configuration.
startTimeStart time (HH:mm). Used in start/end time timer mode and for WORKTIME/BREAK entries.
trackingTypeType of entry. WORK: time on a specific project. WORKTIME: clock-in/clock-out presence for the day, independent of any project. BREAK: pause within a WORKTIME period. Cannot be changed after creation.
commentFilter by comment
invoiceID of the associated Invoice record. The invoice this time entry was billed on. Set automatically when invoiced; cannot be set directly.
teamID of the associated Team record. The user's team at the time of creation. Auto-assigned from the user's primary team if not provided.
validationStatusApproval status. One of: 'NOTSUBMITTED', 'SUBMITTED', 'REJECTED', 'APPROVED'.
validationID of the associated Validation record. Deprecated. Legacy weekly validation reference.
approvedOnTimestamp when approved. (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss.sssZ). This is an exact match filter; for range queries (greater than, less than), use the where parameter instead
approvedByID of the associated User record. The user who approved this time entry.
durationRoundedDuration in seconds, rounded according to the project rounding settings. Computed automatically.
durationRoundedOverrideManual override of the rounded duration in seconds for billing purposes. PM-only.
hourlyRateComputed hourly rate based on the project's billBy mode. Recalculated on create and update.
idFilter by record ID
createdAtFilter by creation date (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss.sssZ). This is an exact match filter; for range queries (greater than, less than), use the where parameter instead
updatedAtFilter by last update date (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss.sssZ). This is an exact match filter; for range queries (greater than, less than), use the where parameter instead
whereA JSON-encoded Waterline criteria for advanced filtering. Only whitelisted criteria are supported: day, sorting, duration, estimate, running, task, project, timeEntryReference, reference, user, billedAt, billable, startTime, trackingType, comment, invoice, team, validationStatus, validation, approvedOn, approvedBy, durationRounded, durationRoundedOverride, hourlyRate, id, createdAt, updatedAt. Sub-attribute modifiers such as startsWith, >=, <=, >, <, and != are supported on any whitelisted criterion. The contains modifier is only supported on: comment.
Note: If where is supplied, the per-attribute filter query parameters above are ignored — where is the entire criteria. (limit, skip, sort, and populate are unaffected.) To combine filters, put them all inside where.
e.g. ?where={"startDate":{">=":"2026-06-01","<":"2026-07-01"}}
limitThe maximum number of records to return. Defaults to 10000, capped at 50000.
skipThe number of records to skip (useful for pagination).
sortThe sort order. By default, returned records are sorted by primary key value in ascending order.
e.g. ?sort=lastName%20ASC
populatePopulate a related record by association name. Single association only — pass exactly one of the listed values, not a comma-separated list. Populated records are side-loaded at the top level of the response under the related model's plural identity, not nested into each row.
List TimeEntry (find where) › Responses
Responds with a paged list of TimeEntry records that match the specified criteria
Create TimeEntry
Create a new TimeEntry record.
Create TimeEntry › Request Body
The model serves three purposes distinguished by trackingType. The three are independent in reporting: WORK totals are not affected by WORKTIME or BREAK.
Required fields depend on both trackingType and the account-level AccountSetting.timerMode:
- WORK (project time) —
projectandtaskare required. FollowstimerMode: inDURATION, provideduration+sorting(no times); inSTART_TIME_END_TIME, providestartTime+endTimeand omitsorting(omitendTimewhilerunning). - WORKTIME (clock in/out) —
projectandtaskmust be omitted. Always usesstartTime+endTime, regardless oftimerMode. - BREAK —
projectandtaskmust be omitted. FollowstimerModeonly when the account does not use worktime. When worktime is enabled, BREAK always usesstartTime+endTime(like WORKTIME), but may still includesorting.
Net worktime over a period is sum(WORKTIME.duration) − sum(BREAK.duration).
Create TimeEntry › Responses
Responds with a JSON dictionary representing the newly created TimeEntry instance
The model serves three purposes distinguished by trackingType. The three are independent in reporting: WORK totals are not affected by WORKTIME or BREAK.
Required fields depend on both trackingType and the account-level AccountSetting.timerMode:
- WORK (project time) —
projectandtaskare required. FollowstimerMode: inDURATION, provideduration+sorting(no times); inSTART_TIME_END_TIME, providestartTime+endTimeand omitsorting(omitendTimewhilerunning). - WORKTIME (clock in/out) —
projectandtaskmust be omitted. Always usesstartTime+endTime, regardless oftimerMode. - BREAK —
projectandtaskmust be omitted. FollowstimerModeonly when the account does not use worktime. When worktime is enabled, BREAK always usesstartTime+endTime(like WORKTIME), but may still includesorting.
Net worktime over a period is sum(WORKTIME.duration) − sum(BREAK.duration).
Get TimeEntry (find one)
Look up the TimeEntry record with the specified ID.
path Parameters
idThe desired TimeEntry record's primary key value
Get TimeEntry (find one) › Responses
Responds with a single TimeEntry record as a JSON dictionary
The model serves three purposes distinguished by trackingType. The three are independent in reporting: WORK totals are not affected by WORKTIME or BREAK.
Required fields depend on both trackingType and the account-level AccountSetting.timerMode:
- WORK (project time) —
projectandtaskare required. FollowstimerMode: inDURATION, provideduration+sorting(no times); inSTART_TIME_END_TIME, providestartTime+endTimeand omitsorting(omitendTimewhilerunning). - WORKTIME (clock in/out) —
projectandtaskmust be omitted. Always usesstartTime+endTime, regardless oftimerMode. - BREAK —
projectandtaskmust be omitted. FollowstimerModeonly when the account does not use worktime. When worktime is enabled, BREAK always usesstartTime+endTime(like WORKTIME), but may still includesorting.
Net worktime over a period is sum(WORKTIME.duration) − sum(BREAK.duration).
Update TimeEntry
Partially update an existing TimeEntry record. Despite using PUT, this endpoint applies PATCH semantics — only the fields included in the request body are modified; omitted fields are left unchanged.
path Parameters
idThe desired TimeEntry record's primary key value
Update TimeEntry › Request Body
The model serves three purposes distinguished by trackingType. The three are independent in reporting: WORK totals are not affected by WORKTIME or BREAK.
Required fields depend on both trackingType and the account-level AccountSetting.timerMode:
- WORK (project time) —
projectandtaskare required. FollowstimerMode: inDURATION, provideduration+sorting(no times); inSTART_TIME_END_TIME, providestartTime+endTimeand omitsorting(omitendTimewhilerunning). - WORKTIME (clock in/out) —
projectandtaskmust be omitted. Always usesstartTime+endTime, regardless oftimerMode. - BREAK —
projectandtaskmust be omitted. FollowstimerModeonly when the account does not use worktime. When worktime is enabled, BREAK always usesstartTime+endTime(like WORKTIME), but may still includesorting.
Net worktime over a period is sum(WORKTIME.duration) − sum(BREAK.duration).
Update TimeEntry › Responses
Responds with the newly updated TimeEntry record as a JSON dictionary
The model serves three purposes distinguished by trackingType. The three are independent in reporting: WORK totals are not affected by WORKTIME or BREAK.
Required fields depend on both trackingType and the account-level AccountSetting.timerMode:
- WORK (project time) —
projectandtaskare required. FollowstimerMode: inDURATION, provideduration+sorting(no times); inSTART_TIME_END_TIME, providestartTime+endTimeand omitsorting(omitendTimewhilerunning). - WORKTIME (clock in/out) —
projectandtaskmust be omitted. Always usesstartTime+endTime, regardless oftimerMode. - BREAK —
projectandtaskmust be omitted. FollowstimerModeonly when the account does not use worktime. When worktime is enabled, BREAK always usesstartTime+endTime(like WORKTIME), but may still includesorting.
Net worktime over a period is sum(WORKTIME.duration) − sum(BREAK.duration).
Get TimeEntry history log
Returns the history log for a TimeEntry record. Each entry contains oldState and newState objects with only the fields that changed between revisions. Fields may be further omitted based on the requesting user's permissions.
query Parameters
idThe ID of the TimeEntry record to retrieve history for
Get TimeEntry history log › Responses
Successful operation
IDs of recently deleted time entries
Returns the IDs of time entries that have been deleted, so clients can reconcile their local cache against deletions they didn't observe.
query Parameters
fromDateLower bound on the deletion date. Omit for no lower bound.
IDs of recently deleted time entries › Responses
Deleted time entries
User's most recent time entry per project
Returns the latest WORK time entry the caller has on each of their assigned active projects. Useful for tracking-view shortcuts that pre-fill a new entry from the user's last activity on each project.
query Parameters
dateLower bound on the candidate time entries' day (YYYY-MM-DD). Defaults to six months ago.
User's most recent time entry per project › Responses
Latest time entries
Create or update the caller's WORKTIME entry for a day, materializing default breaks on creation
Persists a WORKTIME entry (clock-in / clock-out) for the calling user on day. If a WORKTIME already exists for that day, only the WORKTIME is updated — breaks are not touched. If one doesn't exist and worktime tracking is active for the account, the WORKTIME is created and the user's preset defaultBreaks are materialized at the same time, optionally suppressed (deleteGhost) or modified (updateGhost) by matching against a default break's start/end times. Default-break creation is skipped entirely on future-dated days, absences, weekends, or days the user isn't expected to work. Concurrent calls for the same day will not duplicate the worktime. Scoped to the caller — there is no parameter for acting on another user's worktime.
Create or update the caller's WORKTIME entry for a day, materializing default breaks on creation › Request Body
dayDay the worktime applies to (YYYY-MM-DD).
startTimeHH:mm or HH:mm:ss. On creation, falls back to the user's defaultWorktimeStart when omitted.
endTimeHH:mm or HH:mm:ss. On creation, falls back to the user's defaultWorktimeEnd when omitted.
durationAsHoursWorktime duration in hours. When omitted and both startTime and endTime are provided, the duration is computed as endTime − startTime.
approvalStatusInitial validationStatus for the entry. When APPROVED, approvedBy and approvedOn are stamped on the worktime.
Suppress materialization of a single default break by matching its default startTime and endTime. Ignored on the update path.
Materialize a single default break with modifications. Match by the default break's defaultStartTime / defaultEndTime; override any of the listed fields. Ignored on the update path.
metaDataOptional metadata stored alongside the update.
Create or update the caller's WORKTIME entry for a day, materializing default breaks on creation › Responses
The created or updated WORKTIME entry, plus any default BREAK entries materialized on the creation path.