Replace a time registration
Replaces all fields of an existing time registration, identified by its GUID.
Full replace, not a partial update: send every field, including those you do not want to change. Omitted fields are reset (Comment and AdditionalComment cleared, Billable false, BillableHours 0). Exceptions: MonthlyPeriod keeps its value when omitted; Factor not in the allowed list keeps its value.
Not for:
- Changing hours/comment by integer ID →
POST /v1/time-registration/update-time(reads current values first; omitted Comment/Billable are still replaced)
Rules across fields:
- R1: Same as create (GroupType → TaskID/Hours/EntityID)
Behaviour:
- Idempotent.
- Safe to retry.
- Side effect: Overwrites Created and CreatedBy with the update's time and user.
- Side effect: A rejected registration moves to …RejectedAndResolved.
- Read-after-write consistency: not yet documented.
Call first: GET /v1/time-registration/{timeRegistrationID}
Next: GET /v1/time-registration/{timeRegistrationID}
Not yet documented: examples.
curl -X PUT "https://app3.timelog.com/your-account/api/v1/time-registration" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d '{
"ID": "123e4567-e89b-12d3-a456-426614174000",
"TaskID": 123,
"UserID": 123,
"Date": "2024-12-25T10:00:00Z",
"Hours": 3.14,
"Minutes": 42,
"GroupType": 42,
"TimeTrackingFormat": 42,
"EntityID": 123,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"Comment": "null",
"AdditionalComment": "example_string",
"MonthlyPeriod": "example_string",
"StartTime": "2024-12-25T10:00:00Z",
"IsCalendarEvent": true
}'
import requests
import json
url = "https://app3.timelog.com/your-account/api/v1/time-registration"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
data = {
"ID": "123e4567-e89b-12d3-a456-426614174000",
"TaskID": 123,
"UserID": 123,
"Date": "2024-12-25T10:00:00Z",
"Hours": 3.14,
"Minutes": 42,
"GroupType": 42,
"TimeTrackingFormat": 42,
"EntityID": 123,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"Comment": "null",
"AdditionalComment": "example_string",
"MonthlyPeriod": "example_string",
"StartTime": "2024-12-25T10:00:00Z",
"IsCalendarEvent": true
}
response = requests.put(url, headers=headers, json=data)
print(response.json())
const response = await fetch("https://app3.timelog.com/your-account/api/v1/time-registration", {
method: "PUT",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
},
body: JSON.stringify({
"ID": "123e4567-e89b-12d3-a456-426614174000",
"TaskID": 123,
"UserID": 123,
"Date": "2024-12-25T10:00:00Z",
"Hours": 3.14,
"Minutes": 42,
"GroupType": 42,
"TimeTrackingFormat": 42,
"EntityID": 123,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"Comment": "null",
"AdditionalComment": "example_string",
"MonthlyPeriod": "example_string",
"StartTime": "2024-12-25T10:00:00Z",
"IsCalendarEvent": true
})
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"net/http"
"bytes"
"encoding/json"
)
func main() {
data := []byte(`{
"ID": "123e4567-e89b-12d3-a456-426614174000",
"TaskID": 123,
"UserID": 123,
"Date": "2024-12-25T10:00:00Z",
"Hours": 3.14,
"Minutes": 42,
"GroupType": 42,
"TimeTrackingFormat": 42,
"EntityID": 123,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"Comment": "null",
"AdditionalComment": "example_string",
"MonthlyPeriod": "example_string",
"StartTime": "2024-12-25T10:00:00Z",
"IsCalendarEvent": true
}`)
req, err := http.NewRequest("PUT", "https://app3.timelog.com/your-account/api/v1/time-registration", bytes.NewBuffer(data))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("Response Status:", resp.Status)
}
require 'net/http'
require 'json'
uri = URI('https://app3.timelog.com/your-account/api/v1/time-registration')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request.body = '{
"ID": "123e4567-e89b-12d3-a456-426614174000",
"TaskID": 123,
"UserID": 123,
"Date": "2024-12-25T10:00:00Z",
"Hours": 3.14,
"Minutes": 42,
"GroupType": 42,
"TimeTrackingFormat": 42,
"EntityID": 123,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"Comment": "null",
"AdditionalComment": "example_string",
"MonthlyPeriod": "example_string",
"StartTime": "2024-12-25T10:00:00Z",
"IsCalendarEvent": true
}'
response = http.request(request)
puts response.body
"null"
{
"error": "Bad Request",
"message": "The request contains invalid parameters or malformed data",
"code": 400,
"details": [
{
"field": "email",
"message": "Invalid email format"
}
]
}
{
"error": "Unauthorized",
"message": "Authentication required. Please provide a valid API token",
"code": 401
}
{
"error": "Unprocessable Entity",
"message": "The request was well-formed but contains semantic errors",
"code": 422,
"details": [
{
"field": "password",
"message": "Password must be at least 8 characters long"
}
]
}
{
"error": "Internal Server Error",
"message": "An unexpected error occurred on the server",
"code": 500,
"requestId": "req_1234567890"
}
/v1/time-registration
Target server for requests. Edit to use your own host.
OAuth 2.0 bearer token, sent as Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp).
The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user.
> Not yet documented: how to obtain a token.
> Not yet documented: token lifetime.
Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp).
The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user.
> Not yet documented: how to obtain a token.
> Not yet documented: token lifetime.The media type of the request body
Client-generated GUID that identifies the registration. On create you choose it; on update it selects the registration to replace. It is NOT the integer TimeRegistrationID. Can be set on create only. Identifier of this object, unique per TimeLog site. Selects the registration to replace (TimeRegistrationGUID, not TimeRegistrationID). Re-using an existing GUID on create fails with 38030 (422). Create is not idempotent.
The task the time is registered on.
Conditional. Required (non-zero) when GroupType is Project (1) or TravelTime (6). Not used for Absence.
Refers to TaskRead.TaskID.
If the employee is not yet allocated to the task, TimeLog CREATES the allocation (adds the employee to the project resource group, the contract team and a 0-hour allocation) — before the registration is validated. See operation behaviour.
The user (employee) the time belongs to.
Refers to UserRead.UserID.
Overwritten — changing it moves the registration to another user. On update this is overwritten — an update can move a registration to another user.
The date the time is registered on. Time zone: not yet documented. Stored as sent; no truncation of a time component found. Send midnight (YYYY-MM-DDT00:00:00). > Not yet documented: constraints → timezone.
Duration in decimal hours (e.g. 1.5 = 1 h 30 min). Conditional. Required and non-zero when GroupType is Project, or TimeTrackingFormat is Hours. Unit: hours (decimal) - GroupType = Absence and TimeTrackingFormat = FullDay or HalfDay — Hours are taken from the employee's normal working time. No server-side rejection of negative values was found (only != 0 is checked).
Duration in minutes. Conditional. Update validator requires Minutes when Hours is absent (but see behaviour). - GroupType = Project or TravelTime — Hours always wins — the API passes Hours (or 0) to the engine, so Minutes is never applied. Send Hours. - GroupType = Absence and TimeTrackingFormat = Hours — Minutes is applied after Hours and wins.
What kind of registration this is.
Allowed values:
| Value | Name | Meaning |
|---|---|---|
| 1 | Project | Time worked on a project task. |
| 3 | Absence | Absence (vacation, sickness …). EntityID = absence code. |
| 6 | TravelTime | Travel time on a project task. |
How the duration is expressed.
Allowed values:
| Value | Name | Meaning |
|---|---|---|
| 0 | Hours | Duration in hours/minutes. |
| 1 | FullDay | Absence for a full day (hours from normal working time). |
| 2 | HalfDay | Absence for half a day (hours from normal working time). |
| 3 | YesNo | Salary-code (supplement) format: a registration posts a count of 1. |
| 4 | Count | Salary-code (supplement) format: a registration posts the entered number as a count. |
For absence, the absence code to register.
Conditional. Required when GroupType = Absence. Ignored otherwise.
Refers to AbsenceCodeRead.AbsenceCodeID.
- GroupType = Project or TravelTime — Replaced by the allocation resolved from TaskID + UserID.
Whether the time is billable to the customer. - Feature BillableOnTime is OFF — Forced to the task's billable flag. - Task is fixed-price and Billable = false — Fails with 37620.
Billable duration in decimal hours. Unit: hours (decimal) - Feature BillableHoursIsEditable is OFF — Set to the actual Hours. - Feature BillableHoursIsEditable is ON and the field is omitted — 0 billable hours is stored. - Fixed-price task and BillableHoursIsEditableOnFixedPrice is OFF — Synced to actual hours. - RoundingOfBillableTime is ON — Mismatch raises 30168.
Billable duration in minutes. - always — BillableHours is always passed (0 when omitted), so BillableMinutes is never applied.
Registration factor (100 = normal). Used for overtime factors. Default: 0 on the wire → stored as 100 - Feature OvertimeFactor is OFF, or the task is fixed-price — Always 100. - OvertimeFactor ON and value is in the setting RoundingFactorOptionOfTimeRegistrations (default "100") — applied - OvertimeFactor ON, create, value not in the list — Stored as 100. - OvertimeFactor ON, update, value not in the list — Previous value kept. > Not yet documented: description.
Free-text comment on the registration. Null: On update, omitting Comment clears the stored comment. - Feature MandatoryComment is ON and comment is empty — Fails with 300116.
Second free-text field, configurable per site (title and validation are site settings). Conditional. Required when the site configures the additional field as mandatory (30048).
Salary month the registration belongs to. - Feature TempTreatAllTimeRegistrationAsRecurringTask is OFF — ignored - Value outside ±MonthlyPeriodDropdownRange months of today, or malformed — Returns 500 (Code 100), not 400.
Start time of the work. Time zone: not yet documented. - The user does not have timestamps enabled, or the registration is an absence — StartTime/EndTime are cleared. - Timestamps enabled, StartTime sent — Seconds dropped; no timezone conversion; EndTime = StartTime + Hours. - Timestamps enabled, create, no StartTime — EndTime = the user's current time on that date; StartTime = EndTime − Hours. If that would put StartTime on the previous day, StartTime = midnight of Date and EndTime = StartTime + Hours (may run past midnight). - Timestamps enabled, update, no StartTime, stored registration has a StartTime — The stored StartTime is kept; EndTime = StartTime + Hours. - Timestamps enabled, update, no StartTime, stored registration has no StartTime — The registration stays without timestamps (EndTime cleared).
Marks the registration as originating from a calendar meeting. - create — Sets IsMeeting on the registration. No other effect via this API (CalendarEventID is always 0). - update — ignored Ignored on update.
Request Preview
Response
Response will appear here after sending the request
Authentication
Bearer token. OAuth 2.0 bearer token, sent as Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp).
The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user.
Not yet documented: how to obtain a token.
Not yet documented: token lifetime.
Body
Client-generated GUID that identifies the registration. On create you choose it; on update it selects the registration to replace. It is NOT the integer TimeRegistrationID.
Can be set on create only.
Identifier of this object, unique per TimeLog site.
Selects the registration to replace (TimeRegistrationGUID, not TimeRegistrationID). Re-using an existing GUID on create fails with 38030 (422). Create is not idempotent.
The task the time is registered on.
Conditional. Required (non-zero) when GroupType is Project (1) or TravelTime (6). Not used for Absence.
Refers to TaskRead.TaskID.
If the employee is not yet allocated to the task, TimeLog CREATES the allocation (adds the employee to the project resource group, the contract team and a 0-hour allocation) — before the registration is validated. See operation behaviour.
The user (employee) the time belongs to.
Refers to UserRead.UserID.
Overwritten — changing it moves the registration to another user. On update this is overwritten — an update can move a registration to another user.
The date the time is registered on.
Time zone: not yet documented.
Stored as sent; no truncation of a time component found. Send midnight (YYYY-MM-DDT00:00:00).
Not yet documented: constraints → timezone.
Duration in decimal hours (e.g. 1.5 = 1 h 30 min).
Conditional. Required and non-zero when GroupType is Project, or TimeTrackingFormat is Hours.
Unit: hours (decimal)
- GroupType = Absence and TimeTrackingFormat = FullDay or HalfDay — Hours are taken from the employee's normal working time.
No server-side rejection of negative values was found (only != 0 is checked).
Duration in minutes.
Conditional. Update validator requires Minutes when Hours is absent (but see behaviour).
-
GroupType = Project or TravelTime — Hours always wins — the API passes Hours (or 0) to the engine, so Minutes is never applied. Send Hours.
-
GroupType = Absence and TimeTrackingFormat = Hours — Minutes is applied after Hours and wins.
What kind of registration this is.
Allowed values:
| Value | Name | Meaning |
|---|---|---|
1 | Project | Time worked on a project task. |
3 | Absence | Absence (vacation, sickness …). EntityID = absence code. |
6 | TravelTime | Travel time on a project task. |
136How the duration is expressed.
Allowed values:
| Value | Name | Meaning |
|---|---|---|
0 | Hours | Duration in hours/minutes. |
1 | FullDay | Absence for a full day (hours from normal working time). |
2 | HalfDay | Absence for half a day (hours from normal working time). |
3 | YesNo | Salary-code (supplement) format: a registration posts a count of 1. |
4 | Count | Salary-code (supplement) format: a registration posts the entered number as a count. |
01234For absence, the absence code to register.
Conditional. Required when GroupType = Absence. Ignored otherwise.
Refers to AbsenceCodeRead.AbsenceCodeID.
- GroupType = Project or TravelTime — Replaced by the allocation resolved from TaskID + UserID.
Whether the time is billable to the customer.
-
Feature BillableOnTime is OFF — Forced to the task's billable flag.
-
Task is fixed-price and Billable = false — Fails with 37620.
Billable duration in decimal hours.
Unit: hours (decimal)
-
Feature BillableHoursIsEditable is OFF — Set to the actual Hours.
-
Feature BillableHoursIsEditable is ON and the field is omitted — 0 billable hours is stored.
-
Fixed-price task and BillableHoursIsEditableOnFixedPrice is OFF — Synced to actual hours.
-
RoundingOfBillableTime is ON — Mismatch raises 30168.
Billable duration in minutes.
- always — BillableHours is always passed (0 when omitted), so BillableMinutes is never applied.
Registration factor (100 = normal). Used for overtime factors.
Default: 0 on the wire → stored as 100
-
Feature OvertimeFactor is OFF, or the task is fixed-price — Always 100.
-
OvertimeFactor ON and value is in the setting RoundingFactorOptionOfTimeRegistrations (default "100") — applied
-
OvertimeFactor ON, create, value not in the list — Stored as 100.
-
OvertimeFactor ON, update, value not in the list — Previous value kept.
Not yet documented: description.
Free-text comment on the registration.
Null: On update, omitting Comment clears the stored comment.
- Feature MandatoryComment is ON and comment is empty — Fails with 300116.
Second free-text field, configurable per site (title and validation are site settings).
Conditional. Required when the site configures the additional field as mandatory (30048).
Salary month the registration belongs to.
-
Feature TempTreatAllTimeRegistrationAsRecurringTask is OFF — ignored
-
Value outside ±MonthlyPeriodDropdownRange months of today, or malformed — Returns 500 (Code 100), not 400.
Start time of the work.
Time zone: not yet documented.
-
The user does not have timestamps enabled, or the registration is an absence — StartTime/EndTime are cleared.
-
Timestamps enabled, StartTime sent — Seconds dropped; no timezone conversion; EndTime = StartTime + Hours.
-
Timestamps enabled, create, no StartTime — EndTime = the user's current time on that date; StartTime = EndTime − Hours. If that would put StartTime on the previous day, StartTime = midnight of Date and EndTime = StartTime + Hours (may run past midnight).
-
Timestamps enabled, update, no StartTime, stored registration has a StartTime — The stored StartTime is kept; EndTime = StartTime + Hours.
-
Timestamps enabled, update, no StartTime, stored registration has no StartTime — The registration stays without timestamps (EndTime cleared).
Marks the registration as originating from a calendar meeting.
-
create — Sets IsMeeting on the registration. No other effect via this API (CalendarEventID is always 0).
-
update — ignored
Ignored on update.
Responses
Success without content: HTTP 200 with the literal JSON body null. Body is the literal JSON null. Call GET to read the result.