Time Tracking
Time tracking entries record hours worked on projects and tasks. They support both manual time entry and active timer functionality, with automatic value calculation based on hourly rates.
The Time Track Object
Attributes
| Attribute | Type | Description |
|---|---|---|
id | integer | Unique identifier for the time entry |
company_id | integer | ID of the company this time entry belongs to |
user_id | integer | ID of the user who created the time entry |
project_id | integer | ID of the project this time is tracked for |
invoice_id | integer|null | ID of the invoice this time entry is linked to |
task_id | integer|null | ID of the task this time is tracked for |
description | string | Description of work performed |
date | string | Date of work in Y-m-d format |
start | string|null | Start time in H:i format (e.g., "09:30") |
end | string|null | End time in H:i format (e.g., "17:45") |
hours | integer | Hours worked (0-23) |
minutes | integer | Minutes worked (0-59) |
hourly_rate | number | Hourly rate for this entry |
status | string | Entry status: open, invoiced, or paid |
billable | boolean | Whether this time is billable to the customer |
total_value | number | Calculated total value (hours × hourly_rate) |
readable_time | string | Human-readable time format (e.g., "08:30") |
project | object|null | Project object (when included) |
task | object|null | Task object (when included) |
user | object|null | User object (when included) |
created_at | string | ISO 8601 timestamp of creation |
updated_at | string | ISO 8601 timestamp of last update |
Create a Time Entry
Creates a new time tracking entry.
POST /api/companies/{company_id}/timesRequest Body
| Parameter | Type | Required | Description |
|---|---|---|---|
project_id | integer | Yes | ID of the project |
hours | integer | Yes | Hours worked (0-23) |
minutes | integer | Yes | Minutes worked (0-59) |
date | string | Yes | Date of work (any valid date format) |
description | string | No | Description of work performed |
hourly_rate | number | No | Hourly rate (defaults to project's hourly rate, min: 0) |
billable | boolean | No | Whether time is billable (default: false) |
task_id | integer | No | ID of the task |
start | string | No | Start time in H:i format (e.g., "09:30") |
end | string | No | End time in H:i format (must be after start) |
Response
Returns the created time entry object.
{
"data": {
"id": 142,
"company_id": 1,
"user_id": 1,
"project_id": 5,
"invoice_id": null,
"task_id": 12,
"description": "Implemented authentication feature",
"date": "2024-01-26",
"start": "09:00",
"end": "17:30",
"hours": 8,
"minutes": 30,
"hourly_rate": 120.00,
"status": "open",
"billable": true,
"total_value": 1020.00,
"readable_time": "08:30",
"project": null,
"task": null,
"user": null,
"created_at": "2024-01-26T10:00:00.000000Z",
"updated_at": "2024-01-26T10:00:00.000000Z"
}
}List Time Entries
Returns a list of time tracking entries with extensive filtering and grouping options.
GET /api/companies/{company_id}/timesQuery Parameters
| Parameter | Type | Description |
|---|---|---|
filter[user_id] | integer | Filter by user ID |
filter[id] | integer | Filter by specific time entry ID |
filter[customer_id] | integer|array | Filter by customer ID(s) |
filter[project_id] | integer | Filter by project ID |
filter[billable] | boolean | Filter by billable status |
filter[project_type] | string | Filter by project type: byHour, fixedBudget, or fixedPrice |
filter[invoice_id] | integer | Filter by invoice ID |
filter[with_current_invoice_id] | integer | Include entries with this invoice ID (OR condition) |
filter[status] | string | Filter by status: open, invoiced, or paid |
filter[date] | string | Filter by date range (format: start_date,end_date) |
sort | string | Sort by field: date, start, -date, -start (prefix with - for descending) |
include | string | Include related resources (available: project, project.customer, task, user) |
group_by | string | Group results by: date or project |
group_by_weeks | boolean | Group results by calendar weeks |
group_by_week_project_days | boolean | Group by project and weekdays (for timesheets) |
Response
{
"data": [
{
"id": 142,
"company_id": 1,
"user_id": 1,
"project_id": 5,
"invoice_id": null,
"task_id": 12,
"description": "Implemented authentication feature",
"date": "2024-01-26",
"start": "09:00",
"end": "17:30",
"hours": 8,
"minutes": 30,
"hourly_rate": 120.00,
"status": "open",
"billable": true,
"total_value": 1020.00,
"readable_time": "08:30",
"formatted_date": "26.01.2024",
"sortable_time": 510,
"formatted_total_value": "1'020.00",
"project": {
"id": 5,
"name": "Website Redesign",
"customer": {
"id": 3,
"name": "Acme Corp"
}
},
"task": null,
"user": {
"id": 1,
"name": "Max Muster"
}
}
],
"current_count": 1,
"total_count": 245
}Retrieve a Time Entry
Retrieves the details of a specific time entry.
GET /api/companies/{company_id}/times/{time_id}Query Parameters
| Parameter | Type | Description |
|---|---|---|
include | string | Include related resources (available: project, project.customer, task, user) |
Response
Returns a time entry object.
{
"data": {
"id": 142,
"company_id": 1,
"user_id": 1,
"project_id": 5,
"invoice_id": null,
"task_id": 12,
"description": "Implemented authentication feature",
"date": "2024-01-26",
"start": "09:00",
"end": "17:30",
"hours": 8,
"minutes": 30,
"hourly_rate": 120.00,
"status": "open",
"billable": true,
"total_value": 1020.00,
"readable_time": "08:30",
"project": null,
"task": null,
"user": null,
"created_at": "2024-01-26T10:00:00.000000Z",
"updated_at": "2024-01-26T10:00:00.000000Z"
}
}Update a Time Entry
Updates an existing time entry. Note that invoiced and paid entries have restrictions.
PUT /api/companies/{company_id}/times/{time_id}Request Body
All parameters are optional. Only include the fields you want to update.
| Parameter | Type | Description |
|---|---|---|
project_id | integer | ID of the project |
invoice_id | integer | ID of the invoice |
description | string | Description of work performed |
date | string | Date of work (any valid date format) |
hours | integer | Hours worked (0-23) |
minutes | integer | Minutes worked (0-59) |
hourly_rate | number | Hourly rate |
billable | boolean | Whether time is billable |
status | string | Entry status: open, invoiced, or paid |
task_id | integer | ID of the task |
start | string | Start time in H:i format |
end | string | End time in H:i format |
force | boolean | Force update of invoiced entries (default: false) |
Edit Restrictions
- Paid entries: Only the
statusfield can be updated - Invoiced entries: Only the
statusfield can be updated unlessforce=trueis provided - Open entries: All fields can be updated
- Users can only edit their own entries unless they have admin or owner role
Response
Returns the updated time entry object.
{
"data": {
"id": 142,
"company_id": 1,
"user_id": 1,
"project_id": 5,
"invoice_id": 25,
"task_id": 12,
"description": "Implemented authentication feature with OAuth2",
"date": "2024-01-26",
"start": "09:00",
"end": "17:30",
"hours": 8,
"minutes": 30,
"hourly_rate": 120.00,
"status": "invoiced",
"billable": true,
"total_value": 1020.00,
"readable_time": "08:30",
"project": null,
"task": null,
"user": null,
"created_at": "2024-01-26T10:00:00.000000Z",
"updated_at": "2024-01-26T15:30:00.000000Z"
}
}Delete a Time Entry
Deletes a time entry permanently. Invoiced and paid entries cannot be deleted.
DELETE /api/companies/{company_id}/times/{time_id}Response
Returns HTTP 204 No Content on success.
Returns HTTP 403 Forbidden if the entry is invoiced or paid.
Timer Management
The timer allows users to track time actively with start/stop functionality. Only one timer can be active per user.
Start/Stop Timer
Toggles the timer on or off.
POST /api/companies/{company_id}/times/timerRequest Body (Start Timer)
| Parameter | Type | Required | Description |
|---|---|---|---|
project_id | integer | Yes | ID of the project to track time for |
billable | boolean | No | Whether the time is billable (default: false) |
Request Body (Stop Timer)
| Parameter | Type | Required | Description |
|---|---|---|---|
end | string | No | End time in H:i format |
description | string | No | Description of work performed |
Response
Returns a success message.
"Timer wurde gestartet."or
"Zeiteintrag wurde gespeichert."Get Timer Status
Retrieves the current timer status for the authenticated user.
GET /api/companies/{company_id}/times/timerResponse
{
"active": true,
"timer": {
"id": 5,
"user_id": 1,
"company_id": 1,
"project_id": 12,
"billable": true,
"description": "",
"started_at": "2024-01-26T09:00:00.000000Z"
}
}or if no timer is active:
{
"active": false,
"timer": []
}Update Timer Description
Updates the description of the active timer.
PUT /api/companies/{company_id}/times/timer/descriptionRequest Body
| Parameter | Type | Required | Description |
|---|---|---|---|
description | string | No | Description of work being performed |
Response
{
"active": true,
"timer": {
"id": 5,
"user_id": 1,
"company_id": 1,
"project_id": 12,
"billable": true,
"description": "Working on authentication",
"started_at": "2024-01-26T09:00:00.000000Z"
}
}Delete Active Timer
Deletes the active timer without saving it as a time entry.
DELETE /api/companies/{company_id}/times/timerResponse
Returns HTTP 204 No Content on success.
Bulk Operations
Bulk Update Time Entries
Updates multiple time entries at once. Only open entries can be bulk updated.
PUT /api/companies/{company_id}/times/multipleRequest Body
| Parameter | Type | Required | Description |
|---|---|---|---|
ids | array|integer | Yes | Array of time entry IDs or single ID |
project_id | integer | No | Update project for all entries |
date | string | No | Update date for all entries |
description | string | No | Update description for all entries |
hourly_rate | number | No | Update hourly rate for all entries |
billable | boolean | No | Update billable status for all entries |
Restrictions
- Only admin and owner roles can update other users' entries
- Regular users can only bulk update their own entries
- Only entries with status
openwill be updated
Response
Returns HTTP 200 OK on success.
Bulk Delete Time Entries
Deletes multiple time entries at once.
DELETE /api/companies/{company_id}/times/multipleRequest Body
| Parameter | Type | Required | Description |
|---|---|---|---|
ids | array | Yes | Array of time entry IDs to delete |
Restrictions
- Only admin and owner roles can delete other users' entries
- Regular users can only bulk delete their own entries
- Invoiced and paid entries cannot be deleted
Response
Returns HTTP 200 OK on success.
CSV Import
Imports time entries from a CSV file.
POST /api/companies/{company_id}/times/importRequest Body
Multipart form data with a CSV file.
| Parameter | Type | Required | Description |
|---|---|---|---|
file | file | Yes | CSV file containing time entries |
Response
Returns HTTP 200 OK on success.
Time Entry Statuses
Time entries progress through three statuses:
open- Entry is editable and not yet invoicedinvoiced- Entry is linked to an invoice and has restricted editingpaid- Entry's invoice has been paid and cannot be edited (except status field)
Automatic Calculations
Time Calculation
When both start and end times are provided, the system automatically calculates hours and minutes. If minutes exceed 59, they are automatically converted to hours.
Value Calculation
The total_value is automatically calculated as:
total_value = (hours + minutes/60) × hourly_rateIf no hourly_rate is provided, the project's hourly rate is used.
Grouping Options
Group by Date
Returns time entries grouped by date with totals.
GET /api/companies/1/times?group_by=dateGroup by Project
Returns time entries grouped by project with totals and average hourly rates.
GET /api/companies/1/times?group_by=projectGroup by Weeks
Returns time entries grouped by calendar weeks with daily breakdowns.
GET /api/companies/1/times?group_by_weeks=trueGroup by Week/Project/Days
Returns time entries in a timesheet format, grouped by project and weekdays, showing locked (invoiced) vs editable time.
GET /api/companies/1/times?group_by_week_project_days=trueBest Practices
Timer Workflow
Use the timer feature for accurate time tracking. Start the timer when beginning work and stop it when finished. The system automatically converts the timer to a time entry with accurate start and end times.
Hourly Rate Management
The hourly rate defaults to the project's rate but can be overridden per entry. This is useful for special circumstances or when different team members have different rates.
Billable vs Non-Billable
Clearly mark entries as billable or non-billable. Non-billable time (internal meetings, training, etc.) is excluded from client invoicing but still tracked for project profitability analysis.
Status Transitions
Time entries move through a one-way workflow: open → invoiced → paid. Once an entry reaches a later status, editing becomes restricted to prevent accounting inconsistencies. Use the force parameter judiciously when updates to invoiced entries are absolutely necessary.
Date Range Filtering
When querying time entries for specific periods, use the date range filter for optimal performance. Format the date range as comma-separated start and end dates.
