Skip to main content

Time Tracking

The TimeEntry entity represents time entries in InLoox. Via the OData API you can create, update, delete time entries as well as link them to documents and create them from Microsoft Graph calendar events.

OData endpoint base

All endpoints use the base path /odata/TimeEntry. For the dynamic list view including custom fields, /odata/DynamicTimeEntry is available.

info

Time entries are always associated with a project. Use ProjectId when filtering to retrieve only time entries for a specific project.


Data Model

TimeEntry

PropertyTypeDescription
TimeEntryIdGuid (UUID)Unique identifier of the time entry (primary key).
DisplayNamestring?Display name of the time entry.
StartDateTimeDateTimeOffset?Start date and time.
EndDateTimeDateTimeOffset?End date and time.
ProjectIdGuid?Associated project.
DescriptionHTMLstring?Description as HTML.
DescriptionTextstring?Description as plain text.
PhaseIdGuid?Linked planning phase.
IsBillablebooleanIndicates whether the time entry is billable.
PerformedByContactIdGuidContact ID of the person who performed the work.
ColorFlagint32?Color flag (as integer value).
GroupIdGuidGroup ID of the time entry.
TaskItemIdGuid?Linked task.
IsBilledbooleanIndicates whether the time entry has already been billed.
DurationMinutesint32Duration in minutes.

Endpoints

CRUD Operations

Retrieve all time entries across all projects

GET/odata/TimeEntry

Supports OData query parameters.


Retrieve a single time entry

GET/odata/TimeEntry({key})
ParameterTypeRequiredDescription
keyGuidThe TimeEntryId.

Create a new time entry

POST/odata/TimeEntry
ParameterTypeRequiredDescription
BodyDelta<ApiTimeEntry>JSON object with the time entry properties.
tip

If PerformedByContactId is not specified, the time entry is recorded for the authenticated user.


Partially update a time entry

PATCH/odata/TimeEntry({key})
ParameterTypeRequiredDescription
keyGuidThe TimeEntryId.
BodyDelta<ApiTimeEntry>JSON object with the fields to update.

Delete a time entry

DELETE/odata/TimeEntry({key})
ParameterTypeRequiredDescription
keyGuidThe TimeEntryId.
warning

Deleting a time entry is permanent. If the entry has already been billed, deletion is not possible.


Special Functions

Retrieve the calendar view of time entries for a project

GET/odata/TimeEntry/GetCalendarTimeEntriesForProject(projectId={projectId},take={take})
ParameterTypeRequiredDescription
projectIdGuidThe ProjectId.
takeint32Maximum number of entries to return.

Create a time entry from a Microsoft Graph calendar event

POST/odata/TimeEntry/CreateTimeEntryFromGraphEvent
ParameterTypeRequiredDescription
BodyobjectJSON object with the following fields:

projectId (Guid, required) — The project in which the time entry should be created.
graphEventId (string, required) — The ID of the Microsoft Graph calendar event.
tagEvent (bool?, optional) — If true, the "InLoox" category is added to the calendar event.
taskItemId (Guid?, optional) — Optional task to link with the time entry.
Microsoft Graph Integration

With CreateTimeEntryFromGraphEvent you can convert Outlook calendar appointments directly into time entries. This requires an active Microsoft Graph integration.


Copy a time entry

POST/odata/TimeEntry({key})/Copy
ParameterTypeRequiredDescription
keyGuidThe TimeEntryId of the entry to copy.
BodyobjectJSON object with the following fields:

projectId (Guid?, optional) — Target project for the copied time entry. If not specified, the copy remains in the same project as the original.

Copy a time entry with new dates

POST/odata/TimeEntry({key})/CopyWithNewDates
ParameterTypeRequiredDescription
keyGuidThe TimeEntryId of the entry to copy.
BodyobjectJSON object with the following fields:

projectId (Guid?, optional) — Target project for the copy. If not specified, the copy remains in the same project.
startDate (DateTimeOffset?, required) — New start date/time for the copied entry (stored as UTC).
endDate (DateTimeOffset?, required) — New end date/time for the copied entry (stored as UTC).

Documents

Link a document to the time entry

POST/odata/TimeEntry({key})/AddDocumentToTimeEntry
ParameterTypeRequiredDescription
keyGuidThe TimeEntryId.
BodyobjectJSON object with the following fields:

documentIds (Guid[], required) — Array of document IDs to link with the time entry.

Remove a document from the time entry

POST/odata/TimeEntry({key})/RemoveDocumentFromTimeEntry
ParameterTypeRequiredDescription
keyGuidThe TimeEntryId.
BodyobjectJSON object with the following fields:

documentId (Guid, required) — The ID of the document to remove from the time entry.

Relations

Add a relation to the time entry

POST/odata/TimeEntry({key})/AddRelation
ParameterTypeRequiredDescription
keyGuidThe TimeEntryId.
BodyobjectJSON object with the following fields:

itemId (Guid, required) — The ID of the item to link.

Remove a relation from the time entry

POST/odata/TimeEntry({key})/RemoveRelation
ParameterTypeRequiredDescription
keyGuidThe TimeEntryId.
BodyobjectJSON object with the following fields:

itemId (Guid, required) — The ID of the item whose relation should be removed.

Comments

Retrieve all time entry comments

GET/odata/TimeEntryComment

Retrieve a single comment

GET/odata/TimeEntryComment({key})
ParameterTypeRequiredDescription
keyGuidThe TimeEntryCommentId.

Add a comment to the time entry

POST/odata/TimeEntry({key})/AddNote
ParameterTypeRequiredDescription
keyGuidThe TimeEntryId.
BodyobjectJSON object with the following fields:

htmlText (string, required) — HTML-formatted comment text.
notificationContactIds (Guid[], required) — Contact IDs to be notified (can be an empty array []).

Delete a comment from the time entry

GET/odata/TimeEntry/DeleteNote(noteRelationId={noteRelationId})
ParameterTypeRequiredDescription
noteRelationIdGuidThe ID of the comment relation.
warning

Deleting a comment cannot be undone.


DynamicTimeEntry

The /odata/DynamicTimeEntry endpoint provides a read-only, flattened view that combines data from the time entry, project, planning, task, and permissions. All properties are prefixed (e.g., TimeEntry_DisplayName, Project_Name, TaskItem_Name). Custom fields follow the pattern CF_<FieldName>.

Retrieve the flattened time entry view with project, planning, and task data

GET/odata/DynamicTimeEntry
Read-only access

DynamicTimeEntry supports GET requests only. To create or edit, use the regular /odata/TimeEntry endpoints.


OData Query Examples

Retrieve time entries for a project

GET /odata/TimeEntry?$filter=ProjectId eq 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

Billable but not yet billed entries

GET /odata/TimeEntry?$filter=IsBillable eq true and IsBilled eq false

Time entries for a specific date range

GET /odata/TimeEntry?$filter=StartDateTime ge 2025-01-01T00:00:00Z and EndDateTime le 2025-01-31T23:59:59Z

Create a time entry

POST /odata/TimeEntry
Content-Type: application/json

{
"DisplayName": "API module development",
"ProjectId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"StartDateTime": "2025-01-15T09:00:00Z",
"EndDateTime": "2025-01-15T12:30:00Z",
"IsBillable": true,
"PerformedByContactId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
Calculate duration

The DurationMinutes field is calculated server-side from StartDateTime and EndDateTime. You can also set it manually if you do not specify a start/end time.

Time entries by contact

GET /odata/TimeEntry?$filter=PerformedByContactId eq 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'&$top=50&$skip=0&$orderby=StartDateTime desc

C# example

using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);

// Query time entries for April 2025
var response = await client.GetAsync(
"https://{tenant}.inloox.app/odata/TimeEntry?" +
$"$filter=ProjectId eq {projectId}" +
" and StartDateTime ge 2025-04-01T00:00:00Z" +
" and EndDateTime le 2025-04-30T23:59:59Z" +
"&$select=TimeEntryId,StartDateTime,EndDateTime,DurationMinutes,IsBillable" +
"&$orderby=StartDateTime asc");

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);

// Create a time entry
var payload = new StringContent(
"""
{
"ProjectId": "{project-guid}",
"StartDateTime": "2025-04-15T09:00:00Z",
"EndDateTime": "2025-04-15T12:00:00Z",
"DescriptionHTML": "API integration work",
"IsBillable": true
}
""",
System.Text.Encoding.UTF8,
"application/json");

var createResponse = await client.PostAsync(
"https://{tenant}.inloox.app/odata/TimeEntry", payload);
tip

Always filter time entries by date range (StartDateTime and EndDateTime) for reports to avoid loading the entire history. Combine this with $select to reduce the response size.