Register time on a task (for yourself)
Registers project time for the authenticated user on one task and date.
The short form of time registration used by the TAF action add-registration on every task entity: no ID, no UserID, no GroupType. The registration is always for the caller, always project time (GroupType 1) in hours; the server generates its GUID. Unlike POST /v1/time-registration, the response body is the literal JSON null — the new registration's ID is not returned, so the only way to find it is to list your registrations afterwards. If the caller is not yet allocated to the task, TimeLog creates the allocation first.
Use it to:
- Quick registration from a task picker (search-for-time-tracking → add-registration)
Not for:
- Registering for another user, absence or travel-time group type, or when you need the created ID →
POST /v1/time-registration - Import with project/contract and an hourly-rate override →
POST /v1/time-registration/import
Rules across fields:
- R1: StartTime and EndTime both sent → EndTime > StartTime and whole minutes between them = round(Hours × 60).
Behaviour:
- Not idempotent.
- Not safe to retry blindly. Each call generates a new GUID: a retry after a timeout creates a second registration. List the caller's registrations before retrying.
- Duplicates: Never deduplicated: the GUID is server-generated per call.
- Side effect: If the caller is not allocated to the task: adds the caller to the project's resource group and contract team and creates a 0-hour allocation — BEFORE business-rule validation and outside the save transaction, so it persists when the registration is rejected.
- Side effect: Creates the work unit; updates invoicing potential, salary posting and mileage links; recalculates financial data after commit (pilot trace).
- Read-after-write consistency: not yet documented.
Call first: GET /v1/task/search-for-time-tracking, GET /v1/task/get-recently-registered
See also: POST /v1/time-registration
Not yet documented: behaviour → consistency; examples; request → body.
curl -X POST "https://app3.timelog.com/your-account/api/v1/task/registration" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d '{
"TaskID": 123,
"Date": "2024-12-25T10:00:00Z",
"Hours": 3.14,
"Minutes": 42,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"Comment": "null",
"AdditionalComment": "example_string",
"MonthlyPeriod": "example_string",
"StartTime": "2024-12-25T10:00:00Z",
"EndTime": "2024-12-25T10:00:00Z"
}'
import requests
import json
url = "https://app3.timelog.com/your-account/api/v1/task/registration"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
data = {
"TaskID": 123,
"Date": "2024-12-25T10:00:00Z",
"Hours": 3.14,
"Minutes": 42,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"Comment": "null",
"AdditionalComment": "example_string",
"MonthlyPeriod": "example_string",
"StartTime": "2024-12-25T10:00:00Z",
"EndTime": "2024-12-25T10:00:00Z"
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
const response = await fetch("https://app3.timelog.com/your-account/api/v1/task/registration", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
},
body: JSON.stringify({
"TaskID": 123,
"Date": "2024-12-25T10:00:00Z",
"Hours": 3.14,
"Minutes": 42,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"Comment": "null",
"AdditionalComment": "example_string",
"MonthlyPeriod": "example_string",
"StartTime": "2024-12-25T10:00:00Z",
"EndTime": "2024-12-25T10:00:00Z"
})
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"net/http"
"bytes"
"encoding/json"
)
func main() {
data := []byte(`{
"TaskID": 123,
"Date": "2024-12-25T10:00:00Z",
"Hours": 3.14,
"Minutes": 42,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"Comment": "null",
"AdditionalComment": "example_string",
"MonthlyPeriod": "example_string",
"StartTime": "2024-12-25T10:00:00Z",
"EndTime": "2024-12-25T10:00:00Z"
}`)
req, err := http.NewRequest("POST", "https://app3.timelog.com/your-account/api/v1/task/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/task/registration')
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 = '{
"TaskID": 123,
"Date": "2024-12-25T10:00:00Z",
"Hours": 3.14,
"Minutes": 42,
"Billable": true,
"BillableHours": 3.14,
"BillableMinutes": 42,
"Factor": 3.14,
"Comment": "null",
"AdditionalComment": "example_string",
"MonthlyPeriod": "example_string",
"StartTime": "2024-12-25T10:00:00Z",
"EndTime": "2024-12-25T10:00:00Z"
}'
response = http.request(request)
puts response.body
"null"
{
"Code": 200,
"Details": [
"'Date' must not be empty.",
"'Hours' must not be empty.",
"'Hours' must be greater than '0'.",
"'Task ID' must not be empty.",
"'Task ID' must be greater than '0'."
],
"Message": "Invalid model state error.",
"Parameters": "model: {...}",
"Url": "https://app{server-number}.timelog.com/{account}/api/v1/task/registration"
}
{
"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/task/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
The task the time is registered on.
Refers to TaskRead.TaskID. Look up valid values with GET /v1/task/search-for-time-tracking.
- The caller is not allocated to the task — TimeLog CREATES the allocation (adds the caller to the project resource group and contract team, 0-hour allocation) before the registration's business rules run; it persists even if the registration is then rejected.
Valid values come from GET /v1/task/search-for-time-tracking.
The date the time is registered on. Time zone: not yet documented. Stored as sent. Send midnight (YYYY-MM-DDT00:00:00). The default 0001-01-01 counts as empty (400). > Not yet documented: constraints → timezone.
Duration in decimal hours (e.g. 1.5 = 1 h 30 min). Unit: hours (decimal) Must be > 0 (stricter than the pilot create, which only rejects 0). Range: min > 0, unit hours (decimal).
Duration in minutes. Unit: minutes - always — Hours is always passed (and must be > 0), and Hours wins over Minutes for project time — Minutes is never applied.
Whether the time is billable to the customer. - Feature BillableOnTime is OFF — Set to the task's billable flag. - Task is fixed-price and the resulting Billable is false — Fails with 37620 (rest.timeregistration.fixed-price-non-billable).
Billable duration in decimal hours. Unit: hours (decimal) - The registration ends up non-billable — ignored - Task is fixed-price and feature BillableHoursIsEditableOnFixedPrice is OFF — Set to Hours. - Feature BillableHoursIsEditable is OFF — Set to the actual Hours (pilot trace). - Billable and the field is omitted (other cases) — 0 billable hours is stored. - Feature RoundingOfBillableTime is ON — A mismatch raises 30168.
Billable duration in minutes. Unit: minutes - always — BillableHours is always passed (0 when omitted), so BillableMinutes is never applied.
Registration factor in percent (100 = normal). Unit: percent 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 — applied - OvertimeFactor ON, value not in the list — Stored as 100.
Free-text comment on the registration. - Feature MandatoryComment is ON and comment is empty — Fails with 300116. > Not yet documented: constraints → max length.
Second free-text field; its title and validation are site settings (captured title "Support ticket number", validation Number). Conditional. Required when the site configures the additional field as mandatory (30048).
Salary month the registration belongs to, as MMyyyy. - 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: none applied — sent value stored as-is - The caller does not have timestamps enabled — StartTime/EndTime are cleared. - Timestamps enabled, StartTime sent — Seconds dropped; no timezone conversion; the stored end = StartTime + Hours. - Timestamps enabled, no StartTime — End = the caller's current time on that date, start = end − Hours (midnight-anchored if that crosses the previous day).
End time of the work — used only to cross-check StartTime and Hours. Time zone: none applied — only compared with StartTime - StartTime and EndTime both sent — 400 unless EndTime > StartTime and the whole minutes between them equal round(Hours × 60). - always — Never passed to the save: the stored end time is computed from StartTime + Hours.
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
The task the time is registered on.
Refers to TaskRead.TaskID. Look up valid values with GET /v1/task/search-for-time-tracking.
- The caller is not allocated to the task — TimeLog CREATES the allocation (adds the caller to the project resource group and contract team, 0-hour allocation) before the registration's business rules run; it persists even if the registration is then rejected.
Valid values come from GET /v1/task/search-for-time-tracking.
The date the time is registered on.
Time zone: not yet documented.
Stored as sent. Send midnight (YYYY-MM-DDT00:00:00). The default 0001-01-01 counts as empty (400).
Not yet documented: constraints → timezone.
Duration in decimal hours (e.g. 1.5 = 1 h 30 min).
Unit: hours (decimal)
Must be > 0 (stricter than the pilot create, which only rejects 0).
Range: min > 0, unit hours (decimal).
Duration in minutes.
Unit: minutes
- always — Hours is always passed (and must be > 0), and Hours wins over Minutes for project time — Minutes is never applied.
Whether the time is billable to the customer.
-
Feature BillableOnTime is OFF — Set to the task's billable flag.
-
Task is fixed-price and the resulting Billable is false — Fails with 37620 (rest.timeregistration.fixed-price-non-billable).
Billable duration in decimal hours.
Unit: hours (decimal)
-
The registration ends up non-billable — ignored
-
Task is fixed-price and feature BillableHoursIsEditableOnFixedPrice is OFF — Set to Hours.
-
Feature BillableHoursIsEditable is OFF — Set to the actual Hours (pilot trace).
-
Billable and the field is omitted (other cases) — 0 billable hours is stored.
-
Feature RoundingOfBillableTime is ON — A mismatch raises 30168.
Billable duration in minutes.
Unit: minutes
- always — BillableHours is always passed (0 when omitted), so BillableMinutes is never applied.
Registration factor in percent (100 = normal).
Unit: percent
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 — applied
-
OvertimeFactor ON, value not in the list — Stored as 100.
Free-text comment on the registration.
- Feature MandatoryComment is ON and comment is empty — Fails with 300116.
Not yet documented: constraints → max length.
Second free-text field; its title and validation are site settings (captured title "Support ticket number", validation Number).
Conditional. Required when the site configures the additional field as mandatory (30048).
Salary month the registration belongs to, as MMyyyy.
-
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: none applied — sent value stored as-is
-
The caller does not have timestamps enabled — StartTime/EndTime are cleared.
-
Timestamps enabled, StartTime sent — Seconds dropped; no timezone conversion; the stored end = StartTime + Hours.
-
Timestamps enabled, no StartTime — End = the caller's current time on that date, start = end − Hours (midnight-anchored if that crosses the previous day).
End time of the work — used only to cross-check StartTime and Hours.
Time zone: none applied — only compared with StartTime
-
StartTime and EndTime both sent — 400 unless EndTime > StartTime and the whole minutes between them equal round(Hours × 60).
-
always — Never passed to the save: the stored end time is computed from StartTime + Hours.
Responses
Success without content: HTTP 200 with the literal JSON body null. Body is the literal JSON null (TafSuccessResult). No ID, no Location header.