Users and organisationUpdate a user

Update a user

Changes a user's name, licence type, extra roles and approval manager, addressed by the user's GUID.

Updates first and last name, the licence type (with the role changes it implies), adds roles, and sets a new approval manager from a given day. FirstName and LastName are ALWAYS written: omit them and the stored names are cleared, so always send both. Nothing else about the user can be changed through REST v1. The call returns 200 with body null even when the save reported a problem and nothing was changed: read the user back to confirm.

Use it to:

  • Keep names in sync from an HR system
  • Move an employee to a new approval manager from a given date
  • Change a user's licence type (Standard / Limited / TimeExpense)

Not for:

  • E-mail, department, legal entity, dates, rates — not changeable in REST v1

Rules across fields:

  • R1: ApprovalManagerInitials and ApprovalManagerStartDate are sent together or not at all.
  • R2: UserRoleIDs may be non-empty only when UserLicenseType is sent as 2 (Standard) in the same body.

Behaviour:

  • Idempotent.
  • Safe to retry.
  • Side effect: Saves the user and profile; deletes and re-inserts ALL of the user's roles and modules
  • Side effect: On a licence change: removes system roles and modules (to Limited/TimeExpense) or the licence-specific roles (to Standard)
  • Side effect: Refreshes the platform licence status and the allocation-search denormalisation
  • On failure: The user save and the approval-manager change are separate steps: a failure in the second leaves the first committed
  • Changes are visible to the next read immediately.

Call first: GET /v1/user/{id}, GET /v1/user

Next: GET /v1/user/{id}

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

curl -X PUT "https://app3.timelog.com/your-account/api/v1/user" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d '{
  "ID": "123e4567-e89b-12d3-a456-426614174000",
  "FirstName": "John Doe",
  "LastName": "John Doe",
  "ApprovalManagerInitials": "example_string",
  "ApprovalManagerStartDate": "2024-12-25T10:00:00Z",
  "UserLicenseType": 42,
  "UserRoleIDs": [
    "null"
  ]
}'
"null"
PUT
/v1/user
PUT
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
IDstring
Required

GUID of the user to change. Not the integer UserID. Refers to UserRead.ID. Look up valid values with GET /v1/user. - Omitted, empty GUID or not an existing user — HTTP 500, Code 100 'Unknown error' — not 400/404.

Format: uuid
FirstNamestring

New first name. Contains personal data. - Omitted or null — Stored first name cleared.

Max length: 50
LastNamestring

New last name. Contains personal data. - Omitted or null — Stored last name cleared.

Max length: 50
ApprovalManagerInitialsstring

Initials of the user who becomes this user's approval manager from ApprovalManagerStartDate. Conditional. Required when ApprovalManagerStartDate is sent, and vice versa (400). Refers to UserRead.Initials. Look up valid values with GET /v1/user. Contains personal data. - Not the initials of an active user that TimeLog lists as able to approve (relative to the user's current approval manager) — 400 'ApprovalManagerInitials must be one of the valid approvers for the user's current manager.' - The main save reported violations — The manager change is skipped and the call still returns 200. Valid values come from GET /v1/user. > Not yet documented: behaviour → when.

ApprovalManagerStartDatestring

Day from which the new approval manager applies. Conditional. Required when ApprovalManagerInitials is sent, and vice versa (400). Date only — no time component. - Time-of-day sent — Only the date part is stored (valid-from day). > Not yet documented: behaviour → detail.

Format: date-time
UserLicenseTypeinteger

New licence type. Null or omitted keeps the current licence. - Changed to Limited (7) or TimeExpense (8) — All system (non-employee-specific) roles and all modules are removed, then the licence's system role is added. Fails with a business rule (HTTP 500) when a role cannot be removed because the user holds the last system-administration privilege. - Changed to Standard (2) — The 'Limited user' / 'Time and expense registrations' roles are removed; no other role is added unless UserRoleIDs is sent. - Same as the current licence — No role or module change. - Value not allowed by the account features (see UserCreate.UserLicenseType) — 400. Allowed values: | Value | Name | Meaning | |---|---|---| | 2 | Standard | Standard user: access to most functionality, depending on the account's licence model. The only value accepted when neither ExternalUserLicense nor TimeExpenseUserLicense is on. | | 7 | Limited | Limited user. Accepted only when feature ExternalUserLicense is on; the system role 'Limited user' is assigned and UserRoleIDs must be empty. | | 8 | TimeExpense | Time and expense tracking with reports. Accepted only when feature TimeExpenseUserLicense is on; the system role 'Time and expense registrations' is assigned and UserRoleIDs must be empty. | | 1 | External | External user (time tracking only). Rejected by this operation. | | 3 | Advanced | Advanced user of special licence models. Rejected by this operation. | | 4 | ExternalPlus | External user with external disbursement. Rejected by this operation. | | 6 | TlpBasicLimited | Limited user of the Basic contract. Rejected by this operation. | | 0 | NotSpecified | No licence (no access). Rejected by this operation. | > Not yet documented: behaviour → detail.

Options: 2, 7, 8, 1, 3, 4, 6, 0
UserRoleIDsarray

Roles to ADD to the user. Existing roles are never removed by this field. Conditional. Allowed only when UserLicenseType is sent as Standard (2) in the same request — even for a user who already is Standard (400 otherwise). Refers to RoleRead.RoleID. Look up valid values with GET /v1/role. - A role does not exist / is employee-specific / is a locked system role / is inactive — 37037 / 37930 / 37929 / 37926 (business rule, HTTP 500). Valid values come from GET /v1/role. > Not yet documented: multiple → max items. > Not yet documented: multiple → duplicates allowed.

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
IDstring
Required

GUID of the user to change. Not the integer UserID.

Refers to UserRead.ID. Look up valid values with GET /v1/user.

  • Omitted, empty GUID or not an existing user — HTTP 500, Code 100 'Unknown error' — not 400/404.
FirstNamestring

New first name.

Contains personal data.

  • Omitted or null — Stored first name cleared.
LastNamestring

New last name.

Contains personal data.

  • Omitted or null — Stored last name cleared.
ApprovalManagerInitialsstring

Initials of the user who becomes this user's approval manager from ApprovalManagerStartDate.

Conditional. Required when ApprovalManagerStartDate is sent, and vice versa (400).

Refers to UserRead.Initials. Look up valid values with GET /v1/user.

Contains personal data.

  • Not the initials of an active user that TimeLog lists as able to approve (relative to the user's current approval manager) — 400 'ApprovalManagerInitials must be one of the valid approvers for the user's current manager.'

  • The main save reported violations — The manager change is skipped and the call still returns 200.

Valid values come from GET /v1/user.

Not yet documented: behaviour → when.

ApprovalManagerStartDatestring

Day from which the new approval manager applies.

Conditional. Required when ApprovalManagerInitials is sent, and vice versa (400).

Date only — no time component.

  • Time-of-day sent — Only the date part is stored (valid-from day).

Not yet documented: behaviour → detail.

UserLicenseTypeinteger

New licence type. Null or omitted keeps the current licence.

  • Changed to Limited (7) or TimeExpense (8) — All system (non-employee-specific) roles and all modules are removed, then the licence's system role is added. Fails with a business rule (HTTP 500) when a role cannot be removed because the user holds the last system-administration privilege.

  • Changed to Standard (2) — The 'Limited user' / 'Time and expense registrations' roles are removed; no other role is added unless UserRoleIDs is sent.

  • Same as the current licence — No role or module change.

  • Value not allowed by the account features (see UserCreate.UserLicenseType) — 400.

Allowed values:

ValueNameMeaning
2StandardStandard user: access to most functionality, depending on the account's licence model. The only value accepted when neither ExternalUserLicense nor TimeExpenseUserLicense is on.
7LimitedLimited user. Accepted only when feature ExternalUserLicense is on; the system role 'Limited user' is assigned and UserRoleIDs must be empty.
8TimeExpenseTime and expense tracking with reports. Accepted only when feature TimeExpenseUserLicense is on; the system role 'Time and expense registrations' is assigned and UserRoleIDs must be empty.
1ExternalExternal user (time tracking only). Rejected by this operation.
3AdvancedAdvanced user of special licence models. Rejected by this operation.
4ExternalPlusExternal user with external disbursement. Rejected by this operation.
6TlpBasicLimitedLimited user of the Basic contract. Rejected by this operation.
0NotSpecifiedNo licence (no access). Rejected by this operation.

Not yet documented: behaviour → detail.

Allowed values:27813460
UserRoleIDsarray

Roles to ADD to the user. Existing roles are never removed by this field.

Conditional. Allowed only when UserLicenseType is sent as Standard (2) in the same request — even for a user who already is Standard (400 otherwise).

Refers to RoleRead.RoleID. Look up valid values with GET /v1/role.

  • A role does not exist / is employee-specific / is a locked system role / is inactive — 37037 / 37930 / 37929 / 37926 (business rule, HTTP 500).

Valid values come from GET /v1/role.

Not yet documented: multiple → max items.

Not yet documented: multiple → duplicates allowed.

Responses

Success without content: HTTP 200 with the literal JSON body null. Literal JSON null. Returned also when the save reported violations and nothing was stored.