Time registrationsImport a time registration

Import a time registration

Creates a time or absence registration priced with a caller-supplied hourly rate.

Migration-style import: you send the project, contract, task, employee and the hourly rate the registration should carry. The server generates the registration GUID (one new registration per call) and returns the created registration. To price project or travel time, the server temporarily points the employee's allocation at a project-specific hourly rate on ContractID (an existing active rate with the same name and amount is reused, otherwise one is created), saves the registration, then points the allocation back. Cost price is no longer set by this call: CostPrice and CostPriceName are accepted and ignored.

Use it to:

  • Migrating historical hours from another system with their original hourly rates

Not for:

  • Day-to-day time entry → POST /v1/time-registration (client GUID, no rate records)
  • Dry run → POST /v1/time-registration/validate-import

Rules across fields:

  • R1: GroupType ≠ Absence (3) → ProjectID, ContractID and TaskID are required (non-zero) and AbsenceCodeID must be 0.
  • R2: GroupType = Absence (3) → AbsenceCodeID is required (non-zero).
  • R3: GroupType ≠ Absence and HourlyRate ≠ 0 → HourlyRateName is required (400).
  • R4: GroupType = Project or TravelTime and HourlyRate differs from the allocation's current rate → HourlyRateName is required, else 38037 (HTTP 500). This also fires when HourlyRate is omitted (0) and the allocation's rate is not 0; R3 does not catch that case.
  • R5: TaskID is NOT checked against ContractID/ProjectID on import. A mismatch creates or reuses the hourly rate on ContractID while the allocation belongs to TaskID's contract.

Behaviour:

  • Not idempotent.
  • Not safe to retry blindly. The GUID is server-generated, so a retry after a timeout creates a second registration.
  • Duplicates: None. Every call creates a new registration. Rate records are de-duplicated by (contract, name, amount).
  • Side effect: Allocation is created if the employee is not on the task (as create, before validation).
  • Side effect: If HourlyRate differs from the allocation's rate: an active project-specific hourly rate on ContractID with the same name (case-insensitive) and amount is reused; otherwise a NEW one is created (persists, ContractHourlyRateCreated). The allocation is saved pointing at it, the registration is saved, then the allocation is saved back to its original rate in a finally block.
  • On failure: A created hourly-rate record persists.
  • On failure: Not transactional: the switch and the restore are separate saves whose violations are not checked.
  • Read-after-write consistency: not yet documented.

Call first: POST /v1/time-registration/validate-import

Next: GET /v1/time-registration/{timeRegistrationID}

See also: POST /v1/time-registration

Not yet documented: behaviour → consistency; examples (success).

curl -X POST "https://app3.timelog.com/your-account/api/v1/time-registration/import" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d '{
  "TaskID": 123,
  "ProjectID": 123,
  "ContractID": 123,
  "UserID": 123,
  "Date": "2024-12-25T10:00:00Z",
  "Hours": 3.14,
  "GroupType": 42,
  "AbsenceCodeID": 123,
  "Billable": true,
  "Comment": "example_string",
  "AdditionalComment": "example_string",
  "BillableHours": 3.14,
  "MonthlyPeriod": "example_string",
  "HourlyRate": 3.14,
  "HourlyRateName": "John Doe",
  "CostPrice": 29.99,
  "CostPriceName": "John Doe"
}'
{
  "Properties": {
    "TimeRegistrationID": 123,
    "TimeRegistrationGUID": "123e4567-e89b-12d3-a456-426614174000",
    "UserID": 123,
    "DepartmentID": 123,
    "Date": "2024-12-25T10:00:00Z",
    "Hours": 3.14,
    "Minutes": 42,
    "BillableHours": 3.14,
    "BillableMinutes": 42,
    "IsBillable": true,
    "Factor": 3.14,
    "EntityType": 42,
    "EntityID": 123,
    "AbsenceCode": {
      "AbsenceCodeID": 123,
      "AbsenceCode": "example_string",
      "Name": "John Doe",
      "Description": "example_string",
      "IsActive": true,
      "FlexPositiveFactor": 3.14,
      "SalaryAccountFactor": 3.14,
      "SalaryAccountFactorEffect": 10,
      "SalaryAccountID": 123,
      "AbsenceCodeTypeID": 123,
      "DeductCapacity": true,
      "TimeTrackingFormat": 42,
      "RequireApproval": true,
      "IsPublicVisible": true,
      "IsFavourite": "null",
      "ID": "123e4567-e89b-12d3-a456-426614174000"
    },
    "TimeTrackingFormat": 42,
    "Comment": "null",
    "AdditionalTextField": "null",
    "MonthlyPeriod": "null",
    "Status": 42,
    "ApprovalStatus": 42,
    "InvoiceStatus": 42,
    "IsInvoiced": true,
    "IsFixedPrice": "null",
    "IsInClosedAccountingPeriod": true,
    "IsMeeting": true,
    "CalendarEventID": 123,
    "StartTime": "null",
    "EndTime": "null",
    "Created": "2024-12-25T10:00:00Z",
    "CreatedBy": 42,
    "LastModified": "2024-12-25T10:00:00Z",
    "LastModifiedBy": 42,
    "InterfaceCreated": 42,
    "InterfaceModified": 42
  },
  "Links": [
    {
      "Href": "example_string",
      "Rel": "example_string"
    }
  ],
  "Actions": [
    {}
  ]
}
POST
/v1/time-registration/import
POST
Base URLstring

Target server for requests. Edit to use your own host.

Bearer Token
Bearer Tokenstring
Required

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.

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.
Content-Typestring
Required

The media type of the request body

Options: application/json
TaskIDinteger

The task the time is registered on. Determines the allocation (and so the contract actually used). Conditional. Required (non-zero) unless GroupType = Absence (3). Refers to TaskRead.TaskID. - GroupType = Project or TravelTime — If the employee is not allocated to the task, the allocation is CREATED (staffing side effect, see operation). Import does NOT check that TaskID belongs to ContractID/ProjectID (only validate-import does). > Not yet documented: values → lookup op.

Format: int32
ProjectIDinteger

The project. On import it is only used to pick the currency of a newly created hourly rate. Conditional. Required (non-zero) unless GroupType = Absence (3). Refers to ProjectRead.ProjectID. > Not yet documented: values → lookup op.

Format: int32
ContractIDinteger

The project contract (sub-contract) on which the import's project-specific hourly rate is found or created. Conditional. Required (non-zero) unless GroupType = Absence (3). Refers to ContractRead.ContractID. > Not yet documented: values → lookup op.

Format: int32
UserIDinteger
Required

The user (employee) the time belongs to. Refers to UserRead.UserID. - UserID is not the caller and the caller lacks RegistrationAllRegistrations — Fails with 300131 (HTTP 500). Department / legal-entity access does not count on this path. > Not yet documented: values → lookup op.

Format: int32
Datestring
Required

The date the time is registered on. Time zone: not yet documented. > Not yet documented: constraints → timezone.

Format: date-time
Hoursnumber
Required

Duration in decimal hours. Unit: hours (decimal) Required and non-zero for every GroupType, including absence. TimeTrackingFormat is always Hours on import.

Format: double
GroupTypeinteger
Required

What kind of registration this is. The validator's NotNull rule cannot fail on a non-nullable enum: an omitted GroupType arrives as 0 and is treated as a non-absence registration. Allowed values: | Value | Name | Meaning | |---|---|---| | 1 | Project | Time worked on a project task. | | 3 | Absence | Absence. AbsenceCodeID is required; Project/Contract/Task are not. | | 6 | TravelTime | Travel time on a project task. | > Not yet documented: notes.

Options: 1, 3, 6
AbsenceCodeIDinteger

For absence, the absence code to register. Conditional. Required (non-zero) when GroupType = Absence (3); must be 0/omitted otherwise (validation error). Refers to AbsenceCodeRead.AbsenceCodeID. > Not yet documented: values → lookup op.

Format: int32
Billableboolean

Whether the time is billable. Same account-feature overrides as TimeRegistrationWrite.Billable (BillableFlagCoordinator).

Commentstring

Free-text comment on the registration.

AdditionalCommentstring

Second free-text field, configurable per site. Conditional. Required when the site configures the additional field as mandatory (30048).

BillableHoursnumber

Billable duration in decimal hours. Unit: hours (decimal)

Format: double
MonthlyPeriodstring

Salary month the registration belongs to (MMyyyy). Same rules as TimeRegistrationWrite.MonthlyPeriod (malformed → HTTP 500).

HourlyRatenumber

Hourly rate to price this registration with. Unit: currency per hour — the project's currency Contains financial data. - GroupType = Project or TravelTime and value differs from the allocation's current rate — An active project-specific hourly rate on ContractID with the same name (HourlyRateName, case-insensitive) and amount is reused; otherwise a new one is created and persists. The allocation points at it for the save and is pointed back afterwards (also on failure). The value is non-nullable: omitting it means 0, which prices the registration at 0 when HourlyRateName is given and fails with 38037 when it is not (unless the allocation's rate is 0). - GroupType = Project or TravelTime and value equals the allocation's current rate — No rate is created; the allocation's rate applies. - GroupType = Absence — ignored

Format: double
HourlyRateNamestring

Name of the project-specific hourly rate to reuse or create for this import. Conditional. Required when GroupType is not Absence and HourlyRate ≠ 0 (400), and when HourlyRate differs from the allocation's current rate (38037, HTTP 500).

CostPricenumber

Obsolete. Formerly the employee cost price for this registration. Contains financial data. > Not yet documented: constraints → unit.

Format: double
CostPriceNamestring

Obsolete. Formerly the name of the employee cost rate to use or create.

Request Preview
Response

Response will appear here after sending the request

Authentication

header
Authorizationstring
Required

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

application/json
TaskIDinteger

The task the time is registered on. Determines the allocation (and so the contract actually used).

Conditional. Required (non-zero) unless GroupType = Absence (3).

Refers to TaskRead.TaskID.

  • GroupType = Project or TravelTime — If the employee is not allocated to the task, the allocation is CREATED (staffing side effect, see operation).

Import does NOT check that TaskID belongs to ContractID/ProjectID (only validate-import does).

Not yet documented: values → lookup op.

ProjectIDinteger

The project. On import it is only used to pick the currency of a newly created hourly rate.

Conditional. Required (non-zero) unless GroupType = Absence (3).

Refers to ProjectRead.ProjectID.

Not yet documented: values → lookup op.

ContractIDinteger

The project contract (sub-contract) on which the import's project-specific hourly rate is found or created.

Conditional. Required (non-zero) unless GroupType = Absence (3).

Refers to ContractRead.ContractID.

Not yet documented: values → lookup op.

UserIDinteger
Required

The user (employee) the time belongs to.

Refers to UserRead.UserID.

  • UserID is not the caller and the caller lacks RegistrationAllRegistrations — Fails with 300131 (HTTP 500). Department / legal-entity access does not count on this path.

Not yet documented: values → lookup op.

Datestring
Required

The date the time is registered on.

Time zone: not yet documented.

Not yet documented: constraints → timezone.

Hoursnumber
Required

Duration in decimal hours.

Unit: hours (decimal)

Required and non-zero for every GroupType, including absence. TimeTrackingFormat is always Hours on import.

GroupTypeinteger
Required

What kind of registration this is.

The validator's NotNull rule cannot fail on a non-nullable enum: an omitted GroupType arrives as 0 and is treated as a non-absence registration.

Allowed values:

ValueNameMeaning
1ProjectTime worked on a project task.
3AbsenceAbsence. AbsenceCodeID is required; Project/Contract/Task are not.
6TravelTimeTravel time on a project task.

Not yet documented: notes.

Allowed values:136
AbsenceCodeIDinteger

For absence, the absence code to register.

Conditional. Required (non-zero) when GroupType = Absence (3); must be 0/omitted otherwise (validation error).

Refers to AbsenceCodeRead.AbsenceCodeID.

Not yet documented: values → lookup op.

Billableboolean

Whether the time is billable.

Same account-feature overrides as TimeRegistrationWrite.Billable (BillableFlagCoordinator).

Commentstring

Free-text comment on the registration.

AdditionalCommentstring

Second free-text field, configurable per site.

Conditional. Required when the site configures the additional field as mandatory (30048).

BillableHoursnumber

Billable duration in decimal hours.

Unit: hours (decimal)

MonthlyPeriodstring

Salary month the registration belongs to (MMyyyy).

Same rules as TimeRegistrationWrite.MonthlyPeriod (malformed → HTTP 500).

HourlyRatenumber

Hourly rate to price this registration with.

Unit: currency per hour — the project's currency

Contains financial data.

  • GroupType = Project or TravelTime and value differs from the allocation's current rate — An active project-specific hourly rate on ContractID with the same name (HourlyRateName, case-insensitive) and amount is reused; otherwise a new one is created and persists. The allocation points at it for the save and is pointed back afterwards (also on failure). The value is non-nullable: omitting it means 0, which prices the registration at 0 when HourlyRateName is given and fails with 38037 when it is not (unless the allocation's rate is 0).

  • GroupType = Project or TravelTime and value equals the allocation's current rate — No rate is created; the allocation's rate applies.

  • GroupType = Absence — ignored

HourlyRateNamestring

Name of the project-specific hourly rate to reuse or create for this import.

Conditional. Required when GroupType is not Absence and HourlyRate ≠ 0 (400), and when HourlyRate differs from the allocation's current rate (38037, HTTP 500).

CostPricenumber

Obsolete. Formerly the employee cost price for this registration.

Contains financial data.

Not yet documented: constraints → unit.

CostPriceNamestring

Obsolete. Formerly the name of the employee cost rate to use or create.

Responses

Propertiesobject
Linksarray
Actionsobject[]