Update the time of a registration
Changes hours, billing, comment, date or task of a project or travel registration by its integer ID.
The timesheet's "update registration" action for project time. Addressed by the integer TimeRegistrationID; the employee is kept. It is a mixed update: TaskID, Date and MonthlyPeriod keep their values when omitted, but Comment, AdditionalComment, Billable and BillableHours are REPLACED (cleared / false / 0) when omitted. Send every field you want to keep.
Use it to:
- Correct the hours of a registration you only know by its integer ID
Not for:
- Absence registrations → update-hours-absence / update-half-or-full-day-absence
- Changing the employee →
PUT /v1/time-registration(PUT, full replace)
Rules across fields:
- R1: StartTime and EndTime both sent → StartTime < EndTime and (EndTime − StartTime) in minutes = round(Hours × 60).
Behaviour:
- Idempotent.
- Safe to retry.
- Side effect: Same as PUT update: overwrites Created/CreatedBy; a rejected registration becomes …RejectedAndResolved; TimeRegistrationUpdated event.
- Side effect: Changing TaskID can create an allocation (staffing side effect, as create).
- Read-after-write consistency: not yet documented.
Call first: GET /v1/time-registration/{timeRegistrationID}
Next: GET /v1/time-registration/{timeRegistrationID}
See also: PUT /v1/time-registration
Not yet documented: behaviour → consistency; examples (success).
curl -X POST "https://app3.timelog.com/your-account/api/v1/time-registration/update-time" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d '{
"TimeRegistrationID": 123,
"Hours": 3.14,
"Minutes": 42,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"MonthlyPeriod": "example_string",
"TaskID": 123,
"StartTime": "2024-12-25T10:00:00Z",
"EndTime": "2024-12-25T10:00:00Z",
"Date": "2024-12-25T10:00:00Z",
"Comment": "example_string",
"AdditionalComment": "example_string"
}'
import requests
import json
url = "https://app3.timelog.com/your-account/api/v1/time-registration/update-time"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
data = {
"TimeRegistrationID": 123,
"Hours": 3.14,
"Minutes": 42,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"MonthlyPeriod": "example_string",
"TaskID": 123,
"StartTime": "2024-12-25T10:00:00Z",
"EndTime": "2024-12-25T10:00:00Z",
"Date": "2024-12-25T10:00:00Z",
"Comment": "example_string",
"AdditionalComment": "example_string"
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
const response = await fetch("https://app3.timelog.com/your-account/api/v1/time-registration/update-time", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
},
body: JSON.stringify({
"TimeRegistrationID": 123,
"Hours": 3.14,
"Minutes": 42,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"MonthlyPeriod": "example_string",
"TaskID": 123,
"StartTime": "2024-12-25T10:00:00Z",
"EndTime": "2024-12-25T10:00:00Z",
"Date": "2024-12-25T10:00:00Z",
"Comment": "example_string",
"AdditionalComment": "example_string"
})
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"net/http"
"bytes"
"encoding/json"
)
func main() {
data := []byte(`{
"TimeRegistrationID": 123,
"Hours": 3.14,
"Minutes": 42,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"MonthlyPeriod": "example_string",
"TaskID": 123,
"StartTime": "2024-12-25T10:00:00Z",
"EndTime": "2024-12-25T10:00:00Z",
"Date": "2024-12-25T10:00:00Z",
"Comment": "example_string",
"AdditionalComment": "example_string"
}`)
req, err := http.NewRequest("POST", "https://app3.timelog.com/your-account/api/v1/time-registration/update-time", 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/update-time')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request.body = '{
"TimeRegistrationID": 123,
"Hours": 3.14,
"Minutes": 42,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"MonthlyPeriod": "example_string",
"TaskID": 123,
"StartTime": "2024-12-25T10:00:00Z",
"EndTime": "2024-12-25T10:00:00Z",
"Date": "2024-12-25T10:00:00Z",
"Comment": "example_string",
"AdditionalComment": "example_string"
}'
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": "Forbidden",
"message": "You don't have permission to access this resource",
"code": 403
}
{
"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/update-time
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
Integer ID of the registration to change. Identifier of this object, unique per TimeLog site.
New duration in decimal hours. Unit: hours (decimal) Must be non-zero. When StartTime and EndTime are both sent, Hours × 60 must equal their difference in whole minutes.
Duration in minutes. Unit: minutes - always — Hours is always present, and Hours wins for project time — Minutes is never applied.
Whether the time is billable.
Billable duration in decimal hours. Unit: hours (decimal)
Billable duration in minutes. Unit: minutes - always — BillableHours is always passed (0 when omitted), so BillableMinutes is never applied.
Registration factor (100 = normal). Same OvertimeFactor rules as TimeRegistrationWrite.Factor (update context: a value not in the allowed list keeps the previous value).
Salary month (MMyyyy). > Not yet documented: null semantics.
Moves the registration to another task.
Refers to TaskRead.TaskID.
- TaskID differs from the current task and the employee is not allocated to it — The allocation is created (same staffing side effect as create).
> Not yet documented: values → lookup op.
Start time of the work. Time zone: none applied — sent value stored as-is Applied only when the employee has timestamps enabled (see TimeRegistrationWrite.StartTime).
End time of the work — used ONLY to validate Hours. Time zone: none applied - StartTime and EndTime both sent — 400 if EndTime ≤ StartTime, or if (EndTime − StartTime) in minutes ≠ round(Hours × 60). - always — Not stored; the server sets EndTime = StartTime + Hours.
Moves the registration to another date. Time zone: not yet documented. > Not yet documented: constraints → timezone.
Free-text comment.
Second free-text field, configurable per site. Conditional. Required when the site configures the additional field as mandatory (30048).
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
Integer ID of the registration to change.
Identifier of this object, unique per TimeLog site.
New duration in decimal hours.
Unit: hours (decimal)
Must be non-zero. When StartTime and EndTime are both sent, Hours × 60 must equal their difference in whole minutes.
Duration in minutes.
Unit: minutes
- always — Hours is always present, and Hours wins for project time — Minutes is never applied.
Whether the time is billable.
Billable duration in decimal hours.
Unit: hours (decimal)
Billable duration in minutes.
Unit: minutes
- always — BillableHours is always passed (0 when omitted), so BillableMinutes is never applied.
Registration factor (100 = normal).
Same OvertimeFactor rules as TimeRegistrationWrite.Factor (update context: a value not in the allowed list keeps the previous value).
Salary month (MMyyyy).
Not yet documented: null semantics.
Moves the registration to another task.
Refers to TaskRead.TaskID.
- TaskID differs from the current task and the employee is not allocated to it — The allocation is created (same staffing side effect as create).
Not yet documented: values → lookup op.
Start time of the work.
Time zone: none applied — sent value stored as-is
Applied only when the employee has timestamps enabled (see TimeRegistrationWrite.StartTime).
End time of the work — used ONLY to validate Hours.
Time zone: none applied
-
StartTime and EndTime both sent — 400 if EndTime ≤ StartTime, or if (EndTime − StartTime) in minutes ≠ round(Hours × 60).
-
always — Not stored; the server sets EndTime = StartTime + Hours.
Moves the registration to another date.
Time zone: not yet documented.
Not yet documented: constraints → timezone.
Free-text comment.
Second free-text field, configurable per site.
Conditional. Required when the site configures the additional field as mandatory (30048).
Responses
Success without content: HTTP 200 with the literal JSON body null. Body is the literal JSON null. Call GET to read the result.